Skip to content

feat: add TiDB as a compatibility-tested database#313

Open
driessamyn wants to merge 1 commit into
mainfrom
feature/add-tidb-compat
Open

feat: add TiDB as a compatibility-tested database#313
driessamyn wants to merge 1 commit into
mainfrom
feature/add-tidb-compat

Conversation

@driessamyn
Copy link
Copy Markdown
Owner

@driessamyn driessamyn commented Mar 23, 2026

Summary

  • Adds TiDB compatibility testing (maps to DbFlavour.MYSQL)
  • Uses GenericContainer with pingcap/tidb:v8.5.1
  • Added to nightly compatibility-test CI matrix

Test plan

  • Integration tests pass locally with -Ddb=TIDB
  • CI compatibility-test job runs successfully

Summary by CodeRabbit

  • New Features

    • Added TiDB as a supported database option.
  • Tests

    • Extended integration and unit tests to validate TiDB behavior.
  • Documentation

    • Updated supported-database badges to include TiDB.
  • Chores

    • CI pipeline expanded to run compatibility tests against TiDB.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 23, 2026

📝 Walkthrough

Walkthrough

This pull request adds TiDB support by extending the CI compatibility matrix, adding a Testcontainers-based TiDB integration test setup, and treating TiDB product names as MySQL in database-flavour detection.

Changes

Cohort / File(s) Summary
CI & Docs
.github/workflows/build-and-test.yml, README.md
Added TIDB to the CI compatibility test matrix and added a TiDB badge to README.
Integration test infra
core/src/integrationTest/kotlin/net/samyn/kapper/AbstractDbTests.kt
Added a lazily-started Testcontainers pingcap/tidb:v8.5.1 GenericContainer and a TIDB entry in the allDbs connection map (JDBC URL using mapped host/port).
Runtime DB flavour detection
core/src/main/kotlin/net/samyn/kapper/internal/DbFlavourFunc.kt
Treat tidb (case-insensitive) as DbFlavour.MYSQL in Connection.getDbFlavour().
Tests
core/src/test/kotlin/net/samyn/kapper/internal/DbFlavourTest.kt
Extended parameterized test inputs to include TiDB product-name variants verifying they map to DbFlavour.MYSQL.

Sequence Diagram(s)

sequenceDiagram
  participant GH as GitHub Actions
  participant Runner as CI Runner
  participant Gradle as Gradle (integrationTest)
  participant TC as Testcontainers
  participant TiDB as TiDB Container
  participant Test as Integration Tests
  participant Art as Artifact Upload

  GH->>Runner: matrix job (db = MARIADB, TIDB)
  Runner->>Gradle: ./gradlew integrationTest -Ddb=${{ matrix.db }}
  Gradle->>TC: start GenericContainer (only for TIDB case)
  TC->>TiDB: pull/start pingcap/tidb:v8.5.1
  Gradle->>Test: run tests using JDBC -> TiDB (mapped host/port)
  Test-->>Gradle: test results
  Runner->>Art: upload ${matrix.db}-compat-test-results
  GH-->>Runner: report check "${matrix.db} Compatibility Tests"
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • #306: Modifies CI matrix and DbFlavour detection for adding another DB vendor; touches similar files and test infra.
  • #305: Added a new DB flavour previously with similar CI and testcontainer changes.

Suggested labels

run-compat-tests

Poem

🐰 Hopping into logs with a curious twitch,
TiDB joins the garden, snug as a stitch.
Containers hum softly, tests take their leap,
Badges gleam proudly for databases we keep.
A little rabbit cheers — integrations run deep!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding TiDB as a compatibility-tested database. It matches the primary objective of the PR and accurately reflects the work across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/add-tidb-compat

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud
Copy link
Copy Markdown

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 23, 2026

Unit Tests

0 files   -  61  0 suites   - 61   0s ⏱️ - 3m 2s
0 tests  - 517  0 ✅  - 517  0 💤 ±0  0 ❌ ±0 
0 runs   - 533  0 ✅  - 533  0 💤 ±0  0 ❌ ±0 

