Merge branch 'history/cw-adjutant' into 'master'

This commit is contained in:
Andrew Golovashevich 2025-03-23 22:50:04 +03:00
commit fbb03c204e
9 changed files with 142 additions and 34 deletions

View File

@ -0,0 +1,26 @@
package ru.landgrafhomyak.db.raw_sql_skeleton
public class Namespace(
public val _name: String,
private val path: Array<String>
) {
private val usedNames = HashSet<String>()
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<String> = this.path.asList()
private fun formatTableName(name: String) = this.path.joinToString(prefix = "::", separator = "::", postfix = "::${this._name}::${name}")
}

View File

@ -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<String>) {
public val asSqlReference: String = "\"${this.name}\""
public val asSqlString: String = "\'${this.name}\'"
override fun toString(): String = this.asSqlReference
}

View File

@ -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<RT, DT : DatabaseType<RT>, TableUserExtension : Any> {
public val name: String

View File

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

View File

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

View File

@ -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<OwnerTableUserExtension : Any> {

View File

@ -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<UserExtension : Any, PreviousUserExtension : Any> : _Selectable<UserExtension> {
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<String>
}

View File

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

View File

@ -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<R>(
private val continuation: Continuation<R>,
private val task: (connection: Connection) -> R,
) : Callable<Unit> {
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 <R> transaction(body: (connection: Connection) -> R): R = this.raw { connection ->
return@raw connection.transaction(body)
}
public suspend fun <R> 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<String>,
) {
private val usedNames = HashSet<String>()
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
}