Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for GREATEST and LEAST functions #2351

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions exposed-core/api/exposed-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,14 @@ public final class org/jetbrains/exposed/sql/GreaterOp : org/jetbrains/exposed/s
public fun <init> (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;)V
}

public final class org/jetbrains/exposed/sql/Greatest : org/jetbrains/exposed/sql/Function {
public fun <init> (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/IColumnType;[Lorg/jetbrains/exposed/sql/Expression;)V
public final fun getExpr1 ()Lorg/jetbrains/exposed/sql/Expression;
public final fun getExpr2 ()Lorg/jetbrains/exposed/sql/Expression;
public final fun getOthers ()[Lorg/jetbrains/exposed/sql/Expression;
public fun toQueryBuilder (Lorg/jetbrains/exposed/sql/QueryBuilder;)V
}

public final class org/jetbrains/exposed/sql/GroupConcat : org/jetbrains/exposed/sql/Function {
public fun <init> (Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;Z[Lkotlin/Pair;)V
public final fun getDistinct ()Z
Expand Down Expand Up @@ -1140,6 +1148,8 @@ public abstract interface class org/jetbrains/exposed/sql/ISqlExpressionBuilder
public abstract fun greaterEq (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/GreaterEqOp;
public abstract fun greaterEq (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/GreaterEqOp;
public abstract fun greaterEqEntityID (Lorg/jetbrains/exposed/sql/Column;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/GreaterEqOp;
public abstract fun greatest (Ljava/lang/Object;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;[Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/Greatest;
public abstract fun greatest (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;[Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/Greatest;
public abstract fun hasFlag (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Object;)Lorg/jetbrains/exposed/sql/EqOp;
public abstract fun hasFlag (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/EqOp;
public abstract fun inList (Ljava/util/List;Ljava/lang/Iterable;)Lorg/jetbrains/exposed/sql/ops/InListOrNotInListBaseOp;
Expand Down Expand Up @@ -1168,6 +1178,8 @@ public abstract interface class org/jetbrains/exposed/sql/ISqlExpressionBuilder
public abstract fun lag (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/Lag;
public abstract fun lastValue (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/LastValue;
public abstract fun lead (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/Lead;
public abstract fun least (Ljava/lang/Object;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;[Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/Least;
public abstract fun least (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;[Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/Least;
public abstract fun less (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/LessOp;
public abstract fun less (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/LessOp;
public abstract fun less (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/LessOp;
Expand Down Expand Up @@ -1274,6 +1286,8 @@ public final class org/jetbrains/exposed/sql/ISqlExpressionBuilder$DefaultImpls
public static fun greaterEq (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/GreaterEqOp;
public static fun greaterEq (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/GreaterEqOp;
public static fun greaterEqEntityID (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/Column;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/GreaterEqOp;
public static fun greatest (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Ljava/lang/Object;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;[Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/Greatest;
public static fun greatest (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;[Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/Greatest;
public static fun hasFlag (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Object;)Lorg/jetbrains/exposed/sql/EqOp;
public static fun hasFlag (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/EqOp;
public static fun inList (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Ljava/util/List;Ljava/lang/Iterable;)Lorg/jetbrains/exposed/sql/ops/InListOrNotInListBaseOp;
Expand Down Expand Up @@ -1304,6 +1318,8 @@ public final class org/jetbrains/exposed/sql/ISqlExpressionBuilder$DefaultImpls
public static fun lastValue (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/LastValue;
public static fun lead (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/Lead;
public static synthetic fun lead$default (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Lead;
public static fun least (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Ljava/lang/Object;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;[Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/Least;
public static fun least (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;[Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/Least;
public static fun less (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/LessOp;
public static fun less (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/LessOp;
public static fun less (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/LessOp;
Expand Down Expand Up @@ -1555,6 +1571,14 @@ public final class org/jetbrains/exposed/sql/Lead : org/jetbrains/exposed/sql/Wi
public fun toQueryBuilder (Lorg/jetbrains/exposed/sql/QueryBuilder;)V
}

public final class org/jetbrains/exposed/sql/Least : org/jetbrains/exposed/sql/Function {
public fun <init> (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/IColumnType;[Lorg/jetbrains/exposed/sql/Expression;)V
public final fun getExpr1 ()Lorg/jetbrains/exposed/sql/Expression;
public final fun getExpr2 ()Lorg/jetbrains/exposed/sql/Expression;
public final fun getOthers ()[Lorg/jetbrains/exposed/sql/Expression;
public fun toQueryBuilder (Lorg/jetbrains/exposed/sql/QueryBuilder;)V
}

public final class org/jetbrains/exposed/sql/LessEqOp : org/jetbrains/exposed/sql/ComparisonOp {
public fun <init> (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;)V
}
Expand Down Expand Up @@ -2354,6 +2378,8 @@ public final class org/jetbrains/exposed/sql/SqlExpressionBuilder : org/jetbrain
public fun greaterEq (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/GreaterEqOp;
public fun greaterEq (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/GreaterEqOp;
public fun greaterEqEntityID (Lorg/jetbrains/exposed/sql/Column;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/GreaterEqOp;
public fun greatest (Ljava/lang/Object;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;[Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/Greatest;
public fun greatest (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;[Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/Greatest;
public fun hasFlag (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Object;)Lorg/jetbrains/exposed/sql/EqOp;
public fun hasFlag (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/EqOp;
public fun inList (Ljava/util/List;Ljava/lang/Iterable;)Lorg/jetbrains/exposed/sql/ops/InListOrNotInListBaseOp;
Expand Down Expand Up @@ -2382,6 +2408,8 @@ public final class org/jetbrains/exposed/sql/SqlExpressionBuilder : org/jetbrain
public fun lag (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/Lag;
public fun lastValue (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/LastValue;
public fun lead (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/Lead;
public fun least (Ljava/lang/Object;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;[Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/Least;
public fun least (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;[Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/Least;
public fun less (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/LessOp;
public fun less (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/LessOp;
public fun less (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/LessOp;
Expand Down Expand Up @@ -4038,13 +4066,15 @@ public abstract class org/jetbrains/exposed/sql/vendors/FunctionProvider {
public fun delete (ZLorg/jetbrains/exposed/sql/Table;Ljava/lang/String;Ljava/lang/Integer;Lorg/jetbrains/exposed/sql/Transaction;)Ljava/lang/String;
public fun explain (ZLjava/lang/String;Ljava/lang/String;Lorg/jetbrains/exposed/sql/Transaction;)Ljava/lang/String;
public fun getDEFAULT_VALUE_EXPRESSION ()Ljava/lang/String;
public fun greatest (Lorg/jetbrains/exposed/sql/QueryBuilder;[Lorg/jetbrains/exposed/sql/Expression;)V
public fun groupConcat (Lorg/jetbrains/exposed/sql/GroupConcat;Lorg/jetbrains/exposed/sql/QueryBuilder;)V
public fun hour (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/QueryBuilder;)V
public fun insert (ZLorg/jetbrains/exposed/sql/Table;Ljava/util/List;Ljava/lang/String;Lorg/jetbrains/exposed/sql/Transaction;)Ljava/lang/String;
public fun insertValue (Ljava/lang/String;Lorg/jetbrains/exposed/sql/QueryBuilder;)V
public fun jsonContains (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;Lorg/jetbrains/exposed/sql/IColumnType;Lorg/jetbrains/exposed/sql/QueryBuilder;)V
public fun jsonExists (Lorg/jetbrains/exposed/sql/Expression;[Ljava/lang/String;Ljava/lang/String;Lorg/jetbrains/exposed/sql/IColumnType;Lorg/jetbrains/exposed/sql/QueryBuilder;)V
public fun jsonExtract (Lorg/jetbrains/exposed/sql/Expression;[Ljava/lang/String;ZLorg/jetbrains/exposed/sql/IColumnType;Lorg/jetbrains/exposed/sql/QueryBuilder;)V
public fun least (Lorg/jetbrains/exposed/sql/QueryBuilder;[Lorg/jetbrains/exposed/sql/Expression;)V
public fun locate (Lorg/jetbrains/exposed/sql/QueryBuilder;Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;)V
public fun match (Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;Lorg/jetbrains/exposed/sql/vendors/FunctionProvider$MatchMode;)Lorg/jetbrains/exposed/sql/Op;
public static synthetic fun match$default (Lorg/jetbrains/exposed/sql/vendors/FunctionProvider;Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;Lorg/jetbrains/exposed/sql/vendors/FunctionProvider$MatchMode;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Op;
Expand Down
38 changes: 38 additions & 0 deletions exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Function.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,44 @@ class Random(
}
}

/**
* Represents an SQL operator that returns the greatest (maximum, largest
* value) of [expr1], [expr2], and [others].
*
* **Note:** The semantics of this function when applied to null values
* or values of multiple types depends on the vendor. Please check the
* documentation for your respective database.
*/
class Greatest<T>(
val expr1: Expression<in T>,
val expr2: Expression<in T>,
columnType: IColumnType<T & Any>,
vararg val others: Expression<in T>
) : Function<T>(columnType) {
Comment on lines +76 to +81
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@solonovamax The type parameters here won't allow for the possibility of the function returning a null value.
Please see how Min() is implemented or use my suggestion for Greatest from one of my previous comments. The type parameters for the functions will also need to be adjusted.

This can be tested using a nullable column as one of the function arguments (with null as the inserted value). Databases that consider null as the highest value (SQLite, Oracle, MySQL, MariaDB) will fail with NPE otherwise.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type parameters here won't allow for the possibility of the function returning a null value. Please see how Min() is implemented or use my suggestion for Greatest from one of my previous comments. The type parameters for the functions will also need to be adjusted.

This can be tested using a nullable column as one of the function arguments (with null as the inserted value). Databases that consider null as the highest value (SQLite, Oracle, MySQL, MariaDB) will fail with NPE otherwise.

You sure?
Because according to the test cases I have, it's passing perfectly fine when returning a null value.
I hadn't pushed them previously because I had to do a bit of cleanup before being able to push them, however they're now ready to push.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@solonovamax The tests pass perfectly fine because you've used assertNull(), which expects a possible null.
Please replace every assertNull() (lines 448-481) with a println() and run the test again on all db to see what happens.
Or, you could try storing the retrieved ResultRow value as a variable first before asserting and see what happens:

val x = result3[greatestInt]
assertNull(x)

The variable greatestInt is of type Greatest<Int>, which is already not good because one of the arguments passed is of type Column<Int?>. It should be Greatest<Int?>.
But because it isn't, if a user chooses to store the value at any point (without explicitly specifying a nullable type), the compiler would expect the value to be of type Int and an NPE will be thrown.
For the same reason, any subsequent function use that depends on strictly-typed overloads, like with println() etc, would also throw an NPE because the function would expect a non-null argument.

override fun toQueryBuilder(queryBuilder: QueryBuilder): Unit = queryBuilder {
currentDialect.functionProvider.greatest(queryBuilder, expr1, expr2, *others)
}
}

/**
* Represents an SQL operator that returns the least (minimum, smallest
* value) of [expr1], [expr2], and [others].
*
* **Note:** The semantics of this function when applied to null values
* or values of multiple types depends on the vendor. Please check the
* documentation for your respective database.
*/
class Least<T>(
val expr1: Expression<in T>,
val expr2: Expression<in T>,
columnType: IColumnType<T & Any>,
vararg val others: Expression<in T>
) : Function<T>(columnType) {
override fun toQueryBuilder(queryBuilder: QueryBuilder): Unit = queryBuilder {
currentDialect.functionProvider.least(queryBuilder, expr1, expr2, *others)
}
}

// String Functions

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,59 @@ interface ISqlExpressionBuilder {
other: ExpressionWithColumnType<E>
): IsDistinctFromOp = IsDistinctFromOp(this, other)

/**
* The greatest (maximum, largest value) of [expr1], [expr2], and [others].
*
* **Note:** The semantics of this function when applied to null values
* or values of multiple types depends on the vendor. Please check the
* documentation for your respective database.
*/
fun <T> greatest(
expr1: ExpressionWithColumnType<T>,
expr2: Expression<in T>,
vararg others: Expression<in T>,
): Greatest<T> = Greatest(expr1, expr2, expr1.columnType, *others)

/**
* The greatest (maximum, largest value) of [literal], [expr1], and
* [others].
*
* **Note:** The semantics of this function when applied to null values
* or values of multiple types depends on the vendor. Please check the
* documentation for your respective database.
*/
fun <T> greatest(
literal: T,
expr1: ExpressionWithColumnType<T>,
vararg others: Expression<in T>,
): Greatest<T> = Greatest(expr1.wrap(literal), expr1, expr1.columnType, *others)

/**
* The least (minimum, smallest value) of [expr1], [expr2], and [others].
*
* **Note:** The semantics of this function when applied to null values
* or values of multiple types depends on the vendor. Please check the
* documentation for your respective database.
*/
fun <T> least(
expr1: ExpressionWithColumnType<T>,
expr2: Expression<in T>,
vararg others: Expression<in T>,
): Least<T> = Least(expr1, expr2, expr1.columnType, *others)

/**
* The least (minimum, smallest value) of [literal], [expr1], and [others].
*
* **Note:** The semantics of this function when applied to null values
* or values of multiple types depends on the vendor. Please check the
* documentation for your respective database.
*/
fun <T> least(
literal: T,
expr1: ExpressionWithColumnType<T>,
vararg others: Expression<in T>,
): Least<T> = Least(expr1.wrap(literal), expr1, expr1.columnType, *others)

// Mathematical Operators

/** Adds the [t] value to this expression. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,30 @@ abstract class FunctionProvider {
*/
open fun random(seed: Int?): String = "RANDOM(${seed?.toString().orEmpty()})"

/**
* SQL function that returns the greatest (maximum) of two values.
*
* @param queryBuilder Query builder to append the SQL function to.
* @param expr The expressions to compare.
*/
open fun <T> greatest(queryBuilder: QueryBuilder, vararg expr: Expression<in T>): Unit = queryBuilder {
append("GREATEST(")
expr.appendTo { +it }
append(")")
}

/**
* SQL function that returns the least (minimum) of two values.
*
* @param queryBuilder Query builder to append the SQL function to.
* @param expr The expressions to compare.
*/
open fun <T> least(queryBuilder: QueryBuilder, vararg expr: Expression<in T>): Unit = queryBuilder {
append("LEAST(")
expr.appendTo { +it }
append(")")
}

// String functions

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ internal object SQLiteDataTypeProvider : DataTypeProvider() {

@Suppress("TooManyFunctions")
internal object SQLiteFunctionProvider : FunctionProvider() {
override fun <T> greatest(queryBuilder: QueryBuilder, vararg expr: Expression<in T>) = queryBuilder {
append("MAX(")
expr.appendTo { +it }
append(")")
}

override fun <T> least(queryBuilder: QueryBuilder, vararg expr: Expression<in T>) = queryBuilder {
append("MIN(")
expr.appendTo { +it }
append(")")
}

override fun <T : String?> charLength(expr: Expression<T>, queryBuilder: QueryBuilder) = queryBuilder {
append("LENGTH(", expr, ")")
}
Expand Down
Loading