Skip to content

Commit

Permalink
feat: EXPOSED-258 Enhance upsert to allow exclusion of columns set on…
Browse files Browse the repository at this point in the history
… conflict

- Change order of private batchInsert() vararg parameter
- Change onExcludeUpdate parameter to be a List instead of Set
  • Loading branch information
bog-walk committed Feb 23, 2024
1 parent 8b0dee3 commit 0439932
Show file tree
Hide file tree
Showing 12 changed files with 41 additions and 41 deletions.
4 changes: 2 additions & 2 deletions documentation-website/Writerside/topics/Deep-Dive-into-DSL.md
Original file line number Diff line number Diff line change
Expand Up @@ -668,15 +668,15 @@ then `onUpdateExclude` should be provided an argument with the specific columns
This parameter could also be used for the reverse case when only a small subset of columns should be updated but duplicating the insert values is tedious:
```kotlin
// on conflict, all columns EXCEPT [director] are updated with values from the lambda block
StarWarsFilms.upsert(onUpdateExclude = setOf(StarWarsFilms.director)) {
StarWarsFilms.upsert(onUpdateExclude = listOf(StarWarsFilms.director)) {
it[sequelId] = 9
it[name] = "The Rise of Skywalker"
it[director] = "JJ Abrams"
}

// on conflict, ONLY column [director] is updated with value from the lambda block
StarWarsFilms.upsert(
onUpdateExclude = StarWarsFilms.columns.toSet() - StarWarsFilms.director
onUpdateExclude = StarWarsFilms.columns - setOf(StarWarsFilms.director)
) {
it[sequelId] = 9
it[name] = "The Rise of Skywalker"
Expand Down
26 changes: 13 additions & 13 deletions exposed-core/api/exposed-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -1615,10 +1615,10 @@ public final class org/jetbrains/exposed/sql/QueriesKt {
public static final fun batchReplace (Lorg/jetbrains/exposed/sql/Table;Lkotlin/sequences/Sequence;ZLkotlin/jvm/functions/Function2;)Ljava/util/List;
public static synthetic fun batchReplace$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/Iterable;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Ljava/util/List;
public static synthetic fun batchReplace$default (Lorg/jetbrains/exposed/sql/Table;Lkotlin/sequences/Sequence;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Ljava/util/List;
public static final fun batchUpsert (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/Iterable;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/Set;ZLkotlin/jvm/functions/Function2;)Ljava/util/List;
public static final fun batchUpsert (Lorg/jetbrains/exposed/sql/Table;Lkotlin/sequences/Sequence;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/Set;ZLkotlin/jvm/functions/Function2;)Ljava/util/List;
public static synthetic fun batchUpsert$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/Iterable;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/Set;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Ljava/util/List;
public static synthetic fun batchUpsert$default (Lorg/jetbrains/exposed/sql/Table;Lkotlin/sequences/Sequence;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/Set;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Ljava/util/List;
public static final fun batchUpsert (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/Iterable;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/List;ZLkotlin/jvm/functions/Function2;)Ljava/util/List;
public static final fun batchUpsert (Lorg/jetbrains/exposed/sql/Table;Lkotlin/sequences/Sequence;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/List;ZLkotlin/jvm/functions/Function2;)Ljava/util/List;
public static synthetic fun batchUpsert$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/Iterable;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/List;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Ljava/util/List;
public static synthetic fun batchUpsert$default (Lorg/jetbrains/exposed/sql/Table;Lkotlin/sequences/Sequence;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/List;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Ljava/util/List;
public static final fun deleteAll (Lorg/jetbrains/exposed/sql/Table;)I
public static final fun deleteIgnoreWhere (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/Integer;Ljava/lang/Long;Lkotlin/jvm/functions/Function2;)I
public static synthetic fun deleteIgnoreWhere$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/Integer;Ljava/lang/Long;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)I
Expand Down Expand Up @@ -1651,8 +1651,8 @@ public final class org/jetbrains/exposed/sql/QueriesKt {
public static final fun update (Lorg/jetbrains/exposed/sql/Table;Lkotlin/jvm/functions/Function1;Ljava/lang/Integer;Lkotlin/jvm/functions/Function2;)I
public static synthetic fun update$default (Lorg/jetbrains/exposed/sql/Join;Lkotlin/jvm/functions/Function1;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)I
public static synthetic fun update$default (Lorg/jetbrains/exposed/sql/Table;Lkotlin/jvm/functions/Function1;Ljava/lang/Integer;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)I
public static final fun upsert (Lorg/jetbrains/exposed/sql/Table;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/Set;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Lorg/jetbrains/exposed/sql/statements/UpsertStatement;
public static synthetic fun upsert$default (Lorg/jetbrains/exposed/sql/Table;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/Set;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/statements/UpsertStatement;
public static final fun upsert (Lorg/jetbrains/exposed/sql/Table;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/List;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Lorg/jetbrains/exposed/sql/statements/UpsertStatement;
public static synthetic fun upsert$default (Lorg/jetbrains/exposed/sql/Table;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/List;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/statements/UpsertStatement;
}

public class org/jetbrains/exposed/sql/Query : org/jetbrains/exposed/sql/AbstractQuery {
Expand Down Expand Up @@ -2807,11 +2807,11 @@ public class org/jetbrains/exposed/sql/statements/BatchUpdateStatement : org/jet
}

public class org/jetbrains/exposed/sql/statements/BatchUpsertStatement : org/jetbrains/exposed/sql/statements/BaseBatchInsertStatement {
public fun <init> (Lorg/jetbrains/exposed/sql/Table;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/Set;Z)V
public synthetic fun <init> (Lorg/jetbrains/exposed/sql/Table;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/Set;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lorg/jetbrains/exposed/sql/Table;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/List;Z)V
public synthetic fun <init> (Lorg/jetbrains/exposed/sql/Table;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/List;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getKeys ()[Lorg/jetbrains/exposed/sql/Column;
public final fun getOnUpdate ()Ljava/util/List;
public final fun getOnUpdateExclude ()Ljava/util/Set;
public final fun getOnUpdateExclude ()Ljava/util/List;
public fun prepareSQL (Lorg/jetbrains/exposed/sql/Transaction;Z)Ljava/lang/String;
}

Expand Down Expand Up @@ -3034,12 +3034,12 @@ public class org/jetbrains/exposed/sql/statements/UpdateStatement : org/jetbrain
}

public class org/jetbrains/exposed/sql/statements/UpsertStatement : org/jetbrains/exposed/sql/statements/InsertStatement {
public fun <init> (Lorg/jetbrains/exposed/sql/Table;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/Set;Lorg/jetbrains/exposed/sql/Op;)V
public fun <init> (Lorg/jetbrains/exposed/sql/Table;[Lorg/jetbrains/exposed/sql/Column;Ljava/util/List;Ljava/util/List;Lorg/jetbrains/exposed/sql/Op;)V
public synthetic fun arguments ()Ljava/lang/Iterable;
public fun arguments ()Ljava/util/List;
public final fun getKeys ()[Lorg/jetbrains/exposed/sql/Column;
public final fun getOnUpdate ()Ljava/util/List;
public final fun getOnUpdateExclude ()Ljava/util/Set;
public final fun getOnUpdateExclude ()Ljava/util/List;
public final fun getWhere ()Lorg/jetbrains/exposed/sql/Op;
public fun prepareSQL (Lorg/jetbrains/exposed/sql/Transaction;Z)Ljava/lang/String;
}
Expand Down Expand Up @@ -3525,7 +3525,7 @@ 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 getDEFAULT_VALUE_EXPRESSION ()Ljava/lang/String;
protected final fun getKeyColumnsForUpsert (Lorg/jetbrains/exposed/sql/Table;[Lorg/jetbrains/exposed/sql/Column;)Ljava/util/List;
protected final fun getUpdateColumnsForUpsert (Ljava/util/List;Ljava/util/Set;Ljava/util/List;)Ljava/util/List;
protected final fun getUpdateColumnsForUpsert (Ljava/util/List;Ljava/util/List;Ljava/util/List;)Ljava/util/List;
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;
Expand All @@ -3550,7 +3550,7 @@ public abstract class org/jetbrains/exposed/sql/vendors/FunctionProvider {
public static synthetic fun substring$default (Lorg/jetbrains/exposed/sql/vendors/FunctionProvider;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/QueryBuilder;Ljava/lang/String;ILjava/lang/Object;)V
public fun update (Lorg/jetbrains/exposed/sql/Join;Ljava/util/List;Ljava/lang/Integer;Lorg/jetbrains/exposed/sql/Op;Lorg/jetbrains/exposed/sql/Transaction;)Ljava/lang/String;
public fun update (Lorg/jetbrains/exposed/sql/Table;Ljava/util/List;Ljava/lang/Integer;Lorg/jetbrains/exposed/sql/Op;Lorg/jetbrains/exposed/sql/Transaction;)Ljava/lang/String;
public fun upsert (Lorg/jetbrains/exposed/sql/Table;Ljava/util/List;Ljava/util/List;Ljava/util/Set;Lorg/jetbrains/exposed/sql/Op;Lorg/jetbrains/exposed/sql/Transaction;[Lorg/jetbrains/exposed/sql/Column;)Ljava/lang/String;
public fun upsert (Lorg/jetbrains/exposed/sql/Table;Ljava/util/List;Ljava/util/List;Ljava/util/List;Lorg/jetbrains/exposed/sql/Op;Lorg/jetbrains/exposed/sql/Transaction;[Lorg/jetbrains/exposed/sql/Column;)Ljava/lang/String;
public fun varPop (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/QueryBuilder;)V
public fun varSamp (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/QueryBuilder;)V
public fun year (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/QueryBuilder;)V
Expand Down
24 changes: 12 additions & 12 deletions exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Queries.kt
Original file line number Diff line number Diff line change
Expand Up @@ -418,15 +418,15 @@ fun Join.update(where: (SqlExpressionBuilder.() -> Op<Boolean>)? = null, limit:
* If no columns are provided, primary keys will be used. If the table does not have any primary keys, the first unique index will be attempted.
* @param onUpdate List of pairs of specific columns to update and the expressions to update them with.
* If left null, all columns will be updated with the values provided for the insert.
* @param onUpdateExclude Set of specific columns to exclude from updating.
* @param onUpdateExclude List of specific columns to exclude from updating.
* If left null, all columns will be updated with the values provided for the insert.
* @param where Condition that determines which rows to update, if a unique violation is found.
* @sample org.jetbrains.exposed.sql.tests.shared.dml.UpsertTests.testUpsertWithUniqueIndexConflict
*/
fun <T : Table> T.upsert(
vararg keys: Column<*>,
onUpdate: List<Pair<Column<*>, Expression<*>>>? = null,
onUpdateExclude: Set<Column<*>>? = null,
onUpdateExclude: List<Column<*>>? = null,
where: (SqlExpressionBuilder.() -> Op<Boolean>)? = null,
body: T.(UpsertStatement<Long>) -> Unit
) = UpsertStatement<Long>(this, *keys, onUpdate = onUpdate, onUpdateExclude = onUpdateExclude, where = where?.let { SqlExpressionBuilder.it() }).apply {
Expand All @@ -445,7 +445,7 @@ fun <T : Table> T.upsert(
* primary keys will be used. If the table does not have any primary keys, the first unique index will be attempted.
* @param onUpdate List of pairs of specific columns to update and the expressions to update them with.
* If left null, all columns will be updated with the values provided for the insert.
* @param onUpdateExclude Set of specific columns to exclude from updating.
* @param onUpdateExclude List of specific columns to exclude from updating.
* If left null, all columns will be updated with the values provided for the insert.
* @param shouldReturnGeneratedValues Specifies whether newly generated values (for example, auto-incremented IDs) should be returned.
* See [Batch Insert](https://github.com/JetBrains/Exposed/wiki/DSL#batch-insert) for more details.
Expand All @@ -455,11 +455,11 @@ fun <T : Table, E : Any> T.batchUpsert(
data: Iterable<E>,
vararg keys: Column<*>,
onUpdate: List<Pair<Column<*>, Expression<*>>>? = null,
onUpdateExclude: Set<Column<*>>? = null,
onUpdateExclude: List<Column<*>>? = null,
shouldReturnGeneratedValues: Boolean = true,
body: BatchUpsertStatement.(E) -> Unit
): List<ResultRow> {
return batchUpsert(data.iterator(), onUpdate, onUpdateExclude, shouldReturnGeneratedValues, body, keys = keys)
return batchUpsert(data.iterator(), onUpdate, onUpdateExclude, shouldReturnGeneratedValues, keys = keys, body = body)
}

/**
Expand All @@ -473,7 +473,7 @@ fun <T : Table, E : Any> T.batchUpsert(
* primary keys will be used. If the table does not have any primary keys, the first unique index will be attempted.
* @param onUpdate List of pairs of specific columns to update and the expressions to update them with.
* If left null, all columns will be updated with the values provided for the insert.
* @param onUpdateExclude Set of specific columns to exclude from updating.
* @param onUpdateExclude List of specific columns to exclude from updating.
* If left null, all columns will be updated with the values provided for the insert.
* @param shouldReturnGeneratedValues Specifies whether newly generated values (for example, auto-incremented IDs) should be returned.
* See [Batch Insert](https://github.com/JetBrains/Exposed/wiki/DSL#batch-insert) for more details.
Expand All @@ -483,11 +483,11 @@ fun <T : Table, E : Any> T.batchUpsert(
data: Sequence<E>,
vararg keys: Column<*>,
onUpdate: List<Pair<Column<*>, Expression<*>>>? = null,
onUpdateExclude: Set<Column<*>>? = null,
onUpdateExclude: List<Column<*>>? = null,
shouldReturnGeneratedValues: Boolean = true,
body: BatchUpsertStatement.(E) -> Unit
): List<ResultRow> {
return batchUpsert(data.iterator(), onUpdate, onUpdateExclude, shouldReturnGeneratedValues, body, keys = keys)
return batchUpsert(data.iterator(), onUpdate, onUpdateExclude, shouldReturnGeneratedValues, keys = keys, body = body)
}

/**
Expand All @@ -501,7 +501,7 @@ fun <T : Table, E : Any> T.batchUpsert(
* primary keys will be used. If the table does not have any primary keys, the first unique index will be attempted.
* @param onUpdate List of pairs of specific columns to update and the expressions to update them with.
* If left null, all columns will be updated with the values provided for the insert.
* @param onUpdateExclude Set of specific columns to exclude from updating.
* @param onUpdateExclude List of specific columns to exclude from updating.
* If left null, all columns will be updated with the values provided for the insert.
* @param shouldReturnGeneratedValues Specifies whether newly generated values (for example, auto-incremented IDs) should be returned.
* See [Batch Insert](https://github.com/JetBrains/Exposed/wiki/DSL#batch-insert) for more details.
Expand All @@ -510,10 +510,10 @@ fun <T : Table, E : Any> T.batchUpsert(
private fun <T : Table, E> T.batchUpsert(
data: Iterator<E>,
onUpdate: List<Pair<Column<*>, Expression<*>>>? = null,
onUpdateExclude: Set<Column<*>>? = null,
onUpdateExclude: List<Column<*>>? = null,
shouldReturnGeneratedValues: Boolean = true,
body: BatchUpsertStatement.(E) -> Unit,
vararg keys: Column<*>
vararg keys: Column<*>,
body: BatchUpsertStatement.(E) -> Unit
): List<ResultRow> = executeBatch(data, body) {
BatchUpsertStatement(this, *keys, onUpdate = onUpdate, onUpdateExclude = onUpdateExclude, shouldReturnGeneratedValues = shouldReturnGeneratedValues)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import org.jetbrains.exposed.sql.vendors.MysqlFunctionProvider
* primary keys will be used. If the table does not have any primary keys, the first unique index will be attempted.
* @param onUpdate List of pairs of specific columns to update and the expressions to update them with.
* If left null, all columns will be updated with the values provided for the insert.
* @param onUpdateExclude Set of specific columns to exclude from updating.
* @param onUpdateExclude List of specific columns to exclude from updating.
* If left null, all columns will be updated with the values provided for the insert.
* @param shouldReturnGeneratedValues Specifies whether newly generated values (for example, auto-incremented IDs) should be returned.
* See [Batch Insert](https://github.com/JetBrains/Exposed/wiki/DSL#batch-insert) for more details.
Expand All @@ -28,7 +28,7 @@ open class BatchUpsertStatement(
table: Table,
vararg val keys: Column<*>,
val onUpdate: List<Pair<Column<*>, Expression<*>>>?,
val onUpdateExclude: Set<Column<*>>?,
val onUpdateExclude: List<Column<*>>?,
shouldReturnGeneratedValues: Boolean = true
) : BaseBatchInsertStatement(table, ignore = false, shouldReturnGeneratedValues) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import org.jetbrains.exposed.sql.vendors.*
* primary keys will be used. If the table does not have any primary keys, the first unique index will be attempted.
* @param onUpdate List of pairs of specific columns to update and the expressions to update them with.
* If left null, all columns will be updated with the values provided for the insert.
* @param onUpdateExclude Set of specific columns to exclude from updating.
* @param onUpdateExclude List of specific columns to exclude from updating.
* If left null, all columns will be updated with the values provided for the insert.
* @param where Condition that determines which rows to update, if a unique violation is found. This clause may not be supported by all vendors.
*/
open class UpsertStatement<Key : Any>(
table: Table,
vararg val keys: Column<*>,
val onUpdate: List<Pair<Column<*>, Expression<*>>>?,
val onUpdateExclude: Set<Column<*>>?,
val onUpdateExclude: List<Column<*>>?,
val where: Op<Boolean>?
) : InsertStatement<Key>(table) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -534,15 +534,15 @@ abstract class FunctionProvider {
* @param table Table to either insert values into or update values from.
* @param data Pairs of columns to use for insert or update and values to insert or update.
* @param onUpdate List of pairs of specific columns to update and the expressions to update them with.
* @param onUpdateExclude Set of specific columns to exclude from updating.
* @param onUpdateExclude List of specific columns to exclude from updating.
* @param where Condition that determines which rows to update, if a unique violation is found.
* @param transaction Transaction where the operation is executed.
*/
open fun upsert(
table: Table,
data: List<Pair<Column<*>, Any?>>,
onUpdate: List<Pair<Column<*>, Expression<*>>>?,
onUpdateExclude: Set<Column<*>>?,
onUpdateExclude: List<Column<*>>?,
where: Op<Boolean>?,
transaction: Transaction,
vararg keys: Column<*>
Expand Down Expand Up @@ -611,10 +611,10 @@ abstract class FunctionProvider {
/** Returns the columns to be used in the update clause of an upsert statement. */
protected fun getUpdateColumnsForUpsert(
dataColumns: List<Column<*>>,
toExclude: Set<Column<*>>?,
toExclude: List<Column<*>>?,
keyColumns: List<Column<*>>?
): List<Column<*>> {
val updateColumns = toExclude?.let { dataColumns - it } ?: dataColumns
val updateColumns = toExclude?.let { dataColumns - it.toSet() } ?: dataColumns
return keyColumns?.let { keys ->
updateColumns.filter { it !in keys }.ifEmpty { updateColumns }
} ?: updateColumns
Expand Down
Loading

0 comments on commit 0439932

Please sign in to comment.