Functions to safe IO with queries

This commit is contained in:
Andrew Golovashevich 2025-02-24 02:15:03 +03:00
parent 30bb10951b
commit e9377b7640
10 changed files with 585 additions and 0 deletions

View File

@ -0,0 +1,7 @@
package ru.landgrafhomyak.db.serdha0.user_commons.executors
import ru.landgrafhomyak.db.serdha0.api.runtime.OutputRow
public fun interface RowConsumer0<qUE : Any, R> {
public fun transformRow(row: OutputRow<qUE>): R
}

View File

@ -0,0 +1,7 @@
package ru.landgrafhomyak.db.serdha0.user_commons.executors
import ru.landgrafhomyak.db.serdha0.api.runtime.OutputRow
public fun interface RowConsumer1<qUE : Any, R> {
public fun transformRow(row: OutputRow<qUE>, index: Int): R
}

View File

@ -0,0 +1,7 @@
package ru.landgrafhomyak.db.serdha0.user_commons.executors
import ru.landgrafhomyak.db.serdha0.api.runtime.InputRow
public fun interface RowProducer0<qUE : Any> {
public fun initializeRow(row: InputRow<qUE>)
}

View File

@ -0,0 +1,7 @@
package ru.landgrafhomyak.db.serdha0.user_commons.executors
import ru.landgrafhomyak.db.serdha0.api.runtime.InputRow
public fun interface RowProducer1<qUE : Any, E> {
public fun transformToRow(row: InputRow<qUE>, value: E)
}

View File

@ -0,0 +1,7 @@
package ru.landgrafhomyak.db.serdha0.user_commons.executors
import ru.landgrafhomyak.db.serdha0.api.runtime.InputRow
public fun interface RowProducer2<qUE : Any, E> {
public fun transformToRow(row: InputRow<qUE>, index: Int, value: E)
}

View File

@ -0,0 +1,29 @@
@file:JvmName("_AutocloseKt")
package ru.landgrafhomyak.db.serdha0.user_commons.executors
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.jvm.JvmName
@Suppress("FunctionName")
@PublishedApi
internal inline fun <R> _safeAutoClose(onAbort: () -> Unit = {}, action: () -> R): R {
contract {
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
callsInPlace(onAbort, InvocationKind.AT_MOST_ONCE)
}
val ret: R
try {
ret = action()
} catch (e1: Throwable) {
try {
onAbort()
} catch (e2: Throwable) {
e1.addSuppressed(e2)
}
throw e1
}
return ret
}

View File

