Upsert works now
This commit is contained in:
@@ -252,7 +252,7 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource) : Backing
|
|||||||
it[ParcelOptionsT.interact_inventory] = value
|
it[ParcelOptionsT.interact_inventory] = value
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
ParcelOptionsT.replace {
|
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
|
||||||
it[ParcelOptionsT.parcel_id] = id
|
it[ParcelOptionsT.parcel_id] = id
|
||||||
it[ParcelOptionsT.interact_inventory] = value
|
it[ParcelOptionsT.interact_inventory] = value
|
||||||
}
|
}
|
||||||
@@ -260,7 +260,7 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource) : Backing
|
|||||||
|
|
||||||
override suspend fun setParcelAllowsInteractInputs(parcel: Parcel, value: Boolean): Unit = transaction {
|
override suspend fun setParcelAllowsInteractInputs(parcel: Parcel, value: Boolean): Unit = transaction {
|
||||||
val id = getOrInitParcelId(parcel)
|
val id = getOrInitParcelId(parcel)
|
||||||
ParcelOptionsT.replace {
|
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
|
||||||
it[ParcelOptionsT.parcel_id] = id
|
it[ParcelOptionsT.parcel_id] = id
|
||||||
it[ParcelOptionsT.interact_inputs] = value
|
it[ParcelOptionsT.interact_inputs] = value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,44 +5,11 @@ import org.jetbrains.exposed.sql.statements.InsertStatement
|
|||||||
import org.jetbrains.exposed.sql.statements.UpdateStatement
|
import org.jetbrains.exposed.sql.statements.UpdateStatement
|
||||||
import org.jetbrains.exposed.sql.transactions.TransactionManager
|
import org.jetbrains.exposed.sql.transactions.TransactionManager
|
||||||
|
|
||||||
/*
|
|
||||||
* insertOrUpdate from https://github.com/JetBrains/Exposed/issues/167#issuecomment-403837917
|
|
||||||
*/
|
|
||||||
inline fun <T : Table> T.insertOrUpdate(vararg onDuplicateUpdateKeys: Column<*>, body: T.(InsertStatement<Number>) -> Unit) =
|
|
||||||
InsertOrUpdate<Number>(onDuplicateUpdateKeys, this).apply {
|
|
||||||
body(this)
|
|
||||||
execute(TransactionManager.current())
|
|
||||||
}
|
|
||||||
|
|
||||||
class InsertOrUpdate<Key : Any>(
|
|
||||||
private val onDuplicateUpdateKeys: Array<out Column<*>>,
|
|
||||||
table: Table,
|
|
||||||
isIgnore: Boolean = false
|
|
||||||
) : InsertStatement<Key>(table, isIgnore) {
|
|
||||||
override fun prepareSQL(transaction: Transaction): String {
|
|
||||||
val onUpdateSQL = if (onDuplicateUpdateKeys.isNotEmpty()) {
|
|
||||||
" ON DUPLICATE KEY UPDATE " + onDuplicateUpdateKeys.joinToString { "${transaction.identity(it)}=VALUES(${transaction.identity(it)})" }
|
|
||||||
} else ""
|
|
||||||
return super.prepareSQL(transaction) + onUpdateSQL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class UpsertStatement<Key : Any>(table: Table, conflictColumn: Column<*>? = null, conflictIndex: Index? = null)
|
class UpsertStatement<Key : Any>(table: Table, conflictColumn: Column<*>? = null, conflictIndex: Index? = null)
|
||||||
: InsertStatement<Key>(table, false) {
|
: InsertStatement<Key>(table, false) {
|
||||||
val indexName: String
|
val indexName: String
|
||||||
val indexColumns: List<Column<*>>
|
val indexColumns: List<Column<*>>
|
||||||
|
|
||||||
private fun getUpdateStatement(): UpdateStatement {
|
|
||||||
val map: Map<Column<Any?>, Any?> = values.castUnchecked()
|
|
||||||
val statement = updateBody(table, UpdateStatement(table, null, combineAsConjunctions(indexColumns.castUnchecked(), map))) {
|
|
||||||
map.forEach { col, value -> if (col !in indexColumns)
|
|
||||||
it[col] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return statement
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
when {
|
when {
|
||||||
conflictIndex != null -> {
|
conflictIndex != null -> {
|
||||||
@@ -57,44 +24,15 @@ class UpsertStatement<Key : Any>(table: Table, conflictColumn: Column<*>? = null
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun prepareSQL(transaction: Transaction): String {
|
override fun prepareSQL(transaction: Transaction) = buildString {
|
||||||
val insertSQL = super.prepareSQL(transaction)
|
append(super.prepareSQL(transaction))
|
||||||
val updateStatement = getUpdateStatement()
|
append(" ON CONFLICT(")
|
||||||
val updateSQL = updateStatement.prepareSQL(transaction)
|
append(indexName)
|
||||||
super.arguments = listOf(super.arguments!!.first(), updateStatement.firstDataSet)
|
append(") DO UPDATE SET ")
|
||||||
|
|
||||||
return buildString {
|
values.keys.filter { it !in indexColumns}.joinTo(this) { "${transaction.identity(it)}=EXCLUDED.${transaction.identity(it)}" }
|
||||||
append(insertSQL)
|
}.also { println(it) }
|
||||||
append(" ON CONFLICT(")
|
|
||||||
append(indexName)
|
|
||||||
append(") DO UPDATE ")
|
|
||||||
append(updateSQL)
|
|
||||||
}.also { println(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private companion object {
|
|
||||||
|
|
||||||
inline fun <T : Table> updateBody(table: T, updateStatement: UpdateStatement,
|
|
||||||
body: T.(UpdateStatement) -> Unit): UpdateStatement {
|
|
||||||
table.body(updateStatement)
|
|
||||||
return updateStatement
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
|
|
||||||
inline fun <T> Any.castUnchecked() = this as T
|
|
||||||
|
|
||||||
private val absent = Any() // marker object
|
|
||||||
fun combineAsConjunctions(columns: Iterable<Column<Any?>>, map: Map<Column<Any?>, Any?>): Op<Boolean>? {
|
|
||||||
return with(SqlExpressionBuilder) {
|
|
||||||
columns.fold<Column<Any?>, Op<Boolean>?>(null) { op, col ->
|
|
||||||
val arg = map.getOrDefault(col, absent)
|
|
||||||
if (arg === absent) return@fold op
|
|
||||||
op?.let { it and (col eq arg) } ?: col eq arg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <T : Table> T.upsert(conflictColumn: Column<*>? = null, conflictIndex: Index? = null, body: T.(UpsertStatement<Number>) -> Unit) =
|
inline fun <T : Table> T.upsert(conflictColumn: Column<*>? = null, conflictIndex: Index? = null, body: T.(UpsertStatement<Number>) -> Unit) =
|
||||||
|
|||||||
Reference in New Issue
Block a user