Skip to content

Commit 4d7ef5d

Browse files
committed
feat: add StarRocks as a compatibility-tested database
1 parent c431fe4 commit 4d7ef5d

8 files changed

Lines changed: 86 additions & 13 deletions

File tree

.github/workflows/build-and-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ jobs:
126126
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'run-compat-tests')
127127
strategy:
128128
matrix:
129-
db: [ MARIADB ]
129+
db: [ MARIADB, STARROCKS ]
130130
steps:
131131
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
132132
with:

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Kapper is a lightweight, Dapper-inspired ORM (Object-Relational Mapping) library
2222
![MSSQL](https://img.shields.io/badge/mssql-%23CC2927.svg?style=for-the-badge&logo=microsoftsqlserver&logoColor=white)
2323
![DuckDB](https://img.shields.io/badge/duckdb-FFF000.svg?style=for-the-badge&logo=duckdb&logoColor=black)
2424
![MariaDB](https://img.shields.io/badge/mariadb-003545.svg?style=for-the-badge&logo=mariadb&logoColor=white)
25+
![StarRocks](https://img.shields.io/badge/starrocks-5C2D91.svg?style=for-the-badge&logoColor=white)
2526

2627
See [Kapper](https://driessamyn.github.io/kapper/) for more information.
2728

core/src/integrationTest/kotlin/net/samyn/kapper/AbstractDbTests.kt

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import org.junit.jupiter.params.ParameterizedClass
1010
import org.junit.jupiter.params.provider.Arguments
1111
import org.junit.jupiter.params.provider.Arguments.arguments
1212
import org.junit.jupiter.params.provider.MethodSource
13+
import org.testcontainers.containers.GenericContainer
1314
import org.testcontainers.containers.JdbcDatabaseContainer
1415
import org.testcontainers.containers.MSSQLServerContainer
1516
import org.testcontainers.containers.MariaDBContainer
@@ -57,6 +58,14 @@ abstract class AbstractDbTests {
5758
MariaDBContainer("mariadb:11.7").also { it.start() }
5859
}
5960

61+
private val starrocks by lazy {
62+
GenericContainer("starrocks/allin1-ubuntu:latest").apply {
63+
withExposedPorts(9030)
64+
withStartupTimeout(Duration.ofMinutes(3))
65+
start()
66+
}
67+
}
68+
6069
private val msSqlServer by lazy {
6170
MSSQLServerContainer("mcr.microsoft.com/mssql/server:2017-CU12")
6271
.acceptLicense()
@@ -86,6 +95,29 @@ abstract class AbstractDbTests {
8695
"MSSQLSERVER" to { getConnection(msSqlServer) },
8796
"ORACLE" to { getConnection(oracle) },
8897
"MARIADB" to { getConnection(mariadb) },
98+
"STARROCKS" to {
99+
Class.forName("com.mysql.cj.jdbc.Driver")
100+
val url = "jdbc:mysql://${starrocks.host}:${starrocks.getMappedPort(9030)}/"
101+
val bootstrapConn = DriverManager.getConnection(url, "root", "")
102+
// Wait for BE to register with the cluster
103+
for (i in 1..60) {
104+
try {
105+
val alive = bootstrapConn.createStatement().use { stmt ->
106+
stmt.executeQuery("SHOW BACKENDS").use { rs ->
107+
rs.next() && rs.getBoolean("Alive")
108+
}
109+
}
110+
if (alive) break
111+
} catch (_: Exception) {
112+
}
113+
Thread.sleep(2000)
114+
}
115+
bootstrapConn.createStatement().use {
116+
it.execute("CREATE DATABASE IF NOT EXISTS test")
117+
}
118+
bootstrapConn.close()
119+
DriverManager.getConnection("${url}test", "root", "")
120+
},
89121
)
90122

91123
val dbs =
@@ -125,7 +157,7 @@ abstract class AbstractDbTests {
125157
@BeforeAll
126158
fun setup() {
127159
dbs.forEach { container ->
128-
setupDatabase(connections.computeIfAbsent(container.key) { container.value() })
160+
setupDatabase(connections.computeIfAbsent(container.key) { container.value() }, container.key)
129161
}
130162
}
131163

@@ -137,18 +169,37 @@ abstract class AbstractDbTests {
137169
connections.clear()
138170
}
139171

140-
protected open fun setupDatabase(connection: Connection) {
172+
protected open fun setupDatabase(
173+
connection: Connection,
174+
dbKey: String = "",
175+
) {
141176
val dbFlavour = connection.getDbFlavour()
177+
val isStarRocks = dbKey == "STARROCKS"
142178
connection.createStatement().use { statement ->
179+
val createTable =
180+
if (isStarRocks) {
181+
"""
182+
CREATE TABLE super_heroes_$testId (
183+
id ${convertDbColumnType("UUID", dbFlavour)},
184+
name VARCHAR(100),
185+
email VARCHAR(100),
186+
age ${convertDbColumnType("INT", dbFlavour)}
187+
)
188+
PRIMARY KEY (id)
189+
DISTRIBUTED BY HASH(id) BUCKETS 1
190+
""".trimIndent()
191+
} else {
192+
"""
193+
CREATE TABLE super_heroes_$testId (
194+
id ${convertDbColumnType("UUID", dbFlavour)} PRIMARY KEY,
195+
name VARCHAR(100),
196+
email VARCHAR(100),
197+
age ${convertDbColumnType("INT", dbFlavour)}
198+
)
199+
""".trimIndent()
200+
}
143201
statement.execute(
144-
"""
145-
CREATE TABLE super_heroes_$testId (
146-
id ${convertDbColumnType("UUID", dbFlavour)} PRIMARY KEY,
147-
name VARCHAR(100),
148-
email VARCHAR(100),
149-
age ${convertDbColumnType("INT", dbFlavour)}
150-
)
151-
""".trimIndent().also {
202+
createTable.also {
152203
println("------------ $dbFlavour --------------")
153204
println(it)
154205
},

core/src/integrationTest/kotlin/net/samyn/kapper/ExecuteDtoTests.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import io.kotest.assertions.throwables.shouldThrow
55
import io.kotest.matchers.collections.shouldBeEmpty
66
import io.kotest.matchers.shouldBe
77
import net.samyn.kapper.internal.getDbFlavour
8+
import org.junit.jupiter.api.Assumptions.assumeFalse
89
import org.junit.jupiter.api.Test
910
import java.sql.SQLException
1011
import java.util.UUID
@@ -148,6 +149,10 @@ class ExecuteDtoTests : AbstractDbTests() {
148149

149150
@Test
150151
fun `with TX and DTO rolls back`() {
152+
assumeFalse(
153+
System.getProperty("db", "").trim().uppercase() == "STARROCKS",
154+
"StarRocks PRIMARY KEY tables use upsert semantics",
155+
)
151156
val id = UUID.randomUUID()
152157
shouldThrow<SQLException> {
153158
connection.withTransaction {

core/src/integrationTest/kotlin/net/samyn/kapper/ExecuteTests.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import io.kotest.assertions.throwables.shouldThrow
55
import io.kotest.matchers.collections.shouldBeEmpty
66
import io.kotest.matchers.shouldBe
77
import net.samyn.kapper.internal.getDbFlavour
8+
import org.junit.jupiter.api.Assumptions.assumeFalse
89
import org.junit.jupiter.api.Test
910
import java.sql.SQLException
1011
import java.util.UUID
@@ -179,6 +180,10 @@ class ExecuteTests : AbstractDbTests() {
179180

180181
@Test
181182
fun `with TX rolls back`() {
183+
assumeFalse(
184+
System.getProperty("db", "").trim().uppercase() == "STARROCKS",
185+
"StarRocks PRIMARY KEY tables use upsert semantics",
186+
)
182187
val id = UUID.randomUUID()
183188
shouldThrow<SQLException> {
184189
connection.withTransaction {

core/src/integrationTest/kotlin/net/samyn/kapper/TypesTest.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package net.samyn.kapper
22

33
import io.kotest.matchers.shouldBe
44
import net.samyn.kapper.internal.getDbFlavour
5+
import org.junit.jupiter.api.Assumptions.assumeFalse
56
import org.junit.jupiter.api.Test
67
import java.math.BigDecimal
78
import java.sql.Connection
@@ -15,7 +16,11 @@ import java.util.UUID
1516
import kotlin.random.Random
1617

1718
class TypesTest : AbstractDbTests() {
18-
override fun setupDatabase(connection: Connection) {
19+
override fun setupDatabase(
20+
connection: Connection,
21+
dbKey: String,
22+
) {
23+
if (dbKey == "STARROCKS") return
1924
val dbFlavour = connection.getDbFlavour()
2025
connection.createStatement().use { statement ->
2126
statement.execute(
@@ -51,6 +56,10 @@ class TypesTest : AbstractDbTests() {
5156

5257
@Test
5358
fun `can insert and retreive the same types`() {
59+
assumeFalse(
60+
System.getProperty("db", "").trim().uppercase() == "STARROCKS",
61+
"StarRocks does not support all SQL types tested here",
62+
)
5463
val testData = createTestObject()
5564
val result =
5665
connection.execute(

core/src/main/kotlin/net/samyn/kapper/internal/DbFlavourFunc.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ fun Connection.getDbFlavour(): DbFlavour {
1111
productName.contains("postgres", ignoreCase = true) ||
1212
productName.contains("enterprisedb", ignoreCase = true) -> DbFlavour.POSTGRESQL
1313
productName.contains("mysql", ignoreCase = true) ||
14-
productName.contains("mariadb", ignoreCase = true) -> DbFlavour.MYSQL
14+
productName.contains("mariadb", ignoreCase = true) ||
15+
productName.contains("starrocks", ignoreCase = true) -> DbFlavour.MYSQL
1516
productName.contains("sqlite", ignoreCase = true) -> DbFlavour.SQLITE
1617
productName.contains("oracle", ignoreCase = true) -> DbFlavour.ORACLE
1718
productName.contains("sql server", ignoreCase = true) ||

core/src/test/kotlin/net/samyn/kapper/internal/DbFlavourTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class DbFlavourTest {
3434
"MySQL Community Server",
3535
"MySQL Enterprise Server",
3636
"MariaDB",
37+
"StarRocks",
3738
],
3839
)
3940
fun `when databaseProductName is mysql then getDbFlavour returns MYSQL`(value: String) {

0 commit comments

Comments
 (0)