@ -0,0 +1,168 @@
@file:OptIn(LowLevelApi::class)
@file:JvmName("Row2Void")
@file:Suppress("DuplicatedCode")
package ru.landgrafhomyak.db.serdha0.user_commons.executors
import kotlin.jvm.JvmName
import ru.landgrafhomyak.db.serdha0.api.LowLevelApi
import ru.landgrafhomyak.db.serdha0.api.queries._Query
import ru.landgrafhomyak.db.serdha0.api.runtime.Transaction
public class ExpectedOneRowException : Error("Expected at least one row, but table is empty")
public class TooManyRowsException : Error("Expected exactly one row, but got more")
public suspend inline fun <qUE : Any, R> Transaction.selectExactlyOneOrError(
compiledQuery: _Query.Params2Table<qUE>,
params: RowProducer0<qUE>,
result: RowConsumer0<qUE, R>
): R {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
val ret: R
_safeAutoClose(onAbort = { oRow._abort() }) {
if (!oRow._next())
throw ExpectedOneRowException()
ret = result.transformRow(oRow)
if (oRow._next())
throw TooManyRowsException()
}
oRow._finish()
return ret
}
public suspend inline fun <qUE : Any, R> Transaction.selectExactlyOneOrError(
compiledQuery: _Query.Void2Table<qUE>,
result: RowConsumer0<qUE, R>
): R {
val oRow = this._executeQuery(compiledQuery)
val ret: R
_safeAutoClose(onAbort = { oRow._abort() }) {
if (!oRow._next())
throw ExpectedOneRowException()
ret = result.transformRow(oRow)
if (oRow._next())
throw TooManyRowsException()
}
oRow._finish()
return ret
}
public suspend inline fun <qUE : Any, R> Transaction.selectExactlyOneOrNull(
compiledQuery: _Query.Params2Table<qUE>,
params: RowProducer0<qUE>,
result: RowConsumer0<qUE, R>
): R? {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
val ret: R?
_safeAutoClose(onAbort = { oRow._abort() }) {
if (!oRow._next()) {
ret = null
return@_safeAutoClose
}
ret = result.transformRow(oRow)
if (oRow._next())
throw TooManyRowsException()
}
oRow._finish()
return ret
}
public suspend inline fun <qUE : Any, R> Transaction.selectExactlyOneOrNull(
compiledQuery: _Query.Void2Table<qUE>,
result: RowConsumer0<qUE, R>
): R? {
val oRow = this._executeQuery(compiledQuery)
val ret: R?
_safeAutoClose(onAbort = { oRow._abort() }) {
if (!oRow._next()) {
ret = null
return@_safeAutoClose
}
ret = result.transformRow(oRow)
if (oRow._next())
throw TooManyRowsException()
}
oRow._finish()
return ret
}
public suspend inline fun <qUE : Any, R> Transaction.selectFirstOrError(
compiledQuery: _Query.Params2Table<qUE>,
params: RowProducer0<qUE>,
result: RowConsumer0<qUE, R>
): R {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
val ret: R
_safeAutoClose(onAbort = { oRow._abort() }) {
if (!oRow._next())
throw ExpectedOneRowException()
ret = result.transformRow(oRow)
}
oRow._finish()
return ret
}
public suspend inline fun <qUE : Any, R> Transaction.selectFirstOrError(
compiledQuery: _Query.Void2Table<qUE>,
result: RowConsumer0<qUE, R>
): R {
val oRow = this._executeQuery(compiledQuery)
val ret: R
_safeAutoClose(onAbort = { oRow._abort() }) {
if (!oRow._next())
throw ExpectedOneRowException()
ret = result.transformRow(oRow)
}
oRow._finish()
return ret
}
public suspend inline fun <qUE : Any, R> Transaction.selectFirstOrNull(
compiledQuery: _Query.Params2Table<qUE>,
params: RowProducer0<qUE>,
result: RowConsumer0<qUE, R>
): R? {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
val ret: R?
_safeAutoClose(onAbort = { oRow._abort() }) {
if (!oRow._next()) {
ret = null
return@_safeAutoClose
}
ret = result.transformRow(oRow)
}
oRow._finish()
return ret
}
public suspend inline fun <qUE : Any, R> Transaction.selectFirstOrNull(
compiledQuery: _Query.Void2Table<qUE>,
result: RowConsumer0<qUE, R>
): R? {
val oRow = this._executeQuery(compiledQuery)
val ret: R?
_safeAutoClose(onAbort = { oRow._abort() }) {
if (!oRow._next()) {
ret = null
return@_safeAutoClose
}
ret = result.transformRow(oRow)
}
oRow._finish()
return ret
}

View File

