Skip to content

Commit

Permalink
feat: move query mode creation to QueryModel static class
Browse files Browse the repository at this point in the history
  • Loading branch information
skarllot committed Sep 24, 2023
1 parent 02b26ef commit 84d843e
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 44 deletions.
11 changes: 5 additions & 6 deletions src/Expressions.Reading/Queries/EntityQueryModel.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
Expand All @@ -10,12 +9,12 @@ public static class EntityQueryModel
/// <typeparam name="T">The type of the elements of query model.</typeparam>
/// <returns>A query model for the specified type <typeparamref name="T"/>.</returns>
public static IEntityQueryModel<T> Create<T>() where T : class =>
AllQueryModel<T>.Instance;
QueryModel.AllOfEntity<T>();

public static IEntityQueryModel<T> Create<T>(Specification<T> specification) where T : class =>
new SpecificationQueryModel<T>(specification);
QueryModel.CreateForEntity(specification);

public static IEntityQueryModel<TSource, TResult> Create<TSource, TResult>(
Func<IQueryable<TSource>, IQueryable<TResult>> queryModel) where TSource : class =>
new AnonymousEntityQueryModel<TSource, TResult>(queryModel);
QueryModel.CreateForEntity(queryModel);
}
2 changes: 1 addition & 1 deletion src/Expressions.Reading/Queries/IQueryModel.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace Raiqub.Expressions.Queries;

/// <summary>
/// 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 <typeparamref name="TResult"/>.
/// </summary>
/// <typeparam name="TResult">The type of the query result.</typeparam>
Expand Down
78 changes: 77 additions & 1 deletion src/Expressions.Reading/Queries/QueryModel.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>Returns a query model for the specified type <typeparamref name="TSource"/> that returns all items.</summary>
/// <typeparam name="TSource">The type of the data source.</typeparam>
/// <returns>A query model for the specified type <typeparamref name="TSource"/>.</returns>
public static IEntityQueryModel<TSource> AllOfEntity<TSource>() where TSource : class =>
AllQueryModel<TSource>.Instance;

/// <summary>Creates a new query strategy from the specified function.</summary>
/// <param name="queryModel">A function defining the query strategy.</param>
/// <typeparam name="TResult">The type of the query result.</typeparam>
/// <returns>A new query strategy.</returns>
public static IQueryModel<TResult> Create<TResult>(Func<IQuerySource, IQueryable<TResult>> queryModel) =>
new AnonymousQueryModel<TResult>(queryModel);

/// <summary>
/// Creates a new entity query strategy that returns items from data source of type <typeparamref name="TSource"/>.
/// It only returns the items that satisfies the specified business rule.
/// </summary>
/// <param name="specification"></param>
/// <typeparam name="TSource">The type of the data source.</typeparam>
/// <returns>A new entity query strategy.</returns>
public static IEntityQueryModel<TSource> CreateForEntity<TSource>(Specification<TSource> specification) where TSource : class =>
new SpecificationQueryModel<TSource>(specification);

/// <summary>Creates a new entity query strategy from the specified function.</summary>
/// <param name="queryModel">A function defining the query strategy.</param>
/// <typeparam name="TSource">The type of the data source.</typeparam>
/// <typeparam name="TResult">The type of the query result.</typeparam>
/// <returns>A new entity query strategy.</returns>
public static IEntityQueryModel<TSource, TResult> CreateForEntity<TSource, TResult>(
Func<IQueryable<TSource>, IQueryable<TResult>> queryModel) where TSource : class =>
new AnonymousEntityQueryModel<TSource, TResult>(queryModel);

/// <summary>
/// Creates a new query model that returns all items for the nested collection of the specified entity.
/// </summary>
/// <param name="selector">A projection function to retrieve nested collection.</param>
/// <typeparam name="TSource">The type of entity to query.</typeparam>
/// <typeparam name="TNested">The type of nested collection from the specified entity.</typeparam>
/// <returns>A new query model.</returns>
public static IEntityQueryModel<TSource, TNested> CreateNested<TSource, TNested>(
Expression<Func<TSource, IEnumerable<TNested>>> selector)
where TSource : class
where TNested : class =>
new NestingEntityQueryModel<TSource, TNested, TNested>(selector, AllOfEntity<TNested>());

