diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 754dfe35fbc..131ed868441 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -53,6 +53,7 @@ + @@ -78,6 +79,7 @@ + @@ -101,6 +103,7 @@ + @@ -124,6 +127,7 @@ + diff --git a/src/GreenDonut/src/GreenDonut.Data.EntityFramework/Expressions/ExpressionHelpers.cs b/src/GreenDonut/src/GreenDonut.Data.EntityFramework/Expressions/ExpressionHelpers.cs index 8e74d9da3d5..58ff24fa6b3 100644 --- a/src/GreenDonut/src/GreenDonut.Data.EntityFramework/Expressions/ExpressionHelpers.cs +++ b/src/GreenDonut/src/GreenDonut.Data.EntityFramework/Expressions/ExpressionHelpers.cs @@ -15,6 +15,10 @@ internal static class ExpressionHelpers .GetMethod(nameof(CreateAndConvertParameter), BindingFlags.NonPublic | BindingFlags.Static)!; private static readonly ConcurrentDictionary> s_cachedConverters = new(); + private static readonly NullabilityInfoContext s_nullabilityInfoContext = new(); + private static readonly Expression s_null = Expression.Constant(null); + private static readonly Expression s_false = Expression.Constant(false); + private static readonly Expression s_zero = Expression.Constant(0); /// /// Builds a where expression that can be used to slice a dataset. @@ -28,6 +32,9 @@ internal static class ExpressionHelpers /// /// Defines how the dataset is sorted. /// + /// + /// Defines the null ordering to be used. + /// /// /// The entity type. /// @@ -43,7 +50,8 @@ internal static class ExpressionHelpers public static (Expression> WhereExpression, int Offset) BuildWhereExpression( ReadOnlySpan keys, Cursor cursor, - bool forward) + bool forward, + NullOrdering nullOrdering) { if (keys.Length == 0) { @@ -58,14 +66,16 @@ public static (Expression> WhereExpression, int Offset) BuildWhere var cursorExpr = new Expression[cursor.Values.Length]; for (var i = 0; i < cursor.Values.Length; i++) { - cursorExpr[i] = CreateParameter(cursor.Values[i], keys[i].Expression.ReturnType); + var parameterType = Nullable.GetUnderlyingType(keys[i].Expression.ReturnType) + ?? keys[i].Expression.ReturnType; + + cursorExpr[i] = CreateParameter(cursor.Values[i], parameterType); } var handled = new List(); Expression? expression = null; var parameter = Expression.Parameter(typeof(T), "t"); - var zero = Expression.Constant(0); for (var i = 0; i < keys.Length; i++) { @@ -77,24 +87,50 @@ public static (Expression> WhereExpression, int Offset) BuildWhere { var handledKey = handled[j]; - keyExpr = Expression.Equal( - Expression.Call(ReplaceParameter(handledKey.Expression, parameter), handledKey.CompareMethod, - cursorExpr[j]), zero); + keyExpr = BuildEqualToKeyExpr( + handledKey, + parameter, + cursor.Values[j], + cursorExpr[j]); current = current is null ? keyExpr : Expression.AndAlso(current, keyExpr); } + var keyIsNullable = IsNullable(key.Expression); + + if (keyIsNullable && nullOrdering == NullOrdering.Unspecified) + { + throw new Exception( + "The NullOrdering option must be specified in the paging options or " + + "arguments when using nullable keys."); + } + var greaterThan = forward ? key.Direction == CursorKeyDirection.Ascending : key.Direction == CursorKeyDirection.Descending; - keyExpr = greaterThan - ? Expression.GreaterThan( - Expression.Call(ReplaceParameter(key.Expression, parameter), key.CompareMethod, cursorExpr[i]), - zero) - : Expression.LessThan( - Expression.Call(ReplaceParameter(key.Expression, parameter), key.CompareMethod, cursorExpr[i]), - zero); + if (greaterThan) + { + keyExpr = + BuildGreaterThanKeyExpr( + key, + parameter, + cursor.Values[i], + keyIsNullable, + nullOrdering, + cursorExpr[i]); + } + else + { + keyExpr = + BuildLessThanKeyExpr( + key, + parameter, + cursor.Values[i], + keyIsNullable, + nullOrdering, + cursorExpr[i]); + } current = current is null ? keyExpr : Expression.AndAlso(current, keyExpr); expression = expression is null ? current : Expression.OrElse(expression, current); @@ -104,6 +140,207 @@ public static (Expression> WhereExpression, int Offset) BuildWhere return (Expression.Lambda>(expression!, parameter), cursor.Offset ?? 0); } + private static Expression BuildEqualToKeyExpr( + CursorKey cursorKey, + ParameterExpression parameter, + object? cursorValue, + Expression cursorExpr) + { + var keyIsNullable = IsNullable(cursorKey.Expression); + var keyExpr = ReplaceParameter(cursorKey.Expression, parameter); + + // Access the value of the key if it is a nullable value type. + var keyValueExpr = cursorKey.Expression.ReturnType.IsValueType && keyIsNullable + ? Expression.Property(keyExpr, "Value") + : keyExpr; + + if (keyIsNullable) + { + if (cursorValue is null) + { + // SQL: WHERE key IS NULL. + keyExpr = Expression.Equal(keyExpr, s_null); + } + else + { + // SQL: WHERE key = cursorValue. + keyExpr = Expression.Equal( + Expression.Call(keyValueExpr, cursorKey.CompareMethod, cursorExpr), + s_zero); + } + } + else + { + // SQL: WHERE key = cursorValue. + keyExpr = Expression.Equal( + Expression.Call(keyExpr, cursorKey.CompareMethod, cursorExpr), + s_zero); + } + + return keyExpr; + } + + private static Expression BuildGreaterThanKeyExpr( + CursorKey cursorKey, + ParameterExpression parameter, + object? cursorValue, + bool keyIsNullable, + NullOrdering nullOrdering, + Expression cursorExpr) + { + var keyExpr = ReplaceParameter(cursorKey.Expression, parameter); + + // Access the value of the key if it is a nullable value type. + var keyValueExpr = + cursorKey.Expression.ReturnType.IsValueType && keyIsNullable + ? Expression.Property(keyExpr, "Value") + : keyExpr; + + if (keyIsNullable) + { + if (cursorValue is null) + { + keyExpr = nullOrdering == NullOrdering.NativeNullsFirst + // With nulls first, any non-null value is greater than null. + // SQL: WHERE key IS NOT NULL. + ? Expression.NotEqual(keyExpr, s_null) + // With nulls last, no value is greater than null. + // SQL: WHERE false. + : s_false; + } + else + { + if (nullOrdering == NullOrdering.NativeNullsFirst) + { + // SQL: WHERE key > cursorValue. + keyExpr = Expression.GreaterThan( + Expression.Call(keyValueExpr, cursorKey.CompareMethod, cursorExpr), + s_zero); + } + else + { + // When nulls are last, null is greater than any non-null value. + // SQL: WHERE key > cursorValue OR key IS NULL. + keyExpr = Expression.Or( + Expression.GreaterThan( + Expression.Call(keyValueExpr, cursorKey.CompareMethod, cursorExpr), + s_zero), + Expression.Equal(keyExpr, s_null)); + } + } + } + else + { + // SQL: WHERE key > cursorValue. + keyExpr = Expression.GreaterThan( + Expression.Call(keyExpr, cursorKey.CompareMethod, cursorExpr), + s_zero); + } + + return keyExpr; + } + + private static Expression BuildLessThanKeyExpr( + CursorKey cursorKey, + ParameterExpression parameter, + object? cursorValue, + bool keyIsNullable, + NullOrdering nullOrdering, + Expression cursorExpr) + { + var keyExpr = ReplaceParameter(cursorKey.Expression, parameter); + + // Access the value of the key if it is a nullable value type. + var keyValueExpr = + cursorKey.Expression.ReturnType.IsValueType && keyIsNullable + ? Expression.Property(keyExpr, "Value") + : keyExpr; + + if (keyIsNullable) + { + if (cursorValue is null) + { + keyExpr = nullOrdering == NullOrdering.NativeNullsFirst + // With nulls first, no value is less than null. + // SQL: WHERE false. + ? s_false + // With nulls last, any non-null value is less than null. + // SQL: WHERE key IS NOT NULL. + : Expression.NotEqual(keyExpr, s_null); + } + else + { + if (nullOrdering == NullOrdering.NativeNullsFirst) + { + // With nulls first, null is less than any non-null value. + // SQL: WHERE key < cursorValue OR key IS NULL. + keyExpr = Expression.Or( + Expression.LessThan( + Expression.Call(keyValueExpr, cursorKey.CompareMethod, cursorExpr), + s_zero), + Expression.Equal(keyExpr, s_null)); + } + else + { + // SQL: WHERE key < cursorValue. + keyExpr = Expression.LessThan( + Expression.Call(keyValueExpr, cursorKey.CompareMethod, cursorExpr), + s_zero); + } + } + } + else + { + // SQL: WHERE key < cursorValue. + keyExpr = Expression.LessThan( + Expression.Call(keyExpr, cursorKey.CompareMethod, cursorExpr), + s_zero); + } + + return keyExpr; + } + + private static bool IsNullable(LambdaExpression expression) + { + if (expression.ReturnType.IsValueType) + { + return Nullable.GetUnderlyingType(expression.ReturnType) is not null; + } + + var propertyInfo = expression.Body switch + { + MemberExpression + { + Member: PropertyInfo p + } => p, + BinaryExpression + { + NodeType: ExpressionType.Coalesce, + Right: MemberExpression { Member: PropertyInfo p } + } => p, + _ => null + }; + + if (propertyInfo is not null) + { + var nullability = s_nullabilityInfoContext.Create(propertyInfo).ReadState; + + switch (nullability) + { + case NullabilityState.Nullable: + return true; + case NullabilityState.NotNull: + return false; + case NullabilityState.Unknown: + break; + default: + throw new InvalidOperationException(); + } + } + + throw new Exception("The nullability of the cursor key could not be determined."); + } + /// /// Build the select expression for a batch paging expression that uses grouping. /// @@ -184,7 +421,11 @@ public static BatchExpression BuildBatchExpression( if (arguments.After is not null) { cursor = CursorParser.Parse(arguments.After, keys); - var (whereExpr, cursorOffset) = BuildWhereExpression(keys, cursor, forward: true); + var (whereExpr, cursorOffset) = BuildWhereExpression( + keys, + cursor, + forward: true, + arguments.NullOrdering); source = Expression.Call(typeof(Enumerable), "Where", [typeof(TV)], source, whereExpr); offset = cursorOffset; @@ -204,7 +445,12 @@ public static BatchExpression BuildBatchExpression( } cursor = CursorParser.Parse(arguments.Before, keys); - var (whereExpr, cursorOffset) = BuildWhereExpression(keys, cursor, forward: false); + var (whereExpr, cursorOffset) = BuildWhereExpression( + keys, + cursor, + forward: + false, + arguments.NullOrdering); source = Expression.Call(typeof(Enumerable), "Where", [typeof(TV)], source, whereExpr); offset = cursorOffset; } diff --git a/src/GreenDonut/src/GreenDonut.Data.EntityFramework/Extensions/PagingQueryableExtensions.cs b/src/GreenDonut/src/GreenDonut.Data.EntityFramework/Extensions/PagingQueryableExtensions.cs index d0793f412a4..26317726735 100644 --- a/src/GreenDonut/src/GreenDonut.Data.EntityFramework/Extensions/PagingQueryableExtensions.cs +++ b/src/GreenDonut/src/GreenDonut.Data.EntityFramework/Extensions/PagingQueryableExtensions.cs @@ -120,7 +120,11 @@ public static async ValueTask> ToPageAsync( if (arguments.After is not null) { cursor = CursorParser.Parse(arguments.After, keys); - var (whereExpr, cursorOffset) = BuildWhereExpression(keys, cursor, true); + var (whereExpr, cursorOffset) = BuildWhereExpression( + keys, + cursor, + true, + arguments.NullOrdering); source = source.Where(whereExpr); offset = cursorOffset; @@ -145,7 +149,11 @@ public static async ValueTask> ToPageAsync( } cursor = CursorParser.Parse(arguments.Before, keys); - var (whereExpr, cursorOffset) = BuildWhereExpression(keys, cursor, false); + var (whereExpr, cursorOffset) = BuildWhereExpression( + keys, + cursor, + false, + arguments.NullOrdering); source = source.Where(whereExpr); offset = cursorOffset; diff --git a/src/GreenDonut/src/GreenDonut.Data.Primitives/NullOrdering.cs b/src/GreenDonut/src/GreenDonut.Data.Primitives/NullOrdering.cs new file mode 100644 index 00000000000..8a086dea64e --- /dev/null +++ b/src/GreenDonut/src/GreenDonut.Data.Primitives/NullOrdering.cs @@ -0,0 +1,19 @@ +namespace GreenDonut.Data; + +public enum NullOrdering +{ + /// The null ordering is not specified. + Unspecified = 0, + + /// + /// The database orders null values first (i.e., null is considered less than + /// non-null values). + /// + NativeNullsFirst = 1, + + /// + /// The database orders null values last (i.e., null is considered greater than + /// non-null values). + /// + NativeNullsLast = 2 +} diff --git a/src/GreenDonut/src/GreenDonut.Data.Primitives/PagingArguments.cs b/src/GreenDonut/src/GreenDonut.Data.Primitives/PagingArguments.cs index e150e81e6fa..e0d28eb1a15 100644 --- a/src/GreenDonut/src/GreenDonut.Data.Primitives/PagingArguments.cs +++ b/src/GreenDonut/src/GreenDonut.Data.Primitives/PagingArguments.cs @@ -67,6 +67,9 @@ public PagingArguments( /// public bool EnableRelativeCursors { get; init; } + /// Defines the null ordering to be used. + public NullOrdering NullOrdering { get; init; } + /// /// Deconstructs the paging arguments into its components. /// diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/BoolCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/BoolCursorKeySerializer.cs index d7dfda0b1a2..f8161ab62eb 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/BoolCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/BoolCursorKeySerializer.cs @@ -8,7 +8,7 @@ internal sealed class BoolCursorKeySerializer : ICursorKeySerializer private static readonly MethodInfo s_compareTo = CompareToResolver.GetCompareToMethod(); public bool IsSupported(Type type) - => type == typeof(bool); + => type == typeof(bool) || type == typeof(bool?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DateOnlyCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DateOnlyCursorKeySerializer.cs index 0f60548f71e..6698333a3cd 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DateOnlyCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DateOnlyCursorKeySerializer.cs @@ -12,7 +12,7 @@ internal sealed class DateOnlyCursorKeySerializer : ICursorKeySerializer private const string DateFormat = "yyyyMMdd"; public bool IsSupported(Type type) - => type == typeof(DateOnly); + => type == typeof(DateOnly) || type == typeof(DateOnly?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DateTimeCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DateTimeCursorKeySerializer.cs index 96e0b1bf929..775017058c8 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DateTimeCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DateTimeCursorKeySerializer.cs @@ -13,7 +13,7 @@ internal sealed class DateTimeCursorKeySerializer : ICursorKeySerializer private const string DateTimeFormat = "yyyyMMddHHmmssfffffff"; public bool IsSupported(Type type) - => type == typeof(DateTime); + => type == typeof(DateTime) || type == typeof(DateTime?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DateTimeOffsetCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DateTimeOffsetCursorKeySerializer.cs index 7f58f5a8611..8b9900067ce 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DateTimeOffsetCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DateTimeOffsetCursorKeySerializer.cs @@ -14,7 +14,7 @@ internal sealed class DateTimeOffsetCursorKeySerializer : ICursorKeySerializer private const string OffsetFormat = "hhmm"; public bool IsSupported(Type type) - => type == typeof(DateTimeOffset); + => type == typeof(DateTimeOffset) || type == typeof(DateTimeOffset?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DecimalCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DecimalCursorKeySerializer.cs index 8a6988c30d7..2db8b7358f8 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DecimalCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DecimalCursorKeySerializer.cs @@ -8,7 +8,7 @@ internal sealed class DecimalCursorKeySerializer : ICursorKeySerializer private static readonly MethodInfo s_compareTo = CompareToResolver.GetCompareToMethod(); public bool IsSupported(Type type) - => type == typeof(decimal); + => type == typeof(decimal) || type == typeof(decimal?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DoubleCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DoubleCursorKeySerializer.cs index f2bbba889b6..822e7ea1481 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DoubleCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/DoubleCursorKeySerializer.cs @@ -8,7 +8,7 @@ internal sealed class DoubleCursorKeySerializer : ICursorKeySerializer private static readonly MethodInfo s_compareTo = CompareToResolver.GetCompareToMethod(); public bool IsSupported(Type type) - => type == typeof(double); + => type == typeof(double) || type == typeof(double?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/FloatCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/FloatCursorKeySerializer.cs index c55f988d7a6..fd6467e12ea 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/FloatCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/FloatCursorKeySerializer.cs @@ -8,7 +8,7 @@ internal sealed class FloatCursorKeySerializer : ICursorKeySerializer private static readonly MethodInfo s_compareTo = CompareToResolver.GetCompareToMethod(); public bool IsSupported(Type type) - => type == typeof(float); + => type == typeof(float) || type == typeof(float?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/GuidCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/GuidCursorKeySerializer.cs index 9174ee67b3d..9840c4cdc5a 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/GuidCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/GuidCursorKeySerializer.cs @@ -8,7 +8,7 @@ internal sealed class GuidCursorKeySerializer : ICursorKeySerializer private static readonly MethodInfo s_compareTo = CompareToResolver.GetCompareToMethod(); public bool IsSupported(Type type) - => type == typeof(Guid); + => type == typeof(Guid) || type == typeof(Guid?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/IntCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/IntCursorKeySerializer.cs index d33eee4b2a2..73bef74b1bd 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/IntCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/IntCursorKeySerializer.cs @@ -8,7 +8,7 @@ internal sealed class IntCursorKeySerializer : ICursorKeySerializer private static readonly MethodInfo s_compareTo = CompareToResolver.GetCompareToMethod(); public bool IsSupported(Type type) - => type == typeof(int); + => type == typeof(int) || type == typeof(int?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/LongCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/LongCursorKeySerializer.cs index c798c778fd6..260baef755d 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/LongCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/LongCursorKeySerializer.cs @@ -8,7 +8,7 @@ internal sealed class LongCursorKeySerializer : ICursorKeySerializer private static readonly MethodInfo s_compareTo = CompareToResolver.GetCompareToMethod(); public bool IsSupported(Type type) - => type == typeof(long); + => type == typeof(long) || type == typeof(long?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/ShortCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/ShortCursorKeySerializer.cs index e5e4208de6a..c9b308a146a 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/ShortCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/ShortCursorKeySerializer.cs @@ -8,7 +8,7 @@ internal sealed class ShortCursorKeySerializer : ICursorKeySerializer private static readonly MethodInfo s_compareTo = CompareToResolver.GetCompareToMethod(); public bool IsSupported(Type type) - => type == typeof(short); + => type == typeof(short) || type == typeof(short?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/TimeOnlyCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/TimeOnlyCursorKeySerializer.cs index b3057c6c234..9779e7a9473 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/TimeOnlyCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/TimeOnlyCursorKeySerializer.cs @@ -12,7 +12,7 @@ internal sealed class TimeOnlyCursorKeySerializer : ICursorKeySerializer private const string TimeFormat = "HHmmssfffffff"; public bool IsSupported(Type type) - => type == typeof(TimeOnly); + => type == typeof(TimeOnly) || type == typeof(TimeOnly?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/UIntCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/UIntCursorKeySerializer.cs index 668874d013e..3a1b461fc9d 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/UIntCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/UIntCursorKeySerializer.cs @@ -8,7 +8,7 @@ internal sealed class UIntCursorKeySerializer : ICursorKeySerializer private static readonly MethodInfo s_compareTo = CompareToResolver.GetCompareToMethod(); public bool IsSupported(Type type) - => type == typeof(uint); + => type == typeof(uint) || type == typeof(uint?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/ULongCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/ULongCursorKeySerializer.cs index 4dd8f560246..efba41b5b92 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/ULongCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/ULongCursorKeySerializer.cs @@ -8,7 +8,7 @@ internal sealed class ULongCursorKeySerializer : ICursorKeySerializer private static readonly MethodInfo s_compareTo = CompareToResolver.GetCompareToMethod(); public bool IsSupported(Type type) - => type == typeof(ulong); + => type == typeof(ulong) || type == typeof(ulong?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/UShortCursorKeySerializer.cs b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/UShortCursorKeySerializer.cs index b7db336fa36..0ab2949b0c3 100644 --- a/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/UShortCursorKeySerializer.cs +++ b/src/GreenDonut/src/GreenDonut.Data/Cursors/Serializers/UShortCursorKeySerializer.cs @@ -8,7 +8,7 @@ internal sealed class UShortCursorKeySerializer : ICursorKeySerializer private static readonly MethodInfo s_compareTo = CompareToResolver.GetCompareToMethod(); public bool IsSupported(Type type) - => type == typeof(ushort); + => type == typeof(ushort) || type == typeof(ushort?); public MethodInfo GetCompareToMethod(Type type) => s_compareTo; diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/GreenDonut.Data.EntityFramework.Tests.csproj b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/GreenDonut.Data.EntityFramework.Tests.csproj index d4b1212772a..131b0c3a3d7 100644 --- a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/GreenDonut.Data.EntityFramework.Tests.csproj +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/GreenDonut.Data.EntityFramework.Tests.csproj @@ -13,8 +13,10 @@ + + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/PagingHelperPostgreSqlNullableTests.cs b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/PagingHelperPostgreSqlNullableTests.cs new file mode 100644 index 00000000000..427b997904f --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/PagingHelperPostgreSqlNullableTests.cs @@ -0,0 +1,362 @@ +using GreenDonut.Data.TestContext; +using Squadron; +using Record = GreenDonut.Data.TestContext.Record; + +namespace GreenDonut.Data; + +[Collection(PostgresCacheCollectionFixture.DefinitionName)] +public class PagingHelperPostgreSqlNullableTests(PostgreSqlResource resource) +{ + private string CreateConnectionString() + => resource.GetConnectionString($"db_{Guid.NewGuid():N}"); + + [Fact] + public async Task Paging_Nullable_Ascending_Cursor_Value_NonNull() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(2) { NullOrdering = NullOrdering.NativeNullsLast }; + await using var context = new NullableTestsContext(Provider.PostgreSql, connectionString); + var page1 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.Time) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.Time) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot(postFix: TestEnvironment.TargetFramework); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact] + public async Task Paging_Nullable_Descending_Cursor_Value_NonNull() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(2) { NullOrdering = NullOrdering.NativeNullsLast }; + await using var context = new NullableTestsContext(Provider.PostgreSql, connectionString); + var page1 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.Time) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.Time) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot( + postFix: TestEnvironment.TargetFramework == "NET10_0" + ? TestEnvironment.TargetFramework + : null); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact] + public async Task Paging_Nullable_Ascending_Cursor_Value_Null() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(3) { NullOrdering = NullOrdering.NativeNullsLast }; + await using var context = new NullableTestsContext(Provider.PostgreSql, connectionString); + var page1 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.Time) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.Time) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot(postFix: TestEnvironment.TargetFramework); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact] + public async Task Paging_Nullable_Descending_Cursor_Value_Null() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(3) { NullOrdering = NullOrdering.NativeNullsLast }; + await using var context = new NullableTestsContext(Provider.PostgreSql, connectionString); + var page1 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.Time) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.Time) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot( + postFix: TestEnvironment.TargetFramework == "NET10_0" + ? TestEnvironment.TargetFramework + : null); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact] + public async Task Paging_NullableReference_Ascending_Cursor_Value_NonNull() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(2) { NullOrdering = NullOrdering.NativeNullsLast }; + await using var context = new NullableTestsContext(Provider.PostgreSql, connectionString); + var page1 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.String) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.String) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot(postFix: TestEnvironment.TargetFramework); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact] + public async Task Paging_NullableReference_Descending_Cursor_Value_NonNull() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(2) { NullOrdering = NullOrdering.NativeNullsLast }; + await using var context = new NullableTestsContext(Provider.PostgreSql, connectionString); + var page1 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.String) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.String) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot( + postFix: TestEnvironment.TargetFramework == "NET10_0" + ? TestEnvironment.TargetFramework + : null); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact] + public async Task Paging_NullableReference_Ascending_Cursor_Value_Null() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(3) { NullOrdering = NullOrdering.NativeNullsLast }; + await using var context = new NullableTestsContext(Provider.PostgreSql, connectionString); + var page1 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.String) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.String) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot(postFix: TestEnvironment.TargetFramework); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact] + public async Task Paging_NullableReference_Descending_Cursor_Value_Null() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(3) { NullOrdering = NullOrdering.NativeNullsLast }; + await using var context = new NullableTestsContext(Provider.PostgreSql, connectionString); + var page1 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.String) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.String) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot( + postFix: TestEnvironment.TargetFramework == "NET10_0" + ? TestEnvironment.TargetFramework + : null); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact]// move to separate test class? + public async Task Paging_Nullable_Throws_When_NullOrdering_Not_Specified() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + async Task Act() + { + var arguments = new PagingArguments(2); + await using var context + = new NullableTestsContext(Provider.PostgreSql, connectionString); + var page1 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.Time) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.Time) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + } + + // Assert + Assert.Equal( + "The NullOrdering option must be specified in the paging options or arguments when " + + "using nullable keys.", + (await Assert.ThrowsAsync(Act)).Message); + } + + private static async Task SeedAsync(string connectionString) + { + await using var context = new NullableTestsContext(Provider.PostgreSql, connectionString); + await context.Database.EnsureCreatedAsync(); + + // https://stackoverflow.com/questions/68971695/cursor-pagination-prev-next-with-null-values + // ... with the addition of a String property to test nullable reference types. + context.Records.AddRange( + new Record + { + Id = Guid.Parse("68a5c7c2-1234-4def-bc01-9f1a23456789"), + Date = new DateOnly(2017, 10, 28), + Time = new TimeOnly(22, 00, 00), + String = "22:00:00" + }, + new Record + { + Id = Guid.Parse("d3b7e9f1-4567-4abc-a102-8c2b34567890"), + Date = new DateOnly(2017, 11, 03), + Time = null, + String = null + }, + new Record + { + Id = Guid.Parse("dd8f3a21-89ab-4cde-a203-7d3c45678901"), + Date = new DateOnly(2017, 11, 03), + Time = new TimeOnly(21, 45, 00), + String = "21:45:00" + }, + new Record + { + Id = Guid.Parse("62ce9d54-2345-4f01-b304-6e4d56789012"), + Date = new DateOnly(2017, 11, 04), + Time = new TimeOnly(14, 00, 00), + String = "14:00:00" + }, + new Record + { + Id = Guid.Parse("a1d5b763-6789-4f23-c405-5f5e67890123"), + Date = new DateOnly(2017, 11, 04), + Time = new TimeOnly(19, 40, 00), + String = "19:40:00" + }); + + await context.SaveChangesAsync(); + } +} diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/PagingHelperSqlServerNullableTests.cs b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/PagingHelperSqlServerNullableTests.cs new file mode 100644 index 00000000000..84eaf510b00 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/PagingHelperSqlServerNullableTests.cs @@ -0,0 +1,315 @@ +using GreenDonut.Data.TestContext; +using Squadron; +using Record = GreenDonut.Data.TestContext.Record; + +namespace GreenDonut.Data; + +[Collection(SqlServerCacheCollectionFixture.DefinitionName)] +public class PagingHelperSqlServerNullableTests(SqlServerResource resource) +{ + private string CreateConnectionString() + => resource.CreateConnectionString($"db_{Guid.NewGuid():N}"); + + [Fact] + public async Task Paging_Nullable_Ascending_Cursor_Value_NonNull() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(3) { NullOrdering = NullOrdering.NativeNullsFirst }; + await using var context = new NullableTestsContext(Provider.SqlServer, connectionString); + var page1 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.Time) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.Time) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot(postFix: TestEnvironment.TargetFramework); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact] + public async Task Paging_Nullable_Descending_Cursor_Value_NonNull() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(3) { NullOrdering = NullOrdering.NativeNullsFirst }; + await using var context = new NullableTestsContext(Provider.SqlServer, connectionString); + var page1 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.Time) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.Time) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot(postFix: TestEnvironment.TargetFramework); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact] + public async Task Paging_Nullable_Ascending_Cursor_Value_Null() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(2) { NullOrdering = NullOrdering.NativeNullsFirst }; + await using var context = new NullableTestsContext(Provider.SqlServer, connectionString); + var page1 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.Time) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.Time) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot(postFix: TestEnvironment.TargetFramework); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact] + public async Task Paging_Nullable_Descending_Cursor_Value_Null() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(4) { NullOrdering = NullOrdering.NativeNullsFirst }; + await using var context = new NullableTestsContext(Provider.SqlServer, connectionString); + var page1 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.Time) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.Time) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot(postFix: TestEnvironment.TargetFramework); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact] + public async Task Paging_NullableReference_Ascending_Cursor_Value_NonNull() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(3) { NullOrdering = NullOrdering.NativeNullsFirst }; + await using var context = new NullableTestsContext(Provider.SqlServer, connectionString); + var page1 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.String) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.String) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot(postFix: TestEnvironment.TargetFramework); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact] + public async Task Paging_NullableReference_Descending_Cursor_Value_NonNull() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(3) { NullOrdering = NullOrdering.NativeNullsFirst }; + await using var context = new NullableTestsContext(Provider.SqlServer, connectionString); + var page1 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.String) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.String) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot(TestEnvironment.TargetFramework); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact] + public async Task Paging_NullableReference_Ascending_Cursor_Value_Null() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(2) { NullOrdering = NullOrdering.NativeNullsFirst }; + await using var context = new NullableTestsContext(Provider.SqlServer, connectionString); + var page1 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.String) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderBy(t => t.Date) + .ThenBy(t => t.String) + .ThenBy(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot(postFix: TestEnvironment.TargetFramework); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + [Fact] + public async Task Paging_NullableReference_Descending_Cursor_Value_Null() + { + // Arrange + using var interceptor = new CapturePagingQueryInterceptor(); + var connectionString = CreateConnectionString(); + await SeedAsync(connectionString); + + // Act + var arguments = new PagingArguments(4) { NullOrdering = NullOrdering.NativeNullsFirst }; + await using var context = new NullableTestsContext(Provider.SqlServer, connectionString); + var page1 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.String) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + arguments = arguments with { After = page1.CreateCursor(page1.Last!) }; + var page2 = await context.Records + .OrderByDescending(t => t.Date) + .ThenByDescending(t => t.String) + .ThenByDescending(t => t.Id) + .ToPageAsync(arguments); + + // Assert + var snapshot = new Snapshot(TestEnvironment.TargetFramework); + snapshot.Add(page1); + snapshot.Add(page2); + snapshot.AddSql(interceptor); + snapshot.MatchMarkdownSnapshot(); + } + + private static async Task SeedAsync(string connectionString) + { + await using var context = new NullableTestsContext(Provider.SqlServer, connectionString); + await context.Database.EnsureCreatedAsync(); + + // https://stackoverflow.com/questions/68971695/cursor-pagination-prev-next-with-null-values + // ... with the addition of a String property to test nullable reference types. + context.Records.AddRange( + new Record + { + Id = Guid.Parse("68a5c7c2-1234-4def-bc01-9f1a23456789"), + Date = new DateOnly(2017, 10, 28), + Time = new TimeOnly(22, 00, 00), + String = "22:00:00" + }, + new Record + { + Id = Guid.Parse("d3b7e9f1-4567-4abc-a102-8c2b34567890"), + Date = new DateOnly(2017, 11, 03), + Time = null, + String = null + }, + new Record + { + Id = Guid.Parse("dd8f3a21-89ab-4cde-a203-7d3c45678901"), + Date = new DateOnly(2017, 11, 03), + Time = new TimeOnly(21, 45, 00), + String = "21:45:00" + }, + new Record + { + Id = Guid.Parse("62ce9d54-2345-4f01-b304-6e4d56789012"), + Date = new DateOnly(2017, 11, 04), + Time = new TimeOnly(14, 00, 00), + String = "14:00:00" + }, + new Record + { + Id = Guid.Parse("a1d5b763-6789-4f23-c405-5f5e67890123"), + Date = new DateOnly(2017, 11, 04), + Time = new TimeOnly(19, 40, 00), + String = "19:40:00" + }); + + await context.SaveChangesAsync(); + } +} diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/SqlServerCacheCollectionFixture.cs b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/SqlServerCacheCollectionFixture.cs new file mode 100644 index 00000000000..53337da749b --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/SqlServerCacheCollectionFixture.cs @@ -0,0 +1,9 @@ +using Squadron; + +namespace GreenDonut.Data; + +[CollectionDefinition(DefinitionName)] +public class SqlServerCacheCollectionFixture : ICollectionFixture +{ + internal const string DefinitionName = "SqlServerResource"; +} diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/TestContext/NullableTestsContext.cs b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/TestContext/NullableTestsContext.cs new file mode 100644 index 00000000000..67c10249666 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/TestContext/NullableTestsContext.cs @@ -0,0 +1,37 @@ +using Microsoft.EntityFrameworkCore; + +namespace GreenDonut.Data.TestContext; + +public class NullableTestsContext(Provider provider, string connectionString) : DbContext +{ + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + switch (provider) + { + case Provider.PostgreSql: + optionsBuilder.UseNpgsql(connectionString); + break; + case Provider.SqlServer: + optionsBuilder.UseSqlServer(connectionString); + break; + default: + throw new InvalidOperationException(); + } + } + + public DbSet Records { get; set; } = null!; +} + +public class Record +{ + public Guid Id { get; set; } + public DateOnly? Date { get; set; } + public TimeOnly? Time { get; set; } + public string? String { get; set; } +} + +public enum Provider +{ + PostgreSql, + SqlServer +} diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET10_0.md index 0f175695fd2..665c052e606 100644 --- a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET10_0.md +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET10_0.md @@ -16,7 +16,7 @@ LIMIT @p ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) > 0)))).Take(6) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) > 0)))).Take(6) ``` ## Result 3 diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET8_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET8_0.md index 04f7903b579..a99178b77ab 100644 --- a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET8_0.md +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET8_0.md @@ -16,7 +16,7 @@ LIMIT @__p_2 ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) > 0)))).Take(6) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) > 0)))).Take(6) ``` ## Result 3 diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET9_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET9_0.md index 04f7903b579..a99178b77ab 100644 --- a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET9_0.md +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET9_0.md @@ -16,7 +16,7 @@ LIMIT @__p_2 ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) > 0)))).Take(6) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) > 0)))).Take(6) ``` ## Result 3 diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET10_0.md index 53776b7c1c0..b3ce7d699ae 100644 --- a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET10_0.md +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET10_0.md @@ -16,7 +16,7 @@ LIMIT @p ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderByDescending(t => t.Name).ThenByDescending(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) < 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) < 0)))).Take(6) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderByDescending(t => t.Name).ThenByDescending(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) < 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) < 0)))).Take(6) ``` ## Result 3 diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET8_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET8_0.md index ec12ab52cce..f00da3147dd 100644 --- a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET8_0.md +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET8_0.md @@ -16,7 +16,7 @@ LIMIT @__p_2 ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderByDescending(t => t.Name).ThenByDescending(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) < 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) < 0)))).Take(6) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderByDescending(t => t.Name).ThenByDescending(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) < 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) < 0)))).Take(6) ``` ## Result 3 diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET9_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET9_0.md index ec12ab52cce..f00da3147dd 100644 --- a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET9_0.md +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET9_0.md @@ -16,7 +16,7 @@ LIMIT @__p_2 ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderByDescending(t => t.Name).ThenByDescending(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) < 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) < 0)))).Take(6) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderByDescending(t => t.Name).ThenByDescending(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) < 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) < 0)))).Take(6) ``` ## Result 3 diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET10_0.md new file mode 100644 index 00000000000..23c71afc360 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET10_0.md @@ -0,0 +1,64 @@ +# Paging_NullableReference_Ascending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## SQL 0 + +```sql +-- @p='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date", r."String", r."Id" +LIMIT @p +``` + +## SQL 1 + +```sql +-- @value='11/03/2017' (DbType = Date) +-- @value1='21:45:00' +-- @value4='dd8f3a21-89ab-4cde-a203-7d3c45678901' +-- @p='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" > @value OR r."Date" IS NULL OR (r."Date" = @value AND (r."String" > @value1 OR r."String" IS NULL)) OR (r."Date" = @value AND r."String" = @value1 AND r."Id" > @value4) +ORDER BY r."Date", r."String", r."Id" +LIMIT @p +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET8_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET8_0.md new file mode 100644 index 00000000000..1af16bae548 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET8_0.md @@ -0,0 +1,64 @@ +# Paging_NullableReference_Ascending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## SQL 0 + +```sql +-- @__p_0='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date", r."String", r."Id" +LIMIT @__p_0 +``` + +## SQL 1 + +```sql +-- @__value_0='11/03/2017' (DbType = Date) +-- @__value_1='21:45:00' +-- @__value_2='dd8f3a21-89ab-4cde-a203-7d3c45678901' +-- @__p_3='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE (r."Date" > @__value_0 OR r."Date" IS NULL) OR (r."Date" = @__value_0 AND (r."String" > @__value_1 OR r."String" IS NULL)) OR (r."Date" = @__value_0 AND r."String" = @__value_1 AND r."Id" > @__value_2) +ORDER BY r."Date", r."String", r."Id" +LIMIT @__p_3 +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET9_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET9_0.md new file mode 100644 index 00000000000..e7ab1a08eb6 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET9_0.md @@ -0,0 +1,64 @@ +# Paging_NullableReference_Ascending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## SQL 0 + +```sql +-- @__p_0='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date", r."String", r."Id" +LIMIT @__p_0 +``` + +## SQL 1 + +```sql +-- @__value_0='11/03/2017' (DbType = Date) +-- @__value_1='21:45:00' +-- @__value_2='dd8f3a21-89ab-4cde-a203-7d3c45678901' +-- @__p_3='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" > @__value_0 OR r."Date" IS NULL OR (r."Date" = @__value_0 AND (r."String" > @__value_1 OR r."String" IS NULL)) OR (r."Date" = @__value_0 AND r."String" = @__value_1 AND r."Id" > @__value_2) +ORDER BY r."Date", r."String", r."Id" +LIMIT @__p_3 +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET10_0.md new file mode 100644 index 00000000000..7ba32e431e3 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET10_0.md @@ -0,0 +1,69 @@ +# Paging_NullableReference_Ascending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + } +] +``` + +## SQL 0 + +```sql +-- @p='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date", r."String", r."Id" +LIMIT @p +``` + +## SQL 1 + +```sql +-- @value='11/03/2017' (DbType = Date) +-- @value2='d3b7e9f1-4567-4abc-a102-8c2b34567890' +-- @p='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" > @value OR r."Date" IS NULL OR (r."Date" = @value AND r."String" IS NULL AND r."Id" > @value2) +ORDER BY r."Date", r."String", r."Id" +LIMIT @p +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET8_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET8_0.md new file mode 100644 index 00000000000..8a716e2963e --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET8_0.md @@ -0,0 +1,69 @@ +# Paging_NullableReference_Ascending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + } +] +``` + +## SQL 0 + +```sql +-- @__p_0='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date", r."String", r."Id" +LIMIT @__p_0 +``` + +## SQL 1 + +```sql +-- @__value_0='11/03/2017' (DbType = Date) +-- @__value_1='d3b7e9f1-4567-4abc-a102-8c2b34567890' +-- @__p_2='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE (r."Date" > @__value_0 OR r."Date" IS NULL) OR (r."Date" = @__value_0 AND r."String" IS NULL AND r."Id" > @__value_1) +ORDER BY r."Date", r."String", r."Id" +LIMIT @__p_2 +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET9_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET9_0.md new file mode 100644 index 00000000000..d8e5e63834b --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET9_0.md @@ -0,0 +1,69 @@ +# Paging_NullableReference_Ascending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + } +] +``` + +## SQL 0 + +```sql +-- @__p_0='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date", r."String", r."Id" +LIMIT @__p_0 +``` + +## SQL 1 + +```sql +-- @__value_0='11/03/2017' (DbType = Date) +-- @__value_1='d3b7e9f1-4567-4abc-a102-8c2b34567890' +-- @__p_2='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" > @__value_0 OR r."Date" IS NULL OR (r."Date" = @__value_0 AND r."String" IS NULL AND r."Id" > @__value_1) +ORDER BY r."Date", r."String", r."Id" +LIMIT @__p_2 +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull.md new file mode 100644 index 00000000000..30902a1d8b8 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull.md @@ -0,0 +1,64 @@ +# Paging_NullableReference_Descending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## SQL 0 + +```sql +-- @__p_0='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date" DESC, r."String" DESC, r."Id" DESC +LIMIT @__p_0 +``` + +## SQL 1 + +```sql +-- @__value_0='11/04/2017' (DbType = Date) +-- @__value_1='14:00:00' +-- @__value_2='62ce9d54-2345-4f01-b304-6e4d56789012' +-- @__p_3='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" < @__value_0 OR (r."Date" = @__value_0 AND r."String" < @__value_1) OR (r."Date" = @__value_0 AND r."String" = @__value_1 AND r."Id" < @__value_2) +ORDER BY r."Date" DESC, r."String" DESC, r."Id" DESC +LIMIT @__p_3 +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull_NET10_0.md new file mode 100644 index 00000000000..452e0689e8a --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull_NET10_0.md @@ -0,0 +1,64 @@ +# Paging_NullableReference_Descending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## SQL 0 + +```sql +-- @p='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date" DESC, r."String" DESC, r."Id" DESC +LIMIT @p +``` + +## SQL 1 + +```sql +-- @value='11/04/2017' (DbType = Date) +-- @value1='14:00:00' +-- @value4='62ce9d54-2345-4f01-b304-6e4d56789012' +-- @p='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" < @value OR (r."Date" = @value AND r."String" < @value1) OR (r."Date" = @value AND r."String" = @value1 AND r."Id" < @value4) +ORDER BY r."Date" DESC, r."String" DESC, r."Id" DESC +LIMIT @p +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null.md new file mode 100644 index 00000000000..2f5f9f64c7f --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null.md @@ -0,0 +1,69 @@ +# Paging_NullableReference_Descending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +-- @__p_0='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date" DESC, r."String" DESC, r."Id" DESC +LIMIT @__p_0 +``` + +## SQL 1 + +```sql +-- @__value_0='11/03/2017' (DbType = Date) +-- @__value_1='d3b7e9f1-4567-4abc-a102-8c2b34567890' +-- @__p_2='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" < @__value_0 OR (r."Date" = @__value_0 AND r."String" IS NOT NULL) OR (r."Date" = @__value_0 AND r."String" IS NULL AND r."Id" < @__value_1) +ORDER BY r."Date" DESC, r."String" DESC, r."Id" DESC +LIMIT @__p_2 +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null_NET10_0.md new file mode 100644 index 00000000000..019a8f3499e --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null_NET10_0.md @@ -0,0 +1,69 @@ +# Paging_NullableReference_Descending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +-- @p='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date" DESC, r."String" DESC, r."Id" DESC +LIMIT @p +``` + +## SQL 1 + +```sql +-- @value='11/03/2017' (DbType = Date) +-- @value2='d3b7e9f1-4567-4abc-a102-8c2b34567890' +-- @p='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" < @value OR (r."Date" = @value AND r."String" IS NOT NULL) OR (r."Date" = @value AND r."String" IS NULL AND r."Id" < @value2) +ORDER BY r."Date" DESC, r."String" DESC, r."Id" DESC +LIMIT @p +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET10_0.md new file mode 100644 index 00000000000..003e7fa6f74 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET10_0.md @@ -0,0 +1,64 @@ +# Paging_Nullable_Ascending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## SQL 0 + +```sql +-- @p='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date", r."Time", r."Id" +LIMIT @p +``` + +## SQL 1 + +```sql +-- @value='11/03/2017' (DbType = Date) +-- @value1='21:45' (DbType = Time) +-- @value4='dd8f3a21-89ab-4cde-a203-7d3c45678901' +-- @p='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" > @value OR r."Date" IS NULL OR (r."Date" = @value AND (r."Time" > @value1 OR r."Time" IS NULL)) OR (r."Date" = @value AND r."Time" = @value1 AND r."Id" > @value4) +ORDER BY r."Date", r."Time", r."Id" +LIMIT @p +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET8_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET8_0.md new file mode 100644 index 00000000000..a0db4c68ae3 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET8_0.md @@ -0,0 +1,64 @@ +# Paging_Nullable_Ascending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## SQL 0 + +```sql +-- @__p_0='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date", r."Time", r."Id" +LIMIT @__p_0 +``` + +## SQL 1 + +```sql +-- @__value_0='11/03/2017' (DbType = Date) +-- @__value_1='21:45' (DbType = Time) +-- @__value_2='dd8f3a21-89ab-4cde-a203-7d3c45678901' +-- @__p_3='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE (r."Date" > @__value_0 OR r."Date" IS NULL) OR (r."Date" = @__value_0 AND (r."Time" > @__value_1 OR r."Time" IS NULL)) OR (r."Date" = @__value_0 AND r."Time" = @__value_1 AND r."Id" > @__value_2) +ORDER BY r."Date", r."Time", r."Id" +LIMIT @__p_3 +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET9_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET9_0.md new file mode 100644 index 00000000000..6366b17b4c0 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET9_0.md @@ -0,0 +1,64 @@ +# Paging_Nullable_Ascending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## SQL 0 + +```sql +-- @__p_0='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date", r."Time", r."Id" +LIMIT @__p_0 +``` + +## SQL 1 + +```sql +-- @__value_0='11/03/2017' (DbType = Date) +-- @__value_1='21:45' (DbType = Time) +-- @__value_2='dd8f3a21-89ab-4cde-a203-7d3c45678901' +-- @__p_3='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" > @__value_0 OR r."Date" IS NULL OR (r."Date" = @__value_0 AND (r."Time" > @__value_1 OR r."Time" IS NULL)) OR (r."Date" = @__value_0 AND r."Time" = @__value_1 AND r."Id" > @__value_2) +ORDER BY r."Date", r."Time", r."Id" +LIMIT @__p_3 +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET10_0.md new file mode 100644 index 00000000000..4ce17c08c29 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET10_0.md @@ -0,0 +1,69 @@ +# Paging_Nullable_Ascending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + } +] +``` + +## SQL 0 + +```sql +-- @p='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date", r."Time", r."Id" +LIMIT @p +``` + +## SQL 1 + +```sql +-- @value='11/03/2017' (DbType = Date) +-- @value2='d3b7e9f1-4567-4abc-a102-8c2b34567890' +-- @p='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" > @value OR r."Date" IS NULL OR (r."Date" = @value AND r."Time" IS NULL AND r."Id" > @value2) +ORDER BY r."Date", r."Time", r."Id" +LIMIT @p +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET8_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET8_0.md new file mode 100644 index 00000000000..35adec71f47 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET8_0.md @@ -0,0 +1,69 @@ +# Paging_Nullable_Ascending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + } +] +``` + +## SQL 0 + +```sql +-- @__p_0='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date", r."Time", r."Id" +LIMIT @__p_0 +``` + +## SQL 1 + +```sql +-- @__value_0='11/03/2017' (DbType = Date) +-- @__value_1='d3b7e9f1-4567-4abc-a102-8c2b34567890' +-- @__p_2='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE (r."Date" > @__value_0 OR r."Date" IS NULL) OR (r."Date" = @__value_0 AND r."Time" IS NULL AND r."Id" > @__value_1) +ORDER BY r."Date", r."Time", r."Id" +LIMIT @__p_2 +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET9_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET9_0.md new file mode 100644 index 00000000000..7cc215ace76 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET9_0.md @@ -0,0 +1,69 @@ +# Paging_Nullable_Ascending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + } +] +``` + +## SQL 0 + +```sql +-- @__p_0='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date", r."Time", r."Id" +LIMIT @__p_0 +``` + +## SQL 1 + +```sql +-- @__value_0='11/03/2017' (DbType = Date) +-- @__value_1='d3b7e9f1-4567-4abc-a102-8c2b34567890' +-- @__p_2='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" > @__value_0 OR r."Date" IS NULL OR (r."Date" = @__value_0 AND r."Time" IS NULL AND r."Id" > @__value_1) +ORDER BY r."Date", r."Time", r."Id" +LIMIT @__p_2 +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull.md new file mode 100644 index 00000000000..792a694d53b --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull.md @@ -0,0 +1,64 @@ +# Paging_Nullable_Descending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## SQL 0 + +```sql +-- @__p_0='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date" DESC, r."Time" DESC, r."Id" DESC +LIMIT @__p_0 +``` + +## SQL 1 + +```sql +-- @__value_0='11/04/2017' (DbType = Date) +-- @__value_1='14:00' (DbType = Time) +-- @__value_2='62ce9d54-2345-4f01-b304-6e4d56789012' +-- @__p_3='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" < @__value_0 OR (r."Date" = @__value_0 AND r."Time" < @__value_1) OR (r."Date" = @__value_0 AND r."Time" = @__value_1 AND r."Id" < @__value_2) +ORDER BY r."Date" DESC, r."Time" DESC, r."Id" DESC +LIMIT @__p_3 +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull_NET10_0.md new file mode 100644 index 00000000000..46e8a6c5ee2 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull_NET10_0.md @@ -0,0 +1,64 @@ +# Paging_Nullable_Descending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## SQL 0 + +```sql +-- @p='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date" DESC, r."Time" DESC, r."Id" DESC +LIMIT @p +``` + +## SQL 1 + +```sql +-- @value='11/04/2017' (DbType = Date) +-- @value1='14:00' (DbType = Time) +-- @value4='62ce9d54-2345-4f01-b304-6e4d56789012' +-- @p='3' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" < @value OR (r."Date" = @value AND r."Time" < @value1) OR (r."Date" = @value AND r."Time" = @value1 AND r."Id" < @value4) +ORDER BY r."Date" DESC, r."Time" DESC, r."Id" DESC +LIMIT @p +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Descending_Cursor_Value_Null.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Descending_Cursor_Value_Null.md new file mode 100644 index 00000000000..2870df1c929 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Descending_Cursor_Value_Null.md @@ -0,0 +1,69 @@ +# Paging_Nullable_Descending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +-- @__p_0='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date" DESC, r."Time" DESC, r."Id" DESC +LIMIT @__p_0 +``` + +## SQL 1 + +```sql +-- @__value_0='11/03/2017' (DbType = Date) +-- @__value_1='d3b7e9f1-4567-4abc-a102-8c2b34567890' +-- @__p_2='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" < @__value_0 OR (r."Date" = @__value_0 AND r."Time" IS NOT NULL) OR (r."Date" = @__value_0 AND r."Time" IS NULL AND r."Id" < @__value_1) +ORDER BY r."Date" DESC, r."Time" DESC, r."Id" DESC +LIMIT @__p_2 +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Descending_Cursor_Value_Null_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Descending_Cursor_Value_Null_NET10_0.md new file mode 100644 index 00000000000..5b0232099b2 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperPostgreSqlNullableTests.Paging_Nullable_Descending_Cursor_Value_Null_NET10_0.md @@ -0,0 +1,69 @@ +# Paging_Nullable_Descending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +-- @p='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +ORDER BY r."Date" DESC, r."Time" DESC, r."Id" DESC +LIMIT @p +``` + +## SQL 1 + +```sql +-- @value='11/03/2017' (DbType = Date) +-- @value2='d3b7e9f1-4567-4abc-a102-8c2b34567890' +-- @p='4' +SELECT r."Id", r."Date", r."String", r."Time" +FROM "Records" AS r +WHERE r."Date" < @value OR (r."Date" = @value AND r."Time" IS NOT NULL) OR (r."Date" = @value AND r."Time" IS NULL AND r."Id" < @value2) +ORDER BY r."Date" DESC, r."Time" DESC, r."Id" DESC +LIMIT @p +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET10_0.md new file mode 100644 index 00000000000..055bcc5126b --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET10_0.md @@ -0,0 +1,70 @@ +# Paging_NullableReference_Ascending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @p int = 4; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date], [r].[String], [r].[Id] +``` + +## SQL 1 + +```sql +DECLARE @p int = 4; +DECLARE @value date = '2017-11-03'; +DECLARE @value1 nvarchar(4000) = N'21:45:00'; +DECLARE @value4 uniqueIdentifier = 'dd8f3a21-89ab-4cde-a203-7d3c45678901'; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] > @value OR ([r].[Date] = @value AND [r].[String] > @value1) OR ([r].[Date] = @value AND [r].[String] = @value1 AND [r].[Id] > @value4) +ORDER BY [r].[Date], [r].[String], [r].[Id] +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET8_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET8_0.md new file mode 100644 index 00000000000..abfb4fcf4bc --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET8_0.md @@ -0,0 +1,70 @@ +# Paging_NullableReference_Ascending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 4; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date], [r].[String], [r].[Id] +``` + +## SQL 1 + +```sql +DECLARE @__p_3 int = 4; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 nvarchar(4000) = N'21:45:00'; +DECLARE @__value_2 uniqueIdentifier = 'dd8f3a21-89ab-4cde-a203-7d3c45678901'; + +SELECT TOP(@__p_3) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] > @__value_0 OR ([r].[Date] = @__value_0 AND [r].[String] > @__value_1) OR ([r].[Date] = @__value_0 AND [r].[String] = @__value_1 AND [r].[Id] > @__value_2) +ORDER BY [r].[Date], [r].[String], [r].[Id] +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET9_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET9_0.md new file mode 100644 index 00000000000..abfb4fcf4bc --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_NonNull_NET9_0.md @@ -0,0 +1,70 @@ +# Paging_NullableReference_Ascending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 4; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date], [r].[String], [r].[Id] +``` + +## SQL 1 + +```sql +DECLARE @__p_3 int = 4; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 nvarchar(4000) = N'21:45:00'; +DECLARE @__value_2 uniqueIdentifier = 'dd8f3a21-89ab-4cde-a203-7d3c45678901'; + +SELECT TOP(@__p_3) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] > @__value_0 OR ([r].[Date] = @__value_0 AND [r].[String] > @__value_1) OR ([r].[Date] = @__value_0 AND [r].[String] = @__value_1 AND [r].[Id] > @__value_2) +ORDER BY [r].[Date], [r].[String], [r].[Id] +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET10_0.md new file mode 100644 index 00000000000..849267986b1 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET10_0.md @@ -0,0 +1,63 @@ +# Paging_NullableReference_Ascending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @p int = 3; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date], [r].[String], [r].[Id] +``` + +## SQL 1 + +```sql +DECLARE @p int = 3; +DECLARE @value date = '2017-11-03'; +DECLARE @value2 uniqueIdentifier = 'd3b7e9f1-4567-4abc-a102-8c2b34567890'; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] > @value OR ([r].[Date] = @value AND [r].[String] IS NOT NULL) OR ([r].[Date] = @value AND [r].[String] IS NULL AND [r].[Id] > @value2) +ORDER BY [r].[Date], [r].[String], [r].[Id] +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET8_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET8_0.md new file mode 100644 index 00000000000..adc79f79cd5 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET8_0.md @@ -0,0 +1,63 @@ +# Paging_NullableReference_Ascending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 3; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date], [r].[String], [r].[Id] +``` + +## SQL 1 + +```sql +DECLARE @__p_2 int = 3; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 uniqueIdentifier = 'd3b7e9f1-4567-4abc-a102-8c2b34567890'; + +SELECT TOP(@__p_2) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] > @__value_0 OR ([r].[Date] = @__value_0 AND [r].[String] IS NOT NULL) OR ([r].[Date] = @__value_0 AND [r].[String] IS NULL AND [r].[Id] > @__value_1) +ORDER BY [r].[Date], [r].[String], [r].[Id] +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET9_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET9_0.md new file mode 100644 index 00000000000..adc79f79cd5 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Ascending_Cursor_Value_Null_NET9_0.md @@ -0,0 +1,63 @@ +# Paging_NullableReference_Ascending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 3; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date], [r].[String], [r].[Id] +``` + +## SQL 1 + +```sql +DECLARE @__p_2 int = 3; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 uniqueIdentifier = 'd3b7e9f1-4567-4abc-a102-8c2b34567890'; + +SELECT TOP(@__p_2) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] > @__value_0 OR ([r].[Date] = @__value_0 AND [r].[String] IS NOT NULL) OR ([r].[Date] = @__value_0 AND [r].[String] IS NULL AND [r].[Id] > @__value_1) +ORDER BY [r].[Date], [r].[String], [r].[Id] +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull_NET10_0.md new file mode 100644 index 00000000000..722bc9afcb8 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull_NET10_0.md @@ -0,0 +1,70 @@ +# Paging_NullableReference_Descending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @p int = 4; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date] DESC, [r].[String] DESC, [r].[Id] DESC +``` + +## SQL 1 + +```sql +DECLARE @p int = 4; +DECLARE @value date = '2017-11-03'; +DECLARE @value1 nvarchar(4000) = N'21:45:00'; +DECLARE @value4 uniqueIdentifier = 'dd8f3a21-89ab-4cde-a203-7d3c45678901'; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] < @value OR [r].[Date] IS NULL OR ([r].[Date] = @value AND ([r].[String] < @value1 OR [r].[String] IS NULL)) OR ([r].[Date] = @value AND [r].[String] = @value1 AND [r].[Id] < @value4) +ORDER BY [r].[Date] DESC, [r].[String] DESC, [r].[Id] DESC +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull_NET8_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull_NET8_0.md new file mode 100644 index 00000000000..d7c9093f98a --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull_NET8_0.md @@ -0,0 +1,82 @@ +# Paging_NullableReference_Descending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 4; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date] DESC, [r].[String] DESC, [r].[Id] DESC +``` + +## SQL 1 + +```sql +DECLARE @__p_3 int = 4; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 nvarchar(4000) = N'21:45:00'; +DECLARE @__value_2 uniqueIdentifier = 'dd8f3a21-89ab-4cde-a203-7d3c45678901'; + +SELECT TOP(@__p_3) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE CASE + WHEN [r].[Date] < @__value_0 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END | CASE + WHEN [r].[Date] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END = CAST(1 AS bit) OR ([r].[Date] = @__value_0 AND CASE + WHEN [r].[String] < @__value_1 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END | CASE + WHEN [r].[String] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END = CAST(1 AS bit)) OR ([r].[Date] = @__value_0 AND [r].[String] = @__value_1 AND [r].[Id] < @__value_2) +ORDER BY [r].[Date] DESC, [r].[String] DESC, [r].[Id] DESC +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull_NET9_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull_NET9_0.md new file mode 100644 index 00000000000..f3b92498151 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_NonNull_NET9_0.md @@ -0,0 +1,70 @@ +# Paging_NullableReference_Descending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 4; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date] DESC, [r].[String] DESC, [r].[Id] DESC +``` + +## SQL 1 + +```sql +DECLARE @__p_3 int = 4; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 nvarchar(4000) = N'21:45:00'; +DECLARE @__value_2 uniqueIdentifier = 'dd8f3a21-89ab-4cde-a203-7d3c45678901'; + +SELECT TOP(@__p_3) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] < @__value_0 OR [r].[Date] IS NULL OR ([r].[Date] = @__value_0 AND ([r].[String] < @__value_1 OR [r].[String] IS NULL)) OR ([r].[Date] = @__value_0 AND [r].[String] = @__value_1 AND [r].[Id] < @__value_2) +ORDER BY [r].[Date] DESC, [r].[String] DESC, [r].[Id] DESC +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null_NET10_0.md new file mode 100644 index 00000000000..1da599b764b --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null_NET10_0.md @@ -0,0 +1,69 @@ +# Paging_NullableReference_Descending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @p int = 5; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date] DESC, [r].[String] DESC, [r].[Id] DESC +``` + +## SQL 1 + +```sql +DECLARE @p int = 5; +DECLARE @value date = '2017-11-03'; +DECLARE @value2 uniqueIdentifier = 'd3b7e9f1-4567-4abc-a102-8c2b34567890'; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] < @value OR [r].[Date] IS NULL OR ([r].[Date] = @value AND [r].[String] IS NULL AND [r].[Id] < @value2) +ORDER BY [r].[Date] DESC, [r].[String] DESC, [r].[Id] DESC +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null_NET8_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null_NET8_0.md new file mode 100644 index 00000000000..51366a001ac --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null_NET8_0.md @@ -0,0 +1,75 @@ +# Paging_NullableReference_Descending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 5; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date] DESC, [r].[String] DESC, [r].[Id] DESC +``` + +## SQL 1 + +```sql +DECLARE @__p_2 int = 5; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 uniqueIdentifier = 'd3b7e9f1-4567-4abc-a102-8c2b34567890'; + +SELECT TOP(@__p_2) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE CASE + WHEN [r].[Date] < @__value_0 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END | CASE + WHEN [r].[Date] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END = CAST(1 AS bit) OR ([r].[Date] = @__value_0 AND [r].[String] IS NULL AND [r].[Id] < @__value_1) +ORDER BY [r].[Date] DESC, [r].[String] DESC, [r].[Id] DESC +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null_NET9_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null_NET9_0.md new file mode 100644 index 00000000000..11bd69f7565 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_NullableReference_Descending_Cursor_Value_Null_NET9_0.md @@ -0,0 +1,69 @@ +# Paging_NullableReference_Descending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 5; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date] DESC, [r].[String] DESC, [r].[Id] DESC +``` + +## SQL 1 + +```sql +DECLARE @__p_2 int = 5; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 uniqueIdentifier = 'd3b7e9f1-4567-4abc-a102-8c2b34567890'; + +SELECT TOP(@__p_2) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] < @__value_0 OR [r].[Date] IS NULL OR ([r].[Date] = @__value_0 AND [r].[String] IS NULL AND [r].[Id] < @__value_1) +ORDER BY [r].[Date] DESC, [r].[String] DESC, [r].[Id] DESC +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET10_0.md new file mode 100644 index 00000000000..898a60dfb19 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET10_0.md @@ -0,0 +1,70 @@ +# Paging_Nullable_Ascending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @p int = 4; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date], [r].[Time], [r].[Id] +``` + +## SQL 1 + +```sql +DECLARE @p int = 4; +DECLARE @value date = '2017-11-03'; +DECLARE @value1 time = '21:45:00'; +DECLARE @value4 uniqueIdentifier = 'dd8f3a21-89ab-4cde-a203-7d3c45678901'; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] > @value OR ([r].[Date] = @value AND [r].[Time] > @value1) OR ([r].[Date] = @value AND [r].[Time] = @value1 AND [r].[Id] > @value4) +ORDER BY [r].[Date], [r].[Time], [r].[Id] +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET8_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET8_0.md new file mode 100644 index 00000000000..1dbfc7d3655 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET8_0.md @@ -0,0 +1,70 @@ +# Paging_Nullable_Ascending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 4; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date], [r].[Time], [r].[Id] +``` + +## SQL 1 + +```sql +DECLARE @__p_3 int = 4; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 time = '21:45:00'; +DECLARE @__value_2 uniqueIdentifier = 'dd8f3a21-89ab-4cde-a203-7d3c45678901'; + +SELECT TOP(@__p_3) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] > @__value_0 OR ([r].[Date] = @__value_0 AND [r].[Time] > @__value_1) OR ([r].[Date] = @__value_0 AND [r].[Time] = @__value_1 AND [r].[Id] > @__value_2) +ORDER BY [r].[Date], [r].[Time], [r].[Id] +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET9_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET9_0.md new file mode 100644 index 00000000000..1dbfc7d3655 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_NonNull_NET9_0.md @@ -0,0 +1,70 @@ +# Paging_Nullable_Ascending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 4; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date], [r].[Time], [r].[Id] +``` + +## SQL 1 + +```sql +DECLARE @__p_3 int = 4; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 time = '21:45:00'; +DECLARE @__value_2 uniqueIdentifier = 'dd8f3a21-89ab-4cde-a203-7d3c45678901'; + +SELECT TOP(@__p_3) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] > @__value_0 OR ([r].[Date] = @__value_0 AND [r].[Time] > @__value_1) OR ([r].[Date] = @__value_0 AND [r].[Time] = @__value_1 AND [r].[Id] > @__value_2) +ORDER BY [r].[Date], [r].[Time], [r].[Id] +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET10_0.md new file mode 100644 index 00000000000..fd1483babd3 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET10_0.md @@ -0,0 +1,63 @@ +# Paging_Nullable_Ascending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @p int = 3; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date], [r].[Time], [r].[Id] +``` + +## SQL 1 + +```sql +DECLARE @p int = 3; +DECLARE @value date = '2017-11-03'; +DECLARE @value2 uniqueIdentifier = 'd3b7e9f1-4567-4abc-a102-8c2b34567890'; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] > @value OR ([r].[Date] = @value AND [r].[Time] IS NOT NULL) OR ([r].[Date] = @value AND [r].[Time] IS NULL AND [r].[Id] > @value2) +ORDER BY [r].[Date], [r].[Time], [r].[Id] +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET8_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET8_0.md new file mode 100644 index 00000000000..995abc2edc1 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET8_0.md @@ -0,0 +1,63 @@ +# Paging_Nullable_Ascending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 3; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date], [r].[Time], [r].[Id] +``` + +## SQL 1 + +```sql +DECLARE @__p_2 int = 3; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 uniqueIdentifier = 'd3b7e9f1-4567-4abc-a102-8c2b34567890'; + +SELECT TOP(@__p_2) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] > @__value_0 OR ([r].[Date] = @__value_0 AND [r].[Time] IS NOT NULL) OR ([r].[Date] = @__value_0 AND [r].[Time] IS NULL AND [r].[Id] > @__value_1) +ORDER BY [r].[Date], [r].[Time], [r].[Id] +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET9_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET9_0.md new file mode 100644 index 00000000000..995abc2edc1 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Ascending_Cursor_Value_Null_NET9_0.md @@ -0,0 +1,63 @@ +# Paging_Nullable_Ascending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 3; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date], [r].[Time], [r].[Id] +``` + +## SQL 1 + +```sql +DECLARE @__p_2 int = 3; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 uniqueIdentifier = 'd3b7e9f1-4567-4abc-a102-8c2b34567890'; + +SELECT TOP(@__p_2) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] > @__value_0 OR ([r].[Date] = @__value_0 AND [r].[Time] IS NOT NULL) OR ([r].[Date] = @__value_0 AND [r].[Time] IS NULL AND [r].[Id] > @__value_1) +ORDER BY [r].[Date], [r].[Time], [r].[Id] +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull_NET10_0.md new file mode 100644 index 00000000000..dedb9d14400 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull_NET10_0.md @@ -0,0 +1,70 @@ +# Paging_Nullable_Descending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @p int = 4; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date] DESC, [r].[Time] DESC, [r].[Id] DESC +``` + +## SQL 1 + +```sql +DECLARE @p int = 4; +DECLARE @value date = '2017-11-03'; +DECLARE @value1 time = '21:45:00'; +DECLARE @value4 uniqueIdentifier = 'dd8f3a21-89ab-4cde-a203-7d3c45678901'; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] < @value OR [r].[Date] IS NULL OR ([r].[Date] = @value AND ([r].[Time] < @value1 OR [r].[Time] IS NULL)) OR ([r].[Date] = @value AND [r].[Time] = @value1 AND [r].[Id] < @value4) +ORDER BY [r].[Date] DESC, [r].[Time] DESC, [r].[Id] DESC +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull_NET8_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull_NET8_0.md new file mode 100644 index 00000000000..dcd4d8aa3f2 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull_NET8_0.md @@ -0,0 +1,82 @@ +# Paging_Nullable_Descending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 4; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date] DESC, [r].[Time] DESC, [r].[Id] DESC +``` + +## SQL 1 + +```sql +DECLARE @__p_3 int = 4; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 time = '21:45:00'; +DECLARE @__value_2 uniqueIdentifier = 'dd8f3a21-89ab-4cde-a203-7d3c45678901'; + +SELECT TOP(@__p_3) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE CASE + WHEN [r].[Date] < @__value_0 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END | CASE + WHEN [r].[Date] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END = CAST(1 AS bit) OR ([r].[Date] = @__value_0 AND CASE + WHEN [r].[Time] < @__value_1 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END | CASE + WHEN [r].[Time] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END = CAST(1 AS bit)) OR ([r].[Date] = @__value_0 AND [r].[Time] = @__value_1 AND [r].[Id] < @__value_2) +ORDER BY [r].[Date] DESC, [r].[Time] DESC, [r].[Id] DESC +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull_NET9_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull_NET9_0.md new file mode 100644 index 00000000000..9df0db70857 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_NonNull_NET9_0.md @@ -0,0 +1,70 @@ +# Paging_Nullable_Descending_Cursor_Value_NonNull + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + }, + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 4; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date] DESC, [r].[Time] DESC, [r].[Id] DESC +``` + +## SQL 1 + +```sql +DECLARE @__p_3 int = 4; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 time = '21:45:00'; +DECLARE @__value_2 uniqueIdentifier = 'dd8f3a21-89ab-4cde-a203-7d3c45678901'; + +SELECT TOP(@__p_3) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] < @__value_0 OR [r].[Date] IS NULL OR ([r].[Date] = @__value_0 AND ([r].[Time] < @__value_1 OR [r].[Time] IS NULL)) OR ([r].[Date] = @__value_0 AND [r].[Time] = @__value_1 AND [r].[Id] < @__value_2) +ORDER BY [r].[Date] DESC, [r].[Time] DESC, [r].[Id] DESC +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_Null_NET10_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_Null_NET10_0.md new file mode 100644 index 00000000000..67b2e533765 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_Null_NET10_0.md @@ -0,0 +1,69 @@ +# Paging_Nullable_Descending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @p int = 5; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date] DESC, [r].[Time] DESC, [r].[Id] DESC +``` + +## SQL 1 + +```sql +DECLARE @p int = 5; +DECLARE @value date = '2017-11-03'; +DECLARE @value2 uniqueIdentifier = 'd3b7e9f1-4567-4abc-a102-8c2b34567890'; + +SELECT TOP(@p) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] < @value OR [r].[Date] IS NULL OR ([r].[Date] = @value AND [r].[Time] IS NULL AND [r].[Id] < @value2) +ORDER BY [r].[Date] DESC, [r].[Time] DESC, [r].[Id] DESC +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_Null_NET8_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_Null_NET8_0.md new file mode 100644 index 00000000000..d96256ab82d --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_Null_NET8_0.md @@ -0,0 +1,75 @@ +# Paging_Nullable_Descending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 5; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date] DESC, [r].[Time] DESC, [r].[Id] DESC +``` + +## SQL 1 + +```sql +DECLARE @__p_2 int = 5; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 uniqueIdentifier = 'd3b7e9f1-4567-4abc-a102-8c2b34567890'; + +SELECT TOP(@__p_2) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE CASE + WHEN [r].[Date] < @__value_0 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END | CASE + WHEN [r].[Date] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END = CAST(1 AS bit) OR ([r].[Date] = @__value_0 AND [r].[Time] IS NULL AND [r].[Id] < @__value_1) +ORDER BY [r].[Date] DESC, [r].[Time] DESC, [r].[Id] DESC +``` + diff --git a/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_Null_NET9_0.md b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_Null_NET9_0.md new file mode 100644 index 00000000000..e94bf68f2c7 --- /dev/null +++ b/src/GreenDonut/test/GreenDonut.Data.EntityFramework.Tests/__snapshots__/PagingHelperSqlServerNullableTests.Paging_Nullable_Descending_Cursor_Value_Null_NET9_0.md @@ -0,0 +1,69 @@ +# Paging_Nullable_Descending_Cursor_Value_Null + +## Result 1 + +```json +[ + { + "Id": "a1d5b763-6789-4f23-c405-5f5e67890123", + "Date": "2017-11-04", + "Time": "19:40:00", + "String": "19:40:00" + }, + { + "Id": "62ce9d54-2345-4f01-b304-6e4d56789012", + "Date": "2017-11-04", + "Time": "14:00:00", + "String": "14:00:00" + }, + { + "Id": "dd8f3a21-89ab-4cde-a203-7d3c45678901", + "Date": "2017-11-03", + "Time": "21:45:00", + "String": "21:45:00" + }, + { + "Id": "d3b7e9f1-4567-4abc-a102-8c2b34567890", + "Date": "2017-11-03", + "Time": null, + "String": null + } +] +``` + +## Result 2 + +```json +[ + { + "Id": "68a5c7c2-1234-4def-bc01-9f1a23456789", + "Date": "2017-10-28", + "Time": "22:00:00", + "String": "22:00:00" + } +] +``` + +## SQL 0 + +```sql +DECLARE @__p_0 int = 5; + +SELECT TOP(@__p_0) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +ORDER BY [r].[Date] DESC, [r].[Time] DESC, [r].[Id] DESC +``` + +## SQL 1 + +```sql +DECLARE @__p_2 int = 5; +DECLARE @__value_0 date = '2017-11-03'; +DECLARE @__value_1 uniqueIdentifier = 'd3b7e9f1-4567-4abc-a102-8c2b34567890'; + +SELECT TOP(@__p_2) [r].[Id], [r].[Date], [r].[String], [r].[Time] +FROM [Records] AS [r] +WHERE [r].[Date] < @__value_0 OR [r].[Date] IS NULL OR ([r].[Date] = @__value_0 AND [r].[Time] IS NULL AND [r].[Id] < @__value_1) +ORDER BY [r].[Date] DESC, [r].[Time] DESC, [r].[Id] DESC +``` + diff --git a/src/HotChocolate/Core/src/Types.Analyzers/FileBuilders/TypeFileBuilderBase.cs b/src/HotChocolate/Core/src/Types.Analyzers/FileBuilders/TypeFileBuilderBase.cs index a6f72ce21f3..70892187f66 100644 --- a/src/HotChocolate/Core/src/Types.Analyzers/FileBuilders/TypeFileBuilderBase.cs +++ b/src/HotChocolate/Core/src/Types.Analyzers/FileBuilders/TypeFileBuilderBase.cs @@ -943,9 +943,12 @@ private void WriteResolverArguments(Resolver resolver, IMethodSymbol resolverMet using (Writer.IncreaseIndent()) { Writer.WriteIndentedLine( - "EnableRelativeCursors = args{0}_flags.HasFlag(global::{1}.RelativeCursor)", + "EnableRelativeCursors = args{0}_flags.HasFlag(global::{1}.RelativeCursor),", i, WellKnownTypes.ConnectionFlags); + Writer.WriteIndentedLine( + "NullOrdering = args{0}_options.NullOrdering", + i); } Writer.WriteIndentedLine("};"); diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index 14cb4d64f72..08abbe5656a 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -58,6 +58,7 @@ + diff --git a/src/HotChocolate/Core/src/Types/Types/Pagination/PagingOptions.cs b/src/HotChocolate/Core/src/Types/Types/Pagination/PagingOptions.cs index 76520fdc183..9aba984c778 100644 --- a/src/HotChocolate/Core/src/Types/Types/Pagination/PagingOptions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Pagination/PagingOptions.cs @@ -1,6 +1,7 @@ #nullable enable using System.Collections.Immutable; +using GreenDonut.Data; namespace HotChocolate.Types.Pagination; @@ -66,6 +67,9 @@ public class PagingOptions /// public bool? EnableRelativeCursors { get; set; } + /// Defines the null ordering to be used. + public NullOrdering NullOrdering { get; set; } + /// /// Gets or sets the fields that represent relative cursors. /// diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/IntegrationTests.cs b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/IntegrationTests.cs new file mode 100644 index 00000000000..ae2f44e2260 --- /dev/null +++ b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/IntegrationTests.cs @@ -0,0 +1,39 @@ +using GreenDonut.Data; +using HotChocolate.Execution; +using HotChocolate.Tests; +using Microsoft.Extensions.DependencyInjection; + +namespace HotChocolate.Types; + +public class IntegrationTests +{ + [Fact] + public async Task Schema_Snapshot() + { + await new ServiceCollection() + .AddGraphQLServer() + .AddIntegrationTestTypes() + .AddPagingArguments() + .BuildSchemaAsync() + .MatchSnapshotAsync(); + } + + [Fact(Skip = "FIXME")] + public async Task X() + { + // arrange + var executor = await new ServiceCollection() + .AddGraphQLServer() + .AddIntegrationTestTypes() + .AddPagingArguments() + .ModifyPagingOptions(o => o.NullOrdering = NullOrdering.NativeNullsFirst) + .BuildRequestExecutorAsync(); + + // act + var result = await executor.ExecuteAsync("{ ints { nodes } }"); + + // assert + Assert.Null(result.ExpectOperationResult().Errors); + Assert.Equal(NullOrdering.NativeNullsFirst, Query.PagingArguments.NullOrdering); + } +} diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/InterfaceTests.cs b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/InterfaceTests.cs index 582518b51ae..3ae7c2431a4 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/InterfaceTests.cs +++ b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/InterfaceTests.cs @@ -1,21 +1,10 @@ using HotChocolate.Execution; -using HotChocolate.Tests; using Microsoft.Extensions.DependencyInjection; namespace HotChocolate.Types; public class InterfaceTests { - [Fact] - public async Task Schema_Snapshot() - { - await new ServiceCollection() - .AddGraphQLServer() - .AddIntegrationTestTypes() - .BuildSchemaAsync() - .MatchSnapshotAsync(); - } - [Fact] public async Task Ensure_Interface_Resolvers_Are_ParallelExecutable() { @@ -23,6 +12,7 @@ public async Task Ensure_Interface_Resolvers_Are_ParallelExecutable() await new ServiceCollection() .AddGraphQLServer() .AddIntegrationTestTypes() + .AddPagingArguments() .BuildSchemaAsync(); Assert.True( diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/Product.cs b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/Product.cs index a596401cca0..fc4a88bded5 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/Product.cs +++ b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/Product.cs @@ -1,3 +1,5 @@ +using GreenDonut.Data; + namespace HotChocolate.Types; [InterfaceType] @@ -21,5 +23,16 @@ public class Book : Product [QueryType] public static partial class Query { + [GraphQLIgnore] + public static PagingArguments PagingArguments { get; private set; } + public static Product GetProduct() => new Book { Id = "1", Title = "GraphQL in Action" }; + + [UsePaging] + public static IEnumerable GetInts(PagingArguments pagingArguments) + { + PagingArguments = pagingArguments; + + return []; + } } diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/__snapshots__/IntegrationTests.Schema_Snapshot.snap b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/__snapshots__/IntegrationTests.Schema_Snapshot.snap new file mode 100644 index 00000000000..b0c648e144f --- /dev/null +++ b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/__snapshots__/IntegrationTests.Schema_Snapshot.snap @@ -0,0 +1,52 @@ +schema { + query: Query +} + +interface Product { + kind: String! + id: String! +} + +type Book implements Product { + title: String! + id: String! + kind: String! +} + +"A connection to a list of items." +type IntsConnection { + "Information to aid in pagination." + pageInfo: PageInfo! + "A list of edges." + edges: [IntsEdge!] + "A flattened list of the nodes." + nodes: [Int!] +} + +"An edge in a connection." +type IntsEdge { + "A cursor for use in pagination." + cursor: String! + "The item at the end of the edge." + node: Int! +} + +"Information about pagination in a connection." +type PageInfo { + "Indicates whether more edges exist following the set defined by the clients arguments." + hasNextPage: Boolean! + "Indicates whether more edges exist prior the set defined by the clients arguments." + hasPreviousPage: Boolean! + "When paginating backwards, the cursor to continue." + startCursor: String + "When paginating forwards, the cursor to continue." + endCursor: String +} + +type Query { + product: Product! + ints("Returns the first _n_ elements from the list." first: Int "Returns the elements in the list that come after the specified cursor." after: String "Returns the last _n_ elements from the list." last: Int "Returns the elements in the list that come before the specified cursor." before: String): IntsConnection @listSize(assumedSize: 50, slicingArguments: [ "first", "last" ], slicingArgumentDefaultValue: 10, sizedFields: [ "edges", "nodes" ], requireOneSlicingArgument: false) +} + +"The purpose of the `@listSize` directive is to either inform the static analysis about the size of returned lists (if that information is statically available), or to point the analysis to where to find that information." +directive @listSize("The `assumedSize` argument can be used to statically define the maximum length of a list returned by a field." assumedSize: Int "The `slicingArguments` argument can be used to define which of the field's arguments with numeric type are slicing arguments, so that their value determines the size of the list returned by that field. It may specify a list of multiple slicing arguments." slicingArguments: [String!] "The `slicingArgumentDefaultValue` argument can be used to define a default value for a slicing argument, which is used if the argument is not present in a query." slicingArgumentDefaultValue: Int "The `sizedFields` argument can be used to define that the value of the `assumedSize` argument or of a slicing argument does not affect the size of a list returned by a field itself, but that of a list returned by one of its sub-fields." sizedFields: [String!] "The `requireOneSlicingArgument` argument can be used to inform the static analysis that it should expect that exactly one of the defined slicing arguments is present in a query. If that is not the case (i.e., if none or multiple slicing arguments are present), the static analysis may throw an error." requireOneSlicingArgument: Boolean! = true) on FIELD_DEFINITION diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/__snapshots__/InterfaceTests.Schema_Snapshot.snap b/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/__snapshots__/InterfaceTests.Schema_Snapshot.snap deleted file mode 100644 index 7e67827757e..00000000000 --- a/src/HotChocolate/Core/test/Types.Analyzers.Integration.Tests/__snapshots__/InterfaceTests.Schema_Snapshot.snap +++ /dev/null @@ -1,18 +0,0 @@ -schema { - query: Query -} - -interface Product { - kind: String! - id: String! -} - -type Book implements Product { - title: String! - id: String! - kind: String! -} - -type Query { - product: Product! -} diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_ConnectionFlags.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_ConnectionFlags.md index bd50383ca3d..da842caf953 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_ConnectionFlags.md +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_ConnectionFlags.md @@ -289,7 +289,8 @@ namespace TestNamespace.Types.Root args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = global::HotChocolate.Types.Pagination.ConnectionFlagsHelper.GetConnectionFlags(context); var args2 = context.RequestAborted; diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_ConnectionT_MatchesSnapshot.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_ConnectionT_MatchesSnapshot.md index 01cda62e79e..2e576835408 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_ConnectionT_MatchesSnapshot.md +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_ConnectionT_MatchesSnapshot.md @@ -78,7 +78,8 @@ namespace TestNamespace args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = context.RequestAborted; var result = await global::TestNamespace.BookPage.GetAuthorsAsync(args0, args1); diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_MatchesSnapshot.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_MatchesSnapshot.md index edd50bc1ec0..f2e7e402ccb 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_MatchesSnapshot.md +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_MatchesSnapshot.md @@ -271,7 +271,8 @@ namespace TestNamespace args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = context.RequestAborted; var result = await global::TestNamespace.AuthorQueries.GetAuthorsAsync(args0, args1); diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_No_Duplicates_MatchesSnapshot.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_No_Duplicates_MatchesSnapshot.md index 39d05d0d765..70d86b84af1 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_No_Duplicates_MatchesSnapshot.md +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_No_Duplicates_MatchesSnapshot.md @@ -272,7 +272,8 @@ namespace TestNamespace.Types.Nodes args1_before, args1_includeTotalCount) { - EnableRelativeCursors = args1_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args1_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args1_options.NullOrdering }; var args2 = context.RequestAborted; var result = await global::TestNamespace.Types.Nodes.AuthorNode.GetAuthorsAsync(args0, args1, args2); @@ -382,7 +383,8 @@ namespace TestNamespace.Types.Root args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = context.RequestAborted; var result = await global::TestNamespace.Types.Root.AuthorQueries.GetAuthorsAsync(args0, args1); @@ -425,7 +427,8 @@ namespace TestNamespace.Types.Root args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = context.RequestAborted; var result = await global::TestNamespace.Types.Root.AuthorQueries.GetAuthors2Async(args0, args1); diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_UseConnection_ConnectionName_MatchesSnapshot.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_UseConnection_ConnectionName_MatchesSnapshot.md index 719648fcc50..b1627bf1743 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_UseConnection_ConnectionName_MatchesSnapshot.md +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_UseConnection_ConnectionName_MatchesSnapshot.md @@ -83,7 +83,8 @@ namespace TestNamespace args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = context.RequestAborted; var result = await global::TestNamespace.AuthorQueries.GetAuthorsAsync(args0, args1); diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_UseConnection_IncludeTotalCount_MatchesSnapshot.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_UseConnection_IncludeTotalCount_MatchesSnapshot.md index 98eeecf442a..23a31fea7ca 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_UseConnection_IncludeTotalCount_MatchesSnapshot.md +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_CustomConnection_UseConnection_IncludeTotalCount_MatchesSnapshot.md @@ -271,7 +271,8 @@ namespace TestNamespace args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = context.RequestAborted; var result = await global::TestNamespace.AuthorQueries.GetAuthorsAsync(args0, args1); diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_GenericCustomConnection_MatchesSnapshot.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_GenericCustomConnection_MatchesSnapshot.md index 66f4392b2bf..3f663db770b 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_GenericCustomConnection_MatchesSnapshot.md +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_GenericCustomConnection_MatchesSnapshot.md @@ -278,7 +278,8 @@ namespace TestNamespace.Types.Nodes args1_before, args1_includeTotalCount) { - EnableRelativeCursors = args1_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args1_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args1_options.NullOrdering }; var args2 = context.RequestAborted; var result = await global::TestNamespace.Types.Nodes.AuthorNode.GetAuthorsAsync(args0, args1, args2); @@ -388,7 +389,8 @@ namespace TestNamespace.Types.Root args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = context.RequestAborted; var result = await global::TestNamespace.Types.Root.AuthorQueries.GetAuthorsAsync(args0, args1); @@ -431,7 +433,8 @@ namespace TestNamespace.Types.Root args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = context.RequestAborted; var result = await global::TestNamespace.Types.Root.AuthorQueries.GetAuthors2Async(args0, args1); diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_GenericCustomConnection_WithConnectionName_MatchesSnapshot.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_GenericCustomConnection_WithConnectionName_MatchesSnapshot.md index 92079d9621b..ff9f0f2b026 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_GenericCustomConnection_WithConnectionName_MatchesSnapshot.md +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_GenericCustomConnection_WithConnectionName_MatchesSnapshot.md @@ -278,7 +278,8 @@ namespace TestNamespace.Types.Nodes args1_before, args1_includeTotalCount) { - EnableRelativeCursors = args1_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args1_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args1_options.NullOrdering }; var args2 = context.RequestAborted; var result = await global::TestNamespace.Types.Nodes.AuthorNode.GetAuthorsAsync(args0, args1, args2); @@ -388,7 +389,8 @@ namespace TestNamespace.Types.Root args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = context.RequestAborted; var result = await global::TestNamespace.Types.Root.AuthorQueries.GetAuthorsAsync(args0, args1); @@ -431,7 +433,8 @@ namespace TestNamespace.Types.Root args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = context.RequestAborted; var result = await global::TestNamespace.Types.Root.AuthorQueries.GetAuthors2Async(args0, args1); diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_ConnectionBase_Inherit_PageEdge.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_ConnectionBase_Inherit_PageEdge.md index 2948073d274..268d00279cf 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_ConnectionBase_Inherit_PageEdge.md +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_ConnectionBase_Inherit_PageEdge.md @@ -289,7 +289,8 @@ namespace TestNamespace.Types.Root args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = context.RequestAborted; var result = await global::TestNamespace.Types.Root.AuthorQueries.GetAuthorsAsync(args0, args1); diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_ConnectionBase_Reuse_PageEdge.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_ConnectionBase_Reuse_PageEdge.md index c8219773d9a..d8676ba1474 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_ConnectionBase_Reuse_PageEdge.md +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_ConnectionBase_Reuse_PageEdge.md @@ -271,7 +271,8 @@ namespace TestNamespace.Types.Root args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = context.RequestAborted; var result = await global::TestNamespace.Types.Root.AuthorQueries.GetAuthorsAsync(args0, args1); diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_ConnectionBase_Reuse_PageEdge_Generic.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_ConnectionBase_Reuse_PageEdge_Generic.md index e517914ff8b..08ce8d457cd 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_ConnectionBase_Reuse_PageEdge_Generic.md +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_ConnectionBase_Reuse_PageEdge_Generic.md @@ -277,7 +277,8 @@ namespace TestNamespace.Types.Root args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = context.RequestAborted; var result = await global::TestNamespace.Types.Root.AuthorQueries.GetAuthorsAsync(args0, args1); diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_PageConnection.md b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_PageConnection.md index f5fa5c79984..673fb696b65 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_PageConnection.md +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/__snapshots__/PagingTests.GenerateSource_Inherit_From_PageConnection.md @@ -291,7 +291,8 @@ namespace TestNamespace.Types.Root args0_before, args0_includeTotalCount) { - EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor) + EnableRelativeCursors = args0_flags.HasFlag(global::HotChocolate.Types.Pagination.ConnectionFlags.RelativeCursor), + NullOrdering = args0_options.NullOrdering }; var args1 = context.RequestAborted; var result = await global::TestNamespace.Types.Root.AuthorQueries.GetAuthorsAsync(args0, args1); diff --git a/src/HotChocolate/Data/src/Data/Pagination/PagingArgumentsParameterExpressionBuilder.cs b/src/HotChocolate/Data/src/Data/Pagination/PagingArgumentsParameterExpressionBuilder.cs index 323076b3d03..3382c7f7535 100644 --- a/src/HotChocolate/Data/src/Data/Pagination/PagingArgumentsParameterExpressionBuilder.cs +++ b/src/HotChocolate/Data/src/Data/Pagination/PagingArgumentsParameterExpressionBuilder.cs @@ -23,6 +23,7 @@ public T Execute(IResolverContext context) private static PagingArguments MapArguments(IResolverContext context) { + var pagingOptions = PagingHelper.GetPagingOptions(context.Schema, context.Selection.Field); var pagingArguments = context.GetLocalState(WellKnownContextData.PagingArguments); var includeTotalCount = IncludeTotalCount(context.Selection); @@ -31,11 +32,20 @@ private static PagingArguments MapArguments(IResolverContext context) includeTotalCount = context.IsSelected("totalCount"); } - return MapArguments(pagingArguments, includeTotalCount); + return MapArguments(pagingArguments, includeTotalCount, pagingOptions.NullOrdering); } - private static PagingArguments MapArguments(CursorPagingArguments arguments, bool includeTotalCount) - => new(arguments.First, arguments.After, arguments.Last, arguments.Before, includeTotalCount); + private static PagingArguments MapArguments( + CursorPagingArguments arguments, + bool includeTotalCount, + NullOrdering nullOrdering) + => new( + arguments.First, + arguments.After, + arguments.Last, + arguments.Before, + includeTotalCount) + { NullOrdering = nullOrdering }; private static bool IncludeTotalCount(ISelection selection) => selection.Field.Features.Get()?.IncludeTotalCount is true; diff --git a/src/HotChocolate/Data/src/EntityFramework/Pagination/EfQueryableCursorPagingHandler.cs b/src/HotChocolate/Data/src/EntityFramework/Pagination/EfQueryableCursorPagingHandler.cs index 468b4fe5ab9..1123e103450 100644 --- a/src/HotChocolate/Data/src/EntityFramework/Pagination/EfQueryableCursorPagingHandler.cs +++ b/src/HotChocolate/Data/src/EntityFramework/Pagination/EfQueryableCursorPagingHandler.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using GreenDonut.Data; using GreenDonut.Data.Cursors; using GreenDonut.Data.Expressions; using HotChocolate.Resolvers; @@ -46,14 +47,24 @@ private async ValueTask SliceAsync( if (arguments.After is not null) { var cursor = CursorParser.Parse(arguments.After, keys); - var (whereExpr, _) = ExpressionHelpers.BuildWhereExpression(keys, cursor, true); + var (whereExpr, _) = + ExpressionHelpers.BuildWhereExpression( + keys, + cursor, + true, + NullOrdering.Unspecified); query = query.Where(whereExpr); } if (arguments.Before is not null) { var cursor = CursorParser.Parse(arguments.Before, keys); - var (whereExpr, _) = ExpressionHelpers.BuildWhereExpression(keys, cursor, false); + var (whereExpr, _) = + ExpressionHelpers.BuildWhereExpression( + keys, + cursor, + false, + NullOrdering.Unspecified); query = query.Where(whereExpr); } diff --git a/src/HotChocolate/Data/test/Data.Tests/Pagination/PagingArgumentsParameterExpressionBuilderTests.cs b/src/HotChocolate/Data/test/Data.Tests/Pagination/PagingArgumentsParameterExpressionBuilderTests.cs new file mode 100644 index 00000000000..c375a2f907e --- /dev/null +++ b/src/HotChocolate/Data/test/Data.Tests/Pagination/PagingArgumentsParameterExpressionBuilderTests.cs @@ -0,0 +1,41 @@ +using GreenDonut.Data; +using HotChocolate.Execution; +using HotChocolate.Types; +using Microsoft.Extensions.DependencyInjection; + +namespace HotChocolate.Data.Pagination; + +public class PagingArgumentsParameterExpressionBuilderTests +{ + [Fact(Skip = "FIXME")] + public async Task X() + { + // arrange + var executor = await new ServiceCollection() + .AddGraphQL() + .AddQueryType() + .AddPagingArguments() + .ModifyPagingOptions(o => o.NullOrdering = NullOrdering.NativeNullsFirst) + .BuildRequestExecutorAsync(); + + // act + var result = await executor.ExecuteAsync("{ ints { nodes } }"); + + // assert + Assert.Null(result.ExpectOperationResult().Errors); + Assert.Equal(NullOrdering.NativeNullsFirst, Query.PagingArguments.NullOrdering); + } + + public class Query + { + public static PagingArguments PagingArguments { get; private set; } + + [UsePaging] + public IEnumerable GetInts(PagingArguments pagingArguments) + { + PagingArguments = pagingArguments; + + return []; + } + } +} diff --git a/src/HotChocolate/Data/test/Data.Tests/PagingHelperIntegrationTests.cs b/src/HotChocolate/Data/test/Data.Tests/PagingHelperIntegrationTests.cs index 2b7530a0bfb..7979bbab98c 100644 --- a/src/HotChocolate/Data/test/Data.Tests/PagingHelperIntegrationTests.cs +++ b/src/HotChocolate/Data/test/Data.Tests/PagingHelperIntegrationTests.cs @@ -233,6 +233,7 @@ public async Task GetDefaultPage_With_Nullable_SecondPage() .AddGraphQL() .AddQueryType() .AddPagingArguments() + .ModifyPagingOptions(o => o.NullOrdering = NullOrdering.NativeNullsLast) .ExecuteRequestAsync( OperationRequestBuilder.New() .SetDocument( @@ -345,6 +346,7 @@ public async Task GetDefaultPage_With_Nullable_Fallback_SecondPage() .AddGraphQL() .AddQueryType() .AddPagingArguments() + .ModifyPagingOptions(o => o.NullOrdering = NullOrdering.NativeNullsLast) .ExecuteRequestAsync( OperationRequestBuilder.New() .SetDocument( @@ -1201,6 +1203,9 @@ public async Task> GetBrandsNullable( PagingArguments arguments, CancellationToken ct) { + // FIXME: Should be coming from PagingOptions. + arguments = arguments with { NullOrdering = NullOrdering.NativeNullsLast }; + return await context.Brands .OrderBy(t => t.Name) .ThenBy(x => x.AlwaysNull) @@ -1215,6 +1220,9 @@ public async Task> GetBrandsNullableFallback( PagingArguments arguments, CancellationToken ct) { + // FIXME: Should be coming from PagingOptions. + arguments = arguments with { NullOrdering = NullOrdering.NativeNullsLast }; + return await context.Brands .OrderBy(t => t.DisplayName ?? t.Name) .ThenBy(t => t.Id) diff --git a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Deep_SecondPage.md b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Deep_SecondPage.md index 5177074afd6..1801506a3a7 100644 --- a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Deep_SecondPage.md +++ b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Deep_SecondPage.md @@ -16,7 +16,7 @@ LIMIT @__p_2 ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(x => x.BrandDetails.Country.Name).ThenBy(t => t.Id).Where(t => ((t.BrandDetails.Country.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0) OrElse ((t.BrandDetails.Country.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) > 0)))).Take(3) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(x => x.BrandDetails.Country.Name).ThenBy(t => t.Id).Where(t => ((t.BrandDetails.Country.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) > 0) OrElse ((t.BrandDetails.Country.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) > 0)))).Take(3) ``` ## Result diff --git a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Deep_SecondPage_NET10_0.md b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Deep_SecondPage_NET10_0.md index e7f8f4399b3..f002663562e 100644 --- a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Deep_SecondPage_NET10_0.md +++ b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Deep_SecondPage_NET10_0.md @@ -16,7 +16,7 @@ LIMIT @p ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(x => x.BrandDetails.Country.Name).ThenBy(t => t.Id).Where(t => ((t.BrandDetails.Country.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0) OrElse ((t.BrandDetails.Country.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) > 0)))).Take(3) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(x => x.BrandDetails.Country.Name).ThenBy(t => t.Id).Where(t => ((t.BrandDetails.Country.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) > 0) OrElse ((t.BrandDetails.Country.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) > 0)))).Take(3) ``` ## Result diff --git a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_Fallback_SecondPage.md b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_Fallback_SecondPage.md index adf6f0fb443..97743cb9dcd 100644 --- a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_Fallback_SecondPage.md +++ b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_Fallback_SecondPage.md @@ -16,7 +16,7 @@ LIMIT @__p_2 ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => (t.DisplayName ?? t.Name)).ThenBy(t => t.Id).Where(t => (((t.DisplayName ?? t.Name).CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0) OrElse (((t.DisplayName ?? t.Name).CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) > 0)))).Take(3) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => (t.DisplayName ?? t.Name)).ThenBy(t => t.Id).Where(t => (((t.DisplayName ?? t.Name).CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) > 0) OrElse (((t.DisplayName ?? t.Name).CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) > 0)))).Take(3) ``` ## Result diff --git a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_Fallback_SecondPage_NET10_0.md b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_Fallback_SecondPage_NET10_0.md index d4c015a9933..d922adc5a73 100644 --- a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_Fallback_SecondPage_NET10_0.md +++ b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_Fallback_SecondPage_NET10_0.md @@ -16,7 +16,7 @@ LIMIT @p ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => (t.DisplayName ?? t.Name)).ThenBy(t => t.Id).Where(t => (((t.DisplayName ?? t.Name).CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0) OrElse (((t.DisplayName ?? t.Name).CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) > 0)))).Take(3) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => (t.DisplayName ?? t.Name)).ThenBy(t => t.Id).Where(t => (((t.DisplayName ?? t.Name).CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) > 0) OrElse (((t.DisplayName ?? t.Name).CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) > 0)))).Take(3) ``` ## Result diff --git a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_SecondPage.md b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_SecondPage.md index a6fa965501c..47cdec528f6 100644 --- a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_SecondPage.md +++ b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_SecondPage.md @@ -4,19 +4,19 @@ ```sql -- @__value_0='Brand10' --- @__value_2='11' --- @__p_3='3' +-- @__value_1='11' +-- @__p_2='3' SELECT b."Id", b."AlwaysNull", b."DisplayName", b."Name", b."BrandDetails_Country_Name" FROM "Brands" AS b -WHERE b."Name" > @__value_0 OR (b."Name" = @__value_0 AND b."AlwaysNull" > NULL) OR (b."Name" = @__value_0 AND b."AlwaysNull" IS NULL AND b."Id" > @__value_2) +WHERE b."Name" > @__value_0 OR (b."Name" = @__value_0 AND b."AlwaysNull" IS NULL AND b."Id" > @__value_1) ORDER BY b."Name", b."AlwaysNull", b."Id" -LIMIT @__p_3 +LIMIT @__p_2 ``` ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(x => x.AlwaysNull).ThenBy(t => t.Id).Where(t => (((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.AlwaysNull.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0))) OrElse (((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.AlwaysNull.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0)) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) > 0)))).Take(3) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(x => x.AlwaysNull).ThenBy(t => t.Id).Where(t => (((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso False)) OrElse (((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.AlwaysNull == null)) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) > 0)))).Take(3) ``` ## Result diff --git a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_SecondPage_NET10_0.md b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_SecondPage_NET10_0.md index 95dab89742c..1178fc61b95 100644 --- a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_SecondPage_NET10_0.md +++ b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetDefaultPage_With_Nullable_SecondPage_NET10_0.md @@ -4,11 +4,11 @@ ```sql -- @value='Brand10' --- @value4='11' +-- @value2='11' -- @p='3' SELECT b."Id", b."AlwaysNull", b."DisplayName", b."Name", b."BrandDetails_Country_Name" FROM "Brands" AS b -WHERE b."Name" > @value OR (b."Name" = @value AND b."AlwaysNull" > NULL) OR (b."Name" = @value AND b."AlwaysNull" IS NULL AND b."Id" > @value4) +WHERE b."Name" > @value OR (b."Name" = @value AND b."AlwaysNull" IS NULL AND b."Id" > @value2) ORDER BY b."Name", b."AlwaysNull", b."Id" LIMIT @p ``` @@ -16,7 +16,7 @@ LIMIT @p ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(x => x.AlwaysNull).ThenBy(t => t.Id).Where(t => (((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.AlwaysNull.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0))) OrElse (((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.AlwaysNull.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0)) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) > 0)))).Take(3) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(x => x.AlwaysNull).ThenBy(t => t.Id).Where(t => (((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso False)) OrElse (((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.AlwaysNull == null)) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) > 0)))).Take(3) ``` ## Result diff --git a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetSecondPage_With_2_Items.md b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetSecondPage_With_2_Items.md index 5b2cb0ddb0b..72411b089cb 100644 --- a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetSecondPage_With_2_Items.md +++ b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetSecondPage_With_2_Items.md @@ -16,7 +16,7 @@ LIMIT @__p_2 ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) > 0)))).Take(3) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) > 0)))).Take(3) ``` ## Result diff --git a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetSecondPage_With_2_Items_NET10_0.md b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetSecondPage_With_2_Items_NET10_0.md index ec0d501de5a..50b08e4fac2 100644 --- a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetSecondPage_With_2_Items_NET10_0.md +++ b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.GetSecondPage_With_2_Items_NET10_0.md @@ -16,7 +16,7 @@ LIMIT @p ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) > 0)))).Take(3) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) > 0)))).Take(3) ``` ## Result diff --git a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13.md b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13.md index 04f7903b579..a99178b77ab 100644 --- a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13.md +++ b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13.md @@ -16,7 +16,7 @@ LIMIT @__p_2 ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) > 0)))).Take(6) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) > 0)))).Take(6) ``` ## Result 3 diff --git a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET10_0.md b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET10_0.md index 0f175695fd2..665c052e606 100644 --- a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET10_0.md +++ b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_After_Id_13_NET10_0.md @@ -16,7 +16,7 @@ LIMIT @p ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) > 0)))).Take(6) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderBy(t => t.Name).ThenBy(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) > 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) > 0)))).Take(6) ``` ## Result 3 diff --git a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96.md b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96.md index ec12ab52cce..f00da3147dd 100644 --- a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96.md +++ b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96.md @@ -16,7 +16,7 @@ LIMIT @__p_2 ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderByDescending(t => t.Name).ThenByDescending(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) < 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) < 0)))).Take(6) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderByDescending(t => t.Name).ThenByDescending(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) < 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) < 0)))).Take(6) ``` ## Result 3 diff --git a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET10_0.md b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET10_0.md index 53776b7c1c0..b3ce7d699ae 100644 --- a/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET10_0.md +++ b/src/HotChocolate/Data/test/Data.Tests/__snapshots__/PagingHelperIntegrationTests.Paging_First_5_Before_Id_96_NET10_0.md @@ -16,7 +16,7 @@ LIMIT @p ## Expression 0 ```text -[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderByDescending(t => t.Name).ThenByDescending(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) < 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass6_0`1[System.Int32]).value) < 0)))).Take(6) +[Microsoft.EntityFrameworkCore.Query.EntityQueryRootExpression].OrderByDescending(t => t.Name).ThenByDescending(t => t.Id).Where(t => ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) < 0) OrElse ((t.Name.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.String]).value) == 0) AndAlso (t.Id.CompareTo(value(GreenDonut.Data.Expressions.ExpressionHelpers+<>c__DisplayClass14_0`1[System.Int32]).value) < 0)))).Take(6) ``` ## Result 3