DDL & DML

This commit is contained in:
Andrew Golovashevich 2024-11-17 19:51:56 +03:00
parent a6d776014c
commit fd5f02e7a9
22 changed files with 438 additions and 1 deletions

View File

@ -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 {

View File

@ -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>

View File

@ -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>>
}

View File

@ -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, *>
}

View File

@ -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>>
}
}

View File

@ -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
}
}

View File

@ -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>>
}

View File

@ -0,0 +1,3 @@
package ru.landgrafhomyak.serdha.api.v0.ddl
public interface RowId<OwnerTableUserWrapper: Any>

View File

@ -0,0 +1,5 @@
package ru.landgrafhomyak.serdha.api.v0.ddl
public interface Table<UserWrapper : Any, PreviousUserWrapper: Any> {
public val wrapper: UserWrapper
}

View File

@ -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>
}

View File

@ -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, *>)
}

View File

@ -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>>
}

View File

@ -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
}

View File

@ -0,0 +1,5 @@
package ru.landgrafhomyak.serdha.api.v0.dml
public interface Insert<UserWrapper : Any> {
public val userWrapper: UserWrapper
}

View File

@ -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)
}

View File

@ -0,0 +1,5 @@
package ru.landgrafhomyak.serdha.api.v0.dml
public interface Select<QueryUserWrapper : Any> {
public val userWrapper: QueryUserWrapper
}

View File

@ -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>)
}

View File

@ -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> {
}

View File

@ -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>
}

View File

@ -0,0 +1,4 @@
package ru.landgrafhomyak.serdha.api.v0.dml
public interface Update<QueryUserWrapper : Any> {
}

View File

@ -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>)
}

View File

@ -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);
}
}