diff --git a/src/EFCore.PG/Extensions/DbFunctionsExtensions/NpgsqlDbFunctionsExtensions.cs b/src/EFCore.PG/Extensions/DbFunctionsExtensions/NpgsqlDbFunctionsExtensions.cs
index f1684865b..c6e4acbdb 100644
--- a/src/EFCore.PG/Extensions/DbFunctionsExtensions/NpgsqlDbFunctionsExtensions.cs
+++ b/src/EFCore.PG/Extensions/DbFunctionsExtensions/NpgsqlDbFunctionsExtensions.cs
@@ -137,4 +137,342 @@ public static int Distance(this DbFunctions _, DateOnly a, DateOnly b)
///
public static TimeSpan Distance(this DbFunctions _, DateTime a, DateTime b)
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Distance)));
+
+ ///
+ /// Returns a value if equals ; otherwise it returns .
+ ///
+ ///
+ /// For more information on NullIf, see
+ /// .
+ ///
+ public static T? NullIf(this DbFunctions _, T value1, T value2)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(NullIf)));
+
+ #region Greatest
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2, T value3)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2, T value3, T value4)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2, T value3, T value4, T value5)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9, T value10)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9, T value10, T value11)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9, T value10, T value11, T value12)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9, T value10, T value11, T value12, T value13)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9, T value10, T value11, T value12, T value13, T value14)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9, T value10, T value11, T value12, T value13, T value14, T value15)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ ///
+ /// Returns the greatest value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Greatest, see
+ /// .
+ ///
+ public static T Greatest(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9, T value10, T value11, T value12, T value13, T value14, T value15, T value16)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Greatest)));
+
+ #endregion
+
+ #region Least
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2, T value3)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2, T value3, T value4)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2, T value3, T value4, T value5)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9, T value10)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9, T value10, T value11)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9, T value10, T value11, T value12)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9, T value10, T value11, T value12, T value13)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9, T value10, T value11, T value12, T value13, T value14)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9, T value10, T value11, T value12, T value13, T value14, T value15)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ ///
+ /// Returns the least value from a list of any number of expressions.
+ ///
+ ///
+ /// For more information on Least, see
+ /// .
+ ///
+ public static T Least(this DbFunctions _, T value1, T value2, T value3, T value4, T value5, T value6, T value7, T value8, T value9, T value10, T value11, T value12, T value13, T value14, T value15, T value16)
+ => throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(Least)));
+
+ #endregion
}
diff --git a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqConditionalExpressionsTranslator.cs b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqConditionalExpressionsTranslator.cs
new file mode 100644
index 000000000..d9d639d97
--- /dev/null
+++ b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqConditionalExpressionsTranslator.cs
@@ -0,0 +1,64 @@
+using System.Runtime.CompilerServices;
+using static Npgsql.EntityFrameworkCore.PostgreSQL.Utilities.Statics;
+
+namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionTranslators.Internal;
+
+///
+/// Translates methods into PostgreSQL GREATEST expressions.
+///
+public class NpgsqConditionalExpressionsTranslator : IMethodCallTranslator
+{
+ private readonly NpgsqlSqlExpressionFactory _sqlExpressionFactory;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public NpgsqConditionalExpressionsTranslator(NpgsqlSqlExpressionFactory sqlExpressionFactory)
+ {
+ _sqlExpressionFactory = sqlExpressionFactory;
+ }
+
+ ///
+ public virtual SqlExpression? Translate(
+ SqlExpression? instance,
+ MethodInfo method,
+ IReadOnlyList arguments,
+ IDiagnosticsLogger logger)
+ {
+ if (method.DeclaringType == typeof(NpgsqlDbFunctionsExtensions))
+ {
+ switch (method.Name)
+ {
+ case nameof(NpgsqlDbFunctionsExtensions.NullIf):
+ return _sqlExpressionFactory.Function(
+ "nullif",
+ arguments.Skip(1),
+ nullable: true,
+ argumentsPropagateNullability: TrueArrays[arguments.Count - 1],
+ method.ReturnType);
+ case nameof(NpgsqlDbFunctionsExtensions.Greatest):
+ return _sqlExpressionFactory.Function(
+ "greatest",
+ arguments.Skip(1),
+ nullable: true,
+ argumentsPropagateNullability: GetArgumentsPropagateNullability(arguments.Count - 1),
+ method.ReturnType);
+ case nameof(NpgsqlDbFunctionsExtensions.Least):
+ return _sqlExpressionFactory.Function(
+ "least",
+ arguments.Skip(1),
+ nullable: true,
+ argumentsPropagateNullability: GetArgumentsPropagateNullability(arguments.Count - 1),
+ method.ReturnType);
+ }
+ }
+
+ return null;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static IEnumerable GetArgumentsPropagateNullability(int length)
+ => length < TrueArrays.Length
+ ? TrueArrays[length]
+ : (IEnumerable)Enumerable.Repeat(true, length).ToArray();
+}
diff --git a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlMethodCallTranslatorProvider.cs b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlMethodCallTranslatorProvider.cs
index 2a82c7a6d..a7b5442c2 100644
--- a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlMethodCallTranslatorProvider.cs
+++ b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlMethodCallTranslatorProvider.cs
@@ -44,6 +44,7 @@ public NpgsqlMethodCallTranslatorProvider(
{
new NpgsqlArrayMethodTranslator(sqlExpressionFactory, jsonTranslator),
new NpgsqlByteArrayMethodTranslator(sqlExpressionFactory),
+ new NpgsqConditionalExpressionsTranslator(sqlExpressionFactory),
new NpgsqlConvertTranslator(sqlExpressionFactory),
new NpgsqlDateTimeMethodTranslator(typeMappingSource, sqlExpressionFactory),
new NpgsqlFullTextSearchMethodTranslator(typeMappingSource, sqlExpressionFactory, model),
diff --git a/test/EFCore.PG.FunctionalTests/Query/NorthwindDbFunctionsQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/NorthwindDbFunctionsQueryNpgsqlTest.cs
index e5c49de7a..39a3137bd 100644
--- a/test/EFCore.PG.FunctionalTests/Query/NorthwindDbFunctionsQueryNpgsqlTest.cs
+++ b/test/EFCore.PG.FunctionalTests/Query/NorthwindDbFunctionsQueryNpgsqlTest.cs
@@ -207,6 +207,618 @@ WHERE string_to_array(c."ContactName", ' ', 'Maria') = ARRAY[NULL,'Anders']::tex
""");
}
+ [Fact]
+ public void NullIf_returns_not_null()
+ {
+ using var context = CreateContext();
+ var nameNotNull = context.Customers
+ .Where(c => c.CustomerID == "ALFKI")
+ .Select(c => EF.Functions.NullIf(c.ContactName, "Something"))
+ .First();
+
+ Assert.NotNull(nameNotNull);
+
+ AssertSql("""
+SELECT nullif(c."ContactName", 'Something')
+FROM "Customers" AS c
+WHERE c."CustomerID" = 'ALFKI'
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void NullIf_returns_null()
+ {
+ using var context = CreateContext();
+ var nameNull = context.Customers
+ .Where(c => c.CustomerID == "ALFKI")
+ .Select(c => EF.Functions.NullIf(c.ContactName, "Maria Anders"))
+ .First();
+
+ Assert.Null(nameNull);
+
+ AssertSql("""
+SELECT nullif(c."ContactName", 'Maria Anders')
+FROM "Customers" AS c
+WHERE c."CustomerID" = 'ALFKI'
+LIMIT 1
+""");
+ }
+
+ #endregion
+
+ #region Greatest
+
+ [Fact]
+ public void Greatest_with_1_property()
+ {
+ using var context = CreateContext();
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID)).First();
+
+ //Assert.Equal(10582, closestOrder.OrderID);
+
+ AssertSql(
+"""
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID") NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_2_properties()
+ {
+ using var context = CreateContext();
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, o.OrderID)).First();
+
+ AssertSql(
+"""
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", o."OrderID") NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_3_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, value, 2)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", @__value_1, 2) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_4_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, value, 2, 3)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", @__value_1, 2, 3) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_5_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, value, 2, 3, 4)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", @__value_1, 2, 3, 4) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_6_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, value, 2, 3, 4, 5)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", @__value_1, 2, 3, 4, 5) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_7_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, value, 2, 3, 4, 5, 6)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", @__value_1, 2, 3, 4, 5, 6) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_8_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, value, 2, 3, 4, 5, 6, 7)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_9_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_10_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8, 9)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8, 9) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_11_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8, 9, 10)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8, 9, 10) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_12_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_13_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_14_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_15_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Greatest_with_16_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Greatest(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY greatest(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) NULLS FIRST
+LIMIT 1
+""");
+ }
+ #endregion
+
+ #region Least
+
+ [Fact]
+ public void Least_with_1_property()
+ {
+ using var context = CreateContext();
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID)).First();
+
+ //Assert.Equal(10582, closestOrder.OrderID);
+
+ AssertSql(
+"""
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID") NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_2_properties()
+ {
+ using var context = CreateContext();
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, o.OrderID)).First();
+
+ AssertSql(
+"""
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", o."OrderID") NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_3_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, value, 2)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", @__value_1, 2) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_4_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, value, 2, 3)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", @__value_1, 2, 3) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_5_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, value, 2, 3, 4)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", @__value_1, 2, 3, 4) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_6_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, value, 2, 3, 4, 5)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", @__value_1, 2, 3, 4, 5) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_7_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, value, 2, 3, 4, 5, 6)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", @__value_1, 2, 3, 4, 5, 6) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_8_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, value, 2, 3, 4, 5, 6, 7)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_9_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_10_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8, 9)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8, 9) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_11_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8, 9, 10)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8, 9, 10) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_12_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_13_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_14_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_15_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) NULLS FIRST
+LIMIT 1
+""");
+ }
+
+ [Fact]
+ public void Least_with_16_mix()
+ {
+ using var context = CreateContext();
+ var value = 1;
+ var orderDetail = context.OrderDetails.OrderBy(o => EF.Functions.Least(o.ProductID, value, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)).First();
+
+ AssertSql(
+"""
+@__value_1='1'
+
+SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice"
+FROM "Order Details" AS o
+ORDER BY least(o."ProductID", @__value_1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) NULLS FIRST
+LIMIT 1
+""");
+ }
#endregion
private void AssertSql(params string[] expected)