Results for commit 2caedbc. ± Comparison against base commit c431fe4.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown

Code Coverage

File Coverage [100.00%]
core/src/main/kotlin/net/samyn/kapper/internal/DbFlavourFunc.kt 100.00%
Total Project Coverage 98.17%

@github-actions
Copy link
Copy Markdown

DUCKDB Integration Tests

10 files  ±0  10 suites  ±0   23s ⏱️ -1s
46 tests ±0  46 ✅ ±0  0 💤 ±0  0 ❌ ±0 
76 runs  ±0  76 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 392196a. ± Comparison against base commit c431fe4.

@github-actions
Copy link
Copy Markdown

POSTGRESQL Integration Tests

10 files  ±0  10 suites  ±0   27s ⏱️ -2s
46 tests ±0  46 ✅ ±0  0 💤 ±0  0 ❌ ±0 
76 runs  ±0  76 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 392196a. ± Comparison against base commit c431fe4.

@github-actions
Copy link
Copy Markdown

SQLITE Integration Tests

10 files  ±0  10 suites  ±0   27s ⏱️ -1s
46 tests ±0  46 ✅ ±0  0 💤 ±0  0 ❌ ±0 
76 runs  ±0  76 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 392196a. ± Comparison against base commit c431fe4.

@github-actions
Copy link
Copy Markdown

MSSQLSERVER Integration Tests

