Skip to content

Commit

Permalink
Merge pull request #14 from RicardoZambon/fix/catalog-queries
Browse files Browse the repository at this point in the history
fix: Apply dynamic expressions to catalog
  • Loading branch information
RicardoZambon authored May 30, 2024
2 parents 381e6de + 0d4e5cf commit 658f34e
Showing 1 changed file with 26 additions and 25 deletions.
51 changes: 26 additions & 25 deletions ZWebAPI/ExtensionMethods/QueryableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,48 @@ public static class QueryableExtensions
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <param name="query">The query.</param>
/// <param name="parameters">The parameters.</param>
/// <param name="keySelector">The key selector.</param>
/// <param name="valueSelector">The value selector.</param>
/// <param name="displaySelector">The display selector.</param>
/// <returns>The catalog result model.</returns>
public static CatalogResultModel<TKey> GetCatalog<TEntity, TKey>(this IQueryable<TEntity> query, ICatalogParameters parameters, Expression<Func<TEntity, TKey>> keySelector, Expression<Func<TEntity, string?>> valueSelector)
public static CatalogResultModel<TKey> GetCatalog<TEntity, TKey>(this IQueryable<TEntity> query, ICatalogParameters parameters, Expression<Func<TEntity, TKey>> valueSelector, Expression<Func<TEntity, string?>> displaySelector)
where TEntity : class
where TKey : struct
{
CatalogResultModel<TKey> result = new();
// Builds the SELECT query dynamically.
ParameterExpression parameter = Expression.Parameter(typeof(TEntity), "x");

InvocationExpression valueExpression = Expression.Invoke(valueSelector, parameter);
InvocationExpression displayExpression = Expression.Invoke(displaySelector, parameter);

NewExpression newExpression = Expression.New(typeof(CatalogEntryModel<TKey>));
List<MemberBinding> bindings = new() {
Expression.Bind(typeof(CatalogEntryModel<TKey>).GetProperty(nameof(CatalogEntryModel<TKey>.Value))!, valueExpression),
Expression.Bind(typeof(CatalogEntryModel<TKey>).GetProperty(nameof(CatalogEntryModel<TKey>.Display))!, displayExpression),
};

IQueryable<KeyValuePair<TKey, string?>> catalogQuery = query.ConvertToKeyValuePairs(keySelector, valueSelector);
MemberInitExpression memberInit = Expression.MemberInit(newExpression, bindings);

if (!string.IsNullOrEmpty(parameters.Criteria))
Expression<Func<TEntity, CatalogEntryModel<TKey>>> lambda = Expression.Lambda<Func<TEntity, CatalogEntryModel<TKey>>>(memberInit, parameter);

// Execute the query.
IQueryable<CatalogEntryModel<TKey>> catalogQuery = query.Select(lambda);

// When needed, apply criteria.
if (!string.IsNullOrWhiteSpace(parameters.Criteria))
{
catalogQuery = catalogQuery.Where(x =>
x.Value != null
&& EF.Functions.Like(x.Value.ToLower(), $"%{parameters.Criteria.ToLower()}%")
);
catalogQuery = catalogQuery.Where(x => x.Display != null && EF.Functions.Like(x.Display.ToLower(), $"%{parameters.Criteria.ToLower()}%"));
}

// Build the result class.
CatalogResultModel<TKey> result = new();

if (parameters.MaxResults > 0 && catalogQuery.Count() > parameters.MaxResults)
{
result.ShouldUseCriteria = true;
}
else
{
result.Entries = catalogQuery
.Select(x => new CatalogEntryModel<TKey>()
{
Display = x.Value,
Value = x.Key,
});
result.Entries = catalogQuery;
}

return result;
Expand Down Expand Up @@ -235,16 +246,6 @@ public static IQueryable<TEntity> TryFilterWithValue<TEntity>(this IQueryable<TE
return null;
}

private static IQueryable<KeyValuePair<TKey, string?>> ConvertToKeyValuePairs<TEntity, TKey>(this IQueryable<TEntity> query, Expression<Func<TEntity, TKey>> keySelector, Expression<Func<TEntity, string?>> valueSelector)
where TEntity : class
where TKey : struct
{
return query.Select(x => new KeyValuePair<TKey, string?>(
keySelector.Compile().Invoke(x),
valueSelector.Compile().Invoke(x)
));
}

private static ParameterExpression GetParameter<TEntity>()
=> Expression.Parameter(typeof(TEntity), typeof(TEntity).Name.ToLower());

Expand Down

0 comments on commit 658f34e

Please sign in to comment.