First commit

This commit is contained in:
2025-01-11 06:34:04 +01:00
parent 12e0eb37a8
commit 9705818b38
22 changed files with 308 additions and 131 deletions

View File

@@ -1,3 +1,5 @@
import dao.DictionaryDao
import dao.PronunciationDao
import io.ktor.serialization.kotlinx.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.application.*
@@ -7,11 +9,22 @@ import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.plugins.defaultheaders.*
import io.ktor.server.routing.*
import io.ktor.server.websocket.*
import org.jetbrains.exposed.sql.transactions.transaction
import service.DatabaseFactory
//import service.WidgetService
import util.JsonMapper
import web.index
//import web.widget
import service.DatabaseFactory.dbExecId
import service.DatabaseFactory.dbExecName
import service.DictTypeService
import service.DictTypeServiceImpl
import service.DictionaryServiceImpl
import service.PronunciationServiceImpl
import web.dictType
import web.dictionary
import web.pronunciation
fun Application.module() {
install(DefaultHeaders)
@@ -25,12 +38,18 @@ fun Application.module() {
}
DatabaseFactory.connectAndMigrate()
DatabaseFactory.connectAll()
//val widgetService = WidgetService()
val dictTypeService = DictTypeServiceImpl()
val dictionaryService = DictionaryServiceImpl()
val pronunciationService = PronunciationServiceImpl()
routing {
index()
// widget(widgetService)
dictType(dictTypeService)
dictionary(dictionaryService)
pronunciation(pronunciationService)
}
}

View File

@@ -3,10 +3,16 @@ package dao
import org.jetbrains.exposed.dao.*
import org.jetbrains.exposed.dao.id.EntityID
import tables.DictTypes
import models.DictType
class DictTypeDao(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<DictTypeDao>(DictTypes)
var shortName by DictTypes.shortName
var fullName by DictTypes.fullName
fun toModel() = DictType(
id = id.value,
shortName = shortName,
fullName = fullName
)
}

View File

@@ -1,12 +1,25 @@
package dao
import dao.SuffixDao.Companion.referrersOn
import models.Language
import org.jetbrains.exposed.dao.*
import org.jetbrains.exposed.dao.id.EntityID
import tables.Dictionaries
import tables.*
import models.Dictionary
class DictionaryDao(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<DictionaryDao>(Dictionaries)
var name by Dictionaries.name
var fullName by Dictionaries.fullName
var lang1 by LanguageDao referencedOn Dictionaries.lang1
var lang2 by LanguageDao referencedOn Dictionaries.lang2
fun toModel(): Dictionary = Dictionary(
id = id.value,
name = name,
fullName = fullName,
lang1Id = lang1.id.value,
lang2Id = lang2.id.value
)
}

View File

@@ -2,11 +2,17 @@ package dao
import org.jetbrains.exposed.dao.*
import org.jetbrains.exposed.dao.id.EntityID
import tables.Languages
import tables.*
import models.Language
class LanguageDao(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<LanguageDao>(Languages)
var name by Languages.name
var shortName by Languages.shortName
fun toModel() : Language = Language(
id = id.value,
name = name,
shortName = shortName
)
}

View File

@@ -4,10 +4,20 @@ import models.Translation
import org.jetbrains.exposed.dao.*
import org.jetbrains.exposed.dao.id.EntityID
import tables.Pronunciations
import models.Pronunciation
import tables.PronunciationTypes
class PronunciationDao(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<PronunciationDao>(Pronunciations)
var ipa by Pronunciations.ipa
var filename by Pronunciations.filename
var type by PronunciationTypeDao referencedOn Pronunciations.typeId
fun toModel() : Pronunciation = Pronunciation(
id = id.value,
typeId = type.id.value,
ipa = ipa,
filename = filename
)
}

View File