/// <summary>
/// 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.
/// </summary>
/// <param name="selector">A projection function to retrieve nested collection.</param>
/// <param name="specification">The specification used for query.</param>
/// <typeparam name="TSource">The type of entity to query.</typeparam>
/// <typeparam name="TNested">The type of nested collection from the specified entity.</typeparam>
/// <returns>A new query model.</returns>
public static IEntityQueryModel<TSource, TNested> CreateNested<TSource, TNested>(
Expression<Func<TSource, IEnumerable<TNested>>> selector,
Specification<TNested> specification)
where TSource : class
where TNested : class =>
new NestingEntityQueryModel<TSource, TNested, TNested>(selector, CreateForEntity(specification));

/// <summary>
/// Creates a new query model for the nested collection of the specified entity.
/// The nested items are then queried using the specified query model.
/// </summary>
/// <param name="selector">A projection function to retrieve nested collection.</param>
/// <param name="queryModel">The query model to use with nested elements.</param>
/// <typeparam name="TSource">The type of entity to query.</typeparam>
/// <typeparam name="TNested">The type of nested collection from the specified entity.</typeparam>
/// <typeparam name="TResult">The type of result to return.</typeparam>
/// <returns>A new query model.</returns>
public static IEntityQueryModel<TSource, TResult> CreateNested<TSource, TNested, TResult>(
Expression<Func<TSource, IEnumerable<TNested>>> selector,
IEntityQueryModel<TNested, TResult> queryModel)
where TSource : class
where TNested : class =>
new NestingEntityQueryModel<TSource, TNested, TResult>(selector, queryModel);
}
51 changes: 21 additions & 30 deletions src/Expressions.Reading/Sessions/DbQuerySessionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static IDbQuery<TEntity> Query<TEntity>(
return session.Query(AllQueryModel<TEntity>.Instance);
}

/// <summary>Creates a new query using the criteria specification.</summary>
/// <summary>Creates a new query using the specified business rule.</summary>
/// <param name="session">The session to create query from.</param>
/// <param name="specification">The specification used for query.</param>
/// <typeparam name="TEntity">The type of entity to query.</typeparam>
Expand All @@ -31,42 +31,39 @@ public static IDbQuery<TEntity> Query<TEntity>(
return session.Query(new SpecificationQueryModel<TEntity>(specification));
}

/// <summary>Creates a new query using the specified entity query model.</summary>
/// <param name="session">The session to create query from.</param>
/// <typeparam name="TEntity">The type of entity to query.</typeparam>
/// <typeparam name="TResult">The type of result to return.</typeparam>
/// <param name="entityQueryModel">The query model to use.</param>
/// <returns>A new query object.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="entityQueryModel"/> is null.</exception>
public static IDbQuery<TResult> Query<TEntity, TResult>(
this IDbQuerySession session,
IEntityQueryModel<TEntity, TResult> 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());
}

/// <summary>
/// Creates a new query for the nested collection of the specified entity.
/// </summary>
/// <param name="session">The session to create query from.</param>
/// <param name="selector">A projection function to retrieve entity collection.</param>
/// <typeparam name="TEntity">The type of entity to query.</typeparam>
/// <typeparam name="TNested">The type of nested collection from the specified entity.</typeparam>
/// <returns>A new query object.</returns>
[Obsolete("Use the CreateNested method from QueryModel static class", true)]
public static IDbQuery<TNested> QueryNested<TEntity, TNested>(
this IDbQuerySession session,
Expression<Func<TEntity, IEnumerable<TNested>>> selector)
where TEntity : class
where TNested : class
{
return session.Query(
new NestingEntityQueryModel<TEntity, TNested, TNested>(selector, EntityQueryModel.Create<TNested>()));
new NestingEntityQueryModel<TEntity, TNested, TNested>(selector, QueryModel.AllOfEntity<TNested>()));
}

