### Example migration filename Source: https://www.jetbrains.com/help/exposed/exposed-gradle-plugin.html An example of a generated migration filename. ```text V20260417195521__CREATE_TABLE_USERS.sql ``` -------------------------------- ### Gradle initialization output Source: https://www.jetbrains.com/help/exposed/get-started-with-exposed.html Example output showing the interactive prompts and successful completion of the gradle init task. ```text Select type of build to generate: 1: Application 2: Library 3: Gradle plugin 4: Basic (build structure only) Enter selection (default: Application) [1..4] Select implementation language: 1: Java 2: Kotlin 3: Groovy 4: Scala 5: C++ 6: Swift Enter selection (default: Java) [1..6] 2 Enter target Java version (min: 7, default: 21): Project name (default: exposed-kotlin-app): Select application structure: 1: Single application project 2: Application and library project Enter selection (default: Single application project) [1..2] Select build script DSL: 1: Kotlin 2: Groovy Enter selection (default: Kotlin) [1..2] Select test framework: 1: kotlin.test 2: JUnit Jupiter Enter selection (default: kotlin.test) [1..2] Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] > Task :init To learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.8/samples/sample_building_kotlin_applications.html BUILD SUCCESSFUL in 28s 1 actionable task: 1 executed ``` -------------------------------- ### Install Colima for Apple Silicon Source: https://www.jetbrains.com/help/exposed/contributing.html Use Homebrew to install the Colima container runtime required for running Oracle XE tests on Apple Silicon. ```bash brew install colima ``` -------------------------------- ### Connect to H2 Database Source: https://www.jetbrains.com/help/exposed/working-with-database.html Examples for connecting to file-based and in-memory H2 databases. ```kotlin val h2dbFromFile = Database.connect("jdbc:h2:./myh2file", driver = "org.h2.Driver") ``` ```kotlin val h2dbFromFile = R2dbcDatabase.connect("r2dbc:h2:file///./myh2file") ``` ```kotlin val h2db = Database.connect("jdbc:h2:mem:test", driver = "org.h2.Driver") ``` ```kotlin val h2db = R2dbcDatabase.connect("r2dbc:h2:mem:///test") ``` -------------------------------- ### Start Colima Daemon Source: https://www.jetbrains.com/help/exposed/contributing.html Initialize the Colima daemon in x86_64 mode with specified memory and network settings. ```bash colima start --arch x86_64 --memory 4 --network-address ``` -------------------------------- ### View Application SQL Logs Source: https://www.jetbrains.com/help/exposed/get-started-with-exposed.html Example output showing SQL execution logs and query results in the IDE console. ```text SQL: SELECT VALUE FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME = 'MODE' SQL: CREATE TABLE IF NOT EXISTS TASKS (ID INT AUTO_INCREMENT NOT NULL, "name" VARCHAR(128) NOT NULL, DESCRIPTION VARCHAR(128) NOT NULL, COMPLETED BOOLEAN DEFAULT FALSE NOT NULL) SQL: INSERT INTO TASKS (COMPLETED, DESCRIPTION, "name") VALUES (FALSE, 'Go through the Get started with Exposed tutorial', 'Learn Exposed') SQL: INSERT INTO TASKS (COMPLETED, DESCRIPTION, "name") VALUES (TRUE, 'Read the first two chapters of The Hobbit', 'Read The Hobbit') Created new tasks with ids 1 and 2. SQL: SELECT COUNT(TASKS.ID), TASKS.COMPLETED FROM TASKS GROUP BY TASKS.COMPLETED false: 1 true: 1 Process finished with exit code 0 ``` -------------------------------- ### Define binary columns Source: https://www.jetbrains.com/help/exposed/binary-types.html Examples of defining binary columns with and without length constraints. ```kotlin val simpleData = binary("simple_data") // simple version without length ``` ```kotlin val thumbnail = binary("thumbnail", 1024) // length-specified version ``` -------------------------------- ### Configure Exposed Migration Settings Source: https://www.jetbrains.com/help/exposed/exposed-gradle-plugin.html Example configuration block for customizing migration file paths, prefixes, and versioning formats within the build script. ```gradle exposed { migrations { // ... classpath = sourceSets.main.get().runtimeClasspath fileDirectory.set(layout.projectDirectory.dir("src/main/resources/db/migration")) filePrefix.set("V") fileVersionFormat.set(VersionFormat.TIMESTAMP_ONLY) fileSeparator.set("__") useUpperCaseDescription.set(true) fileExtension.set(".sql") } } ``` -------------------------------- ### Define UsersTable and UserEntity Source: https://www.jetbrains.com/help/exposed/dao-relationships.html Basic setup for a parent table and its corresponding entity. ```kotlin object UsersTable : IntIdTable() { val name = varchar("name", MAX_USER_NAME_LENGTH) } ``` ```kotlin class UserEntity(id: EntityID) : IntEntity(id) { companion object : IntEntityClass(UsersTable) var name by UsersTable.name } ``` -------------------------------- ### Install the Exposed Gradle plugin Source: https://www.jetbrains.com/help/exposed/exposed-gradle-plugin.html Add the plugin to the plugins block in your Gradle build script to enable Exposed tooling. ```kotlin plugins { id("org.jetbrains.exposed.plugin") version "1.3.1" } ``` -------------------------------- ### Define RolesTable Source: https://www.jetbrains.com/help/exposed/dsl-joining-tables.html Defines the RolesTable schema for the join examples. ```kotlin package org.example.tables import org.jetbrains.exposed.v1.core.dao.id.IntIdTable const val MAX_CHARACTER_NAME_LENGTH = 50 object RolesTable : IntIdTable() { val sequelId = integer("sequel_id") val actorId = reference("actor_id", ActorsIntIdTable) val characterName = varchar("name", MAX_CHARACTER_NAME_LENGTH) } ``` -------------------------------- ### Define a sequence with parameters Source: https://www.jetbrains.com/help/exposed/working-with-sequence.html Advanced configuration of a sequence including start value, increment, bounds, and caching. ```kotlin private val myseq = Sequence( name = "my_sequence", startWith = 4, incrementBy = 2, minValue = 1, maxValue = 10, cycle = true, cache = 20 ) ``` -------------------------------- ### Define Vector Columns Source: https://www.jetbrains.com/help/exposed/vector-types.html Examples of defining vector columns with different configurations for dimensions and data formats. ```kotlin val embedding = vector("embedding", dimensions = 3) ``` ```kotlin val embedding = vector("embedding", 99) ``` ```kotlin val embedding = vector("embedding", 2049, VectorFormat.FLOAT64) ``` -------------------------------- ### Configure HikariCP DataSource Source: https://www.jetbrains.com/help/exposed/working-with-datasource.html Setup HikariConfig for a MySQL database and include necessary Gradle dependencies. ```kotlin val config = HikariConfig().apply { jdbcUrl = "jdbc:mysql://localhost/dbname" driverClassName = "com.mysql.cj.jdbc.Driver" username = "username" password = "password" maximumPoolSize = 6 // as of version 0.46.0, if these options are set here, they do not need to be duplicated in DatabaseConfig isReadOnly = false transactionIsolation = "TRANSACTION_SERIALIZABLE" } // Gradle implementation "mysql:mysql-connector-java:8.0.33" implementation "com.zaxxer:HikariCP:4.0.3" ``` -------------------------------- ### Custom Batch Insert Implementation (0.61.0) Source: https://www.jetbrains.com/help/exposed/migration-guide-1-0-0.html Example of a custom batch insert statement implementation prior to the 1.0.0 architectural changes. ```kotlin import org.jetbrains.exposed.sql.Table import org.jetbrains.exposed.sql.Transaction import org.jetbrains.exposed.sql.statements.BatchInsertStatement import org.jetbrains.exposed.sql.transactions.transaction class BatchInsertOnConflictDoNothing( table: Table, ) : BatchInsertStatement(table) { override fun prepareSQL( transaction: Transaction, prepared: Boolean ) = buildString { val insertStatement = super.prepareSQL(transaction, prepared) append(insertStatement) append(" ON CONFLICT (id) DO NOTHING") } // optional custom execute logic } transaction { val insertedCount: Int? = BatchInsertOnConflictDoNothing( TableA ).run { addBatch() // set column values using this[columnName] = value addBatch() // set column values using this[columnName] = value execute(this@transaction) } } ``` -------------------------------- ### Define table with binary types Source: https://www.jetbrains.com/help/exposed/binary-types.html Example of a table definition incorporating blob and binary column types. ```kotlin object Files : Table() { val id = integer("id").autoIncrement() val name = varchar("name", 255) val content = blob("content") val simpleData = binary("simple_data") // simple version without length val thumbnail = binary("thumbnail", 1024) // length-specified version override val primaryKey = PrimaryKey(id) } ``` -------------------------------- ### Accessing and Reversing Relationship Data Source: https://www.jetbrains.com/help/exposed/dao-relationships.html Examples for accessing direct references, reverse references via referrersOn, and back references via backReferencedOn. ```kotlin val film = filmRating.film ``` ```kotlin class StarWarsFilmEntity(id: EntityID) : IntEntity(id) { companion object : IntEntityClass(StarWarsFilmsTable) var sequelId by StarWarsFilmsTable.sequelId var name by StarWarsFilmsTable.name var director by StarWarsFilmsTable.director val ratings by UserRatingEntity referrersOn UserRatingsTable.film // make sure to use val and referrersOn } ``` ```kotlin val filmRatings = starWarsFilm.ratings ``` ```kotlin class UserWithSingleRatingEntity(id: EntityID) : IntEntity(id) { companion object : IntEntityClass(UsersTable) var name by UsersTable.name val rating by UserRatingEntity backReferencedOn UserRatingsTable.user // make sure to use val and backReferencedOn } ``` ```kotlin user1.rating // returns a UserRating object ``` -------------------------------- ### Define Table and Entity with java.util.UUID (0.61.0) Source: https://www.jetbrains.com/help/exposed/migration-guide-1-0-0.html Example of table and entity definition using java.util.UUID prior to version 1.0.0. ```kotlin import org.jetbrains.exposed.dao.id.* import org.jetbrains.exposed.dao.* import java.util.UUID object TestTable : UUIDTable("tester") { val secondaryId = uuid("secondary_id").uniqueIndex() } class TestEntity(id: EntityID) : UUIDEntity(id) { companion object : UUIDEntityClass(TestTable) var secondaryId by TestTable.secondaryId } ``` -------------------------------- ### Define a database table using Table Source: https://www.jetbrains.com/help/exposed/dsl-table-types.html Use the Table class to define a schema with columns and constraints. This example includes an auto-incrementing integer ID and string columns. ```kotlin import org.jetbrains.exposed.v1.core.Table const val MAX_VARCHAR_LENGTH = 50 object StarWarsFilmsTable : Table() { val id = integer("id").autoIncrement() val sequelId = integer("sequel_id").uniqueIndex() val name = varchar("name", MAX_VARCHAR_LENGTH) val director = varchar("director", MAX_VARCHAR_LENGTH) } ``` -------------------------------- ### Create project directory Source: https://www.jetbrains.com/help/exposed/get-started-with-exposed.html Commands to create a new directory and navigate into it. ```bash $ mkdir exposed-kotlin-app cd exposed-kotlin-app ``` -------------------------------- ### Initialize Gradle project Source: https://www.jetbrains.com/help/exposed/get-started-with-exposed.html Command to trigger the Gradle initialization wizard. ```bash $ gradle init ``` -------------------------------- ### Apply Window Functions with Partition and Order Source: https://www.jetbrains.com/help/exposed/sql-functions.html Demonstrates using .over(), .partitionBy(), and .orderBy() to perform aggregate and rank calculations over specific table partitions. ```kotlin val window1 = FilmBoxOfficeTable.revenue.sum() .over() .partitionBy(FilmBoxOfficeTable.year, FilmBoxOfficeTable.title) .orderBy(FilmBoxOfficeTable.revenue) val result1 = FilmBoxOfficeTable.select(window1).map { it[window1] } val window2 = rowNumber() .over() .partitionBy(FilmBoxOfficeTable.year, FilmBoxOfficeTable.title) .orderBy(FilmBoxOfficeTable.revenue) val result2 = FilmBoxOfficeTable.select(window2).map { it[window2] } val window3 = FilmBoxOfficeTable.revenue.sum() .over() .orderBy(FilmBoxOfficeTable.year to SortOrder.DESC, FilmBoxOfficeTable.title to SortOrder.ASC_NULLS_FIRST) val result3 = FilmBoxOfficeTable.select(window3).map { it[window3] } ``` -------------------------------- ### Define ActorsIntIdTable Source: https://www.jetbrains.com/help/exposed/dsl-joining-tables.html Defines the ActorsIntIdTable schema for the join examples. ```kotlin package org.example.tables import org.jetbrains.exposed.v1.core.dao.id.IntIdTable const val MAX_NAME_LENGTH = 50 object ActorsIntIdTable : IntIdTable("actors") { val sequelId = integer("sequel_id").uniqueIndex() val name = varchar("name", MAX_NAME_LENGTH) } ``` -------------------------------- ### Define StarWarsFilmsIntIdTable Source: https://www.jetbrains.com/help/exposed/dsl-joining-tables.html Defines the StarWarsFilmsIntIdTable schema for the join examples. ```kotlin package org.example.tables import org.jetbrains.exposed.v1.core.dao.id.IntIdTable object StarWarsFilmsIntIdTable : IntIdTable("star_wars_films_table") { val sequelId = integer("sequel_id").uniqueIndex() val name = varchar("name", MAX_VARCHAR_LENGTH) val director = varchar("director", MAX_VARCHAR_LENGTH) } ``` -------------------------------- ### Connect to SQL Server Source: https://www.jetbrains.com/help/exposed/working-with-database.html Establish a connection using either JDBC or R2DBC drivers. ```kotlin val sqlserverdb = Database.connect( "jdbc:sqlserver://localhost:32768;databaseName=test", "com.microsoft.sqlserver.jdbc.SQLServerDriver", user = "user", password = "password" ) ``` ```kotlin val sqlserverdb = R2dbcDatabase.connect( "r2dbc:mssql://localhost:32768;databaseName=test", driver = "sqlserver", user = "user", password = "password" ) ``` -------------------------------- ### Exposed Update Statement Source: https://www.jetbrains.com/help/exposed/get-started-with-exposed-dao.html Example of an UPDATE statement triggered by property modification. ```text SQL: UPDATE TASKS SET COMPLETED=TRUE, "name"='Try Exposed DAO' WHERE ID = 1 ``` -------------------------------- ### Insert Data into JSONB Column Source: https://www.jetbrains.com/help/exposed/json-and-jsonb-types.html Example of inserting a serialized object into a JSONB column. ```kotlin TasksTable.insert { it[project] = Project("Main", "Java", true) } ``` ```sql INSERT INTO tasks (project) VALUES (JSONB('{"name":"Main","language":"Java","active":true}')) ``` -------------------------------- ### Apply Window Frame Clauses Source: https://www.jetbrains.com/help/exposed/sql-functions.html Shows how to define window boundaries using frame clause functions like .range() with WindowFrameBound options. ```kotlin val window4 = FilmBoxOfficeTable.revenue.sum() .over() .partitionBy(FilmBoxOfficeTable.year, FilmBoxOfficeTable.title) .orderBy(FilmBoxOfficeTable.revenue) .range(WindowFrameBound.offsetPreceding(2), WindowFrameBound.currentRow()) val result4 = FilmBoxOfficeTable.select(window4).map { it[window4] } ``` -------------------------------- ### SQL query representation Source: https://www.jetbrains.com/help/exposed/dao-crud-operations.html Example of the underlying SQL generated by a composite entity query. ```sql SELECT DIRECTORS."name", DIRECTORS.GUILD_ID, DIRECTORS.GENRE FROM DIRECTORS WHERE (DIRECTORS."name" = 'J.J. Abrams') AND (DIRECTORS.GUILD_ID = '2cc64f4f-1a2c-41ce-bda1-ee492f787f4b') ``` -------------------------------- ### Connect to database using R2dbcDatabase.connect with configuration block Source: https://www.jetbrains.com/help/exposed/working-with-connectionfactory.html Establishes a database connection by providing a configuration block that includes the connection URL. ```kotlin import io.r2dbc.spi.IsolationLevel import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabase val database = R2dbcDatabase.connect { defaultMaxAttempts = 1 defaultR2dbcIsolationLevel = IsolationLevel.READ_COMMITTED setUrl("r2dbc:h2:mem:///test;DB_CLOSE_DELAY=-1;") } ``` -------------------------------- ### Substring function Source: https://www.jetbrains.com/help/exposed/sql-functions.html Extract a portion of a string using start index and length parameters. ```kotlin val shortenedTitle = FilmBoxOfficeTable.title.substring(start = 1, length = 3) ``` -------------------------------- ### Initialize Database and Perform CRUD Operations Source: https://www.jetbrains.com/help/exposed/get-started-with-exposed.html Connects to an H2 in-memory database and executes table creation, insertion, and selection within a transaction. ```kotlin package org.example import Tasks import org.jetbrains.exposed.v1.core.* import org.jetbrains.exposed.v1.jdbc.Database import org.jetbrains.exposed.v1.jdbc.SchemaUtils import org.jetbrains.exposed.v1.jdbc.deleteWhere import org.jetbrains.exposed.v1.jdbc.insert import org.jetbrains.exposed.v1.jdbc.select import org.jetbrains.exposed.v1.jdbc.selectAll import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.v1.jdbc.update fun main() { Database.connect("jdbc:h2:mem:test", driver = "org.h2.Driver") transaction { SchemaUtils.create(Tasks) val taskId = Tasks.insert { it[title] = "Learn Exposed" it[description] = "Go through the Get started with Exposed tutorial" } get Tasks.id val secondTaskId = Tasks.insert { it[title] = "Read The Hobbit" it[description] = "Read the first two chapters of The Hobbit" it[isCompleted] = true } get Tasks.id println("Created new tasks with ids $taskId and $secondTaskId.") Tasks.select(Tasks.id.count(), Tasks.isCompleted).groupBy(Tasks.isCompleted).forEach { println("${it[Tasks.isCompleted]}: ${it[Tasks.id.count()]} ") } println("Remaining tasks: ${Tasks.selectAll().toList()}") } } ``` -------------------------------- ### Configure database connection Source: https://www.jetbrains.com/help/exposed/get-started-with-exposed.html Initialize the database connection using Database.connect in your main application file. ```kotlin package org.example import org.jetbrains.exposed.v1.jdbc.Database fun main() { Database.connect("jdbc:h2:mem:test", driver = "org.h2.Driver") } ``` -------------------------------- ### Locate function Source: https://www.jetbrains.com/help/exposed/sql-functions.html Find the starting index of a substring within a column, returning 0 if not found. ```kotlin val firstXSIndex = FilmBoxOfficeTable.title.locate("XS") ``` -------------------------------- ### Open project in IntelliJ IDEA Source: https://www.jetbrains.com/help/exposed/get-started-with-exposed.html Command to open the current directory in IntelliJ IDEA. ```bash idea . ``` -------------------------------- ### Initialize Database Connection Source: https://www.jetbrains.com/help/exposed/working-with-database.html Basic initialization for JDBC and R2DBC database descriptors. ```kotlin val h2db = Database.connect("jdbc:h2:mem:test", driver = "org.h2.Driver") ``` ```kotlin val h2db = R2dbcDatabase.connect("r2dbc:h2:mem:///test") ``` -------------------------------- ### Disable Automatic JSON Casting Source: https://www.jetbrains.com/help/exposed/json-and-jsonb-types.html Example of disabling the automatic JSON() function wrapping for a JSONB column. ```kotlin object TasksRawTable : Table("tasks_raw") { val project = jsonb("project", Json.Default, castToJsonFormat = false) } ``` -------------------------------- ### Initialize Database and Perform DAO Operations Source: https://www.jetbrains.com/help/exposed/get-started-with-exposed-dao.html Connect to an H2 database and execute table creation and entity operations within a transaction block. ```kotlin package org.example import org.jetbrains.exposed.v1.jdbc.Database import org.jetbrains.exposed.v1.jdbc.SchemaUtils import org.jetbrains.exposed.v1.jdbc.transactions.transaction fun main() { Database.connect("jdbc:h2:mem:test", driver = "org.h2.Driver") transaction { SchemaUtils.create(Tasks) val task1 = Task.new { title = "Learn Exposed DAO" description = "Follow the DAO tutorial" } val task2 = Task.new { title = "Read The Hobbit" description = "Read chapter one" isCompleted = true } println("Created new tasks with ids ${task1.id} and ${task2.id}") val completed = Task.find { Tasks.isCompleted eq true }.toList() println("Completed tasks: ${completed.count()}") } } ``` -------------------------------- ### Initialize database schema in native images Source: https://www.jetbrains.com/help/exposed/spring-boot-integration.html Programmatically create database schemas using ApplicationRunner, as dynamic configuration via properties is restricted in AOT mode. ```kotlin @Component @Transactional class SchemaInitialize : ApplicationRunner { override fun run(args: ApplicationArguments) { SchemaUtils.create(MessageEntity) } } ``` -------------------------------- ### Connect to database using R2dbcDatabase.connect with URL Source: https://www.jetbrains.com/help/exposed/working-with-connectionfactory.html Establishes a database connection by passing a connection URL and a configuration block directly to the connect function. ```kotlin val database = R2dbcDatabase.connect( "r2dbc:h2:mem:///test;DB_CLOSE_DELAY=-1;", databaseConfig = R2dbcDatabaseConfig { defaultMaxAttempts = 1 defaultR2dbcIsolationLevel = IsolationLevel.READ_COMMITTED } ) ``` -------------------------------- ### Connect to PostgreSQL Source: https://www.jetbrains.com/help/exposed/working-with-database.html Connection configuration for PostgreSQL using JDBC and R2DBC. ```kotlin val postgresqldb = Database.connect( "jdbc:postgresql://localhost:12346/test", driver = "org.postgresql.Driver", user = "user", password = "password" ) ``` ```kotlin val postgresqldb = R2dbcDatabase.connect( url = "r2dbc:postgresql://db:5432/test", driver = "postgresql", user = "user", password = "password" ) ``` -------------------------------- ### Define Table with Citext Column Source: https://www.jetbrains.com/help/exposed/custom-data-types.html Example of using the custom citext extension function within a table object. ```kotlin object TestTable : Table("test_table") { val firstName = citext("first_name", 32) } ``` -------------------------------- ### Define table with basic data types Source: https://www.jetbrains.com/help/exposed/numeric-boolean-string-types.html Demonstrates how to define a table using integer, varchar, text, short, decimal, and boolean column types. ```kotlin import org.jetbrains.exposed.v1.core.* class BasicTypesExamples { companion object { private const val NAME_LENGTH = 50 private const val RATING_TOTAL_DIGITS = 5 private const val RATING_DECIMAL_DIGITS = 2 } object Users : Table() { val id = integer("id").autoIncrement() val name = varchar("name", NAME_LENGTH) val bio = text("bio") val age = short("age") val rating = decimal("rating", RATING_TOTAL_DIGITS, RATING_DECIMAL_DIGITS) // 5 total digits, 2 after decimal point val isActive = bool("is_active") override val primaryKey = PrimaryKey(id) } } ``` -------------------------------- ### Define a Table with JSONB Column Source: https://www.jetbrains.com/help/exposed/json-and-jsonb-types.html Example of defining a table using the jsonb column type with a default value. ```kotlin @Serializable data class Project(val name: String, val language: String, val active: Boolean) object TasksTable : Table("tasks") { val complete = bool("complete").default(false) val project = jsonb("project", Json.Default) .default(Project("Main", "Kotlin", true)) } ``` ```sql CREATE TABLE IF NOT EXISTS tasks ( complete BOOLEAN DEFAULT 0 NOT NULL, project BLOB DEFAULT (JSONB('{"name":"Main","language":"Kotlin","active":true}')) NOT NULL ) ``` -------------------------------- ### Connect to MySQL Source: https://www.jetbrains.com/help/exposed/working-with-database.html Connection configuration for MySQL using JDBC and R2DBC. ```kotlin val mysqldb = Database.connect( "jdbc:mysql://localhost:3306/test", driver = "com.mysql.cj.jdbc.Driver", user = "user", password = "password" ) ``` ```kotlin val mysqldb = R2dbcDatabase.connect( "r2dbc:mysql://localhost:3306/test", driver = "mysql", user = "user", password = "password" ) ``` -------------------------------- ### Retrieve count of modified rows Source: https://www.jetbrains.com/help/exposed/dsl-crud-operations.html Access the insertedCount property on statement classes to get the number of affected rows. ```kotlin val insertStatement = StarWarsFilmsTable.insertIgnore { it[name] = "The Last Jedi" it[sequelId] = MOVIE_SEQUEL_3_ID it[director] = "Rian Johnson" } val rowCount: Int = insertStatement.insertedCount ``` -------------------------------- ### Connect to Oracle Source: https://www.jetbrains.com/help/exposed/working-with-database.html Connection configuration for Oracle using JDBC and R2DBC. ```kotlin val oracledb = Database.connect( "jdbc:oracle:thin:@//localhost:1521/test", driver = "oracle.jdbc.OracleDriver", user = "user", password = "password" ) ``` ```kotlin val oracledb = R2dbcDatabase.connect( "r2dbc:oracle://localhost:3306/test", driver = "oracle", user = "user", password = "password" ) ``` -------------------------------- ### Select from sub-queries with aliases Source: https://www.jetbrains.com/help/exposed/dsl-querying-data.html Demonstrates how to use aliases when selecting data from sub-queries. ```kotlin 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] } ``` -------------------------------- ### Query Vector Data with Distance Functions Source: https://www.jetbrains.com/help/exposed/vector-types.html Example of performing similarity searches using cosine and euclidean distance functions. ```kotlin val distance = MultipleVectors.ve1.cosineDistance(floatArrayOf(0f, 1f, 0f)).alias("cd") MultipleVectors .select(distance) .where { MultipleVectors.ve2.euclideanDistance(intArrayOf(1, 1, 1)) less 5 } .orderBy(distance to SortOrder.ASC) .toList() ``` -------------------------------- ### Connect using DataSource Source: https://www.jetbrains.com/help/exposed/working-with-datasource.html Basic initialization of a database connection using a DataSource object. ```kotlin val db = Database.connect(dataSource) ``` -------------------------------- ### Custom Batch Insert Implementation (1.0.0) Source: https://www.jetbrains.com/help/exposed/migration-guide-1-0-0.html Updated implementation for 1.0.0, utilizing the toExecutable() extension to separate statement building from execution. ```kotlin import org.jetbrains.exposed.v1.core.Table import org.jetbrains.exposed.v1.core.Transaction import org.jetbrains.exposed.v1.core.statements.BatchInsertStatement import org.jetbrains.exposed.v1.jdbc.statements.toExecutable import org.jetbrains.exposed.v1.jdbc.transactions.transaction class BatchInsertOnConflictDoNothing( table: Table, ) : BatchInsertStatement(table) { override fun prepareSQL( transaction: Transaction, prepared: Boolean ) = buildString { val insertStatement = super.prepareSQL(transaction, prepared) append(insertStatement) append(" ON CONFLICT (id) DO NOTHING") } // optional custom execute logic -> create custom Executable } transaction { val executable = BatchInsertOnConflictDoNothing(TableA).toExecutable() val insertedCount: Int? = executable.run { statement.addBatch() // set column values using statement[column] = value statement.addBatch() // set column values using statement[column] = value execute(this@transaction) } } ``` -------------------------------- ### Use Custom Range Columns in Table Source: https://www.jetbrains.com/help/exposed/custom-data-types.html Example of using the newly defined range column types within a Table definition. ```Kotlin object TestTable : Table("test_table") { val amounts = intRange("amounts").default(1..10) val holidays = dateRange("holidays") } ``` -------------------------------- ### Work with multiple databases Source: https://www.jetbrains.com/help/exposed/transactions.html Illustrates how to pass specific database references to transaction blocks when working with multiple connections. ```kotlin val db1 = connect("jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;", "org.h2.Driver", "root", "") val db2 = connect("jdbc:h2:mem:db2;DB_CLOSE_DELAY=-1;", "org.h2.Driver", "root", "") transaction(db1) { //... val result = transaction(db2) { Table1.selectAll().where { }.map { it[Table1.name] } } val count = Table2.selectAll().where { Table2.name inList result }.count() } ``` -------------------------------- ### Insert and get ID Source: https://www.jetbrains.com/help/exposed/dsl-crud-operations.html Adds a new row to an IdTable and returns the generated ID. Throws an exception if the row already exists. ```kotlin val id = StarWarsFilmsIntIdTable.insertAndGetId { it[sequelId] = MOVIE_SEQUEL_ID it[name] = "The Force Awakens" it[director] = "J.J. Abrams" } ``` ```sql INSERT INTO STAR_WARS_FILMS_TABLE (SEQUEL_ID, "name", DIRECTOR) VALUES (7, 'The Force Awakens', 'J.J. Abrams') ``` -------------------------------- ### Select and Read JSONB Data Source: https://www.jetbrains.com/help/exposed/json-and-jsonb-types.html Example of selecting data from a JSONB column, where Exposed automatically applies the JSON() function to ensure readability. ```kotlin val projectText = TasksTable.project.alias("ptext") val projects = TasksTable.select(projectText).map { it[projectText] } println(projects) // [Project(name=Main, language=Java, active=true)] ``` ```sql SELECT JSON(tasks.project) ptext FROM tasks ``` -------------------------------- ### Initialize HikariDataSource Source: https://www.jetbrains.com/help/exposed/working-with-datasource.html Instantiate the HikariDataSource and connect it to the Exposed Database instance. ```kotlin val dataSource = HikariDataSource(config) Database.connect( datasource = dataSource, databaseConfig = DatabaseConfig { // set other parameters here } ) ``` -------------------------------- ### Connect to MariaDB Source: https://www.jetbrains.com/help/exposed/working-with-database.html Connection configuration for MariaDB using JDBC and R2DBC. ```kotlin val mariadb = Database.connect( "jdbc:mariadb://localhost:3306/test", driver = "org.mariadb.jdbc.Driver", user = "root", password = "your_pwd" ) ``` ```kotlin val mariadb = R2dbcDatabase.connect( "r2dbc:mariadb://localhost:3306/test", driver = "mariadb", user = "root", password = "your_pwd" ) ``` -------------------------------- ### List Docker Contexts Source: https://www.jetbrains.com/help/exposed/contributing.html Verify the current active Docker context. ```bash docker context list ``` -------------------------------- ### PostgreSQL pgjdbc-ng Driver Source: https://www.jetbrains.com/help/exposed/working-with-database.html Alternative PostgreSQL driver configuration. ```kotlin implementation("com.impossibl.pgjdbc-ng:pgjdbc-ng:0.8.9") ``` ```kotlin val postgresqldbNG = Database.connect( "jdbc:pgsql://localhost:12346/test", driver = "com.impossibl.postgres.jdbc.PGDriver", user = "user", password = "password" ) ``` -------------------------------- ### Define Table with Default Values Source: https://www.jetbrains.com/help/exposed/breaking-changes.html Example of a table definition using default values and an insert statement that triggers different SQL generation behavior in version 0.57.0. ```kotlin object TestTable : IntIdTable("test") { val number = integer("number").default(100) val expression = integer("exp") .defaultExpression(intLiteral(100) + intLiteral(200)) } TestTable.insert { } ``` -------------------------------- ### Build and Inspect Query SQL Source: https://www.jetbrains.com/help/exposed/dsl-statement-builder.html Create a query object and retrieve its SQL representation with or without parameter placeholders. ```kotlin val filmQuery = StarWarsFilmsTable .selectAll() .where { StarWarsFilmsTable.sequelId lessEq 3 } ``` ```kotlin val querySql: String = filmQuery .orWhere { StarWarsFilmsTable.sequelId greater 6 } .prepareSQL(this) ``` ```sql SELECT STARWARSFILMS.ID, STARWARSFILMS.SEQUEL_ID, STARWARSFILMS."name", STARWARSFILMS.DIRECTOR FROM STARWARSFILMS WHERE (STARWARSFILMS.SEQUEL_ID <= ?) OR (STARWARSFILMS.SEQUEL_ID > ?) ``` ```kotlin val fullQuerySql = filmQuery .orWhere { StarWarsFilmsTable.sequelId greater 6 } .prepareSQL(this, prepared = false) ``` ```sql SELECT STARWARSFILMS.ID, STARWARSFILMS.SEQUEL_ID, STARWARSFILMS."name", STARWARSFILMS.DIRECTOR FROM STARWARSFILMS WHERE (STARWARSFILMS.SEQUEL_ID <= 3) OR (STARWARSFILMS.SEQUEL_ID > 6) ``` -------------------------------- ### Calculate Min, Max, and Average with Exposed Source: https://www.jetbrains.com/help/exposed/sql-functions.html Use min, max, and avg functions on comparable expressions, often in conjunction with groupBy. ```kotlin val minRevenue = FilmBoxOfficeTable.revenue.min() val maxRevenue = FilmBoxOfficeTable.revenue.max() val averageRevenue = FilmBoxOfficeTable.revenue.avg() val revenueStats = FilmBoxOfficeTable .select(minRevenue, maxRevenue, averageRevenue, FilmBoxOfficeTable.region) .groupBy(FilmBoxOfficeTable.region) .map { Triple(it[minRevenue], it[maxRevenue], it[averageRevenue]) } ``` -------------------------------- ### Insert and ignore and get ID Source: https://www.jetbrains.com/help/exposed/dsl-crud-operations.html Adds a new row and returns its ID, ignoring the operation if the row already exists. Supported on MySQL, MariaDB, PostgreSQL, and SQLite. ```kotlin val rowId = StarWarsFilmsIntIdTable.insertIgnoreAndGetId { it[sequelId] = MOVIE_SEQUEL_ID it[name] = "The Last Jedi" it[director] = "Rian Johnson" } ``` ```sql INSERT IGNORE INTO STAR_WARS_FILMS_TABLE (SEQUEL_ID, "name", DIRECTOR) VALUES (8, 'The Last Jedi', 'Rian Johnson') ``` -------------------------------- ### Pre-construct ConnectionFactoryOptions Source: https://www.jetbrains.com/help/exposed/working-with-connectionfactory.html Create a standalone ConnectionFactoryOptions object and assign it to a R2dbcDatabaseConfig instance. ```kotlin import io.r2dbc.spi.ConnectionFactoryOptions import io.r2dbc.spi.IsolationLevel import io.r2dbc.spi.Option import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabase import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabaseConfig val options = ConnectionFactoryOptions.builder() .option(ConnectionFactoryOptions.DRIVER, "h2") .option(ConnectionFactoryOptions.PROTOCOL, "mem") .option(ConnectionFactoryOptions.DATABASE, "test") .option(Option.valueOf("DB_CLOSE_DELAY"), "-1") .build() val databaseConfig = R2dbcDatabaseConfig { defaultMaxAttempts = 1 defaultR2dbcIsolationLevel = IsolationLevel.READ_COMMITTED connectionFactoryOptions = options } val database = R2dbcDatabase.connect(databaseConfig = databaseConfig) ``` -------------------------------- ### Add Logging Dependencies Source: https://www.jetbrains.com/help/exposed/adding-dependencies.html Configure logging using either a no-op implementation or Logback for full-featured output. ```kotlin dependencies { // Minimal logging (no output) implementation("org.slf4j:slf4j-nop:2.0.9") // Full-featured logging using Logback implementation("ch.qos.logback:logback-classic:1.5.20") } ``` ```xml org.slf4j slf4j-nop 2.0.9 ch.qos.logback logback-classic 1.5.20 ``` ```groovy dependencies { // Minimal logging (no output) implementation("org.slf4j:slf4j-nop:2.0.9") // Full-featured logging using Logback implementation("ch.qos.logback:logback-classic:1.5.20") } ``` -------------------------------- ### Migrate simple comparison queries Source: https://www.jetbrains.com/help/exposed/migration-guide-1-0-0.html Replaces SqlExpressionBuilder imports with top-level core imports for simple comparison operations. ```kotlin import org.jetbrains.exposed.sql.SqlExpressionBuilder.less import org.jetbrains.exposed.sql.selectAll val amountIsLow = TableA.amount less 10 TableA .selectAll() .where(amountIsLow) ``` ```kotlin import org.jetbrains.exposed.v1.core.less import org.jetbrains.exposed.v1.jdbc.selectAll val amountIsLow = TableA.amount less 10 TableA .selectAll() .where(amountIsLow) ``` -------------------------------- ### Configure Keyword Identifier Casing Source: https://www.jetbrains.com/help/exposed/breaking-changes.html Demonstrates how to define a table with keyword identifiers and how to opt out of the default casing preservation behavior in DatabaseConfig. ```kotlin object TestTable : Table("table") { val col = integer("select") } // default behavior (preserveKeywordCasing is by default set to true) // H2 generates SQL -> CREATE TABLE IF NOT EXISTS "table" ("select" INT NOT NULL) // with opt-out Database.connect( url = "jdbc:h2:mem:test", driver = "org.h2.Driver", databaseConfig = DatabaseConfig { @OptIn(ExperimentalKeywordApi::class) preserveKeywordCasing = false } ) // H2 generates SQL -> CREATE TABLE IF NOT EXISTS "TABLE" ("SELECT" INT NOT NULL) ``` -------------------------------- ### Connect to SQLite Source: https://www.jetbrains.com/help/exposed/working-with-database.html Establish a connection to a file-based or in-memory SQLite database. ```kotlin Database.connect("jdbc:sqlite:/data/data.db", "org.sqlite.JDBC") ``` ```kotlin Database.connect("jdbc:sqlite:file:test?mode=memory&cache=shared", "org.sqlite.JDBC") ``` -------------------------------- ### Configure Testcontainers for migrations Source: https://www.jetbrains.com/help/exposed/exposed-gradle-plugin.html Use a containerized database for schema generation by specifying the image name instead of a direct connection string. ```kotlin exposed { migrations { tablesPackage.set("com.example.db.tables") testContainersImageName.set("postgres:latest") } } ``` -------------------------------- ### Apply a simple index Source: https://www.jetbrains.com/help/exposed/working-with-tables.html Use the .index() extension function on a column to create a non-unique index. ```kotlin val name = varchar("name", 50).index() ``` -------------------------------- ### Construct ConnectionFactoryOptions from scratch Source: https://www.jetbrains.com/help/exposed/working-with-connectionfactory.html Define the full connection state holder manually within the R2dbcDatabase.connect block. ```kotlin import io.r2dbc.spi.ConnectionFactoryOptions import io.r2dbc.spi.IsolationLevel import io.r2dbc.spi.Option import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabase val database = R2dbcDatabase.connect { defaultMaxAttempts = 1 defaultR2dbcIsolationLevel = IsolationLevel.READ_COMMITTED connectionFactoryOptions { option(ConnectionFactoryOptions.DRIVER, "h2") option(ConnectionFactoryOptions.PROTOCOL, "mem") option(ConnectionFactoryOptions.DATABASE, "test") option(Option.valueOf("DB_CLOSE_DELAY"), "-1") } } ``` -------------------------------- ### Add Exposed Dependencies Source: https://www.jetbrains.com/help/exposed/adding-dependencies.html Include the core, JDBC, and optional DAO modules in your project build file. ```kotlin dependencies { implementation("org.jetbrains.exposed:exposed-core:1.3.1") implementation("org.jetbrains.exposed:exposed-jdbc:1.3.1") implementation("org.jetbrains.exposed:exposed-dao:1.3.1") // Optional } ``` ```xml org.jetbrains.exposed exposed-core 1.3.1 org.jetbrains.exposed exposed-jdbc 1.3.1 org.jetbrains.exposed exposed-dao 1.3.1 ``` ```groovy dependencies { implementation "org.jetbrains.exposed:exposed-core:1.3.1" implementation "org.jetbrains.exposed:exposed-jdbc:1.3.1" implementation "org.jetbrains.exposed:exposed-dao:1.3.1" //optional } ``` -------------------------------- ### Define Exposed dependencies in version catalog Source: https://www.jetbrains.com/help/exposed/get-started-with-exposed.html Add the Exposed and H2 versions and library definitions to your gradle/libs.versions.toml file. ```toml [versions] //... exposed = "1.3.1" h2 = "2.4.240" [libraries] //... exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" } exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "exposed" } h2 = { module = "com.h2database:h2", version.ref = "h2" } ``` -------------------------------- ### Run Claude Code migration skill Source: https://www.jetbrains.com/help/exposed/migration-guide-1-0-0.html Execute the migration skill from the project root to automatically apply mechanical updates. ```bash /migrate-to-1.0 ``` -------------------------------- ### Insert Datetime Values Source: https://www.jetbrains.com/help/exposed/date-and-time-types.html Shows how to insert datetime values using different date-time library implementations. ```kotlin val createdAt = datetime("created_at") .defaultExpression(CurrentDateTime) // Sets current date/time when inserting new records // Using exposed-kotlin-datetime (recommended) Events.insert { it[createdAt] = Clock.System.now() .toLocalDateTime(TimeZone.UTC) } // Note: CurrentDateTime is available in all date-time modules // Using exposed-java-time Events.insert { it[createdAt] = LocalDateTime.now() } // Using exposed-jodatime Events.insert { it[createdAt] = DateTime.now() } ``` -------------------------------- ### Configure H2 Database Connection Source: https://www.jetbrains.com/help/exposed/spring-boot-integration.html Add these properties to src/resources/application.properties to set up an H2 in-memory database. ```properties spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password ``` -------------------------------- ### Insert Date Values Source: https://www.jetbrains.com/help/exposed/date-and-time-types.html Shows how to insert date values using different date-time library implementations. ```kotlin val birthDate = date("birth_date") // Using exposed-kotlin-datetime (recommended) Events.insert { it[birthDate] = LocalDate(1990, 1, 1) } // Using exposed-java-time Events.insert { it[birthDate] = LocalDate.of(1990, 1, 1) } // Using exposed-jodatime Events.insert { it[birthDate] = org.joda.time.LocalDate(1990, 1, 1) } ``` -------------------------------- ### Insert Time Values Source: https://www.jetbrains.com/help/exposed/date-and-time-types.html Shows how to insert time values using different date-time library implementations. ```kotlin val startTime = time("start_time") // Using exposed-kotlin-datetime (recommended) Events.insert { it[startTime] = LocalTime(9, 0) // 09:00 } // Using exposed-java-time Events.insert { it[startTime] = LocalTime.of(9, 0) // 09:00 } // Using exposed-jodatime Events.insert { it[startTime] = org.joda.time.LocalTime(9, 0) // 09:00 } ``` -------------------------------- ### Create a table using SchemaUtils Source: https://www.jetbrains.com/help/exposed/working-with-tables.html Use this method within a transaction block to generate the necessary SQL for table creation based on your definition. ```kotlin transaction { SchemaUtils.create(StarWarsFilms) //... } ``` -------------------------------- ### Connect to a database using R2DBC ConnectionFactory Source: https://www.jetbrains.com/help/exposed/working-with-connectionfactory.html Uses the R2DBC SPI to build connection options and connect to a database. Requires an explicit dialect to be set in the database configuration. ```kotlin import io.r2dbc.spi.ConnectionFactories import io.r2dbc.spi.ConnectionFactoryOptions import io.r2dbc.spi.IsolationLevel import io.r2dbc.spi.Option import org.jetbrains.exposed.v1.core.vendors.H2Dialect import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabase import org.jetbrains.exposed.v1.r2dbc.R2dbcDatabaseConfig val options = ConnectionFactoryOptions.builder() .option(ConnectionFactoryOptions.DRIVER, "h2") .option(ConnectionFactoryOptions.PROTOCOL, "mem") .option(ConnectionFactoryOptions.DATABASE, "test") .option(Option.valueOf("DB_CLOSE_DELAY"), "-1") .build() val connectionFactory = ConnectionFactories.get(options) val database = R2dbcDatabase.connect( connectionFactory = connectionFactory, databaseConfig = R2dbcDatabaseConfig { defaultMaxAttempts = 1 defaultR2dbcIsolationLevel = IsolationLevel.READ_COMMITTED explicitDialect = H2Dialect() } ) ``` -------------------------------- ### Create and query parent-child hierarchy Source: https://www.jetbrains.com/help/exposed/dao-relationships.html Demonstrates creating entities and assigning hierarchical relationships using SizedCollection. ```kotlin val director1 = DirectorEntity.new { name = "George Lucas" genre = Genre.SCI_FI } val film1 = StarWarsFilmWithParentAndChildEntity.new { name = "Star Wars: A New Hope" director = director1 } val film2 = StarWarsFilmWithParentAndChildEntity.new { name = "Star Wars: The Empire Strikes Back" director = director1 } val film3 = StarWarsFilmWithParentAndChildEntity.new { name = "Star Wars: Return of the Jedi" director = director1 } // Assign parent-child relationships film2.prequels = SizedCollection(listOf(film1)) // Empire Strikes Back is a sequel to A New Hope film3.prequels = SizedCollection(listOf(film2)) // Return of the Jedi is a sequel to Empire Strikes Back film1.sequels = SizedCollection(listOf(film2, film3)) // A New Hope has Empire Strikes Back as a sequel film2.sequels = SizedCollection(listOf(film3)) // Empire Strikes Back has Return of the Jedi as a sequel ``` -------------------------------- ### Generate migration scripts via Gradle Source: https://www.jetbrains.com/help/exposed/exposed-gradle-plugin.html Execute this command in the terminal to generate migration scripts based on the difference between the database schema and Exposed table definitions. ```bash ./gradlew generateMigrations ``` -------------------------------- ### Configure database connection for migrations Source: https://www.jetbrains.com/help/exposed/exposed-gradle-plugin.html Set the database credentials and URL within the exposed migrations block to enable schema generation. ```kotlin exposed { migrations { tablesPackage.set("com.example.db.tables") databaseUrl.set("jdbc:postgresql://localhost:5432/mydb") databaseUser.set("postgres") databasePassword.set("password") } } ``` -------------------------------- ### Create a sequence Source: https://www.jetbrains.com/help/exposed/working-with-sequence.html Persist the sequence definition to the database using SchemaUtils. ```kotlin SchemaUtils.createSequence(myseq) ```