1+ using System . Linq . Expressions ;
2+
3+ namespace CmdScale . EntityFrameworkCore . TimescaleDB . Abstractions
4+ {
5+ /// <summary>
6+ /// Represents an ordering specification for a column.
7+ /// </summary>
8+ /// <param name="columnName">The name of the column to order by.</param>
9+ /// <param name="isAscending">
10+ /// If true, orders Ascending (ASC).
11+ /// If false, orders Descending (DESC).
12+ /// If null, uses database default (ASC).
13+ /// </param>
14+ /// <param name="nullsFirst">
15+ /// If true, forces NULLS FIRST.
16+ /// If false, forces NULLS LAST.
17+ /// If null, uses database default (NULLS LAST for ASC, NULLS FIRST for DESC).
18+ /// </param>
19+ public class OrderBy ( string columnName , bool ? isAscending = null , bool ? nullsFirst = null )
20+ {
21+ public string ColumnName { get ; } = columnName ;
22+ public bool ? IsAscending { get ; } = isAscending ;
23+ public bool ? NullsFirst { get ; } = nullsFirst ;
24+
25+ public string ToSql ( )
26+ {
27+ var sb = new System . Text . StringBuilder ( ColumnName ) ;
28+
29+ // Only append direction if explicitly set
30+ if ( IsAscending . HasValue )
31+ {
32+ sb . Append ( IsAscending . Value ? " ASC" : " DESC" ) ;
33+ }
34+
35+ // Only append NULLS clause if explicitly set
36+ if ( NullsFirst . HasValue )
37+ {
38+ sb . Append ( NullsFirst . Value ? " NULLS FIRST" : " NULLS LAST" ) ;
39+ }
40+
41+ return sb . ToString ( ) ;
42+ }
43+ }
44+
45+ /// <summary>
46+ /// Fluent builder for creating OrderBy instances.
47+ /// </summary>
48+ public static class OrderByBuilder
49+ {
50+ public static OrderByConfiguration < TEntity > For < TEntity > ( Expression < Func < TEntity , object > > expression ) => new ( expression ) ;
51+ }
52+
53+ /// <summary>
54+ /// Fluent configuration for creating OrderBy instances.
55+ /// </summary>
56+ public class OrderByConfiguration < TEntity > ( Expression < Func < TEntity , object > > expression )
57+ {
58+ private readonly string _propertyName = GetPropertyName ( expression ) ;
59+
60+ public OrderBy Default ( bool ? nullsFirst = null ) => new ( _propertyName , null , nullsFirst ) ;
61+ public OrderBy Ascending ( bool ? nullsFirst = null ) => new ( _propertyName , true , nullsFirst ) ;
62+ public OrderBy Descending ( bool ? nullsFirst = null ) => new ( _propertyName , false , nullsFirst ) ;
63+
64+ // Helper to extract the string name from the expression
65+ private static string GetPropertyName ( Expression < Func < TEntity , object > > expression )
66+ {
67+ if ( expression . Body is MemberExpression member ) return member . Member . Name ;
68+ if ( expression . Body is UnaryExpression unary && unary . Operand is MemberExpression m ) return m . Member . Name ;
69+ throw new ArgumentException ( "Invalid expression. Please use a simple property access expression." ) ;
70+ }
71+ }
72+
73+ /// <summary>
74+ /// Fluent builder for creating OrderBy instances using lambda expressions.
75+ /// </summary>
76+ /// <typeparam name="TEntity"></typeparam>
77+ public class OrderBySelector < TEntity >
78+ {
79+ public OrderBy By ( Expression < Func < TEntity , object > > expression , bool ? nullsFirst = null )
80+ => new ( GetPropertyName ( expression ) , null , nullsFirst ) ;
81+
82+ public OrderBy ByAscending ( Expression < Func < TEntity , object > > expression , bool ? nullsFirst = null )
83+ => new ( GetPropertyName ( expression ) , true , nullsFirst ) ;
84+
85+ public OrderBy ByDescending ( Expression < Func < TEntity , object > > expression , bool ? nullsFirst = null )
86+ => new ( GetPropertyName ( expression ) , false , nullsFirst ) ;
87+
88+ // Internal helper to get property names from expressions
89+ private static string GetPropertyName ( Expression < Func < TEntity , object > > expression )
90+ {
91+ if ( expression . Body is MemberExpression m ) return m . Member . Name ;
92+ if ( expression . Body is UnaryExpression u && u . Operand is MemberExpression m2 ) return m2 . Member . Name ;
93+ throw new ArgumentException ( "Expression must be a property access." ) ;
94+ }
95+ }
96+
97+ /// <summary>
98+ /// Extension methods for creating OrderBy instances.
99+ /// </summary>
100+ public static class OrderByExtensions
101+ {
102+ /// <summary>
103+ /// Creates an ascending OrderBy instance.
104+ /// </summary>
105+ /// <param name="columnName">The name of the column to order by.</param>
106+ /// <param name="nullsFirst">Whether nulls should appear first.</param>
107+ public static OrderBy Ascending ( this string columnName , bool nullsFirst = false )
108+ {
109+ return new OrderBy ( columnName , true , nullsFirst ) ;
110+ }
111+
112+ /// <summary>
113+ /// Creates a descending OrderBy instance.
114+ /// </summary>
115+ /// <param name="columnName">The name of the column to order by.</param>
116+ /// <param name="nullsFirst">Whether nulls should appear first.</param>
117+ public static OrderBy Descending ( this string columnName , bool nullsFirst = false )
118+ {
119+ return new OrderBy ( columnName , false , nullsFirst ) ;
120+ }
121+ }
122+ }
0 commit comments