diff --git a/documentation-website/Writerside/snippets/exposed-dsl/README.md b/documentation-website/Writerside/snippets/exposed-dsl/README.md index a0d437fbbe..2b72959174 100644 --- a/documentation-website/Writerside/snippets/exposed-dsl/README.md +++ b/documentation-website/Writerside/snippets/exposed-dsl/README.md @@ -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 diff --git a/documentation-website/Writerside/snippets/exposed-dsl/build.gradle.kts b/documentation-website/Writerside/snippets/exposed-dsl/build.gradle.kts index 1f9cea56a8..301fb02a11 100644 --- a/documentation-website/Writerside/snippets/exposed-dsl/build.gradle.kts +++ b/documentation-website/Writerside/snippets/exposed-dsl/build.gradle.kts @@ -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. diff --git a/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/App.kt b/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/App.kt index abfe5e0f84..b7e9ec3c58 100644 --- a/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/App.kt +++ b/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/App.kt @@ -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 @@ -16,13 +16,26 @@ 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() @@ -30,9 +43,26 @@ fun main() { 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() { @@ -72,7 +102,6 @@ fun runUpdateExamples() { fun runDeleteExamples() { val deleteExamples = DeleteExamples() deleteExamples.delete() - deleteExamples.joinDelete() deleteExamples.deleteAll() } diff --git a/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/examples/CreateExamples.kt b/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/examples/CreateExamples.kt index fc8f57a1c6..63afe03f4f 100644 --- a/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/examples/CreateExamples.kt +++ b/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/examples/CreateExamples.kt @@ -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() { @@ -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" @@ -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) -> diff --git a/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/examples/CustomSelectExamples.kt b/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/examples/CustomSelectExamples.kt index e22427da4b..34f8517735 100644 --- a/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/examples/CustomSelectExamples.kt +++ b/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/examples/CustomSelectExamples.kt @@ -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 @@ -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]) } } } diff --git a/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/examples/DeleteExamples.kt b/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/examples/DeleteExamples.kt index daa1443dd0..867305319b 100644 --- a/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/examples/DeleteExamples.kt +++ b/documentation-website/Writerside/snippets/exposed-dsl/src/main/kotlin/org/example/examples/DeleteExamples.kt @@ -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 { @@ -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) } @@ -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) } } diff --git a/documentation-website/Writerside/topics/DAO-Entity-definition.topic b/documentation-website/Writerside/topics/DAO-Entity-definition.topic index 303c9a9a1e..aadc3e3dd3 100644 --- a/documentation-website/Writerside/topics/DAO-Entity-definition.topic +++ b/documentation-website/Writerside/topics/DAO-Entity-definition.topic @@ -22,11 +22,11 @@ StarWarsFilmsTable:

- + - - + + diff --git a/documentation-website/Writerside/topics/DSL-CRUD-operations.topic b/documentation-website/Writerside/topics/DSL-CRUD-operations.topic index 209c485c17..0fba69a6c2 100644 --- a/documentation-website/Writerside/topics/DSL-CRUD-operations.topic +++ b/documentation-website/Writerside/topics/DSL-CRUD-operations.topic @@ -21,11 +21,11 @@ it throws an exception.

+ include-lines="27-31"/>

The example corresponds to the following SQL statement:

+ include-lines="23-24"/>
@@ -44,7 +44,7 @@ include-symbol="id"/> + include-lines="36-37"/> @@ -62,18 +62,18 @@ + include-lines="49-60"/>

- If insert was used instead of insertIgnore, this would throw a constraint violation exception - Instead, this new row is ignored and discarded. + If insert was used instead of insertIgnore, this would throw a constraint + violation exception. Instead, this new row is ignored and discarded.

<code>insertIgnoreAndGetId</code> -

Supported on: MySQL, PostgreSQL, and SQLite

-

Table types: IntIdTable()

+

Supported on: MySQL, MariaDB, PostgreSQL, and SQLite

+

Table types: IdTable()

@@ -87,7 +87,7 @@ include-symbol="rowId"/> + include-lines="62-63"/> @@ -102,11 +102,11 @@

The following example uses a simple list:

+ include-lines="75-79"/>

Here is an example that uses a list of data class instances:

+ include-lines="83-95"/> The batchInsert function will still create multiple INSERT statements when interacting with your database. diff --git a/documentation-website/Writerside/topics/DSL-Querying-data.topic b/documentation-website/Writerside/topics/DSL-Querying-data.topic index 8a22e8d725..7f0c481969 100644 --- a/documentation-website/Writerside/topics/DSL-Querying-data.topic +++ b/documentation-website/Writerside/topics/DSL-Querying-data.topic @@ -316,6 +316,6 @@ include-lines="4-6,9,18-39"/> + include-lines="43-48,56-58"/>