Skip to content

Commit 51c3d54

Browse files
committed
feat(ksp): Table annotation support specify supper class
1 parent f59e406 commit 51c3d54

File tree

7 files changed

+61
-16
lines changed

7 files changed

+61
-16
lines changed

ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package org.ktorm.ksp.annotation
1818

19+
import org.ktorm.schema.BaseTable
20+
import kotlin.reflect.KClass
21+
1922
/**
2023
* Specify the table for an entity class.
2124
*/
@@ -81,4 +84,12 @@ public annotation class Table(
8184
* Specify properties that should be ignored for generating column definitions.
8285
*/
8386
val ignoreProperties: Array<String> = [],
87+
88+
/**
89+
* The super class of the generated table class.
90+
*
91+
* If not specified, the super class will be determined based on the class kind of the entity:
92+
* `org.ktorm.schema.BaseTable` for interfaces, and `org.ktorm.schema.Table` for classes.
93+
*/
94+
val superClass: KClass<out BaseTable<out Any>> = Nothing::class
8495
)

ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ import org.ktorm.ksp.compiler.util._type
2828
import org.ktorm.ksp.compiler.util.getKotlinType
2929
import org.ktorm.ksp.compiler.util.getRegisteringCodeBlock
3030
import org.ktorm.ksp.spi.TableMetadata
31-
import org.ktorm.schema.BaseTable
3231
import org.ktorm.schema.Column
33-
import org.ktorm.schema.Table
3432

