diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 35852db..f31ab9b 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -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) } } diff --git a/src/main/kotlin/dao/DictTypeDao.kt b/src/main/kotlin/dao/DictTypeDao.kt index 24d85a0..19f1802 100644 --- a/src/main/kotlin/dao/DictTypeDao.kt +++ b/src/main/kotlin/dao/DictTypeDao.kt @@ -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) : IntEntity(id) { companion object : IntEntityClass(DictTypes) var shortName by DictTypes.shortName var fullName by DictTypes.fullName + + fun toModel() = DictType( + id = id.value, + shortName = shortName, + fullName = fullName + ) } \ No newline at end of file diff --git a/src/main/kotlin/dao/DictionaryDao.kt b/src/main/kotlin/dao/DictionaryDao.kt index 8fc2b4d..6c1100c 100644 --- a/src/main/kotlin/dao/DictionaryDao.kt +++ b/src/main/kotlin/dao/DictionaryDao.kt @@ -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) : IntEntity(id) { companion object : IntEntityClass(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 + ) } \ No newline at end of file diff --git a/src/main/kotlin/dao/LanguageDao.kt b/src/main/kotlin/dao/LanguageDao.kt index ff3dca0..e907d92 100644 --- a/src/main/kotlin/dao/LanguageDao.kt +++ b/src/main/kotlin/dao/LanguageDao.kt @@ -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) : IntEntity(id) { companion object : IntEntityClass(Languages) var name by Languages.name var shortName by Languages.shortName + + fun toModel() : Language = Language( + id = id.value, + name = name, + shortName = shortName + ) } \ No newline at end of file diff --git a/src/main/kotlin/dao/PronunciationDao.kt b/src/main/kotlin/dao/PronunciationDao.kt index 580b4a2..e1bde5e 100644 --- a/src/main/kotlin/dao/PronunciationDao.kt +++ b/src/main/kotlin/dao/PronunciationDao.kt @@ -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) : IntEntity(id) { companion object : IntEntityClass(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 + ) } \ No newline at end of file diff --git a/src/main/kotlin/db/migration/V1__test_connection.kt b/src/main/kotlin/db/migration/V1__test_connection.kt index 7c2c66b..3508ca4 100644 --- a/src/main/kotlin/db/migration/V1__test_connection.kt +++ b/src/main/kotlin/db/migration/V1__test_connection.kt @@ -154,7 +154,7 @@ object SharedData { var hashTransMap: Map = mapOf() var hashPron: Map = mapOf() var hashSuffix: Map = mapOf() - var hashTermPron : Map = mapOf() + var hashTermPron : MutableMap> = mutableMapOf() var listTerm : List = listOf() var getListofTerms : (Int) -> List = { 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) } diff --git a/src/main/kotlin/db/migration/V2__crete_settingsdb.kt b/src/main/kotlin/db/migration/V2__crete_settingsdb.kt index ded30aa..8234b34 100644 --- a/src/main/kotlin/db/migration/V2__crete_settingsdb.kt +++ b/src/main/kotlin/db/migration/V2__crete_settingsdb.kt @@ -1,6 +1,6 @@ package db.migration -import dao.DictionaryDao + import kotlinx.serialization.decodeFromString import tables.* import org.flywaydb.core.api.migration.BaseJavaMigration diff --git a/src/main/kotlin/db/migration/V3__create_dictionaries.kt b/src/main/kotlin/db/migration/V3__create_dictionaries.kt deleted file mode 100644 index 23bb4f3..0000000 --- a/src/main/kotlin/db/migration/V3__create_dictionaries.kt +++ /dev/null @@ -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(t.flags?.toString() ?:"[]") - } - } - dictTerms = listOf() - - } - - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/models/TermsPronunciation.kt b/src/main/kotlin/models/TermsPronunciation.kt new file mode 100644 index 0000000..e986a50 --- /dev/null +++ b/src/main/kotlin/models/TermsPronunciation.kt @@ -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 +) diff --git a/src/main/kotlin/service/DatabaseFactory.kt b/src/main/kotlin/service/DatabaseFactory.kt index c3ccfc1..b08562d 100644 --- a/src/main/kotlin/service/DatabaseFactory.kt +++ b/src/main/kotlin/service/DatabaseFactory.kt @@ -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 = mutableMapOf() + private val hdb : MutableMap = 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 { + val hMap : MutableMap = 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 dbExecId( + dbId: Int, block: () -> T + ) : T = transaction(dbs[dbId]) { + block() + } + + fun dbExecName( + d1: String, d2: String, block: () -> T + ) : T = transaction(hdb["${d1.lowercase()}${d2.lowercase()}"]) { + block() + } + } \ No newline at end of file diff --git a/src/main/kotlin/service/DictTypeService.kt b/src/main/kotlin/service/DictTypeService.kt new file mode 100644 index 0000000..7d3bc43 --- /dev/null +++ b/src/main/kotlin/service/DictTypeService.kt @@ -0,0 +1,9 @@ +package service + +import dao.DictTypeDao +import models.DictType + +interface DictTypeService { + fun getDictType(id: Int): DictType? + fun getAllDictTypes(): List +} diff --git a/src/main/kotlin/service/DictTypeServiceImpl.kt b/src/main/kotlin/service/DictTypeServiceImpl.kt new file mode 100644 index 0000000..da1092a --- /dev/null +++ b/src/main/kotlin/service/DictTypeServiceImpl.kt @@ -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 = dbExecId(1) { + DictTypeDao.all().map { it.toModel() } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/service/DictionaryService.kt b/src/main/kotlin/service/DictionaryService.kt new file mode 100644 index 0000000..fb4d91d --- /dev/null +++ b/src/main/kotlin/service/DictionaryService.kt @@ -0,0 +1,9 @@ +package service + +import dao.DictionaryDao +import models.Dictionary + +interface DictionaryService { + fun getDictionary(id: Int): Dictionary? + fun getAllDictionary(): List +} diff --git a/src/main/kotlin/service/DictionaryServiceImpl.kt b/src/main/kotlin/service/DictionaryServiceImpl.kt new file mode 100644 index 0000000..1327d4f --- /dev/null +++ b/src/main/kotlin/service/DictionaryServiceImpl.kt @@ -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 = dbExecId(1) { + DictionaryDao.all().map { it.toModel() } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/service/PronunciationService.kt b/src/main/kotlin/service/PronunciationService.kt new file mode 100644 index 0000000..a20bde9 --- /dev/null +++ b/src/main/kotlin/service/PronunciationService.kt @@ -0,0 +1,9 @@ +package service + +import dao.PronunciationDao +import models.Pronunciation + +interface PronunciationService { + fun getPronunciation(id: Int): Pronunciation? + fun getAllPronunciations(): List +} diff --git a/src/main/kotlin/service/PronunciationServiceImpl.kt b/src/main/kotlin/service/PronunciationServiceImpl.kt new file mode 100644 index 0000000..8bb224c --- /dev/null +++ b/src/main/kotlin/service/PronunciationServiceImpl.kt @@ -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 = dbExecId(1) { + PronunciationDao.all().map { it.toModel() } + } +} diff --git a/src/main/kotlin/tables/Language.kt b/src/main/kotlin/tables/Language.kt index bca9bc3..aba9740 100644 --- a/src/main/kotlin/tables/Language.kt +++ b/src/main/kotlin/tables/Language.kt @@ -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) + } \ No newline at end of file diff --git a/src/main/kotlin/tables/TermsPronunciation.kt b/src/main/kotlin/tables/TermsPronunciation.kt new file mode 100644 index 0000000..c3aa2b4 --- /dev/null +++ b/src/main/kotlin/tables/TermsPronunciation.kt @@ -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") +} diff --git a/src/main/kotlin/web/DictTypeResource.kt b/src/main/kotlin/web/DictTypeResource.kt new file mode 100644 index 0000000..abc6596 --- /dev/null +++ b/src/main/kotlin/web/DictTypeResource.kt @@ -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) + } + + } + +} diff --git a/src/main/kotlin/web/DictionaryResource.kt b/src/main/kotlin/web/DictionaryResource.kt new file mode 100644 index 0000000..e3af989 --- /dev/null +++ b/src/main/kotlin/web/DictionaryResource.kt @@ -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) + } + + } + +} diff --git a/src/main/kotlin/web/PronunciationResource.kt b/src/main/kotlin/web/PronunciationResource.kt new file mode 100644 index 0000000..36b0eaf --- /dev/null +++ b/src/main/kotlin/web/PronunciationResource.kt @@ -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) + } + + } + +} diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 4ae3bc0..46f7717 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -7,4 +7,11 @@ ktor { application { modules = [ MainKt.module ] } -} \ No newline at end of file +} + +h2 { + driver = org.h2.Driver + url = "jdbc:h2:file:./data/%s;DB_CLOSE_DELAY=-1;" + user = "sa" + password = "" + } \ No newline at end of file