You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I was wondering why that is? Is there a major restriction for that?
I would like to use batch update to do something like the following:
val data = listOf<DataToUpdate>()
BatchUpdateStatement(FooTable).apply {
data.forEach {
addBatch(it.id)
// i.e. SET foo_table.amount = foo_table.amount + ?this[FooTable.amount] =FooTable.amount + it.amount
}
execute(Transaction.current())
}
But with the current implementation, I get an error because of the set operator not allowing expressions.
What I've done to fix this is write a new version of BatchUpdateStatement that doesn't override update and then overrides the arguments() function with the following:
overridefunarguments(): Iterable<Iterable<Pair<IColumnType, Any?>>> = data.map { (id, rowInput) ->QueryBuilder(true).run {
rowInput.forEach {
registerArgument(it.key, it.value)
}
// last input arg should be table id for where clause
registerArgument(table.id.columnType, id)
args
}
}
By using a QueryBuilder when fetching the arguments for the preparedStatement, I can use registerArgument which will parse the expression correctly.
I would really appreciate any input here with regards to this approach. Is there something I'm missing? Was there a more specific reason why expressions weren't allowed in the current version of BatchUpdateStatement?
I would also be happy to open a PR against the lib if my current approach seems viable.
Here is the full code for my working implementation with returning (assuming using Postgres):
classBatchUpdateStatementWithExpression(
valtable:IdTable<*>,
privatevalreturnKeys:Boolean = false
) : UpdateStatement(table, null) {
val data =ArrayList<Pair<EntityID<*>, Map<Column<*>, Any?>>>()
overrideval firstDataSet:List<Pair<Column<*>, Any?>> get() = data.first().second.toList()
var resultRows:List<ResultRow> = emptyList()
private set
funaddBatch(id:EntityID<*>) {
val lastBatch = data.lastOrNull()
val different by lazy {
val set1 = firstDataSet.map { it.first }.toSet()
val set2 = lastBatch!!.second.keys
(set1 - set2) + (set2 - set1)
}
if (data.size >1&& different.isNotEmpty()) {
throwBatchDataInconsistentException("Some values missing for batch update. Different columns: $different")
}
if (data.isNotEmpty()) {
data[data.size -1] = lastBatch!!.copy(second = values.toMap())
values.clear()
hasBatchedValues =true
}
data.add(id to values)
}
overridefunprepareSQL(transaction:Transaction): String="${super.prepareSQL(transaction)} WHERE ${transaction.identity(table.id)} = ?"overridefun PreparedStatementApi.executeInternal(transaction:Transaction): Int {
val result =if (data.size ==1) executeUpdate() else executeBatch().sum()
if (returnKeys && resultSet !=null) {
resultRows = processResults(resultSet!!)
}
return result
}
overridefunarguments(): Iterable<Iterable<Pair<IColumnType, Any?>>> = data.map { (id, rowInput) ->QueryBuilder(true).run {
rowInput.forEach {
registerArgument(it.key, it.value)
}
// last input arg should be table id for where clause
registerArgument(table.id.columnType, id)
args
}
}
overridefunprepared(transaction:Transaction, sql:String): PreparedStatementApi {
return transaction.connection.prepareStatement(sql, returnKeys)
}
privatefunprocessResults(resultSet:ResultSet): List<ResultRow> {
// map columns to result set indexval returnedColumns = targetsSet.columns.mapNotNull { col ->try {
resultSet.findColumn(col.name).let { col to it }
} catch (e:SQLException) {
null
}
}
val rows = arrayListOf<MutableMap<Column<*>, Any?>>()
while (resultSet.next()) {
val columnMappings = returnedColumns.associateTo(mutableMapOf()) {
it.first to resultSet.getObject(it.second)
}
rows.add(columnMappings)
}
// cast here because createAndFillValues expects expression instead of column
@Suppress("UNCHECKED_CAST")
return rows.map { ResultRow.createAndFillValues(it asMap<Expression<*>, Any?>) }
}
}
interfaceBatchUpdateRequest<T:Comparable<T>> {
val id:EntityID<T>
}
fun <Key:Comparable<Key>, T : IdTable<Key>, E : BatchUpdateRequest<Key>> T.batchUpdateWithExpression(
data:Iterable<E>,
returnKeys:Boolean = false,
body:BatchUpdateStatementWithExpression.(E) ->Unit
): List<ResultRow> {
if (!data.iterator().hasNext()) return emptyList()
returnBatchUpdateStatementWithExpression(this, returnKeys).apply {
data.forEach {
addBatch(it.id)
body(it)
}
execute(TransactionManager.current())
}.resultRows
}
Which can be used like:
val data = listOf<DataToUpdate>()
FooTable.batchUpdateWithExpression(data, returnKeys =true) {
// i.e. SET foo_table.amount = foo_table.amount + ?this[FooTable.amount] =FooTable.amount + it.amount
}
Any feedback would be greatly appreciated! 🙏
The text was updated successfully, but these errors were encountered:
Hello, first off, thanks for the great lib!
I have some questions about the existing BatchUpdateStatement.
The override for
update
with expression currently has the following function body:I was wondering why that is? Is there a major restriction for that?
I would like to use batch update to do something like the following:
But with the current implementation, I get an error because of the
set
operator not allowing expressions.What I've done to fix this is write a new version of
BatchUpdateStatement
that doesn't overrideupdate
and then overrides thearguments()
function with the following:By using a QueryBuilder when fetching the arguments for the preparedStatement, I can use registerArgument which will parse the expression correctly.
I would really appreciate any input here with regards to this approach. Is there something I'm missing? Was there a more specific reason why expressions weren't allowed in the current version of BatchUpdateStatement?
I would also be happy to open a PR against the lib if my current approach seems viable.
Here is the full code for my working implementation with returning (assuming using Postgres):
Which can be used like:
Any feedback would be greatly appreciated! 🙏
The text was updated successfully, but these errors were encountered: