Skip to content

Commit 1a1a9a0

Browse files
committed
refactor pgen-spec format
1 parent e6f1e7c commit 1a1a9a0

57 files changed

Lines changed: 3129 additions & 3282 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

plugin/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ repositories {
1919

2020
dependencies {
2121
implementation(libs.poet)
22-
implementation(libs.kaml)
2322
implementation(libs.goquati.base)
2423
implementation(libs.goquati.poet)
2524
implementation(libs.kotlinx.serialization.json)
2625
implementation(libs.bundles.flyway)
26+
implementation(libs.bundles.jackson)
2727
compileOnly(kotlin("gradle-plugin"))
2828
}
2929

plugin/gradle/libs.versions.toml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ kotlin = "2.2.0"
33
kotlinx-serialization = "1.9.0"
44
flyway = "11.6.0"
55
goquati = "2.1.0"
6+
jackson = "3.0.4"
67

78
[libraries]
89

@@ -16,16 +17,20 @@ goquati-poet = { module = "de.quati:kotlin-util-poet", version.ref = "goquati" }
1617
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-jvm", version.ref = "kotlinx-serialization" }
1718

1819
poet = { module = "com.squareup:kotlinpoet", version.ref = "kotlin" }
19-
kaml = { module = "com.charleskorn.kaml:kaml", version = "0.66.0" }
20-
2120

21+
jackson-kotlin = { module = "tools.jackson.module:jackson-module-kotlin", version.ref = "jackson" }
22+
jackson-yaml = { module = "tools.jackson.dataformat:jackson-dataformat-yaml", version.ref = "jackson" }
2223

2324
[bundles]
2425
flyway = [
2526
"jdbc-postgresql",
2627
"flyway-core",
2728
"flyway-postgresql",
2829
]
30+
jackson = [
31+
"jackson-kotlin",
32+
"jackson-yaml",
33+
]
2934

3035
[plugins]
3136
kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }

plugin/src/main/kotlin/de/quati/pgen/plugin/ConfigBuilder.kt

Lines changed: 70 additions & 128 deletions
Large diffs are not rendered by default.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package de.quati.pgen.plugin
2+
3+
@RequiresOptIn(
4+
level = RequiresOptIn.Level.ERROR,
5+
message = "This API is experimental and may change in the future."
6+
)
7+
@Retention(AnnotationRetention.BINARY)
8+
@Target(
9+
AnnotationTarget.CLASS,
10+
AnnotationTarget.FUNCTION,
11+
AnnotationTarget.PROPERTY,
12+
AnnotationTarget.CONSTRUCTOR
13+
)
14+
public annotation class ExperimentalPgenApi

plugin/src/main/kotlin/de/quati/pgen/plugin/intern/util/codegen/CodeGenContext.kt renamed to plugin/src/main/kotlin/de/quati/pgen/plugin/intern/codegen/CodeGenContext.kt

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,51 @@
1-
package de.quati.pgen.plugin.intern.util.codegen
1+
package de.quati.pgen.plugin.intern.codegen
22

33
import com.squareup.kotlinpoet.ClassName
44
import com.squareup.kotlinpoet.CodeBlock
55
import de.quati.kotlin.util.poet.PackageName
66
import de.quati.pgen.plugin.intern.model.config.Config
7-
import de.quati.pgen.plugin.intern.model.sql.Column
8-
import de.quati.pgen.plugin.intern.model.sql.KotlinValueClass
9-
import de.quati.pgen.plugin.intern.model.sql.SqlColumnName
10-
import de.quati.pgen.plugin.intern.model.sql.Table
7+
import de.quati.pgen.plugin.intern.model.spec.PgenSpec
8+
import de.quati.pgen.plugin.intern.model.spec.Column
9+
import de.quati.pgen.plugin.intern.model.spec.DbName
10+
import de.quati.pgen.plugin.intern.model.spec.KotlinValueClass
11+
import de.quati.pgen.plugin.intern.model.spec.SqlColumnName
12+
import de.quati.pgen.plugin.intern.model.spec.Table
1113

1214
internal class CodeGenContext(
13-
config: Config,
14-
specContext: SpecContext,
15-
typeGroups: List<Set<SqlColumnName>>,
16-
) : SpecContext by specContext {
17-
val rootPackageName = config.packageName
18-
val connectionType = config.connectionType
19-
val typeMappings = config.dbConfigs.flatMap(Config.Db::typeMappings)
20-
.associate { it.sqlType to it.valueClass }
21-
val enumMappings = config.dbConfigs.flatMap(Config.Db::enumMappings)
22-
.associate { it.sqlType to it.enumClass }
23-
val typeOverwrites = config.dbConfigs.flatMap(Config.Db::typeOverwrites)
24-
.associate { it.sqlColumn to it.valueClass }
25-
val localConfigContext = config.oas?.localConfigContext?.let { c ->
15+
globalConfig: Config.Global,
16+
val dbConfig: Config.Db,
17+
val dbSpec: PgenSpec.Database,
18+
val oas: Config.Oas?,
19+
) {
20+
val typeGroups = dbSpec.tables.getColumnTypeGroups()
21+
val rootPackageName = globalConfig.packageName
22+
val connectionType = globalConfig.connectionType
23+
val typeMappings = dbConfig.typeMappings.associate { it.sqlType to it.valueClass }
24+
val enumMappings = dbConfig.enumMappings.associate { it.sqlType to it.enumClass }
25+
val typeOverwrites = dbConfig.typeOverwrites.associate { it.sqlColumn to it.valueClass }
26+
val referencesMapping = run {
27+
val customTypeMappings = dbConfig.columnTypeMappings.associateBy { it.name }
28+
val refMappings = dbSpec.allTypes.mapNotNull { type ->
29+
type.toSqlObjectNameOrNull()?.let { it to type }
30+
}.toMap()
31+
refMappings + customTypeMappings
32+
}
33+
34+
fun resolve(type: Column.Type): Column.Type.Actual = when (type) {
35+
is Column.Type.Reference -> getRefTypeOrThrow(type)
36+
is Column.Type.Actual -> type
37+
}
38+
39+
private fun getRefTypeOrThrow(ref: Column.Type.Reference): Column.Type.Actual {
40+
return referencesMapping[ref.name]?.takeIf { it != ref }?.let { type ->
41+
when (type) {
42+
is Column.Type.Reference -> getRefTypeOrThrow(type)
43+
is Column.Type.Actual -> type
44+
}
45+
} ?: error("Reference not found: $ref")
46+
}
47+
48+
val localConfigContext = oas?.localConfigContext?.let { c ->
2649
c.copy(
2750
type = ClassName(
2851
c.type.packageName.takeIf { it != "default" } ?: "$rootPackageName.shared",
@@ -42,14 +65,14 @@ internal class CodeGenContext(
4265
}
4366

4467
fun Table.update(): Table {
45-
val newColumns = columns.map { column ->
46-
val columnName = SqlColumnName(tableName = name, name = column.name.value)
47-
if (column.type is Column.Type.NonPrimitive.Overwrite) return@map column
68+
val newColumns = this@update.columns.map { column ->
69+
val columnName = SqlColumnName(tableName = this@update.name, name = column.name.value)
70+
if (column.type is Column.Type.Overwrite) return@map column
4871
val kotlinClass = allTypeOverwrites[columnName] ?: return@map column
49-
val newType = Column.Type.NonPrimitive.Overwrite(
72+
val newType = Column.Type.Overwrite(
5073
valueClass = kotlinClass,
51-
originalType = when (val t = column.type) {
52-
is Column.Type.NonPrimitive.Domain -> t.originalType
74+
base = when (val t = column.type) {
75+
is Column.Type.NonPrimitive.Domain -> t.base
5376
else -> t
5477
},
5578
)
@@ -59,17 +82,19 @@ internal class CodeGenContext(
5982
}
6083

6184
val poet = Poet(
85+
dbName = dbSpec.name,
6286
rootPackageName = rootPackageName,
63-
uuidType = config.uuidType,
87+
uuidType = globalConfig.uuidType,
6488
)
6589

6690
data class Poet(
91+
private val dbName: DbName,
6792
val rootPackageName: PackageName,
6893
private val uuidType: Config.UuidType,
6994
) {
70-
val packageDb = PackageName("$rootPackageName.db")
71-
val packageMapper = PackageName("$rootPackageName.mapper")
72-
val packageService = PackageName("$rootPackageName.service")
95+
val packageDb = rootPackageName.plus("db.${dbName.prettyName}")
96+
val packageMapper = rootPackageName.plus("mapper")
97+
val packageService = rootPackageName.plus("service")
7398

7499
val uuidColumnType = when (uuidType) {
75100
Config.UuidType.KOTLIN -> ClassName("org.jetbrains.exposed.v1.core", "UuidColumnType")
@@ -88,7 +113,6 @@ internal class CodeGenContext(
88113
}
89114

90115
companion object {
91-
92116
fun Collection<Table>.getColumnTypeGroups(): List<Set<SqlColumnName>> {
93117
return flatMap { table ->
94118
table.foreignKeys.flatMap { keySet ->

plugin/src/main/kotlin/de/quati/pgen/plugin/intern/util/codegen/Column.kt renamed to plugin/src/main/kotlin/de/quati/pgen/plugin/intern/codegen/Column.kt

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
1-
package de.quati.pgen.plugin.intern.util.codegen
1+
package de.quati.pgen.plugin.intern.codegen
22

33
import com.squareup.kotlinpoet.CodeBlock
44
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
55
import com.squareup.kotlinpoet.asTypeName
66
import com.squareup.kotlinpoet.buildCodeBlock
77
import de.quati.pgen.plugin.intern.model.config.Config
8-
import de.quati.pgen.plugin.intern.model.sql.Column
9-
import de.quati.pgen.plugin.intern.util.codegen.oas.DbContext
8+
import de.quati.pgen.plugin.intern.model.spec.Column
109

1110

1211
context(c: CodeGenContext)
1312
internal fun Column.getDefaultExpression(): CodeBlock? = when (type) {
14-
Column.Type.Primitive.TIMESTAMP -> when (default) {
13+
Column.Type.Primitive.TIMESTAMP -> when (defaultExpr) {
1514
"now()" -> CodeBlock.of(".defaultExpression(%T)", Poet.Exposed.defaultExpTimestamp)
1615
else -> null
1716
}
1817

19-
Column.Type.Primitive.TIMESTAMP_WITH_TIMEZONE -> when (default) {
18+
Column.Type.Primitive.TIMESTAMP_WITH_TIMEZONE -> when (defaultExpr) {
2019
"now()" -> CodeBlock.of(".defaultExpression(%T)", Poet.Exposed.defaultExpTimestampZ)
2120
else -> null
2221
}
2322

24-
Column.Type.Primitive.UUID -> when (default) {
23+
Column.Type.Primitive.UUID -> when (defaultExpr) {
2524
"gen_random_uuid()" -> CodeBlock.of(
2625
".defaultExpression(%T(%S, %T()))",
2726
Poet.Exposed.customFunction, "gen_random_uuid", c.poet.uuidColumnType,
@@ -30,7 +29,7 @@ internal fun Column.getDefaultExpression(): CodeBlock? = when (type) {
3029
else -> null
3130
}
3231

33-
Column.Type.Primitive.BOOL -> when (default) {
32+
Column.Type.Primitive.BOOL -> when (defaultExpr) {
3433
"false" -> CodeBlock.of(".default(false)")
3534
"true" -> CodeBlock.of(".default(true)")
3635
else -> null
@@ -39,7 +38,7 @@ internal fun Column.getDefaultExpression(): CodeBlock? = when (type) {
3938
Column.Type.Primitive.INT4, Column.Type.Primitive.INT8 -> {
4039
val prefix = "nextval('"
4140
val suffix = "'::regclass)"
42-
default
41+
defaultExpr
4342
?.takeIf { it.startsWith(prefix) && it.endsWith(suffix) }
4443
?.removePrefix(prefix)?.removeSuffix(suffix)
4544
?.let { seqName ->
@@ -50,18 +49,18 @@ internal fun Column.getDefaultExpression(): CodeBlock? = when (type) {
5049
else -> null
5150
}
5251

53-
context(c: CodeGenContext, _: DbContext)
52+
context(c: CodeGenContext)
5453
internal fun initializerBlock(column: Column): CodeBlock {
5554
val columnName = column.name.value
5655
return when (val type = c.resolve(column.type)) {
5756
is Column.Type.NonPrimitive.Array -> {
5857
fun default() = CodeBlock.of("array<%T>(name = %S)", type.getTypeName(), columnName)
5958

60-
when (val elementType = c.resolve(type.elementType)) {
59+
when (val elementType = c.resolve(type.element)) {
6160
is Column.Type.NonPrimitive.Enum -> buildCodeBlock {
6261
add("%T<%T>(\n", Poet.Pgen.pgenEnumArray, type.getTypeName())
6362
add(" name = %S,\n", columnName)
64-
add(" sql = %S,\n", "${elementType.name.schema.schemaName}.${elementType.name.name}")
63+
add(" sql = %S,\n", "${elementType.ref}")
6564
add(")")
6665
}
6766

@@ -79,17 +78,17 @@ internal fun initializerBlock(column: Column): CodeBlock {
7978
type.getTypeName(), columnName, elementType.getColumnTypeTypeName()
8079
)
8180

82-
is Column.Type.NonPrimitive.DomainType -> when (c.connectionType) {
81+
is Column.Type.DomainType -> when (c.connectionType) {
8382
Config.ConnectionType.JDBC -> buildCodeBlock {
8483
add("array(\n")
8584
add(" name = %S,\n", columnName)
8685
add(" columnType = %T.create(\n", Poet.Pgen.domainColumnType)
8786
add(" sqlType = %S,\n", elementType.sqlType)
88-
add(" originType = "); add(elementType.originalType.getExposedColumnType()); add(",\n")
87+
add(" originType = "); add(elementType.base.getExposedColumnType()); add(",\n")
8988
add(
9089
" builder = { %T${elementType.parserFunction}(it as %T) },\n",
9190
elementType.getDomainTypename(),
92-
elementType.originalType.getTypeName(),
91+
elementType.base.getTypeName(),
9392
)
9493
add(" ),\n", Poet.Pgen.domainTypeColumn)
9594
add(")")
@@ -99,11 +98,11 @@ internal fun initializerBlock(column: Column): CodeBlock {
9998
add("%T(\n", Poet.Pgen.pgenDomainArray)
10099
add(" name = %S,\n", columnName)
101100
add(" sqlType = %S,\n", elementType.sqlType)
102-
add(" originType = "); add(elementType.originalType.getExposedColumnType()); add(",\n")
101+
add(" originType = "); add(elementType.base.getExposedColumnType()); add(",\n")
103102
add(
104103
" builder = { %T${elementType.parserFunction}(it as %T) },\n",
105104
elementType.getDomainTypename(),
106-
elementType.originalType.getTypeName(),
105+
elementType.base.getTypeName(),
107106
)
108107
add(")")
109108
}
@@ -116,7 +115,7 @@ internal fun initializerBlock(column: Column): CodeBlock {
116115
is Column.Type.NonPrimitive.Enum -> buildCodeBlock {
117116
add("%T<%T>(\n", Poet.Pgen.pgenEnum, type.getTypeName())
118117
add(" name = %S,\n", columnName)
119-
add(" sql = %S,\n", "${type.name.schema.schemaName}.${type.name.name}")
118+
add(" sql = %S,\n", "${type.ref}")
120119
add(")")
121120
}
122121

@@ -125,15 +124,15 @@ internal fun initializerBlock(column: Column): CodeBlock {
125124
columnName, type.getColumnTypeTypeName(),
126125
)
127126

128-
is Column.Type.NonPrimitive.DomainType -> buildCodeBlock {
129-
add("%T<%T, %T>(\n", Poet.Pgen.domainType, type.getDomainTypename(), type.originalType.getTypeName())
127+
is Column.Type.DomainType -> buildCodeBlock {
128+
add("%T<%T, %T>(\n", Poet.Pgen.domainType, type.getDomainTypename(), type.base.getTypeName())
130129
add(" name = %S,\n", columnName)
131130
add(" sqlType = %S,\n", type.sqlType)
132-
add(" originType = "); add(type.originalType.getExposedColumnType()); add(",\n")
131+
add(" originType = "); add(type.base.getExposedColumnType()); add(",\n")
133132
add(
134133
" builder = { %T${type.parserFunction}(it as %T) }\n",
135134
type.getDomainTypename(),
136-
type.originalType.getTypeName(),
135+
type.base.getTypeName(),
137136
)
138137
add(")")
139138
}
@@ -208,10 +207,10 @@ internal fun initializerBlock(column: Column): CodeBlock {
208207
}
209208
}
210209

211-
context(_: CodeGenContext, _: DbContext)
210+
context(_: CodeGenContext)
212211
internal fun Column.getColumnTypeName() = when (type) {
213212
is Column.Type.NonPrimitive.Array -> List::class.asTypeName()
214213
.parameterizedBy(type.getTypeName())
215214

216215
else -> type.getTypeName()
217-
}.copy(nullable = isNullable)
216+
}.copy(nullable = nullable)

0 commit comments

Comments
 (0)