From ae1430b6961e26c20938b3edd4b068b39ee5dc2d Mon Sep 17 00:00:00 2001 From: Andrew Golovashevich <landgrafhomyak@gmail.com> Date: Thu, 28 Nov 2024 21:33:42 +0300 Subject: [PATCH] DELETE, fixes, auto-transactions --- .../serdha/api/v0/Expression.kt | 7 +- .../serdha/api/v0/ddl/Module.kt | 4 + .../serdha/api/v0/ddl/ModuleModifyingRound.kt | 48 ++- .../serdha/api/v0/ddl/TableCreator.kt | 6 + .../serdha/api/v0/dml/Delete.kt | 5 + .../serdha/api/v0/dml/DeleteCreator.kt | 16 + .../serdha/api/v0/dml/InsertCreator.kt | 2 +- .../serdha/api/v0/dml/SelectCreator.kt | 3 + .../serdha/api/v0/dml/SelectedColumn.kt | 2 +- .../serdha/api/v0/dml/UpdateCreator.kt | 4 +- .../serdha/api/v0/runtime/ParametersSetter.kt | 23 +- .../api/v0/runtime/SynchronizedDatabase.kt | 26 ++ .../serdha/api/v0/runtime/Transaction.kt | 5 + .../api/v0/runtime/transaction_methods.kt | 379 +++++++++++++++++- 14 files changed, 503 insertions(+), 27 deletions(-) create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Delete.kt create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/DeleteCreator.kt diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/Expression.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/Expression.kt index 3e1e962..3338173 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/Expression.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/Expression.kt @@ -2,4 +2,9 @@ package ru.landgrafhomyak.serdha.api.v0 import ru.landgrafhomyak.serdha.api.v0.ddl.ColumnType -public interface Expression<RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>, OwnerBuilderUserWrapper : Any> \ No newline at end of file +public interface Expression<RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>, OwnerBuilderUserWrapper : Any> { + public class Equals<RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>, OwnerBuilderUserWrapper : Any>( + public val left: Expression<RuntimeType, DatabaseType, OwnerBuilderUserWrapper>, + public val right: Expression<RuntimeType, DatabaseType, OwnerBuilderUserWrapper>, + ) : Expression<Boolean, ColumnType.BOOLEAN, OwnerBuilderUserWrapper> +} \ No newline at end of file diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/Module.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/Module.kt index 07164c6..969c1ab 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/Module.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/Module.kt @@ -1,7 +1,11 @@ package ru.landgrafhomyak.serdha.api.v0.ddl +import ru.landgrafhomyak.serdha.api.v0.runtime.SynchronizedDatabase + public interface Module<W : Any> { public val wrapper: W public val versionKey: String + + public val ownerDatabase: SynchronizedDatabase<*> } \ No newline at end of file diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ModuleModifyingRound.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ModuleModifyingRound.kt index 4d4bccb..fd49760 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ModuleModifyingRound.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ModuleModifyingRound.kt @@ -1,5 +1,7 @@ package ru.landgrafhomyak.serdha.api.v0.ddl +import ru.landgrafhomyak.serdha.api.v0.dml.Delete +import ru.landgrafhomyak.serdha.api.v0.dml.DeleteCreator import ru.landgrafhomyak.serdha.api.v0.dml.Insert import ru.landgrafhomyak.serdha.api.v0.dml.InsertCreator import ru.landgrafhomyak.serdha.api.v0.dml.Select @@ -8,15 +10,19 @@ import ru.landgrafhomyak.serdha.api.v0.dml.Update import ru.landgrafhomyak.serdha.api.v0.dml.UpdateCreator public interface ModuleModifyingRound { - public fun <TableUserWrapper : Any> createTable( - namespace: Namespace, - name: String, - initializer: (TableCreator<TableUserWrapper>) -> TableUserWrapper - ): Table<TableUserWrapper, Nothing> + public fun interface CreateTable<TableUserWrapper : Any> { + public fun createTable(creator: TableCreator<TableUserWrapper>): TableUserWrapper + } + + public fun <TableUserWrapper : Any> createTable(namespace: Namespace, name: String, initializer: CreateTable<TableUserWrapper>): Table<TableUserWrapper, Nothing> + + public fun interface UpdateTable<TableNewUserWrapper : Any, TableOldUserWrapper : Any> { + public fun updateTable(oldTable: Table<TableOldUserWrapper, *>, updater: TableUpdater<TableNewUserWrapper, TableOldUserWrapper>): TableNewUserWrapper + } public fun <TableNewUserWrapper : Any, TableOldUserWrapper : Any> updateTable( oldTable: Table<TableOldUserWrapper, *>, - initializer: (TableUpdater<TableNewUserWrapper, TableOldUserWrapper>) -> TableNewUserWrapper + initializer: UpdateTable<TableNewUserWrapper, TableOldUserWrapper> ): Table<TableNewUserWrapper, TableOldUserWrapper> public fun <TableNewUserWrapper : Any, TableOldUserWrapper : Any> renameTable( @@ -33,19 +39,39 @@ public interface ModuleModifyingRound { public fun <TableNewUserWrapper : Any, TableOldUserWrapper : Any> updateAndRenameTable( table: Table<TableOldUserWrapper, *>, newName: String, - initializer: (TableUpdater<TableNewUserWrapper, TableOldUserWrapper>) -> TableNewUserWrapper + initializer: UpdateTable<TableNewUserWrapper, TableOldUserWrapper> ): Table<TableNewUserWrapper, TableOldUserWrapper> public fun <TableNewUserWrapper : Any, TableOldUserWrapper : Any> updateAndRenameTable( table: Table<TableNewUserWrapper, TableOldUserWrapper>, newNamespace: Namespace, newName: String, - initializer: (TableUpdater<TableNewUserWrapper, TableOldUserWrapper>) -> TableNewUserWrapper + initializer: UpdateTable<TableNewUserWrapper, TableOldUserWrapper> ): Table<TableNewUserWrapper, TableOldUserWrapper> - public fun <QueryUserWrapper : Any> createSelect(initializer: (SelectCreator<QueryUserWrapper>) -> QueryUserWrapper): Select<QueryUserWrapper> - public fun <TableUserWrapper : Any, QueryUserWrapper : Any> createInsert(table: Table<TableUserWrapper, *>, initializer: (InsertCreator<TableUserWrapper, QueryUserWrapper>) -> QueryUserWrapper): Insert<QueryUserWrapper> - public fun <TableUserWrapper : Any, QueryUserWrapper : Any> createUpdate(table: Table<TableUserWrapper, *>, initializer: (UpdateCreator<TableUserWrapper, QueryUserWrapper>) -> QueryUserWrapper): Update<QueryUserWrapper> + public fun interface CreateSelect<QueryUserWrapper : Any> { + public fun createSelect(creator: SelectCreator<QueryUserWrapper>): QueryUserWrapper + } + + public fun <QueryUserWrapper : Any> createSelect(initializer: CreateSelect<QueryUserWrapper>): Select<QueryUserWrapper> + + public fun interface CreateInsert<TableUserWrapper : Any, QueryUserWrapper : Any> { + public fun createInsert(table: Table<TableUserWrapper, *>, creator: InsertCreator<TableUserWrapper, QueryUserWrapper>): QueryUserWrapper + } + + public fun <TableUserWrapper : Any, QueryUserWrapper : Any> createInsert(table: Table<TableUserWrapper, *>, initializer: CreateInsert<TableUserWrapper, QueryUserWrapper>): Insert<QueryUserWrapper> + + public fun interface CreateUpdate<TableUserWrapper : Any, QueryUserWrapper : Any> { + public fun createUpdate(table: Table<TableUserWrapper, *>, creator: UpdateCreator<TableUserWrapper, QueryUserWrapper>): QueryUserWrapper + } + + public fun <TableUserWrapper : Any, QueryUserWrapper : Any> createUpdate(table: Table<TableUserWrapper, *>, initializer: CreateUpdate<TableUserWrapper, QueryUserWrapper>): Update<QueryUserWrapper> + + public fun interface CreateDelete<TableUserWrapper : Any, QueryUserWrapper : Any> { + public fun createDelete(table: Table<TableUserWrapper, *>, creator: DeleteCreator<TableUserWrapper, QueryUserWrapper>): QueryUserWrapper + } + + public fun <TableUserWrapper : Any, QueryUserWrapper : Any> createDelete(table: Table<TableUserWrapper, *>, initializer: CreateDelete<TableUserWrapper, QueryUserWrapper>): Delete<QueryUserWrapper> public fun <W : Any> substituteModule(rootNs: Namespace, template: ModuleTemplate<W>): Module<W> public fun <W : Any> upgradeModule(oldModule: Module<*>, rootNs: Namespace, template: ModuleTemplate<W>): Module<W> diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/TableCreator.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/TableCreator.kt index 55a282e..6183c48 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/TableCreator.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/TableCreator.kt @@ -25,9 +25,15 @@ public interface TableCreator<TableUserWrapper : Any> { public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> nullableColumn(name: String, type: DatabaseType): Column<RuntimeType?, DatabaseType, TableUserWrapper> public fun index(name: String, vararg columns: Column<*, *, TableUserWrapper>): Index<TableUserWrapper> + + // todo not-null column uniqueness public fun unique(name: String, distinctNulls: Boolean, vararg columns: Column<*, *, TableUserWrapper>): UniqueConstraint<TableUserWrapper> public fun check(name: String, constraint: Expression<Boolean, ColumnType.BOOLEAN, TableUserWrapper>): CheckConstraint<TableUserWrapper> + public fun rowIdColumn(): Column<RowId<TableUserWrapper>, ColumnType<RowId<TableUserWrapper>>, TableUserWrapper> + + public fun rowIdUniqueConstraint(): UniqueConstraint<TableUserWrapper> + public fun <TargetTableUserWrapper : Any, ColumnType1 : ColumnType<*>> foreignKey( fromColumn: Column<*, ColumnType1, TableUserWrapper>, toTable: Table<TargetTableUserWrapper, *>, diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Delete.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Delete.kt new file mode 100644 index 0000000..0c76949 --- /dev/null +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Delete.kt @@ -0,0 +1,5 @@ +package ru.landgrafhomyak.serdha.api.v0.dml + +public interface Delete<QueryUserWrapper : Any> { + public val userWrapper: QueryUserWrapper +} \ No newline at end of file diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/DeleteCreator.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/DeleteCreator.kt new file mode 100644 index 0000000..d88b943 --- /dev/null +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/DeleteCreator.kt @@ -0,0 +1,16 @@ +package ru.landgrafhomyak.serdha.api.v0.dml + +import ru.landgrafhomyak.serdha.api.v0.Expression +import ru.landgrafhomyak.serdha.api.v0.ddl.Column +import ru.landgrafhomyak.serdha.api.v0.ddl.ColumnType +import ru.landgrafhomyak.serdha.api.v0.ddl.Table + +public interface DeleteCreator<TargetTableUserWrapper : Any, QueryUserWrapper : Any> { + public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> selectColumn(column: Column<RuntimeType, DatabaseType, TargetTableUserWrapper>): SelectedColumn<RuntimeType, DatabaseType, TargetTableUserWrapper, QueryUserWrapper> + + public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> param(name: String, type: DatabaseType): InputParam<RuntimeType, DatabaseType, QueryUserWrapper> + + public fun where(expression: Expression<Boolean, ColumnType.BOOLEAN, QueryUserWrapper>) + + public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> returning(e: Expression<RuntimeType, DatabaseType, QueryUserWrapper>): Column<RuntimeType, DatabaseType, QueryUserWrapper> +} \ No newline at end of file diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/InsertCreator.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/InsertCreator.kt index d628f7c..98248fb 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/InsertCreator.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/InsertCreator.kt @@ -6,7 +6,7 @@ import ru.landgrafhomyak.serdha.api.v0.ddl.ColumnType import ru.landgrafhomyak.serdha.api.v0.ddl.UniqueConstraint public interface InsertCreator<TargetTableUserWrapper : Any, QueryUserWrapper : Any> { - public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> insert(c: Column<RuntimeType, DatabaseType, TargetTableUserWrapper>): InputParam<RuntimeType, DatabaseType, QueryUserWrapper> + public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> insertTo(c: Column<RuntimeType, DatabaseType, TargetTableUserWrapper>): InputParam<RuntimeType, DatabaseType, QueryUserWrapper> public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> selectColumn(c: Column<RuntimeType, DatabaseType, TargetTableUserWrapper>): SelectedColumn<RuntimeType, DatabaseType, TargetTableUserWrapper, QueryUserWrapper> diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectCreator.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectCreator.kt index b9fa2ca..48c3562 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectCreator.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectCreator.kt @@ -8,6 +8,7 @@ import ru.landgrafhomyak.serdha.api.v0.ddl.Table public interface SelectCreator<QueryUserWrapper : Any> { public fun <SelectedTableUserWrapper : Any> selectTable(t: Table<SelectedTableUserWrapper, *>): SelectedTable<SelectedTableUserWrapper, QueryUserWrapper> public fun <SelectedQueryUserWrapper : Any> selectQuery(t: Select<SelectedQueryUserWrapper>): SelectedTable<SelectedQueryUserWrapper, QueryUserWrapper> + public fun where(expression: Expression<Boolean, ColumnType.BOOLEAN, QueryUserWrapper>) // default false @@ -18,4 +19,6 @@ public interface SelectCreator<QueryUserWrapper : Any> { public fun orderBy(vararg columns: Column<*, *, QueryUserWrapper>) public fun groupBy(vararg columns: Column<*, *, QueryUserWrapper>) + + public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> param(name: String, type: DatabaseType): InputParam<RuntimeType, DatabaseType, QueryUserWrapper> } \ No newline at end of file diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectedColumn.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectedColumn.kt index e016a62..95ee139 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectedColumn.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectedColumn.kt @@ -3,6 +3,6 @@ package ru.landgrafhomyak.serdha.api.v0.dml import ru.landgrafhomyak.serdha.api.v0.Expression import ru.landgrafhomyak.serdha.api.v0.ddl.ColumnType -public interface SelectedColumn<RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>, OwnerTypeUserWrapper : Any, QueryUserWrapper : Any> : Expression<RuntimeType, DatabaseType, QueryUserWrapper> { +public interface SelectedColumn<RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>, OwnerTableUserWrapper : Any, QueryUserWrapper : Any> : Expression<RuntimeType, DatabaseType, QueryUserWrapper> { } \ No newline at end of file diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/UpdateCreator.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/UpdateCreator.kt index f092705..5336635 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/UpdateCreator.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/UpdateCreator.kt @@ -3,9 +3,11 @@ package ru.landgrafhomyak.serdha.api.v0.dml import ru.landgrafhomyak.serdha.api.v0.Expression import ru.landgrafhomyak.serdha.api.v0.ddl.Column import ru.landgrafhomyak.serdha.api.v0.ddl.ColumnType +import ru.landgrafhomyak.serdha.api.v0.ddl.Table public interface UpdateCreator<TargetTableUserWrapper : Any, QueryUserWrapper : Any> { - public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> selectColumn(c: Column<RuntimeType, DatabaseType, TargetTableUserWrapper>): SelectedColumn<RuntimeType, DatabaseType, TargetTableUserWrapper, QueryUserWrapper> + public fun <SelectedTableUserWrapper : Any> selectTable(t: Table<SelectedTableUserWrapper, *>): SelectedTable<SelectedTableUserWrapper, QueryUserWrapper> + public fun <SelectedQueryUserWrapper : Any> selectQuery(t: Select<SelectedQueryUserWrapper>): SelectedTable<SelectedQueryUserWrapper, QueryUserWrapper> public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> updateColumn(c: Column<RuntimeType, DatabaseType, TargetTableUserWrapper>, e: Expression<RuntimeType, DatabaseType, QueryUserWrapper>) diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/ParametersSetter.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/ParametersSetter.kt index d947366..c815f76 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/ParametersSetter.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/ParametersSetter.kt @@ -1,18 +1,19 @@ package ru.landgrafhomyak.serdha.api.v0.runtime import ru.landgrafhomyak.serdha.api.v0.ddl.Column +import ru.landgrafhomyak.serdha.api.v0.dml.InputParam public interface ParametersSetter<QueryUserWrapper : Any> { - public operator fun <RuntimeType> set(c: Column<RuntimeType, *, QueryUserWrapper>, value: RuntimeType) + public operator fun <RuntimeType> set(c: InputParam<RuntimeType, *, QueryUserWrapper>, value: RuntimeType) - public operator fun set(c: Column<Byte, *, QueryUserWrapper>, value: Byte): Unit = this.set<Byte>(c, value) - public operator fun set(c: Column<UByte, *, QueryUserWrapper>, value: UByte): Unit = this.set<UByte>(c, value) - public operator fun set(c: Column<Short, *, QueryUserWrapper>, value: Short): Unit = this.set<Short>(c, value) - public operator fun set(c: Column<UShort, *, QueryUserWrapper>, value: UShort): Unit = this.set<UShort>(c, value) - public operator fun set(c: Column<Int, *, QueryUserWrapper>, value: Int): Unit = this.set<Int>(c, value) - public operator fun set(c: Column<UInt, *, QueryUserWrapper>, value: UInt): Unit = this.set<UInt>(c, value) - public operator fun set(c: Column<Long, *, QueryUserWrapper>, value: Long): Unit = this.set<Long>(c, value) - public operator fun set(c: Column<ULong, *, QueryUserWrapper>, value: ULong): Unit = this.set<ULong>(c, value) - public operator fun set(c: Column<Char, *, QueryUserWrapper>, value: Char): Unit = this.set<Char>(c, value) - public operator fun set(c: Column<Boolean, *, QueryUserWrapper>, value: Boolean): Unit = this.set<Boolean>(c, value) + public operator fun set(c: InputParam<Byte, *, QueryUserWrapper>, value: Byte): Unit = this.set<Byte>(c, value) + public operator fun set(c: InputParam<UByte, *, QueryUserWrapper>, value: UByte): Unit = this.set<UByte>(c, value) + public operator fun set(c: InputParam<Short, *, QueryUserWrapper>, value: Short): Unit = this.set<Short>(c, value) + public operator fun set(c: InputParam<UShort, *, QueryUserWrapper>, value: UShort): Unit = this.set<UShort>(c, value) + public operator fun set(c: InputParam<Int, *, QueryUserWrapper>, value: Int): Unit = this.set<Int>(c, value) + public operator fun set(c: InputParam<UInt, *, QueryUserWrapper>, value: UInt): Unit = this.set<UInt>(c, value) + public operator fun set(c: InputParam<Long, *, QueryUserWrapper>, value: Long): Unit = this.set<Long>(c, value) + public operator fun set(c: InputParam<ULong, *, QueryUserWrapper>, value: ULong): Unit = this.set<ULong>(c, value) + public operator fun set(c: InputParam<Char, *, QueryUserWrapper>, value: Char): Unit = this.set<Char>(c, value) + public operator fun set(c: InputParam<Boolean, *, QueryUserWrapper>, value: Boolean): Unit = this.set<Boolean>(c, value) } \ No newline at end of file diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/SynchronizedDatabase.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/SynchronizedDatabase.kt index 98e71a7..f2da287 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/SynchronizedDatabase.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/SynchronizedDatabase.kt @@ -2,12 +2,38 @@ package ru.landgrafhomyak.serdha.api.v0.runtime import ru.landgrafhomyak.serdha.api.v0.LowLevelApi import ru.landgrafhomyak.serdha.api.v0.ddl.Module +import ru.landgrafhomyak.serdha.api.v0.dml.Delete +import ru.landgrafhomyak.serdha.api.v0.dml.Insert +import ru.landgrafhomyak.serdha.api.v0.dml.Select +import ru.landgrafhomyak.serdha.api.v0.dml.Update public interface SynchronizedDatabase<W : Any> : Module<W> { @Suppress("FunctionName") @LowLevelApi public suspend fun _startTransaction(): Transaction + @Suppress("FunctionName") + @LowLevelApi + public suspend fun <QueryUserWrapper : Any> _startAutoTransactedSelect(query: Select<QueryUserWrapper>): _ParametersSetter<QueryUserWrapper, _ResultSet<QueryUserWrapper>> + + @Suppress("FunctionName") + @LowLevelApi + public suspend fun <QueryUserWrapper : Any> _startAutoTransactedInsert(query: Insert<QueryUserWrapper>): _ParametersSetter<QueryUserWrapper, _ResultSet<QueryUserWrapper>?> + + @Suppress("FunctionName") + @LowLevelApi + public suspend fun <QueryUserWrapper : Any> _startAutoTransactedUpdate(query: Update<QueryUserWrapper>): _ParametersSetter<QueryUserWrapper, _ResultSet<QueryUserWrapper>?> + + @Suppress("FunctionName") + @LowLevelApi + public suspend fun <QueryUserWrapper : Any> _startAutoTransactedDelete(query: Delete<QueryUserWrapper>): _ParametersSetter<QueryUserWrapper, _ResultSet<QueryUserWrapper>?> + + public interface AtomicScript<C, A, R> { + public suspend fun executeTransaction(transaction: Transaction, context: C, args: A): R + } + + public suspend fun <C, A, R> transaction(script: AtomicScript<C, A, R>, context: C, args: A): R + @Suppress("FunctionName") @LowLevelApi public suspend fun _close() diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/Transaction.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/Transaction.kt index 07250cf..d76e4f3 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/Transaction.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/Transaction.kt @@ -1,6 +1,7 @@ package ru.landgrafhomyak.serdha.api.v0.runtime import ru.landgrafhomyak.serdha.api.v0.LowLevelApi +import ru.landgrafhomyak.serdha.api.v0.dml.Delete import ru.landgrafhomyak.serdha.api.v0.dml.Insert import ru.landgrafhomyak.serdha.api.v0.dml.Select import ru.landgrafhomyak.serdha.api.v0.dml.Update @@ -18,6 +19,10 @@ public interface Transaction { @LowLevelApi public fun <QueryUserWrapper : Any> _update(compiledQuery: Update<QueryUserWrapper>): _ParametersSetter<QueryUserWrapper, _ResultSet<QueryUserWrapper>?> + @Suppress("FunctionName") + @LowLevelApi + public fun <QueryUserWrapper : Any> _delete(compiledQuery: Delete<QueryUserWrapper>): _ParametersSetter<QueryUserWrapper, _ResultSet<QueryUserWrapper>?> + public suspend fun rollback() public suspend fun commit() diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/transaction_methods.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/transaction_methods.kt index d62f3be..cd8843e 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/transaction_methods.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/runtime/transaction_methods.kt @@ -6,6 +6,7 @@ import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.jvm.JvmName import ru.landgrafhomyak.serdha.api.v0.LowLevelApi +import ru.landgrafhomyak.serdha.api.v0.dml.Delete import ru.landgrafhomyak.serdha.api.v0.dml.Insert import ru.landgrafhomyak.serdha.api.v0.dml.Select import ru.landgrafhomyak.serdha.api.v0.dml.Update @@ -166,6 +167,26 @@ internal suspend inline fun <Q : Any, R> _wrapWithLambdasMap( } +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any, R> SynchronizedDatabase<*>.autoTransactedSelectSingleOrNull( + compiledQuery: Select<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit = {}, + rowsConsumer: (Row<QueryUserWrapper>) -> R +): R? { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.AT_MOST_ONCE) + } + return _wrapWithLambdasSingleOrNull( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedSelect(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + @OptIn(LowLevelApi::class) public suspend inline fun <QueryUserWrapper : Any, R> Transaction.selectSingleOrNull( compiledQuery: Select<QueryUserWrapper>, @@ -186,6 +207,7 @@ public suspend inline fun <QueryUserWrapper : Any, R> Transaction.selectSingleOr ) } + @OptIn(LowLevelApi::class) public suspend inline fun <QueryUserWrapper : Any> Transaction.selectThenIterate( compiledQuery: Select<QueryUserWrapper>, @@ -206,6 +228,26 @@ public suspend inline fun <QueryUserWrapper : Any> Transaction.selectThenIterate ) } +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any> SynchronizedDatabase<*>.autoTransactedSelectThenIterate( + compiledQuery: Select<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit, + rowsConsumer: (Row<QueryUserWrapper>) -> Unit +) { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.UNKNOWN) + } + _wrapWithLambdasIterate( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedSelect(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + @OptIn(LowLevelApi::class) public suspend inline fun <QueryUserWrapper : Any, R> Transaction.selectThenMap( compiledQuery: Select<QueryUserWrapper>, @@ -227,6 +269,27 @@ public suspend inline fun <QueryUserWrapper : Any, R> Transaction.selectThenMap( } +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any, R> SynchronizedDatabase<*>.autoTransactedSelectThenMap( + compiledQuery: Select<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit, + rowsConsumer: (Row<QueryUserWrapper>) -> R +): List<R> { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.UNKNOWN) + } + return _wrapWithLambdasMap( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedSelect(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + + @OptIn(LowLevelApi::class) public suspend inline fun <QueryUserWrapper : Any> Transaction.insert( compiledQuery: Insert<QueryUserWrapper>, @@ -245,6 +308,24 @@ public suspend inline fun <QueryUserWrapper : Any> Transaction.insert( ) } +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any> SynchronizedDatabase<*>.autoTransactedInsert( + compiledQuery: Insert<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit = {}, +) { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + } + _wrapWithLambdas( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedInsert(compiledQuery) }, + parameters = parameters, + hasReturning = false, + returning = {}, + "" + ) +} + @OptIn(LowLevelApi::class) public suspend inline fun <QueryUserWrapper : Any, R> Transaction.insertReturningSingleOrNull( compiledQuery: Insert<QueryUserWrapper>, @@ -265,6 +346,26 @@ public suspend inline fun <QueryUserWrapper : Any, R> Transaction.insertReturnin ) } +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any, R> SynchronizedDatabase<*>.autoTransactedInsertReturningSingleOrNull( + compiledQuery: Insert<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit = {}, + rowsConsumer: (Row<QueryUserWrapper>) -> R +): R? { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.AT_MOST_ONCE) + } + return _wrapWithLambdasSingleOrNull( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedInsert(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + @OptIn(LowLevelApi::class) public suspend inline fun <QueryUserWrapper : Any> Transaction.insertReturningIterate( compiledQuery: Insert<QueryUserWrapper>, @@ -285,6 +386,26 @@ public suspend inline fun <QueryUserWrapper : Any> Transaction.insertReturningIt ) } +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any> SynchronizedDatabase<*>.autoTransactedInsertReturningIterate( + compiledQuery: Insert<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit, + rowsConsumer: (Row<QueryUserWrapper>) -> Unit +) { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.UNKNOWN) + } + _wrapWithLambdasIterate( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedInsert(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + @OptIn(LowLevelApi::class) public suspend inline fun <QueryUserWrapper : Any, R> Transaction.insertReturningMap( compiledQuery: Insert<QueryUserWrapper>, @@ -305,6 +426,26 @@ public suspend inline fun <QueryUserWrapper : Any, R> Transaction.insertReturnin ) } +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any, R> SynchronizedDatabase<*>.autoTransactedInsertReturningMap( + compiledQuery: Insert<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit, + rowsConsumer: (Row<QueryUserWrapper>) -> R +): List<R> { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.UNKNOWN) + } + return _wrapWithLambdasMap( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedInsert(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + @OptIn(LowLevelApi::class) public suspend inline fun <QueryUserWrapper : Any> Transaction.update( compiledQuery: Update<QueryUserWrapper>, @@ -323,6 +464,24 @@ public suspend inline fun <QueryUserWrapper : Any> Transaction.update( ) } +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any> SynchronizedDatabase<*>.autoTransactedUpdate( + compiledQuery: Update<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit = {}, +) { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + } + _wrapWithLambdas( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedUpdate(compiledQuery) }, + parameters = parameters, + hasReturning = false, + returning = {}, + "" + ) +} + @OptIn(LowLevelApi::class) public suspend inline fun <QueryUserWrapper : Any, R> Transaction.updateReturningSingleOrNull( compiledQuery: Update<QueryUserWrapper>, @@ -343,6 +502,27 @@ public suspend inline fun <QueryUserWrapper : Any, R> Transaction.updateReturnin ) } + +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any, R> SynchronizedDatabase<*>.autoTransactedUpdateReturningSingleOrNull( + compiledQuery: Update<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit = {}, + rowsConsumer: (Row<QueryUserWrapper>) -> R +): R? { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.AT_MOST_ONCE) + } + return _wrapWithLambdasSingleOrNull( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedUpdate(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + @OptIn(LowLevelApi::class) public suspend inline fun <QueryUserWrapper : Any> Transaction.updateReturningIterate( compiledQuery: Update<QueryUserWrapper>, @@ -363,6 +543,26 @@ public suspend inline fun <QueryUserWrapper : Any> Transaction.updateReturningIt ) } +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any> SynchronizedDatabase<*>.autoTransactedUpdateReturningIterate( + compiledQuery: Update<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit, + rowsConsumer: (Row<QueryUserWrapper>) -> Unit +) { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.UNKNOWN) + } + _wrapWithLambdasIterate( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedUpdate(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + @OptIn(LowLevelApi::class) public suspend inline fun <QueryUserWrapper : Any, R> Transaction.updateReturningMap( compiledQuery: Update<QueryUserWrapper>, @@ -384,7 +584,184 @@ public suspend inline fun <QueryUserWrapper : Any, R> Transaction.updateReturnin } @OptIn(LowLevelApi::class) -public suspend fun <R> SynchronizedDatabase<*>.transaction(body: (Transaction) -> R):R { +public suspend inline fun <QueryUserWrapper : Any, R> SynchronizedDatabase<*>.autoTransactedUpdateReturningMap( + compiledQuery: Update<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit, + rowsConsumer: (Row<QueryUserWrapper>) -> R +): List<R> { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.UNKNOWN) + } + return _wrapWithLambdasMap( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedUpdate(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any> Transaction.delete( + compiledQuery: Delete<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit = {}, +) { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + } + _wrapWithLambdas( + compiledQuery = compiledQuery, + queryGetter = { this._delete(compiledQuery) }, + parameters = parameters, + hasReturning = false, + returning = {}, + "" + ) +} + +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any> SynchronizedDatabase<*>.autoTransactedDelete( + compiledQuery: Delete<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit = {}, +) { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + } + _wrapWithLambdas( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedDelete(compiledQuery) }, + parameters = parameters, + hasReturning = false, + returning = {}, + "" + ) +} + +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any, R> Transaction.deleteReturningSingleOrNull( + compiledQuery: Delete<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit = {}, + rowsConsumer: (Row<QueryUserWrapper>) -> R +): R? { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.AT_MOST_ONCE) + } + return _wrapWithLambdasSingleOrNull( + compiledQuery = compiledQuery, + queryGetter = { this._delete(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + + +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any, R> SynchronizedDatabase<*>.autoTransactedDeleteReturningSingleOrNull( + compiledQuery: Delete<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit = {}, + rowsConsumer: (Row<QueryUserWrapper>) -> R +): R? { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.AT_MOST_ONCE) + } + return _wrapWithLambdasSingleOrNull( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedDelete(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any> Transaction.deleteReturningIterate( + compiledQuery: Delete<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit, + rowsConsumer: (Row<QueryUserWrapper>) -> Unit +) { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.UNKNOWN) + } + _wrapWithLambdasIterate( + compiledQuery = compiledQuery, + queryGetter = { this._delete(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any> SynchronizedDatabase<*>.autoTransactedDeleteReturningIterate( + compiledQuery: Delete<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit, + rowsConsumer: (Row<QueryUserWrapper>) -> Unit +) { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.UNKNOWN) + } + _wrapWithLambdasIterate( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedDelete(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any, R> Transaction.deleteReturningMap( + compiledQuery: Delete<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit, + rowsConsumer: (Row<QueryUserWrapper>) -> R +): List<R> { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.UNKNOWN) + } + return _wrapWithLambdasMap( + compiledQuery = compiledQuery, + queryGetter = { this._delete(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + +@OptIn(LowLevelApi::class) +public suspend inline fun <QueryUserWrapper : Any, R> SynchronizedDatabase<*>.autoTransactedDeleteReturningMap( + compiledQuery: Delete<QueryUserWrapper>, + parameters: (ParametersSetter<QueryUserWrapper>) -> Unit, + rowsConsumer: (Row<QueryUserWrapper>) -> R +): List<R> { + contract { + callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) + callsInPlace(rowsConsumer, InvocationKind.UNKNOWN) + } + return _wrapWithLambdasMap( + compiledQuery = compiledQuery, + queryGetter = { this._startAutoTransactedDelete(compiledQuery) }, + parameters = parameters, + hasReturning = true, + returning = rowsConsumer, + "" + ) +} + +@OptIn(LowLevelApi::class) +public suspend fun <R> SynchronizedDatabase<*>.transaction(body: (Transaction) -> R): R { contract { callsInPlace(body, InvocationKind.EXACTLY_ONCE) }