10 files  ±0  10 suites  ±0   44s ⏱️ -1s
46 tests ±0  46 ✅ ±0  0 💤 ±0  0 ❌ ±0 
76 runs  ±0  76 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 392196a. ± Comparison against base commit c431fe4.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/src/integrationTest/kotlin/net/samyn/kapper/AbstractDbTests.kt`:
- Line 62: The GenericContainer instantiation uses the string-based constructor
which can break Kotlin's SELF type inference and is deprecated; replace
GenericContainer("pingcap/tidb:v8.5.1") with the typed form
GenericContainer<GenericContainer<*>>(DockerImageName.parse("pingcap/tidb:v8.5.1"))
(or more specifically GenericContainer<DockerImageName> style per Testcontainers
examples) and add the import org.testcontainers.utility.DockerImageName so the
container creation uses DockerImageName.parse(...) for stable API typing and
correct SELF bound resolution; update the GenericContainer usage site (the
expression GenericContainer(...)) accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 490e8a2f-12f7-4725-94aa-e215046ff65d

📥 Commits

Reviewing files that changed from the base of the PR and between c431fe4 and 392196a.

📒 Files selected for processing (5)
  • .github/workflows/build-and-test.yml
  • README.md
  • core/src/integrationTest/kotlin/net/samyn/kapper/AbstractDbTests.kt
  • core/src/main/kotlin/net/samyn/kapper/internal/DbFlavourFunc.kt
  • core/src/test/kotlin/net/samyn/kapper/internal/DbFlavourTest.kt

}

private val tidb by lazy {
GenericContainer("pingcap/tidb:v8.5.1").apply {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

For the current Testcontainers Java API, what is the recommended Kotlin syntax to instantiate GenericContainer? Is GenericContainer("image")valid, or should it beGenericContainer("image")/KGenericContainer?

💡 Result:

For current Testcontainers Java, the “blessed” way is to construct a GenericContainer<?> from a DockerImageName, not a raw string. In Kotlin that typically becomes:

import org.testcontainers.containers.GenericContainer
import org.testcontainers.utility.DockerImageName

val redis = GenericContainer<Nothing>(DockerImageName.parse("redis:6-alpine"))
  .withExposedPorts(6379)
  • Testcontainers’ docs show GenericContainer<?> created via new GenericContainer<>(DockerImageName.parse(...)). [1]
  • The Java API provides GenericContainer(DockerImageName) (and still has a GenericContainer(String) overload), but Testcontainers has been deprecating the (...String) constructor pattern in favor of DockerImageName. [2][3]

So:

  • GenericContainer("image"): often not what you want in Kotlin (type inference for SELF extends GenericContainer<SELF> is awkward) and it also pushes you toward a constructor style Testcontainers has been moving away from. [2][3]
  • GenericContainer<Nothing>(...): recommended Kotlin workaround when you just need a plain GenericContainer and don’t care about fluent “self types”.
  • KGenericContainer: optional convenience (usually a tiny Kotlin subclass people create) if you want fluent chaining to return your subtype, but it’s not required by the Java API. (It’s essentially a Kotlin ergonomics helper built on top of GenericContainer<SELF>.) [2]

Sources:
[1] (java.testcontainers.org)
[2] (javadoc.io)
[3] (newreleases.io)

Citations:


🏁 Script executed:

# Find the file and check context around line 62
cd core/src/integrationTest/kotlin/net/samyn/kapper && \
cat -n AbstractDbTests.kt | sed -n '55,70p'

Repository: driessamyn/kapper

Length of output: 632


🏁 Script executed:

# Check for Testcontainers dependency and version
fd -e "build.gradle" -o "pom.xml" -o "build.gradle.kts" | head -5 | xargs grep -l "testcontainers" -A 2 -B 2

Repository: driessamyn/kapper

Length of output: 196


🏁 Script executed:

# Search for other GenericContainer usages in the codebase
rg "GenericContainer" --type kotlin -B 2 -A 2

Repository: driessamyn/kapper

Length of output: 1188


🏁 Script executed:

# Find build files with correct syntax
fd "build.gradle" -o "pom.xml" -o "build.gradle.kts" | xargs grep -l "testcontainers" -A 3

Repository: driessamyn/kapper

Length of output: 196


🏁 Script executed:

# Check if code currently compiles and check for any reported issues
git log --oneline -20 | head -10

Repository: driessamyn/kapper

Length of output: 118


🏁 Script executed:

# Look at the full build.gradle or pom.xml to find Testcontainers version
fd "build.gradle" --type f | head -3 | xargs cat | grep -A 5 -B 5 "testcontainers"

Repository: driessamyn/kapper

Length of output: 43


🏁 Script executed:

# List all build files in the repo
find . -maxdepth 2 -name "build.gradle*" -o -name "pom.xml" | head -10

Repository: driessamyn/kapper

Length of output: 190


🏁 Script executed:

# Search for testcontainers in all gradle/maven files
rg "testcontainers" -t gradle -t xml -A 2

Repository: driessamyn/kapper

Length of output: 209


🏁 Script executed:

# Check the core/build.gradle.kts file since that's where the test is
cat ./core/build.gradle.kts | grep -A 5 -B 5 "testcontainers"

Repository: driessamyn/kapper

Length of output: 43


🏁 Script executed:

# Also check the main build.gradle.kts
cat ./build.gradle.kts | grep -A 5 -B 5 "testcontainers"

Repository: driessamyn/kapper

Length of output: 43


🏁 Script executed:

# Try searching without grep first to see the full content
cat ./core/build.gradle.kts

Repository: driessamyn/kapper

Length of output: 718


🏁 Script executed:

# Also check if testcontainers is in root build.gradle.kts
cat ./build.gradle.kts

Repository: driessamyn/kapper

Length of output: 1938


🏁 Script executed:

# Find the version catalog (usually in gradle/libs.versions.toml or similar)
find . -name "*.versions.toml" -o -name "libs.versions.toml" | head -5

Repository: driessamyn/kapper

Length of output: 88


🏁 Script executed:

# Look for gradle folder with version catalog
ls -la gradle/ 2>/dev/null || echo "No gradle folder"

Repository: driessamyn/kapper

Length of output: 300


🏁 Script executed:

# Check the testcontainers version in the libs.versions.toml
cat ./gradle/libs.versions.toml | grep -A 10 -B 2 "testcontainers"

Repository: driessamyn/kapper

Length of output: 1694


🏁 Script executed:

# Find the version reference for testcontainers
cat ./gradle/libs.versions.toml | grep "test-containers"

Repository: driessamyn/kapper

Length of output: 1100


🏁 Script executed:

# Check if there are any other GenericContainer usages or similar patterns
rg "GenericContainer\|MariaDBContainer\|MSSQLServerContainer" -A 2

Repository: driessamyn/kapper

Length of output: 43


🏁 Script executed:

# Look for any DockerImageName usage in the codebase
rg "DockerImageName" -A 2

Repository: driessamyn/kapper

Length of output: 43


🏁 Script executed:

# Check the git history for the TiDB addition to see if there were any issues
git log --oneline --all -- "core/src/integrationTest/kotlin/net/samyn/kapper/AbstractDbTests.kt" | head -5

Repository: driessamyn/kapper

Length of output: 345


🏁 Script executed:

# Check the imports in AbstractDbTests.kt to see what's currently being used
head -40 core/src/integrationTest/kotlin/net/samyn/kapper/AbstractDbTests.kt

Repository: driessamyn/kapper

Length of output: 1526


🏁 Script executed:

# Try to understand the GenericContainer API in 1.21.4
# Search for any comments or documentation about the string constructor
rg "withExposedPorts\|start\(\)" core/src/integrationTest/kotlin/net/samyn/kapper/AbstractDbTests.kt -B 3 -A 1

Repository: driessamyn/kapper

Length of output: 43


🏁 Script executed:

# Check if the code compiles by looking at recent commits and build status
git show 392196a --stat | head -20

Repository: driessamyn/kapper

Length of output: 1126


🏁 Script executed:

# Check the exact syntax being used in similar containers
cat core/src/integrationTest/kotlin/net/samyn/kapper/AbstractDbTests.kt | sed -n '57,75p'

Repository: driessamyn/kapper

Length of output: 777


Use explicit type argument to improve Kotlin type inference with GenericContainer.

The string-based constructor form GenericContainer("image") can encounter type inference issues in Kotlin when resolving the SELF bound of GenericContainer<SELF>. Additionally, Testcontainers (v1.21.4 in use here) has moved away from the string-based constructor in favor of DockerImageName.parse() for better API stability.

Prefer explicit type parameters combined with the recommended DockerImageName pattern:

Proposed fix
-        private val tidb by lazy {
-            GenericContainer("pingcap/tidb:v8.5.1").apply {
+        private val tidb by lazy {
+            GenericContainer<Nothing>(DockerImageName.parse("pingcap/tidb:v8.5.1")).apply {
                 withExposedPorts(4000)
                 start()
             }
         }

Add import: import org.testcontainers.utility.DockerImageName

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/integrationTest/kotlin/net/samyn/kapper/AbstractDbTests.kt` at line
62, The GenericContainer instantiation uses the string-based constructor which
can break Kotlin's SELF type inference and is deprecated; replace
GenericContainer("pingcap/tidb:v8.5.1") with the typed form
GenericContainer<GenericContainer<*>>(DockerImageName.parse("pingcap/tidb:v8.5.1"))
(or more specifically GenericContainer<DockerImageName> style per Testcontainers
examples) and add the import org.testcontainers.utility.DockerImageName so the
container creation uses DockerImageName.parse(...) for stable API typing and
correct SELF bound resolution; update the GenericContainer usage site (the
expression GenericContainer(...)) accordingly.

