Skip to content

Commit

Permalink
Consolidate the API for builders.
Browse files Browse the repository at this point in the history
  • Loading branch information
fiseni committed Nov 7, 2024
1 parent 748ab7d commit 84984ea
Show file tree
Hide file tree
Showing 13 changed files with 277 additions and 89 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -386,4 +386,3 @@ FodyWeavers.xsd

# Developer config files
**/appsettings.Development*.json
*V11.csproj
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ List<CustomerDto> result = await _context

### Pagination

The library defines a convenient `ToPagedResult` extension method that returns a detailed paginated result.
The library defines a convenient `ToPagedResult` extension method that returns a detailed paged result.

```csharp
var spec = new CustomerDtoSpec(1, "Customer");
Expand Down
2 changes: 1 addition & 1 deletion readme-nuget.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ List<CustomerDto> result = await _context

### Pagination

The library defines a convenient `ToPagedResult` extension method that returns a detailed paginated result.
The library defines a convenient `ToPagedResult` extension method that returns a detailed paged result.

```csharp
var spec = new CustomerDtoSpec(1, "Customer");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ public interface IIncludableSpecificationBuilder<T, out TProperty> : ISpecificat
{
}

internal class IncludableSpecificationBuilder<T, TResult, TProperty> : SpecificationBuilder<T, TResult>, IIncludableSpecificationBuilder<T, TResult, TProperty> where T : class
internal class IncludableSpecificationBuilder<T, TResult, TProperty>
: SpecificationBuilder<T, TResult>, IIncludableSpecificationBuilder<T, TResult, TProperty> where T : class
{
public IncludableSpecificationBuilder(Specification<T, TResult> specification) : base(specification)
{
}
}