@@ -154,7 +154,7 @@ object SharedData {
var hashTransMap: Map<Int,Translation> = mapOf()
var hashPron: Map<Int,Pronunciation> = mapOf()
var hashSuffix: Map<Int,Suffix> = mapOf()
var hashTermPron : Map<Int,TermsPronunciation> = mapOf()
var hashTermPron : MutableMap<Int,Array<Int>> = mutableMapOf()
var listTerm : List<Term> = listOf()
var getListofTerms : (Int) -> List<Term> = {
listOf()
@@ -184,8 +184,12 @@ class V1__test_connection: BaseJavaMigration() {
SharedData.hashPron = allPronunciation.associateBy { it.id }
val allTermsPronunciationQuery = queryOf("select * from terms_pronunciations").map(toTermsPronunciation).asList
val allTermsPronunciation = session.run(allTermsPronunciationQuery)
SharedData.hashTermPron = allTermsPronunciation.associateBy { it.termId }
allTermsPronunciation.forEach {
val p = SharedData.hashTermPron.getOrDefault(it.termId, arrayOf())
SharedData.hashTermPron[it.termId] = p + it.pronunciationId
}
SharedData.getListofTerms = {
println("DB ID = ${it}")
session.run(queryOf("select * from term WHERE dictionary_id=${it}").map(toTerm).asList)
}

View File

@@ -1,6 +1,6 @@
package db.migration
import dao.DictionaryDao
import kotlinx.serialization.decodeFromString
import tables.*
import org.flywaydb.core.api.migration.BaseJavaMigration

View File

@@ -1,117 +0,0 @@
package db.migration
import dao.DictionaryDao
import kotlinx.serialization.decodeFromString
import tables.*
import org.flywaydb.core.api.migration.BaseJavaMigration
import org.flywaydb.core.api.migration.Context
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.upsert
import kotlin.system.exitProcess
class V3__create_dictionaries: BaseJavaMigration() {
override fun migrate(context: Context?) {
println(SharedData.hashDict)
//exitProcess(0)
for ((db_id,dict) in SharedData.hashDict) {
val db_name = "jdbc:h2:file:/Users/jaro/data/${SharedData.hashLang[dict.lang1Id]?.shortName}-${SharedData.hashLang[dict.lang2Id]?.shortName}"
println(db_name)
val db = Database.connect(db_name)
transaction (db) {
SchemaUtils.create(Dictionaries, Languages, Translations, Pronunciations, PronunciationTypes, DictTypes, Suffixes, Terms)
for ((di, lang) in SharedData.hashLang) {
Languages.insert {
it[id] = lang.id
it[name] = lang.name
it[shortName] = lang.shortName
}
}
for ((di, d) in SharedData.hashDict) {
Dictionaries.insert {
it[id] = d.id
it[lang1] = d.lang1Id
it[lang2] = d.lang2Id
it[name] = d.name
it[fullName] = d.fullName
}
}
for ((di, trans) in SharedData.hashTransMap) {
Translations.insert {
it[id] = trans.id
it[lang1Id] = trans.lang1Id
it[lang2Id] = trans.lang2Id
it[dictionaryId] = trans.dictionaryId
it[langName1] = trans.lang1Name
it[langName2] = trans.lang2Name
it[direction] = trans.direction
}
}
PronunciationTypes.insert {
it[id] = 1
it[name] = "English"
}
PronunciationTypes.insert {
it[id] = 2
it[name] = "American english"
}
PronunciationTypes.insert {
it[id] = 3
it[name] = "Business english"
}
for ((di, pron) in SharedData.hashPron) {
Pronunciations.insert {
it[id] = pron.id
it[typeId] = pron.typeId
it[ipa] = pron.ipa
it[filename] = pron.filename
}
}
for ((di, dt) in SharedData.hashDictType) {
DictTypes.insert {
it[id] = dt.id
it[shortName] = dt.shortName
it[fullName] = dt.fullName
}
}
for ((di, ss) in SharedData.hashSuffix) {
Suffixes.insert {
it[id] = ss.id
it[text] = ss.text
}
}
var dictTerms = SharedData.getListofTerms(db_id)
for (t in dictTerms) {
Terms.insert {
it[id] = t.id
it[string1] = t.string1
it[string2] = t.string2
it[suffix1] = t.suffix1Id
it[suffix2] = t.suffix2Id
it[type] = t.typeId
it[member] = t.member
it[order2] = t.order2
it[flags] = format.decodeFromString<IntArray?>(t.flags?.toString() ?:"[]")
}
}
dictTerms = listOf()
}
}
}
}

View File

@@ -0,0 +1,11 @@
package models
import kotlinx.serialization.Serializable
import org.jetbrains.exposed.sql.Table
@Serializable
data class TermsPronunciation(
val termsId: Int,
val pronunciationId: Int
)

View File

@@ -6,33 +6,63 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.flywaydb.core.Flyway
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import org.slf4j.LoggerFactory
import javax.sql.DataSource
import tables.*
import dao.*
import com.typesafe.config.ConfigFactory
object DatabaseFactory {
private val log = LoggerFactory.getLogger(this::class.java)
private val dbs : MutableMap<Int,Database> = mutableMapOf()
private val hdb : MutableMap<String,Database> = mutableMapOf()
fun connectAndMigrate() {
log.info("Initialising database")
val pool = hikari()
Database.connect(pool)
dbs[0] = Database.connect(pool)
runFlyway(pool)
}
private fun hikari(): HikariDataSource {
val cfg = ConfigFactory.load().getConfig("h2")
val config = HikariConfig().apply {
driverClassName = "org.h2.Driver"
jdbcUrl = "jdbc:h2:file:/Users/jaro/data/dict_settings"
driverClassName = cfg.getString("driver")
jdbcUrl = String.format(cfg.getString("url"),"dict_settings")
maximumPoolSize = 3
isAutoCommit = false
transactionIsolation = "TRANSACTION_REPEATABLE_READ"
validate()
}
return HikariDataSource(config)
}
fun connectAll(): Map<Int,Database> {
val hMap : MutableMap<Int, Database> = mutableMapOf()
transaction {
for (dict in DictionaryDao.all()) {
val cfg = ConfigFactory.load().getConfig("h2")
val config = HikariConfig().apply {
driverClassName = cfg.getString("driver")
jdbcUrl = String.format(cfg.getString("url"),"dict_${dict.lang1.shortName.lowercase()}${dict.lang2.shortName.lowercase()}")
maximumPoolSize = 3
isAutoCommit = false
transactionIsolation = "TRANSACTION_REPEATABLE_READ"
validate()
}
val db = HikariDataSource(config)
val dbc = Database.connect(db)
dbs[dict.id.value] = dbc
hdb["${dict.lang1.shortName.lowercase()}${dict.lang2.shortName.lowercase()}"] = dbc
}
}
return hMap
}
private fun runFlyway(datasource: DataSource) {
val flyway = Flyway.configure().dataSource(datasource).load()
try {
@@ -51,4 +81,16 @@ object DatabaseFactory {
transaction { block() }
}
fun <T> dbExecId(
dbId: Int, block: () -> T
) : T = transaction(dbs[dbId]) {
block()
}
fun <T> dbExecName(
d1: String, d2: String, block: () -> T
) : T = transaction(hdb["${d1.lowercase()}${d2.lowercase()}"]) {
block()
}
}

View File

@@ -0,0 +1,9 @@
package service
import dao.DictTypeDao
import models.DictType
interface DictTypeService {
fun getDictType(id: Int): DictType?
fun getAllDictTypes(): List<DictType>
}

View File

@@ -0,0 +1,17 @@
package service
import dao.DictTypeDao
import org.jetbrains.exposed.sql.transactions.transaction
import service.DatabaseFactory.dbExecId
import models.DictType
class DictTypeServiceImpl : DictTypeService {
override fun getDictType(id: Int): DictType? = dbExecId(1) {
DictTypeDao.findById(id)?.toModel()
}
override fun getAllDictTypes(): List<DictType> = dbExecId(1) {
DictTypeDao.all().map { it.toModel() }
}
}

View File

@@ -0,0 +1,9 @@
package service
import dao.DictionaryDao
import models.Dictionary
interface DictionaryService {
fun getDictionary(id: Int): Dictionary?
fun getAllDictionary(): List<Dictionary>
}

View File

@@ -0,0 +1,16 @@
package service
import dao.DictionaryDao
import org.jetbrains.exposed.sql.transactions.transaction
import service.DatabaseFactory.dbExecId
import models.Dictionary
class DictionaryServiceImpl : DictionaryService {
override fun getDictionary(id: Int): Dictionary? = dbExecId(1) {
DictionaryDao.findById(id)?.toModel()
}
override fun getAllDictionary(): List<Dictionary> = dbExecId(1) {
DictionaryDao.all().map { it.toModel() }
}
}

View File

@@ -0,0 +1,9 @@
package service
import dao.PronunciationDao
import models.Pronunciation
interface PronunciationService {
fun getPronunciation(id: Int): Pronunciation?
fun getAllPronunciations(): List<Pronunciation>
}

View File

@@ -0,0 +1,15 @@
package service
import dao.PronunciationDao
import models.Pronunciation
import service.DatabaseFactory.dbExecId
class PronunciationServiceImpl: PronunciationService {
override fun getPronunciation(id: Int): Pronunciation? = dbExecId(1) {
PronunciationDao.findById(id)?.toModel()
}
override fun getAllPronunciations(): List<Pronunciation> = dbExecId(1) {
PronunciationDao.all().map { it.toModel() }
}
}

View File

@@ -1,8 +1,12 @@
package tables
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.Column
object Languages : IntIdTable() {
val name = varchar("name", 255)
val shortName = varchar("short_name", 255)
}

View File

@@ -0,0 +1,10 @@
package tables
import org.jetbrains.exposed.sql.Table
object TermsPronunciations : Table() {
val term = reference("term", Terms)
val pronunciation = reference("pronunciation", Pronunciations)
override val primaryKey = PrimaryKey(term, pronunciation, name = "PK_Term_Pronunciation")
}

View File

@@ -0,0 +1,29 @@
package web
import io.ktor.http.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.server.websocket.*
import io.ktor.websocket.*
import service.DictTypeService
import service.DictTypeServiceImpl
fun Route.dictType(dictTypeService: DictTypeServiceImpl) {
route("/dict-type") {
get {
call.respond(dictTypeService.getAllDictTypes())
}
get("/{id}") {
val id = call.parameters["id"]?.toInt() ?: throw IllegalStateException("Must provide id")
val dictType = dictTypeService.getDictType(id)
if (dictType == null) call.respond(HttpStatusCode.NotFound)
else call.respond(dictType)
}
}
}

View File

@@ -0,0 +1,29 @@
package web
import io.ktor.http.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.server.websocket.*
import io.ktor.websocket.*
import service.DictionaryServiceImpl
import service.DictionaryService
fun Route.dictionary(dictionaryService: DictionaryServiceImpl) {
route("/dictionary") {
get {
call.respond(dictionaryService.getAllDictionary())
}
get("/{id}") {
val id = call.parameters["id"]?.toInt() ?: throw IllegalStateException("Must provide id")
val dictionary = dictionaryService.getDictionary(id)
if (dictionary == null) call.respond(HttpStatusCode.NotFound)
else call.respond(dictionary)
}
}
}

View File

@@ -0,0 +1,29 @@
package web
import io.ktor.http.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.server.websocket.*
import io.ktor.websocket.*
import service.PronunciationServiceImpl
import service.DictionaryService
fun Route.pronunciation(pronunciationService: PronunciationServiceImpl) {
route("/pronunciation") {
get {
call.respond(pronunciationService.getAllPronunciations())
}
get("/{id}") {
val id = call.parameters["id"]?.toInt() ?: throw IllegalStateException("Must provide id")
val pronunciation = pronunciationService.getPronunciation(id)
if (pronunciation == null) call.respond(HttpStatusCode.NotFound)
else call.respond(pronunciation)
}
}
}

View File

@@ -7,4 +7,11 @@ ktor {
application {
modules = [ MainKt.module ]
}
}
}
h2 {
driver = org.h2.Driver
url = "jdbc:h2:file:./data/%s;DB_CLOSE_DELAY=-1;"
user = "sa"
password = ""
}