From fd5f02e7a9f881cc5cc7de03501160cf5794bb09 Mon Sep 17 00:00:00 2001
From: Andrew Golovashevich <landgrafhomyak@gmail.com>
Date: Sun, 17 Nov 2024 19:51:56 +0300
Subject: [PATCH] DDL & DML

---
 build.gradle.kts                              |  13 +-
 .../serdha/api/v0/Expression.kt               |   5 +
 .../serdha/api/v0/ddl/CheckConstraint.kt      |  10 ++
 .../serdha/api/v0/ddl/Column.kt               |   9 ++
 .../serdha/api/v0/ddl/ColumnType.kt           | 132 ++++++++++++++++++
 .../serdha/api/v0/ddl/ForeignKey.kt           |  36 +++++
 .../landgrafhomyak/serdha/api/v0/ddl/Index.kt |   7 +
 .../landgrafhomyak/serdha/api/v0/ddl/RowId.kt |   3 +
 .../landgrafhomyak/serdha/api/v0/ddl/Table.kt |   5 +
 .../serdha/api/v0/ddl/TableCreator.kt         |  60 ++++++++
 .../serdha/api/v0/ddl/TableUpdater.kt         |  30 ++++
 .../serdha/api/v0/ddl/UniqueConstraint.kt     |   7 +
 .../serdha/api/v0/dml/InputParam.kt           |   9 ++
 .../serdha/api/v0/dml/Insert.kt               |   5 +
 .../serdha/api/v0/dml/InsertCreator.kt        |  20 +++
 .../serdha/api/v0/dml/Select.kt               |   5 +
 .../serdha/api/v0/dml/SelectCreator.kt        |  21 +++
 .../serdha/api/v0/dml/SelectedColumn.kt       |   8 ++
 .../serdha/api/v0/dml/SelectedTable.kt        |   8 ++
 .../serdha/api/v0/dml/Update.kt               |   4 +
 .../serdha/api/v0/dml/UpdateCreator.kt        |  15 ++
 src/jvmMain/java/Test.java                    |  27 ++++
 22 files changed, 438 insertions(+), 1 deletion(-)
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/Expression.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/CheckConstraint.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/Column.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ColumnType.kt
 create 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/Index.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/RowId.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/Table.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/TableCreator.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/TableUpdater.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/UniqueConstraint.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/InputParam.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Insert.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/InsertCreator.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Select.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectCreator.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectedColumn.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectedTable.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Update.kt
 create mode 100644 src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/UpdateCreator.kt
 create mode 100644 src/jvmMain/java/Test.java

diff --git a/build.gradle.kts b/build.gradle.kts
index 24efc9e..fd779ca 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,4 +1,5 @@
 import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
+import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.configureAllCompilersOptions
 import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.defineAllMultiplatformTargets
 import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.defineXomrkGiteaMavenRepo
 import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.optInContracts
@@ -18,7 +19,7 @@ buildscript {
 }
 
 group = "ru.landgrafhomyak.serdha"
