@@ -52,16 +52,32 @@ public static Result<Expression> Evaluate(QueryExpression expression, ParameterE
5252 value = Expression . Constant ( literal . Value , property . Type ) ;
5353 break ;
5454 case DateLiteral literal :
55- property = property . Type == typeof ( DateTime ? ) ?
56- Expression . Property ( Expression . Property ( property , "Value" ) , "Date" ) :
57- Expression . Property ( property , "Date" ) ;
58-
59- value = Expression . Constant ( literal . Value . Date , property . Type ) ;
55+ if ( property . Type == typeof ( DateTime ? ) )
56+ {
57+ // For nullable DateTime, we need to handle this differently in the operator switch
58+ // Just set up the date value for now
59+ value = Expression . Constant ( literal . Value . Date , typeof ( DateTime ) ) ;
60+ }
61+ else
62+ {
63+ property = Expression . Property ( property , "Date" ) ;
64+ value = Expression . Constant ( literal . Value . Date , property . Type ) ;
65+ }
66+ break ;
67+ case NullLiteral _:
68+ value = Expression . Constant ( null , property . Type ) ;
6069 break ;
6170 default :
6271 return Result . Fail ( $ "Unsupported literal type: { exp . Right . GetType ( ) . Name } ") ;
6372 }
6473
74+ // Check if we need special nullable handling
75+ var specialComparison = CreateNullableComparison ( property , value , exp . Right , exp . Operator ) ;
76+ if ( specialComparison != null )
77+ {
78+ return specialComparison ;
79+ }
80+
6581 switch ( exp . Operator )
6682 {
6783 case Keywords . Eq :
@@ -118,6 +134,54 @@ public static Result<Expression> Evaluate(QueryExpression expression, ParameterE
118134 return null ;
119135 }
120136
137+ /// <summary>
138+ /// Creates special nullable property comparisons for types that need property transformation.
139+ /// Returns null if no special handling is needed.
140+ /// </summary>
141+ private static Expression CreateNullableComparison ( MemberExpression property , ConstantExpression value , QueryExpression rightExpression , string operatorKeyword )
142+ {
143+ // Handle nullable DateTime with DateLiteral - requires .Date property access
144+ if ( property . Type == typeof ( DateTime ? ) && rightExpression is DateLiteral )
145+ {
146+ return CreateNullableDateComparison ( property , value , operatorKeyword ) ;
147+ }
148+
149+ // Future extensibility: Add other type transformations here
150+ // if (property.Type == typeof(TimeOnly?) && rightExpression is TimeLiteral)
151+ // {
152+ // return CreateNullableTimeComparison(property, value, operatorKeyword);
153+ // }
154+
155+ return null ;
156+ }
157+
158+ /// <summary>
159+ /// Creates nullable DateTime comparisons that safely access the .Date property.
160+ /// </summary>
161+ private static Expression CreateNullableDateComparison ( MemberExpression property , ConstantExpression value , string operatorKeyword )
162+ {
163+ var hasValueProperty = Expression . Property ( property , "HasValue" ) ;
164+ var valueProperty = Expression . Property ( property , "Value" ) ;
165+ var dateProperty = Expression . Property ( valueProperty , "Date" ) ;
166+
167+ Expression dateComparison = operatorKeyword switch
168+ {
169+ Keywords . Eq => Expression . Equal ( dateProperty , value ) ,
170+ Keywords . Ne => Expression . NotEqual ( dateProperty , value ) ,
171+ Keywords . Lt => Expression . LessThan ( dateProperty , value ) ,
172+ Keywords . Lte => Expression . LessThanOrEqual ( dateProperty , value ) ,
173+ Keywords . Gt => Expression . GreaterThan ( dateProperty , value ) ,
174+ Keywords . Gte => Expression . GreaterThanOrEqual ( dateProperty , value ) ,
175+ _ => throw new ArgumentException ( $ "Unsupported operator for nullable date comparison: { operatorKeyword } ")
176+ } ;
177+
178+ // For inequality, we want: !HasValue OR HasValue && comparison != true
179+ // For others, we want: HasValue && comparison == true
180+ return operatorKeyword == Keywords . Ne
181+ ? Expression . OrElse ( Expression . Not ( hasValueProperty ) , dateComparison )
182+ : Expression . AndAlso ( hasValueProperty , dateComparison ) ;
183+ }
184+
121185 private static Result < ConstantExpression > GetIntegerExpressionConstant ( int value , Type targetType )
122186 {
123187 try
0 commit comments