-
Notifications
You must be signed in to change notification settings - Fork 695
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
feat: EXPOSED-45 Support single statement UPSERT #1743
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package org.jetbrains.exposed.sql.statements | ||
|
||
import org.jetbrains.exposed.sql.* | ||
import org.jetbrains.exposed.sql.vendors.* | ||
|
||
/** | ||
* Represents the SQL command that either inserts a new row into a table, or updates the existing row if insertion would violate a unique constraint. | ||
* | ||
* @param table Table to either insert values into or update values from. | ||
* @param keys (optional) Columns to include in the condition that determines a unique constraint match. 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 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 where: Op<Boolean>? | ||
) : InsertStatement<Key>(table) { | ||
|
||
override fun prepareSQL(transaction: Transaction): String { | ||
val functionProvider = when (val dialect = transaction.db.dialect) { | ||
is H2Dialect -> when (dialect.h2Mode) { | ||
H2Dialect.H2CompatibilityMode.MariaDB, H2Dialect.H2CompatibilityMode.MySQL -> MysqlFunctionProvider() | ||
else -> H2FunctionProvider | ||
} | ||
else -> dialect.functionProvider | ||
} | ||
return functionProvider.upsert(table, arguments!!.first(), onUpdate, where, transaction, *keys) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -195,6 +195,28 @@ internal object OracleFunctionProvider : FunctionProvider() { | |
toString() | ||
} | ||
|
||
override fun upsert( | ||
table: Table, | ||
data: List<Pair<Column<*>, Any?>>, | ||
onUpdate: List<Pair<Column<*>, Expression<*>>>?, | ||
where: Op<Boolean>?, | ||
transaction: Transaction, | ||
vararg keys: Column<*> | ||
): String { | ||
val statement = super.upsert(table, data, onUpdate, where, transaction, *keys) | ||
|
||
val dualTable = data.appendTo(QueryBuilder(true), prefix = "(SELECT ", postfix = " FROM DUAL) S") { (column, value) -> | ||
registerArgument(column, value) | ||
+" AS " | ||
append(transaction.identity(column)) | ||
}.toString() | ||
|
||
val (leftReserved, rightReserved) = " USING " to " ON " | ||
val leftBoundary = statement.indexOf(leftReserved) + leftReserved.length | ||
val rightBoundary = statement.indexOf(rightReserved) | ||
return statement.replaceRange(leftBoundary, rightBoundary, dualTable) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A technicality, but I'm not entirely sure about this choice. If anyone has a cleaner idea of how to replace this chunk in the middle of a statement, I'm open to alternatives. The other way I considered was: return statement.replaceAfter(" USING ", dualTable) + statement.replaceBefore(" ON ", "") There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's ok to make it this way |
||
} | ||
|
||
override fun delete( | ||
ignore: Boolean, | ||
table: Table, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add KDoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done