├── src
├── EF6
│ ├── LinqBuilder.EF6.Tests
│ │ ├── xunit.runner.json
│ │ ├── Data
│ │ │ ├── SomeChildEntity.cs
│ │ │ ├── SomeEntity.cs
│ │ │ ├── Specifications
│ │ │ │ ├── OrderSpecification.cs
│ │ │ │ └── ChildValueSpecification.cs
│ │ │ ├── SqliteConfiguration.cs
│ │ │ ├── TestDbContext.cs
│ │ │ └── TestDb.cs
│ │ ├── Properties
│ │ │ └── AssemblyInfo.cs
│ │ ├── .globalconfig
│ │ ├── IntegrationTests.cs
│ │ ├── LinqBuilder.EF6.Tests.csproj
│ │ └── EntityFrameworkExtensionsTests.cs
│ └── LinqBuilder.EF6
│ │ ├── Properties
│ │ └── AssemblyInfo.cs
│ │ ├── README.md
│ │ ├── LinqBuilder.EF6.csproj
│ │ └── EntityFrameworkExtensions.cs
├── EFCore
│ ├── LinqBuilder.EFCore.Tests
│ │ ├── xunit.runner.json
│ │ ├── Data
│ │ │ ├── SomeChildEntity.cs
│ │ │ ├── SomeEntity.cs
│ │ │ ├── TestDbContext.cs
│ │ │ ├── Specifications
│ │ │ │ ├── OrderSpecification.cs
│ │ │ │ └── ChildValueSpecification.cs
│ │ │ └── TestDb.cs
│ │ ├── Properties
│ │ │ └── AssemblyInfo.cs
│ │ ├── .globalconfig
│ │ ├── LinqBuilder.EFCore.Tests.csproj
│ │ ├── IntegrationTests.cs
│ │ └── EntityFrameworkCoreExtensionsTests.cs
│ └── LinqBuilder.EFCore
│ │ ├── Properties
│ │ └── AssemblyInfo.cs
│ │ ├── README.md
│ │ ├── LinqBuilder.EFCore.csproj
│ │ └── EntityFrameworkCoreExtensions.cs
├── LinqBuilder
│ ├── OrderBy
│ │ ├── Sort.cs
│ │ ├── IOrderedSpecification.cs
│ │ ├── OrderSpec.cs
│ │ ├── IOrderSpecification.cs
│ │ ├── LinqExtensions.cs
│ │ ├── OrderSpecification.cs
│ │ └── SpecificationExtensions.cs
│ ├── ISpecification.cs
│ ├── IDynamicSpecification{TEntity,TValue}.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── IDynamicSpecification{TEntity,TValue1,TValue2,TValue3}.cs
│ ├── IDynamicSpecification{TEntity,TValue1,TValue2,TValue3,TValue4}.cs
│ ├── IDynamicSpecification{TEntity,TValue1,TValue2}.cs
│ ├── Internal
│ │ ├── IQuerySpecification.cs
│ │ ├── DummySpecification.cs
│ │ ├── QuerySpecification.cs
│ │ └── SpecificationBase.cs
│ ├── Spec.cs
│ ├── DynamicSpecification{TEntity,TValue}.cs
│ ├── DynamicSpecification{TEntity,TValue1,TValue2}.cs
│ ├── DynamicSpecification{TEntity,TValue1,TValue2,TValue3}.cs
│ ├── LinqBuilder.csproj
│ ├── MultiSpecification{TEntity1,TEntity2,TEntity3}.cs
│ ├── DynamicSpecification{TEntity,TValue1,TValue2,TValue3,TValue4}.cs
│ ├── MultiSpecification{TEntity1,TEntity2,TEntity3,TEntity4}.cs
│ ├── Specification.cs
│ ├── MultiSpecification{TEntity1,TEntity2}.cs
│ ├── SpecificationExtensions.cs
│ ├── README.md
│ └── LinqExtensions.cs
└── LinqBuilder.Tests
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── .globalconfig
│ ├── Data
│ ├── Entity.cs
│ ├── Entity2.cs
│ ├── Entity3.cs
│ ├── Entity4.cs
│ ├── Entity5.cs
│ ├── Specifications
│ │ ├── Specification.cs
│ │ ├── OrderSpecification.cs
│ │ ├── MultiEntitySpecification2.cs
│ │ ├── MultipleValueSpecification1.cs
│ │ ├── MultipleValueSpecification2.cs
│ │ ├── MultiEntitySpecification3.cs
│ │ ├── MultipleValueSpecification3.cs
│ │ ├── MultipleValueSpecification4.cs
│ │ └── MultiEntitySpecification4.cs
│ ├── EntityTheoryData.cs
│ └── Fixture.cs
│ ├── Internal
│ ├── QuerySpecificationTests.cs
│ └── SpecificationBaseTests.cs
│ ├── SpecTests.cs
│ ├── LinqBuilder.Tests.csproj
│ ├── OrderBy
│ ├── OrderSpecTests.cs
│ ├── LinqExtensionsTests.cs
│ ├── OrderSpecificationTests.cs
│ └── SpecificationExtensionsTests.cs
│ ├── DynamicSpecificationTests.cs
│ ├── SpecificationTests.cs
│ ├── MultiSpecificationTests.cs
│ ├── SpecificationExtensionsTests.cs
│ ├── LinqExtensionsExeSpecTests.cs
│ └── LinqExtensionsTests.cs
├── .nuke
├── parameters.json
└── build.schema.json
├── .vscode
├── extensions.json
└── settings.json
├── GitVersion.yml
├── .idea
└── .idea.LinqBuilder
│ └── .idea
│ ├── codeStyles
│ └── codeStyleConfig.xml
│ ├── vcs.xml
│ ├── indexLayout.xml
│ ├── misc.xml
│ └── projectSettingsUpdater.xml
├── NuGet.Config
├── .editorconfig
├── stylecop.json
├── .globalconfig
├── appveyor.yml
├── LICENSE.txt
├── LinqBuilder.sln.DotSettings
├── Directory.Build.props
├── Directory.Packages.props
├── .gitattributes
├── LinqBuilder.sln
├── README.md
└── .gitignore
/src/EF6/LinqBuilder.EF6.Tests/xunit.runner.json:
--------------------------------------------------------------------------------
1 | {
2 | "parallelizeTestCollections": false
3 | }
4 |
--------------------------------------------------------------------------------
/.nuke/parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./build.schema.json",
3 | "Solution": "LinqBuilder.sln"
4 | }
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore.Tests/xunit.runner.json:
--------------------------------------------------------------------------------
1 | {
2 | "parallelizeTestCollections": false
3 | }
4 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-dotnettools.csharp",
4 | "editorconfig.editorconfig"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/GitVersion.yml:
--------------------------------------------------------------------------------
1 | next-version: 3.2.0
2 | branches:
3 | main:
4 | label: beta
5 | develop:
6 | increment: Patch
7 | ignore:
8 | sha: []
9 |
--------------------------------------------------------------------------------
/src/LinqBuilder/OrderBy/Sort.cs:
--------------------------------------------------------------------------------
1 | namespace LinqBuilder.OrderBy
2 | {
3 | public enum Sort
4 | {
5 | Ascending,
6 | Descending,
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.idea/.idea.LinqBuilder/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/EF6/LinqBuilder.EF6.Tests/Data/SomeChildEntity.cs:
--------------------------------------------------------------------------------
1 | namespace LinqBuilder.EF6.Tests.Data;
2 |
3 | public class SomeChildEntity
4 | {
5 | public int Id { get; set; }
6 |
7 | public int Value { get; set; }
8 | }
9 |
--------------------------------------------------------------------------------
/src/LinqBuilder/OrderBy/IOrderedSpecification.cs:
--------------------------------------------------------------------------------
1 | namespace LinqBuilder.OrderBy
2 | {
3 | public interface IOrderedSpecification : ISpecification
4 | where TEntity : class
5 | {
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/.idea/.idea.LinqBuilder/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore.Tests/Data/SomeChildEntity.cs:
--------------------------------------------------------------------------------
1 | namespace LinqBuilder.EFCore.Tests.Data;
2 |
3 | public class SomeChildEntity
4 | {
5 | public int Id { get; set; }
6 |
7 | public int Value { get; set; }
8 | }
9 |
--------------------------------------------------------------------------------
/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/.idea.LinqBuilder/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.encoding": "utf8",
3 | "files.exclude": {
4 | ".git": true,
5 | ".vs": true,
6 | "artifacts": true,
7 | "coverage": true,
8 | "**/obj": true,
9 | "**/bin": true,
10 | "tools/*": true
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | // These attributes will be patched by GitVersion
4 | [assembly: AssemblyVersion("1.0.0.0")]
5 | [assembly: AssemblyFileVersion("1.0.0.0")]
6 | [assembly: AssemblyInformationalVersion("1.0.0.0")]
7 |
--------------------------------------------------------------------------------
/src/LinqBuilder/ISpecification.cs:
--------------------------------------------------------------------------------
1 | using LinqBuilder.Internal;
2 |
3 | namespace LinqBuilder
4 | {
5 | public interface ISpecification
6 | where TEntity : class
7 | {
8 | SpecificationBase Internal { get; }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/.idea/.idea.LinqBuilder/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/EF6/LinqBuilder.EF6.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | // These attributes will be patched by GitVersion
4 | [assembly: AssemblyVersion("1.0.0.0")]
5 | [assembly: AssemblyFileVersion("1.0.0.0")]
6 | [assembly: AssemblyInformationalVersion("1.0.0.0")]
7 |
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | // These attributes will be patched by GitVersion
4 | [assembly: AssemblyVersion("1.0.0.0")]
5 | [assembly: AssemblyFileVersion("1.0.0.0")]
6 | [assembly: AssemblyInformationalVersion("1.0.0.0")]
7 |
--------------------------------------------------------------------------------
/src/LinqBuilder/IDynamicSpecification{TEntity,TValue}.cs:
--------------------------------------------------------------------------------
1 | namespace LinqBuilder
2 | {
3 | public interface IDynamicSpecification
4 | : ISpecification
5 | where TEntity : class
6 | {
7 | TValue Value { get; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | insert_final_newline = true
6 | trim_trailing_whitespace = true
7 | indent_style = space
8 | indent_size = 2
9 | end_of_line = lf
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
14 | [*.cs]
15 | indent_size = 4
16 |
--------------------------------------------------------------------------------
/.idea/.idea.LinqBuilder/.idea/projectSettingsUpdater.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/LinqBuilder/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 |
4 | [assembly:CLSCompliant(true)]
5 |
6 | // These attributes will be patched by GitVersion
7 | [assembly: AssemblyVersion("1.0.0.0")]
8 | [assembly: AssemblyFileVersion("1.0.0.0")]
9 | [assembly: AssemblyInformationalVersion("1.0.0.0")]
10 |
--------------------------------------------------------------------------------
/src/EF6/LinqBuilder.EF6/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 |
4 | [assembly:CLSCompliant(true)]
5 |
6 | // These attributes will be patched by GitVersion
7 | [assembly: AssemblyVersion("1.0.0.0")]
8 | [assembly: AssemblyFileVersion("1.0.0.0")]
9 | [assembly: AssemblyInformationalVersion("1.0.0.0")]
10 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/.globalconfig:
--------------------------------------------------------------------------------
1 | dotnet_diagnostic.CA1014.severity = none
2 | dotnet_diagnostic.CA1062.severity = none
3 | dotnet_diagnostic.CA1515.severity = none
4 | dotnet_diagnostic.CA1707.severity = none
5 | dotnet_diagnostic.CA1812.severity = none
6 | dotnet_diagnostic.CA2007.severity = none
7 | dotnet_diagnostic.CA2227.severity = none
8 |
--------------------------------------------------------------------------------
/src/EF6/LinqBuilder.EF6.Tests/.globalconfig:
--------------------------------------------------------------------------------
1 | dotnet_diagnostic.CA1014.severity = none
2 | dotnet_diagnostic.CA1062.severity = none
3 | dotnet_diagnostic.CA1515.severity = none
4 | dotnet_diagnostic.CA1707.severity = none
5 | dotnet_diagnostic.CA1812.severity = none
6 | dotnet_diagnostic.CA2007.severity = none
7 | dotnet_diagnostic.CA2227.severity = none
8 |
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 |
4 | [assembly:CLSCompliant(true)]
5 |
6 | // These attributes will be patched by GitVersion
7 | [assembly: AssemblyVersion("1.0.0.0")]
8 | [assembly: AssemblyFileVersion("1.0.0.0")]
9 | [assembly: AssemblyInformationalVersion("1.0.0.0")]
10 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Entity.cs:
--------------------------------------------------------------------------------
1 | // ReSharper disable PropertyCanBeMadeInitOnly.Global
2 | namespace LinqBuilder.Tests.Data;
3 |
4 | public class Entity
5 | {
6 | public int Value1 { get; set; }
7 |
8 | public int Value2 { get; set; }
9 |
10 | public int Value3 { get; set; }
11 |
12 | public int Value4 { get; set; }
13 | }
14 |
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore.Tests/.globalconfig:
--------------------------------------------------------------------------------
1 | dotnet_diagnostic.CA1014.severity = none
2 | dotnet_diagnostic.CA1062.severity = none
3 | dotnet_diagnostic.CA1515.severity = none
4 | dotnet_diagnostic.CA1707.severity = none
5 | dotnet_diagnostic.CA1812.severity = none
6 | dotnet_diagnostic.CA2007.severity = none
7 | dotnet_diagnostic.CA2227.severity = none
8 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Entity2.cs:
--------------------------------------------------------------------------------
1 | // ReSharper disable PropertyCanBeMadeInitOnly.Global
2 | namespace LinqBuilder.Tests.Data;
3 |
4 | public class Entity2
5 | {
6 | public int Value1 { get; set; }
7 |
8 | public int Value2 { get; set; }
9 |
10 | public int Value3 { get; set; }
11 |
12 | public int Value4 { get; set; }
13 | }
14 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Entity3.cs:
--------------------------------------------------------------------------------
1 | // ReSharper disable PropertyCanBeMadeInitOnly.Global
2 | namespace LinqBuilder.Tests.Data;
3 |
4 | public class Entity3
5 | {
6 | public int Value1 { get; set; }
7 |
8 | public int Value2 { get; set; }
9 |
10 | public int Value3 { get; set; }
11 |
12 | public int Value4 { get; set; }
13 | }
14 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Entity4.cs:
--------------------------------------------------------------------------------
1 | // ReSharper disable PropertyCanBeMadeInitOnly.Global
2 | namespace LinqBuilder.Tests.Data;
3 |
4 | public class Entity4
5 | {
6 | public int Value1 { get; set; }
7 |
8 | public int Value2 { get; set; }
9 |
10 | public int Value3 { get; set; }
11 |
12 | public int Value4 { get; set; }
13 | }
14 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Entity5.cs:
--------------------------------------------------------------------------------
1 | // ReSharper disable PropertyCanBeMadeInitOnly.Global
2 | namespace LinqBuilder.Tests.Data;
3 |
4 | public class Entity5
5 | {
6 | public int Value1 { get; set; }
7 |
8 | public int Value2 { get; set; }
9 |
10 | public int Value3 { get; set; }
11 |
12 | public int Value4 { get; set; }
13 | }
14 |
--------------------------------------------------------------------------------
/src/LinqBuilder/IDynamicSpecification{TEntity,TValue1,TValue2,TValue3}.cs:
--------------------------------------------------------------------------------
1 | namespace LinqBuilder
2 | {
3 | public interface IDynamicSpecification
4 | : IDynamicSpecification
5 | where TEntity : class
6 | {
7 | TValue3 Value3 { get; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Specifications/Specification.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder.Tests.Data.Specifications;
5 |
6 | public class Specification : Specification
7 | {
8 | public override Expression> AsExpression()
9 | {
10 | return entity => entity.Value1 == 1;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/LinqBuilder/IDynamicSpecification{TEntity,TValue1,TValue2,TValue3,TValue4}.cs:
--------------------------------------------------------------------------------
1 | namespace LinqBuilder
2 | {
3 | public interface IDynamicSpecification
4 | : IDynamicSpecification
5 | where TEntity : class
6 | {
7 | TValue4 Value4 { get; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/LinqBuilder/IDynamicSpecification{TEntity,TValue1,TValue2}.cs:
--------------------------------------------------------------------------------
1 | using LinqBuilder.Internal;
2 |
3 | namespace LinqBuilder
4 | {
5 | public interface IDynamicSpecification
6 | : IQuerySpecification
7 | where TEntity : class
8 | {
9 | TValue1 Value1 { get; }
10 |
11 | TValue2 Value2 { get; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/LinqBuilder/Internal/IQuerySpecification.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder.Internal
5 | {
6 | public interface IQuerySpecification : ISpecification
7 | where TEntity : class
8 | {
9 | Expression>? AsExpression();
10 |
11 | Func? AsFunc();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Internal/QuerySpecificationTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using LinqBuilder.Tests.Data;
3 | using Xunit;
4 |
5 | namespace LinqBuilder.Tests.Internal;
6 |
7 | public class QuerySpecificationTests
8 | {
9 | [Fact]
10 | public void AsFunc_NoExpression_ShouldBeNull()
11 | {
12 | new Specification().AsFunc().Should().BeNull();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/stylecop.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
3 | "settings": {
4 | "indentation": {
5 | "indentationSize": 4,
6 | "useTabs": false
7 | },
8 | "orderingRules": {
9 | "usingDirectivesPlacement": "outsideNamespace"
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/EF6/LinqBuilder.EF6.Tests/Data/SomeEntity.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace LinqBuilder.EF6.Tests.Data;
4 |
5 | public class SomeEntity
6 | {
7 | public int Id { get; set; }
8 |
9 | public int Value1 { get; set; }
10 |
11 | public int Value2 { get; set; }
12 |
13 | public virtual ICollection ChildEntities { get; set; } = new HashSet();
14 | }
15 |
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore.Tests/Data/SomeEntity.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace LinqBuilder.EFCore.Tests.Data;
4 |
5 | public class SomeEntity
6 | {
7 | public int Id { get; set; }
8 |
9 | public int Value1 { get; set; }
10 |
11 | public int Value2 { get; set; }
12 |
13 | public virtual ICollection ChildEntities { get; set; } = new HashSet();
14 | }
15 |
--------------------------------------------------------------------------------
/src/EF6/LinqBuilder.EF6.Tests/Data/Specifications/OrderSpecification.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 | using LinqBuilder.OrderBy;
4 |
5 | namespace LinqBuilder.EF6.Tests.Data.Specifications;
6 |
7 | public class OrderSpecification(Sort sort = Sort.Ascending) : OrderSpecification(sort)
8 | {
9 | public override Expression> AsExpression()
10 | {
11 | return entity => entity.Value1;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore.Tests/Data/TestDbContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 |
3 | namespace LinqBuilder.EFCore.Tests.Data;
4 |
5 | public class TestDbContext : DbContext
6 | {
7 | public TestDbContext(DbContextOptions options)
8 | : base(options)
9 | {
10 | }
11 |
12 | public virtual DbSet Entities { get; set; } = null!;
13 |
14 | public virtual DbSet ChildEntities { get; set; } = null!;
15 | }
16 |
--------------------------------------------------------------------------------
/src/LinqBuilder/Spec.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder
5 | {
6 | // Just an alias of Specification
7 | public sealed class Spec : Specification
8 | where TEntity : class
9 | {
10 | public Spec()
11 | {
12 | }
13 |
14 | public Spec(Expression> expression)
15 | : base(expression)
16 | {
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/EF6/LinqBuilder.EF6.Tests/Data/Specifications/ChildValueSpecification.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Linq.Expressions;
4 |
5 | namespace LinqBuilder.EF6.Tests.Data.Specifications;
6 |
7 | public class ChildValueSpecification(int value) : Specification
8 | {
9 | public override Expression> AsExpression()
10 | {
11 | return entity => entity.ChildEntities.Any(x => x.Value == value);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/.globalconfig:
--------------------------------------------------------------------------------
1 | is_global = true
2 |
3 | dotnet_diagnostic.CA1000.severity = none
4 | dotnet_diagnostic.CA1510.severity = none # Does not work in .NET Standard
5 | dotnet_diagnostic.CA1859.severity = none
6 |
7 | dotnet_diagnostic.CS1591.severity = none
8 |
9 | dotnet_diagnostic.SA1101.severity = none
10 | dotnet_diagnostic.SA1309.severity = none
11 | dotnet_diagnostic.SA1600.severity = none
12 | dotnet_diagnostic.SA1602.severity = none
13 | dotnet_diagnostic.SA1633.severity = none
14 |
--------------------------------------------------------------------------------
/src/LinqBuilder/OrderBy/OrderSpec.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder.OrderBy
5 | {
6 | // Just an alias of OrderSpecification
7 | public sealed class OrderSpec : OrderSpecification
8 | where TEntity : class
9 | {
10 | public OrderSpec(Expression> expression, Sort sort = Sort.Ascending)
11 | : base(expression, sort)
12 | {
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/LinqBuilder/Internal/DummySpecification.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder.Internal
5 | {
6 | internal sealed class DummySpecification : IQuerySpecification
7 | where TEntity : class
8 | {
9 | public SpecificationBase Internal => new SpecificationBase(this);
10 |
11 | public Expression>? AsExpression() => null;
12 |
13 | public Func? AsFunc() => null;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Specifications/OrderSpecification.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 | using LinqBuilder.OrderBy;
4 |
5 | namespace LinqBuilder.Tests.Data.Specifications;
6 |
7 | public class OrderSpecification : OrderSpecification
8 | {
9 | public OrderSpecification(Sort sort = Sort.Ascending)
10 | : base(sort)
11 | {
12 | }
13 |
14 | public override Expression> AsExpression()
15 | {
16 | return entity => entity.Value1;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore.Tests/Data/Specifications/OrderSpecification.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 | using LinqBuilder.OrderBy;
4 |
5 | namespace LinqBuilder.EFCore.Tests.Data.Specifications;
6 |
7 | public class OrderSpecification : OrderSpecification
8 | {
9 | public OrderSpecification(Sort sort = Sort.Ascending)
10 | : base(sort)
11 | {
12 | }
13 |
14 | public override Expression> AsExpression()
15 | {
16 | return entity => entity.Value1;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Specifications/MultiEntitySpecification2.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder.Tests.Data.Specifications;
5 |
6 | public class MultiEntitySpecification2 : MultiSpecification
7 | {
8 | public override Expression> AsExpressionForEntity1()
9 | {
10 | return entity => entity.Value1 == 1;
11 | }
12 |
13 | public override Expression> AsExpressionForEntity2()
14 | {
15 | return entity => entity.Value2 == 2;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Specifications/MultipleValueSpecification1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder.Tests.Data.Specifications;
5 |
6 | public class MultipleValueSpecification1 : DynamicSpecification
7 | {
8 | public MultipleValueSpecification1()
9 | {
10 | }
11 |
12 | public MultipleValueSpecification1(int value1)
13 | : base(value1)
14 | {
15 | }
16 |
17 | public override Expression> AsExpression()
18 | {
19 | return entity => entity.Value1 == Value;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore.Tests/Data/Specifications/ChildValueSpecification.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Linq.Expressions;
4 |
5 | namespace LinqBuilder.EFCore.Tests.Data.Specifications;
6 |
7 | public class ChildValueSpecification : Specification
8 | {
9 | private readonly int _value;
10 |
11 | public ChildValueSpecification(int value)
12 | {
13 | _value = value;
14 | }
15 |
16 | public override Expression> AsExpression()
17 | {
18 | return entity => entity.ChildEntities.Any(x => x.Value == _value);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/LinqBuilder/OrderBy/IOrderSpecification.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 |
4 | namespace LinqBuilder.OrderBy
5 | {
6 | public interface IOrderSpecification : ISpecification
7 | where TEntity : class
8 | {
9 | IOrderedQueryable InvokeSort(IQueryable query);
10 |
11 | IOrderedEnumerable InvokeSort(IEnumerable collection);
12 |
13 | IOrderedQueryable InvokeSort(IOrderedQueryable query);
14 |
15 | IOrderedEnumerable InvokeSort(IOrderedEnumerable collection);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/EF6/LinqBuilder.EF6.Tests/Data/SqliteConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System.Data.Entity;
2 | using System.Data.Entity.Core.Common;
3 | using System.Data.SQLite;
4 | using System.Data.SQLite.EF6;
5 |
6 | namespace LinqBuilder.EF6.Tests.Data;
7 |
8 | public class SqliteConfiguration : DbConfiguration
9 | {
10 | public SqliteConfiguration()
11 | {
12 | SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);
13 | SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
14 | SetProviderServices("System.Data.SQLite", (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Specifications/MultipleValueSpecification2.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder.Tests.Data.Specifications;
5 |
6 | public class MultipleValueSpecification2 : DynamicSpecification
7 | {
8 | public MultipleValueSpecification2()
9 | {
10 | }
11 |
12 | public MultipleValueSpecification2(int value1, int value2)
13 | : base(value1, value2)
14 | {
15 | }
16 |
17 | public override Expression> AsExpression()
18 | {
19 | return entity => entity.Value1 == Value1 &&
20 | entity.Value2 == Value2;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/EF6/LinqBuilder.EF6/README.md:
--------------------------------------------------------------------------------
1 | # LinqBuilder.EF6
2 |
3 | **LinqBuilder.EF6** packages extends the following extensions to support ```ISpecification```.
4 | ```csharp
5 | bool result = await _sampleContext.Entities.AnyAsync(specification);
6 | bool result = await _sampleContext.Entities.AllAsync(specification);
7 | int result = await _sampleContext.Entities.CountAsync(specification);
8 | Entity result = await _sampleContext.Entities.FirstAsync(specification);
9 | Entity result = await _sampleContext.Entities.FirstOrDefaultAsync(specification);
10 | Entity result = await _sampleContext.Entities.SingleAsync(specification);
11 | Entity result = await _sampleContext.Entities.SingleOrDefaultAsync(specification);
12 | ```
13 |
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore/README.md:
--------------------------------------------------------------------------------
1 | # LinqBuilder.EFCore
2 |
3 | **LinqBuilder.EFCore** packages extends the following extensions to support ```ISpecification```.
4 | ```csharp
5 | bool result = await _sampleContext.Entities.AnyAsync(specification);
6 | bool result = await _sampleContext.Entities.AllAsync(specification);
7 | int result = await _sampleContext.Entities.CountAsync(specification);
8 | Entity result = await _sampleContext.Entities.FirstAsync(specification);
9 | Entity result = await _sampleContext.Entities.FirstOrDefaultAsync(specification);
10 | Entity result = await _sampleContext.Entities.SingleAsync(specification);
11 | Entity result = await _sampleContext.Entities.SingleOrDefaultAsync(specification);
12 | ```
13 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Specifications/MultiEntitySpecification3.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder.Tests.Data.Specifications;
5 |
6 | public class MultiEntitySpecification3 : MultiSpecification
7 | {
8 | public override Expression> AsExpressionForEntity1()
9 | {
10 | return entity => entity.Value1 == 1;
11 | }
12 |
13 | public override Expression> AsExpressionForEntity2()
14 | {
15 | return entity => entity.Value2 == 2;
16 | }
17 |
18 | public override Expression> AsExpressionForEntity3()
19 | {
20 | return entity => entity.Value3 == 3;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Specifications/MultipleValueSpecification3.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder.Tests.Data.Specifications;
5 |
6 | public class MultipleValueSpecification3 : DynamicSpecification
7 | {
8 | public MultipleValueSpecification3()
9 | {
10 | }
11 |
12 | public MultipleValueSpecification3(int value1, int value2, int value3)
13 | : base(value1, value2, value3)
14 | {
15 | }
16 |
17 | public override Expression> AsExpression()
18 | {
19 | return entity => entity.Value1 == Value1 &&
20 | entity.Value2 == Value2 &&
21 | entity.Value3 == Value3;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/LinqBuilder/DynamicSpecification{TEntity,TValue}.cs:
--------------------------------------------------------------------------------
1 | using LinqBuilder.Internal;
2 |
3 | namespace LinqBuilder
4 | {
5 | public abstract class DynamicSpecification
6 | : QuerySpecification, IDynamicSpecification
7 | where TEntity : class
8 | {
9 | protected DynamicSpecification()
10 | {
11 | }
12 |
13 | protected DynamicSpecification(TValue value)
14 | {
15 | Set(value);
16 | }
17 |
18 | public TValue Value { get; private set; } = default!;
19 |
20 | public IDynamicSpecification Set(TValue value)
21 | {
22 | Value = value;
23 | return this;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/EntityTheoryData.cs:
--------------------------------------------------------------------------------
1 | using Xunit;
2 |
3 | namespace LinqBuilder.Tests.Data;
4 |
5 | public abstract class EntityTheoryData : TheoryData
6 | {
7 | protected void AddEntity(int value1, int value2, bool expected)
8 | {
9 | var entity = new Entity
10 | {
11 | Value1 = value1,
12 | Value2 = value2,
13 | };
14 | Add(entity, expected);
15 | }
16 |
17 | protected void AddEntity(int value1, int value2, int value3, int value4, bool expected)
18 | {
19 | var entity = new Entity
20 | {
21 | Value1 = value1,
22 | Value2 = value2,
23 | Value3 = value3,
24 | Value4 = value4,
25 | };
26 | Add(entity, expected);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Specifications/MultipleValueSpecification4.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder.Tests.Data.Specifications;
5 |
6 | public class MultipleValueSpecification4 : DynamicSpecification
7 | {
8 | public MultipleValueSpecification4()
9 | {
10 | }
11 |
12 | public MultipleValueSpecification4(int value1, int value2, int value3, int value4)
13 | : base(value1, value2, value3, value4)
14 | {
15 | }
16 |
17 | public override Expression> AsExpression()
18 | {
19 | return entity => entity.Value1 == Value1 &&
20 | entity.Value2 == Value2 &&
21 | entity.Value3 == Value3 &&
22 | entity.Value4 == Value4;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Specifications/MultiEntitySpecification4.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder.Tests.Data.Specifications;
5 |
6 | public class MultiEntitySpecification4 : MultiSpecification
7 | {
8 | public override Expression> AsExpressionForEntity1()
9 | {
10 | return entity => entity.Value1 == 1;
11 | }
12 |
13 | public override Expression> AsExpressionForEntity2()
14 | {
15 | return entity => entity.Value2 == 2;
16 | }
17 |
18 | public override Expression> AsExpressionForEntity3()
19 | {
20 | return entity => entity.Value3 == 3;
21 | }
22 |
23 | public override Expression> AsExpressionForEntity4()
24 | {
25 | return entity => entity.Value4 == 4;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/SpecTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using LinqBuilder.Tests.Data;
3 | using Xunit;
4 |
5 | namespace LinqBuilder.Tests;
6 |
7 | public class SpecTests
8 | {
9 | [Fact]
10 | public void Constructor_DefaultExpression_ShouldBeTrue()
11 | {
12 | new Spec()
13 | .IsSatisfiedBy(new Entity())
14 | .Should().BeTrue();
15 | }
16 |
17 | [Fact]
18 | public void Constructor_InlineExpression_ShouldBeTrue()
19 | {
20 | new Spec(entity => entity.Value1 == 1)
21 | .IsSatisfiedBy(new Entity { Value1 = 1 })
22 | .Should().BeTrue();
23 | }
24 |
25 | [Fact]
26 | public void Constructor_InlineExpression_ShouldBeFalse()
27 | {
28 | new Spec(entity => entity.Value1 == 2)
29 | .IsSatisfiedBy(new Entity { Value1 = 1 })
30 | .Should().BeFalse();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/LinqBuilder/DynamicSpecification{TEntity,TValue1,TValue2}.cs:
--------------------------------------------------------------------------------
1 | using LinqBuilder.Internal;
2 |
3 | namespace LinqBuilder
4 | {
5 | public abstract class DynamicSpecification
6 | : QuerySpecification, IDynamicSpecification
7 | where TEntity : class
8 | {
9 | protected DynamicSpecification()
10 | {
11 | }
12 |
13 | protected DynamicSpecification(TValue1 value1, TValue2 value2)
14 | {
15 | Set(value1, value2);
16 | }
17 |
18 | public TValue1 Value1 { get; private set; } = default!;
19 |
20 | public TValue2 Value2 { get; private set; } = default!;
21 |
22 | public IDynamicSpecification Set(TValue1 value1, TValue2 value2)
23 | {
24 | Value1 = value1;
25 | Value2 = value2;
26 | return this;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Data/Fixture.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 |
4 | namespace LinqBuilder.Tests.Data;
5 |
6 | public class Fixture
7 | {
8 | private readonly List _store = new();
9 |
10 | public IReadOnlyList Store => _store;
11 |
12 | public IEnumerable Collection => _store.AsEnumerable();
13 |
14 | public IQueryable Query => _store.AsQueryable();
15 |
16 | public void AddToCollection(int value1, int value2, int? value3 = null, int? value4 = null)
17 | {
18 | var entity = new Entity
19 | {
20 | Value1 = value1,
21 | Value2 = value2,
22 | };
23 |
24 | if (value3.HasValue)
25 | {
26 | entity.Value3 = value3.Value;
27 | }
28 |
29 | if (value4.HasValue)
30 | {
31 | entity.Value4 = value4.Value;
32 | }
33 |
34 | _store.Add(entity);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/LinqBuilder/DynamicSpecification{TEntity,TValue1,TValue2,TValue3}.cs:
--------------------------------------------------------------------------------
1 | namespace LinqBuilder
2 | {
3 | public abstract class DynamicSpecification
4 | : DynamicSpecification, IDynamicSpecification
5 | where TEntity : class
6 | {
7 | protected DynamicSpecification()
8 | {
9 | }
10 |
11 | protected DynamicSpecification(TValue1 value1, TValue2 value2, TValue3 value3)
12 | : base(value1, value2)
13 | {
14 | Value3 = value3;
15 | }
16 |
17 | public TValue3 Value3 { get; private set; } = default!;
18 |
19 | public IDynamicSpecification Set(TValue1 value1, TValue2 value2, TValue3 value3)
20 | {
21 | Set(value1, value2);
22 | Value3 = value3;
23 | return this;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/LinqBuilder/LinqBuilder.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0;net6.0;net8.0;net9.0
5 | Morten Larsen
6 | MIT
7 | LinqBuilder is an implementation of the specification pattern.
8 | Made for use with IEnumerable and IQueryable.
9 | git
10 | https://github.com/Baune8D/LinqBuilder
11 | https://github.com/Baune8D/LinqBuilder
12 | Specification, Linq
13 | README.md
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/LinqBuilder/MultiSpecification{TEntity1,TEntity2,TEntity3}.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder
5 | {
6 | public abstract class MultiSpecification
7 | : MultiSpecification
8 | where TEntity1 : class
9 | where TEntity2 : class
10 | where TEntity3 : class
11 | {
12 | // ReSharper disable once MemberCanBeProtected.Global
13 | public abstract Expression> AsExpressionForEntity3();
14 |
15 | protected override Specification? Transform()
16 | {
17 | object? specification = base.Transform();
18 |
19 | if (specification == null && typeof(TEntity) == typeof(TEntity3))
20 | {
21 | specification = new Specification(AsExpressionForEntity3());
22 | }
23 |
24 | return (Specification?)specification;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/LinqBuilder.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0;net8.0;net9.0
5 | false
6 |
7 |
8 |
9 |
10 | all
11 | runtime; build; native; contentfiles; analyzers; buildtransitive
12 |
13 |
14 |
15 |
16 |
17 | all
18 | runtime; build; native; contentfiles; analyzers; buildtransitive
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/LinqBuilder/DynamicSpecification{TEntity,TValue1,TValue2,TValue3,TValue4}.cs:
--------------------------------------------------------------------------------
1 | namespace LinqBuilder
2 | {
3 | public abstract class DynamicSpecification
4 | : DynamicSpecification, IDynamicSpecification
5 | where TEntity : class
6 | {
7 | protected DynamicSpecification()
8 | {
9 | }
10 |
11 | protected DynamicSpecification(TValue1 value1, TValue2 value2, TValue3 value3, TValue4 value4)
12 | : base(value1, value2, value3)
13 | {
14 | Value4 = value4;
15 | }
16 |
17 | public TValue4 Value4 { get; private set; } = default!;
18 |
19 | public IDynamicSpecification Set(TValue1 value1, TValue2 value2, TValue3 value3, TValue4 value4)
20 | {
21 | Set(value1, value2, value3);
22 | Value4 = value4;
23 | return this;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # ------------------------------------------------------------------------------
2 | #
3 | #
4 | # This code was generated.
5 | #
6 | # - To turn off auto-generation set:
7 | #
8 | # [AppVeyor (AutoGenerate = false)]
9 | #
10 | # - To trigger manual generation invoke:
11 | #
12 | # nuke --generate-configuration AppVeyor --host AppVeyor
13 | #
14 | #
15 | # ------------------------------------------------------------------------------
16 |
17 | image:
18 | - Visual Studio 2022
19 |
20 | build_script:
21 | - cmd: .\build.cmd UploadCodecov PushNuGet PushMyGet
22 | - sh: ./build.cmd UploadCodecov PushNuGet PushMyGet
23 |
24 | artifacts:
25 | - path: 'artifacts/*.nupkg'
26 |
27 | environment:
28 | MYGET_API_KEY:
29 | secure: 78qy8e6pKfJlQV7RAG5tJOWegzXpjASkUs3aFdVBoPYA5gi6+mWdjbuAmNa5OQPe
30 | NUGET_API_KEY:
31 | secure: aMbj+EdePo74elFCi6lrQZcO81mru5j8cqD5FxGoDBWgXFFHwok/z4B+BtS4H1Sw
32 | CODECOV_TOKEN:
33 | secure: 3FxtGPNTgZyQGToJBaH68/oIjptV79CcViR9mHt2aOKGh3++oKTehBIuPSb7oYCE
34 |
--------------------------------------------------------------------------------
/src/LinqBuilder/MultiSpecification{TEntity1,TEntity2,TEntity3,TEntity4}.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder
5 | {
6 | public abstract class MultiSpecification
7 | : MultiSpecification
8 | where TEntity1 : class
9 | where TEntity2 : class
10 | where TEntity3 : class
11 | where TEntity4 : class
12 | {
13 | // ReSharper disable once MemberCanBeProtected.Global
14 | public abstract Expression> AsExpressionForEntity4();
15 |
16 | protected override Specification? Transform()
17 | {
18 | object? specification = base.Transform();
19 |
20 | if (specification == null && typeof(TEntity) == typeof(TEntity4))
21 | {
22 | specification = new Specification(AsExpressionForEntity4());
23 | }
24 |
25 | return (Specification?)specification;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/EF6/LinqBuilder.EF6/LinqBuilder.EF6.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | Morten Larsen
6 | MIT
7 | Entity Framework 6 extensions.
8 | Enables most async methods to use ISpecification.
9 | git
10 | https://github.com/Baune8D/LinqBuilder
11 | https://github.com/Baune8D/LinqBuilder
12 | Specification, Linq, EntityFramework
13 | README.md
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore/LinqBuilder.EFCore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0;net8.0;net9.0
5 | Morten Larsen
6 | MIT
7 | Entity Framework Core extensions.
8 | Enables most async methods to use ISpecification.
9 | git
10 | https://github.com/Baune8D/LinqBuilder
11 | https://github.com/Baune8D/LinqBuilder
12 | Specification, Linq, EntityFrameworkCore
13 | README.md
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Morten Larsen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/src/LinqBuilder/Internal/QuerySpecification.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | namespace LinqBuilder.Internal
5 | {
6 | public abstract class QuerySpecification : IQuerySpecification
7 | where TEntity : class
8 | {
9 | private readonly Expression>? _expression;
10 | private Func? _func;
11 |
12 | protected QuerySpecification()
13 | {
14 | }
15 |
16 | protected QuerySpecification(Expression> expression)
17 | {
18 | _expression = expression;
19 | }
20 |
21 | public SpecificationBase Internal => new SpecificationBase(this);
22 |
23 | public virtual Expression>? AsExpression()
24 | {
25 | return _expression;
26 | }
27 |
28 | public Func? AsFunc()
29 | {
30 | var expression = AsExpression();
31 | if (expression == null)
32 | {
33 | return null;
34 | }
35 |
36 | return _func ??= expression.Compile();
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/EF6/LinqBuilder.EF6.Tests/Data/TestDbContext.cs:
--------------------------------------------------------------------------------
1 | using System.Data.Common;
2 | using System.Data.Entity;
3 | using SQLite.CodeFirst;
4 |
5 | namespace LinqBuilder.EF6.Tests.Data;
6 |
7 | public sealed class TestDbContext : DbContext
8 | {
9 | private static DbModelBuilder? _modelBuilder;
10 |
11 | public TestDbContext(DbConnection connection)
12 | : base(connection, true)
13 | {
14 | if (_modelBuilder == null)
15 | {
16 | return;
17 | }
18 |
19 | var model = _modelBuilder.Build(Database.Connection);
20 | var sqliteDatabaseCreator = new SqliteDatabaseCreator();
21 | sqliteDatabaseCreator.Create(Database, model);
22 | }
23 |
24 | public DbSet Entities { get; set; } = null!;
25 |
26 | public DbSet ChildEntities { get; set; } = null!;
27 |
28 | protected override void OnModelCreating(DbModelBuilder modelBuilder)
29 | {
30 | var sqliteConnectionInitializer = new SqliteDropCreateDatabaseAlways(modelBuilder);
31 | Database.SetInitializer(sqliteConnectionInitializer);
32 | _modelBuilder = modelBuilder;
33 | base.OnModelCreating(modelBuilder);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LinqBuilder.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
3 | <data />
4 | <data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="LinqBuilder.*Tests" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data>
5 | True
6 | True
7 | True
8 | True
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore.Tests/LinqBuilder.EFCore.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0;net8.0;net9.0
5 | false
6 |
7 |
8 |
9 |
10 | all
11 | runtime; build; native; contentfiles; analyzers; buildtransitive
12 |
13 |
14 |
15 |
16 |
17 |
18 | all
19 | runtime; build; native; contentfiles; analyzers; buildtransitive
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | PreserveNewest
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/EF6/LinqBuilder.EF6.Tests/IntegrationTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data.Entity;
3 | using System.Threading.Tasks;
4 | using FluentAssertions;
5 | using LinqBuilder.EF6.Tests.Data;
6 | using LinqBuilder.EF6.Tests.Data.Specifications;
7 | using LinqBuilder.OrderBy;
8 | using Xunit;
9 |
10 | namespace LinqBuilder.EF6.Tests;
11 |
12 | public sealed class IntegrationTests : IDisposable
13 | {
14 | private readonly TestDb _testDb;
15 |
16 | public IntegrationTests()
17 | {
18 | _testDb = new TestDb();
19 | _testDb.AddEntity(2, 1, 2);
20 | _testDb.AddEntity(1, 2, 3);
21 | _testDb.AddEntity(3, 1, 1);
22 | _testDb.Context.SaveChanges();
23 | }
24 |
25 | public void Dispose()
26 | {
27 | _testDb.Dispose();
28 | }
29 |
30 | [Fact]
31 | public async Task ExeSpecAsync_ChildSpecification_ShouldReturnCorrectResult()
32 | {
33 | var specification = new ChildValueSpecification(1)
34 | .Or(new ChildValueSpecification(2))
35 | .OrderBy(new OrderSpecification());
36 |
37 | var result = await _testDb.Context.Entities
38 | .ExeSpec(specification)
39 | .ToListAsync();
40 |
41 | result.Count.Should().Be(2);
42 | result[0].Id.Should().Be(1);
43 | result[1].Id.Should().Be(3);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore.Tests/IntegrationTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using FluentAssertions;
4 | using LinqBuilder.EFCore.Tests.Data;
5 | using LinqBuilder.EFCore.Tests.Data.Specifications;
6 | using LinqBuilder.OrderBy;
7 | using Microsoft.EntityFrameworkCore;
8 | using Xunit;
9 |
10 | namespace LinqBuilder.EFCore.Tests;
11 |
12 | public sealed class IntegrationTests : IDisposable
13 | {
14 | private readonly TestDb _testDb;
15 |
16 | public IntegrationTests()
17 | {
18 | _testDb = new TestDb();
19 | _testDb.AddEntity(2, 1, 2);
20 | _testDb.AddEntity(1, 2, 3);
21 | _testDb.AddEntity(3, 1, 1);
22 | _testDb.Context.SaveChanges();
23 | }
24 |
25 | public void Dispose()
26 | {
27 | _testDb.Dispose();
28 | }
29 |
30 | [Fact]
31 | public async Task ExeSpecAsync_ChildSpecification_ShouldReturnCorrectResult()
32 | {
33 | var specification = new ChildValueSpecification(1)
34 | .Or(new ChildValueSpecification(2))
35 | .OrderBy(new OrderSpecification());
36 |
37 | var result = await _testDb.Context.Entities
38 | .ExeSpec(specification)
39 | .ToListAsync();
40 |
41 | result.Count.Should().Be(2);
42 | result[0].Id.Should().Be(1);
43 | result[1].Id.Should().Be(3);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/OrderBy/OrderSpecTests.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using FluentAssertions;
3 | using LinqBuilder.OrderBy;
4 | using LinqBuilder.Tests.Data;
5 | using Xunit;
6 |
7 | namespace LinqBuilder.Tests.OrderBy;
8 |
9 | public class OrderSpecTests
10 | {
11 | private readonly Fixture _fixture;
12 |
13 | public OrderSpecTests()
14 | {
15 | _fixture = new Fixture();
16 | _fixture.AddToCollection(3, 1, 1);
17 | _fixture.AddToCollection(1, 1, 1);
18 | _fixture.AddToCollection(2, 1, 1);
19 | }
20 |
21 | [Fact]
22 | public void Constructor_InlineExpression__ShouldReturnOrderedList()
23 | {
24 | var specification = new OrderSpec(entity => entity.Value1);
25 | var result = _fixture.Query.OrderBy(specification).ToList();
26 | result[0].Value1.Should().Be(1);
27 | result[1].Value1.Should().Be(2);
28 | result[2].Value1.Should().Be(3);
29 | }
30 |
31 | [Fact]
32 | public void Constructor_InlineExpression_ShouldReturnOrderedList()
33 | {
34 | var specification = new OrderSpec(entity => entity.Value1, Sort.Descending);
35 | var result = _fixture.Query.OrderBy(specification).ToList();
36 | result[0].Value1.Should().Be(3);
37 | result[1].Value1.Should().Be(2);
38 | result[2].Value1.Should().Be(1);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/EF6/LinqBuilder.EF6.Tests/LinqBuilder.EF6.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | false
6 |
7 |
8 |
9 |
10 | all
11 | runtime; build; native; contentfiles; analyzers; buildtransitive
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | all
22 | runtime; build; native; contentfiles; analyzers; buildtransitive
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | PreserveNewest
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | enable
5 | AnyCPU
6 | true
7 | AllEnabledByDefault
8 | false
9 | false
10 | false
11 |
12 |
13 |
14 |
15 | 8
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | all
25 | runtime; build; native; contentfiles; analyzers; buildtransitive
26 |
27 |
28 | all
29 | runtime; build; native; contentfiles; analyzers; buildtransitive
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/LinqBuilder/Specification.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Linq.Expressions;
4 | using LinqBuilder.Internal;
5 |
6 | namespace LinqBuilder
7 | {
8 | public class Specification : QuerySpecification
9 | where TEntity : class
10 | {
11 | public Specification()
12 | {
13 | }
14 |
15 | public Specification(Expression> expression)
16 | : base(expression)
17 | {
18 | }
19 |
20 | public static ISpecification New()
21 | {
22 | return new Specification();
23 | }
24 |
25 | public static ISpecification New(Expression> expression)
26 | {
27 | return new Specification(expression);
28 | }
29 |
30 | public static ISpecification All(params ISpecification[] specifications)
31 | {
32 | return specifications.Aggregate(New(), (current, specification) => current.And(specification));
33 | }
34 |
35 | public static ISpecification None(params ISpecification[] specifications)
36 | {
37 | return specifications.Aggregate(New(), (current, specification) => current.And(specification)).Not();
38 | }
39 |
40 | public static ISpecification Any(params ISpecification[] specifications)
41 | {
42 | return specifications.Aggregate(New(), (current, specification) => current.Or(specification));
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/EF6/LinqBuilder.EF6.Tests/Data/TestDb.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data.SQLite;
4 |
5 | namespace LinqBuilder.EF6.Tests.Data;
6 |
7 | public sealed class TestDb : IDisposable
8 | {
9 | private readonly SQLiteConnection _connection;
10 |
11 | public TestDb()
12 | {
13 | _connection = CreateSqliteConnection();
14 | _connection.Open();
15 | Context = new TestDbContext(_connection);
16 | }
17 |
18 | public TestDbContext Context { get; }
19 |
20 | // Tear down in-memory database.
21 | public void Dispose()
22 | {
23 | Context.Dispose();
24 | _connection.Dispose();
25 | }
26 |
27 | public void AddEntity(int value1, int value2, int? childValue = null)
28 | {
29 | var entity = new SomeEntity
30 | {
31 | Value1 = value1,
32 | Value2 = value2,
33 | };
34 |
35 | if (childValue.HasValue)
36 | {
37 | entity.ChildEntities = new List
38 | {
39 | new()
40 | {
41 | Value = childValue.Value,
42 | },
43 | };
44 | }
45 |
46 | Context.Entities.Add(entity);
47 | }
48 |
49 | private static SQLiteConnection CreateSqliteConnection()
50 | {
51 | var connectionStringBuilder = new SQLiteConnectionStringBuilder
52 | {
53 | DataSource = ":memory:",
54 | ForeignKeys = true,
55 | };
56 | var connectionString = connectionStringBuilder.ConnectionString;
57 | return new SQLiteConnection(connectionString);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/LinqBuilder/MultiSpecification{TEntity1,TEntity2}.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 | using LinqBuilder.Internal;
4 |
5 | namespace LinqBuilder
6 | {
7 | public abstract class MultiSpecification
8 | : ISpecification
9 | where TEntity1 : class
10 | where TEntity2 : class
11 | {
12 | public SpecificationBase Internal => new SpecificationBase(For());
13 |
14 | // ReSharper disable once MemberCanBeProtected.Global
15 | public abstract Expression> AsExpressionForEntity1();
16 |
17 | // ReSharper disable once MemberCanBeProtected.Global
18 | public abstract Expression> AsExpressionForEntity2();
19 |
20 | public Specification For()
21 | where TEntity : class
22 | {
23 | var result = Transform();
24 | if (result == null)
25 | {
26 | throw new InvalidOperationException("Type is not defined in specification!");
27 | }
28 |
29 | return result;
30 | }
31 |
32 | protected virtual Specification? Transform()
33 | where TEntity : class
34 | {
35 | object? specification = null;
36 |
37 | if (typeof(TEntity) == typeof(TEntity1))
38 | {
39 | specification = new Specification(AsExpressionForEntity1());
40 | }
41 | else if (typeof(TEntity) == typeof(TEntity2))
42 | {
43 | specification = new Specification(AsExpressionForEntity2());
44 | }
45 |
46 | return (Specification?)specification;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/LinqBuilder/OrderBy/LinqExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace LinqBuilder.OrderBy
6 | {
7 | public static class LinqExtensions
8 | {
9 | public static IOrderedQueryable OrderBy(this IQueryable query, IOrderSpecification orderSpecification)
10 | where TEntity : class
11 | {
12 | if (orderSpecification == null)
13 | {
14 | throw new ArgumentNullException(nameof(orderSpecification));
15 | }
16 |
17 | return orderSpecification.InvokeSort(query);
18 | }
19 |
20 | public static IOrderedEnumerable OrderBy(this IEnumerable collection, IOrderSpecification orderSpecification)
21 | where TEntity : class
22 | {
23 | if (orderSpecification == null)
24 | {
25 | throw new ArgumentNullException(nameof(orderSpecification));
26 | }
27 |
28 | return orderSpecification.InvokeSort(collection);
29 | }
30 |
31 | public static IOrderedQueryable ThenBy(this IOrderedQueryable query, IOrderSpecification orderSpecification)
32 | where TEntity : class
33 | {
34 | if (orderSpecification == null)
35 | {
36 | throw new ArgumentNullException(nameof(orderSpecification));
37 | }
38 |
39 | return orderSpecification.InvokeSort(query);
40 | }
41 |
42 | public static IOrderedEnumerable ThenBy(this IOrderedEnumerable collection, IOrderSpecification orderSpecification)
43 | where TEntity : class
44 | {
45 | if (orderSpecification == null)
46 | {
47 | throw new ArgumentNullException(nameof(orderSpecification));
48 | }
49 |
50 | return orderSpecification.InvokeSort(collection);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/LinqBuilder/Internal/SpecificationBase.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using LinqBuilder.OrderBy;
4 |
5 | namespace LinqBuilder.Internal
6 | {
7 | public sealed class SpecificationBase : IOrderedSpecification
8 | where TEntity : class
9 | {
10 | private readonly List> _orderSpecifications;
11 |
12 | public SpecificationBase(IQuerySpecification querySpecification)
13 | {
14 | _orderSpecifications = new List>();
15 | QuerySpecification = querySpecification;
16 | }
17 |
18 | public SpecificationBase(IOrderSpecification orderSpecification)
19 | {
20 | _orderSpecifications = new List> { orderSpecification };
21 | QuerySpecification = new DummySpecification();
22 | }
23 |
24 | public SpecificationBase(IQuerySpecification querySpecification, IEnumerable> orderSpecifications)
25 | {
26 | _orderSpecifications = orderSpecifications.ToList();
27 | QuerySpecification = querySpecification;
28 | }
29 |
30 | public IQuerySpecification QuerySpecification { get; set; }
31 |
32 | public int? Skip { get; set; }
33 |
34 | public int? Take { get; set; }
35 |
36 | public IReadOnlyList> OrderSpecifications => _orderSpecifications;
37 |
38 | public SpecificationBase Internal => this;
39 |
40 | public void AddOrderSpecifications(params IOrderSpecification[] specifications)
41 | {
42 | _orderSpecifications.AddRange(specifications);
43 | }
44 |
45 | public ISpecification Clone()
46 | {
47 | return new SpecificationBase(QuerySpecification, _orderSpecifications)
48 | {
49 | Skip = Skip,
50 | Take = Take,
51 | };
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore.Tests/Data/TestDb.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Microsoft.Data.Sqlite;
4 | using Microsoft.EntityFrameworkCore;
5 |
6 | namespace LinqBuilder.EFCore.Tests.Data;
7 |
8 | public sealed class TestDb : IDisposable
9 | {
10 | private readonly SqliteConnection _connection;
11 |
12 | public TestDb()
13 | {
14 | // We need to hold the SQLite connection open to force the in-memory database not to reset.
15 | _connection = CreateSqliteConnection();
16 | _connection.Open();
17 |
18 | // Create the context and ensure the schema is created.
19 | Context = CreateContext();
20 | Context.Database.EnsureCreated();
21 | }
22 |
23 | public TestDbContext Context { get; }
24 |
25 | // Tear down in-memory database.
26 | public void Dispose()
27 | {
28 | Context.Dispose();
29 | _connection.Dispose();
30 | }
31 |
32 | public void AddEntity(int value1, int value2, int? childValue = null)
33 | {
34 | var entity = new SomeEntity
35 | {
36 | Value1 = value1,
37 | Value2 = value2,
38 | };
39 |
40 | if (childValue.HasValue)
41 | {
42 | entity.ChildEntities = new List
43 | {
44 | new()
45 | {
46 | Value = childValue.Value,
47 | },
48 | };
49 | }
50 |
51 | Context.Entities.Add(entity);
52 | }
53 |
54 | private static SqliteConnection CreateSqliteConnection()
55 | {
56 | var connectionStringBuilder = new SqliteConnectionStringBuilder
57 | {
58 | DataSource = ":memory:",
59 | };
60 | var connectionString = connectionStringBuilder.ToString();
61 | return new SqliteConnection(connectionString);
62 | }
63 |
64 | private TestDbContext CreateContext()
65 | {
66 | var optionsBuilder = new DbContextOptionsBuilder();
67 | optionsBuilder.UseSqlite(_connection);
68 | return new TestDbContext(optionsBuilder.Options);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/Internal/SpecificationBaseTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using FluentAssertions;
4 | using LinqBuilder.Internal;
5 | using LinqBuilder.OrderBy;
6 | using LinqBuilder.Tests.Data;
7 | using Xunit;
8 |
9 | namespace LinqBuilder.Tests.Internal;
10 |
11 | public class SpecificationBaseTests
12 | {
13 | [Fact]
14 | public void Configuration_NewOrderSpecification_ShouldBeCorrectlyConfigured()
15 | {
16 | var configuration = new SpecificationBase(new OrderSpecification(x => x.Value1));
17 | configuration.QuerySpecification.Internal.Should().NotBeNull();
18 | configuration.QuerySpecification.Should().NotBeNull();
19 | configuration.QuerySpecification.AsExpression().Should().BeNull();
20 | configuration.QuerySpecification.AsFunc().Should().BeNull();
21 | configuration.OrderSpecifications.Count.Should().Be(1);
22 | }
23 |
24 | [Fact]
25 | public void Configuration_NewSpecification_ShouldBeCorrectlyConfigured()
26 | {
27 | var configuration = new SpecificationBase(new Specification());
28 | configuration.QuerySpecification.Internal.Should().NotBeNull();
29 | configuration.QuerySpecification.Should().NotBeNull();
30 | configuration.QuerySpecification.AsExpression().Should().BeNull();
31 | configuration.QuerySpecification.AsFunc().Should().BeNull();
32 | configuration.OrderSpecifications.Any().Should().BeFalse();
33 | }
34 |
35 | [Fact]
36 | public void Configuration_NewOrderSpecificationAndNewSpecification_ShouldBeCorrectlyConfigured()
37 | {
38 | var configuration = new SpecificationBase(new Specification(), new List>
39 | {
40 | new OrderSpecification(x => x.Value1),
41 | });
42 | configuration.QuerySpecification.Internal.Should().NotBeNull();
43 | configuration.QuerySpecification.Should().NotBeNull();
44 | configuration.QuerySpecification.AsExpression().Should().BeNull();
45 | configuration.QuerySpecification.AsFunc().Should().BeNull();
46 | configuration.OrderSpecifications.Count.Should().Be(1);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Directory.Packages.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 |
6 |
7 | all
8 | runtime; build; native; contentfiles; analyzers; buildtransitive
9 |
10 |
11 | all
12 | runtime; build; native; contentfiles; analyzers; buildtransitive
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | all
21 | runtime; build; native; contentfiles; analyzers; buildtransitive
22 |
23 |
24 |
25 |
26 |
27 | all
28 | runtime; build; native; contentfiles; analyzers; buildtransitive
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text eol=lf
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/OrderBy/LinqExtensionsTests.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using FluentAssertions;
3 | using LinqBuilder.OrderBy;
4 | using LinqBuilder.Tests.Data;
5 | using Xunit;
6 |
7 | namespace LinqBuilder.Tests.OrderBy;
8 |
9 | public class LinqExtensionsTests
10 | {
11 | private readonly IOrderSpecification _orderValue1Asc = OrderSpec.New(entity => entity.Value1);
12 | private readonly IOrderSpecification _orderValue2Asc = OrderSpec.New(entity => entity.Value2);
13 |
14 | private readonly Fixture _fixture;
15 |
16 | public LinqExtensionsTests()
17 | {
18 | _fixture = new Fixture();
19 | _fixture.AddToCollection(3, 1, 1);
20 | _fixture.AddToCollection(1, 1, 1);
21 | _fixture.AddToCollection(2, 2, 1);
22 | _fixture.AddToCollection(2, 1, 1);
23 | }
24 |
25 | [Fact]
26 | public void OrderBy_IQueryable_ShouldReturnCorrectResult()
27 | {
28 | var result = _fixture.Query
29 | .OrderBy(_orderValue1Asc)
30 | .ToList();
31 |
32 | result.Count.Should().Be(4);
33 | result[0].Value1.Should().Be(1);
34 | result[1].Value1.Should().Be(2);
35 | result[1].Value2.Should().Be(2);
36 | result[2].Value1.Should().Be(2);
37 | result[2].Value2.Should().Be(1);
38 | result[3].Value1.Should().Be(3);
39 | }
40 |
41 | [Fact]
42 | public void OrderBy_IEnumerable_ShouldReturnCorrectResult()
43 | {
44 | var result = _fixture.Collection
45 | .OrderBy(_orderValue1Asc)
46 | .ToList();
47 |
48 | result.Count.Should().Be(4);
49 | result[0].Value1.Should().Be(1);
50 | result[1].Value1.Should().Be(2);
51 | result[1].Value2.Should().Be(2);
52 | result[2].Value1.Should().Be(2);
53 | result[2].Value2.Should().Be(1);
54 | result[3].Value1.Should().Be(3);
55 | }
56 |
57 | [Fact]
58 | public void ThenBy_IQueryable_ShouldReturnCorrectResult()
59 | {
60 | var result = _fixture.Query
61 | .OrderBy(_orderValue1Asc)
62 | .ThenBy(_orderValue2Asc)
63 | .ToList();
64 |
65 | result.Count.Should().Be(4);
66 | result[0].Value1.Should().Be(1);
67 | result[1].Value1.Should().Be(2);
68 | result[1].Value2.Should().Be(1);
69 | result[2].Value1.Should().Be(2);
70 | result[2].Value2.Should().Be(2);
71 | result[3].Value1.Should().Be(3);
72 | }
73 |
74 | [Fact]
75 | public void ThenBy_IEnumerable_ShouldReturnCorrectResult()
76 | {
77 | var result = _fixture.Collection
78 | .OrderBy(_orderValue1Asc)
79 | .ThenBy(_orderValue2Asc)
80 | .ToList();
81 |
82 | result.Count.Should().Be(4);
83 | result[0].Value1.Should().Be(1);
84 | result[1].Value1.Should().Be(2);
85 | result[1].Value2.Should().Be(1);
86 | result[2].Value1.Should().Be(2);
87 | result[2].Value2.Should().Be(2);
88 | result[3].Value1.Should().Be(3);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/DynamicSpecificationTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using LinqBuilder.Tests.Data;
3 | using LinqBuilder.Tests.Data.Specifications;
4 | using Xunit;
5 |
6 | namespace LinqBuilder.Tests;
7 |
8 | public class DynamicSpecificationTests
9 | {
10 | [Theory]
11 | [ClassData(typeof(TestData))]
12 | public void IsSatisfiedBy_TheoryData(Entity entity, bool expected)
13 | {
14 | new MultipleValueSpecification4(3, 5, 4, 2)
15 | .IsSatisfiedBy(entity)
16 | .Should().Be(expected);
17 | }
18 |
19 | [Fact]
20 | public void Constructor_MultipleValueSpecification1_ShouldHaveCorrectValue()
21 | {
22 | var specification = new MultipleValueSpecification1(1);
23 | specification.Value.Should().Be(1);
24 | }
25 |
26 | [Fact]
27 | public void Constructor_MultipleValueSpecification2_ShouldHaveCorrectValues()
28 | {
29 | var specification = new MultipleValueSpecification2(1, 2);
30 | specification.Value1.Should().Be(1);
31 | specification.Value2.Should().Be(2);
32 | }
33 |
34 | [Fact]
35 | public void Constructor_MultipleValueSpecification3_ShouldHaveCorrectValues()
36 | {
37 | var specification = new MultipleValueSpecification3(1, 2, 3);
38 | specification.Value1.Should().Be(1);
39 | specification.Value2.Should().Be(2);
40 | specification.Value3.Should().Be(3);
41 | }
42 |
43 | [Fact]
44 | public void Constructor_MultipleValueSpecification4_ShouldHaveCorrectValues()
45 | {
46 | var specification = new MultipleValueSpecification4(1, 2, 3, 4);
47 | specification.Value1.Should().Be(1);
48 | specification.Value2.Should().Be(2);
49 | specification.Value3.Should().Be(3);
50 | specification.Value4.Should().Be(4);
51 | }
52 |
53 | [Fact]
54 | public void Set_MultipleValueSpecification1_ShouldHaveCorrectValue()
55 | {
56 | var specification = new MultipleValueSpecification1().Set(1);
57 | specification.Value.Should().Be(1);
58 | }
59 |
60 | [Fact]
61 | public void Set_MultipleValueSpecification2_ShouldHaveCorrectValues()
62 | {
63 | var specification = new MultipleValueSpecification2().Set(1, 2);
64 | specification.Value1.Should().Be(1);
65 | specification.Value2.Should().Be(2);
66 | }
67 |
68 | [Fact]
69 | public void Set_MultipleValueSpecification3_ShouldHaveCorrectValues()
70 | {
71 | var specification = new MultipleValueSpecification3().Set(1, 2, 3);
72 | specification.Value1.Should().Be(1);
73 | specification.Value2.Should().Be(2);
74 | specification.Value3.Should().Be(3);
75 | }
76 |
77 | [Fact]
78 | public void Set_MultipleValueSpecification4_ShouldHaveCorrectValues()
79 | {
80 | var specification = new MultipleValueSpecification4().Set(1, 2, 3, 4);
81 | specification.Value1.Should().Be(1);
82 | specification.Value2.Should().Be(2);
83 | specification.Value3.Should().Be(3);
84 | specification.Value4.Should().Be(4);
85 | }
86 |
87 | private sealed class TestData : EntityTheoryData
88 | {
89 | public TestData()
90 | {
91 | AddEntity(3, 5, 4, 2, true);
92 | AddEntity(3, 4, 4, 2, false);
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/SpecificationTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using LinqBuilder.Tests.Data;
3 | using Xunit;
4 |
5 | namespace LinqBuilder.Tests;
6 |
7 | public class SpecificationTests
8 | {
9 | private readonly ISpecification _emptySpecification = Spec.New();
10 | private readonly ISpecification _value1ShouldBe1 = Spec.New(entity => entity.Value1 == 1);
11 | private readonly ISpecification _value2ShouldBe2 = Spec.New(entity => entity.Value2 == 2);
12 |
13 | [Fact]
14 | public void Constructor_DefaultExpression_ShouldBeTrue()
15 | {
16 | _emptySpecification
17 | .IsSatisfiedBy(new Entity())
18 | .Should().BeTrue();
19 | }
20 |
21 | [Fact]
22 | public void Constructor_InlineExpression_ShouldBeTrue()
23 | {
24 | _value1ShouldBe1
25 | .IsSatisfiedBy(new Entity { Value1 = 1 })
26 | .Should().BeTrue();
27 | }
28 |
29 | [Fact]
30 | public void Constructor_InlineExpression_ShouldBeFalse()
31 | {
32 | _value1ShouldBe1
33 | .IsSatisfiedBy(new Entity { Value1 = 2 })
34 | .Should().BeFalse();
35 | }
36 |
37 | [Fact]
38 | public void New_DefaultExpression_ShouldBeTrue()
39 | {
40 | _emptySpecification
41 | .IsSatisfiedBy(new Entity())
42 | .Should().BeTrue();
43 | }
44 |
45 | [Fact]
46 | public void New_InlineExpression_ShouldBeTrue()
47 | {
48 | _value1ShouldBe1
49 | .IsSatisfiedBy(new Entity { Value1 = 1 })
50 | .Should().BeTrue();
51 | }
52 |
53 | [Fact]
54 | public void New_InlineExpression_ShouldBeFalse()
55 | {
56 | _value1ShouldBe1
57 | .IsSatisfiedBy(new Entity { Value1 = 2 })
58 | .Should().BeFalse();
59 | }
60 |
61 | [Fact]
62 | public void All_Specifications_ShouldBeTrue()
63 | {
64 | Specification.All(_value1ShouldBe1, _value2ShouldBe2)
65 | .IsSatisfiedBy(new Entity { Value1 = 1, Value2 = 2 });
66 | }
67 |
68 | [Fact]
69 | public void All_Specifications_ShouldBeFalse()
70 | {
71 | Specification.All(_value1ShouldBe1, _value2ShouldBe2)
72 | .IsSatisfiedBy(new Entity { Value1 = 1, Value2 = 1 });
73 | }
74 |
75 | [Fact]
76 | public void None_Specifications_ShouldBeTrue()
77 | {
78 | Specification.None(_value1ShouldBe1, _value2ShouldBe2)
79 | .IsSatisfiedBy(new Entity { Value1 = 2, Value2 = 1 });
80 | }
81 |
82 | [Fact]
83 | public void None_Specifications_ShouldBeFalse()
84 | {
85 | Specification.None(_value1ShouldBe1, _value2ShouldBe2)
86 | .IsSatisfiedBy(new Entity { Value1 = 1, Value2 = 2 });
87 | }
88 |
89 | [Fact]
90 | public void Any_Specifications_ShouldBeTrue()
91 | {
92 | Specification.Any(_value1ShouldBe1, _value2ShouldBe2)
93 | .IsSatisfiedBy(new Entity { Value1 = 1, Value2 = 1 });
94 | }
95 |
96 | [Fact]
97 | public void Any_Specifications_ShouldBeFalse()
98 | {
99 | Specification.Any(_value1ShouldBe1, _value2ShouldBe2)
100 | .IsSatisfiedBy(new Entity { Value1 = 2, Value2 = 1 });
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/LinqBuilder.Tests/OrderBy/OrderSpecificationTests.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using FluentAssertions;
3 | using LinqBuilder.OrderBy;
4 | using LinqBuilder.Tests.Data;
5 | using Xunit;
6 |
7 | namespace LinqBuilder.Tests.OrderBy;
8 |
9 | public class OrderSpecificationTests
10 | {
11 | private readonly IOrderSpecification _orderValue1Asc = OrderSpec.New(entity => entity.Value1);
12 | private readonly IOrderSpecification _orderValue1Desc = OrderSpec.New(entity => entity.Value1, Sort.Descending);
13 |
14 | private readonly Fixture _fixture;
15 |
16 | public OrderSpecificationTests()
17 | {
18 | _fixture = new Fixture();
19 | _fixture.AddToCollection(3, 1, 1);
20 | _fixture.AddToCollection(1, 1, 1);
21 | _fixture.AddToCollection(2, 1, 1);
22 | }
23 |
24 | [Fact]
25 | public void Constructor_InlineExpression__ShouldReturnOrderedList()
26 | {
27 | var result = _fixture.Query.OrderBy(_orderValue1Asc).ToList();
28 | result[0].Value1.Should().Be(1);
29 | result[1].Value1.Should().Be(2);
30 | result[2].Value1.Should().Be(3);
31 | }
32 |
33 | [Fact]
34 | public void Constructor_InlineExpression_ShouldReturnOrderedList()
35 | {
36 | var result = _fixture.Query.OrderBy(_orderValue1Desc).ToList();
37 | result[0].Value1.Should().Be(3);
38 | result[1].Value1.Should().Be(2);
39 | result[2].Value1.Should().Be(1);
40 | }
41 |
42 | [Fact]
43 | public void New_InlineExpression__ShouldReturnOrderedList()
44 | {
45 | var result = _fixture.Query.OrderBy(_orderValue1Asc).ToList();
46 | result[0].Value1.Should().Be(1);
47 | result[1].Value1.Should().Be(2);
48 | result[2].Value1.Should().Be(3);
49 | }
50 |
51 | [Fact]
52 | public void New_InlineExpression_ShouldReturnOrderedList()
53 | {
54 | var result = _fixture.Query.OrderBy(_orderValue1Desc).ToList();
55 | result[0].Value1.Should().Be(3);
56 | result[1].Value1.Should().Be(2);
57 | result[2].Value1.Should().Be(1);
58 | }
59 |
60 | [Fact]
61 | public void InvokeSort_IQueryableAscending_ShouldReturnOrderedList()
62 | {
63 | var result = _orderValue1Asc.InvokeSort(_fixture.Query).ToList();
64 | result[0].Value1.Should().Be(1);
65 | result[1].Value1.Should().Be(2);
66 | result[2].Value1.Should().Be(3);
67 | }
68 |
69 | [Fact]
70 | public void InvokeSort_IEnumerableAscending_ShouldReturnOrderedList()
71 | {
72 | var result = _orderValue1Asc.InvokeSort(_fixture.Collection).ToList();
73 | result[0].Value1.Should().Be(1);
74 | result[1].Value1.Should().Be(2);
75 | result[2].Value1.Should().Be(3);
76 | }
77 |
78 | [Fact]
79 | public void InvokeSort_IQueryableDescending_ShouldReturnOrderedList()
80 | {
81 | var result = _orderValue1Desc.InvokeSort(_fixture.Query).ToList();
82 | result[0].Value1.Should().Be(3);
83 | result[1].Value1.Should().Be(2);
84 | result[2].Value1.Should().Be(1);
85 | }
86 |
87 | [Fact]
88 | public void InvokeSort_IEnumerableDescending_ShouldReturnOrderedList()
89 | {
90 | var result = _orderValue1Desc.InvokeSort(_fixture.Collection).ToList();
91 | result[0].Value1.Should().Be(3);
92 | result[1].Value1.Should().Be(2);
93 | result[2].Value1.Should().Be(1);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/LinqBuilder/OrderBy/OrderSpecification.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using LinqBuilder.Internal;
6 |
7 | namespace LinqBuilder.OrderBy
8 | {
9 | public class OrderSpecification : IOrderSpecification
10 | where TEntity : class
11 | {
12 | private readonly Sort _sort;
13 | private readonly Expression>? _expression;
14 | private Func? _func;
15 |
16 | public OrderSpecification(Expression> expression, Sort sort = Sort.Ascending)
17 | : this(sort)
18 | {
19 | _expression = expression;
20 | }
21 |
22 | protected OrderSpecification(Sort sort = Sort.Ascending)
23 | {
24 | _sort = sort;
25 | }
26 |
27 | public SpecificationBase Internal => new SpecificationBase(this);
28 |
29 | public static IOrderSpecification New(Expression> expression, Sort sort = Sort.Ascending)
30 | {
31 | return new OrderSpecification(expression, sort);
32 | }
33 |
34 | // ReSharper disable once MemberCanBeProtected.Global
35 | public virtual Expression>? AsExpression()
36 | {
37 | return _expression;
38 | }
39 |
40 | // ReSharper disable once MemberCanBePrivate.Global
41 | public Func? AsFunc()
42 | {
43 | var expression = AsExpression();
44 | if (expression == null)
45 | {
46 | return null;
47 | }
48 |
49 | return _func ??= expression.Compile();
50 | }
51 |
52 | public IOrderedQueryable InvokeSort(IQueryable query)
53 | {
54 | var expression = AsExpression();
55 | if (expression == null)
56 | {
57 | throw new InvalidOperationException("AsExpression returns null");
58 | }
59 |
60 | return _sort == Sort.Descending
61 | ? query.OrderByDescending(expression)
62 | : query.OrderBy(expression);
63 | }
64 |
65 | public IOrderedEnumerable InvokeSort(IEnumerable collection)
66 | {
67 | var func = AsFunc();
68 | if (func == null)
69 | {
70 | throw new InvalidOperationException("AsExpression returns null");
71 | }
72 |
73 | return _sort == Sort.Descending
74 | ? collection.OrderByDescending(func)
75 | : collection.OrderBy(func);
76 | }
77 |
78 | public IOrderedQueryable InvokeSort(IOrderedQueryable query)
79 | {
80 | var expression = AsExpression();
81 | if (expression == null)
82 | {
83 | throw new InvalidOperationException("AsExpression returns null");
84 | }
85 |
86 | return _sort == Sort.Descending
87 | ? query.ThenByDescending(expression)
88 | : query.ThenBy(expression);
89 | }
90 |
91 | public IOrderedEnumerable InvokeSort(IOrderedEnumerable collection)
92 | {
93 | var func = AsFunc();
94 | if (func == null)
95 | {
96 | throw new InvalidOperationException("AsExpression returns null");
97 | }
98 |
99 | return _sort == Sort.Descending
100 | ? collection.ThenByDescending(func)
101 | : collection.ThenBy(func);
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/EFCore/LinqBuilder.EFCore/EntityFrameworkCoreExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Microsoft.EntityFrameworkCore;
5 |
6 | namespace LinqBuilder.EFCore;
7 |
8 | public static class EntityFrameworkCoreExtensions
9 | {
10 | public static async Task AnyAsync(this IQueryable query, ISpecification specification)
11 | where TEntity : class
12 | {
13 | if (specification == null)
14 | {
15 | throw new ArgumentNullException(nameof(specification));
16 | }
17 |
18 | var expression = specification.Internal.QuerySpecification.AsExpression();
19 | return await (expression == null ? query.AnyAsync() : query.AnyAsync(expression)).ConfigureAwait(false);
20 | }
21 |
22 | public static async Task AllAsync(this IQueryable query, ISpecification specification)
23 | where TEntity : class
24 | {
25 | if (specification == null)
26 | {
27 | throw new ArgumentNullException(nameof(specification));
28 | }
29 |
30 | var expression = specification.Internal.QuerySpecification.AsExpression();
31 | return expression == null || await query.AllAsync(expression).ConfigureAwait(false);
32 | }
33 |
34 | public static async Task CountAsync(this IQueryable query, ISpecification