Skip to content

Commit

Permalink
docs: EXPOSED-640 Update and extract DSL code snippets to a snippets …
Browse files Browse the repository at this point in the history
…project (#2321)

* Reference DSL code from a snippets project

* Move joining tables to a separate topic and add API links to CRUD operations

* Improve condition group titles and edit subchapters to include intros
  • Loading branch information
vnikolova authored Dec 5, 2024
1 parent f608246 commit 6c63a2c
Show file tree
Hide file tree
Showing 31 changed files with 1,533 additions and 657 deletions.
1 change: 1 addition & 0 deletions documentation-website/Writerside/hi.tree
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
</toc-element>
<toc-element toc-title="Deep Dive into DSL">
<toc-element topic="DSL-Table-Types.topic"/>
<toc-element topic="DSL-Joining-tables.topic"/>
<toc-element topic="DSL-CRUD-operations.topic"/>
<toc-element topic="Working-with-Sequence.topic"/>
<toc-element topic="DSL-Querying-data.topic"/>
Expand Down
24 changes: 24 additions & 0 deletions documentation-website/Writerside/snippets/exposed-dsl/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# 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.

## Build

To build the application, in a terminal window navigate to the `snippets` folder and run the following command:

```shell
./gradlew :exposed-dsl:build
```

## Run

To run the application, in a terminal window navigate to the `snippets` folder and run the following command:

```shell
./gradlew :exposed-dsl: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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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.exposed.kotlin.datetime)
implementation("com.h2database:h2:2.2.224")
}

// 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()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package org.example

import CreateExamples
import org.example.examples.AliasExamples
import org.example.examples.CustomSelectExamples
import org.example.examples.DeleteExamples
import org.example.examples.QueryingExamples
import org.example.examples.ReadExamples
import org.example.examples.UpdateExamples
import org.example.tables.*
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() {
Database.connect(
"jdbc:h2:mem:test",
"org.h2.Driver",
databaseConfig = DatabaseConfig { useNestedTransactions = true }
)

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

fun createTables() {
val tables = listOf(
StarWarsFilmsTable,
StarWarsFilmsIntIdTable,
CitiesTable,
ActorsTable,
CitiesTable,
UsersTable
)

tables.forEach { table ->
SchemaUtils.create(table)
}
}

fun runCreateExamples() {
val createExamples = CreateExamples()
createExamples.createFilmRecords()
createExamples.createIntIdFilmRecords()
createExamples.simpleBatchInsert()
createExamples.batchInsert()
}

fun runReadExamples() {
val readExamples = ReadExamples()
readExamples.read()
readExamples.readAll()
}

fun runUpdateExamples() {
val updateExamples = UpdateExamples()
updateExamples.updateRecords()
}

fun runDeleteExamples() {
val deleteExamples = DeleteExamples()
deleteExamples.delete()
deleteExamples.joinDelete()
deleteExamples.deleteAll()
}

fun runQueryingExamples() {
val queryingExamples = QueryingExamples()
queryingExamples.useWhereConditions()
}

fun runAliasExamples() {
val aliasExamples = AliasExamples()
aliasExamples.useAlias()
}

fun runCustomSelectExamples() {
val customSelectExamples = CustomSelectExamples()
customSelectExamples.useCustomQueryWithHint()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.example.examples

import org.example.tables.StarWarsFilmsTable
import org.jetbrains.exposed.sql.JoinType
import org.jetbrains.exposed.sql.alias
import org.jetbrains.exposed.sql.selectAll

class AliasExamples {
fun useAlias() {
val filmTable1 = StarWarsFilmsTable.alias("ft1")
val allFilms = filmTable1.selectAll() // can be used in joins etc'
println(allFilms)

// use the same table in a join multiple times
val sequelTable = StarWarsFilmsTable.alias("sql")
val originalAndSequelNames = StarWarsFilmsTable
.join(sequelTable, JoinType.INNER, StarWarsFilmsTable.sequelId, sequelTable[StarWarsFilmsTable.id])
.select(StarWarsFilmsTable.name, sequelTable[StarWarsFilmsTable.name])
.map { it[StarWarsFilmsTable.name] to it[sequelTable[StarWarsFilmsTable.name]] }
println(originalAndSequelNames)

// selecting from subqueries
val starWarsFilms = StarWarsFilmsTable
.select(StarWarsFilmsTable.id, StarWarsFilmsTable.name)
.alias("swf")
val id = starWarsFilms[StarWarsFilmsTable.id]
val name = starWarsFilms[StarWarsFilmsTable.name]
val allStarWarsFilms = starWarsFilms
.select(id, name)
.map { it[id] to it[name] }

allStarWarsFilms.forEach { println("${it.first} -> ${it.second}") }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
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`.
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

class CreateExamples {
fun createFilmRecords() {
/*
INSERT INTO STARWARSFILMS (SEQUEL_ID, "name", DIRECTOR)
VALUES (7, 'The Force Awakens', 'J.J. Abrams')
*/

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

fun createIntIdFilmRecords() {
/*
INSERT INTO STAR_WARS_FILMS_TABLE (SEQUEL_ID, "name", DIRECTOR)
VALUES (7, 'The Force Awakens', 'J.J. Abrams')
*/

val id = StarWarsFilmsIntIdTable.insertAndGetId {
it[sequelId] = MOVIE_SEQUEL_ID
it[name] = "The Force Awakens"
it[director] = "J.J. Abrams"
}
println(id)
}

fun insertIgnoreRecords() {
StarWarsFilmsTable.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 {
it[sequelId] = MOVIE_SEQUEL_2_ID
it[name] = "The Last Jedi"
it[director] = "Rian Johnson"
}

/*
INSERT IGNORE INTO STAR_WARS_FILMS_TABLE (SEQUEL_ID, "name", DIRECTOR)
VALUES (8, 'The Last Jedi', 'Rian Johnson')
*/

val rowId = StarWarsFilmsIntIdTable.insertIgnoreAndGetId {
it[sequelId] = MOVIE_SEQUEL_ID
it[name] = "The Last Jedi"
it[director] = "Rian Johnson"
}
println(rowId)
}

fun simpleBatchInsert() {
val cityNames = listOf("Paris", "Moscow", "Helsinki")

CitiesTable.batchInsert(cityNames) { name ->
this[CitiesTable.name] = name
}
}

fun batchInsert() {
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")
)

StarWarsFilmsTable.batchInsert(films) { (id, name, director) ->
this[StarWarsFilmsTable.sequelId] = id
this[StarWarsFilmsTable.name] = name
this[StarWarsFilmsTable.director] = director
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.example.examples

import org.example.tables.StarWarsFilmsTable
import org.jetbrains.exposed.sql.Query
import org.jetbrains.exposed.sql.QueryBuilder
import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction

/*
Important: The contents of this file are referenced by line number in `DSL-Querying-Data.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_SEQUEL_ID = 8

fun Query.indexHint(hint: String) = IndexHintQuery(this, hint)

class IndexHintQuery(
val source: Query,
val indexHint: String
) : Query(source.set, source.where) {

init {
// copies any stored properties from the original query
source.copyTo(this)
}

override fun prepareSQL(builder: QueryBuilder): String {
val originalSql = super.prepareSQL(builder)
val fromTableSql = " FROM ${transaction.identity(set.source as Table)} "
return originalSql.replace(fromTableSql, "$fromTableSql$indexHint ")
}

override fun copy(): IndexHintQuery = IndexHintQuery(source.copy(), indexHint).also { copy ->
copyTo(copy)
}
}

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)
}
}
}
Loading

0 comments on commit 6c63a2c

Please sign in to comment.