feat(01-02): create Quill PostgreSQL context with ZIO integration

- Add QuillContext with dataSourceLayer and quillLayer
- Update application.conf for HikariCP-compatible format
- Export combined quillLive layer for database access
This commit is contained in:
Jakub Zych
2026-02-04 22:00:33 +01:00
parent bcf928da77
commit 106e66413e
2 changed files with 74 additions and 0 deletions

View File

@@ -5,6 +5,7 @@ server {
port = ${?SERVER_PORT}
}
# Database configuration for ZIO config (used by AppConfig)
database {
host = "localhost"
host = ${?DB_HOST}
@@ -17,3 +18,24 @@ database {
password = "summercms"
password = ${?DB_PASSWORD}
}
# HikariCP configuration for Quill DataSource
# Reads from "database" prefix via Quill.DataSource.fromPrefix
database {
dataSourceClassName = "org.postgresql.ds.PGSimpleDataSource"
dataSource {
serverName = "localhost"
serverName = ${?DB_HOST}
portNumber = 5432
portNumber = ${?DB_PORT}
databaseName = "summercms"
databaseName = ${?DB_NAME}
user = "summercms"
user = ${?DB_USER}
password = "summercms"
password = ${?DB_PASSWORD}
}
# HikariCP pool settings
maximumPoolSize = 10
connectionTimeout = 30000
}

View File

@@ -0,0 +1,52 @@
package db
import io.getquill.*
import io.getquill.jdbczio.Quill
import zio.*
import javax.sql.DataSource
/** Quill PostgreSQL context with ZIO integration
*
* Provides compile-time SQL query validation via Quill. Exports two layers:
* - dataSourceLayer: HikariCP-managed connection pool configured from application.conf
* - quillLayer: Quill PostgreSQL context with SnakeCase naming strategy
*
* Usage:
* {{{
* import db.QuillContext.*
*
* def findUser(email: String) =
* run(query[SummerUser].filter(_.email == lift(email)))
* .provide(quillLive)
* }}}
*
* IMPORTANT: Never use "io" as a variable name in files importing Quill
* (conflicts with io.getquill package).
*/
object QuillContext {
/** DataSource layer from HikariCP configuration
*
* Reads configuration from "database" prefix in application.conf.
* HikariCP manages the connection pool.
*/
val dataSourceLayer: ZLayer[Any, Throwable, DataSource] =
Quill.DataSource.fromPrefix("database")
/** Quill PostgreSQL context with snake_case naming
*
* Converts Scala camelCase field names to PostgreSQL snake_case columns.
* Example: passwordHash -> password_hash
*/
val quillLayer: ZLayer[DataSource, Nothing, Quill.Postgres[SnakeCase]] =
Quill.Postgres.fromNamingStrategy(SnakeCase)
/** Combined layer for full Quill PostgreSQL access
*
* Provides both DataSource and Quill context.
* Use this when you need to run queries.
*/
val quillLive: ZLayer[Any, Throwable, Quill.Postgres[SnakeCase]] =
dataSourceLayer >>> quillLayer
}