🚧 Starts rework of database

This commit is contained in:
Daniel Svitan 2025-05-11 12:48:41 +02:00
parent 42544a2478
commit aa3e82010f
7 changed files with 105 additions and 75 deletions

View File

@ -33,7 +33,7 @@ dependencies {
implementation("io.ktor:ktor-serialization-kotlinx-json")
implementation("org.jetbrains.exposed:exposed-core:$exposed_version")
implementation("org.jetbrains.exposed:exposed-jdbc:$exposed_version")
implementation("com.h2database:h2:$h2_version")
implementation("org.postgresql:postgresql:42.7.2")
implementation("io.github.flaxoos:ktor-server-rate-limiting:2.2.1")
implementation("io.ktor:ktor-server-compression")
implementation("io.ktor:ktor-server-netty")

14
backend/compose.yaml Normal file
View File

@ -0,0 +1,14 @@
version: "3.3"
services:
postgres:
image: postgres:17
restart: on-failure
environment:
POSTGRES_USER: "user"
POSTGRES_PASSWORD: "password"
POSTGRES_DB: "db"
ports:
- "5432:5432"

View File

@ -10,6 +10,7 @@ import dev.svitan.plugins.configureHTTP
import dev.svitan.plugins.configureMonitoring
import dev.svitan.plugins.configureRouting
import dev.svitan.plugins.configureSecurity
import dev.svitan.plugins.configureSerialization
fun main() {
embeddedServer(
@ -25,8 +26,9 @@ fun Application.module() {
configureHTTP()
configureRouting()
configureDatabases()
configureMonitoring()
configureSerialization()
configureAdministration()
configureSecurity(dotenv)
configureDatabases(dotenv)
}

View File

@ -1,62 +0,0 @@
package dev.svitan
import kotlinx.coroutines.Dispatchers
import kotlinx.serialization.Serializable
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
import org.jetbrains.exposed.sql.transactions.transaction
@Serializable
data class ExposedUser(val name: String, val age: Int)
class UserService(database: Database) {
object Users : Table() {
val id = integer("id").autoIncrement()
val name = varchar("name", length = 50)
val age = integer("age")
override val primaryKey = PrimaryKey(id)
}
init {
transaction(database) {
SchemaUtils.create(Users)
}
}
suspend fun create(user: ExposedUser): Int = dbQuery {
Users.insert {
it[name] = user.name
it[age] = user.age
}[Users.id]
}
suspend fun read(id: Int): ExposedUser? {
return dbQuery {
Users.selectAll()
.where { Users.id eq id }
.map { ExposedUser(it[Users.name], it[Users.age]) }
.singleOrNull()
}
}
suspend fun update(id: Int, user: ExposedUser) {
dbQuery {
Users.update({ Users.id eq id }) {
it[name] = user.name
it[age] = user.age
}
}
}
suspend fun delete(id: Int) {
dbQuery {
Users.deleteWhere { Users.id.eq(id) }
}
}
private suspend fun <T> dbQuery(block: suspend () -> T): T =
newSuspendedTransaction(Dispatchers.IO) { block() }
}

View File

@ -1,26 +1,34 @@
package dev.svitan.plugins
import dev.svitan.schemas.UserDTO
import dev.svitan.schemas.UserService
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import org.jetbrains.exposed.sql.Database
import dev.svitan.ExposedUser
import dev.svitan.UserService
import io.github.cdimascio.dotenv.Dotenv
fun Application.configureDatabases() {
val database = Database.connect(
url = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1",
user = "root",
driver = "org.h2.Driver",
password = "",
fun Application.configureDatabases(dotenv: Dotenv) {
val dbHost = dotenv["DB_HOST"] ?: throw Exception("DB_HOST not found")
val dbPort = dotenv["DB_PORT"] ?: throw Exception("DB_PORT not found")
val dbName = dotenv["DB_NAME"] ?: throw Exception("DB_NAME not found")
val dbUser = dotenv["DB_USER"] ?: throw Exception("DB_USER not found")
val dbPassword = dotenv["DB_PASSWORD"] ?: throw Exception("DB_PASSWORD not found")
Database.connect(
url = "jdbc:postgresql://${dbHost}:${dbPort}/${dbName}",
driver = "org.postgresql.Driver",
user = dbUser,
password = dbPassword
)
val userService = UserService(database)
val userService = UserService()
routing {
// Create user
post("/users") {
val user = call.receive<ExposedUser>()
val user = call.receive<UserDTO>()
val id = userService.create(user)
call.respond(HttpStatusCode.Created, id)
}
@ -39,7 +47,7 @@ fun Application.configureDatabases() {
// Update user
put("/users/{id}") {
val id = call.parameters["id"]?.toInt() ?: throw IllegalArgumentException("Invalid ID")
val user = call.receive<ExposedUser>()
val user = call.receive<UserDTO>()
userService.update(id, user)
call.respond(HttpStatusCode.OK)
}

View File

@ -0,0 +1,12 @@
package dev.svitan.plugins
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.Application
import io.ktor.server.application.install
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
fun Application.configureSerialization() {
install(ContentNegotiation) {
json()
}
}

View File

@ -0,0 +1,56 @@
package dev.svitan.schemas
import kotlinx.serialization.Serializable
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.transactions.transaction
@Serializable
data class UserDTO(val name: String, val age: Int)
class UserService {
object Users : Table("users") {
val id = integer("id").autoIncrement()
val name = varchar("name", length = 50)
val age = integer("age")
override val primaryKey = PrimaryKey(id)
}
init {
transaction {
SchemaUtils.create(Users)
}
}
fun create(user: UserDTO): Int =
transaction {
Users.insert {
it[name] = user.name
it[age] = user.age
}[Users.id]
}
fun read(id: Int): UserDTO? =
transaction {
Users.selectAll()
.where { Users.id eq id }
.map { UserDTO(it[Users.name], it[Users.age]) }
.singleOrNull()
}
fun update(id: Int, user: UserDTO) {
transaction {
Users.update({ Users.id eq id }) {
it[name] = user.name
it[age] = user.age
}
}
}
fun delete(id: Int) {
transaction {
Users.deleteWhere { Users.id.eq(id) }
}
}
}