@github-actions
Copy link
Copy Markdown

ORACLE Integration Tests

10 files  ±0  10 suites  ±0   1m 8s ⏱️ -13s
46 tests ±0  46 ✅ ±0  0 💤 ±0  0 ❌ ±0 
76 runs  ±0  76 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 392196a. ± Comparison against base commit c431fe4.

@github-actions
Copy link
Copy Markdown

MYSQL Integration Tests

10 files  ±0  10 suites  ±0   48s ⏱️ -1s
46 tests ±0  46 ✅ ±0  0 💤 ±0  0 ❌ ±0 
76 runs  ±0  76 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 392196a. ± Comparison against base commit c431fe4.

@driessamyn driessamyn force-pushed the feature/add-tidb-compat branch from 392196a to 2caedbc Compare March 24, 2026 07:34
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
core/src/integrationTest/kotlin/net/samyn/kapper/AbstractDbTests.kt (1)

62-67: Extract TiDB literals to constants to avoid config drift.

Line 64 and Line 100 repeat the TiDB port literal (4000), and the image/database strings are embedded inline. Pulling these into companion-object constants makes future updates safer and clearer.

Proposed refactor
 companion object {
+        private const val TIDB_IMAGE = "pingcap/tidb:v8.5.1"
+        private const val TIDB_PORT = 4000
+        private const val TIDB_DATABASE = "test"
+
         init {
             Class.forName("org.sqlite.JDBC")
             Class.forName("org.duckdb.DuckDBDriver")
         }
@@
         private val tidb by lazy {
-            GenericContainer<Nothing>(DockerImageName.parse("pingcap/tidb:v8.5.1")).apply {
-                withExposedPorts(4000)
+            GenericContainer<Nothing>(DockerImageName.parse(TIDB_IMAGE)).apply {
+                withExposedPorts(TIDB_PORT)
                 start()
             }
         }
@@
                 "TIDB" to {
                     DriverManager.getConnection(
-                        "jdbc:mysql://${tidb.host}:${tidb.getMappedPort(4000)}/test?user=root&allowPublicKeyRetrieval=true&useSSL=false",
+                        "jdbc:mysql://${tidb.host}:${tidb.getMappedPort(TIDB_PORT)}/$TIDB_DATABASE?user=root&allowPublicKeyRetrieval=true&useSSL=false",
                     )
                 },
             )

Also applies to: 98-102

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/integrationTest/kotlin/net/samyn/kapper/AbstractDbTests.kt` around
lines 62 - 67, The TiDB container configuration in the lazy val tidb and its
usages hardcodes literals (image tag "pingcap/tidb:v8.5.1", port 4000 and any
inline DB name strings); extract these into companion-object constants (e.g.,
TIDB_IMAGE, TIDB_PORT, TIDB_DB_NAME) and replace occurrences in
GenericContainer<Nothing>(DockerImageName.parse(...)), withExposedPorts(4000)
and any other inline references so updates are centralized; update the lazy val
tidb and any other places (around the second occurrence at lines ~98–102) to
reference those constants.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@core/src/integrationTest/kotlin/net/samyn/kapper/AbstractDbTests.kt`:
- Around line 62-67: The TiDB container configuration in the lazy val tidb and
its usages hardcodes literals (image tag "pingcap/tidb:v8.5.1", port 4000 and
any inline DB name strings); extract these into companion-object constants
(e.g., TIDB_IMAGE, TIDB_PORT, TIDB_DB_NAME) and replace occurrences in
GenericContainer<Nothing>(DockerImageName.parse(...)), withExposedPorts(4000)
and any other inline references so updates are centralized; update the lazy val
tidb and any other places (around the second occurrence at lines ~98–102) to
reference those constants.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 36c40a76-c011-42bb-99d2-0a27ba888916

📥 Commits

Reviewing files that changed from the base of the PR and between 392196a and 2caedbc.

📒 Files selected for processing (5)
  • .github/workflows/build-and-test.yml
  • README.md
  • core/src/integrationTest/kotlin/net/samyn/kapper/AbstractDbTests.kt
  • core/src/main/kotlin/net/samyn/kapper/internal/DbFlavourFunc.kt
  • core/src/test/kotlin/net/samyn/kapper/internal/DbFlavourTest.kt
✅ Files skipped from review due to trivial changes (3)
  • README.md
  • core/src/main/kotlin/net/samyn/kapper/internal/DbFlavourFunc.kt
  • core/src/test/kotlin/net/samyn/kapper/internal/DbFlavourTest.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/build-and-test.yml

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant