From 3607030a87fe80af5e4bbabf793fe58a4be17853 Mon Sep 17 00:00:00 2001
From: Andrew Golovashevich <landgrafhomyak@gmail.com>
Date: Thu, 2 Jan 2025 02:09:27 +0300
Subject: [PATCH] Changing ForeignKey to ForeignRowReference

---
 .../serdha/api/v0/ddl/ColumnType.kt           |   5 +-
 .../serdha/api/v0/ddl/ForeignKey.kt           | 118 ------------------
 .../serdha/api/v0/ddl/ForeignRowReference.kt  |  63 ++++++++++
 .../serdha/api/v0/ddl/TableCreator.kt         |  68 ++--------
 .../serdha/api/v0/ddl/TableUpdater.kt         |  41 +++---
 5 files changed, 95 insertions(+), 200 deletions(-)
 delete mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ForeignKey.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ForeignRowReference.kt

diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ColumnType.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ColumnType.kt
index 07fdea6..ab81c80 100644
--- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ColumnType.kt
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ColumnType.kt
@@ -28,6 +28,8 @@ public interface ColumnType<@Suppress("unused") RuntimeType> {
 	public interface Builder {
 		/**
 		 * Type of internal row id. Can't be casted to types like integers or pointers.
+		 * @param TableUserExtension User's extension type for target table. For static type checking.
+		 * @param table Descriptor of table whose row_id type will be obtained.
 		 */
 		@Suppress("INAPPLICABLE_JVM_NAME")
 		@JvmName("ROW_ID")
@@ -172,9 +174,10 @@ public interface ColumnType<@Suppress("unused") RuntimeType> {
 
 	/**
 	 * Descriptor of an internal row id type for static type-checking.
+	 * @param TargetTableUserWrapper  User's extension type for target table. For static type checking.
 	 * @see ColumnType.Builder.ROW_ID
 	 */
-	public interface ROW_ID : ColumnType<RowId<*>>
+	public interface ROW_ID<TargetTableUserWrapper: Any> : ColumnType<RowId<TargetTableUserWrapper>>
 
 	/**
 	 * Descriptor of a boolean type for static type-checking.
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ForeignKey.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ForeignKey.kt
deleted file mode 100644
index ede502a..0000000
--- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ForeignKey.kt
+++ /dev/null
@@ -1,118 +0,0 @@
-package ru.landgrafhomyak.serdha.api.v0.ddl
-
-import kotlin.jvm.JvmName
-import kotlin.jvm.JvmStatic
-
-/**
- * Descriptor of a foreign key. Used for schema manipulations.
- *
- * @param ContainerTableUserExtension Type of [owner table's][ForeignKey.fromTable] user expression for static reporting errors when this descriptor passed to wrong table.
- * @param TargetTableUserExtension Type of [target table's][ForeignKey.toTable] user expression for static reporting errors when this descriptor passed to wrong table.
- */
-public interface ForeignKey<ContainerTableUserExtension : Any, TargetTableUserExtension : Any> {
-	/**
-	 * Table that contains this foreign key. For debugging.
-	 */
-	@Suppress("INAPPLICABLE_JVM_NAME")
-	@get:JvmName("fromTable")
-	public val fromTable: Table<ContainerTableUserExtension, *>
-
-	/**
-	 * Columns in [ForeignKey.fromTable] which are used to reference row in [ForeignKey.toTable]. For debugging.
-	 */
-	@Suppress("INAPPLICABLE_JVM_NAME")
-	@get:JvmName("fromColumns")
-	public val fromColumns: List<Column<*, *, ContainerTableUserExtension>>
-
-	/**
-	 * Table referenced by this foreign key. For debugging.
-	 */
-	@Suppress("INAPPLICABLE_JVM_NAME")
-	@get:JvmName("toTable")
-	public val toTable: Table<TargetTableUserExtension, *>
-
-	/**
-	 * Columns in [ForeignKey.toTable] that are identifying row(s). For debugging.
-	 */
-	@Suppress("INAPPLICABLE_JVM_NAME")
-	@get:JvmName("toColumns")
-	public val toColumns: List<Column<*, *, TargetTableUserExtension>>
-
-	/**
-	 * Enum of actions to do when value in any of [ForeignKey.toColumns] in referenced row is changed.
-	 */
-	public enum class OnUpdateAction {
-		/**
-		 * Don't perform any actions in [ForeignKey.fromColumns]. May break reference.
-		 */
-		NO_ACTION,
-
-		/**
-		 * Forbids changing values in [ForeignKey.toColumns] if there is at least one reference from [ForeignKey.fromTable].
-		 */
-		RESTRICT,
-
-		/**
-		 * Sets `null` value to all columns in [ForeignKey.fromColumns] if any cell in [ForeignKey.toColumns] in referenced row was changed.
-		 *
-		 * All of [ForeignKey.fromColumns] must be nullable.
-		 */
-		SET_NULL,
-
-		/**
-		 * Sets default value to all columns in [ForeignKey.fromColumns] if any cell in [ForeignKey.toColumns] in referenced row was changed.
-		 *
-		 * All of [ForeignKey.fromColumns] must have [DefaultConstraint].
-		 */
-		SET_DEFAULT,
-
-		/**
-		 * Reflects all changes from [ForeignKey.toColumns] to [ForeignKey.fromColumns].
-		 */
-		CASCADE
-	}
-
-	/**
-	 * Enum of actions to do when referenced row in [ForeignKey.toTable] deleted.
-	 */
-	public enum class OnDeleteAction {
-		/**
-		 * Don't perform any actions in [ForeignKey.fromColumns]. Breaks reference.
-		 */
-		NO_ACTION,
-
-		/**
-		 * Forbids deleting row in [ForeignKey.toTable] if there is at least one reference from [ForeignKey.fromTable].
-		 */
-		RESTRICT,
-
-		/**
-		 * Sets `null` value to all columns in [ForeignKey.fromColumns] if referenced row was deleted.
-		 *
-		 * All of [ForeignKey.fromColumns] must be nullable.
-		 */
-		SET_NULL,
-
-		/**
-		 * Sets default value to all columns in [ForeignKey.fromColumns] if referenced row was deleted.
-		 *
-		 * All of [ForeignKey.fromColumns] must have [DefaultConstraint].
-		 */
-		SET_DEFAULT,
-
-		/**
-		 * Deletes all rows in [ForeignKey.fromTable] that are referencing deleted row in [ForeignKey.toTable].
-		 */
-		CASCADE
-	}
-
-	public companion object {
-		@JvmStatic
-		public val DEFAULT_ON_UPDATE_ACTION: OnUpdateAction
-			inline get() = OnUpdateAction.CASCADE
-
-		@JvmStatic
-		public val DEFAULT_ON_DELETE_ACTION: OnDeleteAction
-			inline get() = OnDeleteAction.RESTRICT
-	}
-}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ForeignRowReference.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ForeignRowReference.kt
new file mode 100644
index 0000000..a7d72a7
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ForeignRowReference.kt
@@ -0,0 +1,63 @@
+package ru.landgrafhomyak.serdha.api.v0.ddl
+
+import kotlin.jvm.JvmName
+import kotlin.jvm.JvmStatic
+
+/**
+ * Descriptor of a reference to row in another table (== foreign key to `INTEGER PRIMARY KEY AUTOINCREMENT`). Used for schema manipulations.
+ *
+ * @param ContainerTableUserExtension Type of [owner table's][ForeignRowReference.fromTable] user expression for static reporting errors when this descriptor passed to wrong table.
+ * @param TargetTableUserExtension Type of [target table's][ForeignRowReference.toTable] user expression for static reporting errors when this descriptor passed to wrong table.
+ */
+public interface ForeignRowReference<ContainerTableUserExtension : Any, TargetTableUserExtension : Any> {
+	/**
+	 * Table that contains references. For debugging.
+	 */
+	@Suppress("INAPPLICABLE_JVM_NAME")
+	@get:JvmName("fromTable")
+	public val fromTable: Table<ContainerTableUserExtension, *>
+
+	/**
+	 * Column in [ForeignRowReference.fromTable] which references row in [ForeignRowReference.toTable]. For debugging.
+	 */
+	@Suppress("INAPPLICABLE_JVM_NAME")
+	@get:JvmName("fromColumn")
+	public val fromColumn: Column<RowId<TargetTableUserExtension>, ColumnType.ROW_ID<TargetTableUserExtension>, ContainerTableUserExtension>
+
+	/**
+	 * Table referenced by this foreign key. For debugging.
+	 */
+	@Suppress("INAPPLICABLE_JVM_NAME")
+	@get:JvmName("toTable")
+	public val toTable: Table<TargetTableUserExtension, *>
+
+	/**
+	 * Row id column in [ForeignRowReference.toTable]. For debugging.
+	 */
+	@Suppress("INAPPLICABLE_JVM_NAME")
+	@get:JvmName("toColumn")
+	public val toColumn: Column<RowId<TargetTableUserExtension>, ColumnType.ROW_ID<TargetTableUserExtension>, TargetTableUserExtension>
+
+
+	/**
+	 * Enum of actions to do when referenced row in [ForeignRowReference.toTable] deleted.
+	 */
+	public enum class OnDeleteAction {
+		/**
+		 * Forbids deleting row in [ForeignRowReference.toTable] if there is at least one reference from [ForeignRowReference.fromTable].
+		 */
+		RESTRICT,
+
+		/**
+		 * Replaces all references to deleted row in [ForeignRowReference.fromColumn] with `null`.
+		 *
+		 * Type of [ForeignRowReference.fromColumn] must be [nullable][ColumnType.Builder.nullableOf].
+		 */
+		SET_NULL,
+
+		/**
+		 * Deletes all rows in [ForeignRowReference.fromTable] that are referencing deleted row in [ForeignRowReference.toTable].
+		 */
+		CASCADE
+	}
+}
\ No newline at end of file
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 8644598..5d51bee 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
@@ -1,7 +1,6 @@
 package ru.landgrafhomyak.serdha.api.v0.ddl
 
 import ru.landgrafhomyak.serdha.api.v0.Expression
-import ru.landgrafhomyak.serdha.api.v0.LowLevelApi
 
 public interface TableCreator<TableUserExtension : Any> {
 	public val expressionBuilder: Expression.Builder<TableUserExtension>
@@ -22,64 +21,15 @@ public interface TableCreator<TableUserExtension : Any> {
 	@Suppress("PropertyName")
 	public val rowId_uniqueConstraint: UniqueIndex<TableUserExtension>
 
-	@Suppress("FunctionName")
-	@LowLevelApi
-	public fun <TargetTableUserWrapper : Any> _foreignKey(
-		fromColumns: Array<Column<*, *, TableUserExtension>>,
-		toTable: Table<TargetTableUserWrapper, *>,
-		toColumns: Array<Column<*, *, TargetTableUserWrapper>>,
-		onUpdate: ForeignKey.OnUpdateAction,
-		onDelete: ForeignKey.OnDeleteAction,
-	): ForeignKey<TableUserExtension, TargetTableUserWrapper>
+	public fun <TargetTableUserWrapper : Any> selfRowReference(
+		onDelete: ForeignRowReference.OnDeleteAction,
+		toColumn: Column<RowId<TargetTableUserWrapper>, ColumnType.ROW_ID<TargetTableUserWrapper>, TargetTableUserWrapper>,
+	): ForeignRowReference<TableUserExtension, TableUserExtension>
 
-	@OptIn(LowLevelApi::class)
-	public fun <TargetTableUserWrapper : Any, ColumnType1 : ColumnType<*>> foreignKey(
-		fromColumn: Column<*, ColumnType1, TableUserExtension>,
+	public fun <TargetTableUserWrapper : Any> foreignRowReference(
+		fromColumn: Column<RowId<TargetTableUserWrapper>, ColumnType.ROW_ID<TargetTableUserWrapper>, TableUserExtension>,
 		toTable: Table<TargetTableUserWrapper, *>,
-		toColumn: Column<*, ColumnType1, TargetTableUserWrapper>,
-		onUpdate: ForeignKey.OnUpdateAction,
-		onDelete: ForeignKey.OnDeleteAction,
-	): ForeignKey<TableUserExtension, TargetTableUserWrapper> = this._foreignKey(
-		fromColumns = arrayOf(fromColumn),
-		toTable = toTable,
-		toColumns = arrayOf(toColumn),
-		onUpdate = onUpdate,
-		onDelete = onDelete
-	)
-
-	@OptIn(LowLevelApi::class)
-	public fun <TargetTableUserWrapper : Any, ColumnType1 : ColumnType<*>, ColumnType2 : ColumnType<*>> foreignKey(
-		fromColumn1: Column<*, ColumnType1, TableUserExtension>,
-		fromColumn2: Column<*, ColumnType2, TableUserExtension>,
-		toTable: Table<TargetTableUserWrapper, *>,
-		toColumn1: Column<*, ColumnType1, TargetTableUserWrapper>,
-		toColumn2: Column<*, ColumnType2, TargetTableUserWrapper>,
-		onUpdate: ForeignKey.OnUpdateAction,
-		onDelete: ForeignKey.OnDeleteAction,
-	): ForeignKey<TableUserExtension, TargetTableUserWrapper> = this._foreignKey(
-		fromColumns = arrayOf(fromColumn1, fromColumn2),
-		toTable = toTable,
-		toColumns = arrayOf(toColumn1, toColumn2),
-		onUpdate = onUpdate,
-		onDelete = onDelete
-	)
-
-	@OptIn(LowLevelApi::class)
-	public fun <TargetTableUserWrapper : Any, ColumnType1 : ColumnType<*>, ColumnType2 : ColumnType<*>, ColumnType3 : ColumnType<*>> foreignKey(
-		fromColumn1: Column<*, ColumnType1, TableUserExtension>,
-		fromColumn2: Column<*, ColumnType2, TableUserExtension>,
-		fromColumn3: Column<*, ColumnType3, TableUserExtension>,
-		toTable: Table<TargetTableUserWrapper, *>,
-		toColumn1: Column<*, ColumnType1, TargetTableUserWrapper>,
-		toColumn2: Column<*, ColumnType2, TargetTableUserWrapper>,
-		toColumn3: Column<*, ColumnType3, TargetTableUserWrapper>,
-		onUpdate: ForeignKey.OnUpdateAction,
-		onDelete: ForeignKey.OnDeleteAction,
-	): ForeignKey<TableUserExtension, TargetTableUserWrapper> = this._foreignKey(
-		fromColumns = arrayOf(fromColumn1, fromColumn2, fromColumn3),
-		toTable = toTable,
-		toColumns = arrayOf(toColumn1, toColumn2, toColumn3),
-		onUpdate = onUpdate,
-		onDelete = onDelete
-	)
+		toColumn: Column<RowId<TargetTableUserWrapper>, ColumnType.ROW_ID<TargetTableUserWrapper>, TargetTableUserWrapper>,
+		onDelete: ForeignRowReference.OnDeleteAction,
+	): ForeignRowReference<TableUserExtension, TargetTableUserWrapper>
 }
\ No newline at end of file
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/TableUpdater.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/TableUpdater.kt
index edb67b0..0e612f8 100644
--- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/TableUpdater.kt
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/TableUpdater.kt
@@ -30,31 +30,28 @@ public interface TableUpdater<TableNewUserExtension : Any, TableOldUserExtension
 	public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType>> changeDefaultValue(c: Column<RuntimeType, DatabaseType, TableNewUserExtension>, d: DefaultConstraint<*, *, TableOldUserExtension>): DefaultConstraint<RuntimeType, DatabaseType, TableNewUserExtension>
 	public fun deleteDefaultValue(i: DefaultConstraint<*, *, TableOldUserExtension>)
 
-	public fun <TargetTableOldUserWrapper : Any, TargetTableNewUserWrapper : Any> keepForeignKeyToUpdatedTable(
-		fk: ForeignKey<TableOldUserExtension, TargetTableOldUserWrapper>,
+	public fun <TargetTableUserWrapper : Any> keepForeignRowReference(
+		frr: ForeignRowReference<TableOldUserExtension, TargetTableUserWrapper>,
+		onDelete: ForeignRowReference.OnDeleteAction? = null
+	): ForeignRowReference<TableNewUserExtension, TargetTableUserWrapper>
+
+	public fun <TargetTableOldUserWrapper : Any, TargetTableNewUserWrapper : Any> keepForeignRowReferenceToUpdatedTable(
+		frr: ForeignRowReference<TableOldUserExtension, TargetTableOldUserWrapper>,
 		updatedTable: Table<TargetTableNewUserWrapper, TargetTableOldUserWrapper>,
-		onUpdate: ForeignKey.OnUpdateAction? = null,
-		onDelete: ForeignKey.OnDeleteAction? = null
-	): ForeignKey<TableNewUserExtension, TargetTableNewUserWrapper>
+		onDelete: ForeignRowReference.OnDeleteAction? = null
+	): ForeignRowReference<TableNewUserExtension, TargetTableNewUserWrapper>
 
-	public fun <TargetTableUserWrapper : Any> keepForeignKey(
-		fk: ForeignKey<TableOldUserExtension, TargetTableUserWrapper>,
-		onUpdate: ForeignKey.OnUpdateAction? = null,
-		onDelete: ForeignKey.OnDeleteAction? = null
-	): ForeignKey<TableNewUserExtension, TargetTableUserWrapper>
+	public fun <TargetTableUserWrapper : Any> renameAndKeepForeignRowReference(
+		frr: ForeignRowReference<TableOldUserExtension, TargetTableUserWrapper>,
+		onDelete: ForeignRowReference.OnDeleteAction? = null
+	): ForeignRowReference<TableNewUserExtension, TargetTableUserWrapper>
 
-	public fun <TargetTableOldUserWrapper : Any, TargetTableNewUserWrapper : Any> renameAndKeepForeignKeyToUpdatedTable(
-		fk: ForeignKey<TableOldUserExtension, TargetTableOldUserWrapper>,
+
+	public fun <TargetTableOldUserWrapper : Any, TargetTableNewUserWrapper : Any> renameAndKeepForeignRowReferenceToUpdatedTable(
+		frr: ForeignRowReference<TableOldUserExtension, TargetTableOldUserWrapper>,
 		updatedTable: Table<TargetTableNewUserWrapper, TargetTableOldUserWrapper>,
-		onUpdate: ForeignKey.OnUpdateAction? = null,
-		onDelete: ForeignKey.OnDeleteAction? = null
-	): ForeignKey<TableNewUserExtension, TargetTableNewUserWrapper>
+		onDelete: ForeignRowReference.OnDeleteAction? = null
+	): ForeignRowReference<TableNewUserExtension, TargetTableNewUserWrapper>
 
-	public fun <TargetTableUserWrapper : Any> renameAndKeepForeignKey(
-		fk: ForeignKey<TableOldUserExtension, TargetTableUserWrapper>,
-		onUpdate: ForeignKey.OnUpdateAction? = null,
-		onDelete: ForeignKey.OnDeleteAction? = null
-	): ForeignKey<TableNewUserExtension, TargetTableUserWrapper>
-
-	public fun deleteForeignKey(fk: ForeignKey<TableOldUserExtension, *>)
+	public fun deleteForeignRowReference(frr: ForeignRowReference<TableOldUserExtension, *>)
 }
\ No newline at end of file