diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/db/raw_sql_skeleton/Namespace.kt b/src/commonMain/kotlin/ru/landgrafhomyak/db/raw_sql_skeleton/Namespace.kt new file mode 100644 index 0000000..57b8fe9 --- /dev/null +++ b/src/commonMain/kotlin/ru/landgrafhomyak/db/raw_sql_skeleton/Namespace.kt @@ -0,0 +1,26 @@ +package ru.landgrafhomyak.db.raw_sql_skeleton + +public class Namespace( + public val _name: String, + private val path: Array +) { + private val usedNames = HashSet() + + public fun subnamespace(name: String): Namespace { + if (name in this.usedNames) + throw IllegalArgumentException("Name is already used: $name") + this.usedNames.add(name) + return Namespace(name, this.path + this._name) + } + + public fun table(name: String): Table { + if (name in this.usedNames) + throw IllegalArgumentException("Name is already used: $name") + this.usedNames.add(name) + + return Table(this.formatTableName(name), this._path + this._name) + } + + public val _path: List = this.path.asList() + private fun formatTableName(name: String) = this.path.joinToString(prefix = "::", separator = "::", postfix = "::${this._name}::${name}") +} \ No newline at end of file diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/db/raw_sql_skeleton/Table.kt b/src/commonMain/kotlin/ru/landgrafhomyak/db/raw_sql_skeleton/Table.kt new file mode 100644 index 0000000..41361be --- /dev/null +++ b/src/commonMain/kotlin/ru/landgrafhomyak/db/raw_sql_skeleton/Table.kt @@ -0,0 +1,9 @@ +package ru.landgrafhomyak.db.raw_sql_skeleton + +import ru.landgrafhomyak.db.serdha0.api.module.Module + +public class Table(public val name: String, public val namespacesFromModuleRoot: List) { + public val asSqlReference: String = "\"${this.name}\"" + public val asSqlString: String = "\'${this.name}\'" + override fun toString(): String = this.asSqlReference +} \ No newline at end of file diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/misc/Column.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/misc/Column.kt index d05bbdf..b32b402 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/misc/Column.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/misc/Column.kt @@ -1,7 +1,7 @@ package ru.landgrafhomyak.db.serdha0.api.misc import kotlin.jvm.JvmName -import ru.landgrafhomyak.db.serdha0.api.table.Table +import ru.landgrafhomyak.db.raw_sql_skeleton.Table public interface Column, TableUserExtension : Any> { public val name: String diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/module/CreateModuleScope.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/module/CreateModuleScope.kt index 0421757..45d1e16 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/module/CreateModuleScope.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/module/CreateModuleScope.kt @@ -1,10 +1,9 @@ package ru.landgrafhomyak.db.serdha0.api.module -import ru.landgrafhomyak.db.serdha0.api.table.Table +import ru.landgrafhomyak.db.raw_sql_skeleton.Table import ru.landgrafhomyak.db.serdha0.api.queries._Query -import ru.landgrafhomyak.db.serdha0.api.runtime.SynchronizedDatabase -import ru.landgrafhomyak.db.serdha0.api.runtime.Transaction import ru.landgrafhomyak.db.serdha0.api.table.TableConstructor +import ru.landgrafhomyak.serdha0.api.module.Namespace /** * Scope methods for creating new [module template][ModuleTemplate]. diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/module/Namespace.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/module/Namespace.kt deleted file mode 100644 index 40f935f..0000000 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/module/Namespace.kt +++ /dev/null @@ -1,10 +0,0 @@ -package ru.landgrafhomyak.db.serdha0.api.module - -public interface Namespace { - @Suppress("SpellCheckingInspection") - public fun subnamespace(name: String): Namespace - - public val name: String - - public val path: List -} \ No newline at end of file diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/table/Index.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/table/Index.kt index 0306c89..43ebc75 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/table/Index.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/table/Index.kt @@ -1,6 +1,7 @@ package ru.landgrafhomyak.db.serdha0.api.table import kotlin.jvm.JvmName +import ru.landgrafhomyak.db.raw_sql_skeleton.Table import ru.landgrafhomyak.db.serdha0.api.misc.Column public interface Index { diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/table/Table.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/table/Table.kt deleted file mode 100644 index 7f506da..0000000 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/table/Table.kt +++ /dev/null @@ -1,20 +0,0 @@ -package ru.landgrafhomyak.db.serdha0.api.table - -import ru.landgrafhomyak.db.serdha0.api.misc._Selectable -import ru.landgrafhomyak.db.serdha0.api.module.Module - -public interface Table : _Selectable { - public val userExtension: UserExtension - public val name: String - public val module: Module<*> - - public enum class TemporaryType { - TRANSACTION_SCOPE, - CONNECTION_SCOPE - } - - public val temporaryType: TemporaryType? - - // todo make nullable for temp tables - public val namespacesFromModuleRoot: List -} \ No newline at end of file diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/table/TableConstructor.kt b/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/table/TableConstructor.kt index 6c64bbc..11650fd 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/table/TableConstructor.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/serdha0/api/table/TableConstructor.kt @@ -1,5 +1,6 @@ package ru.landgrafhomyak.db.serdha0.api.table +import ru.landgrafhomyak.db.raw_sql_skeleton.Table import ru.landgrafhomyak.db.serdha0.api.misc.Column import ru.landgrafhomyak.db.serdha0.api.misc.DatabaseType diff --git a/src/jvmMain/kotlin/ru/landgrafhomyak/db/raw_sql_skeleton/namespaces_sqlite.kt b/src/jvmMain/kotlin/ru/landgrafhomyak/db/raw_sql_skeleton/namespaces_sqlite.kt new file mode 100644 index 0000000..eec8efb --- /dev/null +++ b/src/jvmMain/kotlin/ru/landgrafhomyak/db/raw_sql_skeleton/namespaces_sqlite.kt @@ -0,0 +1,102 @@ +@file:JvmName("NamespacesSqliteKt") + +package ru.landgrafhomyak.db.raw_sql_skeleton + +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import java.sql.Connection +import java.sql.DriverManager +import java.util.concurrent.Callable +import java.util.concurrent.Executors.newFixedThreadPool +import kotlin.coroutines.Continuation +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine + + +public class SqliteConnection private constructor( + internal val jdbcConnection: Connection, +) { + private val executor = newFixedThreadPool(1) + + private val mutex = Mutex() + + private inner class Task( + private val continuation: Continuation, + private val task: (connection: Connection) -> R, + ) : Callable { + override fun call() { + try { + this.continuation.resume(this.task(this@SqliteConnection.jdbcConnection)) + } catch (e: InterruptedException) { + this.continuation.resumeWithException(RuntimeException("runner interrupted")) + throw e + } catch (e: Throwable) { + this.continuation.resumeWithException(e) + } + } + } + + public suspend fun transaction(body: (connection: Connection) -> R): R = this.raw { connection -> + return@raw connection.transaction(body) + } + + public suspend fun raw(action: (Connection) -> R): R = this.mutex.withLock { + return@withLock suspendCoroutine { continuation -> + this.executor.submit(this.Task(continuation, action)) + } + } + + public val rootNamespace: SqliteNamespace = SqliteNamespace(this, emptyArray()) + + public companion object { + @JvmStatic + public suspend fun wrap7prepare(rawConnection: Connection): SqliteConnection { + val w = SqliteConnection(rawConnection) + w.raw { connection -> + connection.autoCommit = false + connection.prepareStatement("ROLLBACK TRANSACTION") { ps -> ps.execute() } + connection.prepareStatement("PRAGMA foreign_keys=TRUE") { ps -> ps.execute() } + } + return w + } + + @JvmStatic + public suspend fun connect(url: String): SqliteConnection = this.wrap7prepare(DriverManager.getConnection(url)) + + @JvmStatic + public fun connectBlocking(url: String): SqliteConnection = runBlocking { this@Companion.connect(url) } + } +} + +public class SqliteNamespace( + private val owner: SqliteConnection, + private val path: Array, +) { + private val usedNames = HashSet() + + public fun subNamespace(name: String): SqliteNamespace { + if (name in this.usedNames) + throw IllegalArgumentException("Name is already used: $name") + this.usedNames.add(name) + return SqliteNamespace(this.owner, this.path + name) + } + + public fun table(name: String): SqliteTableName { + if (name in this.usedNames) + throw IllegalArgumentException("Name is already used: $name") + this.usedNames.add(name) + + return SqliteTableName(this.formatTableName(name)) + } + + private fun formatTableName(name: String) = this.path.joinToString(prefix = "::", separator = "::", postfix = "::${name}") +} + + +public class SqliteTableName(private val name: String) { + public val asSqlReference: String = "\"${this.name}\"" + public val asSqlString: String = "\'${this.name}\'" + override fun toString(): String = this.asSqlReference +}