-
Notifications
You must be signed in to change notification settings - Fork 697
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: EXPOSED-684 Add documentation for exec() and move transaction d…
…ocs to new element - Move Transactions.md to a new top-level element (Transactions) - Separate section on statement interceptors to its own topic - Create new topic about working with SQL strings with exec() - Put example code for new topic in new exposed-transactions snippets project
- Loading branch information
Showing
15 changed files
with
456 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
documentation-website/Writerside/snippets/exposed-transactions/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Exposed SQL Functions examples | ||
|
||
A Gradle application that shows how to perform units of work with database transactions using Exposed API. | ||
The files are referenced in the Transactions's [Working with SQL Strings](../../topics/Working-with-SQL-Strings.md) topic. | ||
|
||
## Prerequisites | ||
|
||
The project contains examples that run against H2 and MySQL databases. While H2 makes use of | ||
in-memory storage, in order to run queries against MySQL, you must first install MySQL and create a local database. | ||
|
||
To learn how to install MySQL, see the [installation guide](https://dev.mysql.com/doc/refman/8.4/en/installing.html). | ||
|
||
## Database configuration | ||
|
||
All database connections are configured within the `App.kt` file located in `src/main/kotlin/org/example/`. | ||
You might want to adjust the MySQL database configuration to match your local setup. | ||
|
||
```kotlin | ||
val mysqlDb = Database.connect( | ||
"jdbc:mysql://localhost:3306/test", | ||
driver = "com.mysql.cj.jdbc.Driver", | ||
user = "root", | ||
password = "password" | ||
) | ||
``` | ||
|
||
## Build | ||
|
||
To build the application, in a terminal window navigate to the `snippets` folder and run the following command: | ||
|
||
```shell | ||
./gradlew :exposed-sql-functions:build | ||
``` | ||
|
||
## Run | ||
|
||
To run the application, in a terminal window navigate to the `snippets` folder and run the following command: | ||
|
||
```shell | ||
./gradlew :exposed-sql-functions:run | ||
``` | ||
|
||
This will run queries to create new tables and run all functions in the `/examples` folder. | ||
To only run a specific example, modify the `App.kt` file and re-run the project. |
47 changes: 47 additions & 0 deletions
47
documentation-website/Writerside/snippets/exposed-transactions/build.gradle.kts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
plugins { | ||
// Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. | ||
alias(libs.plugins.jvm) | ||
|
||
// Apply the application plugin to add support for building a CLI application in Java. | ||
application | ||
} | ||
|
||
repositories { | ||
// Use Maven Central for resolving dependencies. | ||
mavenCentral() | ||
} | ||
|
||
dependencies { | ||
// Use the Kotlin JUnit 5 integration. | ||
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") | ||
|
||
// Use the JUnit 5 integration. | ||
testImplementation(libs.junit.jupiter.engine) | ||
|
||
testRuntimeOnly("org.junit.platform:junit-platform-launcher") | ||
|
||
// This dependency is used by the application. | ||
implementation(libs.guava) | ||
implementation(libs.exposed.core) | ||
implementation(libs.exposed.jdbc) | ||
implementation(libs.h2) | ||
implementation("mysql:mysql-connector-java:8.0.33") | ||
implementation(libs.slf4j) | ||
} | ||
|
||
// Apply a specific Java toolchain to ease working on different environments. | ||
java { | ||
toolchain { | ||
languageVersion = JavaLanguageVersion.of(21) | ||
} | ||
} | ||
|
||
application { | ||
// Define the main class for the application. | ||
mainClass = "org.example.AppKt" | ||
} | ||
|
||
tasks.named<Test>("test") { | ||
// Use JUnit Platform for unit tests. | ||
useJUnitPlatform() | ||
} |
51 changes: 51 additions & 0 deletions
51
...ation-website/Writerside/snippets/exposed-transactions/src/main/kotlin/org/example/App.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package org.example | ||
|
||
import org.example.examples.ExecExamples | ||
import org.example.examples.ExecMySQLExamples | ||
import org.example.tables.FilmsTable | ||
import org.jetbrains.exposed.sql.Database | ||
import org.jetbrains.exposed.sql.DatabaseConfig | ||
import org.jetbrains.exposed.sql.SchemaUtils | ||
import org.jetbrains.exposed.sql.StdOutSqlLogger | ||
import org.jetbrains.exposed.sql.addLogger | ||
import org.jetbrains.exposed.sql.transactions.transaction | ||
|
||
fun main() { | ||
val h2Db = Database.connect( | ||
"jdbc:h2:mem:test", | ||
"org.h2.Driver", | ||
databaseConfig = DatabaseConfig { useNestedTransactions = true } | ||
) | ||
|
||
val mysqlDb = Database.connect( | ||
"jdbc:mysql://localhost:3306/test?allowMultiQueries=true", | ||
driver = "com.mysql.cj.jdbc.Driver", | ||
user = "root", | ||
password = "password", | ||
) | ||
|
||
transaction(h2Db) { | ||
addLogger(StdOutSqlLogger) | ||
SchemaUtils.create(FilmsTable) | ||
runExecExamples() | ||
} | ||
|
||
transaction(mysqlDb) { | ||
addLogger(StdOutSqlLogger) | ||
SchemaUtils.create(FilmsTable) | ||
runExecMySQLExamples() | ||
} | ||
} | ||
|
||
fun runExecExamples() { | ||
val execExamples = ExecExamples() | ||
execExamples.execBasicStrings() | ||
execExamples.execAndMapResult() | ||
execExamples.execWithParameters() | ||
execExamples.execWithTypeOverride() | ||
} | ||
|
||
fun runExecMySQLExamples() { | ||
val execMySQLExamples = ExecMySQLExamples() | ||
execMySQLExamples.execMultipleStrings() | ||
} |
14 changes: 14 additions & 0 deletions
14
.../snippets/exposed-transactions/src/main/kotlin/org/example/examples/ExecAndMapFunction.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package org.example.examples | ||
|
||
import org.jetbrains.exposed.sql.transactions.TransactionManager | ||
import java.sql.ResultSet | ||
|
||
fun <T : Any> String.execAndMap(transform: (ResultSet) -> T): List<T> { | ||
val result = mutableListOf<T>() | ||
TransactionManager.current().exec(this) { rs -> | ||
while (rs.next()) { | ||
result += transform(rs) | ||
} | ||
} | ||
return result | ||
} |
114 changes: 114 additions & 0 deletions
114
...erside/snippets/exposed-transactions/src/main/kotlin/org/example/examples/ExecExamples.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package org.example.examples | ||
|
||
import org.example.tables.FilmsTable | ||
import org.jetbrains.exposed.sql.BooleanColumnType | ||
import org.jetbrains.exposed.sql.DoubleColumnType | ||
import org.jetbrains.exposed.sql.StdOutSqlLogger | ||
import org.jetbrains.exposed.sql.addLogger | ||
import org.jetbrains.exposed.sql.insert | ||
import org.jetbrains.exposed.sql.statements.StatementType | ||
import org.jetbrains.exposed.sql.transactions.transaction | ||
|
||
/* | ||
Important: This file is referenced by line number in `Working-with-SQL-Strings.md`. | ||
If you add, remove, or modify any lines, ensure you update the corresponding | ||
line numbers in the `code-block` element of the referenced file. | ||
*/ | ||
|
||
private const val GOOD_RATING = 9.0 | ||
private const val BAD_RATING = 2.1 | ||
|
||
class ExecExamples { | ||
fun execBasicStrings() { | ||
transaction { | ||
addLogger(StdOutSqlLogger) | ||
|
||
val secretCode = "abc" | ||
exec("CREATE USER IF NOT EXISTS GUEST PASSWORD '$secretCode'") | ||
exec("GRANT ALL PRIVILEGES ON ${FilmsTable.nameInDatabaseCase()} TO GUEST") | ||
|
||
val version = exec("SELECT H2VERSION()") { result -> | ||
result.next() | ||
result.getString(1) | ||
} | ||
println(version) | ||
|
||
val schema = "TABLE_SCHEMA" | ||
val name = "TABLE_NAME" | ||
val rowCount = "ROW_COUNT_ESTIMATE" | ||
val tableInfo = exec("SELECT $schema, $name, $rowCount FROM INFORMATION_SCHEMA.TABLES") { result -> | ||
val info = mutableListOf<Triple<String, String, Int>>() | ||
while (result.next()) { | ||
info += Triple(result.getString(schema), result.getString(name), result.getInt(rowCount)) | ||
} | ||
info | ||
} ?: emptyList() | ||
println(tableInfo.last()) | ||
|
||
exec( | ||
stmt = "DROP USER IF EXISTS GUEST", | ||
explicitStatementType = StatementType.DROP | ||
) | ||
} | ||
} | ||
|
||
fun execAndMapResult() { | ||
transaction { | ||
addLogger(StdOutSqlLogger) | ||
|
||
FilmsTable.insert { | ||
it[title] = "The Good Film" | ||
it[rating] = GOOD_RATING | ||
it[nominated] = true | ||
} | ||
FilmsTable.insert { | ||
it[title] = "The Bad Film" | ||
it[rating] = BAD_RATING | ||
it[nominated] = false | ||
} | ||
|
||
val toIgnore = "SELECT FILMS.ID, FILMS.TITLE FROM FILMS WHERE FILMS.RATING <= 3.0".execAndMap { result -> | ||
result.getInt("FILMS.ID") to result.getString("FILMS.TITLE") | ||
} | ||
println(toIgnore) | ||
} | ||
} | ||
|
||
fun execWithParameters() { | ||
transaction { | ||
addLogger(StdOutSqlLogger) | ||
|
||
val toWatch = exec( | ||
stmt = "SELECT FILMS.ID, FILMS.TITLE FROM FILMS WHERE (FILMS.NOMINATED = ?) AND (FILMS.RATING >= ?)", | ||
args = listOf(BooleanColumnType() to true, DoubleColumnType() to GOOD_RATING) | ||
) { result -> | ||
val films = mutableListOf<Pair<Int, String>>() | ||
while (result.next()) { | ||
films += result.getInt(1) to result.getString(2) | ||
} | ||
films | ||
} | ||
println(toWatch) | ||
} | ||
} | ||
|
||
fun execWithTypeOverride() { | ||
transaction { | ||
addLogger(StdOutSqlLogger) | ||
|
||
val plan = exec( | ||
stmt = "EXPLAIN SELECT * FROM FILMS WHERE FILMS.ID = 1", | ||
explicitStatementType = StatementType.EXEC | ||
) { result -> | ||
val data = mutableListOf<Pair<String, Any?>>() | ||
while (result.next()) { | ||
repeat(result.metaData.columnCount) { | ||
data += result.metaData.getColumnName(it + 1) to result.getObject(it + 1) | ||
} | ||
} | ||
data | ||
} ?: emptyList() | ||
println(plan) | ||
} | ||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
...e/snippets/exposed-transactions/src/main/kotlin/org/example/examples/ExecMySQLExamples.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package org.example.examples | ||
|
||
import org.jetbrains.exposed.sql.BooleanColumnType | ||
import org.jetbrains.exposed.sql.DoubleColumnType | ||
import org.jetbrains.exposed.sql.StdOutSqlLogger | ||
import org.jetbrains.exposed.sql.VarCharColumnType | ||
import org.jetbrains.exposed.sql.addLogger | ||
import org.jetbrains.exposed.sql.statements.StatementType | ||
import org.jetbrains.exposed.sql.transactions.transaction | ||
|
||
/* | ||
Important: This file is referenced by line number in `Working-with-SQL-Strings.md`. | ||
If you add, remove, or modify any lines, ensure you update the corresponding | ||
line numbers in the `code-block` element of the referenced file. | ||
*/ | ||
|
||
private const val MAX_TITLE_LENGTH = 150 | ||
private const val NEW_TITLE = "The New Film" | ||
private const val NEW_RATING = 9.0 | ||
|
||
class ExecMySQLExamples { | ||
fun execMultipleStrings() { | ||
transaction { | ||
addLogger(StdOutSqlLogger) | ||
|
||
val insertStmt = "INSERT INTO Films (title, rating, nominated) VALUES (?, ?, ?)" | ||
val lastIdAlias = "last_id" | ||
val selectStmt = "SELECT LAST_INSERT_ID() AS $lastIdAlias" | ||
val lastId = exec( | ||
stmt = "$insertStmt; $selectStmt;", | ||
args = listOf( | ||
VarCharColumnType(MAX_TITLE_LENGTH) to NEW_TITLE, | ||
DoubleColumnType() to NEW_RATING, | ||
BooleanColumnType() to false | ||
), | ||
explicitStatementType = StatementType.MULTI | ||
) { result -> | ||
result.next() | ||
result.getInt(lastIdAlias) | ||
} | ||
println(lastId) | ||
} | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
...Writerside/snippets/exposed-transactions/src/main/kotlin/org/example/tables/FilmsTable.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package org.example.tables | ||
|
||
import org.jetbrains.exposed.sql.Table | ||
|
||
const val MAX_TITLE_LENGTH = 150 | ||
|
||
object FilmsTable : Table() { | ||
val id = integer("id").autoIncrement() | ||
val title = varchar("title", MAX_TITLE_LENGTH) | ||
val rating = double("rating") | ||
val nominated = bool("nominated") | ||
|
||
override val primaryKey = PrimaryKey(id) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.