Exposed
—
(Shengyou Fan)
GDG DevFest Kaohsiung
2019/12/07
—
• Developer Advocate
• Backend Developer
• Open Source Community Organizer
Kotlin https://youtu.be/hg8oYJ8Ez8s
• General-purpose
• Static typing
• OOP + FP
• Developed by
JetBrains
• Open Source
(Apache 2.0)
https://kotlinlang.org/
Kotlin
—
Kotlin
—
Browser
Kotlin/JS
Server
Kotlin/JVM
iOS
Kotlin/Native
Android
Kotlin/JVM
Exposed SQL
—
https://github.com/JetBrains/Exposed
• SQL
• 100% Kotlin
•
• Developed by
JetBrains
• Open Source
(Apache 2.0)
—
PostgreSQL SQLite Oracle
SQL Server
—
DSL DAO
typesafe SQL wrapping DSL lightweight data access objects
Exposed
—
// gradle.properties
exposed_version=0.17.7
mysql_connector_version=5.1.46
// build.gradle
dependencies {
//...
implementation "org.jetbrains.exposed:exposed:$ver"
implementation "mysql:mysql-connector-java:$ver"
}
MySQL
—
version: "2"
services:
database:
image: mysql:5.7
ports:
- "...:3306"
environment:
MYSQL_ROOT_PASSWORD: ...
MYSQL_DATABASE: ...
command: ...
—
object Books : Table() {
val id: Column<Int> = integer("id")
.autoIncrement()
.primaryKey()
val title: Column<String> = varchar("title", 255)
val isbn: Column<String> = varchar("isbn", 13)
val publishedAt: Column<DateTime> = datetime("...")
}
object Books : IntIdTable() {
val title = varchar("title", 255)
val isbn = varchar("isbn", 13)
val publishedAt = datetime("...")
}
DAO
—
class Book(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<Book>(Books)
var title by Books.title
var isbn by Books.isbn
var publishedAt by Books.publishedAt
}
—
Database.connect(
url = "...",
driver = "com.mysql.jdbc.Driver",
user = "...",
password = "..."
)
—
transaction {
// ...
SchemaUtils.drop(…)
// ...
SchemaUtils.create(...)
}
JavaFaker
—
// gradle.properties
javafaker_version=1.0.1
// build.gradle
dependencies {
//...
implementation "com.github.javafaker:javafaker:$ver"
}
// create
Books.insert {
it[...] = ...
}
// read
Books.selectAll()
Books.select { ... }
.orderBy(... to SortOrder.ASC)
// update
Books.update({ ... }) {
it[...] = ...
}
// delete
Books.deleteWhere {
...
}
CRUD (DSL)
—
// create
Book.new {
title = ...
}
// read
Book.all()
Book.find { ... }
.sortedBy { it.id }
// update
val book = Book.findById(...)
if (book != null) {
book.title = ...
}
// delete
val book = Book.findById(1)
book?.delete()
CRUD (DAO)
—
object Books : IntIdTable() {
val title = varchar("title", 255)
val isbn = varchar("isbn", 13)
val publishedAt = datetime(“published_at")
val author = reference("author", Authors)
}
object Authors: IntIdTable() {
val name = varchar("name", 255)
}
(Table)
—
class Book(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<Book>(Books)
var title by Books.title
var isbn by Books.isbn
var publishedAt by Books.publishedAt
var author by Author referencedOn Books.author
}
class Author(id: EntityID<Int>): IntEntity(id) {
companion object: IntEntityClass<Author>(Authors)
var name by Authors.name
val books by Book referrersOn Books.author
}
(Entity)
—
Book.all().map {
println("(${it.title} by ${it.author.name}")
}
Author.all().map { author ->
author.books.forEach {
println("${author.name} wrote ${it.title}")
}
}
—
Ktor
—
https://ktor.io/
• Web Framework
• Asynchronous
• Servers + Clients
• Developed by
JetBrains
• Open Source
(Apache 2.0)
JSON API
—
// define respond class
data class BookRespond(
val title:String,
val author: String,
val isbn: String,
val publishedAt: String
)
// define api
get("/api/v1/books") {
val books = transaction {
Book.all().sortedByDescending { it.id }.map {
BookRespond(
title = it.title,
isbn = it.isbn,
publishedAt = ...,
author = it.author.name
)
}
}
call.respond(mapOf("books" to books))
}
—
• Exposed
• DSL
• DAO
• Migration & Seeding
•
• Ktor JSON API
—
https://github.com/shengyou/exposed-sample
ktor.guide
Ktor
—
(Shengyou)
shengyou.fan@jetbrains.com
Q&A
—
Exposed

運用 Exposed 管理及操作資料庫