-version = "v0.1"
+version = "v1.0"
 
 repositories {
 	mavenCentral()
@@ -31,9 +32,19 @@ xomrk {
 		warningsAsErrors()
 		optInContracts()
 		setCompatibilityWithKotlin(KotlinVersion.KOTLIN_1_7)
+		configureAllCompilersOptions { freeCompilerArgs.add("-Xjvm-default=all") }
 
 		jvmToolchain(8)
 		defineAllMultiplatformTargets()
+
+
+		sourceSets {
+			commonMain {
+				dependencies {
+					compileOnly("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")
+				}
+			}
+		}
 	}
 
 	publishing {
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/Expression.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/Expression.kt
new file mode 100644
index 0000000..3e1e962
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/Expression.kt
@@ -0,0 +1,5 @@
+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
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/CheckConstraint.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/CheckConstraint.kt
new file mode 100644
index 0000000..12887c7
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/CheckConstraint.kt
@@ -0,0 +1,10 @@
+package ru.landgrafhomyak.serdha.api.v0.ddl
+
+import ru.landgrafhomyak.serdha.api.v0.Expression
+
+public interface CheckConstraint<TableUserWrapper : Any> {
+	public val name: String
+	public val table: Table<TableUserWrapper, *>
+	public val constraint: Expression<Boolean, ColumnType.BOOLEAN, TableUserWrapper>
+	public val affectedColumns: List<Column<*, *, TableUserWrapper>>
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/Column.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/Column.kt
new file mode 100644
index 0000000..6435ef2
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/Column.kt
@@ -0,0 +1,9 @@
+package ru.landgrafhomyak.serdha.api.v0.ddl
+
+public interface Column<RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>, TableUserWrapper : Any> /*: Expression<RuntimeType, DatabaseType>*/ {
+	public val name: String
+
+	public val type: DatabaseType
+
+	public val table: Table<TableUserWrapper, *>
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..4767027
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ColumnType.kt
@@ -0,0 +1,132 @@
+package ru.landgrafhomyak.serdha.api.v0.ddl
+
+import kotlin.jvm.JvmStatic
+import kotlinx.datetime.Instant
+import kotlinx.datetime.LocalDate
+import kotlinx.datetime.LocalDateTime
+import kotlinx.datetime.LocalTime
+
+@Suppress("ClassName")
+public abstract class ColumnType<RuntimeType : Any> {
+	public abstract val typeName: String
+
+	abstract override fun toString(): String
+
+	public sealed class _StandardType<R : Any> : ColumnType<R>() {
+		override fun toString(): String = "<serdha | column type '${this.typeName}'>"
+	}
+
+	public abstract class _VirtualType<R : Any>(public val wraps: ColumnType<R>) {
+		override fun toString(): String = "<serdha | virtual column type 'ROW_ID'>"
+	}
+
+	public object ROW_ID : _StandardType<RowId<*>>() {
+		override val typeName: String get() = "ROW_ID"
+	}
+
+	public object BOOLEAN : _StandardType<Boolean>() {
+		override val typeName: String get() = "BOOLEAN"
+	}
+
+	public object INT_S8 : _StandardType<Byte>() {
+		override val typeName: String get() = "INT_S8"
+	}
+
+	public object INT_U8 : _StandardType<UByte>() {
+		override val typeName: String get() = "INT_U8"
+	}
+
+	public object INT_S16 : _StandardType<Short>() {
+		override val typeName: String get() = "INT_S16"
+	}
+
+	public object INT_U16 : _StandardType<UShort>() {
+		override val typeName: String get() = "INT_U16"
+	}
+
+	public object INT_S32 : _StandardType<Int>() {
+		override val typeName: String get() = "INT_S32"
+	}
+
+	public object INT_U32 : _StandardType<UInt>() {
+		override val typeName: String get() = "INT_U32"
+	}
+
+	public object INT_S64 : _StandardType<Long>() {
+		override val typeName: String get() = "INT_S64"
+	}
+
+	public object INT_U64 : _StandardType<ULong>() {
+		override val typeName: String get() = "INT_U64"
+	}
+
+	public object LOCAL_DATE : _StandardType<LocalDate>() {
+		override val typeName: String get() = "LOCAL_DATE"
+	}
+
+	public object LOCAL_TIME : _StandardType<LocalTime>() {
+		override val typeName: String get() = "LOCAL_TIME"
+	}
+
+	public object LOCAL_DATETIME : _StandardType<LocalDateTime>() {
+		override val typeName: String get() = "LOCAL_DATETIME"
+	}
+
+	public object INSTANT : _StandardType<Instant>() {
+		override val typeName: String get() = "INSTANT"
+	}
+
+	public object FLOAT_32 : _StandardType<Float>() {
+		override val typeName: String get() = "FLOAT_32"
+	}
+
+	public object FLOAT_64 : _StandardType<Float>() {
+		override val typeName: String get() = "FLOAT_64"
+	}
+
+	public class STRING internal constructor(
+		private val _size: UInt
+	) : _StandardType<String>() {
+		override val typeName: String = if (this._size == 0u) "STRING" else "STRING(${this._size})"
+
+		public val size: UInt? get() = if (this._size == 0u) null else this._size
+	}
+
+	public class BYTE_ARRAY internal constructor(
+		private val _size: UInt
+	) : _StandardType<String>() {
+		override val typeName: String = if (this._size == 0u) "BYTE_ARRAY" else "BYTE_ARRAY(${this._size})"
+
+		public val size: UInt? get() = if (this._size == 0u) null else this._size
+	}
+
+	public companion object DSL {
+		@Suppress("RemoveRedundantQualifierName")
+		@JvmStatic
+		public val STRING: STRING = ColumnType.STRING(0u)
+
+		@Suppress("RemoveRedundantQualifierName")
+		@JvmStatic
+		public fun STRING(size: UInt): STRING {
+			if (size == 0u)
+				throw IllegalArgumentException("Size of string can't be 0")
+			return ColumnType.STRING(size)
+		}
+
+		@Suppress("RemoveRedundantQualifierName")
+		@JvmStatic
+		public val BYTE_ARRAY: BYTE_ARRAY = ColumnType.BYTE_ARRAY(0u)
+
+		@Suppress("RemoveRedundantQualifierName")
+		@JvmStatic
+		public fun BYTE_ARRAY(size: UInt): BYTE_ARRAY {
+			if (size == 0u)
+				throw IllegalArgumentException("Size of byte array can't be 0")
+			return ColumnType.BYTE_ARRAY(size)
+		}
+
+		@Suppress("FunctionName", "UNCHECKED_CAST", "RemoveRedundantQualifierName")
+		@JvmStatic
+		public fun <T : Any> ROW_ID(): ColumnType<RowId<T>> = ColumnType.ROW_ID as ColumnType<RowId<T>>
+	}
+}
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
new file mode 100644
index 0000000..358f16d
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/ForeignKey.kt
@@ -0,0 +1,36 @@
+package ru.landgrafhomyak.serdha.api.v0.ddl
+
+import kotlin.jvm.JvmStatic
+
+public interface ForeignKey<ContainerTableUserWrapper : Any, TargetTableUserWrapper : Any> {
+	public val fromTable: Table<ContainerTableUserWrapper, *>
+	public val fromColumns: List<Column<*, *, ContainerTableUserWrapper>>
+	public val toTable: Table<TargetTableUserWrapper, *>
+	public val toColumns: List<Column<*, *, TargetTableUserWrapper>>
+
+	public enum class OnUpdateAction {
+		NO_ACTION,
+		RESTRICT,
+		SET_NULL,
+		SET_DEFAULT,
+		CASCADE
+	}
+
+	public enum class OnDeleteAction {
+		NO_ACTION,
+		RESTRICT,
+		SET_NULL,
+		SET_DEFAULT,
+		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/Index.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/Index.kt
new file mode 100644
index 0000000..1b80d29
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/Index.kt
@@ -0,0 +1,7 @@
+package ru.landgrafhomyak.serdha.api.v0.ddl
+
+public interface Index<OwnerTableUserWrapper : Any> {
+	public val name: String
+	public val table: Table<OwnerTableUserWrapper, *>
+	public val columns: List<Column<*, *, OwnerTableUserWrapper>>
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/RowId.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/RowId.kt
new file mode 100644
index 0000000..e14f45b
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/RowId.kt
@@ -0,0 +1,3 @@
+package ru.landgrafhomyak.serdha.api.v0.ddl
+
+public interface RowId<OwnerTableUserWrapper: Any>
\ No newline at end of file
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/Table.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/Table.kt
new file mode 100644
index 0000000..d6c3c72
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/Table.kt
@@ -0,0 +1,5 @@
+package ru.landgrafhomyak.serdha.api.v0.ddl
+
+public interface Table<UserWrapper : Any, PreviousUserWrapper: Any> {
+	public val wrapper: UserWrapper
+}
\ 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
new file mode 100644
index 0000000..55a282e
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/TableCreator.kt
@@ -0,0 +1,60 @@
+package ru.landgrafhomyak.serdha.api.v0.ddl
+
+import kotlin.jvm.JvmName
+import ru.landgrafhomyak.serdha.api.v0.Expression
+
+public interface TableCreator<TableUserWrapper : Any> {
+	/**
+	 * Offers column of type [D][type] with `NOT NULL` constraint named [name] and runtime type [RuntimeType].
+	 *
+	 * @return Descriptor of offered column for future operations.
+	 */
+	public fun <RuntimeType : Any, DatabaseType : ColumnType<RuntimeType>> column(name: String, type: DatabaseType): Column<RuntimeType, DatabaseType, TableUserWrapper>
+
+	@Suppress("INAPPLICABLE_JVM_NAME")
+	@JvmName("nullableColumn\$notNull")
+	@Deprecated("This column can be not-null", replaceWith = ReplaceWith("this.column"))
+	public fun <RuntimeType : Any, DatabaseType : ColumnType<RuntimeType>> nullableColumn(name: String, type: DatabaseType): Column<RuntimeType?, DatabaseType, TableUserWrapper> =
+		this.nullableColumn<RuntimeType?, DatabaseType>(name, type)
+
+	/**
+	 * Offers column of type [D][type] named [name] and runtime type [R?][RuntimeType].
+	 *
+	 * @return Descriptor of offered column for future operations.
+	 */
+	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>
+	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 <TargetTableUserWrapper : Any, ColumnType1 : ColumnType<*>> foreignKey(
+		fromColumn: Column<*, ColumnType1, TableUserWrapper>,
+		toTable: Table<TargetTableUserWrapper, *>,
+		toColumn: Column<*, ColumnType1, TargetTableUserWrapper>,
+		onUpdate: ForeignKey.OnUpdateAction,
+		onDelete: ForeignKey.OnDeleteAction
+	): ForeignKey<TableUserWrapper, TargetTableUserWrapper>
+
+	public fun <TargetTableUserWrapper : Any, ColumnType1 : ColumnType<*>, ColumnType2 : ColumnType<*>> foreignKey(
+		fromColumn1: Column<*, ColumnType1, TableUserWrapper>,
+		fromColumn2: Column<*, ColumnType2, TableUserWrapper>,
+		toTable: Table<TargetTableUserWrapper, *>,
+		toColumn1: Column<*, ColumnType1, TargetTableUserWrapper>,
+		toColumn2: Column<*, ColumnType2, TargetTableUserWrapper>,
+		onUpdate: ForeignKey.OnUpdateAction,
+		onDelete: ForeignKey.OnDeleteAction
+	): ForeignKey<TableUserWrapper, TargetTableUserWrapper>
+
+	public fun <TargetTableUserWrapper : Any, ColumnType1 : ColumnType<*>, ColumnType2 : ColumnType<*>, ColumnType3 : ColumnType<*>> foreignKey(
+		fromColumn1: Column<*, ColumnType1, TableUserWrapper>,
+		fromColumn2: Column<*, ColumnType2, TableUserWrapper>,
+		fromColumn3: Column<*, ColumnType3, TableUserWrapper>,
+		toTable: Table<TargetTableUserWrapper, *>,
+		toColumn1: Column<*, ColumnType1, TargetTableUserWrapper>,
+		toColumn2: Column<*, ColumnType2, TargetTableUserWrapper>,
+		toColumn3: Column<*, ColumnType3, TargetTableUserWrapper>,
+		onUpdate: ForeignKey.OnUpdateAction,
+		onDelete: ForeignKey.OnDeleteAction
+	): ForeignKey<TableUserWrapper, 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
new file mode 100644
index 0000000..da7ecfc
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/TableUpdater.kt
@@ -0,0 +1,30 @@
+package ru.landgrafhomyak.serdha.api.v0.ddl
+
+import ru.landgrafhomyak.serdha.api.v0.Expression
+
+
+public interface TableUpdater<TableOldUserWrapper : Any, TableNewUserWrapper : Any> : TableCreator<TableNewUserWrapper> {
+	public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> keepColumn(c: Column<RuntimeType, DatabaseType, TableOldUserWrapper>): Column<RuntimeType, DatabaseType, TableNewUserWrapper>
+	public fun <R, D : ColumnType<R & Any>> renameColumn(c: Column<R, D, TableOldUserWrapper>, newName: String): Column<R, D, TableNewUserWrapper>
+	public fun <R, D : ColumnType<R & Any>> mapColumn(c: Column<R, D, TableNewUserWrapper>, newValue: Expression<R, D, TableNewUserWrapper>, where: Expression<Boolean, ColumnType.BOOLEAN, TableNewUserWrapper>?)
+	public fun <R, D : ColumnType<R & Any>> mapColumn(c: Column<R, D, TableNewUserWrapper>, newValue: Expression<R, D, TableNewUserWrapper>): Unit = this.mapColumn(c, newValue, null)
+	public fun deleteColumn(c: Column<*, *, TableOldUserWrapper>)
+
+	public fun keepIndex(i: Index<TableOldUserWrapper>): Index<TableNewUserWrapper>
+	public fun renameIndex(i: Index<TableOldUserWrapper>, newName: String): Index<TableNewUserWrapper>
+	public fun deleteIndex(i: Index<TableOldUserWrapper>)
+
+	public fun keepCheck(i: CheckConstraint<TableOldUserWrapper>): CheckConstraint<TableNewUserWrapper>
+	public fun renameCheck(i: CheckConstraint<TableOldUserWrapper>, newName: String): CheckConstraint<TableNewUserWrapper>
+	public fun deleteCheck(i: CheckConstraint<TableOldUserWrapper>)
+
+	public fun keepUnique(i: UniqueConstraint<TableOldUserWrapper>): UniqueConstraint<TableNewUserWrapper>
+	public fun renameUnique(i: UniqueConstraint<TableOldUserWrapper>, newName: String): UniqueConstraint<TableNewUserWrapper>
+	public fun deleteUnique(i: UniqueConstraint<TableOldUserWrapper>)
+
+	public fun <TargetTableOldUserWrapper : Any, TargetTableNewUserWrapper : Any> keepForeignKeyToUpdatedTable(i: ForeignKey<TableOldUserWrapper, TargetTableOldUserWrapper>, updatedTable: Table<TargetTableNewUserWrapper, TargetTableOldUserWrapper>): ForeignKey<TableNewUserWrapper, TargetTableNewUserWrapper>
+	public fun <TargetTableUserWrapper : Any> keepForeignKey(i: ForeignKey<TableOldUserWrapper, TargetTableUserWrapper>): ForeignKey<TableNewUserWrapper, TargetTableUserWrapper>
+	public fun <TargetTableOldUserWrapper : Any, TargetTableNewUserWrapper : Any> renameForeignKeyToUpdatedTable(i: ForeignKey<TableOldUserWrapper, TargetTableOldUserWrapper>, updatedTable: Table<TargetTableNewUserWrapper, TargetTableOldUserWrapper>): ForeignKey<TableNewUserWrapper, TargetTableNewUserWrapper>
+	public fun <TargetTableUserWrapper : Any> renameForeignKey(i: ForeignKey<TableOldUserWrapper, TargetTableUserWrapper>): ForeignKey<TableNewUserWrapper, TargetTableUserWrapper>
+	public fun deleteForeignKey(i: ForeignKey<TableOldUserWrapper, *>)
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/UniqueConstraint.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/UniqueConstraint.kt
new file mode 100644
index 0000000..25b144c
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/ddl/UniqueConstraint.kt
@@ -0,0 +1,7 @@
+package ru.landgrafhomyak.serdha.api.v0.ddl
+
+public interface UniqueConstraint<OwnerTableUserWrapper : Any> {
+	public val name: String
+	public val table: Table<OwnerTableUserWrapper, *>
+	public val columns: List<Column<*, *, OwnerTableUserWrapper>>
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/InputParam.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/InputParam.kt
new file mode 100644
index 0000000..f1480ab
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/InputParam.kt
@@ -0,0 +1,9 @@
+package ru.landgrafhomyak.serdha.api.v0.dml
+
+import ru.landgrafhomyak.serdha.api.v0.Expression
+import ru.landgrafhomyak.serdha.api.v0.ddl.ColumnType
+
+public interface InputParam<RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>, OwnerQueryUserWrapper : Any> : Expression<RuntimeType, DatabaseType, OwnerQueryUserWrapper> {
+	public val name: String
+	public val userWrapper: OwnerQueryUserWrapper
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Insert.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Insert.kt
new file mode 100644
index 0000000..60adf2f
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Insert.kt
@@ -0,0 +1,5 @@
+package ru.landgrafhomyak.serdha.api.v0.dml
+
+public interface Insert<UserWrapper : Any> {
+	public val userWrapper: UserWrapper
+}
\ 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
new file mode 100644
index 0000000..d628f7c
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/InsertCreator.kt
@@ -0,0 +1,20 @@
+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.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>> selectColumn(c: Column<RuntimeType, DatabaseType, TargetTableUserWrapper>): SelectedColumn<RuntimeType, DatabaseType, TargetTableUserWrapper, QueryUserWrapper>
+
+	public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> returning(e: Expression<RuntimeType, DatabaseType, QueryUserWrapper>): Column<RuntimeType, DatabaseType, QueryUserWrapper>
+
+	public interface UpsertCreator<TargetTableUserWrapper : Any, QueryUserWrapper : Any> : UpdateCreator<TargetTableUserWrapper, QueryUserWrapper> {
+		public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> overwrittenColumn(c: Column<RuntimeType, DatabaseType, TargetTableUserWrapper>): SelectedColumn<RuntimeType, DatabaseType, TargetTableUserWrapper, QueryUserWrapper>
+	}
+
+	public fun onConflict(u: UniqueConstraint<TargetTableUserWrapper>, c: UpsertCreator<TargetTableUserWrapper, QueryUserWrapper>.() -> Unit)
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Select.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Select.kt
new file mode 100644
index 0000000..e2e2c6f
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Select.kt
@@ -0,0 +1,5 @@
+package ru.landgrafhomyak.serdha.api.v0.dml
+
+public interface Select<QueryUserWrapper : Any> {
+	public val userWrapper: QueryUserWrapper
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..b9fa2ca
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectCreator.kt
@@ -0,0 +1,21 @@
+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 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
+	public var isDistinct: Boolean
+
+	public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> returnExpression(expression: Expression<RuntimeType, DatabaseType, QueryUserWrapper>): Column<RuntimeType, DatabaseType, QueryUserWrapper>
+
+	public fun orderBy(vararg columns: Column<*, *, QueryUserWrapper>)
+
+	public fun groupBy(vararg columns: Column<*, *, 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
new file mode 100644
index 0000000..e016a62
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectedColumn.kt
@@ -0,0 +1,8 @@
+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> {
+
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectedTable.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectedTable.kt
new file mode 100644
index 0000000..564f04d
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/SelectedTable.kt
@@ -0,0 +1,8 @@
+package ru.landgrafhomyak.serdha.api.v0.dml
+
+import ru.landgrafhomyak.serdha.api.v0.ddl.Column
+import ru.landgrafhomyak.serdha.api.v0.ddl.ColumnType
+
+public interface SelectedTable<SelectedTableUserWrapper : Any, QueryUserWrapper : Any> {
+	public fun <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> selectColumn(column: Column<RuntimeType, DatabaseType, SelectedTableUserWrapper>): SelectedColumn<RuntimeType, DatabaseType, SelectedTableUserWrapper, QueryUserWrapper>
+}
\ No newline at end of file
diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Update.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Update.kt
new file mode 100644
index 0000000..fb8ccd6
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/Update.kt
@@ -0,0 +1,4 @@
+package ru.landgrafhomyak.serdha.api.v0.dml
+
+public interface Update<QueryUserWrapper : Any> {
+}
\ 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
new file mode 100644
index 0000000..f092705
--- /dev/null
+++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha/api/v0/dml/UpdateCreator.kt
@@ -0,0 +1,15 @@
+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
+
+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 <RuntimeType, DatabaseType : ColumnType<RuntimeType & Any>> updateColumn(c: Column<RuntimeType, DatabaseType, TargetTableUserWrapper>, e: Expression<RuntimeType, DatabaseType, 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>)
+}
\ No newline at end of file
diff --git a/src/jvmMain/java/Test.java b/src/jvmMain/java/Test.java
new file mode 100644
index 0000000..084dda7
--- /dev/null
+++ b/src/jvmMain/java/Test.java
@@ -0,0 +1,27 @@
+import org.jetbrains.annotations.NotNull;
+import ru.landgrafhomyak.serdha.api.v0.Column;
+import ru.landgrafhomyak.serdha.api.v0.ColumnType;
+import ru.landgrafhomyak.serdha.api.v0.ForeignKey;
+import ru.landgrafhomyak.serdha.api.v0.Index;
+import ru.landgrafhomyak.serdha.api.v0.Table;
+import ru.landgrafhomyak.serdha.api.v0.TableCreator;
+
+public class Test implements TableCreator {
+	@NotNull
+	@Override
+	public Column column(@NotNull String name, @NotNull ColumnType type) {
+		return null;
+	}
+
+	@NotNull
+	@Override
+	public Index index(@NotNull String name, @NotNull Column[] columns) {
+		return null;
+	}
+
+	@NotNull
+	@Override
+	public ForeignKey foreignKey(@NotNull Column fromColumn, @NotNull Table toTable, @NotNull Column toColumn, @NotNull ForeignKey.OnUpdateAction onUpdate, @NotNull ForeignKey.OnDeleteAction onDelete) {
+		this.foreignKey(null, null, null);
+	}
+}