Skip to content

Commit

Permalink
chore: docs: EXPOSED-661 Support non-H2 compatible queries in the `ex…
Browse files Browse the repository at this point in the history
…posed-dsl` snippets project (#2329)

* chore: EXPOSED-661 Run queries in `exposed-dsl` against SQLite and MySQL databases

* fix: wrong tab id and element-id provided
  • Loading branch information
vnikolova authored Dec 10, 2024
1 parent cfc7423 commit 6bbceb4
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 55 deletions.
26 changes: 24 additions & 2 deletions documentation-website/Writerside/snippets/exposed-dsl/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,30 @@
# Exposed DSL API examples

A Gradle application that shows how to work with Exposed DSL API.
The files are referenced in the DSL's [CRUD operations](../../topics/DSL-CRUD-operations.topic) and
[Table types](../../topics/DSL-Table-Types.topic) topics.
The files are referenced in the DSL's [CRUD operations](../../topics/DSL-CRUD-operations.topic),
[Querying Data](../../topics/DSL-Querying-data.topic), [Joining tables](../../topics/DSL-Joining-tables.topic),
and [Table types](../../topics/DSL-Table-Types.topic) topics.

## Prerequisites

The project contains examples that run against H2, SQLite, and MySQL databases. While H2 and SQLite make 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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ dependencies {
implementation(libs.exposed.jdbc)
implementation(libs.exposed.kotlin.datetime)
implementation("com.h2database:h2:2.2.224")
implementation("org.xerial:sqlite-jdbc:3.44.1.0")
implementation("mysql:mysql-connector-java:8.0.33")
}

// Apply a specific Java toolchain to ease working on different environments.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.example

import CreateExamples
import org.example.examples.AliasExamples
import org.example.examples.CreateExamples
import org.example.examples.CustomSelectExamples
import org.example.examples.DeleteExamples
import org.example.examples.QueryingExamples
Expand All @@ -16,23 +16,53 @@ import org.jetbrains.exposed.sql.addLogger
import org.jetbrains.exposed.sql.transactions.transaction

fun main() {
Database.connect(
val h2Db = Database.connect(
"jdbc:h2:mem:test",
"org.h2.Driver",
databaseConfig = DatabaseConfig { useNestedTransactions = true }
)

transaction {
val sqliteDb = Database.connect(
"jdbc:sqlite:file:test?mode=memory&cache=shared",
"org.sqlite.JDBC",
databaseConfig = DatabaseConfig { useNestedTransactions = true }
)

val mysqlDb = Database.connect(
"jdbc:mysql://localhost:3306/test",
driver = "com.mysql.cj.jdbc.Driver",
user = "root",
password = "password",
)

transaction(h2Db) {
addLogger(StdOutSqlLogger)
createTables()
runCreateExamples()
runReadExamples()
runUpdateExamples()
runQueryingExamples()
runAliasExamples()
runCustomSelectExamples()
runDeleteExamples()
}

transaction(sqliteDb) {
addLogger(StdOutSqlLogger)
SchemaUtils.create(StarWarsFilmsIntIdTable)
// run examples for insertIgnore and insertIgnoreAndGetId
CreateExamples().insertIgnoreRecords()
}

transaction(mysqlDb) {
addLogger(StdOutSqlLogger)
SchemaUtils.create(StarWarsFilmsIntIdTable)
SchemaUtils.create(ActorsIntIdTable)
runCustomSelectExamples()
// run examples for deleteIgnoreWhere
DeleteExamples().deleteIgnore()
// run examples for joinDelete and joinUpdate
DeleteExamples().joinDelete()
}
}

fun createTables() {
Expand Down Expand Up @@ -72,7 +102,6 @@ fun runUpdateExamples() {
fun runDeleteExamples() {
val deleteExamples = DeleteExamples()
deleteExamples.delete()
deleteExamples.joinDelete()
deleteExamples.deleteAll()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package org.example.examples

import org.example.tables.CitiesTable
import org.example.tables.StarWarsFilmsIntIdTable
import org.example.tables.StarWarsFilmsTable
import org.jetbrains.exposed.sql.*

/*
Important: The SQL statements in this file are referenced by line number in `DSL-CRUD-Operations.topic`.
Important: The contents of this file are referenced by line number in `DSL-CRUD-Operations.topic`.
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 MOVIE_ORIGINAL_ID = 4
private const val MOVIE_SEQUEL_ID = 5
private const val MOVIE_SEQUEL_2_ID = 6
private const val MOVIE_ORIGINAL_2_ID = 5
private const val MOVIE_ORIGINAL_3_ID = 6
private const val MOVIE_SEQUEL_ID = 7
private const val MOVIE_SEQUEL_2_ID = 8

class CreateExamples {
fun createFilmRecords() {
Expand Down Expand Up @@ -42,13 +46,13 @@ class CreateExamples {
}

fun insertIgnoreRecords() {
StarWarsFilmsTable.insert {
StarWarsFilmsIntIdTable.insert {
it[sequelId] = MOVIE_SEQUEL_2_ID // column pre-defined with a unique index
it[name] = "The Last Jedi"
it[director] = "Rian Johnson"
}

StarWarsFilmsTable.insertIgnore {
StarWarsFilmsIntIdTable.insertIgnore {
it[sequelId] = MOVIE_SEQUEL_2_ID
it[name] = "The Last Jedi"
it[director] = "Rian Johnson"
Expand Down Expand Up @@ -79,9 +83,9 @@ class CreateExamples {
data class SWFilmData(val sequelId: Int, val name: String, val director: String)

val films = listOf(
SWFilmData(MOVIE_SEQUEL_ID, "The Empire Strikes Back", "Irvin Kershner"),
SWFilmData(MOVIE_ORIGINAL_ID, "A New Hope", "George Lucas"),
SWFilmData(MOVIE_SEQUEL_2_ID, "Return of the Jedi", "Richard Marquand")
SWFilmData(MOVIE_ORIGINAL_2_ID, "The Empire Strikes Back", "Irvin Kershner"),
SWFilmData(MOVIE_ORIGINAL_3_ID, "Return of the Jedi", "Richard Marquand")
)

StarWarsFilmsTable.batchInsert(films) { (id, name, director) ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.example.examples

import org.example.tables.StarWarsFilmsTable
import org.example.tables.StarWarsFilmsIntIdTable
import org.jetbrains.exposed.sql.Query
import org.jetbrains.exposed.sql.QueryBuilder
import org.jetbrains.exposed.sql.Table
Expand Down Expand Up @@ -40,15 +40,21 @@ class IndexHintQuery(

class CustomSelectExamples {
fun useCustomQueryWithHint() {
transaction {
val originalQuery = StarWarsFilmsTable
.selectAll()
.withDistinct()
.where { StarWarsFilmsTable.sequelId less MOVIE_SEQUEL_ID }
.groupBy(StarWarsFilmsTable.id)

originalQuery.indexHint("FORCE INDEX (PRIMARY)")
.orderBy(StarWarsFilmsTable.sequelId)
}
val originalQuery = StarWarsFilmsIntIdTable
.selectAll()
.withDistinct()
.where { StarWarsFilmsIntIdTable.sequelId less MOVIE_SEQUEL_ID }
.groupBy(StarWarsFilmsIntIdTable.id)

/*
SELECT DISTINCT star_wars_films_table.id, star_wars_films_table.sequel_id, star_wars_films_table.`name`, star_wars_films_table.director
FROM star_wars_films_table
FORCE INDEX (PRIMARY) WHERE star_wars_films_table.sequel_id < 8
GROUP BY star_wars_films_table.id
ORDER BY star_wars_films_table.sequel_id ASC
*/
originalQuery.indexHint("FORCE INDEX (PRIMARY)")
.orderBy(StarWarsFilmsIntIdTable.sequelId)
.forEach { println(it[StarWarsFilmsIntIdTable.name]) }
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
package org.example.examples

import org.example.tables.ActorsTable
import org.example.tables.ActorsIntIdTable
import org.example.tables.StarWarsFilmsIntIdTable
import org.example.tables.StarWarsFilmsTable
import org.jetbrains.exposed.sql.JoinType
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.delete
import org.jetbrains.exposed.sql.deleteAll
import org.jetbrains.exposed.sql.deleteIgnoreWhere
import org.jetbrains.exposed.sql.deleteWhere

private const val MOVIE_SEQUEL_ID = 6
private const val MOVIE_SEQUEL_2_ID = 7
private const val MOVIE_SEQUEL_ID = 7
private const val ACTORS_SEQUEL_ID = 2

class DeleteExamples {
Expand All @@ -24,7 +20,7 @@ class DeleteExamples {
}

fun deleteIgnore() {
val deleteIgnoreRowsCount = StarWarsFilmsTable.deleteIgnoreWhere { StarWarsFilmsTable.sequelId eq MOVIE_SEQUEL_2_ID }
val deleteIgnoreRowsCount = StarWarsFilmsIntIdTable.deleteIgnoreWhere { StarWarsFilmsIntIdTable.sequelId eq MOVIE_SEQUEL_ID }
println(deleteIgnoreRowsCount)
}

Expand All @@ -35,16 +31,27 @@ class DeleteExamples {

fun joinDelete() {
/*
MERGE INTO ACTORS USING STAR_WARS_FILMS_TABLE
ON STAR_WARS_FILMS_TABLE.ID = ACTORS.SEQUEL_ID
WHEN MATCHED AND ACTORS.SEQUEL_ID > 2
THEN DELETE
DELETE actors
FROM star_wars_films_table INNER JOIN actors
ON star_wars_films_table.id = actors.sequel_id
WHERE actors.sequel_id > 2
*/

StarWarsFilmsIntIdTable.insertIgnore {
it[sequelId] = MOVIE_SEQUEL_ID
it[name] = "The Force Awakens"
it[director] = "J.J. Abrams"
}

ActorsIntIdTable.insertIgnore {
it[id] = ACTORS_SEQUEL_ID
it[name] = "Harrison Ford"
it[sequelId] = MOVIE_SEQUEL_ID
}
// val simpleJoin = StarWarsFilmsTable innerJoin ActorsTable
val join = StarWarsFilmsTable.join(ActorsTable, JoinType.INNER, StarWarsFilmsTable.id, ActorsTable.sequelId)
val join = StarWarsFilmsIntIdTable.join(ActorsIntIdTable, JoinType.INNER, StarWarsFilmsIntIdTable.id, ActorsIntIdTable.sequelId)

val deletedActorsCount = join.delete(ActorsTable) { ActorsTable.sequelId greater ACTORS_SEQUEL_ID }
val deletedActorsCount = join.delete(ActorsIntIdTable) { ActorsIntIdTable.sequelId greater ACTORS_SEQUEL_ID }
println(deletedActorsCount)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@
<code>StarWarsFilmsTable</code>:
</p>
<tabs>
<tab id="windows-install" title="StarWarsFilmEntity">
<tab id="StarWarsFilmEntity" title="StarWarsFilmEntity">
<code-block lang="kotlin" src="exposed-dao/src/main/kotlin/org/example/entities/StarWarsFilmEntity.kt"/>
</tab>
<tab id="macos-install" title="StarWarsFilmsTable">
<include from="DAO-Table-Types.topic" element-id="StarWarsFilmsTable-code-block"/>
<tab id="StarWarsFilmsTable" title="StarWarsFilmsTable">
<include from="DAO-Table-Types.topic" element-id="StarWarsFilmsTable-dao-code-block"/>
</tab>
</tabs>
<chapter id="entity-type" title="Entity type">
Expand Down
22 changes: 11 additions & 11 deletions documentation-website/Writerside/topics/DSL-CRUD-operations.topic
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
it throws an exception.</p>
<code-block lang="kotlin"
src="exposed-dsl/src/main/kotlin/org/example/examples/CreateExamples.kt"
include-lines="23-27"/>
include-lines="27-31"/>
<p>The example corresponds to the following SQL statement:</p>
<code-block lang="sql"
src="exposed-dsl/src/main/kotlin/org/example/examples/CreateExamples.kt"
include-lines="19-20"/>
include-lines="23-24"/>
</chapter>

<chapter id="insertAndGetId">
Expand All @@ -44,7 +44,7 @@
include-symbol="id"/>
<code-block lang="sql"
src="exposed-dsl/src/main/kotlin/org/example/examples/CreateExamples.kt"
include-lines="32-33"/>
include-lines="36-37"/>
</chapter>

<chapter id="insertIgnore">
Expand All @@ -62,18 +62,18 @@

<code-block lang="kotlin"
src="exposed-dsl/src/main/kotlin/org/example/examples/CreateExamples.kt"
include-lines="45-56"/>
include-lines="49-60"/>
<p>
If <code>insert</code> was used instead of <code>insertIgnore</code>, this would throw a constraint violation exception
Instead, this new row is ignored and discarded.
If <code>insert</code> was used instead of <code>insertIgnore</code>, this would throw a constraint
violation exception. Instead, this new row is ignored and discarded.
</p>
</chapter>

<chapter id="insertIgnoreAndGetId">
<title><code>insertIgnoreAndGetId</code></title>
<tldr>
<p>Supported on: MySQL, PostgreSQL, and SQLite</p>
<p>Table types: <code>IntIdTable()</code> </p>
<p>Supported on: MySQL, MariaDB, PostgreSQL, and SQLite</p>
<p>Table types: <code>IdTable()</code> </p>
</tldr>
<p>
<a href="https://jetbrains.github.io/Exposed/api/exposed-core/org.jetbrains.exposed.sql/insert-ignore-and-get-id.html">
Expand All @@ -87,7 +87,7 @@
include-symbol="rowId"/>
<code-block lang="sql"
src="exposed-dsl/src/main/kotlin/org/example/examples/CreateExamples.kt"
include-lines="58-59"/>
include-lines="62-63"/>
</chapter>

<chapter id="batch-insert">
Expand All @@ -102,11 +102,11 @@
<p>The following example uses a simple list:</p>
<code-block lang="kotlin"
src="exposed-dsl/src/main/kotlin/org/example/examples/CreateExamples.kt"
include-lines="71-75"/>
include-lines="75-79"/>
<p>Here is an example that uses a list of data class instances:</p>
<code-block lang="kotlin"
src="exposed-dsl/src/main/kotlin/org/example/examples/CreateExamples.kt"
include-lines="79-91"/>
include-lines="83-95"/>
<note>
The <code>batchInsert</code> function will still create multiple <code>INSERT</code> statements when
interacting with your database.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,6 @@
include-lines="4-6,9,18-39"/>
<code-block lang="kotlin"
src="exposed-dsl/src/main/kotlin/org/example/examples/CustomSelectExamples.kt"
include-lines="43-52"/>
include-lines="43-48,56-58"/>
</chapter>
</topic>

0 comments on commit 6bbceb4

Please sign in to comment.