diff --git a/src/Expressions.Reading/Queries/EntityQueryModel.cs b/src/Expressions.Reading/Queries/EntityQueryModel.cs index af74f18..c31e72b 100644 --- a/src/Expressions.Reading/Queries/EntityQueryModel.cs +++ b/src/Expressions.Reading/Queries/EntityQueryModel.cs @@ -1,7 +1,6 @@ -using Raiqub.Expressions.Queries.Internal; - -namespace Raiqub.Expressions.Queries; +namespace Raiqub.Expressions.Queries; +[Obsolete("Use QueryModel static class instead", true)] public static class EntityQueryModel { /// @@ -10,12 +9,12 @@ public static class EntityQueryModel /// The type of the elements of query model. /// A query model for the specified type . public static IEntityQueryModel Create() where T : class => - AllQueryModel.Instance; + QueryModel.AllOfEntity(); public static IEntityQueryModel Create(Specification specification) where T : class => - new SpecificationQueryModel(specification); + QueryModel.CreateForEntity(specification); public static IEntityQueryModel Create( Func, IQueryable> queryModel) where TSource : class => - new AnonymousEntityQueryModel(queryModel); + QueryModel.CreateForEntity(queryModel); } diff --git a/src/Expressions.Reading/Queries/IQueryModel.cs b/src/Expressions.Reading/Queries/IQueryModel.cs index cc5f298..1008cd9 100644 --- a/src/Expressions.Reading/Queries/IQueryModel.cs +++ b/src/Expressions.Reading/Queries/IQueryModel.cs @@ -1,7 +1,7 @@ namespace Raiqub.Expressions.Queries; /// -/// Represents a query model that can execute a query aggregating data sources of multiple entities +/// Represents a query strategy that can execute a query against one or more data sources /// and return a result of type . /// /// The type of the query result. diff --git a/src/Expressions.Reading/Queries/QueryModel.cs b/src/Expressions.Reading/Queries/QueryModel.cs index 5f57cd3..67cacf9 100644 --- a/src/Expressions.Reading/Queries/QueryModel.cs +++ b/src/Expressions.Reading/Queries/QueryModel.cs @@ -1,9 +1,85 @@ -using Raiqub.Expressions.Queries.Internal; +using System.Linq.Expressions; +using Raiqub.Expressions.Queries.Internal; namespace Raiqub.Expressions.Queries; public static class QueryModel { + /// Returns a query model for the specified type that returns all items. + /// The type of the data source. + /// A query model for the specified type . + public static IEntityQueryModel AllOfEntity() where TSource : class => + AllQueryModel.Instance; + + /// Creates a new query strategy from the specified function. + /// A function defining the query strategy. + /// The type of the query result. + /// A new query strategy. public static IQueryModel Create(Func> queryModel) => new AnonymousQueryModel(queryModel); + + /// + /// Creates a new entity query strategy that returns items from data source of type . + /// It only returns the items that satisfies the specified business rule. + /// + /// + /// The type of the data source. + /// A new entity query strategy. + public static IEntityQueryModel CreateForEntity(Specification specification) where TSource : class => + new SpecificationQueryModel(specification); + + /// Creates a new entity query strategy from the specified function. + /// A function defining the query strategy. + /// The type of the data source. + /// The type of the query result. + /// A new entity query strategy. + public static IEntityQueryModel CreateForEntity( + Func, IQueryable> queryModel) where TSource : class => + new AnonymousEntityQueryModel(queryModel); + + /// + /// Creates a new query model that returns all items for the nested collection of the specified entity. + /// + /// A projection function to retrieve nested collection. + /// The type of entity to query. + /// The type of nested collection from the specified entity. + /// A new query model. + public static IEntityQueryModel CreateNested( + Expression>> selector) + where TSource : class + where TNested : class => + new NestingEntityQueryModel(selector, AllOfEntity()); + + /// + /// Creates a new query model that returns the items of the nested collection of the specified entity. + /// It only returns the nested items that satisfies the specified business rule. + /// + /// A projection function to retrieve nested collection. + /// The specification used for query. + /// The type of entity to query. + /// The type of nested collection from the specified entity. + /// A new query model. + public static IEntityQueryModel CreateNested( + Expression>> selector, + Specification specification) + where TSource : class + where TNested : class => + new NestingEntityQueryModel(selector, CreateForEntity(specification)); + + /// + /// Creates a new query model for the nested collection of the specified entity. + /// The nested items are then queried using the specified query model. + /// + /// A projection function to retrieve nested collection. + /// The query model to use with nested elements. + /// The type of entity to query. + /// The type of nested collection from the specified entity. + /// The type of result to return. + /// A new query model. + public static IEntityQueryModel CreateNested( + Expression>> selector, + IEntityQueryModel queryModel) + where TSource : class + where TNested : class => + new NestingEntityQueryModel(selector, queryModel); } diff --git a/src/Expressions.Reading/Sessions/DbQuerySessionExtensions.cs b/src/Expressions.Reading/Sessions/DbQuerySessionExtensions.cs index 58a606c..e274046 100644 --- a/src/Expressions.Reading/Sessions/DbQuerySessionExtensions.cs +++ b/src/Expressions.Reading/Sessions/DbQuerySessionExtensions.cs @@ -18,7 +18,7 @@ public static IDbQuery Query( return session.Query(AllQueryModel.Instance); } - /// Creates a new query using the criteria specification. + /// Creates a new query using the specified business rule. /// The session to create query from. /// The specification used for query. /// The type of entity to query. @@ -31,22 +31,28 @@ public static IDbQuery Query( return session.Query(new SpecificationQueryModel(specification)); } + /// Creates a new query using the specified entity query model. + /// The session to create query from. + /// The type of entity to query. + /// The type of result to return. + /// The query model to use. + /// A new query object. + /// Thrown when is null. public static IDbQuery Query( this IDbQuerySession session, IEntityQueryModel entityQueryModel) where TEntity : class { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(entityQueryModel); +#else + if (entityQueryModel is null) throw new ArgumentNullException(nameof(entityQueryModel)); +#endif + return session.Query(entityQueryModel.ToQueryModel()); } - /// - /// Creates a new query for the nested collection of the specified entity. - /// - /// The session to create query from. - /// A projection function to retrieve entity collection. - /// The type of entity to query. - /// The type of nested collection from the specified entity. - /// A new query object. + [Obsolete("Use the CreateNested method from QueryModel static class", true)] public static IDbQuery QueryNested( this IDbQuerySession session, Expression>> selector) @@ -54,19 +60,10 @@ public static IDbQuery QueryNested( where TNested : class { return session.Query( - new NestingEntityQueryModel(selector, EntityQueryModel.Create())); + new NestingEntityQueryModel(selector, QueryModel.AllOfEntity())); } - /// - /// Creates a new query for the nested collection of the specified entity using the specified query model. - /// - /// The session to create query from. - /// A projection function to retrieve entity collection. - /// The query model to use. - /// The type of entity to query. - /// The type of nested collection from the specified entity. - /// The type of result to return. - /// A new query object. + [Obsolete("Use the CreateNested method from QueryModel static class", true)] public static IDbQuery QueryNested( this IDbQuerySession session, Expression>> selector, @@ -77,15 +74,7 @@ public static IDbQuery QueryNested( return session.Query(new NestingEntityQueryModel(selector, queryModel)); } - /// - /// Creates a new query for the nested collection of the specified entity using the criteria specification. - /// - /// The session to create query from. - /// A projection function to retrieve entity collection. - /// The specification used for query. - /// The type of entity to query. - /// The type of nested collection from the specified entity. - /// A new query object. + [Obsolete("Use the CreateNested method from QueryModel static class", true)] public static IDbQuery QueryNested( this IDbQuerySession session, Expression>> selector, @@ -94,6 +83,8 @@ public static IDbQuery QueryNested( where TNested : class { return session.Query( - new NestingEntityQueryModel(selector, EntityQueryModel.Create(specification))); + new NestingEntityQueryModel( + selector, + QueryModel.CreateForEntity(specification))); } } diff --git a/tests/Common.Tests/Queries/QueryTestBase.cs b/tests/Common.Tests/Queries/QueryTestBase.cs index 712acfd..6215967 100644 --- a/tests/Common.Tests/Queries/QueryTestBase.cs +++ b/tests/Common.Tests/Queries/QueryTestBase.cs @@ -48,7 +48,7 @@ public async Task CountAllShouldReturn3() { await AddBlogs(GetBlogs()); await using var session = CreateSession(); - var query = session.QueryNested((Blog b) => b.Posts); + var query = session.Query(QueryModel.CreateNested((Blog b) => b.Posts)); long count = await query.CountAsync(); @@ -92,7 +92,7 @@ public async Task ToListShouldReturnAll() { await AddBlogs(GetBlogs()); await using var session = CreateSession(); - var query = session.Query(EntityQueryModel.Create((IQueryable source) => source.SelectMany(b => b.Posts))); + var query = session.Query(QueryModel.CreateForEntity((IQueryable source) => source.SelectMany(b => b.Posts))); var posts = await query.ToListAsync(); @@ -106,7 +106,7 @@ public async Task ToListShouldReturnExpected() await AddBlogs(GetBlogs()); await using var session = CreateSession(); var query = session.Query( - EntityQueryModel.Create( + QueryModel.CreateForEntity( (IQueryable source) => source .SelectMany(b => b.Posts) .Where(p => p.Content.StartsWith("You")))); diff --git a/tests/Common.Tests/Sessions/SessionFactoryTestBase.cs b/tests/Common.Tests/Sessions/SessionFactoryTestBase.cs index cfafd9e..431bb28 100644 --- a/tests/Common.Tests/Sessions/SessionFactoryTestBase.cs +++ b/tests/Common.Tests/Sessions/SessionFactoryTestBase.cs @@ -128,7 +128,7 @@ public async Task UpdateRangeAndSaveShouldCommitChanges() await using (var session = sessionFactory.Create()) { finalBlogs = await session - .Query(EntityQueryModel.Create((IQueryable source) => source.OrderBy(b => b.Name))) + .Query(QueryModel.CreateForEntity((IQueryable source) => source.OrderBy(b => b.Name))) .ToListAsync(); } diff --git a/tests/Expressions.Reading.Tests/Queries/QueryModelTest.cs b/tests/Expressions.Reading.Tests/Queries/QueryModelTest.cs index 403890d..954a57d 100644 --- a/tests/Expressions.Reading.Tests/Queries/QueryModelTest.cs +++ b/tests/Expressions.Reading.Tests/Queries/QueryModelTest.cs @@ -10,7 +10,7 @@ public class QueryModelTest public void CreateShouldAlwaysReturnAll() { string[] source = { "john", "jane", "", "hugo", "jack" }; - var queryModel = EntityQueryModel.Create(); + var queryModel = QueryModel.AllOfEntity(); string?[] result1 = source .Apply(queryModel) @@ -28,7 +28,7 @@ public void CreateShouldAlwaysReturnAll() public void CreateShouldEvaluateSpecificationCorrectly() { string[] source = { "john", "jane", "hugo", "jack" }; - var queryModel = EntityQueryModel.Create(new StringBeginsWithJohnSpecification()); + var queryModel = QueryModel.CreateForEntity(new StringBeginsWithJohnSpecification()); string[] result1 = source .Apply(queryModel)