Skip to content

Commit d834ab9

Browse files
committed
comments
1 parent 9eda8ed commit d834ab9

File tree

4 files changed

+131
-35
lines changed

4 files changed

+131
-35
lines changed

src/AutSoft.Linq/Queryable/FirstAndSingleExtensions.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ public static class FirstAndSingleExtensions
2020
/// <param name="entityId">Identifier of the requested element</param>
2121
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
2222
/// <exception cref="EntityNotFoundException">Throws when no result found</exception>
23-
public static async Task<T> SingleEntityAsync<T>(this IQueryable<T> source, Expression<Func<T, bool>> predicate, long entityId, CancellationToken cancellationToken = default)
23+
/// <returns>A <see cref="Task"/> representing the asynchronous operation. Wraps the requested entity.</returns>
24+
public static async Task<T> SingleEntityAsync<T>(
25+
this IQueryable<T> source,
26+
Expression<Func<T, bool>> predicate,
27+
long entityId,
28+
CancellationToken cancellationToken = default)
2429
{
2530
return await source.SingleOrDefaultAsync(predicate, cancellationToken)
2631
?? throw EntityNotFoundException.CreateForType<T>(entityId);
@@ -35,7 +40,12 @@ public static async Task<T> SingleEntityAsync<T>(this IQueryable<T> source, Expr
3540
/// <param name="queryParameters">Query parameters of the requested element</param>
3641
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
3742
/// <exception cref="EntityNotFoundException">Throws when no result found</exception>
38-
public static async Task<T> SingleEntityAsync<T>(this IQueryable<T> source, Expression<Func<T, bool>> predicate, object[] queryParameters, CancellationToken cancellationToken = default)
43+
/// <returns>A <see cref="Task"/> representing the asynchronous operation. Wraps the requested entity.</returns>
44+
public static async Task<T> SingleEntityAsync<T>(
45+
this IQueryable<T> source,
46+
Expression<Func<T, bool>> predicate,
47+
object[] queryParameters,
48+
CancellationToken cancellationToken = default)
3949
{
4050
return await source.SingleAsync(predicate, cancellationToken)
4151
?? throw EntityNotFoundException.CreateForTypeCustomParams<T>(queryParameters);

src/AutSoft.Linq/Queryable/OrderByExtensions.cs

Lines changed: 73 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,30 @@
1111

1212
namespace AutSoft.Linq.Queryable;
1313

14+
/// <summary>
15+
/// Extensions methods for <see cref="IQueryable{T}"/> with extended functionality fo element ordering
16+
/// </summary>
1417
public static class OrderByExtensions
1518
{
19+
/// <summary>
20+
/// Determine that a property has <see cref="NotSortableAttribute"/>
21+
/// </summary>
22+
/// <param name="propertyInfo">Property to examine</param>
23+
/// <returns>True if the property has <see cref="NotSortableAttribute"/></returns>
1624
public static bool IsSortable(this PropertyInfo propertyInfo)
1725
{
1826
return !Attribute.IsDefined(propertyInfo, typeof(NotSortableAttribute));
1927
}
2028

29+
/// <summary>
30+
/// OrderBy where the direction is coming from a parameter in order to write order by with fluent syntax
31+
/// </summary>
32+
/// <typeparam name="TSource">Element's type</typeparam>
33+
/// <typeparam name="TKey">Ordering key's type</typeparam>
34+
/// <param name="source">An <see cref="IQueryable{T}" /> to order</param>
35+
/// <param name="keySelector">Expression of the ordering key</param>
36+
/// <param name="orderDirection">Direction of ordering represents with <see cref="OrderDirection"/> enum</param>
37+
/// <returns><see cref="IQueryable{T}" /> with ordering information</returns>
2138
public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(
2239
this IQueryable<TSource> source,
2340
Expression<Func<TSource, TKey>> keySelector,
@@ -28,6 +45,37 @@ public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(
2845
: source.OrderBy(keySelector);
2946
}
3047

48+
/// <summary>
49+
/// ThenBy where the direction is coming from a parameter in order to write order by with fluent syntax
50+
/// </summary>
51+
/// <typeparam name="TSource">Element's type</typeparam>
52+
/// <typeparam name="TKey">Ordering key's type</typeparam>
53+
/// <param name="source">An <see cref="IQueryable{T}" /> to order</param>
54+
/// <param name="keySelector">Expression of the ordering key</param>
55+
/// <param name="orderDirection">Direction of ordering represents with <see cref="OrderDirection"/> enum</param>
56+
/// <returns><see cref="IQueryable{T}" /> with ordering information</returns>
57+
public static IOrderedQueryable<TSource> ThenBy<TSource, TKey>(
58+
this IOrderedQueryable<TSource> source,
59+
Expression<Func<TSource, TKey>> keySelector,
60+
OrderDirection orderDirection)
61+
{
62+
return orderDirection == OrderDirection.Descending
63+
? source.ThenByDescending(keySelector)
64+
: source.ThenBy(keySelector);
65+
}
66+
67+
/// <summary>
68+
/// OrderBy where the desired ordering is coming from a <see cref="PageRequest"/>
69+
/// </summary>
70+
/// <typeparam name="TSource">Element's type</typeparam>
71+
/// <param name="source">An <see cref="IQueryable{T}" /> to order</param>
72+
/// <param name="pageRequest">A page request which contains the desired column's name to order.</param>
73+
/// <param name="defaultOrderingSelector">If the page request does not define any ordering information</param>
74+
/// <returns><see cref="IQueryable{T}" /> with ordering information</returns>
75+
/// <remarks>
76+
/// This overload fits if the page request contains ordering information in entity model level.
77+
/// If you use AutoMapper's <see cref="IMapper.ProjectTo"/> consider to use overloads with TDto type parameters
78+
/// </remarks>
3179
public static IOrderedQueryable<TSource> OrderBy<TSource>(
3280
this IQueryable<TSource> source,
3381
PageRequest pageRequest,
@@ -40,6 +88,17 @@ public static IOrderedQueryable<TSource> OrderBy<TSource>(
4088
pageRequest.OrderDirection);
4189
}
4290

91+
/// <summary>
92+
/// OrderBy where the desired ordering is coming from a <see cref="PageRequest"/>
93+
/// and mapping expression calculated based on the provided mapping configuration
94+
/// </summary>
95+
/// <typeparam name="TSource">Element's type</typeparam>
96+
/// <typeparam name="TDto">Target DTO's type to find mapping information</typeparam>
97+
/// <param name="source">An <see cref="IQueryable{T}" /> to order</param>
98+
/// <param name="pageRequest">A page request which contains the desired column's name to order.</param>
99+
/// <param name="defaultOrderingSelector">If the page request does not define any ordering information</param>
100+
/// <param name="mappings">AutoMapper mapping configuration which contains mapping expressions for TSource -> TDto type conversion</param>
101+
/// <returns><see cref="IQueryable{T}" /> with ordering information</returns>
43102
public static IOrderedQueryable<TSource> OrderBy<TSource, TDto>(
44103
this IQueryable<TSource> source,
45104
PageRequest pageRequest,
@@ -51,6 +110,18 @@ public static IOrderedQueryable<TSource> OrderBy<TSource, TDto>(
51110
return source.OrderBy(orderKeySelector, pageRequest.OrderDirection);
52111
}
53112

113+
/// <summary>
114+
/// OrderBy where the desired ordering is coming from a <see cref="PageRequest"/>
115+
/// and mapping expression calculated based on the provided mapping configuration
116+
/// </summary>
117+
/// <typeparam name="TSource">Element's type</typeparam>
118+
/// <typeparam name="TDto">Target DTO's type to find mapping information</typeparam>
119+
/// <param name="source">An <see cref="IQueryable{T}" /> to order</param>
120+
/// <param name="pageRequest">A page request which contains the desired column's name to order.</param>
121+
/// <param name="defaultOrderingSelector">If the page request does not define any ordering information</param>
122+
/// <param name="defaultOrderDirection">Ordering direction for <paramref name="defaultOrderingSelector"/></param>
123+
/// <param name="mappings">AutoMapper mapping configuration which contains mapping expressions for TSource -> TDto type conversion</param>
124+
/// <returns><see cref="IQueryable{T}" /> with ordering information</returns>
54125
public static IOrderedQueryable<TSource> OrderBy<TSource, TDto>(
55126
this IQueryable<TSource> source,
56127
PageRequest pageRequest,
@@ -66,30 +137,17 @@ public static IOrderedQueryable<TSource> OrderBy<TSource, TDto>(
66137
return source.OrderBy(orderKeySelector, pageRequest.OrderDirection);
67138
}
68139

69-
public static IOrderedQueryable<TSource> ThenBy<TSource, TKey>(
70-
this IOrderedQueryable<TSource> source,
71-
Expression<Func<TSource, TKey>> keySelector,
72-
OrderDirection orderDirection)
73-
{
74-
if (orderDirection == OrderDirection.Descending)
75-
return source.ThenByDescending(keySelector);
76-
77-
return source.ThenBy(keySelector);
78-
}
79-
80140
private static Expression<Func<TSource, object>> GetOrderKeySelector<TSource, TDto>(
81141
PageRequest pageRequest,
82142
Expression<Func<TSource, object>> defaultOrderingSelector,
83143
IConfigurationProvider mappings)
84144
{
85145
if (!string.IsNullOrEmpty(pageRequest.OrderBy))
86146
{
87-
// A kliens olyan property-re szeretne rendezni,
88-
// amire a lekérdezésben nincs ráhatásunk,
89-
// vagy nem szeretnénk engedni a rendezést
147+
// The caller want to order based on a not existed or an unsortable property
90148
var pi = typeof(TDto).GetProperty(pageRequest.OrderBy);
91149
if (pi?.IsSortable() != true)
92-
throw new ValidationException(pageRequest.OrderBy, "Ezt az oszlopot nem lehet sorba rendezni!");
150+
throw new ValidationException(pageRequest.OrderBy, "Cannot sort based on this property!");
93151
}
94152

95153
var orderKeySelector = defaultOrderingSelector;

src/AutSoft.Linq/Queryable/PagingExtensions.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,36 @@
44

55
namespace AutSoft.Linq.Queryable;
66

7+
/// <summary>
8+
/// Extensions methods for <see cref="IQueryable{T}"/> to created paged responses
9+
/// </summary>
710
public static class PagingExtensions
811
{
12+
/// <summary>
13+
/// Create a paged response based on <see cref="PageRequest"/>
14+
/// </summary>
15+
/// <typeparam name="TSource">Element's type</typeparam>
16+
/// <param name="source">An <see cref="IQueryable{T}" /> to query its page</param>
17+
/// <param name="pageRequest">Paging parameters</param>
18+
/// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
19+
/// <returns>
20+
/// A task that represents the asynchronous operation.
21+
/// The task result contains a <see cref="List{T}" /> that contains elements from the input sequence.
22+
/// </returns>
923
public static async Task<PageResponse<TSource>> ToPagedListAsync<TSource>(
10-
this IQueryable<TSource> source, PageRequest pageRequest, CancellationToken cancellationToken = default)
24+
this IQueryable<TSource> source,
25+
PageRequest pageRequest,
26+
CancellationToken cancellationToken = default)
1127
{
1228
var totalCount = await source.CountAsync(cancellationToken);
1329
var pageCount = (totalCount + pageRequest.PageSize - 1) / pageRequest.PageSize;
1430

1531
return new PageResponse<TSource>(
16-
await source.Skip(pageRequest.Page * pageRequest.PageSize).Take(pageRequest.PageSize).ToListAsync(cancellationToken), pageRequest.Page, totalCount, pageCount);
32+
await source.Skip(pageRequest.Page * pageRequest.PageSize)
33+
.Take(pageRequest.PageSize)
34+
.ToListAsync(cancellationToken),
35+
pageRequest.Page,
36+
totalCount,
37+
pageCount);
1738
}
1839
}

src/AutSoft.Linq/Queryable/WhereExtensions.cs

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,20 @@
22

33
namespace AutSoft.Linq.Queryable;
44

5+
/// <summary>
6+
/// Extensions methods for <see cref="IQueryable{T}"/> with helper functionality for Where methods
7+
/// </summary>
58
public static class WhereExtensions
69
{
10+
/// <summary>
11+
/// Conditionally append a where expression to <see cref="IQueryable{T}"/> for performance considerations.
12+
/// </summary>
13+
/// <typeparam name="TSource">Element's type</typeparam>
14+
/// <param name="source">An <see cref="IQueryable{T}" /> to conditionally filter</param>
15+
/// <param name="condition">Condition to determine which expression to use in Where clause</param>
16+
/// <param name="conditionTruePredicate">Expression to use if the <paramref name="condition"/> is true</param>
17+
/// <param name="conditionFalsePredicate">Optional expression to use if the <paramref name="condition"/> is false</param>
18+
/// <returns><see cref="IQueryable{T}"/> with filtering expressions.</returns>
719
public static IQueryable<TSource> Where<TSource>(
820
this IQueryable<TSource> source,
921
bool condition,
@@ -24,24 +36,19 @@ public static IQueryable<TSource> Where<TSource>(
2436
}
2537
}
2638

27-
public static IQueryable<TSource> Where<TSource>(
39+
/// <summary>
40+
/// Conditionally append statements to a <see cref="IQueryable{T}"/> fluent call chain
41+
/// in order to keep the fluent syntax
42+
/// </summary>
43+
/// <typeparam name="TSource">Element's type</typeparam>
44+
/// <param name="source">An <see cref="IQueryable{T}" /> to extend</param>
45+
/// <param name="condition">Condition to determine which expression to use in Where clause</param>
46+
/// <param name="transform">Function which describes the modifications on the <paramref name="source"/>.</param>
47+
/// <returns>An extended <see cref="IQueryable{T}"/></returns>
48+
public static IQueryable<TSource> If<TSource>(
2849
this IQueryable<TSource> source,
29-
bool? condition,
30-
Expression<Func<TSource, bool>> truePredicate,
31-
Expression<Func<TSource, bool>> falsePredicate)
32-
{
33-
if (!condition.HasValue)
34-
return source;
35-
36-
return condition.Value
37-
? source.Where(truePredicate)
38-
: source.Where(falsePredicate);
39-
}
40-
41-
public static IQueryable<T> If<T>(
42-
this IQueryable<T> source,
4350
bool condition,
44-
Func<IQueryable<T>, IQueryable<T>> transform)
51+
Func<IQueryable<TSource>, IQueryable<TSource>> transform)
4552
{
4653
return condition ? transform(source) : source;
4754
}

0 commit comments

Comments
 (0)