@ -0,0 +1,212 @@
@file:OptIn(LowLevelApi::class)
@file:JvmName("Row2Void")
@file:Suppress("DuplicatedCode")
package ru.landgrafhomyak.db.serdha0.user_commons.executors
import kotlin.jvm.JvmName
import ru.landgrafhomyak.db.serdha0.api.LowLevelApi
import ru.landgrafhomyak.db.serdha0.api.queries._Query
import ru.landgrafhomyak.db.serdha0.api.runtime.Transaction
public suspend inline fun <qUE : Any> Transaction.select(
compiledQuery: _Query.Params2Table<qUE>,
params: RowProducer0<qUE>,
transform: RowConsumer0<qUE, Unit>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
_safeAutoClose(onAbort = { oRow._abort() }) {
while (oRow._next())
transform.transformRow(oRow)
}
oRow._finish()
}
public suspend inline fun <qUE : Any> Transaction.select(
compiledQuery: _Query.Void2Table<qUE>,
transform: RowConsumer0<qUE, Unit>
) {
val oRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { oRow._abort() }) {
while (oRow._next())
transform.transformRow(oRow)
}
oRow._finish()
}
public suspend inline fun <qUE : Any, E> Transaction.mapRows(
compiledQuery: _Query.Params2Table<qUE>,
params: RowProducer0<qUE>,
transform: RowConsumer0<qUE, E>
): List<E> {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
val out = ArrayList<E>()
_safeAutoClose(onAbort = { oRow._abort() }) {
while (oRow._next())
out.add(transform.transformRow(oRow))
}
oRow._finish()
return out
}
public suspend inline fun <qUE : Any, E> Transaction.mapRows(
compiledQuery: _Query.Void2Table<qUE>,
transform: RowConsumer0<qUE, E>
): List<E> {
val oRow = this._executeQuery(compiledQuery)
val out = ArrayList<E>()
_safeAutoClose(onAbort = { oRow._abort() }) {
while (oRow._next())
out.add(transform.transformRow(oRow))
}
oRow._finish()
return out
}
public suspend inline fun <qUE : Any, E> Transaction.mapRowsIndexed(
compiledQuery: _Query.Params2Table<qUE>,
params: RowProducer0<qUE>,
firstIndex: Int = 0,
transform: RowConsumer1<qUE, E>
): List<E> {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
val out = ArrayList<E>()
_safeAutoClose(onAbort = { oRow._abort() }) {
var i = firstIndex
while (oRow._next())
out.add(transform.transformRow(oRow, i++))
}
oRow._finish()
return out
}
public suspend inline fun <qUE : Any, E> Transaction.mapRowsIndexed(
compiledQuery: _Query.Void2Table<qUE>,
firstIndex: Int = 0,
transform: RowConsumer1<qUE, E>
): List<E> {
val oRow = this._executeQuery(compiledQuery)
val out = ArrayList<E>()
_safeAutoClose(onAbort = { oRow._abort() }) {
var i = firstIndex
while (oRow._next())
out.add(transform.transformRow(oRow, i++))
}
oRow._finish()
return out
}
public suspend inline fun <qUE : Any, E, C : MutableCollection<E>> Transaction.mapRowsTo(
compiledQuery: _Query.Params2Table<qUE>,
params: RowProducer0<qUE>,
dst: C,
transform: RowConsumer0<qUE, E>
): C {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
_safeAutoClose(onAbort = { oRow._abort() }) {
while (oRow._next())
dst.add(transform.transformRow(oRow))
}
oRow._finish()
return dst
}
public suspend inline fun <qUE : Any, E, C : MutableCollection<E>> Transaction.mapRowsTo(
compiledQuery: _Query.Void2Table<qUE>,
dst: C,
transform: RowConsumer0<qUE, E>
): C {
val oRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { oRow._abort() }) {
while (oRow._next())
dst.add(transform.transformRow(oRow))
}
oRow._finish()
return dst
}
public suspend inline fun <qUE : Any, E, C : MutableCollection<E>> Transaction.mapRowsIndexedTo(
compiledQuery: _Query.Params2Table<qUE>,
params: RowProducer0<qUE>,
dst: C, firstIndex: Int = 0,
transform: RowConsumer1<qUE, E>
): C {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
_safeAutoClose(onAbort = { oRow._abort() }) {
var i = firstIndex
while (oRow._next())
dst.add(transform.transformRow(oRow, i++))
}
oRow._finish()
return dst
}
public suspend inline fun <qUE : Any, E, C : MutableCollection<E>> Transaction.mapRowsIndexedTo(
compiledQuery: _Query.Void2Table<qUE>,
dst: C, firstIndex: Int = 0,
transform: RowConsumer1<qUE, E>
): C {
val oRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { oRow._abort() }) {
var i = firstIndex
while (oRow._next())
dst.add(transform.transformRow(oRow, i++))
}
oRow._finish()
return dst
}
public suspend inline fun <qUE : Any, E> Transaction.mapRowsTo(
compiledQuery: _Query.Params2Table<qUE>,
params: RowProducer0<qUE>,
dst: Array<E>, dstOffset: Int = 0,
transform: RowConsumer0<qUE, E>
): Array<E> {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
val oRow = iRow._finish()
_safeAutoClose(onAbort = { oRow._abort() }) {
var i = dstOffset
while (oRow._next())
dst[i++] = transform.transformRow(oRow)
}
oRow._finish()
return dst
}
public suspend inline fun <qUE : Any, E> Transaction.mapRowsTo(
compiledQuery: _Query.Void2Table<qUE>,
dst: Array<E>, dstOffset: Int = 0,
transform: RowConsumer0<qUE, E>
): Array<E> {
val oRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { oRow._abort() }) {
var i = dstOffset
while (oRow._next())
dst[i++] = transform.transformRow(oRow)
}
oRow._finish()
return dst
}