internal class IncludableSpecificationBuilder<T, TProperty> : SpecificationBuilder<T>, IIncludableSpecificationBuilder<T, TProperty> where T : class
internal class IncludableSpecificationBuilder<T, TProperty>
: SpecificationBuilder<T>, IIncludableSpecificationBuilder<T, TProperty> where T : class
{
public IncludableSpecificationBuilder(Specification<T> specification) : base(specification)
{
Expand Down
29 changes: 21 additions & 8 deletions src/QuerySpecification/Builders/SpecificationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,45 @@ public interface IOrderedSpecificationBuilder<T, TResult> : ISpecificationBuilde
public interface IOrderedSpecificationBuilder<T> : ISpecificationBuilder<T>
{
}

public interface ISpecificationBuilder<T, TResult>
{
internal Specification<T, TResult> Specification { get; }

void Add(int type, object value);
void AddOrUpdate(int type, object value);
}

public interface ISpecificationBuilder<T>
{
internal Specification<T> Specification { get; }

void Add(int type, object value);
void AddOrUpdate(int type, object value);
}

internal class SpecificationBuilder<T, TResult> : IOrderedSpecificationBuilder<T, TResult>, ISpecificationBuilder<T, TResult>
{
public SpecificationBuilder(Specification<T, TResult> specification)
=> Specification = specification;

public Specification<T, TResult> Specification { get; }

public SpecificationBuilder(Specification<T, TResult> specification)
{
Specification = specification;
}
public void Add(int type, object value)
=> Specification.Add(type, value);
public void AddOrUpdate(int type, object value)
=> Specification.AddOrUpdate(type, value);
}

internal class SpecificationBuilder<T> : IOrderedSpecificationBuilder<T>, ISpecificationBuilder<T>
{
public SpecificationBuilder(Specification<T> specification)
=> Specification = specification;

public Specification<T> Specification { get; }

public SpecificationBuilder(Specification<T> specification)
{
Specification = specification;
}
public void Add(int type, object value)
=> Specification.Add(type, value);
public void AddOrUpdate(int type, object value)
=> Specification.AddOrUpdate(type, value);
}
32 changes: 16 additions & 16 deletions src/QuerySpecification/Builders/SpecificationBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public static ISpecificationBuilder<T, TResult> Take<T, TResult>(
{
if (condition)
{
builder.Specification.Take = take;
builder.Specification.GetOrCreate<SpecPaging>(ItemType.Paging).Take = take;
}
return builder;
}
Expand All @@ -272,7 +272,7 @@ public static ISpecificationBuilder<T> Take<T>(
{
if (condition)
{
builder.Specification.Take = take;
builder.Specification.GetOrCreate<SpecPaging>(ItemType.Paging).Take = take;
}
return builder;
}
Expand All @@ -289,7 +289,7 @@ public static ISpecificationBuilder<T, TResult> Skip<T, TResult>(
{
if (condition)
{
builder.Specification.Skip = skip;
builder.Specification.GetOrCreate<SpecPaging>(ItemType.Paging).Skip = skip;
}
return builder;
}
Expand All @@ -306,7 +306,7 @@ public static ISpecificationBuilder<T> Skip<T>(
{
if (condition)
{
builder.Specification.Skip = skip;
builder.Specification.GetOrCreate<SpecPaging>(ItemType.Paging).Skip = skip;
}
return builder;
}
Expand All @@ -321,7 +321,7 @@ public static ISpecificationBuilder<T, TResult> IgnoreQueryFilters<T, TResult>(
{
if (condition)
{
builder.Specification.IgnoreQueryFilters = true;
builder.Specification.AddOrUpdateFlag(SpecFlags.IgnoreQueryFilters, true);
}
return builder;
}
Expand All @@ -336,7 +336,7 @@ public static ISpecificationBuilder<T> IgnoreQueryFilters<T>(
{
if (condition)
{
builder.Specification.IgnoreQueryFilters = true;
builder.Specification.AddOrUpdateFlag(SpecFlags.IgnoreQueryFilters, true);
}
return builder;
}
Expand All @@ -351,7 +351,7 @@ public static ISpecificationBuilder<T, TResult> AsSplitQuery<T, TResult>(
{
if (condition)
{
builder.Specification.AsSplitQuery = true;
builder.Specification.AddOrUpdateFlag(SpecFlags.AsSplitQuery, true);
}
return builder;
}
Expand All @@ -366,7 +366,7 @@ public static ISpecificationBuilder<T> AsSplitQuery<T>(
{
if (condition)
{
builder.Specification.AsSplitQuery = true;
builder.Specification.AddOrUpdateFlag(SpecFlags.AsSplitQuery, true);
}
return builder;
}
Expand All @@ -381,8 +381,8 @@ public static ISpecificationBuilder<T, TResult> AsNoTracking<T, TResult>(
{
if (condition)
{
builder.Specification.AsNoTrackingWithIdentityResolution = false;
builder.Specification.AsNoTracking = true;
builder.Specification.AddOrUpdateFlag(SpecFlags.AsNoTrackingWithIdentityResolution, false);
builder.Specification.AddOrUpdateFlag(SpecFlags.AsNoTracking, true);
}
return builder;
}
Expand All @@ -397,8 +397,8 @@ public static ISpecificationBuilder<T> AsNoTracking<T>(
{
if (condition)
{
builder.Specification.AsNoTrackingWithIdentityResolution = false;
builder.Specification.AsNoTracking = true;
builder.Specification.AddOrUpdateFlag(SpecFlags.AsNoTrackingWithIdentityResolution, false);
builder.Specification.AddOrUpdateFlag(SpecFlags.AsNoTracking, true);
}
return builder;
}
Expand All @@ -413,8 +413,8 @@ public static ISpecificationBuilder<T, TResult> AsNoTrackingWithIdentityResoluti
{
if (condition)
{
builder.Specification.AsNoTracking = false;
builder.Specification.AsNoTrackingWithIdentityResolution = true;
builder.Specification.AddOrUpdateFlag(SpecFlags.AsNoTracking, false);
builder.Specification.AddOrUpdateFlag(SpecFlags.AsNoTrackingWithIdentityResolution, true);
}
return builder;
}
Expand All @@ -429,8 +429,8 @@ public static ISpecificationBuilder<T> AsNoTrackingWithIdentityResolution<T>(
{
if (condition)
{
builder.Specification.AsNoTracking = false;
builder.Specification.AsNoTrackingWithIdentityResolution = true;
builder.Specification.AddOrUpdateFlag(SpecFlags.AsNoTracking, false);
builder.Specification.AddOrUpdateFlag(SpecFlags.AsNoTrackingWithIdentityResolution, true);
}
return builder;
}
Expand Down
10 changes: 10 additions & 0 deletions src/QuerySpecification/Internals/SpecFlags.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Pozitron.QuerySpecification;

[Flags]
internal enum SpecFlags
{
IgnoreQueryFilters = 1,
AsNoTracking = 2,
AsNoTrackingWithIdentityResolution = 4,
AsSplitQuery = 8
}
64 changes: 19 additions & 45 deletions src/QuerySpecification/Specification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,36 +86,12 @@ public virtual bool IsSatisfiedBy(T entity)
? Enumerable.Empty<string>()
: new SpecSelectIterator<string, string>(_items, ItemType.IncludeString, (x, bag) => x);

public int Take
{
get => FirstOrDefault<SpecPaging>(ItemType.Paging)?.Take ?? -1;
set => GetOrCreate<SpecPaging>(ItemType.Paging).Take = value;
}
public int Skip
{
get => FirstOrDefault<SpecPaging>(ItemType.Paging)?.Skip ?? -1;
set => GetOrCreate<SpecPaging>(ItemType.Paging).Skip = value;
}
public bool IgnoreQueryFilters
{
get => GetFlag(SpecFlag.IgnoreQueryFilters);
set => UpdateFlag(SpecFlag.IgnoreQueryFilters, value);
}
public bool AsSplitQuery
{
get => GetFlag(SpecFlag.AsSplitQuery);
set => UpdateFlag(SpecFlag.AsSplitQuery, value);
}
public bool AsNoTracking
{
get => GetFlag(SpecFlag.AsNoTracking);
set => UpdateFlag(SpecFlag.AsNoTracking, value);
}
public bool AsNoTrackingWithIdentityResolution
{
get => GetFlag(SpecFlag.AsNoTrackingWithIdentityResolution);
set => UpdateFlag(SpecFlag.AsNoTrackingWithIdentityResolution, value);
}
public int Take => FirstOrDefault<SpecPaging>(ItemType.Paging)?.Take ?? -1;
public int Skip => FirstOrDefault<SpecPaging>(ItemType.Paging)?.Skip ?? -1;
public bool IgnoreQueryFilters => GetFlag(SpecFlags.IgnoreQueryFilters);
public bool AsSplitQuery => GetFlag(SpecFlags.AsSplitQuery);
public bool AsNoTracking => GetFlag(SpecFlags.AsNoTracking);
public bool AsNoTrackingWithIdentityResolution => GetFlag(SpecFlags.AsNoTrackingWithIdentityResolution);

public void Add(int type, object value)
{
Expand All @@ -124,6 +100,13 @@ public void Add(int type, object value)

AddInternal(type, value);
}
public void AddOrUpdate(int type, object value)
{
ArgumentNullException.ThrowIfNull(value);
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(type);

AddOrUpdateInternal(type, value);
}
public TObject? FirstOrDefault<TObject>(int type)
{
if (IsEmpty) return default;
Expand Down Expand Up @@ -318,7 +301,7 @@ static SpecItem[] GenerateCompiledItems(SpecItem[] items, int count)
}
}

private TObject GetOrCreate<TObject>(int type) where TObject : new()
internal TObject GetOrCreate<TObject>(int type) where TObject : new()
{
return FirstOrDefault<TObject>(type) ?? Create();
TObject Create()
Expand All @@ -328,20 +311,20 @@ TObject Create()
return reference;
}
}
private bool GetFlag(SpecFlag flag)
internal bool GetFlag(SpecFlags flag)
{
if (IsEmpty) return false;

foreach (var item in _items)
{
if (item.Type == ItemType.Flags)
{
return ((SpecFlag)item.Bag & flag) == flag;
return ((SpecFlags)item.Bag & flag) == flag;
}
}
return false;
}
private void UpdateFlag(SpecFlag flag, bool value)
internal void AddOrUpdateFlag(SpecFlags flag, bool value)
{
if (IsEmpty)
{
Expand All @@ -358,8 +341,8 @@ private void UpdateFlag(SpecFlag flag, bool value)
if (items[i].Type == ItemType.Flags)
{
var newValue = value
? (SpecFlag)items[i].Bag | flag
: (SpecFlag)items[i].Bag & ~flag;
? (SpecFlags)items[i].Bag | flag
: (SpecFlags)items[i].Bag & ~flag;

_items[i].Bag = (int)newValue;
return;
Expand All @@ -371,13 +354,4 @@ private void UpdateFlag(SpecFlag flag, bool value)
AddInternal(ItemType.Flags, null!, (int)flag);
}
}

[Flags]
private enum SpecFlag
{
IgnoreQueryFilters = 1,
AsNoTracking = 2,
AsNoTrackingWithIdentityResolution = 4,
AsSplitQuery = 8
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</PropertyGroup>

<PropertyGroup>
<NoWarn>1701;1702;CA1822</NoWarn>
<NoWarn>1701;1702;CA1822;IDE0060</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit 84984ea

Please sign in to comment.