3533
@OptIn(KotlinPoetKspPreview::class)
3634
internal object TableClassGenerator {
@@ -49,11 +47,7 @@ internal object TableClassGenerator {
4947
}
5048

5149
private fun TypeSpec.Builder.configureSuperClass(table: TableMetadata): TypeSpec.Builder {
52-
if (table.entityClass.classKind == ClassKind.INTERFACE) {
53-
superclass(Table::class.asClassName().parameterizedBy(table.entityClass.toClassName()))
54-
} else {
55-
superclass(BaseTable::class.asClassName().parameterizedBy(table.entityClass.toClassName()))
56-
}
50+
superclass(table.superClass.asClassName().parameterizedBy(table.entityClass.toClassName()))
5751

5852
addSuperclassConstructorParameter("%S", table.name)
5953
addSuperclassConstructorParameter("alias")

ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import org.ktorm.ksp.spi.CodingNamingStrategy
2828
import org.ktorm.ksp.spi.ColumnMetadata
2929
import org.ktorm.ksp.spi.DatabaseNamingStrategy
3030
import org.ktorm.ksp.spi.TableMetadata
31+
import org.ktorm.schema.BaseTable
3132
import org.ktorm.schema.TypeReference
3233
import java.lang.reflect.InvocationTargetException
3334
import java.util.*
@@ -93,6 +94,9 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn
9394

9495
_logger.info("[ktorm-ksp-compiler] parse table metadata from entity: $className")
9596
val table = cls.getAnnotationsByType(Table::class).first()
97+
val superClass = table.superClass.takeIf { it != Nothing::class }
98+
?: if (cls.classKind == INTERFACE) org.ktorm.schema.Table::class else BaseTable::class
99+
96100
val tableMetadata = TableMetadata(
97101
entityClass = cls,
98102
name = table.name.ifEmpty { _databaseNamingStrategy.getTableName(cls) },
@@ -102,7 +106,8 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn
102106
tableClassName = table.className.ifEmpty { _codingNamingStrategy.getTableClassName(cls) },
103107
entitySequenceName = table.entitySequenceName.ifEmpty { _codingNamingStrategy.getEntitySequenceName(cls) },
104108
ignoreProperties = table.ignoreProperties.toSet(),
105-
columns = ArrayList()
109+
columns = ArrayList(),
110+
superClass = superClass
106111
)
107112

108113
val columns = tableMetadata.columns as MutableList

ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/BaseKspTest.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,14 @@ abstract class BaseKspTest {
4040
}
4141

4242
protected fun kspFailing(message: String, @Language("kotlin") code: String, vararg options: Pair<String, String>) {
43-
val result = compile(code, mapOf(*options))
43+
val result = compile(code, emptyList(), mapOf(*options))
4444
assert(result.exitCode == KotlinCompilation.ExitCode.COMPILATION_ERROR)
4545
assert(result.messages.contains("e: Error occurred in KSP, check log for detail"))
4646
assert(result.messages.contains(message))
4747
}
4848

49-
protected fun runKotlin(@Language("kotlin") code: String, vararg options: Pair<String, String>) {
50-
val result = compile(code, mapOf(*options))
49+
protected fun runKotlin(@Language("kotlin") code: String, additionalImports: List<String> = emptyList(), vararg options: Pair<String, String>) {
50+
val result = compile(code, additionalImports, mapOf(*options))
5151
assert(result.exitCode == KotlinCompilation.ExitCode.OK)
5252

5353
try {
@@ -59,7 +59,7 @@ abstract class BaseKspTest {
5959
}
6060
}
6161

62-
private fun compile(@Language("kotlin") code: String, options: Map<String, String>): KotlinCompilation.Result {
62+
private fun compile(@Language("kotlin") code: String, additionalImports: List<String>, options: Map<String, String>): KotlinCompilation.Result {
6363
@Language("kotlin")
6464
val header = """
6565
import java.math.*
@@ -72,6 +72,8 @@ abstract class BaseKspTest {
7272
import org.ktorm.dsl.*
7373
import org.ktorm.entity.*
7474
import org.ktorm.ksp.annotation.*
75+
76+
${additionalImports.joinToString("\n") { "import $it" }}
7577
7678
lateinit var database: Database
7779

ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/TableClassGeneratorTest.kt

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package org.ktorm.ksp.compiler.generator
22

33
import org.junit.Test
4+
import org.ktorm.entity.Entity
45
import org.ktorm.ksp.compiler.BaseKspTest
6+
import kotlin.reflect.KClass
57

68
class TableClassGeneratorTest : BaseKspTest() {
79

@@ -101,7 +103,7 @@ class TableClassGeneratorTest : BaseKspTest() {
101103
assert(user.username == "jack")
102104
assert(user.phone == "12345")
103105
}
104-
""".trimIndent(), "ktorm.allowReflection" to "true")
106+
""".trimIndent(), emptyList(), "ktorm.allowReflection" to "true")
105107

106108
@Test
107109
fun `ignore properties`() = runKotlin("""
@@ -199,4 +201,29 @@ class TableClassGeneratorTest : BaseKspTest() {
199201
assert(Users.columns.map { it.name }.toSet() == setOf("id", "class", "operator"))
200202
}
201203
""".trimIndent())
204+
205+
@Test
206+
fun `super class`() = runKotlin("""
207+
@Table(superClass = CstmTable::class)
208+
interface User: Entity<User> {
209+
@PrimaryKey
210+
var id: Int
211+
var `class`: String
212+
var operator: String
213+
}
214+
215+
fun run() {
216+
assert(CstmTable::class.isSubclassOf(CstmTable::class))
217+
}
218+
""".trimIndent(), listOf("org.ktorm.ksp.compiler.generator.CstmTable", "kotlin.reflect.full.*"))
202219
}
220+
221+
abstract class CstmTable<E: Entity<E>>(
222+
tableName: String,
223+
alias: String? = null,
224+
catalog: String? = null,
225+
schema: String? = null,
226+
entityClass: KClass<E>? = null
227+
) : org.ktorm.schema.Table<E>(
228+
tableName, alias, catalog, schema, entityClass
229+
)

ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/DatabaseNamingStrategyTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class DatabaseNamingStrategyTest : BaseKspTest() {
101101
assert(UserProfiles.tableName == "USER_PROFILE")
102102
assert(UserProfiles.columns.map { it.name }.toSet() == setOf("ID", "PUBLIC_EMAIL", "PROFILE_PICTURE", "COMPANY_ID"))
103103
}
104-
""".trimIndent(), "ktorm.dbNamingStrategy" to "upper-snake-case")
104+
""".trimIndent(), emptyList(), "ktorm.dbNamingStrategy" to "upper-snake-case")
105105

106106
@Test
107107
fun testUpperCamelCaseNamingByClassName() = runKotlin("""
@@ -128,5 +128,5 @@ class DatabaseNamingStrategyTest : BaseKspTest() {
128128
assert(UserProfiles.tableName == "USER_PROFILE")
129129
assert(UserProfiles.columns.map { it.name }.toSet() == setOf("ID", "PUBLIC_EMAIL", "PROFILE_PICTURE", "COMPANY_ID"))
130130
}
131-
""".trimIndent(), "ktorm.dbNamingStrategy" to "org.ktorm.ksp.compiler.util.UpperSnakeCaseDatabaseNamingStrategy")
131+
""".trimIndent(), emptyList(), "ktorm.dbNamingStrategy" to "org.ktorm.ksp.compiler.util.UpperSnakeCaseDatabaseNamingStrategy")
132132
}

ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/TableMetadata.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.ktorm.ksp.spi
1818

1919
import com.google.devtools.ksp.symbol.KSClassDeclaration
20+
import kotlin.reflect.KClass
2021

2122
/**
2223
* Table definition metadata.
@@ -66,5 +67,10 @@ public data class TableMetadata(
6667
/**
6768
* Columns in the table.
6869
*/
69-
val columns: List<ColumnMetadata>
70+
val columns: List<ColumnMetadata>,
71+
72+
/**
73+
* The super class of the table class in the generated code.
74+
*/
75+
val superClass: KClass<*>
7076
)

0 commit comments

Comments
 (0)