From 850f6cebf1d9f083eba48ca67f86461dae0c6486 Mon Sep 17 00:00:00 2001
From: Andrew Golovashevich <landgrafhomyak@gmail.com>
Date: Sat, 21 Dec 2024 21:54:25 +0300
Subject: [PATCH] Sub-querying inserts and separated schema and data
 manipulations at sync time

---
 .../serdha/api/v0/ddl/ModuleCreator.kt        |  3 +-
 .../serdha/api/v0/ddl/ModuleTemplate.kt       | 12 +++++--
 .../serdha/api/v0/dml/_CommonQueryMethods.kt  | 36 ++++++++++++++++++-
 3 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ModuleCreator.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ModuleCreator.kt
index a4e08ca..8aef13f 100644
--- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ModuleCreator.kt
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ModuleCreator.kt
@@ -8,9 +8,8 @@ import ru.landgrafhomyak.serdha.api.v0.dml.Select
 import ru.landgrafhomyak.serdha.api.v0.dml.SelectCreator
 import ru.landgrafhomyak.serdha.api.v0.dml.Update
 import ru.landgrafhomyak.serdha.api.v0.dml.UpdateCreator
-import ru.landgrafhomyak.serdha.api.v0.runtime.Transaction
 
-public interface ModuleCreator : Transaction {
+public interface ModuleCreator {
 	public interface CreateTable<TableUserExtension : Any> {
 		public fun createTable(creator: TableCreator<TableUserExtension>): TableUserExtension
 	}
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ModuleTemplate.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ModuleTemplate.kt
index 7327918..8a9f71b 100644
--- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ModuleTemplate.kt
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ModuleTemplate.kt
@@ -1,5 +1,7 @@
 package ru.landgrafhomyak.serdha.api.v0.ddl
 
+import ru.landgrafhomyak.serdha.api.v0.runtime.Transaction
+
 public interface ModuleTemplate<ModuleUserExtension : Any> {
 	public interface Creator {
 		public fun <NewModuleUserExtension : Any> createTemplate(
@@ -14,11 +16,17 @@ public interface ModuleTemplate<ModuleUserExtension : Any> {
 	}
 
 	public interface CreateModule<ModuleUserExtension : Any> {
-		public suspend fun createModule(rootNs: Namespace, creator: ModuleCreator): ModuleUserExtension
+		public fun createSchema(rootNs: Namespace, creator: ModuleCreator): ModuleUserExtension
+
+		public suspend fun initData(ext: ModuleUserExtension, transaction: Transaction) {}
 	}
 
 	public interface UpgradeModule<OldModuleUserExtension : Any, NewModuleUserExtension : Any> {
-		public suspend fun upgradeModule(oldModule: Module<OldModuleUserExtension>, rootNs: Namespace, updater: ModuleCreator): NewModuleUserExtension
+		public fun upgradeSchema(oldModule: Module<OldModuleUserExtension>, rootNs: Namespace, updater: ModuleCreator): NewModuleUserExtension
+
+		public suspend fun upgradeData(ext: NewModuleUserExtension, transaction: Transaction) {}
+
+		public fun postUpgradeCleanupSchema(ext: NewModuleUserExtension, updater: ModuleCreator) {}
 	}
 
 	public val versionKey: String
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/_CommonQueryMethods.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/_CommonQueryMethods.kt
index daac7a9..06d11f9 100644
--- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/_CommonQueryMethods.kt
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/_CommonQueryMethods.kt
@@ -1,10 +1,12 @@
 package ru.landgrafhomyak.serdha.api.v0.dml
 
 import ru.landgrafhomyak.serdha.api.v0.Expression
+import ru.landgrafhomyak.serdha.api.v0.LowLevelApi
 import ru.landgrafhomyak.serdha.api.v0.ddl.Column
 import ru.landgrafhomyak.serdha.api.v0.ddl.ColumnType
 import ru.landgrafhomyak.serdha.api.v0.ddl.Table
 import ru.landgrafhomyak.serdha.api.v0.runtime.ParametersSetter
+import ru.landgrafhomyak.serdha.api.v0.runtime._ParametersSetter
 
 @Suppress("ClassName")
 public interface _CommonQueryMethods<QueryUserExtension : Any> {
@@ -18,7 +20,39 @@ public interface _CommonQueryMethods<QueryUserExtension : Any> {
 		public operator fun <RuntimeType, DatabaseType : ColumnType<RuntimeType>> set(c: InputParam<RuntimeType, DatabaseType, QueryUserExtension>, value: Expression<RuntimeType, DatabaseType, QueryUserExtension>)
 	}
 
-	public fun <SubqueryUserExtension : Any> selectingQuery(q: CanBeSubquery<SubqueryUserExtension>, p: (SubqueryParametersSetter<SubqueryUserExtension, QueryUserExtension>) -> Unit): SelectedTable<SubqueryUserExtension, QueryUserExtension>
+	public fun <SubqueryUserExtension : Any> selectQuery(q: CanBeSubquery<SubqueryUserExtension>, p: (SubqueryParametersSetter<SubqueryUserExtension, QueryUserExtension>) -> Unit): SelectedTable<SubqueryUserExtension, QueryUserExtension>
+
+	public class SelectedInsert<SubqueryUserExtension : Any, QueryUserExtension : Any>(
+		public val inserted: SelectedTable<SubqueryUserExtension, QueryUserExtension>,
+		public val updated: SelectedTable<SubqueryUserExtension, QueryUserExtension>
+	)
+
+	public fun <SubqueryUserExtension : Any> selectInsert(q: Insert.InsertParams<SubqueryUserExtension>, p: (SubqueryParametersSetter<SubqueryUserExtension, QueryUserExtension>) -> Unit): SelectedInsert<SubqueryUserExtension, QueryUserExtension>
+
+	@Suppress("FunctionName")
+	@LowLevelApi
+	public fun <SubqueryUserExtension : Any> _selectInsert(
+		q: Insert.InsertFromQuery<SubqueryUserExtension>,
+		p: (SubqueryParametersSetter<SubqueryUserExtension, QueryUserExtension>) -> Unit,
+		r: (_ParametersSetter._Multi<InsertCreator.InsertParams.DataParam<SubqueryUserExtension>, Nothing>) -> Unit
+	): SelectedInsert<SubqueryUserExtension, QueryUserExtension>
+
+	@OptIn(LowLevelApi::class)
+	public fun <SubqueryUserExtension : Any> selectInsertOne(
+		q: Insert.InsertFromQuery<SubqueryUserExtension>,
+		p: (SubqueryParametersSetter<SubqueryUserExtension, QueryUserExtension>) -> Unit,
+		r: (ParametersSetter<InsertCreator.InsertParams.DataParam<SubqueryUserExtension>>) -> Unit
+	): SelectedInsert<SubqueryUserExtension, QueryUserExtension> =
+		this._selectInsert(q, p, r)
+
+	@OptIn(LowLevelApi::class)
+	public fun <SubqueryUserExtension : Any, T> selectInsertMulti(
+		q: Insert.InsertFromQuery<SubqueryUserExtension>,
+		p: (SubqueryParametersSetter<SubqueryUserExtension, QueryUserExtension>) -> Unit,
+		data: Iterable<T>,
+		r: (T, ParametersSetter<InsertCreator.InsertParams.DataParam<SubqueryUserExtension>>) -> Unit
+	): SelectedInsert<SubqueryUserExtension, QueryUserExtension> =
+		this._selectInsert(q, p) { rr -> for (e in data) r(e, rr) }
 
 	public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType>> param(name: String, type: DatabaseType): InputParam<RuntimeType, DatabaseType, QueryUserExtension>