{"owner":"JetBrains","repo":"Exposed","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["CLAUDE.md"],"skills":{"CLAUDE.md":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Project Overview\n\nExposed is a lightweight ORM framework for Kotlin that provides two APIs:\n- **DSL API**: Type-safe SQL-wrapping Domain Specific Language (in `exposed-core`)\n  - Works with both JDBC (`exposed-jdbc`) and R2DBC (`exposed-r2dbc`)\n- **DAO API**: Lightweight Data Access Object API (in `exposed-dao`)\n  - **Only works with JDBC** - does not support R2DBC\n\n## Module Architecture\n\n### Core Modules\n- **exposed-core**: Foundation layer with DSL API, database abstractions, column types, and vendor dialects\n- **exposed-dao**: DAO API with entity classes and relationships (JDBC only, does not work with R2DBC)\n- **exposed-jdbc**: JDBC implementation with blocking transactions\n- **exposed-r2dbc**: R2DBC implementation with suspending transactions\n\n### Extension Modules\n- **exposed-java-time**, **exposed-jodatime**, **exposed-kotlin-datetime**: Date/time support\n- **exposed-json**: JSON/JSONB column types\n- **exposed-crypt**: Encrypted column types\n- **exposed-money**: JavaMoney MonetaryAmount support\n- **exposed-migration-core**: Common migration functionality\n- **exposed-migration-jdbc**: JDBC-based schema migrations\n- **exposed-migration-r2dbc**: R2DBC-based schema migrations\n- **exposed-spring-boot-starter**: Spring Boot integration\n- **spring-transaction**: Spring Framework transaction manager\n\n### Test Modules\n- **exposed-tests**: Main JDBC-based test suite\n- **exposed-r2dbc-tests**: R2DBC-specific test suite\n- **exposed-jdbc-r2dbc-tests**: Cross-compatibility tests\n\n## Build & Development\n\n### Building\n```bash\n./gradlew compileKotlin  # Compile the projects code\n./gradlew detekt         # Validate code style\n./gradlew apiDump        # Update dokka API docs after changing public API\n```\n\n### Running Tests\n\nTests are organized by database and dialect. Each module has database-specific test tasks:\n\n#### Quick test with H2 (no Docker required)\n```bash\n./gradlew test_h2_v2                              # All modules with H2\n./gradlew :exposed-tests:test_h2_v2               # JDBC Tests with H2\n./gradlew :exposed-r2dbc-tests:test_h2_v2         # R2DBC Tests with H2\n```\n\n#### Test with Postgres\n```bash\n./gradlew test_postgres                           # All modules with Postgres\n./gradlew :exposed-tests:test_postgres            # JDBC Tests with Postgres\n./gradlew :exposed-r2dbc-tests:test_postgres      # R2DBC Tests with Postgres\n```\n\n#### Test with specific database (requires Docker)\n```bash\n# Start database containers first\n./gradlew mariadbComposeUp        # Start MariaDB\n./gradlew postgresComposeUp       # Start PostgreSQL\n./gradlew mysql8ComposeUp         # Start MySQL 8\n./gradlew oracleComposeUp         # Start Oracle\n./gradlew sqlserverComposeUp      # Start SQL Server\n\n# Run tests\n./gradlew :exposed-tests:test_postgres\n./gradlew :exposed-tests:test_mysql_v8\n./gradlew :exposed-tests:test_mariadb\n\n# Stop containers\n./gradlew postgresComposeDownForced\n```\n\n#### Run specific test class or method with H2\n```bash\n./gradlew :exposed-tests:test_h2_v2 --tests \"org.jetbrains.exposed.v1.tests.shared.dml.InsertTests\"\n./gradlew :exposed-tests:test_h2_v2 --tests \"*.InsertTests.testBatchInsert\"\n```\n\n#### Available test databases\n- `test_h2_v2`, `test_h2_v2_mysql`, `test_h2_v2_psql`, etc. (H2 with different dialect emulations)\n- `test_sqlite`\n- `test_mysql_v5`, `test_mysql_v8`\n- `test_mariadb`\n- `test_postgres`, `test_postgresng`\n- `test_oracle`\n- `test_sqlserver`\n\n## Testing Infrastructure\n\n### Test Base Classes and Utilities\n\nTests inherit from different base classes depending on the driver:\n\n**JDBC Tests** - inherit from `DatabaseTestsBase` (in `exposed-tests/src/main/kotlin/org/jetbrains/exposed/v1/tests/`):\n- Tests are parameterized by database dialect using `@ParameterizedClass` and `@MethodSource(\"data\")`\n- Each test automatically runs against all enabled dialects\n- Available dialects are determined by system properties set by Gradle test tasks\n\n**R2DBC Tests** - inherit from `R2dbcDatabaseTestsBase` (in `exposed-r2dbc-tests/src/main/kotlin/`):\n- Similar parameterized testing pattern as JDBC\n- Uses suspending functions and coroutine context\n- Test methods use `= runTest { }` for coroutine support, or utils methods like `withDb`, `withTables`,\n\n### TestDB Enums\n\nThere are separate `TestDB` enums for JDBC and R2DBC tests:\n\n**JDBC TestDB** (`exposed-tests/src/main/kotlin/org/jetbrains/exposed/v1/tests/TestDB.kt`):\n- Connection strings using JDBC URLs (e.g., `jdbc:h2:mem:...`, `jdbc:postgresql://...`)\n- JDBC driver class names\n- Before/after connection hooks\n- Database-specific configuration (e.g., H2 dialect emulation modes)\n\nAvailable JDBC TestDB values:\n- `H2_V2`, `H2_V2_MYSQL`, `H2_V2_PSQL`, `H2_V2_MARIADB`, `H2_V2_ORACLE`, `H2_V2_SQLSERVER`\n- `SQLITE`, `MYSQL_V5`, `MYSQL_V8`, `MARIADB`, `POSTGRESQL`, `POSTGRESQLNG`, `ORACLE`, `SQLSERVER`\n\n**R2DBC TestDB** (`exposed-r2dbc-tests/src/main/kotlin/org/jetbrains/exposed/v1/r2dbc/tests/TestDB.kt`):\n- Connection strings using R2DBC URLs (e.g., `r2dbc:h2:mem:...`, `r2dbc:postgresql://...`)\n- R2DBC isolation levels\n- Suspend-aware before/after connection hooks\n\nAvailable R2DBC TestDB values:\n- `H2_V2`, `H2_V2_MYSQL`, `H2_V2_PSQL`, `H2_V2_MARIADB`, `H2_V2_ORACLE`, `H2_V2_SQLSERVER`\n- `MYSQL_V5`, `MYSQL_V8`, `MARIADB`, `POSTGRESQL`, `ORACLE`, `SQLSERVER`\n- Note: R2DBC does **not** support `SQLITE` or `POSTGRESQLNG`\n\n### Writing Tests\n\nTests extend `DatabaseTestsBase` and use these helper functions:\n\n#### JDBC Tests with `withDb`\n```kotlin\nclass MyTests : DatabaseTestsBase() {\n    @Test\n    fun testSomething() {\n        withDb { testDb ->  // Runs against current dialect\n            // Create tables\n            SchemaUtils.create(MyTable)\n\n            // Insert/query data\n            MyTable.insert { it[name] = \"test\" }\n\n            // Clean up\n            SchemaUtils.drop(MyTable)\n        }\n    }\n}\n```\n\n#### Using `withTables` for automatic table management\n```kotlin\n@Test\nfun testWithTables() {\n    withTables(MyTable, AnotherTable) {\n        // Tables are created before block and dropped after\n        MyTable.insert { it[name] = \"test\" }\n    }\n}\n```\n\n#### Conditional tests\n```kotlin\n@Test\nfun testPostgresOnly() {\n    withDb(TestDB.POSTGRESQL) {  // Only runs for PostgreSQL\n        // Postgres-specific test\n    }\n}\n```\n\n#### Skip databases that don't support a feature\n```kotlin\n@Test\nfun testJsonSupport() {\n    withTables(JsonTable, excludeSettings = listOf(TestDB.SQLITE, TestDB.MYSQL_V5)) {\n        // Test JSON columns\n    }\n}\n```\n\n## Important Patterns\n\n### Transaction Context\n- JDBC: `transaction { }` - blocking transaction execution\n- JDBC: `suspendTransaction { }` - suspending, with actually blocking database connections\n- R2DBC: `suspendTransaction { }` - suspending, uses coroutine context\n- Never mix JDBC and R2DBC transaction functions\n\n### Database Vendor Support\nDatabase-specific behavior is in `exposed-core/src/main/kotlin/org/jetbrains/exposed/v1/core/vendors/`:\n- `H2.kt`, `MysqlDialect.kt`, `PostgreSQL.kt`, `OracleDialect.kt`, `SQLServerDialect.kt`, `SQLiteDialect.kt`, `MariaDBDialect.kt`\n- Extend `DatabaseDialect` and implement `VendorDialect`\n- Override `DataTypeProvider` and `FunctionProvider` for dialect-specific SQL\n\n## Common Development Tasks\n\n### Adding a new column type\n1. Create column type class in `exposed-core` (extends `ColumnType`)\n2. Add factory method to `Table` class\n3. Add dialect-specific SQL type mapping in `DataTypeProvider` implementations\n4. Add tests in `exposed-tests` covering multiple databases\n5. Add tests in `exposed-r2dbc-tests` covering multiple databases\n\n### Working with migrations\n- Migration modules use serialization to track schema state\n- JDBC migrations: `exposed-migration-jdbc` with `MigrationUtils`\n- R2DBC migrations: `exposed-migration-r2dbc` with suspend support\n- Both share common code from `exposed-migration-core`\n\n## Best Practices and Gotchas\n\n### Multi-Database Compatibility\n- Always test features against multiple databases, especially H2, PostgreSQL, and MySQL\n- Use dialect checks when implementing database-specific features:\n  ```kotlin\n  if (currentDialectTest is PostgreSQLDialect) {\n      // PostgreSQL-specific code\n  }\n  ```\n- H2 dialect emulation modes (`H2_V2_MYSQL`, `H2_V2_PSQL`, etc.) help catch compatibility issues early\n\n### Testing Best Practices\n- Extend `DatabaseTestsBase` or `R2dbcDatabaseTestsBase` for parameterized multi-database testing\n- Use `Assumptions.assumeTrue()` or `excludeSettings` argument in `withTables` to skip tests for unsupported databases\n- Prefer `withTables` over manual `SchemaUtils.create/drop` for cleaner tests\n- Test both JDBC and R2DBC implementations when adding core features\n- Use `currentDialectTest` to access current dialect in assertions\n\n### API Compatibility\n- Run `./gradlew apiCheck` before committing public API changes\n- Binary compatibility is critical - breaking changes require major version bump\n- Use `@InternalApi` annotation for internal implementation details\n- Document breaking changes in BREAKING_CHANGES.md under \"Breaking changes\" section\n\n## Code Style and Conventions\n\n### Style Configuration\n- **EditorConfig**: `.editorconfig` defines code formatting rules\n  - Indent: 4 spaces\n  - Max line length: 166 characters\n  - Charset: UTF-8\n  - End of line: LF\n  - Kotlin code style: KOTLIN_OFFICIAL\n\n- **Detekt**: Static analysis with `detekt/detekt-config.yml`\n  - Max issues: 0 (all issues must be fixed)\n  - Wildcard imports are allowed\n  - Magic numbers allowed in named arguments and ranges\n  - Run with: `./gradlew detekt`\n\n### Naming Conventions\n- Package structure uses `org.jetbrains.exposed.v1.*` namespace\n- Table objects: PascalCase (e.g., `Users`, `Cities`)\n- Column names: camelCase in code, snake_case in SQL\n- Test classes: Suffix with `Tests` or `Test`\n- Test methods: Descriptive names starting with `test`\n\n### Common Utilities\nLocated in `exposed-tests/src/main/kotlin/org/jetbrains/exposed/v1/tests/`:\n- `TestUtils.kt`: `currentDialectTest`, `currentDialectMetadataTest`, helper functions\n- `DatabaseTestsBase.kt`: Base class for all JDBC tests\n- `R2DBCDatabaseTestsBase.kt`: Base class for all R2DBC tests\n- `TestDB.kt`: Database connection configurations\n- `shared/Assert.kt`: Custom assertion functions\n- `shared/MiscTable.kt`, `shared/ForeignKeyTables.kt`: Reusable test tables\n\n## Sample Projects\n\nThe `samples/` directory contains reference implementations:\n- **exposed-ktor**: Ktor application with JDBC\n- **exposed-ktor-r2dbc**: Ktor application with R2DBC\n- **exposed-migration**: Migration examples\n- **exposed-spring**: Spring Boot integration examples\n\nThese demonstrate best practices for using Exposed in real applications.\n\n## Key Files\n\n- `buildSrc/`: Custom Gradle plugins and build configuration\n- `build.gradle.kts`: Root build configuration with testDb DSL usage\n- `settings.gradle.kts`: Module definitions\n- `buildScripts/docker/`: Database container configurations\n- `gradle.properties`: Version and build settings\n- `.editorconfig`: Code formatting rules\n- `detekt/detekt-config.yml`: Static analysis configuration\n"},"files":{"CLAUDE.md":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Project Overview\n\nExposed is a lightweight ORM framework for Kotlin that provides two APIs:\n- **DSL API**: Type-safe SQL-wrapping Domain Specific Language (in `exposed-core`)\n  - Works with both JDBC (`exposed-jdbc`) and R2DBC (`exposed-r2dbc`)\n- **DAO API**: Lightweight Data Access Object API (in `exposed-dao`)\n  - **Only works with JDBC** - does not support R2DBC\n\n## Module Architecture\n\n### Core Modules\n- **exposed-core**: Foundation layer with DSL API, database abstractions, column types, and vendor dialects\n- **exposed-dao**: DAO API with entity classes and relationships (JDBC only, does not work with R2DBC)\n- **exposed-jdbc**: JDBC implementation with blocking transactions\n- **exposed-r2dbc**: R2DBC implementation with suspending transactions\n\n### Extension Modules\n- **exposed-java-time**, **exposed-jodatime**, **exposed-kotlin-datetime**: Date/time support\n- **exposed-json**: JSON/JSONB column types\n- **exposed-crypt**: Encrypted column types\n- **exposed-money**: JavaMoney MonetaryAmount support\n- **exposed-migration-core**: Common migration functionality\n- **exposed-migration-jdbc**: JDBC-based schema migrations\n- **exposed-migration-r2dbc**: R2DBC-based schema migrations\n- **exposed-spring-boot-starter**: Spring Boot integration\n- **spring-transaction**: Spring Framework transaction manager\n\n### Test Modules\n- **exposed-tests**: Main JDBC-based test suite\n- **exposed-r2dbc-tests**: R2DBC-specific test suite\n- **exposed-jdbc-r2dbc-tests**: Cross-compatibility tests\n\n## Build & Development\n\n### Building\n```bash\n./gradlew compileKotlin  # Compile the projects code\n./gradlew detekt         # Validate code style\n./gradlew apiDump        # Update dokka API docs after changing public API\n```\n\n### Running Tests\n\nTests are organized by database and dialect. Each module has database-specific test tasks:\n\n#### Quick test with H2 (no Docker required)\n```bash\n./gradlew test_h2_v2                              # All modules with H2\n./gradlew :exposed-tests:test_h2_v2               # JDBC Tests with H2\n./gradlew :exposed-r2dbc-tests:test_h2_v2         # R2DBC Tests with H2\n```\n\n#### Test with Postgres\n```bash\n./gradlew test_postgres                           # All modules with Postgres\n./gradlew :exposed-tests:test_postgres            # JDBC Tests with Postgres\n./gradlew :exposed-r2dbc-tests:test_postgres      # R2DBC Tests with Postgres\n```\n\n#### Test with specific database (requires Docker)\n```bash\n# Start database containers first\n./gradlew mariadbComposeUp        # Start MariaDB\n./gradlew postgresComposeUp       # Start PostgreSQL\n./gradlew mysql8ComposeUp         # Start MySQL 8\n./gradlew oracleComposeUp         # Start Oracle\n./gradlew sqlserverComposeUp      # Start SQL Server\n\n# Run tests\n./gradlew :exposed-tests:test_postgres\n./gradlew :exposed-tests:test_mysql_v8\n./gradlew :exposed-tests:test_mariadb\n\n# Stop containers\n./gradlew postgresComposeDownForced\n```\n\n#### Run specific test class or method with H2\n```bash\n./gradlew :exposed-tests:test_h2_v2 --tests \"org.jetbrains.exposed.v1.tests.shared.dml.InsertTests\"\n./gradlew :exposed-tests:test_h2_v2 --tests \"*.InsertTests.testBatchInsert\"\n```\n\n#### Available test databases\n- `test_h2_v2`, `test_h2_v2_mysql`, `test_h2_v2_psql`, etc. (H2 with different dialect emulations)\n- `test_sqlite`\n- `test_mysql_v5`, `test_mysql_v8`\n- `test_mariadb`\n- `test_postgres`, `test_postgresng`\n- `test_oracle`\n- `test_sqlserver`\n\n## Testing Infrastructure\n\n### Test Base Classes and Utilities\n\nTests inherit from different base classes depending on the driver:\n\n**JDBC Tests** - inherit from `DatabaseTestsBase` (in `exposed-tests/src/main/kotlin/org/jetbrains/exposed/v1/tests/`):\n- Tests are parameterized by database dialect using `@ParameterizedClass` and `@MethodSource(\"data\")`\n- Each test automatically runs against all enabled dialects\n- Available dialects are determined by system properties set by Gradle test tasks\n\n**R2DBC Tests** - inherit from `R2dbcDatabaseTestsBase` (in `exposed-r2dbc-tests/src/main/kotlin/`):\n- Similar parameterized testing pattern as JDBC\n- Uses suspending functions and coroutine context\n- Test methods use `= runTest { }` for coroutine support, or utils methods like `withDb`, `withTables`,\n\n### TestDB Enums\n\nThere are separate `TestDB` enums for JDBC and R2DBC tests:\n\n**JDBC TestDB** (`exposed-tests/src/main/kotlin/org/jetbrains/exposed/v1/tests/TestDB.kt`):\n- Connection strings using JDBC URLs (e.g., `jdbc:h2:mem:...`, `jdbc:postgresql://...`)\n- JDBC driver class names\n- Before/after connection hooks\n- Database-specific configuration (e.g., H2 dialect emulation modes)\n\nAvailable JDBC TestDB values:\n- `H2_V2`, `H2_V2_MYSQL`, `H2_V2_PSQL`, `H2_V2_MARIADB`, `H2_V2_ORACLE`, `H2_V2_SQLSERVER`\n- `SQLITE`, `MYSQL_V5`, `MYSQL_V8`, `MARIADB`, `POSTGRESQL`, `POSTGRESQLNG`, `ORACLE`, `SQLSERVER`\n\n**R2DBC TestDB** (`exposed-r2dbc-tests/src/main/kotlin/org/jetbrains/exposed/v1/r2dbc/tests/TestDB.kt`):\n- Connection strings using R2DBC URLs (e.g., `r2dbc:h2:mem:...`, `r2dbc:postgresql://...`)\n- R2DBC isolation levels\n- Suspend-aware before/after connection hooks\n\nAvailable R2DBC TestDB values:\n- `H2_V2`, `H2_V2_MYSQL`, `H2_V2_PSQL`, `H2_V2_MARIADB`, `H2_V2_ORACLE`, `H2_V2_SQLSERVER`\n- `MYSQL_V5`, `MYSQL_V8`, `MARIADB`, `POSTGRESQL`, `ORACLE`, `SQLSERVER`\n- Note: R2DBC does **not** support `SQLITE` or `POSTGRESQLNG`\n\n### Writing Tests\n\nTests extend `DatabaseTestsBase` and use these helper functions:\n\n#### JDBC Tests with `withDb`\n```kotlin\nclass MyTests : DatabaseTestsBase() {\n    @Test\n    fun testSomething() {\n        withDb { testDb ->  // Runs against current dialect\n            // Create tables\n            SchemaUtils.create(MyTable)\n\n            // Insert/query data\n            MyTable.insert { it[name] = \"test\" }\n\n            // Clean up\n            SchemaUtils.drop(MyTable)\n        }\n    }\n}\n```\n\n#### Using `withTables` for automatic table management\n```kotlin\n@Test\nfun testWithTables() {\n    withTables(MyTable, AnotherTable) {\n        // Tables are created before block and dropped after\n        MyTable.insert { it[name] = \"test\" }\n    }\n}\n```\n\n#### Conditional tests\n```kotlin\n@Test\nfun testPostgresOnly() {\n    withDb(TestDB.POSTGRESQL) {  // Only runs for PostgreSQL\n        // Postgres-specific test\n    }\n}\n```\n\n#### Skip databases that don't support a feature\n```kotlin\n@Test\nfun testJsonSupport() {\n    withTables(JsonTable, excludeSettings = listOf(TestDB.SQLITE, TestDB.MYSQL_V5)) {\n        // Test JSON columns\n    }\n}\n```\n\n## Important Patterns\n\n### Transaction Context\n- JDBC: `transaction { }` - blocking transaction execution\n- JDBC: `suspendTransaction { }` - suspending, with actually blocking database connections\n- R2DBC: `suspendTransaction { }` - suspending, uses coroutine context\n- Never mix JDBC and R2DBC transaction functions\n\n### Database Vendor Support\nDatabase-specific behavior is in `exposed-core/src/main/kotlin/org/jetbrains/exposed/v1/core/vendors/`:\n- `H2.kt`, `MysqlDialect.kt`, `PostgreSQL.kt`, `OracleDialect.kt`, `SQLServerDialect.kt`, `SQLiteDialect.kt`, `MariaDBDialect.kt`\n- Extend `DatabaseDialect` and implement `VendorDialect`\n- Override `DataTypeProvider` and `FunctionProvider` for dialect-specific SQL\n\n## Common Development Tasks\n\n### Adding a new column type\n1. Create column type class in `exposed-core` (extends `ColumnType`)\n2. Add factory method to `Table` class\n3. Add dialect-specific SQL type mapping in `DataTypeProvider` implementations\n4. Add tests in `exposed-tests` covering multiple databases\n5. Add tests in `exposed-r2dbc-tests` covering multiple databases\n\n### Working with migrations\n- Migration modules use serialization to track schema state\n- JDBC migrations: `exposed-migration-jdbc` with `MigrationUtils`\n- R2DBC migrations: `exposed-migration-r2dbc` with suspend support\n- Both share common code from `exposed-migration-core`\n\n## Best Practices and Gotchas\n\n### Multi-Database Compatibility\n- Always test features against multiple databases, especially H2, PostgreSQL, and MySQL\n- Use dialect checks when implementing database-specific features:\n  ```kotlin\n  if (currentDialectTest is PostgreSQLDialect) {\n      // PostgreSQL-specific code\n  }\n  ```\n- H2 dialect emulation modes (`H2_V2_MYSQL`, `H2_V2_PSQL`, etc.) help catch compatibility issues early\n\n### Testing Best Practices\n- Extend `DatabaseTestsBase` or `R2dbcDatabaseTestsBase` for parameterized multi-database testing\n- Use `Assumptions.assumeTrue()` or `excludeSettings` argument in `withTables` to skip tests for unsupported databases\n- Prefer `withTables` over manual `SchemaUtils.create/drop` for cleaner tests\n- Test both JDBC and R2DBC implementations when adding core features\n- Use `currentDialectTest` to access current dialect in assertions\n\n### API Compatibility\n- Run `./gradlew apiCheck` before committing public API changes\n- Binary compatibility is critical - breaking changes require major version bump\n- Use `@InternalApi` annotation for internal implementation details\n- Document breaking changes in BREAKING_CHANGES.md under \"Breaking changes\" section\n\n## Code Style and Conventions\n\n### Style Configuration\n- **EditorConfig**: `.editorconfig` defines code formatting rules\n  - Indent: 4 spaces\n  - Max line length: 166 characters\n  - Charset: UTF-8\n  - End of line: LF\n  - Kotlin code style: KOTLIN_OFFICIAL\n\n- **Detekt**: Static analysis with `detekt/detekt-config.yml`\n  - Max issues: 0 (all issues must be fixed)\n  - Wildcard imports are allowed\n  - Magic numbers allowed in named arguments and ranges\n  - Run with: `./gradlew detekt`\n\n### Naming Conventions\n- Package structure uses `org.jetbrains.exposed.v1.*` namespace\n- Table objects: PascalCase (e.g., `Users`, `Cities`)\n- Column names: camelCase in code, snake_case in SQL\n- Test classes: Suffix with `Tests` or `Test`\n- Test methods: Descriptive names starting with `test`\n\n### Common Utilities\nLocated in `exposed-tests/src/main/kotlin/org/jetbrains/exposed/v1/tests/`:\n- `TestUtils.kt`: `currentDialectTest`, `currentDialectMetadataTest`, helper functions\n- `DatabaseTestsBase.kt`: Base class for all JDBC tests\n- `R2DBCDatabaseTestsBase.kt`: Base class for all R2DBC tests\n- `TestDB.kt`: Database connection configurations\n- `shared/Assert.kt`: Custom assertion functions\n- `shared/MiscTable.kt`, `shared/ForeignKeyTables.kt`: Reusable test tables\n\n## Sample Projects\n\nThe `samples/` directory contains reference implementations:\n- **exposed-ktor**: Ktor application with JDBC\n- **exposed-ktor-r2dbc**: Ktor application with R2DBC\n- **exposed-migration**: Migration examples\n- **exposed-spring**: Spring Boot integration examples\n\nThese demonstrate best practices for using Exposed in real applications.\n\n## Key Files\n\n- `buildSrc/`: Custom Gradle plugins and build configuration\n- `build.gradle.kts`: Root build configuration with testDb DSL usage\n- `settings.gradle.kts`: Module definitions\n- `buildScripts/docker/`: Database container configurations\n- `gradle.properties`: Version and build settings\n- `.editorconfig`: Code formatting rules\n- `detekt/detekt-config.yml`: Static analysis configuration\n"},"items":[{"name":"CLAUDE.md","path":"CLAUDE.md","title":"CLAUDE.md","content":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Project Overview\n\nExposed is a lightweight ORM framework for Kotlin that provides two APIs:\n- **DSL API**: Type-safe SQL-wrapping Domain Specific Language (in `exposed-core`)\n  - Works with both JDBC (`exposed-jdbc`) and R2DBC (`exposed-r2dbc`)\n- **DAO API**: Lightweight Data Access Object API (in `exposed-dao`)\n  - **Only works with JDBC** - does not support R2DBC\n\n## Module Architecture\n\n### Core Modules\n- **exposed-core**: Foundation layer with DSL API, database abstractions, column types, and vendor dialects\n- **exposed-dao**: DAO API with entity classes and relationships (JDBC only, does not work with R2DBC)\n- **exposed-jdbc**: JDBC implementation with blocking transactions\n- **exposed-r2dbc**: R2DBC implementation with suspending transactions\n\n### Extension Modules\n- **exposed-java-time**, **exposed-jodatime**, **exposed-kotlin-datetime**: Date/time support\n- **exposed-json**: JSON/JSONB column types\n- **exposed-crypt**: Encrypted column types\n- **exposed-money**: JavaMoney MonetaryAmount support\n- **exposed-migration-core**: Common migration functionality\n- **exposed-migration-jdbc**: JDBC-based schema migrations\n- **exposed-migration-r2dbc**: R2DBC-based schema migrations\n- **exposed-spring-boot-starter**: Spring Boot integration\n- **spring-transaction**: Spring Framework transaction manager\n\n### Test Modules\n- **exposed-tests**: Main JDBC-based test suite\n- **exposed-r2dbc-tests**: R2DBC-specific test suite\n- **exposed-jdbc-r2dbc-tests**: Cross-compatibility tests\n\n## Build & Development\n\n### Building\n```bash\n./gradlew compileKotlin  # Compile the projects code\n./gradlew detekt         # Validate code style\n./gradlew apiDump        # Update dokka API docs after changing public API\n```\n\n### Running Tests\n\nTests are organized by database and dialect. Each module has database-specific test tasks:\n\n#### Quick test with H2 (no Docker required)\n```bash\n./gradlew test_h2_v2                              # All modules with H2\n./gradlew :exposed-tests:test_h2_v2               # JDBC Tests with H2\n./gradlew :exposed-r2dbc-tests:test_h2_v2         # R2DBC Tests with H2\n```\n\n#### Test with Postgres\n```bash\n./gradlew test_postgres                           # All modules with Postgres\n./gradlew :exposed-tests:test_postgres            # JDBC Tests with Postgres\n./gradlew :exposed-r2dbc-tests:test_postgres      # R2DBC Tests with Postgres\n```\n\n#### Test with specific database (requires Docker)\n```bash\n# Start database containers first\n./gradlew mariadbComposeUp        # Start MariaDB\n./gradlew postgresComposeUp       # Start PostgreSQL\n./gradlew mysql8ComposeUp         # Start MySQL 8\n./gradlew oracleComposeUp         # Start Oracle\n./gradlew sqlserverComposeUp      # Start SQL Server\n\n# Run tests\n./gradlew :exposed-tests:test_postgres\n./gradlew :exposed-tests:test_mysql_v8\n./gradlew :exposed-tests:test_mariadb\n\n# Stop containers\n./gradlew postgresComposeDownForced\n```\n\n#### Run specific test class or method with H2\n```bash\n./gradlew :exposed-tests:test_h2_v2 --tests \"org.jetbrains.exposed.v1.tests.shared.dml.InsertTests\"\n./gradlew :exposed-tests:test_h2_v2 --tests \"*.InsertTests.testBatchInsert\"\n```\n\n#### Available test databases\n- `test_h2_v2`, `test_h2_v2_mysql`, `test_h2_v2_psql`, etc. (H2 with different dialect emulations)\n- `test_sqlite`\n- `test_mysql_v5`, `test_mysql_v8`\n- `test_mariadb`\n- `test_postgres`, `test_postgresng`\n- `test_oracle`\n- `test_sqlserver`\n\n## Testing Infrastructure\n\n### Test Base Classes and Utilities\n\nTests inherit from different base classes depending on the driver:\n\n**JDBC Tests** - inherit from `DatabaseTestsBase` (in `exposed-tests/src/main/kotlin/org/jetbrains/exposed/v1/tests/`):\n- Tests are parameterized by database dialect using `@ParameterizedClass` and `@MethodSource(\"data\")`\n- Each test automatically runs against all enabled dialects\n- Available dialects are determined by system properties set by Gradle test tasks\n\n**R2DBC Tests** - inherit from `R2dbcDatabaseTestsBase` (in `exposed-r2dbc-tests/src/main/kotlin/`):\n- Similar parameterized testing pattern as JDBC\n- Uses suspending functions and coroutine context\n- Test methods use `= runTest { }` for coroutine support, or utils methods like `withDb`, `withTables`,\n\n### TestDB Enums\n\nThere are separate `TestDB` enums for JDBC and R2DBC tests:\n\n**JDBC TestDB** (`exposed-tests/src/main/kotlin/org/jetbrains/exposed/v1/tests/TestDB.kt`):\n- Connection strings using JDBC URLs (e.g., `jdbc:h2:mem:...`, `jdbc:postgresql://...`)\n- JDBC driver class names\n- Before/after connection hooks\n- Database-specific configuration (e.g., H2 dialect emulation modes)\n\nAvailable JDBC TestDB values:\n- `H2_V2`, `H2_V2_MYSQL`, `H2_V2_PSQL`, `H2_V2_MARIADB`, `H2_V2_ORACLE`, `H2_V2_SQLSERVER`\n- `SQLITE`, `MYSQL_V5`, `MYSQL_V8`, `MARIADB`, `POSTGRESQL`, `POSTGRESQLNG`, `ORACLE`, `SQLSERVER`\n\n**R2DBC TestDB** (`exposed-r2dbc-tests/src/main/kotlin/org/jetbrains/exposed/v1/r2dbc/tests/TestDB.kt`):\n- Connection strings using R2DBC URLs (e.g., `r2dbc:h2:mem:...`, `r2dbc:postgresql://...`)\n- R2DBC isolation levels\n- Suspend-aware before/after connection hooks\n\nAvailable R2DBC TestDB values:\n- `H2_V2`, `H2_V2_MYSQL`, `H2_V2_PSQL`, `H2_V2_MARIADB`, `H2_V2_ORACLE`, `H2_V2_SQLSERVER`\n- `MYSQL_V5`, `MYSQL_V8`, `MARIADB`, `POSTGRESQL`, `ORACLE`, `SQLSERVER`\n- Note: R2DBC does **not** support `SQLITE` or `POSTGRESQLNG`\n\n### Writing Tests\n\nTests extend `DatabaseTestsBase` and use these helper functions:\n\n#### JDBC Tests with `withDb`\n```kotlin\nclass MyTests : DatabaseTestsBase() {\n    @Test\n    fun testSomething() {\n        withDb { testDb ->  // Runs against current dialect\n            // Create tables\n            SchemaUtils.create(MyTable)\n\n            // Insert/query data\n            MyTable.insert { it[name] = \"test\" }\n\n            // Clean up\n            SchemaUtils.drop(MyTable)\n        }\n    }\n}\n```\n\n#### Using `withTables` for automatic table management\n```kotlin\n@Test\nfun testWithTables() {\n    withTables(MyTable, AnotherTable) {\n        // Tables are created before block and dropped after\n        MyTable.insert { it[name] = \"test\" }\n    }\n}\n```\n\n#### Conditional tests\n```kotlin\n@Test\nfun testPostgresOnly() {\n    withDb(TestDB.POSTGRESQL) {  // Only runs for PostgreSQL\n        // Postgres-specific test\n    }\n}\n```\n\n#### Skip databases that don't support a feature\n```kotlin\n@Test\nfun testJsonSupport() {\n    withTables(JsonTable, excludeSettings = listOf(TestDB.SQLITE, TestDB.MYSQL_V5)) {\n        // Test JSON columns\n    }\n}\n```\n\n## Important Patterns\n\n### Transaction Context\n- JDBC: `transaction { }` - blocking transaction execution\n- JDBC: `suspendTransaction { }` - suspending, with actually blocking database connections\n- R2DBC: `suspendTransaction { }` - suspending, uses coroutine context\n- Never mix JDBC and R2DBC transaction functions\n\n### Database Vendor Support\nDatabase-specific behavior is in `exposed-core/src/main/kotlin/org/jetbrains/exposed/v1/core/vendors/`:\n- `H2.kt`, `MysqlDialect.kt`, `PostgreSQL.kt`, `OracleDialect.kt`, `SQLServerDialect.kt`, `SQLiteDialect.kt`, `MariaDBDialect.kt`\n- Extend `DatabaseDialect` and implement `VendorDialect`\n- Override `DataTypeProvider` and `FunctionProvider` for dialect-specific SQL\n\n## Common Development Tasks\n\n### Adding a new column type\n1. Create column type class in `exposed-core` (extends `ColumnType`)\n2. Add factory method to `Table` class\n3. Add dialect-specific SQL type mapping in `DataTypeProvider` implementations\n4. Add tests in `exposed-tests` covering multiple databases\n5. Add tests in `exposed-r2dbc-tests` covering multiple databases\n\n### Working with migrations\n- Migration modules use serialization to track schema state\n- JDBC migrations: `exposed-migration-jdbc` with `MigrationUtils`\n- R2DBC migrations: `exposed-migration-r2dbc` with suspend support\n- Both share common code from `exposed-migration-core`\n\n## Best Practices and Gotchas\n\n### Multi-Database Compatibility\n- Always test features against multiple databases, especially H2, PostgreSQL, and MySQL\n- Use dialect checks when implementing database-specific features:\n  ```kotlin\n  if (currentDialectTest is PostgreSQLDialect) {\n      // PostgreSQL-specific code\n  }\n  ```\n- H2 dialect emulation modes (`H2_V2_MYSQL`, `H2_V2_PSQL`, etc.) help catch compatibility issues early\n\n### Testing Best Practices\n- Extend `DatabaseTestsBase` or `R2dbcDatabaseTestsBase` for parameterized multi-database testing\n- Use `Assumptions.assumeTrue()` or `excludeSettings` argument in `withTables` to skip tests for unsupported databases\n- Prefer `withTables` over manual `SchemaUtils.create/drop` for cleaner tests\n- Test both JDBC and R2DBC implementations when adding core features\n- Use `currentDialectTest` to access current dialect in assertions\n\n### API Compatibility\n- Run `./gradlew apiCheck` before committing public API changes\n- Binary compatibility is critical - breaking changes require major version bump\n- Use `@InternalApi` annotation for internal implementation details\n- Document breaking changes in BREAKING_CHANGES.md under \"Breaking changes\" section\n\n## Code Style and Conventions\n\n### Style Configuration\n- **EditorConfig**: `.editorconfig` defines code formatting rules\n  - Indent: 4 spaces\n  - Max line length: 166 characters\n  - Charset: UTF-8\n  - End of line: LF\n  - Kotlin code style: KOTLIN_OFFICIAL\n\n- **Detekt**: Static analysis with `detekt/detekt-config.yml`\n  - Max issues: 0 (all issues must be fixed)\n  - Wildcard imports are allowed\n  - Magic numbers allowed in named arguments and ranges\n  - Run with: `./gradlew detekt`\n\n### Naming Conventions\n- Package structure uses `org.jetbrains.exposed.v1.*` namespace\n- Table objects: PascalCase (e.g., `Users`, `Cities`)\n- Column names: camelCase in code, snake_case in SQL\n- Test classes: Suffix with `Tests` or `Test`\n- Test methods: Descriptive names starting with `test`\n\n### Common Utilities\nLocated in `exposed-tests/src/main/kotlin/org/jetbrains/exposed/v1/tests/`:\n- `TestUtils.kt`: `currentDialectTest`, `currentDialectMetadataTest`, helper functions\n- `DatabaseTestsBase.kt`: Base class for all JDBC tests\n- `R2DBCDatabaseTestsBase.kt`: Base class for all R2DBC tests\n- `TestDB.kt`: Database connection configurations\n- `shared/Assert.kt`: Custom assertion functions\n- `shared/MiscTable.kt`, `shared/ForeignKeyTables.kt`: Reusable test tables\n\n## Sample Projects\n\nThe `samples/` directory contains reference implementations:\n- **exposed-ktor**: Ktor application with JDBC\n- **exposed-ktor-r2dbc**: Ktor application with R2DBC\n- **exposed-migration**: Migration examples\n- **exposed-spring**: Spring Boot integration examples\n\nThese demonstrate best practices for using Exposed in real applications.\n\n## Key Files\n\n- `buildSrc/`: Custom Gradle plugins and build configuration\n- `build.gradle.kts`: Root build configuration with testDb DSL usage\n- `settings.gradle.kts`: Module definitions\n- `buildScripts/docker/`: Database container configurations\n- `gradle.properties`: Version and build settings\n- `.editorconfig`: Code formatting rules\n- `detekt/detekt-config.yml`: Static analysis configuration\n","category":"root","tokens":2801}]}