/// <summary>
/// Creates a new query for the nested collection of the specified entity using the specified query model.
/// </summary>
/// <param name="session">The session to create query from.</param>
/// <param name="selector">A projection function to retrieve entity collection.</param>
/// <param name="queryModel">The query model to use.</param>
/// <typeparam name="TEntity">The type of entity to query.</typeparam>
/// <typeparam name="TNested">The type of nested collection from the specified entity.</typeparam>
/// <typeparam name="TResult">The type of result to return.</typeparam>
/// <returns>A new query object.</returns>
[Obsolete("Use the CreateNested method from QueryModel static class", true)]
public static IDbQuery<TResult> QueryNested<TEntity, TNested, TResult>(
this IDbQuerySession session,
Expression<Func<TEntity, IEnumerable<TNested>>> selector,
Expand All @@ -77,15 +74,7 @@ public static IDbQuery<TResult> QueryNested<TEntity, TNested, TResult>(
return session.Query(new NestingEntityQueryModel<TEntity, TNested, TResult>(selector, queryModel));
}

/// <summary>
/// Creates a new query for the nested collection of the specified entity using the criteria specification.
/// </summary>
/// <param name="session">The session to create query from.</param>
/// <param name="selector">A projection function to retrieve entity collection.</param>
/// <param name="specification">The specification used for query.</param>
/// <typeparam name="TEntity">The type of entity to query.</typeparam>
/// <typeparam name="TNested">The type of nested collection from the specified entity.</typeparam>
/// <returns>A new query object.</returns>
[Obsolete("Use the CreateNested method from QueryModel static class", true)]
public static IDbQuery<TNested> QueryNested<TEntity, TNested>(
this IDbQuerySession session,
Expression<Func<TEntity, IEnumerable<TNested>>> selector,
Expand All @@ -94,6 +83,8 @@ public static IDbQuery<TNested> QueryNested<TEntity, TNested>(
where TNested : class
{
return session.Query(
new NestingEntityQueryModel<TEntity, TNested, TNested>(selector, EntityQueryModel.Create(specification)));
new NestingEntityQueryModel<TEntity, TNested, TNested>(
selector,
QueryModel.CreateForEntity(specification)));
}
}
6 changes: 3 additions & 3 deletions tests/Common.Tests/Queries/QueryTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -92,7 +92,7 @@ public async Task ToListShouldReturnAll()
{
await AddBlogs(GetBlogs());
await using var session = CreateSession();
var query = session.Query(EntityQueryModel.Create((IQueryable<Blog> source) => source.SelectMany(b => b.Posts)));
var query = session.Query(QueryModel.CreateForEntity((IQueryable<Blog> source) => source.SelectMany(b => b.Posts)));

var posts = await query.ToListAsync();

Expand All @@ -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<Blog> source) => source
.SelectMany(b => b.Posts)
.Where(p => p.Content.StartsWith("You"))));
Expand Down
2 changes: 1 addition & 1 deletion tests/Common.Tests/Sessions/SessionFactoryTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public async Task UpdateRangeAndSaveShouldCommitChanges()
await using (var session = sessionFactory.Create())
{
finalBlogs = await session
.Query(EntityQueryModel.Create((IQueryable<Blog> source) => source.OrderBy(b => b.Name)))
.Query(QueryModel.CreateForEntity((IQueryable<Blog> source) => source.OrderBy(b => b.Name)))
.ToListAsync();
}

Expand Down
4 changes: 2 additions & 2 deletions tests/Expressions.Reading.Tests/Queries/QueryModelTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class QueryModelTest
public void CreateShouldAlwaysReturnAll()
{
string[] source = { "john", "jane", "", "hugo", "jack" };
var queryModel = EntityQueryModel.Create<string>();
var queryModel = QueryModel.AllOfEntity<string>();

string?[] result1 = source
.Apply(queryModel)
Expand All @@ -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)
Expand Down

0 comments on commit 84d843e

Please sign in to comment.