View File

@ -0,0 +1,32 @@
@file:OptIn(LowLevelApi::class)
@file:JvmName("Row2Void")
@file:Suppress("DuplicatedCode")
package ru.landgrafhomyak.db.serdha0.user_commons.executors
import kotlin.jvm.JvmName
import ru.landgrafhomyak.db.serdha0.api.LowLevelApi
import ru.landgrafhomyak.db.serdha0.api.queries._Query
import ru.landgrafhomyak.db.serdha0.api.runtime.Transaction
public suspend inline fun <qUE : Any> Transaction.executeWithParams(
compiledQuery: _Query.Params2Void<qUE>,
params: RowProducer0<qUE>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
iRow._finish()
}
public suspend inline fun <qUE : Any> Transaction.executeWithParams(
compiledQuery: _Query.Params2Table<qUE>,
params: RowProducer0<qUE>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
params.initializeRow(iRow)
}
iRow._finish()._finish()
}

View File

@ -0,0 +1,109 @@
@file:OptIn(LowLevelApi::class)
@file:JvmName("Rows2VoidKt")
@file:Suppress("DuplicatedCode")
package ru.landgrafhomyak.db.serdha0.user_commons.executors
import kotlin.jvm.JvmName
import ru.landgrafhomyak.db.serdha0.api.LowLevelApi
import ru.landgrafhomyak.db.serdha0.api.queries._Query
import ru.landgrafhomyak.db.serdha0.api.runtime.Transaction
public suspend inline fun <qUE : Any, E> Transaction.mapToRows(
compiledQuery: _Query.Table2Void<qUE>,
collection: Iterable<E>,
transform: RowProducer1<qUE, E>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
for (elem in collection) {
iRow._next()
transform.transformToRow(iRow, elem)
}
}
iRow._finish()
}
public suspend inline fun <qUE : Any, E> Transaction.mapToRowsIndexed(
compiledQuery: _Query.Table2Void<qUE>,
collection: Iterable<E>,
firstIndex: Int = 0,
transform: RowProducer2<qUE, E>
) {
val iRow = this._executeQuery(compiledQuery)
var index = firstIndex
_safeAutoClose(onAbort = { iRow._abort() }) {
for (elem in collection) {
iRow._next()
transform.transformToRow(iRow, index, elem)
index++
}
}
iRow._finish()
}
public suspend inline fun <qUE : Any, E> Transaction.mapToRows(
compiledQuery: _Query.Table2Void<qUE>,
sequence: Sequence<E>,
transform: RowProducer1<qUE, E>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
for (elem in sequence) {
iRow._next()
transform.transformToRow(iRow, elem)
}
}
iRow._finish()
}
public suspend inline fun <qUE : Any, E> Transaction.mapToRowsIndexed(
compiledQuery: _Query.Table2Void<qUE>,
sequence: Sequence<E>,
firstIndex: Int = 0,
transform: RowProducer2<qUE, E>
) {
val iRow = this._executeQuery(compiledQuery)
var index = firstIndex
_safeAutoClose(onAbort = { iRow._abort() }) {
for (elem in sequence) {
iRow._next()
transform.transformToRow(iRow, index, elem)
index++
}
}
iRow._finish()
}
public suspend inline fun <qUE : Any, E> Transaction.mapToRows(
compiledQuery: _Query.Table2Void<qUE>,
sequence: Array<E>,
transform: RowProducer1<qUE, E>
) {
val iRow = this._executeQuery(compiledQuery)
_safeAutoClose(onAbort = { iRow._abort() }) {
for (elem in sequence) {
iRow._next()
transform.transformToRow(iRow, elem)
}
}
iRow._finish()
}
public suspend inline fun <qUE : Any, E> Transaction.mapToRowsIndexed(
compiledQuery: _Query.Table2Void<qUE>,
sequence: Array<E>,
firstIndex: Int = 0,
transform: RowProducer2<qUE, E>
) {
val iRow = this._executeQuery(compiledQuery)
var index = firstIndex
_safeAutoClose(onAbort = { iRow._abort() }) {
for (elem in sequence) {
iRow._next()
transform.transformToRow(iRow, index, elem)
index++
}
}
iRow._finish()
}