-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathOrderBy.cs
More file actions
152 lines (133 loc) · 7.08 KB
/
OrderBy.cs
File metadata and controls
152 lines (133 loc) · 7.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
using System.Linq.Expressions;
using System.Text;
namespace CmdScale.EntityFrameworkCore.TimescaleDB.Configuration.Hypertable
{
/// <summary>
/// Represents an ordering specification for a column.
/// </summary>
/// <param name="columnName">The name of the column to order by.</param>
/// <param name="isAscending">
/// If true, orders Ascending (ASC).
/// If false, orders Descending (DESC).
/// If null, uses database default (ASC).
/// </param>
/// <param name="nullsFirst">
/// If true, forces NULLS FIRST.
/// If false, forces NULLS LAST.
/// If null, uses database default (NULLS LAST for ASC, NULLS FIRST for DESC).
/// </param>
public class OrderBy(string columnName, bool? isAscending = null, bool? nullsFirst = null)
{
/// <summary>The name of the column to order by.</summary>
public string ColumnName { get; } = columnName;
/// <summary>Ordering direction. True for ASC, false for DESC, null for database default.</summary>
public bool? IsAscending { get; } = isAscending;
/// <summary>Null sorting behavior. True for NULLS FIRST, false for NULLS LAST, null for database default.</summary>
public bool? NullsFirst { get; } = nullsFirst;
/// <summary>
/// Converts this ordering specification to a SQL clause fragment.
/// </summary>
public string ToSql()
{
StringBuilder sb = new(ColumnName);
// Only append direction if explicitly set
if (IsAscending.HasValue)
{
sb.Append(IsAscending.Value ? " ASC" : " DESC");
}
// Only append NULLS clause if explicitly set
if (NullsFirst.HasValue)
{
sb.Append(NullsFirst.Value ? " NULLS FIRST" : " NULLS LAST");
}
return sb.ToString();
}
}
/// <summary>
/// Fluent builder for creating OrderBy instances.
/// </summary>
public static class OrderByBuilder
{
/// <summary>
/// Starts building an OrderBy specification for the specified property.
/// </summary>
/// <typeparam name="TEntity">The entity type containing the property.</typeparam>
/// <param name="expression">A lambda expression selecting the property to order by.</param>
public static OrderByConfiguration<TEntity> For<TEntity>(Expression<Func<TEntity, object>> expression) => new(expression);
}
/// <summary>
/// Fluent configuration for creating OrderBy instances.
/// </summary>
public class OrderByConfiguration<TEntity>(Expression<Func<TEntity, object>> expression)
{
private readonly string _propertyName = GetPropertyName(expression);
/// <summary>Creates an OrderBy using the database default direction.</summary>
/// <param name="nullsFirst">Optional null sorting behavior. Null uses database default.</param>
public OrderBy Default(bool? nullsFirst = null) => new(_propertyName, null, nullsFirst);
/// <summary>Creates an ascending OrderBy specification.</summary>
/// <param name="nullsFirst">Optional null sorting behavior. Null uses database default.</param>
public OrderBy Ascending(bool? nullsFirst = null) => new(_propertyName, true, nullsFirst);
/// <summary>Creates a descending OrderBy specification.</summary>
/// <param name="nullsFirst">Optional null sorting behavior. Null uses database default.</param>
public OrderBy Descending(bool? nullsFirst = null) => new(_propertyName, false, nullsFirst);
// Helper to extract the string name from the expression
private static string GetPropertyName(Expression<Func<TEntity, object>> expression)
{
if (expression.Body is MemberExpression member) return member.Member.Name;
if (expression.Body is UnaryExpression unary && unary.Operand is MemberExpression m) return m.Member.Name;
throw new ArgumentException("Invalid expression. Please use a simple property access expression.");
}
}
/// <summary>
/// Fluent builder for creating OrderBy instances using lambda expressions.
/// </summary>
/// <typeparam name="TEntity"></typeparam>
public class OrderBySelector<TEntity>
{
/// <summary>Creates an OrderBy using the database default direction for the selected property.</summary>
/// <param name="expression">A lambda expression selecting the property to order by.</param>
/// <param name="nullsFirst">Optional null sorting behavior. Null uses database default.</param>
public OrderBy By(Expression<Func<TEntity, object>> expression, bool? nullsFirst = null)
=> new(GetPropertyName(expression), null, nullsFirst);
/// <summary>Creates an ascending OrderBy specification for the selected property.</summary>
/// <param name="expression">A lambda expression selecting the property to order by.</param>
/// <param name="nullsFirst">Optional null sorting behavior. Null uses database default.</param>
public OrderBy ByAscending(Expression<Func<TEntity, object>> expression, bool? nullsFirst = null)
=> new(GetPropertyName(expression), true, nullsFirst);
/// <summary>Creates a descending OrderBy specification for the selected property.</summary>
/// <param name="expression">A lambda expression selecting the property to order by.</param>
/// <param name="nullsFirst">Optional null sorting behavior. Null uses database default.</param>
public OrderBy ByDescending(Expression<Func<TEntity, object>> expression, bool? nullsFirst = null)
=> new(GetPropertyName(expression), false, nullsFirst);
private static string GetPropertyName(Expression<Func<TEntity, object>> expression)
{
if (expression.Body is MemberExpression m) return m.Member.Name;
if (expression.Body is UnaryExpression u && u.Operand is MemberExpression m2) return m2.Member.Name;
throw new ArgumentException("Expression must be a property access.");
}
}
/// <summary>
/// Extension methods for creating OrderBy instances.
/// </summary>
public static class OrderByExtensions
{
/// <summary>
/// Creates an ascending OrderBy instance.
/// </summary>
/// <param name="columnName">The name of the column to order by.</param>
/// <param name="nullsFirst">Optional null sorting behavior. Null uses database default.</param>
public static OrderBy Ascending(this string columnName, bool? nullsFirst = null)
{
return new OrderBy(columnName, true, nullsFirst);
}
/// <summary>
/// Creates a descending OrderBy instance.
/// </summary>
/// <param name="columnName">The name of the column to order by.</param>
/// <param name="nullsFirst">Optional null sorting behavior. Null uses database default.</param>
public static OrderBy Descending(this string columnName, bool? nullsFirst = null)
{
return new OrderBy(columnName, false, nullsFirst);
}
}
}