@@ -29,6 +29,10 @@ import org.ktorm.ksp.spi.ColumnMetadata
29
29
import org.ktorm.ksp.spi.DatabaseNamingStrategy
30
30
import org.ktorm.ksp.spi.TableMetadata
31
31
import org.ktorm.schema.TypeReference
32
+ import com.squareup.kotlinpoet.ClassName
33
+ import com.squareup.kotlinpoet.asClassName
34
+ import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview
35
+ import com.squareup.kotlinpoet.ksp.toClassName
32
36
import java.lang.reflect.InvocationTargetException
33
37
import java.util.*
34
38
import kotlin.reflect.jvm.jvmName
@@ -93,6 +97,9 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn
93
97
94
98
_logger .info(" [ktorm-ksp-compiler] parse table metadata from entity: $className " )
95
99
val table = cls.getAnnotationsByType(Table ::class ).first()
100
+ val (superClass, superTableClasses) = parseSuperTableClass(cls)
101
+ val allPropertyNamesOfSuperTables = superTableClasses.flatMap { it.getProperties(emptySet()) }.map { it.simpleName.asString() }
102
+
96
103
val tableMetadata = TableMetadata (
97
104
entityClass = cls,
98
105
name = table.name.ifEmpty { _databaseNamingStrategy .getTableName(cls) },
@@ -101,8 +108,9 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn
101
108
schema = table.schema.ifEmpty { _options [" ktorm.schema" ] }?.takeIf { it.isNotEmpty() },
102
109
tableClassName = table.className.ifEmpty { _codingNamingStrategy .getTableClassName(cls) },
103
110
entitySequenceName = table.entitySequenceName.ifEmpty { _codingNamingStrategy .getEntitySequenceName(cls) },
104
- ignoreProperties = table.ignoreProperties.toSet(),
105
- columns = ArrayList ()
111
+ ignoreProperties = table.ignoreProperties.toSet() + allPropertyNamesOfSuperTables, // ignore properties of super tables
112
+ columns = ArrayList (),
113
+ superClass = superClass
106
114
)
107
115
108
116
val columns = tableMetadata.columns as MutableList
@@ -274,6 +282,51 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn
274
282
)
275
283
}
276
284
285
+ /* *
286
+ * @return the super table class and all class be annotated with [SuperTableClass] in the inheritance hierarchy.
287
+ */
288
+ @OptIn(KotlinPoetKspPreview ::class )
289
+ private fun parseSuperTableClass (cls : KSClassDeclaration ): Pair <ClassName , Set <KSClassDeclaration >> {
290
+ val superTableClassAnnPair = cls.findAllAnnotationsInInheritanceHierarchy(SuperTableClass ::class .qualifiedName!! )
291
+
292
+ // if there is no SuperTableClass annotation, return the default super table class based on the class kind.
293
+ if (superTableClassAnnPair.isEmpty()) {
294
+ return if (cls.classKind == INTERFACE ) {
295
+ org.ktorm.schema.Table ::class .asClassName() to emptySet()
296
+ } else {
297
+ org.ktorm.schema.BaseTable ::class .asClassName() to emptySet()
298
+ }
299
+ }
300
+
301
+ // SuperTableClass annotation can only be used on interface
302
+ if (superTableClassAnnPair.map { it.first }.any { it.classKind != INTERFACE }) {
303
+ val msg = " SuperTableClass annotation can only be used on interface."
304
+ throw IllegalArgumentException (msg)
305
+ }
306
+
307
+ // find the last annotation in the inheritance hierarchy
308
+ val superTableClasses = superTableClassAnnPair
309
+ .map { it.second }
310
+ .map { it.arguments.single { it.name?.asString() == SuperTableClass ::value.name } }
311
+ .map { it.value as KSType }
312
+ .map { it.declaration as KSClassDeclaration }
313
+
314
+ var lowestSubClass = superTableClasses.first()
315
+ for (i in 1 until superTableClasses.size) {
316
+ val cur = superTableClasses[i]
317
+ if (cur.isSubclassOf(lowestSubClass)) {
318
+ lowestSubClass = cur
319
+ } else if (! lowestSubClass.isSubclassOf(cur)) {
320
+ val msg =
321
+ " There are multiple SuperTableClass annotations in the inheritance hierarchy of class ${cls.qualifiedName?.asString()} ," +
322
+ " but the values of annotation are not in the same inheritance hierarchy."
323
+ throw IllegalArgumentException (msg)
324
+ }
325
+ }
326
+ // TODO: to check All constructor parameters owned by `BaseTable` should also be owned by lowestSubClass.
327
+ return lowestSubClass.toClassName() to superTableClasses.toSet()
328
+ }
329
+
277
330
private fun TableMetadata.checkCircularRef (ref : KSClassDeclaration , stack : LinkedList <String > = LinkedList ()) {
278
331
val className = this .entityClass.qualifiedName?.asString()
279
332
val refClassName = ref.qualifiedName?.asString()
0 commit comments