From a25e08baa0a47b506353482d3af1a0cd4bdd6c54 Mon Sep 17 00:00:00 2001 From: Sven Allers Date: Thu, 9 Feb 2023 18:50:52 +0100 Subject: [PATCH 001/105] PostgresSQL: array_position() for String and Enum (via casting) --- .../src/test/kotlin/org/ktorm/BaseTest.kt | 2 +- .../org/ktorm/support/postgresql/Functions.kt | 62 +++++++++++++++++++ .../support/postgresql/BasePostgreSqlTest.kt | 17 ++++- .../ktorm/support/postgresql/CommonTest.kt | 13 +--- .../ktorm/support/postgresql/FunctionsTest.kt | 60 ++++++++++++++++++ 5 files changed, 139 insertions(+), 15 deletions(-) create mode 100644 ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt create mode 100644 ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/FunctionsTest.kt diff --git a/ktorm-core/src/test/kotlin/org/ktorm/BaseTest.kt b/ktorm-core/src/test/kotlin/org/ktorm/BaseTest.kt index 745d31b39..fdda2bd8f 100644 --- a/ktorm-core/src/test/kotlin/org/ktorm/BaseTest.kt +++ b/ktorm-core/src/test/kotlin/org/ktorm/BaseTest.kt @@ -116,4 +116,4 @@ abstract class BaseTest { val Database.employees get() = this.sequenceOf(Employees) val Database.customers get() = this.sequenceOf(Customers) -} \ No newline at end of file +} diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt new file mode 100644 index 000000000..5c953b744 --- /dev/null +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.support.postgresql + +import org.ktorm.dsl.cast +import org.ktorm.expression.ArgumentExpression +import org.ktorm.expression.FunctionExpression +import org.ktorm.schema.ColumnDeclaring +import org.ktorm.schema.IntSqlType +import org.ktorm.schema.SqlType +import org.ktorm.schema.TextSqlType + +/** + * PostgreSQL array_position function for enums, translated to `array_position(value, cast(column as text))`. + * Uses the `name` attribute of the enums as actual value for the query. + */ +public fun > arrayPosition(value: Array, column: ColumnDeclaring): FunctionExpression = + arrayPosition(value.map { it?.name }.toTypedArray(), column.cast(TextSqlType)) + +/** + * PostgreSQL array_position function for enums, translated to `array_position(value, cast(column as text))`. + * Uses the `name` attribute of the enums as actual value for the query. + */ +public inline fun > arrayPosition( + value: Collection, + column: ColumnDeclaring +): FunctionExpression = + arrayPosition(value.map { it?.name }.toTypedArray(), column.cast(TextSqlType)) + +/** + * PostgreSQL array_position function, translated to `array_position(value, column)`. + */ +public fun arrayPosition(value: TextArray, column: ColumnDeclaring): FunctionExpression = + arrayPosition(value, column, TextArraySqlType) + +/** + * PostgreSQL array_position function, translated to `array_position(value, column)`. + */ +public fun arrayPosition( + value: Array, + column: ColumnDeclaring, + arraySqlType: SqlType> +): FunctionExpression = + FunctionExpression( + functionName = "array_position", + arguments = listOf(ArgumentExpression(value, arraySqlType), column.asExpression()), + sqlType = IntSqlType + ) diff --git a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/BasePostgreSqlTest.kt b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/BasePostgreSqlTest.kt index 675a55525..68d3178d8 100644 --- a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/BasePostgreSqlTest.kt +++ b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/BasePostgreSqlTest.kt @@ -2,6 +2,9 @@ package org.ktorm.support.postgresql import org.ktorm.BaseTest import org.ktorm.database.Database +import org.ktorm.schema.Table +import org.ktorm.schema.enum +import org.ktorm.schema.int import org.testcontainers.containers.PostgreSQLContainer import kotlin.concurrent.thread @@ -16,7 +19,7 @@ abstract class BasePostgreSqlTest : BaseTest() { execSqlScript("drop-postgresql-data.sql") } - companion object : PostgreSQLContainer("postgres:13-alpine") { + companion object : PostgreSQLContainer("postgres:14-alpine") { init { // Start the container when it's first used. start() @@ -24,4 +27,14 @@ abstract class BasePostgreSqlTest : BaseTest() { Runtime.getRuntime().addShutdownHook(thread(start = false) { stop() }) } } -} \ No newline at end of file + + enum class Mood { + HAPPY, + SAD + } + + object TableWithEnum : Table("t_enum") { + val id = int("id").primaryKey() + val current_mood = enum("current_mood") + } +} diff --git a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/CommonTest.kt b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/CommonTest.kt index 018c650c4..1edd2a6df 100644 --- a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/CommonTest.kt +++ b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/CommonTest.kt @@ -7,7 +7,6 @@ import org.ktorm.database.use import org.ktorm.dsl.* import org.ktorm.entity.* import org.ktorm.schema.Table -import org.ktorm.schema.enum import org.ktorm.schema.int import org.ktorm.schema.varchar import java.util.concurrent.ExecutionException @@ -151,16 +150,6 @@ class CommonTest : BasePostgreSqlTest() { } - enum class Mood { - HAPPY, - SAD - } - - object TableWithEnum : Table("t_enum") { - val id = int("id").primaryKey() - val current_mood = enum("current_mood") - } - @Test fun testEnum() { database.insert(TableWithEnum) { @@ -220,4 +209,4 @@ class CommonTest : BasePostgreSqlTest() { assertEquals("test~~", e1.v) assert(e1.k.isNotEmpty()) } -} \ No newline at end of file +} diff --git a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/FunctionsTest.kt b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/FunctionsTest.kt new file mode 100644 index 000000000..4f3619f79 --- /dev/null +++ b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/FunctionsTest.kt @@ -0,0 +1,60 @@ +package org.ktorm.support.postgresql + +import org.junit.Test +import org.ktorm.dsl.* +import kotlin.test.assertEquals + +class FunctionsTest : BasePostgreSqlTest() { + @Test + fun testArrayPositionEnumCollection() { + database.insert(TableWithEnum) { + set(it.current_mood, Mood.SAD) + } + database.insert(TableWithEnum) { + set(it.current_mood, Mood.HAPPY) + } + + val moodsSorted = database + .from(TableWithEnum) + .select() + .orderBy(arrayPosition(listOf(Mood.SAD, Mood.HAPPY), TableWithEnum.current_mood).asc()) + .map { row -> + row[TableWithEnum.current_mood] + } + + assertEquals(listOf(Mood.SAD, Mood.HAPPY, Mood.HAPPY), moodsSorted) + } + + @Test + fun testArrayPositionEnumArray() { + database.insert(TableWithEnum) { + set(it.current_mood, Mood.SAD) + } + database.insert(TableWithEnum) { + set(it.current_mood, Mood.HAPPY) + } + + val moodsSorted = database + .from(TableWithEnum) + .select() + .orderBy(arrayPosition(arrayOf(Mood.SAD, Mood.HAPPY), TableWithEnum.current_mood).asc()) + .map { row -> + row[TableWithEnum.current_mood] + } + + assertEquals(listOf(Mood.SAD, Mood.HAPPY, Mood.HAPPY), moodsSorted) + } + + @Test + fun testArrayPositionTextArray() { + val namesSorted = database + .from(Employees) + .select() + .orderBy(arrayPosition(arrayOf("tom", "vince", "marry"), Employees.name).asc()) + .map { row -> + row[Employees.name] + } + + assertEquals(listOf("tom", "vince", "marry", "penny"), namesSorted) + } +} From 59bfb57b1f0f97167a9d40d012d24cb2bc9cdba3 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 24 Jun 2023 19:52:41 +0800 Subject: [PATCH 002/105] prepare for next version --- ktorm.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ktorm.version b/ktorm.version index 40c341bdc..371dce871 100644 --- a/ktorm.version +++ b/ktorm.version @@ -1 +1 @@ -3.6.0 +3.7.0-SNAPSHOT From 947ec8b622da859d8d1cb043b7d25d901c7d75f9 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 24 Jun 2023 20:27:55 +0800 Subject: [PATCH 003/105] init ksp annotations module --- ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts | 9 +++++++++ settings.gradle.kts | 1 + 2 files changed, 10 insertions(+) create mode 100644 ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts diff --git a/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts b/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts new file mode 100644 index 000000000..877d7e1f8 --- /dev/null +++ b/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts @@ -0,0 +1,9 @@ + +plugins { + id("ktorm.module") +} + +dependencies { + compileOnly(project(":ktorm-core")) + compileOnly(project(":ktorm-jackson")) +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 5d3b92db4..f9993842f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,6 +6,7 @@ plugins { include("ktorm-core") include("ktorm-global") include("ktorm-jackson") +include("ktorm-ksp-annotations") include("ktorm-support-mysql") include("ktorm-support-oracle") include("ktorm-support-postgresql") From beec7509cf39ed1ca62d34bfcbf5949e8f207b15 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 24 Jun 2023 21:00:56 +0800 Subject: [PATCH 004/105] migrate ksp annotations module --- .../ktorm-ksp-annotations.gradle.kts | 1 + .../kotlin/org/ktorm/ksp/annotation/Column.kt | 60 ++++++ .../kotlin/org/ktorm/ksp/annotation/Ignore.kt | 24 +++ .../org/ktorm/ksp/annotation/PrimaryKey.kt | 24 +++ .../org/ktorm/ksp/annotation/References.kt | 55 ++++++ .../ktorm/ksp/annotation/SqlTypeFactories.kt | 51 +++++ .../ktorm/ksp/annotation/SqlTypeFactory.kt | 31 +++ .../kotlin/org/ktorm/ksp/annotation/Table.kt | 84 +++++++++ .../org/ktorm/ksp/annotation/Undefined.kt | 178 ++++++++++++++++++ .../org/ktorm/ksp/annotation/UndefinedTest.kt | 171 +++++++++++++++++ 10 files changed, 679 insertions(+) create mode 100644 ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt create mode 100644 ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Ignore.kt create mode 100644 ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/PrimaryKey.kt create mode 100644 ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt create mode 100644 ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactories.kt create mode 100644 ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactory.kt create mode 100644 ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt create mode 100644 ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt create mode 100644 ktorm-ksp-annotations/src/test/kotlin/org/ktorm/ksp/annotation/UndefinedTest.kt diff --git a/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts b/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts index 877d7e1f8..89966fea7 100644 --- a/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts +++ b/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts @@ -6,4 +6,5 @@ plugins { dependencies { compileOnly(project(":ktorm-core")) compileOnly(project(":ktorm-jackson")) + testImplementation(project(":ktorm-core")) } diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt new file mode 100644 index 000000000..cb719430b --- /dev/null +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2022-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.annotation + +import org.ktorm.schema.SqlType +import kotlin.reflect.KClass + +/** + * Specify the mapped column for an entity property. If no `@Column` annotation is specified, the default values apply. + */ +@Target(AnnotationTarget.PROPERTY) +@Retention(AnnotationRetention.SOURCE) +public annotation class Column( + + /** + * The name of the column. + * + * If not specified, the name will be generated by a naming strategy. This naming strategy can be configured + * by KSP option `ktorm.dbNamingStrategy`, which accepts the following values: + * + * - lower-snake-case (default): generate lower snake-case names, for example: userId --> user_id. + * + * - upper-snake-case: generate upper snake-case names, for example: userId --> USER_ID. + * + * - Class name of a custom naming strategy, which should be an implementation of + * `org.ktorm.ksp.spi.DatabaseNamingStrategy`. + */ + val name: String = "", + + /** + * The SQL type of the column. + * + * If not specified, the SQL type will be automatically inferred by the annotated property's Kotlin type. + * The specified class must be a Kotlin singleton object and typed of [SqlType] or [SqlTypeFactory]. + */ + val sqlType: KClass<*> = Nothing::class, + + /** + * The name of the corresponding column property in the generated table class. + * + * If not specified, the name will be the annotated property's name. This behavior can be configured by KSP option + * `ktorm.codingNamingStrategy`, which accepts an implementation class name of + * `org.ktorm.ksp.spi.CodingNamingStrategy`. + */ + val propertyName: String = "", +) diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Ignore.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Ignore.kt new file mode 100644 index 000000000..671dc4b95 --- /dev/null +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Ignore.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2022-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.annotation + +/** + * Ignore the annotated property, not generating the column definition. + */ +@Target(AnnotationTarget.PROPERTY) +@Retention(AnnotationRetention.SOURCE) +public annotation class Ignore diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/PrimaryKey.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/PrimaryKey.kt new file mode 100644 index 000000000..155182288 --- /dev/null +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/PrimaryKey.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2022-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.annotation + +/** + * Mark the annotated column as a primary key. + */ +@Target(AnnotationTarget.PROPERTY) +@Retention(AnnotationRetention.SOURCE) +public annotation class PrimaryKey diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt new file mode 100644 index 000000000..75708f0cf --- /dev/null +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2022-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.annotation + +/** + * Specify the mapped column for an entity property, and bind this column to a reference table. Typically, + * this column is a foreign key in relational databases. Entity sequence APIs would automatically left-join + * all references (recursively) by default. + */ +@Target(AnnotationTarget.PROPERTY) +@Retention(AnnotationRetention.SOURCE) +public annotation class References( + + /** + * The name of the column. + * + * If not specified, the name will be generated by a naming strategy. This naming strategy can be configured + * by KSP option `ktorm.dbNamingStrategy`, which accepts the following values: + * + * - lower-snake-case (default): generate names in lower snake-case, the names are concatenation of the current + * property's name and the referenced table's primary key name. For example, a property `user` referencing a table + * that has a primary key named `id` will get a name `user_id`. + * + * - upper-snake-case: generate names in upper snake-case, the names are concatenation of the current + * property's name and the referenced table's primary key name. For example, a property `user` referencing a table + * that has a primary key named `id` will get a name `USER_ID`. + * + * - Class name of a custom naming strategy, which should be an implementation of + * `org.ktorm.ksp.spi.DatabaseNamingStrategy`. + */ + val name: String = "", + + /** + * The name of the corresponding column property in the generated table class. + * + * If not specified, the name will be the concatenation of the current property's name and the referenced table's + * primary key name. This behavior can be configured by KSP option `ktorm.codingNamingStrategy`, which accepts + * an implementation class name of `org.ktorm.ksp.spi.CodingNamingStrategy`. + */ + val propertyName: String = "", +) diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactories.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactories.kt new file mode 100644 index 000000000..c33686f59 --- /dev/null +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactories.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2022-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.annotation + +import org.ktorm.jackson.JsonSqlType +import org.ktorm.jackson.sharedObjectMapper +import org.ktorm.schema.EnumSqlType +import org.ktorm.schema.SqlType +import kotlin.reflect.KProperty1 +import kotlin.reflect.jvm.javaType +import kotlin.reflect.jvm.jvmErasure + +/** + * Type factory object that creates [EnumSqlType] instances. + */ +public object EnumSqlTypeFactory : SqlTypeFactory { + + @Suppress("UNCHECKED_CAST") + override fun createSqlType(property: KProperty1<*, T?>): SqlType { + val returnType = property.returnType.jvmErasure.java + if (returnType.isEnum) { + return EnumSqlType(returnType as Class>) as SqlType + } else { + throw IllegalArgumentException("The property is required to be typed of enum but actually: $returnType") + } + } +} + +/** + * Type factory object that creates [JsonSqlType] instances. + */ +public object JsonSqlTypeFactory : SqlTypeFactory { + + override fun createSqlType(property: KProperty1<*, T?>): SqlType { + return JsonSqlType(sharedObjectMapper, sharedObjectMapper.constructType(property.returnType.javaType)) + } +} diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactory.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactory.kt new file mode 100644 index 000000000..6cac1733a --- /dev/null +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactory.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2022-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.annotation + +import org.ktorm.schema.SqlType +import kotlin.reflect.KProperty1 + +/** + * Factory interface that creates [SqlType] instances from entity properties. + */ +public interface SqlTypeFactory { + + /** + * Create a [SqlType] instance. + */ + public fun createSqlType(property: KProperty1<*, T?>): SqlType +} diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt new file mode 100644 index 000000000..48b39c9de --- /dev/null +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2022-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.annotation + +/** + * Specify the table for an entity class. + */ +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.SOURCE) +public annotation class Table( + + /** + * The name of the table. + * + * If not specified, the name will be generated by a naming strategy. This naming strategy can be configured + * by KSP option `ktorm.dbNamingStrategy`, which accepts the following values: + * + * - lower-snake-case (default): generate lower snake-case names, for example: UserProfile --> user_profile. + * + * - upper-snake-case: generate upper snake-case names, for example: UserProfile --> USER_PROFILE. + * + * - Class name of a custom naming strategy, which should be an implementation of + * `org.ktorm.ksp.spi.DatabaseNamingStrategy`. + */ + val name: String = "", + + /** + * The alias of the table. + */ + val alias: String = "", + + /** + * The catalog of the table. + * + * The default value can be configured by KSP option `ktorm.catalog`. + */ + val catalog: String = "", + + /** + * The schema of the table. + * + * The default value can be configured by KSP option `ktorm.schema`. + */ + val schema: String = "", + + /** + * The name of the corresponding table class in the generated code. + * + * If not specified, the name will be the plural form of the annotated class's name, + * for example: UserProfile --> UserProfiles. This behavior can be configured by KSP option + * `ktorm.codingNamingStrategy`, which accepts an implementation class name of + * `org.ktorm.ksp.spi.CodingNamingStrategy`. + */ + val className: String = "", + + /** + * The name of the corresponding entity sequence in the generated code. + * + * If not specified, the name will be the plural form of the annotated class's name, with the first word in + * lower case, for example: UserProfile --> userProfiles. This behavior can be configured by KSP option + * `ktorm.codingNamingStrategy`, which accepts an implementation class name of + * `org.ktorm.ksp.spi.CodingNamingStrategy`. + */ + val entitySequenceName: String = "", + + /** + * Specify properties that should be ignored for generating column definitions. + */ + val ignoreProperties: Array = [] +) diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt new file mode 100644 index 000000000..b1bc4de08 --- /dev/null +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt @@ -0,0 +1,178 @@ +/* + * Copyright 2022-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("NoMultipleSpaces") + +package org.ktorm.ksp.annotation + +import sun.misc.Unsafe +import java.lang.reflect.Modifier +import java.lang.reflect.Proxy +import java.nio.ByteBuffer +import java.util.concurrent.ConcurrentHashMap + +/** + * Utility class that creates unique `undefined` values for any class. + * + * These `undefined` values are typically used as default values of parameters in ktorm-ksp generated pseudo + * constructor functions for entities. Pseudo constructors check if the parameter is referential identical to + * the `undefined` value to judge whether it is manually assigned by users or not. We don't use `null` in + * this case because `null` can also be a valid value for entity properties. + * + * For example: + * + * ```kotlin + * public fun Employee(name: String? = Undefined.of()): Employee { + * val entity = Entity.create() + * if (name !== Undefined.of()) { + * entity.name = name + * } + * return entity + * } + * ``` + * + * In this example, `Employee("vince")` creates an employee named vince, `Employee(null)` creates an employee with + * null name (can also be valid in some cases), and, in the meanwhile, `Employee()` creates an employee without giving + * a name, which is different with `Employee(null)`. + * + * Note: `undefined` values created by this class can only be used for referential comparing, any method invocation + * on these values can cause exceptions. + */ +public object Undefined { + private val unsafe = getUnsafe() + private val undefinedValuesCache = ConcurrentHashMap, Any>() + + /** + * Return the `undefined` value for class [T]. See more details in the class level document. + * + * Note: this function never returns null, but we have to mark it as nullable to ensure we are always boxing + * JVM primitive types and Kotlin inline classes. + */ + public inline fun of(): T? { + return getUndefinedValue(T::class.java) as T? + } + + /** + * Get or create the `undefined` value for class [cls]. + */ + @PublishedApi + internal fun getUndefinedValue(cls: Class<*>): Any { + return undefinedValuesCache.computeIfAbsent(cls) { + if (cls.isArray) { + java.lang.reflect.Array.newInstance(cls.componentType, 0) + } else if (cls.isInterface) { + createUndefinedValueByJdkProxy(cls) + } else if (Modifier.isAbstract(cls.modifiers)) { + createUndefinedValueBySubclassing(cls) + } else { + unsafe.allocateInstance(cls) + } + } + } + + /** + * Obtain the [Unsafe] instance by reflection. + */ + private fun getUnsafe(): Unsafe { + val field = Unsafe::class.java.getDeclaredField("theUnsafe") + field.isAccessible = true + return field.get(null) as Unsafe + } + + /** + * Create the `undefined` value for interface by JDK dynamic proxy. + */ + private fun createUndefinedValueByJdkProxy(cls: Class<*>): Any { + return Proxy.newProxyInstance(cls.classLoader, arrayOf(cls)) { proxy, method, args -> + when (method.declaringClass.kotlin) { + Any::class -> { + when (method.name) { + "equals" -> proxy === args!![0] + "hashCode" -> System.identityHashCode(proxy) + "toString" -> "Ktorm undefined value proxy for ${cls.name}" + else -> throw UnsupportedOperationException("Method not supported: $method") + } + } + else -> { + throw UnsupportedOperationException("Method not supported: $method") + } + } + } + } + + /** + * Create the `undefined` value for abstract class by generating a subclass dynamically. + */ + private fun createUndefinedValueBySubclassing(cls: Class<*>): Any { + val subclassName = if (cls.name.startsWith("java.")) "\$${cls.name}\$Undefined" else "${cls.name}\$Undefined" + val classLoader = UndefinedClassLoader(cls.classLoader ?: Thread.currentThread().contextClassLoader) + val subclass = Class.forName(subclassName, true, classLoader) + return unsafe.allocateInstance(subclass) + } + + /** + * Class loader that generates `undefined` subclasses. + * + * Note: + * + * 1. Subclasses generated by this class loader doesn't have any constructors, so we have to use + * [Unsafe.allocateInstance] to create instances. + * + * 2. Subclasses generated by this class loader doesn't implement any abstract methods from their super classes, + * so any invocation on those abstract methods will cause [AbstractMethodError]. + */ + private class UndefinedClassLoader(parent: ClassLoader) : ClassLoader(parent) { + + override fun findClass(name: String): Class<*> { + if (!name.endsWith("\$Undefined")) { + throw ClassNotFoundException(name) + } + + val className = name.replace(".", "/") + val superClassName = className.removePrefix("\$").removeSuffix("\$Undefined") + val bytes = generateByteCode(className.toByteArray(), superClassName.toByteArray()) + return defineClass(name, bytes, null) + } + + @Suppress("MagicNumber") + private fun generateByteCode(className: ByteArray, superClassName: ByteArray): ByteBuffer { + val buf = ByteBuffer.allocate(1024) + buf.putInt(0xCAFEBABE.toInt()) // magic + buf.putShort(0) // minor version + buf.putShort(52) // major version, 52 for JDK1.8 + buf.putShort(5) // constant pool count, 5 means 4 constants in all + buf.put(1) // #1, CONSTANT_Utf8_info + buf.putShort(className.size.toShort()) // length + buf.put(className) // class name + buf.put(7) // #2, CONSTANT_Class_info + buf.putShort(1) // name index, ref to constant #1 + buf.put(1) // #3, CONSTANT_Utf8_info + buf.putShort(superClassName.size.toShort()) // length + buf.put(superClassName) // super class name + buf.put(7) // #4, CONSTANT_Class_info + buf.putShort(3) // name index, ref to constant #3 + buf.putShort((0x0001 or 0x0020 or 0x1000).toShort()) // ACC_PUBLIC | ACC_SUPER | ACC_SYNTHETIC + buf.putShort(2) // this class, ref to constant #2 + buf.putShort(4) // super class, ref to constant #4 + buf.putShort(0) // interfaces count + buf.putShort(0) // fields count + buf.putShort(0) // methods count + buf.putShort(0) // attributes count + buf.flip() + return buf + } + } +} diff --git a/ktorm-ksp-annotations/src/test/kotlin/org/ktorm/ksp/annotation/UndefinedTest.kt b/ktorm-ksp-annotations/src/test/kotlin/org/ktorm/ksp/annotation/UndefinedTest.kt new file mode 100644 index 000000000..932e9a8ef --- /dev/null +++ b/ktorm-ksp-annotations/src/test/kotlin/org/ktorm/ksp/annotation/UndefinedTest.kt @@ -0,0 +1,171 @@ +/* + * Copyright 2022-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.annotation + +import org.junit.Test +import org.ktorm.entity.Entity + +class UndefinedTest { + + private inline fun testUndefined(value: T?) { + val undefined1 = Undefined.of() + val undefined2 = Undefined.of() + + assert(undefined1 is T) + assert(undefined2 is T) + assert(undefined1 !== value) + assert(undefined2 !== value) + assert(undefined1 === undefined2) + + println("Undefined Class Name: " + undefined1!!.javaClass.name) + } + + private fun testUndefinedInt(haveValue: Boolean, value: Int? = Undefined.of()) { + val undefined = Undefined.of() + println("Undefined Class Name: " + undefined!!.javaClass.name) + + if (haveValue) { + assert(value !== undefined) + } else { + assert(value === undefined) + } + } + + private fun testUndefinedUInt(haveValue: Boolean, value: UInt? = Undefined.of()) { + val undefined = Undefined.of() + println("Undefined Class Name: " + undefined!!.javaClass.name) + + if (haveValue) { + assert((value as Any?) !== (undefined as Any?)) + } else { + assert((value as Any?) === (undefined as Any?)) + } + } + + @Test + fun `undefined inlined class`() { + testUndefinedUInt(haveValue = true, value = 1U) + testUndefinedUInt(haveValue = true, value = 0U) + testUndefinedUInt(haveValue = true, value = null) + testUndefinedUInt(haveValue = false) + + testUndefined(0.toUByte()) + testUndefined(0.toUShort()) + testUndefined(0U) + testUndefined(0UL) + } + + @Test + fun `undefined primitive type`() { + testUndefinedInt(haveValue = true, value = 1) + testUndefinedInt(haveValue = true, value = 0) + testUndefinedInt(haveValue = true, value = null) + testUndefinedInt(haveValue = false) + + testUndefined(0.toByte()) + testUndefined(0.toShort()) + testUndefined(0) + testUndefined(0L) + testUndefined('0') + testUndefined(false) + testUndefined(0f) + testUndefined(0.0) + } + + private interface Employee : Entity + + enum class Gender { + MALE, + FEMALE + } + + abstract class Biology + + @Suppress("unused") + abstract class Animal(val name: String) : Biology() + + @Suppress("unused") + private class Dog(val age: Int) : Animal("dog") + + private data class Cat(val age: Int) : Animal("cat") + + @Test + fun `undefined interface`() { + testUndefined(Entity.create()) + testUndefined(null) + } + + @Test + fun `undefined abstract class`() { + testUndefined(Dog(0)) + testUndefined(Dog(0)) + testUndefined(0) + } + + @Test + fun `undefined enum`() { + testUndefined(Gender.MALE) + testUndefined(Gender.FEMALE) + } + + @Test + fun `undefined class`() { + testUndefined(Dog(0)) + } + + @Test + fun `undefined data class`() { + testUndefined(Cat(0)) + } + + private class School { + inner class Teacher + + @Suppress("unused") + inner class Class(private val name: String) + } + + @Test + fun `undefined inner class`() { + val school = School() + val teacher = school.Teacher() + testUndefined(teacher) + val aClass = school.Class("A") + testUndefined(aClass) + } + + @Test + fun `undefined object`() { + testUndefined(Unit) + } + + @Test + fun `undefined companion object`() { + testUndefined(Int.Companion) + } + + @Test + fun `undefined function`() { + testUndefined<(Int) -> String> { it.toString() } + } + + @Test + fun `undefined array`() { + testUndefined(intArrayOf()) + testUndefined>(arrayOf()) + } +} From 2913b26cba51b6f9f425f7b39534387a150ac980 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 24 Jun 2023 23:53:43 +0800 Subject: [PATCH 005/105] rm SqlTypeFactory --- .../main/kotlin/org/ktorm/schema/SqlTypes.kt | 3 ++ .../kotlin/org/ktorm/jackson/JsonSqlType.kt | 4 ++ .../ktorm-ksp-annotations.gradle.kts | 1 - .../kotlin/org/ktorm/ksp/annotation/Column.kt | 5 +- .../ktorm/ksp/annotation/SqlTypeFactories.kt | 51 ------------------- .../ktorm/ksp/annotation/SqlTypeFactory.kt | 31 ----------- 6 files changed, 10 insertions(+), 85 deletions(-) delete mode 100644 ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactories.kt delete mode 100644 ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactory.kt diff --git a/ktorm-core/src/main/kotlin/org/ktorm/schema/SqlTypes.kt b/ktorm-core/src/main/kotlin/org/ktorm/schema/SqlTypes.kt index e033bf492..6c953e45b 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/schema/SqlTypes.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/schema/SqlTypes.kt @@ -504,6 +504,9 @@ public inline fun > BaseTable<*>.enum(name: String): Column< * @property enumClass the enum class. */ public class EnumSqlType>(public val enumClass: Class) : SqlType(Types.OTHER, "enum") { + @Suppress("UNCHECKED_CAST") + public constructor(typeRef: TypeReference) : this(typeRef.referencedType as Class) + private val pgStatementClass = try { Class.forName("org.postgresql.PGStatement") } catch (_: ClassNotFoundException) { null } diff --git a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JsonSqlType.kt b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JsonSqlType.kt index ef0b90f3b..617e5f1ec 100644 --- a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JsonSqlType.kt +++ b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JsonSqlType.kt @@ -58,6 +58,10 @@ public class JsonSqlType( public val objectMapper: ObjectMapper, public val javaType: JavaType ) : SqlType(Types.OTHER, "json") { + public constructor( + typeRef: TypeReference + ) : this(sharedObjectMapper, sharedObjectMapper.constructType(typeRef.referencedType)) + // Access postgresql API by reflection, because it is not a JDK 9 module, // we are not able to require it in module-info.java. private val pgStatementClass = loadClass("org.postgresql.PGStatement") diff --git a/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts b/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts index 89966fea7..5337d5209 100644 --- a/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts +++ b/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts @@ -5,6 +5,5 @@ plugins { dependencies { compileOnly(project(":ktorm-core")) - compileOnly(project(":ktorm-jackson")) testImplementation(project(":ktorm-core")) } diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt index cb719430b..aacec1531 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt @@ -45,9 +45,10 @@ public annotation class Column( * The SQL type of the column. * * If not specified, the SQL type will be automatically inferred by the annotated property's Kotlin type. - * The specified class must be a Kotlin singleton object and typed of [SqlType] or [SqlTypeFactory]. + * The specified class must be a Kotlin singleton object or a normal class with a constructor that accepts a single + * [org.ktorm.schema.TypeReference] argument. */ - val sqlType: KClass<*> = Nothing::class, + val sqlType: KClass<*> = SqlType::class, /** * The name of the corresponding column property in the generated table class. diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactories.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactories.kt deleted file mode 100644 index c33686f59..000000000 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactories.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2022-2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.ktorm.ksp.annotation - -import org.ktorm.jackson.JsonSqlType -import org.ktorm.jackson.sharedObjectMapper -import org.ktorm.schema.EnumSqlType -import org.ktorm.schema.SqlType -import kotlin.reflect.KProperty1 -import kotlin.reflect.jvm.javaType -import kotlin.reflect.jvm.jvmErasure - -/** - * Type factory object that creates [EnumSqlType] instances. - */ -public object EnumSqlTypeFactory : SqlTypeFactory { - - @Suppress("UNCHECKED_CAST") - override fun createSqlType(property: KProperty1<*, T?>): SqlType { - val returnType = property.returnType.jvmErasure.java - if (returnType.isEnum) { - return EnumSqlType(returnType as Class>) as SqlType - } else { - throw IllegalArgumentException("The property is required to be typed of enum but actually: $returnType") - } - } -} - -/** - * Type factory object that creates [JsonSqlType] instances. - */ -public object JsonSqlTypeFactory : SqlTypeFactory { - - override fun createSqlType(property: KProperty1<*, T?>): SqlType { - return JsonSqlType(sharedObjectMapper, sharedObjectMapper.constructType(property.returnType.javaType)) - } -} diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactory.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactory.kt deleted file mode 100644 index 6cac1733a..000000000 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/SqlTypeFactory.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022-2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.ktorm.ksp.annotation - -import org.ktorm.schema.SqlType -import kotlin.reflect.KProperty1 - -/** - * Factory interface that creates [SqlType] instances from entity properties. - */ -public interface SqlTypeFactory { - - /** - * Create a [SqlType] instance. - */ - public fun createSqlType(property: KProperty1<*, T?>): SqlType -} From 191c21235661d5126d35ec743dccc0a2074b45ef Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 25 Jun 2023 00:00:21 +0800 Subject: [PATCH 006/105] fix --- .../src/main/kotlin/org/ktorm/ksp/annotation/Column.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt index aacec1531..5d95a2f3f 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt @@ -45,10 +45,10 @@ public annotation class Column( * The SQL type of the column. * * If not specified, the SQL type will be automatically inferred by the annotated property's Kotlin type. - * The specified class must be a Kotlin singleton object or a normal class with a constructor that accepts a single - * [org.ktorm.schema.TypeReference] argument. + * The specified class must be a Kotlin singleton object or a normal class with a constructor that accepts + * a single [org.ktorm.schema.TypeReference] argument. */ - val sqlType: KClass<*> = SqlType::class, + val sqlType: KClass> = Nothing::class, /** * The name of the corresponding column property in the generated table class. From 1cd8f876accee4c40adf50fa17ff20202d86c565 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 25 Jun 2023 11:41:58 +0800 Subject: [PATCH 007/105] add module-info.java for ktorm-ksp-annotations --- ktorm-ksp-annotations/src/main/moditect/module-info.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ktorm-ksp-annotations/src/main/moditect/module-info.java diff --git a/ktorm-ksp-annotations/src/main/moditect/module-info.java b/ktorm-ksp-annotations/src/main/moditect/module-info.java new file mode 100644 index 000000000..fce2a4b48 --- /dev/null +++ b/ktorm-ksp-annotations/src/main/moditect/module-info.java @@ -0,0 +1,4 @@ +module ktorm.ksp.annotations { + requires static ktorm.core; + exports org.ktorm.ksp.annotation; +} From f372d3b39b8e39b0dbc1f9fee03cc7e09eae09e9 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 25 Jun 2023 15:32:59 +0800 Subject: [PATCH 008/105] requires jdk.unsupported --- ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts | 3 +-- ktorm-ksp-annotations/src/main/moditect/module-info.java | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts b/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts index 5337d5209..2dda76336 100644 --- a/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts +++ b/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts @@ -4,6 +4,5 @@ plugins { } dependencies { - compileOnly(project(":ktorm-core")) - testImplementation(project(":ktorm-core")) + api(project(":ktorm-core")) } diff --git a/ktorm-ksp-annotations/src/main/moditect/module-info.java b/ktorm-ksp-annotations/src/main/moditect/module-info.java index fce2a4b48..698a72c04 100644 --- a/ktorm-ksp-annotations/src/main/moditect/module-info.java +++ b/ktorm-ksp-annotations/src/main/moditect/module-info.java @@ -1,4 +1,5 @@ module ktorm.ksp.annotations { - requires static ktorm.core; + requires ktorm.core; + requires jdk.unsupported; exports org.ktorm.ksp.annotation; } From 1f1bf5b9a31d1ac46b8260e115f55dfc20abf31f Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 25 Jun 2023 19:41:15 +0800 Subject: [PATCH 009/105] fix copyright header --- .../src/main/kotlin/org/ktorm/ksp/annotation/Column.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/annotation/Ignore.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/annotation/PrimaryKey.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/annotation/References.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/annotation/Table.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt index 5d95a2f3f..0d1e3a62b 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 the original author or authors. + * Copyright 2018-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Ignore.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Ignore.kt index 671dc4b95..f8724d1f6 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Ignore.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Ignore.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 the original author or authors. + * Copyright 2018-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/PrimaryKey.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/PrimaryKey.kt index 155182288..604a8eb17 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/PrimaryKey.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/PrimaryKey.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 the original author or authors. + * Copyright 2018-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt index 75708f0cf..03f2c5e94 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 the original author or authors. + * Copyright 2018-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt index 48b39c9de..a51e61f4f 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 the original author or authors. + * Copyright 2018-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt index b1bc4de08..527db1dc3 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 the original author or authors. + * Copyright 2018-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 83f016ce1700574a9248bda26618c4a913ee8bb1 Mon Sep 17 00:00:00 2001 From: vince Date: Tue, 27 Jun 2023 23:39:40 +0800 Subject: [PATCH 010/105] init ksp spi module --- ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts | 9 +++++++++ settings.gradle.kts | 1 + 2 files changed, 10 insertions(+) create mode 100644 ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts diff --git a/ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts b/ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts new file mode 100644 index 000000000..80f509de9 --- /dev/null +++ b/ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts @@ -0,0 +1,9 @@ + +plugins { + id("ktorm.module") +} + +dependencies { + api("com.google.devtools.ksp:symbol-processing-api:1.7.22-1.0.8") + api("com.squareup:kotlinpoet-ksp:1.11.0") +} diff --git a/settings.gradle.kts b/settings.gradle.kts index f9993842f..b8d8ece63 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -7,6 +7,7 @@ include("ktorm-core") include("ktorm-global") include("ktorm-jackson") include("ktorm-ksp-annotations") +include("ktorm-ksp-spi") include("ktorm-support-mysql") include("ktorm-support-oracle") include("ktorm-support-postgresql") From cbf6266507f1ade77c3143f80ee058b889c336c9 Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 30 Jun 2023 20:45:56 +0800 Subject: [PATCH 011/105] migrate spi code --- .../org/ktorm/ksp/spi/CodingNamingStrategy.kt | 46 ++++++++++++ .../org/ktorm/ksp/spi/ColumnMetadata.kt | 66 +++++++++++++++++ .../ktorm/ksp/spi/DatabaseNamingStrategy.kt | 41 +++++++++++ .../org/ktorm/ksp/spi/ExtCodeGenerator.kt | 49 +++++++++++++ .../kotlin/org/ktorm/ksp/spi/TableMetadata.kt | 70 +++++++++++++++++++ 5 files changed, 272 insertions(+) create mode 100644 ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt create mode 100644 ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt create mode 100644 ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/DatabaseNamingStrategy.kt create mode 100644 ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ExtCodeGenerator.kt create mode 100644 ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/TableMetadata.kt diff --git a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt new file mode 100644 index 000000000..69f6b9a13 --- /dev/null +++ b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.spi + +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSPropertyDeclaration + +/** + * Naming strategy for Kotlin symbols in the generated code. + */ +public interface CodingNamingStrategy { + + /** + * Generate the table class name. + */ + public fun getTableClassName(c: KSClassDeclaration): String + + /** + * Generate the entity sequence name. + */ + public fun getEntitySequenceName(c: KSClassDeclaration): String + + /** + * Generate the column property name. + */ + public fun getColumnPropertyName(c: KSClassDeclaration, prop: KSPropertyDeclaration): String + + /** + * Generate the reference column property name. + */ + public fun getRefColumnPropertyName(c: KSClassDeclaration, prop: KSPropertyDeclaration, ref: TableMetadata): String +} diff --git a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt new file mode 100644 index 000000000..9d4019366 --- /dev/null +++ b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.spi + +import com.google.devtools.ksp.symbol.KSPropertyDeclaration +import com.google.devtools.ksp.symbol.KSType + +/** + * Column definition metadata. + */ +public data class ColumnMetadata( + + /** + * The annotated entity property of the column. + */ + val entityProperty: KSPropertyDeclaration, + + /** + * The belonging table. + */ + val table: TableMetadata, + + /** + * The name of the column. + */ + val name: String, + + /** + * Check if the column is a primary key. + */ + val isPrimaryKey: Boolean, + + /** + * The SQL type of the column. + */ + val sqlType: KSType, + + /** + * Check if the column is a reference column. + */ + val isReference: Boolean, + + /** + * The referenced table of the column. + */ + val referenceTable: TableMetadata?, + + /** + * The name of the corresponding column property in the generated table class. + */ + val columnPropertyName: String +) diff --git a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/DatabaseNamingStrategy.kt b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/DatabaseNamingStrategy.kt new file mode 100644 index 000000000..8e748bfac --- /dev/null +++ b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/DatabaseNamingStrategy.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.spi + +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSPropertyDeclaration + +/** + * Naming strategy for database tables and columns. + */ +public interface DatabaseNamingStrategy { + + /** + * Generate the table name. + */ + public fun getTableName(c: KSClassDeclaration): String + + /** + * Generate the column name. + */ + public fun getColumnName(c: KSClassDeclaration, prop: KSPropertyDeclaration): String + + /** + * Generate the reference column name. + */ + public fun getRefColumnName(c: KSClassDeclaration, prop: KSPropertyDeclaration, ref: TableMetadata): String +} diff --git a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ExtCodeGenerator.kt b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ExtCodeGenerator.kt new file mode 100644 index 000000000..6c1132430 --- /dev/null +++ b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ExtCodeGenerator.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.spi + +import com.google.devtools.ksp.processing.SymbolProcessorEnvironment +import com.squareup.kotlinpoet.FunSpec +import com.squareup.kotlinpoet.PropertySpec +import com.squareup.kotlinpoet.TypeSpec + +/** + * Ktorm KSP code generator interface for third-party extensions. + */ +public interface ExtCodeGenerator { + + /** + * Generate types for the [table] in the corresponding resulting file. + */ + public fun generateTypes(table: TableMetadata, environment: SymbolProcessorEnvironment): List { + return emptyList() + } + + /** + * Generate top-level properties for the [table] in the corresponding resulting file. + */ + public fun generateProperties(table: TableMetadata, environment: SymbolProcessorEnvironment): List { + return emptyList() + } + + /** + * Generate top-level functions for the [table] in the corresponding resulting file. + */ + public fun generateFunctions(table: TableMetadata, environment: SymbolProcessorEnvironment): List { + return emptyList() + } +} diff --git a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/TableMetadata.kt b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/TableMetadata.kt new file mode 100644 index 000000000..1359b4505 --- /dev/null +++ b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/TableMetadata.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.spi + +import com.google.devtools.ksp.symbol.KSClassDeclaration + +/** + * Table definition metadata. + */ +public data class TableMetadata( + + /** + * The annotated entity class of the table. + */ + val entityClass: KSClassDeclaration, + + /** + * The name of the table. + */ + val name: String, + + /** + * The alias of the table. + */ + val alias: String?, + + /** + * The catalog of the table. + */ + val catalog: String?, + + /** + * The schema of the table. + */ + val schema: String?, + + /** + * The name of the corresponding table class in the generated code. + */ + val tableClassName: String, + + /** + * The name of the corresponding entity sequence in the generated code. + */ + val entitySequenceName: String, + + /** + * Properties that should be ignored for generating column definitions. + */ + val ignoreProperties: Set, + + /** + * Columns in the table. + */ + val columns: List +) From 4382539d540ff42236bfca707fd70c4efd94fe1e Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 30 Jun 2023 20:50:42 +0800 Subject: [PATCH 012/105] add module-info.java for spi module --- ktorm-ksp-spi/src/main/moditect/module-info.java | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 ktorm-ksp-spi/src/main/moditect/module-info.java diff --git a/ktorm-ksp-spi/src/main/moditect/module-info.java b/ktorm-ksp-spi/src/main/moditect/module-info.java new file mode 100644 index 000000000..19e86d8d7 --- /dev/null +++ b/ktorm-ksp-spi/src/main/moditect/module-info.java @@ -0,0 +1,3 @@ +module ktorm.ksp.spi { + exports org.ktorm.ksp.spi; +} From c96bfd290ac075a897430dd3e65217a22068a90a Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 2 Jul 2023 00:21:23 +0800 Subject: [PATCH 013/105] skip modular for ksp spi --- ...odule.gradle.kts => ktorm.base.gradle.kts} | 28 ----------------- .../main/kotlin/ktorm.modularity.gradle.kts | 30 +++++++++++++++++++ ktorm-core/ktorm-core.gradle.kts | 5 +++- ktorm-global/ktorm-global.gradle.kts | 5 +++- ktorm-jackson/ktorm-jackson.gradle.kts | 5 +++- .../ktorm-ksp-annotations.gradle.kts | 5 +++- ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts | 4 ++- .../src/main/moditect/module-info.java | 3 -- .../ktorm-support-mysql.gradle.kts | 5 +++- .../ktorm-support-oracle.gradle.kts | 5 +++- .../ktorm-support-postgresql.gradle.kts | 5 +++- .../ktorm-support-sqlite.gradle.kts | 5 +++- .../ktorm-support-sqlserver.gradle.kts | 5 +++- 13 files changed, 69 insertions(+), 41 deletions(-) rename buildSrc/src/main/kotlin/{ktorm.module.gradle.kts => ktorm.base.gradle.kts} (50%) create mode 100644 buildSrc/src/main/kotlin/ktorm.modularity.gradle.kts delete mode 100644 ktorm-ksp-spi/src/main/moditect/module-info.java diff --git a/buildSrc/src/main/kotlin/ktorm.module.gradle.kts b/buildSrc/src/main/kotlin/ktorm.base.gradle.kts similarity index 50% rename from buildSrc/src/main/kotlin/ktorm.module.gradle.kts rename to buildSrc/src/main/kotlin/ktorm.base.gradle.kts index 6f401b380..227aa9b72 100644 --- a/buildSrc/src/main/kotlin/ktorm.module.gradle.kts +++ b/buildSrc/src/main/kotlin/ktorm.base.gradle.kts @@ -5,10 +5,7 @@ version = rootProject.version plugins { id("kotlin") id("org.gradle.jacoco") - id("org.moditect.gradleplugin") id("io.gitlab.arturbosch.detekt") - id("ktorm.source-header-check") - id("ktorm.publish") } repositories { @@ -22,31 +19,6 @@ dependencies { detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:${detekt.toolVersion}") } -moditect { - // Generate a multi-release jar, the module descriptor will be located at META-INF/versions/9/module-info.class - addMainModuleInfo { - jvmVersion.set("9") - overwriteExistingFiles.set(true) - module { - moduleInfoFile = file("src/main/moditect/module-info.java") - } - } - - // Let kotlin compiler know the module descriptor. - if (JavaVersion.current() >= JavaVersion.VERSION_1_9) { - sourceSets.main { - kotlin.srcDir("src/main/moditect") - } - } - - // Workaround to avoid circular task dependencies, see https://github.com/moditect/moditect-gradle-plugin/issues/14 - afterEvaluate { - val compileJava = tasks.compileJava.get() - val addDependenciesModuleInfo = tasks.addDependenciesModuleInfo.get() - compileJava.setDependsOn(compileJava.dependsOn - addDependenciesModuleInfo) - } -} - detekt { source = files("src/main/kotlin") config = files("${project.rootDir}/detekt.yml") diff --git a/buildSrc/src/main/kotlin/ktorm.modularity.gradle.kts b/buildSrc/src/main/kotlin/ktorm.modularity.gradle.kts new file mode 100644 index 000000000..1d6fd4792 --- /dev/null +++ b/buildSrc/src/main/kotlin/ktorm.modularity.gradle.kts @@ -0,0 +1,30 @@ + +plugins { + id("kotlin") + id("org.moditect.gradleplugin") +} + +moditect { + // Generate a multi-release jar, the module descriptor will be located at META-INF/versions/9/module-info.class + addMainModuleInfo { + jvmVersion.set("9") + overwriteExistingFiles.set(true) + module { + moduleInfoFile = file("src/main/moditect/module-info.java") + } + } + + // Let kotlin compiler know the module descriptor. + if (JavaVersion.current() >= JavaVersion.VERSION_1_9) { + sourceSets.main { + kotlin.srcDir("src/main/moditect") + } + } + + // Workaround to avoid circular task dependencies, see https://github.com/moditect/moditect-gradle-plugin/issues/14 + afterEvaluate { + val compileJava = tasks.compileJava.get() + val addDependenciesModuleInfo = tasks.addDependenciesModuleInfo.get() + compileJava.setDependsOn(compileJava.dependsOn - addDependenciesModuleInfo) + } +} diff --git a/ktorm-core/ktorm-core.gradle.kts b/ktorm-core/ktorm-core.gradle.kts index db70c7ea9..12f505c7c 100644 --- a/ktorm-core/ktorm-core.gradle.kts +++ b/ktorm-core/ktorm-core.gradle.kts @@ -1,6 +1,9 @@ plugins { - id("ktorm.module") + id("ktorm.base") + id("ktorm.modularity") + id("ktorm.publish") + id("ktorm.source-header-check") id("ktorm.tuples-codegen") } diff --git a/ktorm-global/ktorm-global.gradle.kts b/ktorm-global/ktorm-global.gradle.kts index 4ccd4f19f..5a4eed686 100644 --- a/ktorm-global/ktorm-global.gradle.kts +++ b/ktorm-global/ktorm-global.gradle.kts @@ -1,6 +1,9 @@ plugins { - id("ktorm.module") + id("ktorm.base") + id("ktorm.modularity") + id("ktorm.publish") + id("ktorm.source-header-check") } dependencies { diff --git a/ktorm-jackson/ktorm-jackson.gradle.kts b/ktorm-jackson/ktorm-jackson.gradle.kts index dc55022aa..06c086ce5 100644 --- a/ktorm-jackson/ktorm-jackson.gradle.kts +++ b/ktorm-jackson/ktorm-jackson.gradle.kts @@ -1,6 +1,9 @@ plugins { - id("ktorm.module") + id("ktorm.base") + id("ktorm.modularity") + id("ktorm.publish") + id("ktorm.source-header-check") } dependencies { diff --git a/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts b/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts index 2dda76336..bee31c74f 100644 --- a/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts +++ b/ktorm-ksp-annotations/ktorm-ksp-annotations.gradle.kts @@ -1,6 +1,9 @@ plugins { - id("ktorm.module") + id("ktorm.base") + id("ktorm.modularity") + id("ktorm.publish") + id("ktorm.source-header-check") } dependencies { diff --git a/ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts b/ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts index 80f509de9..3bbbfa191 100644 --- a/ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts +++ b/ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts @@ -1,6 +1,8 @@ plugins { - id("ktorm.module") + id("ktorm.base") + id("ktorm.publish") + id("ktorm.source-header-check") } dependencies { diff --git a/ktorm-ksp-spi/src/main/moditect/module-info.java b/ktorm-ksp-spi/src/main/moditect/module-info.java deleted file mode 100644 index 19e86d8d7..000000000 --- a/ktorm-ksp-spi/src/main/moditect/module-info.java +++ /dev/null @@ -1,3 +0,0 @@ -module ktorm.ksp.spi { - exports org.ktorm.ksp.spi; -} diff --git a/ktorm-support-mysql/ktorm-support-mysql.gradle.kts b/ktorm-support-mysql/ktorm-support-mysql.gradle.kts index 933027468..9bee95e83 100644 --- a/ktorm-support-mysql/ktorm-support-mysql.gradle.kts +++ b/ktorm-support-mysql/ktorm-support-mysql.gradle.kts @@ -1,6 +1,9 @@ plugins { - id("ktorm.module") + id("ktorm.base") + id("ktorm.modularity") + id("ktorm.publish") + id("ktorm.source-header-check") } dependencies { diff --git a/ktorm-support-oracle/ktorm-support-oracle.gradle.kts b/ktorm-support-oracle/ktorm-support-oracle.gradle.kts index ec6b3a257..88df99709 100644 --- a/ktorm-support-oracle/ktorm-support-oracle.gradle.kts +++ b/ktorm-support-oracle/ktorm-support-oracle.gradle.kts @@ -1,6 +1,9 @@ plugins { - id("ktorm.module") + id("ktorm.base") + id("ktorm.modularity") + id("ktorm.publish") + id("ktorm.source-header-check") } dependencies { diff --git a/ktorm-support-postgresql/ktorm-support-postgresql.gradle.kts b/ktorm-support-postgresql/ktorm-support-postgresql.gradle.kts index fc93a6966..9fcb7edf4 100644 --- a/ktorm-support-postgresql/ktorm-support-postgresql.gradle.kts +++ b/ktorm-support-postgresql/ktorm-support-postgresql.gradle.kts @@ -1,6 +1,9 @@ plugins { - id("ktorm.module") + id("ktorm.base") + id("ktorm.modularity") + id("ktorm.publish") + id("ktorm.source-header-check") } dependencies { diff --git a/ktorm-support-sqlite/ktorm-support-sqlite.gradle.kts b/ktorm-support-sqlite/ktorm-support-sqlite.gradle.kts index b399f4841..d0143ac3e 100644 --- a/ktorm-support-sqlite/ktorm-support-sqlite.gradle.kts +++ b/ktorm-support-sqlite/ktorm-support-sqlite.gradle.kts @@ -1,6 +1,9 @@ plugins { - id("ktorm.module") + id("ktorm.base") + id("ktorm.modularity") + id("ktorm.publish") + id("ktorm.source-header-check") } dependencies { diff --git a/ktorm-support-sqlserver/ktorm-support-sqlserver.gradle.kts b/ktorm-support-sqlserver/ktorm-support-sqlserver.gradle.kts index d501c2936..ed99e1e71 100644 --- a/ktorm-support-sqlserver/ktorm-support-sqlserver.gradle.kts +++ b/ktorm-support-sqlserver/ktorm-support-sqlserver.gradle.kts @@ -1,6 +1,9 @@ plugins { - id("ktorm.module") + id("ktorm.base") + id("ktorm.modularity") + id("ktorm.publish") + id("ktorm.source-header-check") } dependencies { From 26524aadc46d147f21947951ae10778323b938bc Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 2 Jul 2023 10:49:43 +0800 Subject: [PATCH 014/105] init ksp compiler module --- .../ktorm-ksp-compiler.gradle.kts | 20 +++++++++++++++++++ settings.gradle.kts | 1 + 2 files changed, 21 insertions(+) create mode 100644 ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts diff --git a/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts b/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts new file mode 100644 index 000000000..4d440ca62 --- /dev/null +++ b/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts @@ -0,0 +1,20 @@ + +plugins { + id("ktorm.base") + id("ktorm.publish") + id("ktorm.source-header-check") +} + +dependencies { + implementation(project(":ktorm-core")) + implementation(project(":ktorm-ksp-annotations")) + implementation(project(":ktorm-ksp-spi")) + implementation("com.google.devtools.ksp:symbol-processing-api:1.7.22-1.0.8") + implementation("com.squareup:kotlinpoet-ksp:1.11.0") + implementation("com.facebook:ktfmt:0.40") + implementation("org.atteo:evo-inflector:1.3") + testImplementation("com.github.tschuchortdev:kotlin-compile-testing:1.4.8") + testImplementation("com.github.tschuchortdev:kotlin-compile-testing-ksp:1.4.8") + testImplementation("com.h2database:h2:1.4.198") + testImplementation("org.slf4j:slf4j-simple:1.7.25") +} diff --git a/settings.gradle.kts b/settings.gradle.kts index b8d8ece63..1a5d4b011 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -7,6 +7,7 @@ include("ktorm-core") include("ktorm-global") include("ktorm-jackson") include("ktorm-ksp-annotations") +include("ktorm-ksp-compiler") include("ktorm-ksp-spi") include("ktorm-support-mysql") include("ktorm-support-oracle") From e4b07f739ef7da1b5357be227f38fe1ba6ed8f4b Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 2 Jul 2023 16:33:29 +0800 Subject: [PATCH 015/105] migrate ksp compiler code --- .../org/ktorm/ksp/annotation/UndefinedTest.kt | 2 +- .../ksp/compiler/KtormProcessorProvider.kt | 106 +++++++ .../generator/AddFunctionGenerator.kt | 192 ++++++++++++ .../generator/ComponentFunctionGenerator.kt | 45 +++ .../generator/CopyFunctionGenerator.kt | 39 +++ .../EntitySequencePropertyGenerator.kt | 47 +++ .../ksp/compiler/generator/FileGenerator.kt | 77 +++++ .../PseudoConstructorFunctionGenerator.kt | 102 ++++++ .../compiler/generator/TableClassGenerator.kt | 220 +++++++++++++ .../generator/UpdateFunctionGenerator.kt | 126 ++++++++ .../ksp/compiler/parser/MetadataParser.kt | 292 ++++++++++++++++++ .../ktorm/ksp/compiler/util/KspExtensions.kt | 102 ++++++ .../org/ktorm/ksp/compiler/util/Namings.kt | 96 ++++++ .../ksp/compiler/util/SqlTypeMappings.kt | 135 ++++++++ ...ols.ksp.processing.SymbolProcessorProvider | 1 + 15 files changed, 1581 insertions(+), 1 deletion(-) create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGenerator.kt create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGenerator.kt create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/EntitySequencePropertyGenerator.kt create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt create mode 100644 ktorm-ksp-compiler/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider diff --git a/ktorm-ksp-annotations/src/test/kotlin/org/ktorm/ksp/annotation/UndefinedTest.kt b/ktorm-ksp-annotations/src/test/kotlin/org/ktorm/ksp/annotation/UndefinedTest.kt index 932e9a8ef..aa8042bc8 100644 --- a/ktorm-ksp-annotations/src/test/kotlin/org/ktorm/ksp/annotation/UndefinedTest.kt +++ b/ktorm-ksp-annotations/src/test/kotlin/org/ktorm/ksp/annotation/UndefinedTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 the original author or authors. + * Copyright 2018-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt new file mode 100644 index 000000000..789035fe9 --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt @@ -0,0 +1,106 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.compiler + +import com.facebook.ktfmt.format.Formatter +import com.facebook.ktfmt.format.FormattingOptions +import com.google.devtools.ksp.processing.* +import com.google.devtools.ksp.symbol.KSAnnotated +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSFile +import com.squareup.kotlinpoet.FileSpec +import org.ktorm.ksp.api.Table +import org.ktorm.ksp.compiler.generator.FileGenerator +import org.ktorm.ksp.compiler.parser.MetadataParser +import org.ktorm.ksp.compiler.util.isValid +import org.ktorm.ksp.spi.TableMetadata +import kotlin.reflect.jvm.jvmName + +public class KtormProcessorProvider : SymbolProcessorProvider { + + override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { + for (generator in FileGenerator.extCodeGenerators) { + environment.logger.info("[ktorm-ksp-compiler] load ext generator: $generator") + } + + return object : SymbolProcessor { + override fun process(resolver: Resolver): List { + return doProcess(resolver, environment) + } + } + } + + private fun doProcess(resolver: Resolver, environment: SymbolProcessorEnvironment): List { + val (symbols, deferral) = resolver.getSymbolsWithAnnotation(Table::class.jvmName).partition { it.isValid() } + + val parser = MetadataParser(resolver, environment) + for (symbol in symbols) { + if (symbol is KSClassDeclaration) { + val table = parser.parseTableMetadata(symbol) + generateFile(table, environment) + } + } + + return deferral + } + + private fun generateFile(table: TableMetadata, environment: SymbolProcessorEnvironment) { + // Generate file spec by kotlinpoet. + val fileSpec = FileGenerator.generate(table, environment) + + // Beautify the generated code by facebook ktfmt. + val formattedCode = formatCode(fileSpec, environment.logger) + + // Output the formatted code. + val dependencies = Dependencies(false, *table.getDependencyFiles().toTypedArray()) + val file = environment.codeGenerator.createNewFile(dependencies, fileSpec.packageName, fileSpec.name) + file.writer(Charsets.UTF_8).use { it.write(formattedCode) } + } + + private fun formatCode(fileSpec: FileSpec, logger: KSPLogger): String { + // Use the Kotlin official code style. + val options = FormattingOptions(style = FormattingOptions.Style.GOOGLE, maxWidth = 120, blockIndent = 4) + + // Remove tailing commas in parameter lists. + val code = fileSpec.toString().replace(Regex(""",\s*\)"""), ")") + + try { + return Formatter.format(options, code) + } catch (e: Exception) { + logger.exception(e) + return code + } + } + + private fun TableMetadata.getDependencyFiles(): List { + val files = ArrayList() + + val containingFile = entityClass.containingFile + if (containingFile != null) { + files += containingFile + } + + for (column in columns) { + val ref = column.referenceTable + if (ref != null) { + files += ref.getDependencyFiles() + } + } + + return files + } +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt new file mode 100644 index 000000000..163e5895e --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt @@ -0,0 +1,192 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.compiler.generator + +import com.squareup.kotlinpoet.* +import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy +import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview +import com.squareup.kotlinpoet.ksp.toClassName +import org.ktorm.dsl.AliasRemover +import org.ktorm.entity.EntitySequence +import org.ktorm.expression.ColumnAssignmentExpression +import org.ktorm.expression.InsertExpression +import org.ktorm.ksp.spi.ColumnMetadata +import org.ktorm.ksp.spi.TableMetadata +import org.ktorm.schema.Column + +@OptIn(KotlinPoetKspPreview::class) +internal object AddFunctionGenerator { + + fun generate(table: TableMetadata): FunSpec { + val primaryKeys = table.columns.filter { it.isPrimaryKey } + val useGeneratedKey = primaryKeys.size == 1 + && primaryKeys[0].entityProperty.isMutable + && primaryKeys[0].entityProperty.type.resolve().isMarkedNullable + + val entityClass = table.entityClass.toClassName() + val tableClass = ClassName(table.entityClass.packageName.asString(), table.tableClassName) + + return FunSpec.builder("add") + .addKdoc(kdoc(table, useGeneratedKey)) + .receiver(EntitySequence::class.asClassName().parameterizedBy(entityClass, tableClass)) + .addParameter("entity", entityClass) + .addParameter(ParameterSpec.builder("isDynamic", typeNameOf()).defaultValue("false").build()) + .returns(Int::class.asClassName()) + .addCode(checkForDml()) + .addCode(addValFun()) + .addCode(addAssignments(table, useGeneratedKey)) + .addCode(createExpression()) + .addCode(executeUpdate(useGeneratedKey, primaryKeys)) + .build() + } + + private fun kdoc(table: TableMetadata, useGeneratedKey: Boolean): String { + var kdoc = "" + + "Insert the given entity into this sequence and return the affected record number. " + + "If [isDynamic] is set to true, the generated SQL will include only the non-null columns. " + + if (useGeneratedKey) { + val pk = table.columns.single { it.isPrimaryKey } + val pkName = table.entityClass.simpleName.asString() + "." + pk.entityProperty.simpleName.asString() + + kdoc += "\n\n" + + "Note that this function will obtain the generated primary key from the database and fill it into " + + "the property [${pkName}] after the insertion completes. But this requires us not to set " + + "the primary key’s value beforehand, otherwise, if you do that, the given value will be " + + "inserted into the database, and no keys generated." + } + + return kdoc + } + + internal fun checkForDml(): CodeBlock { + val code = """ + val isModified = + expression.where != null || + expression.groupBy.isNotEmpty() || + expression.having != null || + expression.isDistinct || + expression.orderBy.isNotEmpty() || + expression.offset != null || + expression.limit != null + + if (isModified) { + val msg = + "Entity manipulation functions are not supported by this sequence object. " + + "Please call on the origin sequence returned from database.sequenceOf(table)" + throw UnsupportedOperationException(msg) + } + + + """.trimIndent() + + return CodeBlock.of(code) + } + + internal fun addValFun(): CodeBlock { + val code = """ + fun MutableList<%1T<*>>.addVal(column: %2T, value: T?, isDynamic: Boolean) { + if (!isDynamic || value != null) { + this += %1T(column.asExpression(), column.wrapArgument(value)) + } + } + + + """.trimIndent() + + return CodeBlock.of(code, ColumnAssignmentExpression::class.asClassName(), Column::class.asClassName()) + } + + private fun addAssignments(table: TableMetadata, useGeneratedKey: Boolean): CodeBlock { + return buildCodeBlock { + addStatement("val assignments = ArrayList<%T<*>>()", ColumnAssignmentExpression::class.asClassName()) + + for (column in table.columns) { + val forceDynamic = useGeneratedKey + && column.isPrimaryKey && column.entityProperty.type.resolve().isMarkedNullable + + addStatement( + "assignments.addVal(sourceTable.%N, entity.%N, %L)", + column.columnPropertyName, + column.entityProperty.simpleName.asString(), + if (forceDynamic) "isDynamic·=·true" else "isDynamic" + ) + } + + add("\n") + + beginControlFlow("if (assignments.isEmpty())") + addStatement("return 0") + endControlFlow() + + add("\n") + } + } + + private fun createExpression(): CodeBlock { + val code = """ + val expression = database.dialect.createExpressionVisitor(%T).visit( + %T(sourceTable.asExpression(), assignments) + ) + + + """.trimIndent() + + return CodeBlock.of(code, AliasRemover::class.asClassName(), InsertExpression::class.asClassName()) + } + + private fun executeUpdate(useGeneratedKey: Boolean, primaryKeys: List): CodeBlock { + return buildCodeBlock { + if (!useGeneratedKey) { + addStatement("return database.executeUpdate(expression)") + } else { + // If the primary key value is manually specified, not obtain the generated key. + beginControlFlow("if (entity.%N != null)", primaryKeys[0].entityProperty.simpleName.asString()) + addStatement("return database.executeUpdate(expression)") + + // Else obtain the generated key value. + nextControlFlow("else") + addNamed( + format = """ + val (effects, rowSet) = database.executeUpdateAndRetrieveKeys(expression) + if (rowSet.next()) { + // TODO: use CachedRowSet.getGeneratedKey + val generatedKey = sourceTable.%columnName:N.sqlType.getResult(rowSet, 1) + if (generatedKey != null) { + if (database.logger.isDebugEnabled()) { + database.logger.debug("Generated Key: ${'$'}generatedKey") + } + + entity.%propertyName:N = generatedKey + } + } + + return effects + + """.trimIndent(), + + arguments = mapOf( + "columnName" to primaryKeys[0].columnPropertyName, + "propertyName" to primaryKeys[0].entityProperty.simpleName.asString() + ) + ) + + endControlFlow() + } + } + } +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGenerator.kt new file mode 100644 index 000000000..59a6f61e8 --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGenerator.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.compiler.generator + +import com.google.devtools.ksp.isAbstract +import com.squareup.kotlinpoet.FunSpec +import com.squareup.kotlinpoet.KModifier +import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview +import com.squareup.kotlinpoet.ksp.toClassName +import com.squareup.kotlinpoet.ksp.toTypeName +import org.ktorm.ksp.spi.TableMetadata + +@OptIn(KotlinPoetKspPreview::class) +internal object ComponentFunctionGenerator { + + fun generate(table: TableMetadata): Sequence { + return table.entityClass.getAllProperties() + .filter { it.isAbstract() } + .filterNot { it.simpleName.asString() in setOf("entityClass", "properties") } + .mapIndexed { i, prop -> + FunSpec.builder("component${i + 1}") + .addKdoc("Return the value of [%L.%L]. ", + table.entityClass.simpleName.asString(), prop.simpleName.asString()) + .addModifiers(KModifier.OPERATOR) + .receiver(table.entityClass.toClassName()) + .returns(prop.type.resolve().toTypeName()) + .addCode("return·this.%N", prop.simpleName.asString()) + .build() + } + } +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGenerator.kt new file mode 100644 index 000000000..b4ef8cb46 --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGenerator.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.compiler.generator + +import com.squareup.kotlinpoet.FunSpec +import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview +import com.squareup.kotlinpoet.ksp.toClassName +import org.ktorm.ksp.spi.TableMetadata + +@OptIn(KotlinPoetKspPreview::class) +internal object CopyFunctionGenerator { + + fun generate(table: TableMetadata): FunSpec { + return FunSpec.builder("copy") + .addKdoc( + "Return a deep copy of this entity (which has the same property values and tracked statuses), " + + "and alter the specified property values. " + ) + .receiver(table.entityClass.toClassName()) + .addParameters(PseudoConstructorFunctionGenerator.buildParameters(table).asIterable()) + .returns(table.entityClass.toClassName()) + .addCode(PseudoConstructorFunctionGenerator.buildFunctionBody(table, isCopy = true)) + .build() + } +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/EntitySequencePropertyGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/EntitySequencePropertyGenerator.kt new file mode 100644 index 000000000..0aedb86d5 --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/EntitySequencePropertyGenerator.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.compiler.generator + +import com.squareup.kotlinpoet.* +import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy +import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview +import com.squareup.kotlinpoet.ksp.toClassName +import org.ktorm.database.Database +import org.ktorm.entity.EntitySequence +import org.ktorm.ksp.spi.TableMetadata + +@OptIn(KotlinPoetKspPreview::class) +internal object EntitySequencePropertyGenerator { + + fun generate(table: TableMetadata): PropertySpec { + val entityClass = table.entityClass.toClassName() + val tableClass = ClassName(table.entityClass.packageName.asString(), table.tableClassName) + val entitySequenceType = EntitySequence::class.asClassName().parameterizedBy(entityClass, tableClass) + + return PropertySpec.builder(table.entitySequenceName, entitySequenceType) + .addKdoc("Return the default entity sequence of [%L].", table.tableClassName) + .receiver(Database::class.asClassName()) + .getter( + FunSpec.getterBuilder() + .addStatement( + "return·this.%M(%N)", + MemberName("org.ktorm.entity", "sequenceOf", true), + table.tableClassName) + .build()) + .build() + } +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt new file mode 100644 index 000000000..cd3e2d144 --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.compiler.generator + +import com.google.devtools.ksp.processing.SymbolProcessorEnvironment +import com.google.devtools.ksp.symbol.ClassKind +import com.squareup.kotlinpoet.AnnotationSpec +import com.squareup.kotlinpoet.FileSpec +import org.ktorm.ksp.spi.ExtCodeGenerator +import org.ktorm.ksp.spi.TableMetadata +import java.util.* + +internal object FileGenerator { + val extCodeGenerators = ServiceLoader.load(ExtCodeGenerator::class.java).toList() + + fun generate(table: TableMetadata, environment: SymbolProcessorEnvironment): FileSpec { + val fileSpec = FileSpec.builder(table.entityClass.packageName.asString(), table.tableClassName) + .addFileComment("Auto-generated by ktorm-ksp-compiler, DO NOT EDIT!") + .addAnnotation( + AnnotationSpec.builder(Suppress::class).addMember("%S", "RedundantVisibilityModifier").build()) + .addType(TableClassGenerator.generate(table, environment)) + .addProperty(EntitySequencePropertyGenerator.generate(table)) + + if (table.entityClass.classKind == ClassKind.INTERFACE) { + fileSpec.addFunction(PseudoConstructorFunctionGenerator.generate(table)) + fileSpec.addFunction(CopyFunctionGenerator.generate(table)) + + for (func in ComponentFunctionGenerator.generate(table)) { + fileSpec.addFunction(func) + } + } else { + fileSpec.addFunction(AddFunctionGenerator.generate(table)) + + if (table.columns.any { it.isPrimaryKey }) { + fileSpec.addFunction(UpdateFunctionGenerator.generate(table)) + } + } + + for (generator in extCodeGenerators) { + val desc = "Code generated by ext generator: $generator" + + for (type in generator.generateTypes(table, environment)) { + fileSpec.addType( + type.toBuilder().addKdoc(if (type.kdoc.isEmpty()) desc else "\n\n$desc").build() + ) + } + + for (property in generator.generateProperties(table, environment)) { + fileSpec.addProperty( + property.toBuilder().addKdoc(if (property.kdoc.isEmpty()) desc else "\n\n$desc").build() + ) + } + + for (function in generator.generateFunctions(table, environment)) { + fileSpec.addFunction( + function.toBuilder().addKdoc(if (function.kdoc.isEmpty()) desc else "\n\n$desc").build() + ) + } + } + + return fileSpec.build() + } +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt new file mode 100644 index 000000000..94fb7b114 --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt @@ -0,0 +1,102 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.compiler.generator + +import com.google.devtools.ksp.isAbstract +import com.squareup.kotlinpoet.* +import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview +import com.squareup.kotlinpoet.ksp.toClassName +import com.squareup.kotlinpoet.ksp.toTypeName +import org.ktorm.entity.Entity +import org.ktorm.ksp.api.Undefined +import org.ktorm.ksp.compiler.util.* +import org.ktorm.ksp.spi.TableMetadata + +@OptIn(KotlinPoetKspPreview::class) +internal object PseudoConstructorFunctionGenerator { + + fun generate(table: TableMetadata): FunSpec { + return FunSpec.builder(table.entityClass.simpleName.asString()) + .addKdoc( + "Create an entity of [%L] and specify the initial values for each property, " + + "properties that doesn't have an initial value will leave unassigned. ", + table.entityClass.simpleName.asString() + ) + .addParameters(buildParameters(table).asIterable()) + .returns(table.entityClass.toClassName()) + .addCode(buildFunctionBody(table)) + .build() + } + + internal fun buildParameters(table: TableMetadata): Sequence { + return table.entityClass.getAllProperties() + .filter { it.isAbstract() } + .filterNot { it.simpleName.asString() in setOf("entityClass", "properties") } + .map { prop -> + val propName = prop.simpleName.asString() + val propType = prop.type.resolve().makeNullable().toTypeName() + + ParameterSpec.builder(propName, propType) + .defaultValue("%T.of()", Undefined::class.asClassName()) + .build() + } + } + + internal fun buildFunctionBody(table: TableMetadata, isCopy: Boolean = false): CodeBlock = buildCodeBlock { + if (isCopy) { + addStatement("val·entity·=·this.copy()") + } else { + addStatement("val·entity·=·%T.create<%T>()", Entity::class.asClassName(), table.entityClass.toClassName()) + } + + for (prop in table.entityClass.getAllProperties()) { + if (!prop.isAbstract() || prop.simpleName.asString() in setOf("entityClass", "properties")) { + continue + } + + val propName = prop.simpleName.asString() + val propType = prop.type.resolve() + if (propType.isInline()) { + beginControlFlow( + "if·((%N·as·Any?)·!==·(%T.of<%T>()·as·Any?))", + propName, Undefined::class.asClassName(), propType.makeNotNullable().toTypeName() + ) + } else { + beginControlFlow( + "if·(%N·!==·%T.of<%T>())", + propName, Undefined::class.asClassName(), propType.makeNotNullable().toTypeName() + ) + } + + var statement: String + if (prop.isMutable) { + statement = "entity.%1N·=·%1N" + } else { + statement = "entity[%1S]·=·%1N" + } + + if (!propType.isMarkedNullable) { + statement += "·?:·error(\"`%1L` should not be null.\")" + } + + addStatement(statement, propName) + endControlFlow() + } + + addStatement("return entity") + } +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt new file mode 100644 index 000000000..7cd7e6943 --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt @@ -0,0 +1,220 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.compiler.generator + +import com.google.devtools.ksp.processing.SymbolProcessorEnvironment +import com.google.devtools.ksp.symbol.ClassKind +import com.squareup.kotlinpoet.* +import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy +import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview +import com.squareup.kotlinpoet.ksp.toClassName +import org.ktorm.dsl.QueryRowSet +import org.ktorm.ksp.compiler.util.getKotlinType +import org.ktorm.ksp.compiler.util.getRegisteringCodeBlock +import org.ktorm.ksp.spi.TableMetadata +import org.ktorm.schema.BaseTable +import org.ktorm.schema.Column +import org.ktorm.schema.Table + +@OptIn(KotlinPoetKspPreview::class) +internal object TableClassGenerator { + + fun generate(table: TableMetadata, environment: SymbolProcessorEnvironment): TypeSpec { + return TypeSpec.classBuilder(table.tableClassName) + .addKdoc("Table %L. %L", table.name, table.entityClass.docString?.trimIndent().orEmpty()) + .addModifiers(KModifier.OPEN) + .primaryConstructor(FunSpec.constructorBuilder().addParameter("alias", typeNameOf()).build()) + .configureSuperClass(table) + .configureColumnProperties(table) + .configureDoCreateEntityFunction(table, environment.options) + .configureAliasedFunction(table) + .configureCompanionObject(table) + .build() + } + + private fun TypeSpec.Builder.configureSuperClass(table: TableMetadata): TypeSpec.Builder { + if (table.entityClass.classKind == ClassKind.INTERFACE) { + superclass(Table::class.asClassName().parameterizedBy(table.entityClass.toClassName())) + } else { + superclass(BaseTable::class.asClassName().parameterizedBy(table.entityClass.toClassName())) + } + + addSuperclassConstructorParameter("%S", table.name) + addSuperclassConstructorParameter("alias") + + if (table.catalog != null) { + addSuperclassConstructorParameter("catalog·=·%S", table.catalog!!) + } + + if (table.schema != null) { + addSuperclassConstructorParameter("schema·=·%S", table.schema!!) + } + + return this + } + + private fun TypeSpec.Builder.configureColumnProperties(table: TableMetadata): TypeSpec.Builder { + for (column in table.columns) { + val columnType = Column::class.asClassName().parameterizedBy(column.getKotlinType()) + val propertySpec = PropertySpec.builder(column.columnPropertyName, columnType) + .addKdoc("Column %L. %L", column.name, column.entityProperty.docString?.trimIndent().orEmpty()) + .initializer(buildCodeBlock { + add(column.getRegisteringCodeBlock()) + + if (column.isPrimaryKey) { + add(".primaryKey()") + } + + if (table.entityClass.classKind == ClassKind.INTERFACE) { + if (column.isReference) { + val pkg = column.referenceTable!!.entityClass.packageName.asString() + val name = column.referenceTable!!.tableClassName + val propName = column.entityProperty.simpleName.asString() + add(".references(%T)·{·it.%N·}", ClassName(pkg, name), propName) + } else { + add(".bindTo·{·it.%N·}", column.entityProperty.simpleName.asString()) + } + } + }) + .build() + + addProperty(propertySpec) + } + + return this + } + + private fun TypeSpec.Builder.configureDoCreateEntityFunction( + table: TableMetadata, options: Map + ): TypeSpec.Builder { + if (table.entityClass.classKind == ClassKind.INTERFACE) { + return this + } + + val func = FunSpec.builder("doCreateEntity") + .addKdoc("Create an entity object from the specific row of query results.") + .addModifiers(KModifier.OVERRIDE) + .addParameter("row", QueryRowSet::class.asTypeName()) + .addParameter("withReferences", Boolean::class.asTypeName()) + .returns(table.entityClass.toClassName()) + .addCode(buildCodeBlock { buildDoCreateEntityFunctionBody(table, options) }) + .build() + + addFunction(func) + return this + } + + private fun CodeBlock.Builder.buildDoCreateEntityFunctionBody(table: TableMetadata, options: Map) { + val constructorParams = table.entityClass.primaryConstructor!!.parameters.associateBy { it.name!!.asString() } + + val hasDefaultValues = table.columns + .mapNotNull { constructorParams[it.entityProperty.simpleName.asString()] } + .any { it.hasDefault } + + if (hasDefaultValues && options["ktorm.allowReflection"] == "true") { + addStatement( + "val constructor = %T::class.%M!!", + table.entityClass.toClassName(), + MemberName("kotlin.reflect.full", "primaryConstructor", true) + ) + + add("«val args = mapOf(") + + for (column in table.columns) { + val propName = column.entityProperty.simpleName.asString() + if (propName in constructorParams) { + add( + "constructor.%M(%S)!! to row[this.%N],", + MemberName("kotlin.reflect.full", "findParameterByName", true), + propName, + column.columnPropertyName + ) + } + } + + add(")\n»") + addStatement("// Filter optional arguments out to make default values work.") + + if (table.columns.all { it.entityProperty.simpleName.asString() in constructorParams }) { + addStatement("return constructor.callBy(args.filterNot { (k, v) -> k.isOptional && v == null })") + } else { + addStatement("val entity = constructor.callBy(args.filterNot { (k, v) -> k.isOptional && v == null })") + } + } else { + if (table.columns.all { it.entityProperty.simpleName.asString() in constructorParams }) { + add("«return·%T(", table.entityClass.toClassName()) + } else { + add("«val·entity·=·%T(", table.entityClass.toClassName()) + } + + for (column in table.columns) { + val parameter = constructorParams[column.entityProperty.simpleName.asString()] ?: continue + if (parameter.type.resolve().isMarkedNullable) { + add("%N·=·row[this.%N],", parameter.name!!.asString(), column.columnPropertyName) + } else { + add("%N·=·row[this.%N]!!,", parameter.name!!.asString(), column.columnPropertyName) + } + } + + add(")\n»") + } + + for (column in table.columns) { + val propName = column.entityProperty.simpleName.asString() + if (propName in constructorParams) { + continue + } + + if (column.entityProperty.type.resolve().isMarkedNullable) { + addStatement("entity.%N·=·row[this.%N]", propName, column.columnPropertyName) + } else { + addStatement("entity.%N·=·row[this.%N]!!", propName, column.columnPropertyName) + } + } + + if (table.columns.any { it.entityProperty.simpleName.asString() !in constructorParams }) { + addStatement("return·entity") + } + } + + private fun TypeSpec.Builder.configureAliasedFunction(table: TableMetadata): TypeSpec.Builder { + val func = FunSpec.builder("aliased") + .addKdoc( + "Return a new-created table object with all properties (including the table name and columns " + + "and so on) being copied from this table, but applying a new alias given by the parameter." + ) + .addModifiers(KModifier.OVERRIDE) + .addParameter("alias", typeNameOf()) + .returns(ClassName(table.entityClass.packageName.asString(), table.tableClassName)) + .addCode("return %L(alias)", table.tableClassName) + .build() + + addFunction(func) + return this + } + + private fun TypeSpec.Builder.configureCompanionObject(table: TableMetadata): TypeSpec.Builder { + val companion = TypeSpec.companionObjectBuilder(null) + .addKdoc("The default table object of %L.", table.name) + .superclass(ClassName(table.entityClass.packageName.asString(), table.tableClassName)) + .addSuperclassConstructorParameter(CodeBlock.of("alias·=·%S", table.alias)) + .build() + + addType(companion) + return this + } +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt new file mode 100644 index 000000000..3bc1e0bf0 --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt @@ -0,0 +1,126 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.compiler.generator + +import com.squareup.kotlinpoet.* +import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy +import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview +import com.squareup.kotlinpoet.ksp.toClassName +import org.ktorm.dsl.AliasRemover +import org.ktorm.entity.EntitySequence +import org.ktorm.expression.ColumnAssignmentExpression +import org.ktorm.expression.UpdateExpression +import org.ktorm.ksp.compiler.util.* +import org.ktorm.ksp.spi.TableMetadata + +@OptIn(KotlinPoetKspPreview::class) +internal object UpdateFunctionGenerator { + + fun generate(table: TableMetadata): FunSpec { + val kdoc = "" + + "Update the given entity to the database and return the affected record number. " + + "If [isDynamic] is set to true, the generated SQL will include only the non-null columns. " + + val entityClass = table.entityClass.toClassName() + val tableClass = ClassName(table.entityClass.packageName.asString(), table.tableClassName) + + return FunSpec.builder("update") + .addKdoc(kdoc) + .receiver(EntitySequence::class.asClassName().parameterizedBy(entityClass, tableClass)) + .addParameter("entity", entityClass) + .addParameter(ParameterSpec.builder("isDynamic", typeNameOf()).defaultValue("false").build()) + .returns(Int::class.asClassName()) + .addCode(AddFunctionGenerator.checkForDml()) + .addCode(AddFunctionGenerator.addValFun()) + .addCode(addAssignments(table)) + .addCode(buildConditions(table)) + .addCode(createExpression()) + .addStatement("return database.executeUpdate(expression)") + .build() + } + + private fun addAssignments(table: TableMetadata): CodeBlock { + return buildCodeBlock { + addStatement("val assignments = ArrayList<%T<*>>()", ColumnAssignmentExpression::class.asClassName()) + + for (column in table.columns) { + if (column.isPrimaryKey) { + continue + } + + addStatement( + "assignments.addVal(sourceTable.%N, entity.%N, isDynamic)", + column.columnPropertyName, + column.entityProperty.simpleName.asString(), + ) + } + + add("\n") + + beginControlFlow("if (assignments.isEmpty())") + addStatement("return 0") + endControlFlow() + + add("\n") + } + } + + private fun buildConditions(table: TableMetadata): CodeBlock { + return buildCodeBlock { + add("«val conditions = listOf(") + + for (column in table.columns) { + if (!column.isPrimaryKey) { + continue + } + + val condition: String + if (column.entityProperty.type.resolve().isMarkedNullable) { + condition = "sourceTable.%N·%M·entity.%N!!," + } else { + condition = "sourceTable.%N·%M·entity.%N," + } + + add( + condition, + column.columnPropertyName, + MemberName("org.ktorm.dsl", "eq", true), + column.entityProperty.simpleName.asString() + ) + } + + add(")\n»") + } + } + + private fun createExpression(): CodeBlock { + val code = """ + val expression = database.dialect.createExpressionVisitor(%T).visit( + %T(sourceTable.asExpression(), assignments, conditions.%M().asExpression()) + ) + + + """.trimIndent() + + return CodeBlock.of( + code, + AliasRemover::class.asClassName(), + UpdateExpression::class.asClassName(), + MemberName("org.ktorm.dsl", "combineConditions", true) + ) + } +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt new file mode 100644 index 000000000..d00262e3d --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -0,0 +1,292 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.compiler.parser + +import com.google.devtools.ksp.KspExperimental +import com.google.devtools.ksp.getAnnotationsByType +import com.google.devtools.ksp.isAbstract +import com.google.devtools.ksp.isAnnotationPresent +import com.google.devtools.ksp.processing.Resolver +import com.google.devtools.ksp.processing.SymbolProcessorEnvironment +import com.google.devtools.ksp.symbol.* +import com.google.devtools.ksp.symbol.ClassKind.* +import org.ktorm.entity.Entity +import org.ktorm.ksp.api.* +import org.ktorm.ksp.compiler.util.* +import org.ktorm.ksp.spi.CodingNamingStrategy +import org.ktorm.ksp.spi.ColumnMetadata +import org.ktorm.ksp.spi.DatabaseNamingStrategy +import org.ktorm.ksp.spi.TableMetadata +import org.ktorm.schema.SqlType +import java.lang.reflect.InvocationTargetException +import java.util.LinkedList +import kotlin.reflect.jvm.jvmName + +@OptIn(KspExperimental::class) +internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessorEnvironment) { + private val resolver = _resolver + private val options = _environment.options + private val databaseNamingStrategy = loadDatabaseNamingStrategy() + private val codingNamingStrategy = loadCodingNamingStrategy() + private val tablesCache = HashMap() + + private fun loadDatabaseNamingStrategy(): DatabaseNamingStrategy { + val name = options["ktorm.dbNamingStrategy"] ?: "lower-snake-case" + if (name == "lower-snake-case") { + return LowerSnakeCaseDatabaseNamingStrategy + } + if (name == "upper-snake-case") { + return UpperSnakeCaseDatabaseNamingStrategy + } + + try { + val cls = Class.forName(name) + return (cls.kotlin.objectInstance ?: cls.getDeclaredConstructor().newInstance()) as DatabaseNamingStrategy + } catch (e: InvocationTargetException) { + throw e.targetException + } + } + + private fun loadCodingNamingStrategy(): CodingNamingStrategy { + val name = options["ktorm.codingNamingStrategy"] ?: return DefaultCodingNamingStrategy + + try { + val cls = Class.forName(name) + return (cls.kotlin.objectInstance ?: cls.getDeclaredConstructor().newInstance()) as CodingNamingStrategy + } catch (e: InvocationTargetException) { + throw e.targetException + } + } + + fun parseTableMetadata(cls: KSClassDeclaration): TableMetadata { + val r = tablesCache[cls.qualifiedName!!.asString()] + if (r != null) { + return r + } + + if (cls.classKind != CLASS && cls.classKind != INTERFACE) { + val name = cls.qualifiedName!!.asString() + throw IllegalStateException("$name is expected to be a class or interface but actually ${cls.classKind}.") + } + + if (cls.classKind == INTERFACE && !cls.isSubclassOf>()) { + val name = cls.qualifiedName!!.asString() + throw IllegalStateException("$name must extends from org.ktorm.entity.Entity.") + } + + val table = cls.getAnnotationsByType(Table::class).first() + val tableDef = TableMetadata( + entityClass = cls, + name = table.name.ifEmpty { databaseNamingStrategy.getTableName(cls) }, + alias = table.alias.takeIf { it.isNotEmpty() }, + catalog = table.catalog.ifEmpty { options["ktorm.catalog"] }?.takeIf { it.isNotEmpty() }, + schema = table.schema.ifEmpty { options["ktorm.schema"] }?.takeIf { it.isNotEmpty() }, + tableClassName = table.className.ifEmpty { codingNamingStrategy.getTableClassName(cls) }, + entitySequenceName = table.entitySequenceName.ifEmpty { codingNamingStrategy.getEntitySequenceName(cls) }, + ignoreProperties = table.ignoreProperties.toSet(), + columns = ArrayList() + ) + + for (property in cls.getProperties(tableDef.ignoreProperties)) { + if (property.isAnnotationPresent(References::class)) { + (tableDef.columns as MutableList) += parseRefColumnMetadata(property, tableDef) + } else { + (tableDef.columns as MutableList) += parseColumnMetadata(property, tableDef) + } + } + + tablesCache[cls.qualifiedName!!.asString()] = tableDef + return tableDef + } + + private fun KSClassDeclaration.getProperties(ignoreProperties: Set): Sequence { + val constructorParams = HashSet() + if (classKind == CLASS) { + primaryConstructor?.parameters?.mapTo(constructorParams) { it.name!!.asString() } + } + + return this.getAllProperties() + .filterNot { it.simpleName.asString() in ignoreProperties } + .filterNot { it.isAnnotationPresent(Ignore::class) } + .filterNot { classKind == CLASS && !it.hasBackingField } + .filterNot { classKind == INTERFACE && !it.isAbstract() } + .filterNot { classKind == INTERFACE && it.simpleName.asString() in setOf("entityClass", "properties") } + .sortedByDescending { it.simpleName.asString() in constructorParams } + } + + private fun parseColumnMetadata(property: KSPropertyDeclaration, table: TableMetadata): ColumnMetadata { + val column = property.getAnnotationsByType(Column::class).firstOrNull() + + var name = column?.name + if (name.isNullOrEmpty()) { + name = databaseNamingStrategy.getColumnName(table.entityClass, property) + } + + var propertyName = column?.propertyName + if (propertyName.isNullOrEmpty()) { + propertyName = codingNamingStrategy.getColumnPropertyName(table.entityClass, property) + } + + return ColumnMetadata( + entityProperty = property, + table = table, + name = name, + isPrimaryKey = property.isAnnotationPresent(PrimaryKey::class), + sqlType = parseColumnSqlType(property), + isReference = false, + referenceTable = null, + columnPropertyName = propertyName + ) + } + + private fun parseColumnSqlType(property: KSPropertyDeclaration): KSType { + val annotation = property.annotations.find { anno -> + val annoType = anno.annotationType.resolve() + annoType.declaration.qualifiedName?.asString() == Column::class.jvmName + } + + val argument = annotation?.arguments?.find { it.name?.asString() == Column::sqlType.name } + + var sqlType = argument?.value as KSType? + if (sqlType?.declaration?.qualifiedName?.asString() == Nothing::class.jvmName) { + sqlType = null + } + + if (sqlType == null) { + sqlType = property.getSqlType(resolver) + } + + if (sqlType == null) { + val name = property.qualifiedName?.asString() + throw IllegalArgumentException( + "Parse sqlType error for property $name: cannot infer sqlType, please specify manually." + ) + } + + val declaration = sqlType.declaration as KSClassDeclaration + if (declaration.classKind != OBJECT) { + val name = property.qualifiedName?.asString() + throw IllegalArgumentException( + "Parse sqlType error for property $name: the sqlType class must be a Kotlin singleton object." + ) + } + + if (!declaration.isSubclassOf>() && !declaration.isSubclassOf()) { + val name = property.qualifiedName?.asString() + throw IllegalArgumentException( + "Parse sqlType error for property $name: the sqlType class must be subtype of SqlType/SqlTypeFactory." + ) + } + + return sqlType + } + + private fun parseRefColumnMetadata(property: KSPropertyDeclaration, table: TableMetadata): ColumnMetadata { + if (property.isAnnotationPresent(Column::class)) { + val n = property.qualifiedName?.asString() + throw IllegalStateException( + "Parse ref column error for property $n: @Column and @References cannot be used together." + ) + } + + if (table.entityClass.classKind != INTERFACE) { + val n = property.qualifiedName?.asString() + throw IllegalStateException( + "Parse ref column error for property $n: @References can only be used in interface-based entities." + ) + } + + val refEntityClass = property.type.resolve().declaration as KSClassDeclaration + table.checkCircularRef(refEntityClass) + + if (refEntityClass.classKind != INTERFACE) { + val n = property.qualifiedName?.asString() + throw IllegalStateException( + "Parse ref column error for property $n: the referenced entity class must be an interface." + ) + } + + if (!refEntityClass.isAnnotationPresent(Table::class)) { + val n = property.qualifiedName?.asString() + throw IllegalStateException( + "Parse ref column error for property $n: the referenced entity class must be annotated with @Table." + ) + } + + val referenceTable = parseTableMetadata(refEntityClass) + val primaryKeys = referenceTable.columns.filter { it.isPrimaryKey } + if (primaryKeys.isEmpty()) { + val n = property.qualifiedName?.asString() + throw IllegalStateException( + "Parse ref column error for property $n: the referenced table doesn't have a primary key." + ) + } + + if (primaryKeys.size > 1) { + val n = property.qualifiedName?.asString() + throw IllegalStateException( + "Parse ref column error for property $n: the referenced table cannot have compound primary keys." + ) + } + + val reference = property.getAnnotationsByType(References::class).first() + var name = reference.name + if (name.isEmpty()) { + name = databaseNamingStrategy.getRefColumnName(table.entityClass, property, referenceTable) + } + + var propertyName = reference.propertyName + if (propertyName.isEmpty()) { + propertyName = codingNamingStrategy.getRefColumnPropertyName(table.entityClass, property, referenceTable) + } + + return ColumnMetadata( + entityProperty = property, + table = table, + name = name, + isPrimaryKey = property.isAnnotationPresent(PrimaryKey::class), + sqlType = primaryKeys[0].sqlType, + isReference = true, + referenceTable = referenceTable, + columnPropertyName = propertyName + ) + } + + private fun TableMetadata.checkCircularRef(ref: KSClassDeclaration, stack: LinkedList = LinkedList()) { + val className = this.entityClass.qualifiedName?.asString() + val refClassName = ref.qualifiedName?.asString() + + stack.push(refClassName) + + if (className == refClassName) { + val route = stack.asReversed().joinToString(separator = " --> ") + throw IllegalStateException( + "Circular reference is not allowed, current table: $className, reference route: $route." + ) + } + + val refTable = ref.getAnnotationsByType(Table::class).firstOrNull() + for (property in ref.getProperties(refTable?.ignoreProperties?.toSet() ?: emptySet())) { + if (property.isAnnotationPresent(References::class)) { + val propType = property.type.resolve().declaration as KSClassDeclaration + checkCircularRef(propType, stack) + } + } + + stack.pop() + } +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt new file mode 100644 index 000000000..e2bc9054f --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt @@ -0,0 +1,102 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.compiler.util + +import com.google.devtools.ksp.KspExperimental +import com.google.devtools.ksp.isAnnotationPresent +import com.google.devtools.ksp.symbol.* +import com.google.devtools.ksp.visitor.KSValidateVisitor +import kotlin.reflect.jvm.jvmName + +/** + * Check if the given symbol is valid. + */ +internal fun KSNode.isValid(): Boolean { + // Custom visitor to avoid stack overflow, see https://github.com/google/ksp/issues/1114 + val visitor = object : KSValidateVisitor({ _, _ -> true }) { + private val stack = LinkedHashSet() + + private fun validateType(type: KSType): Boolean { + if (!stack.add(type)) { + // Skip if the type already in the stack, avoid infinite recursion. + return true + } + + try { + return !type.isError && !type.arguments.any { it.type?.accept(this, null) == false } + } finally { + stack.remove(type) + } + } + + override fun visitTypeReference(typeReference: KSTypeReference, data: KSNode?): Boolean { + return validateType(typeReference.resolve()) + } + + override fun visitValueArgument(valueArgument: KSValueArgument, data: KSNode?): Boolean { + fun visitValue(value: Any?): Boolean = when (value) { + is KSType -> this.validateType(value) + is KSAnnotation -> this.visitAnnotation(value, data) + is List<*> -> value.all { visitValue(it) } + else -> true + } + + return visitValue(valueArgument.value) + } + } + + return this.accept(visitor, null) +} + +/** + * Check if this class is a subclass of [T]. + */ +internal inline fun KSClassDeclaration.isSubclassOf(): Boolean { + return findSuperTypeReference(T::class.jvmName) != null +} + +/** + * Find the specific super type reference for this class. + */ +internal fun KSClassDeclaration.findSuperTypeReference(name: String): KSTypeReference? { + for (superType in this.superTypes) { + val ksType = superType.resolve() + val declaration = ksType.declaration + + if (declaration is KSClassDeclaration && declaration.qualifiedName?.asString() == name) { + return superType + } + + if (declaration is KSClassDeclaration) { + val result = declaration.findSuperTypeReference(name) + if (result != null) { + return result + } + } + } + + return null +} + +/** + * Check if this type is an inline class. + */ +@OptIn(KspExperimental::class) +internal fun KSType.isInline(): Boolean { + val declaration = declaration as KSClassDeclaration + return declaration.isAnnotationPresent(JvmInline::class) && declaration.modifiers.contains(Modifier.VALUE) +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt new file mode 100644 index 000000000..1183071ec --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.compiler.util + +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSPropertyDeclaration +import org.atteo.evo.inflector.English +import org.ktorm.ksp.spi.CodingNamingStrategy +import org.ktorm.ksp.spi.DatabaseNamingStrategy +import org.ktorm.ksp.spi.TableMetadata + +internal object LowerSnakeCaseDatabaseNamingStrategy : DatabaseNamingStrategy { + + override fun getTableName(c: KSClassDeclaration): String { + return CamelCase.toLowerSnakeCase(c.simpleName.asString()) + } + + override fun getColumnName(c: KSClassDeclaration, prop: KSPropertyDeclaration): String { + return CamelCase.toLowerSnakeCase(prop.simpleName.asString()) + } + + override fun getRefColumnName(c: KSClassDeclaration, prop: KSPropertyDeclaration, ref: TableMetadata): String { + val pk = ref.columns.single { it.isPrimaryKey } + return CamelCase.toLowerSnakeCase(prop.simpleName.asString()) + "_" + pk.name + } +} + +internal object UpperSnakeCaseDatabaseNamingStrategy : DatabaseNamingStrategy { + + override fun getTableName(c: KSClassDeclaration): String { + return CamelCase.toUpperSnakeCase(c.simpleName.asString()) + } + + override fun getColumnName(c: KSClassDeclaration, prop: KSPropertyDeclaration): String { + return CamelCase.toUpperSnakeCase(prop.simpleName.asString()) + } + + override fun getRefColumnName(c: KSClassDeclaration, prop: KSPropertyDeclaration, ref: TableMetadata): String { + val pk = ref.columns.single { it.isPrimaryKey } + return CamelCase.toUpperSnakeCase(prop.simpleName.asString()) + "_" + pk.name + } +} + +internal object DefaultCodingNamingStrategy : CodingNamingStrategy { + + override fun getTableClassName(c: KSClassDeclaration): String { + return English.plural(c.simpleName.asString()) + } + + override fun getEntitySequenceName(c: KSClassDeclaration): String { + return CamelCase.toFirstLowerCamelCase(English.plural(c.simpleName.asString())) + } + + override fun getColumnPropertyName(c: KSClassDeclaration, prop: KSPropertyDeclaration): String { + return prop.simpleName.asString() + } + + override fun getRefColumnPropertyName( + c: KSClassDeclaration, prop: KSPropertyDeclaration, ref: TableMetadata + ): String { + val pk = ref.columns.single { it.isPrimaryKey } + return prop.simpleName.asString() + pk.columnPropertyName.replaceFirstChar { it.uppercase() } + } +} + +object CamelCase { + // Matches boundaries between words, for example (abc|Def), (ABC|Def) + private val boundaries = listOf(Regex("([a-z])([A-Z])"), Regex("([A-Z])([A-Z][a-z])")) + + fun toLowerSnakeCase(name: String): String { + return boundaries.fold(name) { s, regex -> s.replace(regex, "$1_$2") }.lowercase() + } + + fun toUpperSnakeCase(name: String): String { + return boundaries.fold(name) { s, regex -> s.replace(regex, "$1_$2") }.uppercase() + } + + fun toFirstLowerCamelCase(name: String): String { + val i = boundaries.mapNotNull { regex -> regex.find(name) }.minOfOrNull { it.range.first } ?: 0 + return name.substring(0, i + 1).lowercase() + name.substring(i + 1) + } +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt new file mode 100644 index 000000000..f6f454276 --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt @@ -0,0 +1,135 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.compiler.util + +import com.google.devtools.ksp.getClassDeclarationByName +import com.google.devtools.ksp.processing.Resolver +import com.google.devtools.ksp.symbol.ClassKind +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSPropertyDeclaration +import com.google.devtools.ksp.symbol.KSType +import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.MemberName +import com.squareup.kotlinpoet.TypeName +import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview +import com.squareup.kotlinpoet.ksp.toClassName +import com.squareup.kotlinpoet.ksp.toTypeName +import org.ktorm.ksp.api.EnumSqlTypeFactory +import org.ktorm.ksp.api.SqlTypeFactory +import org.ktorm.ksp.spi.ColumnMetadata +import org.ktorm.schema.* + +internal fun KSPropertyDeclaration.getSqlType(resolver: Resolver): KSType? { + val declaration = this.type.resolve().declaration as KSClassDeclaration + if (declaration.classKind == ClassKind.ENUM_CLASS) { + return resolver.getClassDeclarationByName()?.asType(emptyList()) + } + + val sqlType = when (declaration.qualifiedName?.asString()) { + "kotlin.Boolean" -> BooleanSqlType::class + "kotlin.Int" -> IntSqlType::class + "kotlin.Short" -> ShortSqlType::class + "kotlin.Long" -> LongSqlType::class + "kotlin.Float" -> FloatSqlType::class + "kotlin.Double" -> DoubleSqlType::class + "kotlin.String" -> VarcharSqlType::class + "kotlin.ByteArray" -> BytesSqlType::class + "java.math.BigDecimal" -> DecimalSqlType::class + "java.sql.Timestamp" -> TimestampSqlType::class + "java.sql.Date" -> DateSqlType::class + "java.sql.Time" -> TimeSqlType::class + "java.time.Instant" -> InstantSqlType::class + "java.time.LocalDateTime" -> LocalDateTimeSqlType::class + "java.time.LocalDate" -> LocalDateSqlType::class + "java.time.LocalTime" -> LocalTimeSqlType::class + "java.time.MonthDay" -> MonthDaySqlType::class + "java.time.YearMonth" -> YearMonthSqlType::class + "java.time.Year" -> YearSqlType::class + "java.util.UUID" -> UuidSqlType::class + else -> null + } + + return sqlType?.qualifiedName?.let { resolver.getClassDeclarationByName(it)?.asType(emptyList()) } +} + +@OptIn(KotlinPoetKspPreview::class) +internal fun ColumnMetadata.getRegisteringCodeBlock(): CodeBlock { + val sqlTypeName = sqlType.declaration.qualifiedName?.asString() + val registerFun = when (sqlTypeName) { + "org.ktorm.schema.BooleanSqlType" -> MemberName("org.ktorm.schema", "boolean", true) + "org.ktorm.schema.IntSqlType" -> MemberName("org.ktorm.schema", "int", true) + "org.ktorm.schema.ShortSqlType" -> MemberName("org.ktorm.schema", "short", true) + "org.ktorm.schema.LongSqlType" -> MemberName("org.ktorm.schema", "long", true) + "org.ktorm.schema.FloatSqlType" -> MemberName("org.ktorm.schema", "float", true) + "org.ktorm.schema.DoubleSqlType" -> MemberName("org.ktorm.schema", "double", true) + "org.ktorm.schema.DecimalSqlType" -> MemberName("org.ktorm.schema", "decimal", true) + "org.ktorm.schema.VarcharSqlType" -> MemberName("org.ktorm.schema", "varchar", true) + "org.ktorm.schema.TextSqlType" -> MemberName("org.ktorm.schema", "text", true) + "org.ktorm.schema.BlobSqlType" -> MemberName("org.ktorm.schema", "blob", true) + "org.ktorm.schema.BytesSqlType" -> MemberName("org.ktorm.schema", "bytes", true) + "org.ktorm.schema.TimestampSqlType" -> MemberName("org.ktorm.schema", "jdbcTimestamp", true) + "org.ktorm.schema.DateSqlType" -> MemberName("org.ktorm.schema", "jdbcDate", true) + "org.ktorm.schema.TimeSqlType" -> MemberName("org.ktorm.schema", "jdbcTime", true) + "org.ktorm.schema.InstantSqlType" -> MemberName("org.ktorm.schema", "timestamp", true) + "org.ktorm.schema.LocalDateTimeSqlType" -> MemberName("org.ktorm.schema", "datetime", true) + "org.ktorm.schema.LocalDateSqlType" -> MemberName("org.ktorm.schema", "date", true) + "org.ktorm.schema.LocalTimeSqlType" -> MemberName("org.ktorm.schema", "time", true) + "org.ktorm.schema.MonthDaySqlType" -> MemberName("org.ktorm.schema", "monthDay", true) + "org.ktorm.schema.YearMonthSqlType" -> MemberName("org.ktorm.schema", "yearMonth", true) + "org.ktorm.schema.YearSqlType" -> MemberName("org.ktorm.schema", "year", true) + "org.ktorm.schema.UuidSqlType" -> MemberName("org.ktorm.schema", "uuid", true) + else -> null + } + + if (registerFun != null) { + return CodeBlock.of("%M(%S)", registerFun, name) + } + + if (sqlTypeName == "org.ktorm.ksp.api.EnumSqlTypeFactory") { + return CodeBlock.of("%M<%T>(%S)", MemberName("org.ktorm.schema", "enum", true), getKotlinType(), name) + } + + if (sqlTypeName == "org.ktorm.ksp.api.JsonSqlTypeFactory") { + return CodeBlock.of("%M<%T>(%S)", MemberName("org.ktorm.jackson", "json", true), getKotlinType(), name) + } + + val declaration = sqlType.declaration as KSClassDeclaration + if (declaration.isSubclassOf>()) { + return CodeBlock.of("registerColumn(%S,·%T)", name, sqlType.toTypeName()) + } + + if (declaration.isSubclassOf()) { + return CodeBlock.of( + "registerColumn(%S,·%T.createSqlType(%T::%N))", + name, + sqlType.toTypeName(), + table.entityClass.toClassName(), + entityProperty.simpleName.asString() + ) + } + + throw IllegalArgumentException("The sqlType class $sqlTypeName must be subtype of SqlType or SqlTypeFactory.") +} + +@OptIn(KotlinPoetKspPreview::class) +internal fun ColumnMetadata.getKotlinType(): TypeName { + if (isReference) { + return referenceTable!!.columns.single { it.isPrimaryKey }.getKotlinType() + } else { + return entityProperty.type.resolve().makeNotNullable().toTypeName() + } +} diff --git a/ktorm-ksp-compiler/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/ktorm-ksp-compiler/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider new file mode 100644 index 000000000..091bb5f70 --- /dev/null +++ b/ktorm-ksp-compiler/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider @@ -0,0 +1 @@ +org.ktorm.ksp.compiler.KtormProcessorProvider From d6f98aa070e89a5a9c0256c4653330a098ad08c8 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 2 Jul 2023 16:46:46 +0800 Subject: [PATCH 016/105] fix compile error --- .../compiler/generator/PseudoConstructorFunctionGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt index 94fb7b114..840f25ea0 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt @@ -22,7 +22,7 @@ import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview import com.squareup.kotlinpoet.ksp.toClassName import com.squareup.kotlinpoet.ksp.toTypeName import org.ktorm.entity.Entity -import org.ktorm.ksp.api.Undefined +import org.ktorm.ksp.annotation.Undefined import org.ktorm.ksp.compiler.util.* import org.ktorm.ksp.spi.TableMetadata From 2048c93943d9f72905a2715deff13f4cdc89e98f Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 2 Jul 2023 20:15:56 +0800 Subject: [PATCH 017/105] fix compile error --- .../ksp/compiler/parser/MetadataParser.kt | 56 ++++++++++--------- .../ktorm/ksp/compiler/util/KspExtensions.kt | 7 +++ .../ksp/compiler/util/SqlTypeMappings.kt | 4 +- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index d00262e3d..e1f94b8e7 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -16,24 +16,21 @@ package org.ktorm.ksp.compiler.parser -import com.google.devtools.ksp.KspExperimental -import com.google.devtools.ksp.getAnnotationsByType -import com.google.devtools.ksp.isAbstract -import com.google.devtools.ksp.isAnnotationPresent +import com.google.devtools.ksp.* import com.google.devtools.ksp.processing.Resolver import com.google.devtools.ksp.processing.SymbolProcessorEnvironment import com.google.devtools.ksp.symbol.* import com.google.devtools.ksp.symbol.ClassKind.* import org.ktorm.entity.Entity -import org.ktorm.ksp.api.* +import org.ktorm.ksp.annotation.* import org.ktorm.ksp.compiler.util.* import org.ktorm.ksp.spi.CodingNamingStrategy import org.ktorm.ksp.spi.ColumnMetadata import org.ktorm.ksp.spi.DatabaseNamingStrategy import org.ktorm.ksp.spi.TableMetadata -import org.ktorm.schema.SqlType +import org.ktorm.schema.TypeReference import java.lang.reflect.InvocationTargetException -import java.util.LinkedList +import java.util.* import kotlin.reflect.jvm.jvmName @OptIn(KspExperimental::class) @@ -154,15 +151,14 @@ internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessor } private fun parseColumnSqlType(property: KSPropertyDeclaration): KSType { - val annotation = property.annotations.find { anno -> - val annoType = anno.annotationType.resolve() - annoType.declaration.qualifiedName?.asString() == Column::class.jvmName - } - - val argument = annotation?.arguments?.find { it.name?.asString() == Column::sqlType.name } - - var sqlType = argument?.value as KSType? - if (sqlType?.declaration?.qualifiedName?.asString() == Nothing::class.jvmName) { + var sqlType = property.annotations + .filter { it.annotationType.resolve().getJvmName() == Column::class.jvmName } + .flatMap { it.arguments } + .filter { it.name?.asString() == Column::sqlType.name } + .map { it.value as KSType? } + .singleOrNull() + + if (sqlType?.getJvmName() == Nothing::class.jvmName) { sqlType = null } @@ -179,17 +175,25 @@ internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessor val declaration = sqlType.declaration as KSClassDeclaration if (declaration.classKind != OBJECT) { - val name = property.qualifiedName?.asString() - throw IllegalArgumentException( - "Parse sqlType error for property $name: the sqlType class must be a Kotlin singleton object." - ) - } + if (declaration.isAbstract()) { + val name = property.qualifiedName?.asString() + throw IllegalArgumentException( + "Parse sqlType error for property $name: the sqlType class cannot be abstract." + ) + } - if (!declaration.isSubclassOf>() && !declaration.isSubclassOf()) { - val name = property.qualifiedName?.asString() - throw IllegalArgumentException( - "Parse sqlType error for property $name: the sqlType class must be subtype of SqlType/SqlTypeFactory." - ) + val hasConstructor = declaration.getConstructors() + .filter { it.parameters.size == 1 } + .filter { it.parameters[0].type.resolve().getJvmName() == TypeReference::class.jvmName } + .any() + + if (!hasConstructor) { + val name = property.qualifiedName?.asString() + throw IllegalArgumentException( + "Parse sqlType error for property $name: the sqlType class must be a Kotlin singleton object or" + + "a normal class with a constructor that accepts a single org.ktorm.schema.TypeReference argument." + ) + } } return sqlType diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt index e2bc9054f..bfc0c8a7b 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt @@ -100,3 +100,10 @@ internal fun KSType.isInline(): Boolean { val declaration = declaration as KSClassDeclaration return declaration.isAnnotationPresent(JvmInline::class) && declaration.modifiers.contains(Modifier.VALUE) } + +/** + * Return the JVM class name of [this] type. + */ +internal fun KSType.getJvmName(): String? { + return declaration.qualifiedName?.asString() +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt index f6f454276..3fb3429db 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt @@ -28,15 +28,13 @@ import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview import com.squareup.kotlinpoet.ksp.toClassName import com.squareup.kotlinpoet.ksp.toTypeName -import org.ktorm.ksp.api.EnumSqlTypeFactory -import org.ktorm.ksp.api.SqlTypeFactory import org.ktorm.ksp.spi.ColumnMetadata import org.ktorm.schema.* internal fun KSPropertyDeclaration.getSqlType(resolver: Resolver): KSType? { val declaration = this.type.resolve().declaration as KSClassDeclaration if (declaration.classKind == ClassKind.ENUM_CLASS) { - return resolver.getClassDeclarationByName()?.asType(emptyList()) + return resolver.getClassDeclarationByName>()?.asType(emptyList()) } val sqlType = when (declaration.qualifiedName?.asString()) { From c30604dbd10bfe484d873d2bcb5840a0812ea035 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 2 Jul 2023 20:41:57 +0800 Subject: [PATCH 018/105] fix --- .../org/ktorm/ksp/compiler/util/KspExtensions.kt | 11 ++++------- .../org/ktorm/ksp/compiler/util/SqlTypeMappings.kt | 8 ++++---- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt index bfc0c8a7b..bad91180c 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt @@ -75,17 +75,14 @@ internal inline fun KSClassDeclaration.isSubclassOf(): Boolean internal fun KSClassDeclaration.findSuperTypeReference(name: String): KSTypeReference? { for (superType in this.superTypes) { val ksType = superType.resolve() - val declaration = ksType.declaration - if (declaration is KSClassDeclaration && declaration.qualifiedName?.asString() == name) { + if (ksType.getJvmName() == name) { return superType } - if (declaration is KSClassDeclaration) { - val result = declaration.findSuperTypeReference(name) - if (result != null) { - return result - } + val result = (ksType.declaration as KSClassDeclaration).findSuperTypeReference(name) + if (result != null) { + return result } } diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt index 3fb3429db..15185ef5a 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt @@ -32,12 +32,12 @@ import org.ktorm.ksp.spi.ColumnMetadata import org.ktorm.schema.* internal fun KSPropertyDeclaration.getSqlType(resolver: Resolver): KSType? { - val declaration = this.type.resolve().declaration as KSClassDeclaration - if (declaration.classKind == ClassKind.ENUM_CLASS) { + val propType = this.type.resolve() + if ((propType.declaration as KSClassDeclaration).classKind == ClassKind.ENUM_CLASS) { return resolver.getClassDeclarationByName>()?.asType(emptyList()) } - val sqlType = when (declaration.qualifiedName?.asString()) { + val sqlType = when (propType.getJvmName()) { "kotlin.Boolean" -> BooleanSqlType::class "kotlin.Int" -> IntSqlType::class "kotlin.Short" -> ShortSqlType::class @@ -66,7 +66,7 @@ internal fun KSPropertyDeclaration.getSqlType(resolver: Resolver): KSType? { @OptIn(KotlinPoetKspPreview::class) internal fun ColumnMetadata.getRegisteringCodeBlock(): CodeBlock { - val sqlTypeName = sqlType.declaration.qualifiedName?.asString() + val sqlTypeName = sqlType.getJvmName() val registerFun = when (sqlTypeName) { "org.ktorm.schema.BooleanSqlType" -> MemberName("org.ktorm.schema", "boolean", true) "org.ktorm.schema.IntSqlType" -> MemberName("org.ktorm.schema", "int", true) From 38d291138e62c7f45f18a329a5e458a527af6116 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 2 Jul 2023 21:36:09 +0800 Subject: [PATCH 019/105] fix compile error --- .../kotlin/org/ktorm/jackson/JsonSqlType.kt | 4 +++- .../ksp/compiler/KtormProcessorProvider.kt | 2 +- .../org/ktorm/ksp/compiler/util/Namings.kt | 2 +- .../ksp/compiler/util/SqlTypeMappings.kt | 22 +++++-------------- 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JsonSqlType.kt b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JsonSqlType.kt index 617e5f1ec..168cb61e3 100644 --- a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JsonSqlType.kt +++ b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JsonSqlType.kt @@ -58,9 +58,11 @@ public class JsonSqlType( public val objectMapper: ObjectMapper, public val javaType: JavaType ) : SqlType(Types.OTHER, "json") { + public constructor(typeRef: TypeReference) : this(sharedObjectMapper, typeRef) public constructor( + objectMapper: ObjectMapper, typeRef: TypeReference - ) : this(sharedObjectMapper, sharedObjectMapper.constructType(typeRef.referencedType)) + ) : this(objectMapper, objectMapper.constructType(typeRef.referencedType)) // Access postgresql API by reflection, because it is not a JDK 9 module, // we are not able to require it in module-info.java. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt index 789035fe9..2b4f665ef 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt @@ -23,7 +23,7 @@ import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSFile import com.squareup.kotlinpoet.FileSpec -import org.ktorm.ksp.api.Table +import org.ktorm.ksp.annotation.Table import org.ktorm.ksp.compiler.generator.FileGenerator import org.ktorm.ksp.compiler.parser.MetadataParser import org.ktorm.ksp.compiler.util.isValid diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt index 1183071ec..e0b715d93 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt @@ -77,7 +77,7 @@ internal object DefaultCodingNamingStrategy : CodingNamingStrategy { } } -object CamelCase { +internal object CamelCase { // Matches boundaries between words, for example (abc|Def), (ABC|Def) private val boundaries = listOf(Regex("([a-z])([A-Z])"), Regex("([A-Z])([A-Z][a-z])")) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt index 15185ef5a..8f304fc4b 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt @@ -26,7 +26,6 @@ import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.MemberName import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview -import com.squareup.kotlinpoet.ksp.toClassName import com.squareup.kotlinpoet.ksp.toTypeName import org.ktorm.ksp.spi.ColumnMetadata import org.ktorm.schema.* @@ -97,30 +96,21 @@ internal fun ColumnMetadata.getRegisteringCodeBlock(): CodeBlock { return CodeBlock.of("%M(%S)", registerFun, name) } - if (sqlTypeName == "org.ktorm.ksp.api.EnumSqlTypeFactory") { + if (sqlTypeName == "org.ktorm.schema.EnumSqlType") { return CodeBlock.of("%M<%T>(%S)", MemberName("org.ktorm.schema", "enum", true), getKotlinType(), name) } - if (sqlTypeName == "org.ktorm.ksp.api.JsonSqlTypeFactory") { + if (sqlTypeName == "org.ktorm.jackson.JsonSqlType") { return CodeBlock.of("%M<%T>(%S)", MemberName("org.ktorm.jackson", "json", true), getKotlinType(), name) } val declaration = sqlType.declaration as KSClassDeclaration - if (declaration.isSubclassOf>()) { + if (declaration.classKind == ClassKind.OBJECT) { + return CodeBlock.of("registerColumn(%S,·%T)", name, sqlType.toTypeName()) + } else { + // TODO: create SqlType by constructor return CodeBlock.of("registerColumn(%S,·%T)", name, sqlType.toTypeName()) } - - if (declaration.isSubclassOf()) { - return CodeBlock.of( - "registerColumn(%S,·%T.createSqlType(%T::%N))", - name, - sqlType.toTypeName(), - table.entityClass.toClassName(), - entityProperty.simpleName.asString() - ) - } - - throw IllegalArgumentException("The sqlType class $sqlTypeName must be subtype of SqlType or SqlTypeFactory.") } @OptIn(KotlinPoetKspPreview::class) From d1fe23dfe78963bd368614c156fa9ab3df32cdef Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 2 Jul 2023 22:35:44 +0800 Subject: [PATCH 020/105] migrate ksp compiler test code --- .../ktorm/jackson/JacksonAnnotationTest.kt | 15 - .../org/ktorm/ksp/annotation/UndefinedTest.kt | 16 - .../org/ktorm/ksp/compiler/BaseKspTest.kt | 122 ++++++++ .../generator/AddFunctionGeneratorTest.kt | 50 ++++ .../ComponentFunctionGeneratorTest.kt | 36 +++ .../generator/CopyFunctionGeneratorTest.kt | 37 +++ .../EntitySequencePropertyGeneratorTest.kt | 61 ++++ .../generator/ExtCodeGeneratorTest.kt | 43 +++ .../PseudoConstructorFunctionGeneratorTest.kt | 27 ++ .../generator/TableClassGeneratorTest.kt | 202 +++++++++++++ .../generator/UpdateFunctionGeneratorTest.kt | 49 +++ .../parser/CompoundPrimaryKeysTest.kt | 31 ++ .../parser/DatabaseNamingStrategyTest.kt | 132 ++++++++ .../ksp/compiler/parser/MetadataParserTest.kt | 283 ++++++++++++++++++ .../ktorm/ksp/compiler/parser/SqlTypeTest.kt | 152 ++++++++++ .../src/test/resources/drop-ksp-data.sql | 3 + .../src/test/resources/init-ksp-data.sql | 45 +++ .../org.ktorm.ksp.spi.ExtCodeGenerator | 1 + .../test/resources/simplelogger.properties | 6 + 19 files changed, 1280 insertions(+), 31 deletions(-) create mode 100644 ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/BaseKspTest.kt create mode 100644 ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGeneratorTest.kt create mode 100644 ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGeneratorTest.kt create mode 100644 ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGeneratorTest.kt create mode 100644 ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/EntitySequencePropertyGeneratorTest.kt create mode 100644 ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/ExtCodeGeneratorTest.kt create mode 100644 ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGeneratorTest.kt create mode 100644 ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/TableClassGeneratorTest.kt create mode 100644 ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGeneratorTest.kt create mode 100644 ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/CompoundPrimaryKeysTest.kt create mode 100644 ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/DatabaseNamingStrategyTest.kt create mode 100644 ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt create mode 100644 ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/SqlTypeTest.kt create mode 100644 ktorm-ksp-compiler/src/test/resources/drop-ksp-data.sql create mode 100644 ktorm-ksp-compiler/src/test/resources/init-ksp-data.sql create mode 100644 ktorm-ksp-compiler/src/test/resources/services/org.ktorm.ksp.spi.ExtCodeGenerator create mode 100644 ktorm-ksp-compiler/src/test/resources/simplelogger.properties diff --git a/ktorm-jackson/src/test/kotlin/org/ktorm/jackson/JacksonAnnotationTest.kt b/ktorm-jackson/src/test/kotlin/org/ktorm/jackson/JacksonAnnotationTest.kt index 7cd48d84b..66ebd5893 100644 --- a/ktorm-jackson/src/test/kotlin/org/ktorm/jackson/JacksonAnnotationTest.kt +++ b/ktorm-jackson/src/test/kotlin/org/ktorm/jackson/JacksonAnnotationTest.kt @@ -1,18 +1,3 @@ -/* - * Copyright 2018-2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ package org.ktorm.jackson import com.fasterxml.jackson.annotation.JsonAlias diff --git a/ktorm-ksp-annotations/src/test/kotlin/org/ktorm/ksp/annotation/UndefinedTest.kt b/ktorm-ksp-annotations/src/test/kotlin/org/ktorm/ksp/annotation/UndefinedTest.kt index aa8042bc8..e636c9fa5 100644 --- a/ktorm-ksp-annotations/src/test/kotlin/org/ktorm/ksp/annotation/UndefinedTest.kt +++ b/ktorm-ksp-annotations/src/test/kotlin/org/ktorm/ksp/annotation/UndefinedTest.kt @@ -1,19 +1,3 @@ -/* - * Copyright 2018-2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package org.ktorm.ksp.annotation import org.junit.Test diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/BaseKspTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/BaseKspTest.kt new file mode 100644 index 000000000..d8b7e7014 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/BaseKspTest.kt @@ -0,0 +1,122 @@ +package org.ktorm.ksp.compiler + +import com.tschuchort.compiletesting.* +import org.intellij.lang.annotations.Language +import org.junit.After +import org.junit.Before +import org.ktorm.database.Database +import org.ktorm.database.use +import java.lang.reflect.InvocationTargetException + +abstract class BaseKspTest { + lateinit var database: Database + + @Before + fun init() { + database = Database.connect("jdbc:h2:mem:ktorm;DB_CLOSE_DELAY=-1", alwaysQuoteIdentifiers = true) + execSqlScript("init-ksp-data.sql") + } + + @After + fun destroy() { + execSqlScript("drop-ksp-data.sql") + } + + private fun execSqlScript(filename: String) { + database.useConnection { conn -> + conn.createStatement().use { statement -> + javaClass.classLoader + ?.getResourceAsStream(filename) + ?.bufferedReader() + ?.use { reader -> + for (sql in reader.readText().split(';')) { + if (sql.any { it.isLetterOrDigit() }) { + statement.executeUpdate(sql) + } + } + } + } + } + } + + protected fun kspFailing(message: String, @Language("kotlin") code: String, vararg options: Pair) { + val result = compile(code, mapOf(*options)) + assert(result.exitCode == KotlinCompilation.ExitCode.OK) + assert(result.messages.contains("e: Error occurred in KSP, check log for detail")) + assert(result.messages.contains(message)) + } + + protected fun runKotlin(@Language("kotlin") code: String, vararg options: Pair) { + val result = compile(code, mapOf(*options)) + assert(result.exitCode == KotlinCompilation.ExitCode.OK) + + try { + val cls = result.classLoader.loadClass("SourceKt") + cls.getMethod("setDatabase", Database::class.java).invoke(null, database) + cls.getMethod("run").invoke(null) + } catch (e: InvocationTargetException) { + throw e.targetException + } + } + + private fun compile(@Language("kotlin") code: String, options: Map): KotlinCompilation.Result { + @Language("kotlin") + val header = """ + import java.math.* + import java.sql.* + import java.time.* + import java.util.* + import kotlin.reflect.* + import kotlin.reflect.jvm.* + import org.ktorm.database.* + import org.ktorm.dsl.* + import org.ktorm.entity.* + import org.ktorm.ksp.api.* + + lateinit var database: Database + + + """.trimIndent() + + val source = header + code + printFile(source, "Source.kt") + + val compilation = createCompilation(SourceFile.kotlin("Source.kt", source), options) + val result = compilation.compile() + + for (file in compilation.kspSourcesDir.walk()) { + if (file.isFile) { + printFile(file.readText(), "Generated file: ${file.absolutePath}") + } + } + + return result + } + + private fun createCompilation(source: SourceFile, options: Map): KotlinCompilation { + return KotlinCompilation().apply { + sources = listOf(source) + verbose = false + messageOutputStream = System.out + inheritClassPath = true + allWarningsAsErrors = true + symbolProcessorProviders = listOf(KtormProcessorProvider()) + kspIncremental = true + kspWithCompilation = true + kspArgs += options + } + } + + private fun printFile(text: String, title: String) { + val lines = text.lines() + val gutterSize = lines.size.toString().count() + + println("${"#".repeat(gutterSize + 2)}-----------------------------------------") + println("${"#".repeat(gutterSize + 2)} $title") + println("${"#".repeat(gutterSize + 2)}-----------------------------------------") + + for ((i, line) in lines.withIndex()) { + println(String.format("#%${gutterSize}d| %s", i + 1, line)) + } + } +} diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGeneratorTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGeneratorTest.kt new file mode 100644 index 000000000..d96205024 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGeneratorTest.kt @@ -0,0 +1,50 @@ +package org.ktorm.ksp.compiler.generator + +import org.junit.Test +import org.ktorm.ksp.compiler.BaseKspTest + +class AddFunctionGeneratorTest : BaseKspTest() { + + @Test + fun `sequence add function`() = runKotlin(""" + @Table + data class User( + @PrimaryKey + var id: Int?, + var username: String, + var age: Int, + ) + + fun run() { + database.users.add(User(null, "test", 100)) + + val users = database.users.toList() + assert(users.size == 4) + assert(users[0] == User(id = 1, username = "jack", age = 20)) + assert(users[1] == User(id = 2, username = "lucy", age = 22)) + assert(users[2] == User(id = 3, username = "mike", age = 22)) + assert(users[3] == User(id = 4, username = "test", age = 100)) + + } + """.trimIndent()) + + @Test + fun `modified entity sequence call add fun`() = runKotlin(""" + @Table + data class User( + @PrimaryKey + var id: Int?, + var username: String, + var age: Int + ) + + fun run() { + try { + val users = database.users.filter { it.id eq 1 } + users.add(User(null, "lucy", 10)) + throw AssertionError("fail") + } catch (_: UnsupportedOperationException) { + } + } + """.trimIndent()) +} diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGeneratorTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGeneratorTest.kt new file mode 100644 index 000000000..49167c089 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGeneratorTest.kt @@ -0,0 +1,36 @@ +package org.ktorm.ksp.compiler.generator + +import org.junit.Test +import org.ktorm.ksp.compiler.BaseKspTest + +class ComponentFunctionGeneratorTest : BaseKspTest() { + + @Test + fun `interface entity component function`() = runKotlin(""" + @Table + interface Employee: Entity { + @PrimaryKey + var id: Int? + var name: String + var job: String + @Ignore + var hireDate: LocalDate + } + + fun run() { + val today = LocalDate.now() + + val employee = Entity.create() + employee.id = 1 + employee.name = "name" + employee.job = "job" + employee.hireDate = today + + val (id, name, job, hireDate) = employee + assert(id == 1) + assert(name == "name") + assert(job == "job") + assert(hireDate == today) + } + """.trimIndent()) +} diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGeneratorTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGeneratorTest.kt new file mode 100644 index 000000000..35e1327d3 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGeneratorTest.kt @@ -0,0 +1,37 @@ +package org.ktorm.ksp.compiler.generator + +import org.junit.Test +import org.ktorm.ksp.compiler.BaseKspTest + +class CopyFunctionGeneratorTest : BaseKspTest() { + + @Test + fun `interface entity copy function`() = runKotlin(""" + @Table + interface Employee: Entity { + @PrimaryKey + var id: Int? + var name: String + var job: String + @Ignore + var hireDate: LocalDate + } + + fun run() { + val today = LocalDate.now() + + val jack = Employee(name = "jack", job = "programmer", hireDate = today) + val tom = jack.copy(name = "tom") + + assert(tom != jack) + assert(tom !== jack) + assert(tom.name == "tom") + assert(tom.job == "programmer") + assert(tom.hireDate == today) + + with(EntityExtensionsApi()) { + assert(!tom.hasColumnValue(Employees.id.binding!!)) + } + } + """.trimIndent()) +} diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/EntitySequencePropertyGeneratorTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/EntitySequencePropertyGeneratorTest.kt new file mode 100644 index 000000000..32ac1d561 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/EntitySequencePropertyGeneratorTest.kt @@ -0,0 +1,61 @@ +package org.ktorm.ksp.compiler.generator + +import org.junit.Test +import org.ktorm.ksp.compiler.BaseKspTest + +class EntitySequencePropertyGeneratorTest : BaseKspTest() { + + @Test + fun `sequenceOf function`() = runKotlin(""" + @Table + data class User( + @PrimaryKey + var id: Int, + var username: String, + var age: Int + ) + + @Table + interface Employee: Entity { + @PrimaryKey + var id: Int + var name: String + var job: String + var hireDate: LocalDate + } + + fun run() { + val users = database.users.toList() + assert(users.size == 3) + assert(users[0] == User(id = 1, username = "jack", age = 20)) + assert(users[1] == User(id = 2, username = "lucy", age = 22)) + assert(users[2] == User(id = 3, username = "mike", age = 22)) + + val employees = database.employees.toList() + assert(employees.size == 4) + assert(employees[0] == Employee(id = 1, name = "vince", job = "engineer", hireDate = LocalDate.of(2018, 1, 1))) + assert(employees[1] == Employee(id = 2, name = "marry", job = "trainee", hireDate = LocalDate.of(2019, 1, 1))) + assert(employees[2] == Employee(id = 3, name = "tom", job = "director", hireDate = LocalDate.of(2018, 1, 1))) + assert(employees[3] == Employee(id = 4, name = "penny", job = "assistant", hireDate = LocalDate.of(2019, 1, 1))) + } + """.trimIndent()) + + @Test + fun `custom sequence name`() = runKotlin(""" + @Table(entitySequenceName = "aUsers") + data class User( + @PrimaryKey + var id: Int, + var username: String, + var age: Int + ) + + fun run() { + val users = database.aUsers.toList() + assert(users.size == 3) + assert(users[0] == User(id = 1, username = "jack", age = 20)) + assert(users[1] == User(id = 2, username = "lucy", age = 22)) + assert(users[2] == User(id = 3, username = "mike", age = 22)) + } + """.trimIndent()) +} diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/ExtCodeGeneratorTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/ExtCodeGeneratorTest.kt new file mode 100644 index 000000000..1e750fc87 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/ExtCodeGeneratorTest.kt @@ -0,0 +1,43 @@ +package org.ktorm.ksp.compiler.generator + +import com.google.devtools.ksp.processing.SymbolProcessorEnvironment +import com.squareup.kotlinpoet.FunSpec +import com.squareup.kotlinpoet.PropertySpec +import com.squareup.kotlinpoet.TypeSpec +import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview +import com.squareup.kotlinpoet.ksp.toClassName +import com.squareup.kotlinpoet.typeNameOf +import org.ktorm.ksp.spi.ExtCodeGenerator +import org.ktorm.ksp.spi.TableMetadata + +/** + * Created by vince at May 27, 2023. + */ +@OptIn(KotlinPoetKspPreview::class) +class ExtCodeGeneratorTest : ExtCodeGenerator { + + override fun generateTypes(table: TableMetadata, environment: SymbolProcessorEnvironment): List { + return listOf(TypeSpec.classBuilder("TestFor" + table.tableClassName).build()) + } + + override fun generateProperties(table: TableMetadata, environment: SymbolProcessorEnvironment): List { + return listOf( + PropertySpec.builder("pTest", typeNameOf()) + .addKdoc("This is a test property.") + .receiver(table.entityClass.toClassName()) + .getter(FunSpec.getterBuilder().addStatement("return 0").build()) + .build() + ) + } + + override fun generateFunctions(table: TableMetadata, environment: SymbolProcessorEnvironment): List { + return listOf( + FunSpec.builder("fTest") + .addKdoc("This is a test function. \n\n @since 3.6.0") + .receiver(table.entityClass.toClassName()) + .returns(typeNameOf()) + .addStatement("return 0") + .build() + ) + } +} \ No newline at end of file diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGeneratorTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGeneratorTest.kt new file mode 100644 index 000000000..3a71cf7e1 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGeneratorTest.kt @@ -0,0 +1,27 @@ +package org.ktorm.ksp.compiler.generator + +import org.junit.Test +import org.ktorm.ksp.compiler.BaseKspTest + +class PseudoConstructorFunctionGeneratorTest : BaseKspTest() { + + @Test + fun `interface entity constructor function`() = runKotlin(""" + @Table + interface Employee: Entity { + @PrimaryKey + var id: Int? + var name: String + var job: String + @Ignore + var hireDate: LocalDate + } + + fun run() { + assert(Employee().toString() == "Employee()") + assert(Employee(id = null).toString() == "Employee(id=null)") + assert(Employee(id = null, name = "").toString() == "Employee(id=null, name=)") + assert(Employee(1, "vince", "engineer", LocalDate.of(2023, 1, 1)).toString() == "Employee(id=1, name=vince, job=engineer, hireDate=2023-01-01)") + } + """.trimIndent()) +} diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/TableClassGeneratorTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/TableClassGeneratorTest.kt new file mode 100644 index 000000000..0d21efa85 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/TableClassGeneratorTest.kt @@ -0,0 +1,202 @@ +package org.ktorm.ksp.compiler.generator + +import org.junit.Test +import org.ktorm.ksp.compiler.BaseKspTest + +class TableClassGeneratorTest : BaseKspTest() { + + @Test + fun `dataClass entity`() = runKotlin(""" + @Table + data class User( + @PrimaryKey + var id: Int? = null, + var username: String, + var age: Int = 0 + ) + + fun run() { + assert(Users.tableName == "user") + assert(Users.columns.map { it.name }.toSet() == setOf("id", "username", "age")) + } + """.trimIndent()) + + @Test + fun `data class keyword identifier`() = runKotlin(""" + @Table + data class User( + @PrimaryKey + var id: Int, + var `class`: String, + var operator: String, + ) { + var `interface`: String = "" + var constructor: String = "" + } + + fun run() { + assert(Users.tableName == "user") + assert(Users.columns.map { it.name }.toSet() == setOf("id", "class", "operator", "interface", "constructor")) + } + """.trimIndent()) + + @Test + fun `table annotation`() = runKotlin(""" + @Table( + name = "t_user", + alias = "t_user_alias", + catalog = "catalog", + schema = "schema", + className = "UserTable", + entitySequenceName = "userTable", + ignoreProperties = ["age"] + ) + data class User( + @PrimaryKey + var id: Int, + var username: String, + ) { + var age: Int = 10 + } + + fun run() { + assert(UserTable.tableName == "t_user") + assert(UserTable.alias == "t_user_alias") + assert(UserTable.catalog == "catalog") + assert(UserTable.schema == "schema") + assert(UserTable.columns.map { it.name }.toSet() == setOf("id", "username")) + println(database.userTable) + } + """.trimIndent()) + + @Test + fun `data class constructor with default parameters column`() = runKotlin(""" + @Table + data class User( + @PrimaryKey + var id: Int, + var username: String, + var phone: String? = "12345" + ) + + fun run() { + val user = database.users.first { it.id eq 1 } + assert(user.username == "jack") + assert(user.phone == null) + } + """.trimIndent()) + + @Test + fun `data class constructor with default parameters column allowing reflection`() = runKotlin(""" + @Table + data class User( + @PrimaryKey + var id: Int, + var username: String, + var phone: String? = "12345" + ) + + fun run() { + val user = database.users.first { it.id eq 1 } + assert(user.username == "jack") + assert(user.phone == "12345") + } + """.trimIndent(), "ktorm.allowReflection" to "true") + + @Test + fun `ignore properties`() = runKotlin(""" + @Table(ignoreProperties = ["email"]) + data class User( + @PrimaryKey + var id: Int, + var age: Int, + @Ignore + var username: String = "" + ) { + var email: String = "" + } + + fun run() { + assert(Users.tableName == "user") + assert(Users.columns.map { it.name }.toSet() == setOf("id", "age")) + } + """.trimIndent()) + + @Test + fun `column has no backingField`() = runKotlin(""" + @Table + data class User( + @PrimaryKey + var id: Int, + var age: Int + ) { + val username: String get() = "username" + } + + fun run() { + assert(Users.tableName == "user") + assert(Users.columns.map { it.name }.toSet() == setOf("id", "age")) + } + """.trimIndent()) + + @Test + fun `column reference`() = runKotlin(""" + @Table + interface User: Entity { + @PrimaryKey + var id: Int + var username: String + var age: Int + @References + var firstSchool: School + @References("second_school_identity") + var secondSchool: School + } + + @Table + interface School: Entity { + @PrimaryKey + var id: Int + var schoolName: String + } + + fun run() { + assert(Users.firstSchoolId.referenceTable is Schools) + assert(Users.firstSchoolId.name == "first_school_id") + assert(Users.secondSchoolId.referenceTable is Schools) + assert(Users.secondSchoolId.name == "second_school_identity") + } + """.trimIndent()) + + @Test + fun `interface entity`() = runKotlin(""" + @Table + interface User: Entity { + @PrimaryKey + var id: Int + var username: String + var age: Int + } + + fun run() { + assert(Users.tableName == "user") + assert(Users.columns.map { it.name }.toSet() == setOf("id", "username", "age")) + } + """.trimIndent()) + + @Test + fun `interface entity keyword identifier`() = runKotlin(""" + @Table + interface User: Entity { + @PrimaryKey + var id: Int + var `class`: String + var operator: String + } + + fun run() { + assert(Users.tableName == "user") + assert(Users.columns.map { it.name }.toSet() == setOf("id", "class", "operator")) + } + """.trimIndent()) +} diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGeneratorTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGeneratorTest.kt new file mode 100644 index 000000000..37a164e75 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGeneratorTest.kt @@ -0,0 +1,49 @@ +package org.ktorm.ksp.compiler.generator + +import org.junit.Test +import org.ktorm.ksp.compiler.BaseKspTest + +class UpdateFunctionGeneratorTest : BaseKspTest() { + + @Test + fun `sequence update function`() = runKotlin(""" + @Table + data class User( + @PrimaryKey + var id: Int?, + var username: String, + var age: Int, + ) + + fun run() { + val user = database.users.first { it.id eq 1 } + assert(user.username == "jack") + + user.username = "tom" + database.users.update(user) + + val user0 = database.users.first { it.id eq 1 } + assert(user0.username == "tom") + } + """.trimIndent()) + + @Test + fun `modified entity sequence call update fun`() = runKotlin(""" + @Table + data class User( + @PrimaryKey + var id: Int?, + var username: String, + var age: Int + ) + + fun run() { + try { + val users = database.users.filter { it.id eq 1 } + users.update(User(1, "lucy", 10)) + throw AssertionError("fail") + } catch (_: UnsupportedOperationException) { + } + } + """.trimIndent()) +} diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/CompoundPrimaryKeysTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/CompoundPrimaryKeysTest.kt new file mode 100644 index 000000000..22eac07e5 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/CompoundPrimaryKeysTest.kt @@ -0,0 +1,31 @@ +package org.ktorm.ksp.compiler.parser + +import org.junit.Test +import org.ktorm.ksp.compiler.BaseKspTest + +class CompoundPrimaryKeysTest : BaseKspTest() { + + @Test + fun `multi primary key`() = runKotlin(""" + @Table(name = "province") + data class Province( + @PrimaryKey + val country:String, + @PrimaryKey + val province:String, + var population:Int + ) + + fun run() { + database.provinces.add(Province("China", "Guangdong", 150000)) + assert(database.provinces.toList().contains(Province("China", "Guangdong", 150000))) + + var province = database.provinces.first { (it.country eq "China") and (it.province eq "Hebei") } + province.population = 200000 + database.provinces.update(province) + + province = database.provinces.first { (it.country eq "China") and (it.province eq "Hebei") } + assert(province.population == 200000) + } + """.trimIndent()) +} diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/DatabaseNamingStrategyTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/DatabaseNamingStrategyTest.kt new file mode 100644 index 000000000..76d1b4a01 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/DatabaseNamingStrategyTest.kt @@ -0,0 +1,132 @@ +package org.ktorm.ksp.compiler.parser + +import org.junit.Test +import org.ktorm.ksp.compiler.BaseKspTest +import org.ktorm.ksp.compiler.util.CamelCase +import kotlin.test.assertEquals + +class DatabaseNamingStrategyTest : BaseKspTest() { + + @Test + fun testCamelCase() { + assertEquals("abc_def", CamelCase.toLowerSnakeCase("abcDef")) + assertEquals("abc_def", CamelCase.toLowerSnakeCase("AbcDef")) + assertEquals("ABC_DEF", CamelCase.toUpperSnakeCase("abcDef")) + assertEquals("ABC_DEF", CamelCase.toUpperSnakeCase("AbcDef")) + assertEquals("abcDef", CamelCase.toFirstLowerCamelCase("abcDef")) + assertEquals("abcDef", CamelCase.toFirstLowerCamelCase("AbcDef")) + + assertEquals("abc_def", CamelCase.toLowerSnakeCase("ABCDef")) + assertEquals("ABC_DEF", CamelCase.toUpperSnakeCase("ABCDef")) + assertEquals("abcDef", CamelCase.toFirstLowerCamelCase("ABCDef")) + + assertEquals("io_utils", CamelCase.toLowerSnakeCase("IOUtils")) + assertEquals("IO_UTILS", CamelCase.toUpperSnakeCase("IOUtils")) + assertEquals("ioUtils", CamelCase.toFirstLowerCamelCase("IOUtils")) + + assertEquals("pwd_utils", CamelCase.toLowerSnakeCase("PWDUtils")) + assertEquals("PWD_UTILS", CamelCase.toUpperSnakeCase("PWDUtils")) + assertEquals("pwdUtils", CamelCase.toFirstLowerCamelCase("PWDUtils")) + + assertEquals("pwd_utils", CamelCase.toLowerSnakeCase("PwdUtils")) + assertEquals("PWD_UTILS", CamelCase.toUpperSnakeCase("PwdUtils")) + assertEquals("pwdUtils", CamelCase.toFirstLowerCamelCase("PwdUtils")) + + assertEquals("test_io", CamelCase.toLowerSnakeCase("testIO")) + assertEquals("TEST_IO", CamelCase.toUpperSnakeCase("testIO")) + assertEquals("testIO", CamelCase.toFirstLowerCamelCase("testIO")) + + assertEquals("test_pwd", CamelCase.toLowerSnakeCase("testPWD")) + assertEquals("TEST_PWD", CamelCase.toUpperSnakeCase("testPWD")) + assertEquals("testPWD", CamelCase.toFirstLowerCamelCase("testPWD")) + + assertEquals("test_pwd", CamelCase.toLowerSnakeCase("testPwd")) + assertEquals("TEST_PWD", CamelCase.toUpperSnakeCase("testPwd")) + assertEquals("testPwd", CamelCase.toFirstLowerCamelCase("testPwd")) + + assertEquals("a2c_count", CamelCase.toLowerSnakeCase("A2CCount")) + assertEquals("A2C_COUNT", CamelCase.toUpperSnakeCase("A2CCount")) + assertEquals("a2cCount", CamelCase.toFirstLowerCamelCase("A2CCount")) + } + + @Test + fun testDefaultNaming() = runKotlin(""" + @Table + interface UserProfile: Entity { + @PrimaryKey + var id: Int + var publicEmail: String + var profilePicture: Int + @References + var company: Company + } + + @Table + interface Company: Entity { + @PrimaryKey + var id: Int + var name: String + } + + fun run() { + assert(Companies.tableName == "company") + assert(Companies.columns.map { it.name }.toSet() == setOf("id", "name")) + assert(UserProfiles.tableName == "user_profile") + assert(UserProfiles.columns.map { it.name }.toSet() == setOf("id", "public_email", "profile_picture", "company_id")) + } + """.trimIndent()) + + @Test + fun testUpperCamelCaseNamingByAlias() = runKotlin(""" + @Table + interface UserProfile: Entity { + @PrimaryKey + var id: Int + var publicEmail: String + var profilePicture: Int + @References + var company: Company + } + + @Table + interface Company: Entity { + @PrimaryKey + var id: Int + var name: String + } + + fun run() { + assert(Companies.tableName == "COMPANY") + assert(Companies.columns.map { it.name }.toSet() == setOf("ID", "NAME")) + assert(UserProfiles.tableName == "USER_PROFILE") + assert(UserProfiles.columns.map { it.name }.toSet() == setOf("ID", "PUBLIC_EMAIL", "PROFILE_PICTURE", "COMPANY_ID")) + } + """.trimIndent(), "ktorm.dbNamingStrategy" to "upper-snake-case") + + @Test + fun testUpperCamelCaseNamingByClassName() = runKotlin(""" + @Table + interface UserProfile: Entity { + @PrimaryKey + var id: Int + var publicEmail: String + var profilePicture: Int + @References + var company: Company + } + + @Table + interface Company: Entity { + @PrimaryKey + var id: Int + var name: String + } + + fun run() { + assert(Companies.tableName == "COMPANY") + assert(Companies.columns.map { it.name }.toSet() == setOf("ID", "NAME")) + assert(UserProfiles.tableName == "USER_PROFILE") + assert(UserProfiles.columns.map { it.name }.toSet() == setOf("ID", "PUBLIC_EMAIL", "PROFILE_PICTURE", "COMPANY_ID")) + } + """.trimIndent(), "ktorm.dbNamingStrategy" to "org.ktorm.ksp.compiler.util.UpperSnakeCaseDatabaseNamingStrategy") +} diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt new file mode 100644 index 000000000..9caa63eed --- /dev/null +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt @@ -0,0 +1,283 @@ +package org.ktorm.ksp.compiler.parser + +import org.junit.Test +import org.ktorm.ksp.compiler.BaseKspTest + +/** + * Created by vince at Apr 16, 2023. + */ +class MetadataParserTest : BaseKspTest() { + + @Test + fun testEnumClass() = kspFailing("Gender is expected to be a class or interface but actually ENUM_CLASS.", """ + @Table + enum class Gender { MALE, FEMALE } + """.trimIndent()) + + @Test + fun testInterfaceNotExtendingEntity() = kspFailing("User must extends from org.ktorm.entity.Entity.", """ + @Table + interface User { + val id: Int + val name: String + } + """.trimIndent()) + + @Test + fun testClassIgnoreProperties() = runKotlin(""" + @Table(ignoreProperties = ["name"]) + class User( + val id: Int, + val name: String? = null + ) + + fun run() { + assert(Users.columns.map { it.name }.toSet() == setOf("id")) + } + """.trimIndent()) + + @Test + fun testInterfaceIgnoreProperties() = runKotlin(""" + @Table(ignoreProperties = ["name"]) + interface User : Entity { + val id: Int + val name: String + } + + fun run() { + assert(Users.columns.map { it.name }.toSet() == setOf("id")) + } + """.trimIndent()) + + @Test + fun testClassIgnoreAnnotation() = runKotlin(""" + @Table + class User( + val id: Int, + @Ignore + val name: String? = null + ) + + fun run() { + assert(Users.columns.map { it.name }.toSet() == setOf("id")) + } + """.trimIndent()) + + @Test + fun testInterfaceIgnoreAnnotation() = runKotlin(""" + @Table + interface User : Entity { + val id: Int + @Ignore + val name: String + } + + fun run() { + assert(Users.columns.map { it.name }.toSet() == setOf("id")) + } + """.trimIndent()) + + @Test + fun testClassPropertiesWithoutBackingField() = runKotlin(""" + @Table + class User(val id: Int) { + val name: String get() = "vince" + } + + fun run() { + assert(Users.columns.map { it.name }.toSet() == setOf("id")) + } + """.trimIndent()) + + @Test + fun testClassPropertiesOrder() = runKotlin(""" + @Table + class User(var id: Int) { + var name: String? = null + } + + fun run() { + assert(Users.columns.map { it.name }[0] == "id") + assert(Users.columns.map { it.name }[1] == "name") + } + """.trimIndent()) + + @Test + fun testInterfaceNonAbstractProperties() = runKotlin(""" + @Table + interface User : Entity { + val id: Int + val name: String get() = "vince" + } + + fun run() { + assert(Users.columns.map { it.name }.toSet() == setOf("id")) + } + """.trimIndent()) + + @Test + fun testSqlTypeInferError() = kspFailing("Parse sqlType error for property User.name: cannot infer sqlType, please specify manually.", """ + @Table + interface User : Entity { + val name: java.lang.StringBuilder + } + """.trimIndent()) + + @Test + fun testSqlTypeShouldBeObject() = kspFailing("Parse sqlType error for property User.name: the sqlType class must be a Kotlin singleton object.", """ + @Table + interface User : Entity { + val id: Int + @Column(sqlType = org.ktorm.schema.EnumSqlType::class) + val name: String + } + """.trimIndent()) + + @Test + fun testSqlTypeShouldBeSqlType() = kspFailing("Parse sqlType error for property User.name: the sqlType class must be subtype of SqlType/SqlTypeFactory.", """ + @Table + interface User : Entity { + val id: Int + @Column(sqlType = Test::class) + val name: String + } + + object Test + """.trimIndent()) + + @Test + fun testReferencesWithColumn() = kspFailing("Parse ref column error for property User.profile: @Column and @References cannot be used together.", """ + @Table + interface User : Entity { + val id: Int + @References + @Column + val profile: Profile + } + + @Table + interface Profile : Entity { + val id: Int + val name: String + } + """.trimIndent()) + + @Test + fun testReferencesFromClassEntity() = kspFailing("Parse ref column error for property User.profile: @References can only be used in interface-based entities", """ + @Table + class User( + val id: Int, + @References + val profile: Profile + ) + + @Table + interface Profile : Entity { + val id: Int + val name: String + } + """.trimIndent()) + + @Test + fun testReferencesToClassEntity() = kspFailing("Parse ref column error for property User.profile: the referenced entity class must be an interface", """ + @Table + interface User : Entity { + val id: Int + @References + val profile: Profile + } + + @Table + class Profile( + val id: Int, + val name: String + ) + """.trimIndent()) + + @Test + fun testReferencesToNonTableClass() = kspFailing("Parse ref column error for property User.profile: the referenced entity class must be annotated with @Table", """ + @Table + interface User : Entity { + val id: Int + @References + val profile: Profile + } + + interface Profile : Entity { + val id: Int + val name: String + } + """.trimIndent()) + + @Test + fun testReferencesNoPrimaryKeys() = kspFailing("Parse ref column error for property User.profile: the referenced table doesn't have a primary key", """ + @Table + interface User : Entity { + val id: Int + @References + val profile: Profile + } + + @Table + interface Profile : Entity { + val id: Int + val name: String + } + """.trimIndent()) + + @Test + fun testReferencesWithCompoundPrimaryKeys() = kspFailing("Parse ref column error for property User.profile: the referenced table cannot have compound primary keys", """ + @Table + interface User : Entity { + val id: Int + @References + val profile: Profile + } + + @Table + interface Profile : Entity { + @PrimaryKey + val id: Int + @PrimaryKey + val name: String + } + """.trimIndent()) + + @Test + fun testCircularReference() = kspFailing("Circular reference is not allowed, current table: User, reference route: Profile --> Operator --> User", """ + @Table + interface User : Entity { + @PrimaryKey + val id: Int + @References + val profile: Profile + } + + @Table + interface Profile : Entity { + @PrimaryKey + val id: Int + @References + val operator: Operator + } + + @Table + interface Operator : Entity { + @PrimaryKey + val id: Int + @References + val user: User + } + """.trimIndent()) + + @Test + fun testSelfReference() = kspFailing("Circular reference is not allowed, current table: User, reference route: User", """ + @Table + interface User : Entity { + @PrimaryKey + val id: Int + @References + val manager: User + } + """.trimIndent()) +} diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/SqlTypeTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/SqlTypeTest.kt new file mode 100644 index 000000000..e2b5eca48 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/SqlTypeTest.kt @@ -0,0 +1,152 @@ +package org.ktorm.ksp.compiler.parser + +import org.junit.Test +import org.ktorm.ksp.compiler.BaseKspTest + +class SqlTypeTest : BaseKspTest() { + + @Test + fun testDefaultSqlType() = runKotlin(""" + @Table + data class User( + val int: Int, + val string: String, + val boolean: Boolean, + val long: Long, + val short: Short, + val double: Double, + val float: Float, + val bigDecimal: BigDecimal, + val date: java.sql.Date, + val time: Time, + val timestamp: Timestamp, + val localDateTime: LocalDateTime, + val localDate: LocalDate, + val localTime: LocalTime, + val monthDay: MonthDay, + val yearMonth: YearMonth, + val year: Year, + val instant: Instant, + val uuid: UUID, + val byteArray: ByteArray, + val gender: Gender + ) + + enum class Gender { + MALE, + FEMALE + } + + fun run() { + assert(Users.int.sqlType == org.ktorm.schema.IntSqlType) + assert(Users.string.sqlType == org.ktorm.schema.VarcharSqlType) + assert(Users.boolean.sqlType == org.ktorm.schema.BooleanSqlType) + assert(Users.long.sqlType == org.ktorm.schema.LongSqlType) + assert(Users.short.sqlType == org.ktorm.schema.ShortSqlType) + assert(Users.double.sqlType == org.ktorm.schema.DoubleSqlType) + assert(Users.float.sqlType == org.ktorm.schema.FloatSqlType) + assert(Users.bigDecimal.sqlType == org.ktorm.schema.DecimalSqlType) + assert(Users.date.sqlType == org.ktorm.schema.DateSqlType) + assert(Users.time.sqlType == org.ktorm.schema.TimeSqlType) + assert(Users.timestamp.sqlType == org.ktorm.schema.TimestampSqlType) + assert(Users.localDateTime.sqlType == org.ktorm.schema.LocalDateTimeSqlType) + assert(Users.localDate.sqlType == org.ktorm.schema.LocalDateSqlType) + assert(Users.localTime.sqlType == org.ktorm.schema.LocalTimeSqlType) + assert(Users.monthDay.sqlType == org.ktorm.schema.MonthDaySqlType) + assert(Users.yearMonth.sqlType == org.ktorm.schema.YearMonthSqlType) + assert(Users.year.sqlType == org.ktorm.schema.YearSqlType) + assert(Users.instant.sqlType == org.ktorm.schema.InstantSqlType) + assert(Users.uuid.sqlType == org.ktorm.schema.UuidSqlType) + assert(Users.byteArray.sqlType == org.ktorm.schema.BytesSqlType) + assert(Users.gender.sqlType is org.ktorm.schema.EnumSqlType<*>) + } + """.trimIndent()) + + @Test + fun testCustomSqlType() = runKotlin(""" + @Table + data class User( + @PrimaryKey + var id: Int, + @Column(sqlType = UsernameSqlType::class) + var username: Username, + var age: Int, + var gender: Int + ) + + data class Username( + val firstName:String, + val lastName:String + ) + + object UsernameSqlType : org.ktorm.schema.SqlType(Types.VARCHAR, "varchar") { + override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: Username) { + ps.setString(index, parameter.firstName + "#" + parameter.lastName) + } + + override fun doGetResult(rs: ResultSet, index: Int): Username? { + val (firstName, lastName) = rs.getString(index)?.split("#") ?: return null + return Username(firstName, lastName) + } + } + + fun run() { + assert(Users.username.sqlType == UsernameSqlType) + assert(Users.username.sqlType.typeCode == Types.VARCHAR) + assert(Users.username.sqlType.typeName == "varchar") + + database.users.add(User(100, Username("Vincent", "Lau"), 28, 0)) + assert(database.users.first { it.id eq 100 } == User(100, Username("Vincent", "Lau"), 28, 0)) + } + """.trimIndent()) + + @Test + fun testCustomSqlTypeFactory() = runKotlin(""" + @Table + data class User( + @PrimaryKey + var id: Int, + var username: String, + var age: Int, + @Column(sqlType = IntEnumSqlTypeFactory::class) + var gender: Gender + ) + + enum class Gender { + MALE, + FEMALE + } + + object IntEnumSqlTypeFactory : SqlTypeFactory { + + @Suppress("UNCHECKED_CAST") + override fun createSqlType(property: KProperty1<*, T?>): org.ktorm.schema.SqlType { + val returnType = property.returnType.jvmErasure.java + if (returnType.isEnum) { + return IntEnumSqlType(returnType as Class>) as org.ktorm.schema.SqlType + } else { + throw IllegalArgumentException("The property is required to be typed of enum but actually: ${"$"}returnType") + } + } + + private class IntEnumSqlType>(val enumClass: Class) : org.ktorm.schema.SqlType(Types.INTEGER, "int") { + override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: E) { + ps.setInt(index, parameter.ordinal) + } + + override fun doGetResult(rs: ResultSet, index: Int): E? { + return enumClass.enumConstants[rs.getInt(index)] + } + } + } + + fun run() { + assert(Users.gender.sqlType::class.simpleName == "IntEnumSqlType") + assert(Users.gender.sqlType.typeCode == Types.INTEGER) + assert(Users.gender.sqlType.typeName == "int") + + database.users.add(User(100, "Vincent", 28, Gender.MALE)) + assert(database.users.first { it.id eq 100 } == User(100, "Vincent", 28, Gender.MALE)) + } + """.trimIndent()) +} diff --git a/ktorm-ksp-compiler/src/test/resources/drop-ksp-data.sql b/ktorm-ksp-compiler/src/test/resources/drop-ksp-data.sql new file mode 100644 index 000000000..72e77692a --- /dev/null +++ b/ktorm-ksp-compiler/src/test/resources/drop-ksp-data.sql @@ -0,0 +1,3 @@ +drop table if exists "user"; +drop table if exists "employee"; +drop table if exists "province"; diff --git a/ktorm-ksp-compiler/src/test/resources/init-ksp-data.sql b/ktorm-ksp-compiler/src/test/resources/init-ksp-data.sql new file mode 100644 index 000000000..112e7518b --- /dev/null +++ b/ktorm-ksp-compiler/src/test/resources/init-ksp-data.sql @@ -0,0 +1,45 @@ +create table "user" +( + "id" int not null primary key auto_increment, + "username" varchar(128) not null, + "age" int not null, + "gender" int not null default 0, + "phone" varchar(128) null +); + + +insert into "user"("username", "age", "gender") +values ('jack', 20, 0), + ('lucy', 22, 1), + ('mike', 22, 0); + + +create table "employee" +( + "id" int not null primary key auto_increment, + "name" varchar(128) not null, + "job" varchar(128) not null, + "manager_id" int null, + "hire_date" date not null, + "salary" bigint not null, + "department_id" int not null +); + + +insert into "employee"("name", "job", "manager_id", "hire_date", "salary", "department_id") +values ('vince', 'engineer', null, '2018-01-01', 100, 1), + ('marry', 'trainee', 1, '2019-01-01', 50, 1), + ('tom', 'director', null, '2018-01-01', 200, 2), + ('penny', 'assistant', 3, '2019-01-01', 100, 2); + +create table "province" +( + "country" varchar(128) not null, + "province" varchar(128) not null, + "population" int not null, + primary key ("country", "province") +); + +insert into "province"("country", "province", "population") +values ('China', 'Hebei', 130000), + ('China', 'Henan', 140000); diff --git a/ktorm-ksp-compiler/src/test/resources/services/org.ktorm.ksp.spi.ExtCodeGenerator b/ktorm-ksp-compiler/src/test/resources/services/org.ktorm.ksp.spi.ExtCodeGenerator new file mode 100644 index 000000000..c7eda3524 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/resources/services/org.ktorm.ksp.spi.ExtCodeGenerator @@ -0,0 +1 @@ +org.ktorm.ksp.compiler.test.generator.ExtCodeGeneratorTest diff --git a/ktorm-ksp-compiler/src/test/resources/simplelogger.properties b/ktorm-ksp-compiler/src/test/resources/simplelogger.properties new file mode 100644 index 000000000..08dada486 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/resources/simplelogger.properties @@ -0,0 +1,6 @@ +org.slf4j.simpleLogger.logFile=System.err +org.slf4j.simpleLogger.defaultLogLevel=info +org.slf4j.simpleLogger.log.org.ktorm.database=trace +org.slf4j.simpleLogger.showThreadName=false +org.slf4j.simpleLogger.showLogName=false +org.slf4j.simpleLogger.levelInBrackets=true \ No newline at end of file From d99bb98f22c2767a7c36f2aba31a012ac69317bd Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 2 Jul 2023 22:37:14 +0800 Subject: [PATCH 021/105] fix ksp test --- .../test/resources/services/org.ktorm.ksp.spi.ExtCodeGenerator | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ktorm-ksp-compiler/src/test/resources/services/org.ktorm.ksp.spi.ExtCodeGenerator b/ktorm-ksp-compiler/src/test/resources/services/org.ktorm.ksp.spi.ExtCodeGenerator index c7eda3524..b161c3299 100644 --- a/ktorm-ksp-compiler/src/test/resources/services/org.ktorm.ksp.spi.ExtCodeGenerator +++ b/ktorm-ksp-compiler/src/test/resources/services/org.ktorm.ksp.spi.ExtCodeGenerator @@ -1 +1 @@ -org.ktorm.ksp.compiler.test.generator.ExtCodeGeneratorTest +org.ktorm.ksp.compiler.generator.ExtCodeGeneratorTest From 0716ffeed54910079b8879a9821cf2a1d1a5dd93 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 3 Jul 2023 18:07:12 +0800 Subject: [PATCH 022/105] refactor --- .../generator/AddFunctionGenerator.kt | 5 ++-- .../generator/ComponentFunctionGenerator.kt | 3 ++- .../PseudoConstructorFunctionGenerator.kt | 25 ++++++++----------- .../compiler/generator/TableClassGenerator.kt | 5 ++-- .../generator/UpdateFunctionGenerator.kt | 2 +- .../ksp/compiler/parser/MetadataParser.kt | 8 +++--- .../ktorm/ksp/compiler/util/KspExtensions.kt | 20 ++++++++++++++- .../ksp/compiler/util/SqlTypeMappings.kt | 7 +++--- 8 files changed, 46 insertions(+), 29 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt index 163e5895e..9cb5ffb47 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt @@ -24,6 +24,7 @@ import org.ktorm.dsl.AliasRemover import org.ktorm.entity.EntitySequence import org.ktorm.expression.ColumnAssignmentExpression import org.ktorm.expression.InsertExpression +import org.ktorm.ksp.compiler.util._type import org.ktorm.ksp.spi.ColumnMetadata import org.ktorm.ksp.spi.TableMetadata import org.ktorm.schema.Column @@ -35,7 +36,7 @@ internal object AddFunctionGenerator { val primaryKeys = table.columns.filter { it.isPrimaryKey } val useGeneratedKey = primaryKeys.size == 1 && primaryKeys[0].entityProperty.isMutable - && primaryKeys[0].entityProperty.type.resolve().isMarkedNullable + && primaryKeys[0].entityProperty._type.isMarkedNullable val entityClass = table.entityClass.toClassName() val tableClass = ClassName(table.entityClass.packageName.asString(), table.tableClassName) @@ -117,7 +118,7 @@ internal object AddFunctionGenerator { for (column in table.columns) { val forceDynamic = useGeneratedKey - && column.isPrimaryKey && column.entityProperty.type.resolve().isMarkedNullable + && column.isPrimaryKey && column.entityProperty._type.isMarkedNullable addStatement( "assignments.addVal(sourceTable.%N, entity.%N, %L)", diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGenerator.kt index 59a6f61e8..4cb0cef60 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGenerator.kt @@ -22,6 +22,7 @@ import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview import com.squareup.kotlinpoet.ksp.toClassName import com.squareup.kotlinpoet.ksp.toTypeName +import org.ktorm.ksp.compiler.util._type import org.ktorm.ksp.spi.TableMetadata @OptIn(KotlinPoetKspPreview::class) @@ -37,7 +38,7 @@ internal object ComponentFunctionGenerator { table.entityClass.simpleName.asString(), prop.simpleName.asString()) .addModifiers(KModifier.OPERATOR) .receiver(table.entityClass.toClassName()) - .returns(prop.type.resolve().toTypeName()) + .returns(prop._type.toTypeName()) .addCode("return·this.%N", prop.simpleName.asString()) .build() } diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt index 840f25ea0..7c79ab4be 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt @@ -48,7 +48,7 @@ internal object PseudoConstructorFunctionGenerator { .filterNot { it.simpleName.asString() in setOf("entityClass", "properties") } .map { prop -> val propName = prop.simpleName.asString() - val propType = prop.type.resolve().makeNullable().toTypeName() + val propType = prop._type.makeNullable().toTypeName() ParameterSpec.builder(propName, propType) .defaultValue("%T.of()", Undefined::class.asClassName()) @@ -68,20 +68,17 @@ internal object PseudoConstructorFunctionGenerator { continue } - val propName = prop.simpleName.asString() - val propType = prop.type.resolve() - if (propType.isInline()) { - beginControlFlow( - "if·((%N·as·Any?)·!==·(%T.of<%T>()·as·Any?))", - propName, Undefined::class.asClassName(), propType.makeNotNullable().toTypeName() - ) + val condition: String + if (prop._type.isInline()) { + condition = "if·((%N·as·Any?)·!==·(%T.of<%T>()·as·Any?))" } else { - beginControlFlow( - "if·(%N·!==·%T.of<%T>())", - propName, Undefined::class.asClassName(), propType.makeNotNullable().toTypeName() - ) + condition = "if·(%N·!==·%T.of<%T>())" } + beginControlFlow(condition, + prop.simpleName.asString(), Undefined::class.asClassName(), prop._type.makeNotNullable().toTypeName() + ) + var statement: String if (prop.isMutable) { statement = "entity.%1N·=·%1N" @@ -89,11 +86,11 @@ internal object PseudoConstructorFunctionGenerator { statement = "entity[%1S]·=·%1N" } - if (!propType.isMarkedNullable) { + if (!prop._type.isMarkedNullable) { statement += "·?:·error(\"`%1L` should not be null.\")" } - addStatement(statement, propName) + addStatement(statement, prop.simpleName.asString()) endControlFlow() } diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt index 7cd7e6943..5f1b31dda 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt @@ -23,6 +23,7 @@ import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview import com.squareup.kotlinpoet.ksp.toClassName import org.ktorm.dsl.QueryRowSet +import org.ktorm.ksp.compiler.util._type import org.ktorm.ksp.compiler.util.getKotlinType import org.ktorm.ksp.compiler.util.getRegisteringCodeBlock import org.ktorm.ksp.spi.TableMetadata @@ -163,7 +164,7 @@ internal object TableClassGenerator { for (column in table.columns) { val parameter = constructorParams[column.entityProperty.simpleName.asString()] ?: continue - if (parameter.type.resolve().isMarkedNullable) { + if (parameter._type.isMarkedNullable) { add("%N·=·row[this.%N],", parameter.name!!.asString(), column.columnPropertyName) } else { add("%N·=·row[this.%N]!!,", parameter.name!!.asString(), column.columnPropertyName) @@ -179,7 +180,7 @@ internal object TableClassGenerator { continue } - if (column.entityProperty.type.resolve().isMarkedNullable) { + if (column.entityProperty._type.isMarkedNullable) { addStatement("entity.%N·=·row[this.%N]", propName, column.columnPropertyName) } else { addStatement("entity.%N·=·row[this.%N]!!", propName, column.columnPropertyName) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt index 3bc1e0bf0..9a99efa32 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt @@ -89,7 +89,7 @@ internal object UpdateFunctionGenerator { } val condition: String - if (column.entityProperty.type.resolve().isMarkedNullable) { + if (column.entityProperty._type.isMarkedNullable) { condition = "sourceTable.%N·%M·entity.%N!!," } else { condition = "sourceTable.%N·%M·entity.%N," diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index e1f94b8e7..bd8540562 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -152,7 +152,7 @@ internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessor private fun parseColumnSqlType(property: KSPropertyDeclaration): KSType { var sqlType = property.annotations - .filter { it.annotationType.resolve().getJvmName() == Column::class.jvmName } + .filter { it._annotationType.getJvmName() == Column::class.jvmName } .flatMap { it.arguments } .filter { it.name?.asString() == Column::sqlType.name } .map { it.value as KSType? } @@ -184,7 +184,7 @@ internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessor val hasConstructor = declaration.getConstructors() .filter { it.parameters.size == 1 } - .filter { it.parameters[0].type.resolve().getJvmName() == TypeReference::class.jvmName } + .filter { it.parameters[0]._type.getJvmName() == TypeReference::class.jvmName } .any() if (!hasConstructor) { @@ -214,7 +214,7 @@ internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessor ) } - val refEntityClass = property.type.resolve().declaration as KSClassDeclaration + val refEntityClass = property._type.declaration as KSClassDeclaration table.checkCircularRef(refEntityClass) if (refEntityClass.classKind != INTERFACE) { @@ -286,7 +286,7 @@ internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessor val refTable = ref.getAnnotationsByType(Table::class).firstOrNull() for (property in ref.getProperties(refTable?.ignoreProperties?.toSet() ?: emptySet())) { if (property.isAnnotationPresent(References::class)) { - val propType = property.type.resolve().declaration as KSClassDeclaration + val propType = property._type.declaration as KSClassDeclaration checkCircularRef(propType, stack) } } diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt index bad91180c..e89a68043 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt @@ -22,6 +22,24 @@ import com.google.devtools.ksp.symbol.* import com.google.devtools.ksp.visitor.KSValidateVisitor import kotlin.reflect.jvm.jvmName +/** + * Return the resolved [KSType] of this property. + */ +@Suppress("ObjectPropertyName") +internal val KSPropertyDeclaration._type: KSType get() = type.resolve() + +/** + * Return the resolved [KSType] of this annotation. + */ +@Suppress("ObjectPropertyName") +internal val KSAnnotation._annotationType: KSType get() = annotationType.resolve() + +/** + * Return the resolved [KSType] of this parameter. + */ +@Suppress("ObjectPropertyName") +internal val KSValueParameter._type: KSType get() = type.resolve() + /** * Check if the given symbol is valid. */ @@ -99,7 +117,7 @@ internal fun KSType.isInline(): Boolean { } /** - * Return the JVM class name of [this] type. + * Return the JVM class name of this type. */ internal fun KSType.getJvmName(): String? { return declaration.qualifiedName?.asString() diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt index 8f304fc4b..5eda1ec55 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt @@ -31,12 +31,11 @@ import org.ktorm.ksp.spi.ColumnMetadata import org.ktorm.schema.* internal fun KSPropertyDeclaration.getSqlType(resolver: Resolver): KSType? { - val propType = this.type.resolve() - if ((propType.declaration as KSClassDeclaration).classKind == ClassKind.ENUM_CLASS) { + if ((_type.declaration as KSClassDeclaration).classKind == ClassKind.ENUM_CLASS) { return resolver.getClassDeclarationByName>()?.asType(emptyList()) } - val sqlType = when (propType.getJvmName()) { + val sqlType = when (_type.getJvmName()) { "kotlin.Boolean" -> BooleanSqlType::class "kotlin.Int" -> IntSqlType::class "kotlin.Short" -> ShortSqlType::class @@ -118,6 +117,6 @@ internal fun ColumnMetadata.getKotlinType(): TypeName { if (isReference) { return referenceTable!!.columns.single { it.isPrimaryKey }.getKotlinType() } else { - return entityProperty.type.resolve().makeNotNullable().toTypeName() + return entityProperty._type.makeNotNullable().toTypeName() } } From 74baae89a6cf24a90e021f3bba90f7198f4b15c9 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 3 Jul 2023 18:12:28 +0800 Subject: [PATCH 023/105] refactor --- .../ktorm/ksp/compiler/util/KspExtensions.kt | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt index e89a68043..7c8d224bf 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt @@ -40,6 +40,49 @@ internal val KSAnnotation._annotationType: KSType get() = annotationType.resolve @Suppress("ObjectPropertyName") internal val KSValueParameter._type: KSType get() = type.resolve() +/** + * Return the JVM class name of this type. + */ +internal fun KSType.getJvmName(): String? { + return declaration.qualifiedName?.asString() +} + +/** + * Check if this type is an inline class. + */ +@OptIn(KspExperimental::class) +internal fun KSType.isInline(): Boolean { + val declaration = declaration as KSClassDeclaration + return declaration.isAnnotationPresent(JvmInline::class) && declaration.modifiers.contains(Modifier.VALUE) +} + +/** + * Check if this class is a subclass of [T]. + */ +internal inline fun KSClassDeclaration.isSubclassOf(): Boolean { + return findSuperTypeReference(T::class.jvmName) != null +} + +/** + * Find the specific super type reference for this class. + */ +internal fun KSClassDeclaration.findSuperTypeReference(name: String): KSTypeReference? { + for (superType in this.superTypes) { + val ksType = superType.resolve() + + if (ksType.getJvmName() == name) { + return superType + } + + val result = (ksType.declaration as KSClassDeclaration).findSuperTypeReference(name) + if (result != null) { + return result + } + } + + return null +} + /** * Check if the given symbol is valid. */ @@ -79,46 +122,3 @@ internal fun KSNode.isValid(): Boolean { return this.accept(visitor, null) } - -/** - * Check if this class is a subclass of [T]. - */ -internal inline fun KSClassDeclaration.isSubclassOf(): Boolean { - return findSuperTypeReference(T::class.jvmName) != null -} - -/** - * Find the specific super type reference for this class. - */ -internal fun KSClassDeclaration.findSuperTypeReference(name: String): KSTypeReference? { - for (superType in this.superTypes) { - val ksType = superType.resolve() - - if (ksType.getJvmName() == name) { - return superType - } - - val result = (ksType.declaration as KSClassDeclaration).findSuperTypeReference(name) - if (result != null) { - return result - } - } - - return null -} - -/** - * Check if this type is an inline class. - */ -@OptIn(KspExperimental::class) -internal fun KSType.isInline(): Boolean { - val declaration = declaration as KSClassDeclaration - return declaration.isAnnotationPresent(JvmInline::class) && declaration.modifiers.contains(Modifier.VALUE) -} - -/** - * Return the JVM class name of this type. - */ -internal fun KSType.getJvmName(): String? { - return declaration.qualifiedName?.asString() -} From 4914d5796e242f80cefd358ca284be2fe605bd80 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 3 Jul 2023 18:26:41 +0800 Subject: [PATCH 024/105] refactor --- .../ktorm/ksp/compiler/parser/MetadataParser.kt | 6 +++--- .../org/ktorm/ksp/compiler/util/KspExtensions.kt | 15 ++++----------- .../ktorm/ksp/compiler/util/SqlTypeMappings.kt | 7 ++++--- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index bd8540562..04ac15a1f 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -152,13 +152,13 @@ internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessor private fun parseColumnSqlType(property: KSPropertyDeclaration): KSType { var sqlType = property.annotations - .filter { it._annotationType.getJvmName() == Column::class.jvmName } + .filter { it._annotationType.declaration.qualifiedName?.asString() == Column::class.jvmName } .flatMap { it.arguments } .filter { it.name?.asString() == Column::sqlType.name } .map { it.value as KSType? } .singleOrNull() - if (sqlType?.getJvmName() == Nothing::class.jvmName) { + if (sqlType?.declaration?.qualifiedName?.asString() == Nothing::class.jvmName) { sqlType = null } @@ -184,7 +184,7 @@ internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessor val hasConstructor = declaration.getConstructors() .filter { it.parameters.size == 1 } - .filter { it.parameters[0]._type.getJvmName() == TypeReference::class.jvmName } + .filter { it.parameters[0]._type.declaration.qualifiedName?.asString() == TypeReference::class.jvmName } .any() if (!hasConstructor) { diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt index 7c8d224bf..4a0858dbf 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt @@ -28,12 +28,6 @@ import kotlin.reflect.jvm.jvmName @Suppress("ObjectPropertyName") internal val KSPropertyDeclaration._type: KSType get() = type.resolve() -/** - * Return the resolved [KSType] of this annotation. - */ -@Suppress("ObjectPropertyName") -internal val KSAnnotation._annotationType: KSType get() = annotationType.resolve() - /** * Return the resolved [KSType] of this parameter. */ @@ -41,11 +35,10 @@ internal val KSAnnotation._annotationType: KSType get() = annotationType.resolve internal val KSValueParameter._type: KSType get() = type.resolve() /** - * Return the JVM class name of this type. + * Return the resolved [KSType] of this annotation. */ -internal fun KSType.getJvmName(): String? { - return declaration.qualifiedName?.asString() -} +@Suppress("ObjectPropertyName") +internal val KSAnnotation._annotationType: KSType get() = annotationType.resolve() /** * Check if this type is an inline class. @@ -70,7 +63,7 @@ internal fun KSClassDeclaration.findSuperTypeReference(name: String): KSTypeRefe for (superType in this.superTypes) { val ksType = superType.resolve() - if (ksType.getJvmName() == name) { + if (ksType.declaration.qualifiedName?.asString() == name) { return superType } diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt index 5eda1ec55..2bd977b00 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt @@ -31,11 +31,12 @@ import org.ktorm.ksp.spi.ColumnMetadata import org.ktorm.schema.* internal fun KSPropertyDeclaration.getSqlType(resolver: Resolver): KSType? { - if ((_type.declaration as KSClassDeclaration).classKind == ClassKind.ENUM_CLASS) { + val declaration = _type.declaration as KSClassDeclaration + if (declaration.classKind == ClassKind.ENUM_CLASS) { return resolver.getClassDeclarationByName>()?.asType(emptyList()) } - val sqlType = when (_type.getJvmName()) { + val sqlType = when (declaration.qualifiedName?.asString()) { "kotlin.Boolean" -> BooleanSqlType::class "kotlin.Int" -> IntSqlType::class "kotlin.Short" -> ShortSqlType::class @@ -64,7 +65,7 @@ internal fun KSPropertyDeclaration.getSqlType(resolver: Resolver): KSType? { @OptIn(KotlinPoetKspPreview::class) internal fun ColumnMetadata.getRegisteringCodeBlock(): CodeBlock { - val sqlTypeName = sqlType.getJvmName() + val sqlTypeName = sqlType.declaration.qualifiedName?.asString() val registerFun = when (sqlTypeName) { "org.ktorm.schema.BooleanSqlType" -> MemberName("org.ktorm.schema", "boolean", true) "org.ktorm.schema.IntSqlType" -> MemberName("org.ktorm.schema", "int", true) From 3777883cc479daef77ebd00e1dd11032fa8126e2 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 3 Jul 2023 19:23:56 +0800 Subject: [PATCH 025/105] fix long method --- .../ksp/compiler/KtormProcessorProvider.kt | 3 + .../compiler/generator/TableClassGenerator.kt | 101 ++++++++++-------- 2 files changed, 60 insertions(+), 44 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt index 2b4f665ef..097f68a71 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt @@ -30,6 +30,9 @@ import org.ktorm.ksp.compiler.util.isValid import org.ktorm.ksp.spi.TableMetadata import kotlin.reflect.jvm.jvmName +/** + * Ktorm KSP symbol processor provider. + */ public class KtormProcessorProvider : SymbolProcessorProvider { override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt index 5f1b31dda..a407ffafb 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt @@ -18,6 +18,7 @@ package org.ktorm.ksp.compiler.generator import com.google.devtools.ksp.processing.SymbolProcessorEnvironment import com.google.devtools.ksp.symbol.ClassKind +import com.google.devtools.ksp.symbol.KSValueParameter import com.squareup.kotlinpoet.* import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview @@ -127,51 +128,9 @@ internal object TableClassGenerator { .any { it.hasDefault } if (hasDefaultValues && options["ktorm.allowReflection"] == "true") { - addStatement( - "val constructor = %T::class.%M!!", - table.entityClass.toClassName(), - MemberName("kotlin.reflect.full", "primaryConstructor", true) - ) - - add("«val args = mapOf(") - - for (column in table.columns) { - val propName = column.entityProperty.simpleName.asString() - if (propName in constructorParams) { - add( - "constructor.%M(%S)!! to row[this.%N],", - MemberName("kotlin.reflect.full", "findParameterByName", true), - propName, - column.columnPropertyName - ) - } - } - - add(")\n»") - addStatement("// Filter optional arguments out to make default values work.") - - if (table.columns.all { it.entityProperty.simpleName.asString() in constructorParams }) { - addStatement("return constructor.callBy(args.filterNot { (k, v) -> k.isOptional && v == null })") - } else { - addStatement("val entity = constructor.callBy(args.filterNot { (k, v) -> k.isOptional && v == null })") - } + createEntityByReflection(table, constructorParams) } else { - if (table.columns.all { it.entityProperty.simpleName.asString() in constructorParams }) { - add("«return·%T(", table.entityClass.toClassName()) - } else { - add("«val·entity·=·%T(", table.entityClass.toClassName()) - } - - for (column in table.columns) { - val parameter = constructorParams[column.entityProperty.simpleName.asString()] ?: continue - if (parameter._type.isMarkedNullable) { - add("%N·=·row[this.%N],", parameter.name!!.asString(), column.columnPropertyName) - } else { - add("%N·=·row[this.%N]!!,", parameter.name!!.asString(), column.columnPropertyName) - } - } - - add(")\n»") + createEntityByConstructor(table, constructorParams) } for (column in table.columns) { @@ -192,6 +151,60 @@ internal object TableClassGenerator { } } + private fun CodeBlock.Builder.createEntityByReflection( + table: TableMetadata, constructorParams: Map + ) { + addStatement( + "val constructor = %T::class.%M!!", + table.entityClass.toClassName(), + MemberName("kotlin.reflect.full", "primaryConstructor", true) + ) + + add("«val args = mapOf(") + + for (column in table.columns) { + val propName = column.entityProperty.simpleName.asString() + if (propName in constructorParams) { + add( + "constructor.%M(%S)!! to row[this.%N],", + MemberName("kotlin.reflect.full", "findParameterByName", true), + propName, + column.columnPropertyName + ) + } + } + + add(")\n»") + addStatement("// Filter optional arguments out to make default values work.") + + if (table.columns.all { it.entityProperty.simpleName.asString() in constructorParams }) { + addStatement("return constructor.callBy(args.filterNot { (k, v) -> k.isOptional && v == null })") + } else { + addStatement("val entity = constructor.callBy(args.filterNot { (k, v) -> k.isOptional && v == null })") + } + } + + private fun CodeBlock.Builder.createEntityByConstructor( + table: TableMetadata, constructorParams: Map + ) { + if (table.columns.all { it.entityProperty.simpleName.asString() in constructorParams }) { + add("«return·%T(", table.entityClass.toClassName()) + } else { + add("«val·entity·=·%T(", table.entityClass.toClassName()) + } + + for (column in table.columns) { + val parameter = constructorParams[column.entityProperty.simpleName.asString()] ?: continue + if (parameter._type.isMarkedNullable) { + add("%N·=·row[this.%N],", parameter.name!!.asString(), column.columnPropertyName) + } else { + add("%N·=·row[this.%N]!!,", parameter.name!!.asString(), column.columnPropertyName) + } + } + + add(")\n»") + } + private fun TypeSpec.Builder.configureAliasedFunction(table: TableMetadata): TypeSpec.Builder { val func = FunSpec.builder("aliased") .addKdoc( From 60fa150c685be4a0b6073702b91f1046788dc300 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 3 Jul 2023 19:34:51 +0800 Subject: [PATCH 026/105] fix code style --- .../ksp/compiler/parser/MetadataParser.kt | 45 ++++++++++--------- .../ksp/compiler/util/SqlTypeMappings.kt | 3 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index 04ac15a1f..feaf691ce 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -34,15 +34,15 @@ import java.util.* import kotlin.reflect.jvm.jvmName @OptIn(KspExperimental::class) -internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessorEnvironment) { - private val resolver = _resolver - private val options = _environment.options - private val databaseNamingStrategy = loadDatabaseNamingStrategy() - private val codingNamingStrategy = loadCodingNamingStrategy() - private val tablesCache = HashMap() +internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEnvironment) { + private val _resolver = resolver + private val _options = environment.options + private val _databaseNamingStrategy = loadDatabaseNamingStrategy() + private val _codingNamingStrategy = loadCodingNamingStrategy() + private val _tablesCache = HashMap() private fun loadDatabaseNamingStrategy(): DatabaseNamingStrategy { - val name = options["ktorm.dbNamingStrategy"] ?: "lower-snake-case" + val name = _options["ktorm.dbNamingStrategy"] ?: "lower-snake-case" if (name == "lower-snake-case") { return LowerSnakeCaseDatabaseNamingStrategy } @@ -59,7 +59,7 @@ internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessor } private fun loadCodingNamingStrategy(): CodingNamingStrategy { - val name = options["ktorm.codingNamingStrategy"] ?: return DefaultCodingNamingStrategy + val name = _options["ktorm.codingNamingStrategy"] ?: return DefaultCodingNamingStrategy try { val cls = Class.forName(name) @@ -70,7 +70,7 @@ internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessor } fun parseTableMetadata(cls: KSClassDeclaration): TableMetadata { - val r = tablesCache[cls.qualifiedName!!.asString()] + val r = _tablesCache[cls.qualifiedName!!.asString()] if (r != null) { return r } @@ -88,25 +88,26 @@ internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessor val table = cls.getAnnotationsByType(Table::class).first() val tableDef = TableMetadata( entityClass = cls, - name = table.name.ifEmpty { databaseNamingStrategy.getTableName(cls) }, + name = table.name.ifEmpty { _databaseNamingStrategy.getTableName(cls) }, alias = table.alias.takeIf { it.isNotEmpty() }, - catalog = table.catalog.ifEmpty { options["ktorm.catalog"] }?.takeIf { it.isNotEmpty() }, - schema = table.schema.ifEmpty { options["ktorm.schema"] }?.takeIf { it.isNotEmpty() }, - tableClassName = table.className.ifEmpty { codingNamingStrategy.getTableClassName(cls) }, - entitySequenceName = table.entitySequenceName.ifEmpty { codingNamingStrategy.getEntitySequenceName(cls) }, + catalog = table.catalog.ifEmpty { _options["ktorm.catalog"] }?.takeIf { it.isNotEmpty() }, + schema = table.schema.ifEmpty { _options["ktorm.schema"] }?.takeIf { it.isNotEmpty() }, + tableClassName = table.className.ifEmpty { _codingNamingStrategy.getTableClassName(cls) }, + entitySequenceName = table.entitySequenceName.ifEmpty { _codingNamingStrategy.getEntitySequenceName(cls) }, ignoreProperties = table.ignoreProperties.toSet(), columns = ArrayList() ) + val columns = tableDef.columns as MutableList for (property in cls.getProperties(tableDef.ignoreProperties)) { if (property.isAnnotationPresent(References::class)) { - (tableDef.columns as MutableList) += parseRefColumnMetadata(property, tableDef) + columns += parseRefColumnMetadata(property, tableDef) } else { - (tableDef.columns as MutableList) += parseColumnMetadata(property, tableDef) + columns += parseColumnMetadata(property, tableDef) } } - tablesCache[cls.qualifiedName!!.asString()] = tableDef + _tablesCache[cls.qualifiedName!!.asString()] = tableDef return tableDef } @@ -130,12 +131,12 @@ internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessor var name = column?.name if (name.isNullOrEmpty()) { - name = databaseNamingStrategy.getColumnName(table.entityClass, property) + name = _databaseNamingStrategy.getColumnName(table.entityClass, property) } var propertyName = column?.propertyName if (propertyName.isNullOrEmpty()) { - propertyName = codingNamingStrategy.getColumnPropertyName(table.entityClass, property) + propertyName = _codingNamingStrategy.getColumnPropertyName(table.entityClass, property) } return ColumnMetadata( @@ -163,7 +164,7 @@ internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessor } if (sqlType == null) { - sqlType = property.getSqlType(resolver) + sqlType = property.getSqlType(_resolver) } if (sqlType == null) { @@ -250,12 +251,12 @@ internal class MetadataParser(_resolver: Resolver, _environment: SymbolProcessor val reference = property.getAnnotationsByType(References::class).first() var name = reference.name if (name.isEmpty()) { - name = databaseNamingStrategy.getRefColumnName(table.entityClass, property, referenceTable) + name = _databaseNamingStrategy.getRefColumnName(table.entityClass, property, referenceTable) } var propertyName = reference.propertyName if (propertyName.isEmpty()) { - propertyName = codingNamingStrategy.getRefColumnPropertyName(table.entityClass, property, referenceTable) + propertyName = _codingNamingStrategy.getRefColumnPropertyName(table.entityClass, property, referenceTable) } return ColumnMetadata( diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt index 2bd977b00..92435fb14 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt @@ -108,8 +108,7 @@ internal fun ColumnMetadata.getRegisteringCodeBlock(): CodeBlock { if (declaration.classKind == ClassKind.OBJECT) { return CodeBlock.of("registerColumn(%S,·%T)", name, sqlType.toTypeName()) } else { - // TODO: create SqlType by constructor - return CodeBlock.of("registerColumn(%S,·%T)", name, sqlType.toTypeName()) + return CodeBlock.of("registerColumn(%S,·%T(TODO))", name, sqlType.toTypeName()) } } From 80999caa49657c2860c3832c83546cf1c8a1fa47 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 3 Jul 2023 19:39:47 +0800 Subject: [PATCH 027/105] fix code style --- .../ktorm/ksp/compiler/generator/AddFunctionGenerator.kt | 2 +- .../ktorm/ksp/compiler/generator/TableClassGenerator.kt | 9 +++++---- .../kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt | 6 +++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt index 9cb5ffb47..868794259 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt @@ -66,7 +66,7 @@ internal object AddFunctionGenerator { kdoc += "\n\n" + "Note that this function will obtain the generated primary key from the database and fill it into " + - "the property [${pkName}] after the insertion completes. But this requires us not to set " + + "the property [$pkName] after the insertion completes. But this requires us not to set " + "the primary key’s value beforehand, otherwise, if you do that, the given value will be " + "inserted into the database, and no keys generated." } diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt index a407ffafb..e7a989862 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt @@ -206,11 +206,12 @@ internal object TableClassGenerator { } private fun TypeSpec.Builder.configureAliasedFunction(table: TableMetadata): TypeSpec.Builder { + val kdoc = "" + + "Return a new-created table object with all properties (including the table name and columns " + + "and so on) being copied from this table, but applying a new alias given by the parameter." + val func = FunSpec.builder("aliased") - .addKdoc( - "Return a new-created table object with all properties (including the table name and columns " + - "and so on) being copied from this table, but applying a new alias given by the parameter." - ) + .addKdoc(kdoc) .addModifiers(KModifier.OVERRIDE) .addParameter("alias", typeNameOf()) .returns(ClassName(table.entityClass.packageName.asString(), table.tableClassName)) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt index 4a0858dbf..3d500a95b 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt @@ -25,19 +25,19 @@ import kotlin.reflect.jvm.jvmName /** * Return the resolved [KSType] of this property. */ -@Suppress("ObjectPropertyName") +@Suppress("ObjectPropertyName", "TopLevelPropertyNaming") internal val KSPropertyDeclaration._type: KSType get() = type.resolve() /** * Return the resolved [KSType] of this parameter. */ -@Suppress("ObjectPropertyName") +@Suppress("ObjectPropertyName", "TopLevelPropertyNaming") internal val KSValueParameter._type: KSType get() = type.resolve() /** * Return the resolved [KSType] of this annotation. */ -@Suppress("ObjectPropertyName") +@Suppress("ObjectPropertyName", "TopLevelPropertyNaming") internal val KSAnnotation._annotationType: KSType get() = annotationType.resolve() /** From c3d825c0575d69d8226f6c39155133eef059cf3c Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 3 Jul 2023 19:46:24 +0800 Subject: [PATCH 028/105] fix code style --- .../compiler/generator/CopyFunctionGenerator.kt | 9 +++++---- .../PseudoConstructorFunctionGenerator.kt | 10 +++++----- .../ktorm/ksp/compiler/parser/MetadataParser.kt | 14 ++++++-------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGenerator.kt index b4ef8cb46..60e0a7cea 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGenerator.kt @@ -25,11 +25,12 @@ import org.ktorm.ksp.spi.TableMetadata internal object CopyFunctionGenerator { fun generate(table: TableMetadata): FunSpec { + val kdoc = "" + + "Return a deep copy of this entity (which has the same property values and tracked statuses), " + + "and alter the specified property values. " + return FunSpec.builder("copy") - .addKdoc( - "Return a deep copy of this entity (which has the same property values and tracked statuses), " + - "and alter the specified property values. " - ) + .addKdoc(kdoc) .receiver(table.entityClass.toClassName()) .addParameters(PseudoConstructorFunctionGenerator.buildParameters(table).asIterable()) .returns(table.entityClass.toClassName()) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt index 7c79ab4be..458fe79d4 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt @@ -30,12 +30,12 @@ import org.ktorm.ksp.spi.TableMetadata internal object PseudoConstructorFunctionGenerator { fun generate(table: TableMetadata): FunSpec { + val kdoc = "" + + "Create an entity of [%L] and specify the initial values for each property, " + + "properties that doesn't have an initial value will leave unassigned. " + return FunSpec.builder(table.entityClass.simpleName.asString()) - .addKdoc( - "Create an entity of [%L] and specify the initial values for each property, " + - "properties that doesn't have an initial value will leave unassigned. ", - table.entityClass.simpleName.asString() - ) + .addKdoc(kdoc, table.entityClass.simpleName.asString()) .addParameters(buildParameters(table).asIterable()) .returns(table.entityClass.toClassName()) .addCode(buildFunctionBody(table)) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index feaf691ce..9fdf0964d 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -152,6 +152,7 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn } private fun parseColumnSqlType(property: KSPropertyDeclaration): KSType { + val propName = property.qualifiedName?.asString() var sqlType = property.annotations .filter { it._annotationType.declaration.qualifiedName?.asString() == Column::class.jvmName } .flatMap { it.arguments } @@ -168,18 +169,16 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn } if (sqlType == null) { - val name = property.qualifiedName?.asString() throw IllegalArgumentException( - "Parse sqlType error for property $name: cannot infer sqlType, please specify manually." + "Parse sqlType error for property $propName: cannot infer sqlType, please specify manually." ) } val declaration = sqlType.declaration as KSClassDeclaration if (declaration.classKind != OBJECT) { if (declaration.isAbstract()) { - val name = property.qualifiedName?.asString() throw IllegalArgumentException( - "Parse sqlType error for property $name: the sqlType class cannot be abstract." + "Parse sqlType error for property $propName: the sqlType class cannot be abstract." ) } @@ -189,11 +188,10 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn .any() if (!hasConstructor) { - val name = property.qualifiedName?.asString() - throw IllegalArgumentException( - "Parse sqlType error for property $name: the sqlType class must be a Kotlin singleton object or" + + val msg = "" + + "Parse sqlType error for property $propName: the sqlType must be a Kotlin singleton object or " + "a normal class with a constructor that accepts a single org.ktorm.schema.TypeReference argument." - ) + throw IllegalArgumentException(msg) } } From 6a8d997f87635df375c17f130438e2699ee7e4bf Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 3 Jul 2023 19:48:35 +0800 Subject: [PATCH 029/105] fix code style --- .../main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index 9fdf0964d..060ece4b1 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -41,6 +41,7 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn private val _codingNamingStrategy = loadCodingNamingStrategy() private val _tablesCache = HashMap() + @Suppress("SwallowedException") private fun loadDatabaseNamingStrategy(): DatabaseNamingStrategy { val name = _options["ktorm.dbNamingStrategy"] ?: "lower-snake-case" if (name == "lower-snake-case") { @@ -58,6 +59,7 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn } } + @Suppress("SwallowedException") private fun loadCodingNamingStrategy(): CodingNamingStrategy { val name = _options["ktorm.codingNamingStrategy"] ?: return DefaultCodingNamingStrategy From 214aed8e59b1a3d6846e2e0addb35e7d4269c360 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 3 Jul 2023 20:01:53 +0800 Subject: [PATCH 030/105] fix code style --- .../ksp/compiler/parser/MetadataParser.kt | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index 060ece4b1..80ea7bfd7 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -201,17 +201,16 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn } private fun parseRefColumnMetadata(property: KSPropertyDeclaration, table: TableMetadata): ColumnMetadata { + val propName = property.qualifiedName?.asString() if (property.isAnnotationPresent(Column::class)) { - val n = property.qualifiedName?.asString() throw IllegalStateException( - "Parse ref column error for property $n: @Column and @References cannot be used together." + "Parse ref column error for property $propName: @Column and @References cannot be used together." ) } if (table.entityClass.classKind != INTERFACE) { - val n = property.qualifiedName?.asString() throw IllegalStateException( - "Parse ref column error for property $n: @References can only be used in interface-based entities." + "Parse ref column error for property $propName: @References only allowed in interface-based entities." ) } @@ -219,32 +218,28 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn table.checkCircularRef(refEntityClass) if (refEntityClass.classKind != INTERFACE) { - val n = property.qualifiedName?.asString() throw IllegalStateException( - "Parse ref column error for property $n: the referenced entity class must be an interface." + "Parse ref column error for property $propName: the referenced entity class must be an interface." ) } if (!refEntityClass.isAnnotationPresent(Table::class)) { - val n = property.qualifiedName?.asString() throw IllegalStateException( - "Parse ref column error for property $n: the referenced entity class must be annotated with @Table." + "Parse ref column error for property $propName: the referenced entity must be annotated with @Table." ) } val referenceTable = parseTableMetadata(refEntityClass) val primaryKeys = referenceTable.columns.filter { it.isPrimaryKey } if (primaryKeys.isEmpty()) { - val n = property.qualifiedName?.asString() throw IllegalStateException( - "Parse ref column error for property $n: the referenced table doesn't have a primary key." + "Parse ref column error for property $propName: the referenced table doesn't have a primary key." ) } if (primaryKeys.size > 1) { - val n = property.qualifiedName?.asString() throw IllegalStateException( - "Parse ref column error for property $n: the referenced table cannot have compound primary keys." + "Parse ref column error for property $propName: the referenced table cannot have compound primary keys." ) } From 88fb1f2683acb2328e062d4ab898ced32f38aa0c Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 3 Jul 2023 20:23:12 +0800 Subject: [PATCH 031/105] refactor --- .../main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt | 3 ++- .../kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt index 3d500a95b..564c4b740 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:OptIn(KspExperimental::class) + package org.ktorm.ksp.compiler.util import com.google.devtools.ksp.KspExperimental @@ -43,7 +45,6 @@ internal val KSAnnotation._annotationType: KSType get() = annotationType.resolve /** * Check if this type is an inline class. */ -@OptIn(KspExperimental::class) internal fun KSType.isInline(): Boolean { val declaration = declaration as KSClassDeclaration return declaration.isAnnotationPresent(JvmInline::class) && declaration.modifiers.contains(Modifier.VALUE) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt index 92435fb14..2c6978b80 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:OptIn(KotlinPoetKspPreview::class) + package org.ktorm.ksp.compiler.util import com.google.devtools.ksp.getClassDeclarationByName @@ -63,7 +65,6 @@ internal fun KSPropertyDeclaration.getSqlType(resolver: Resolver): KSType? { return sqlType?.qualifiedName?.let { resolver.getClassDeclarationByName(it)?.asType(emptyList()) } } -@OptIn(KotlinPoetKspPreview::class) internal fun ColumnMetadata.getRegisteringCodeBlock(): CodeBlock { val sqlTypeName = sqlType.declaration.qualifiedName?.asString() val registerFun = when (sqlTypeName) { @@ -112,7 +113,6 @@ internal fun ColumnMetadata.getRegisteringCodeBlock(): CodeBlock { } } -@OptIn(KotlinPoetKspPreview::class) internal fun ColumnMetadata.getKotlinType(): TypeName { if (isReference) { return referenceTable!!.columns.single { it.isPrimaryKey }.getKotlinType() From 45155f417203f160f648c40453d060aa8b154ac5 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 8 Jul 2023 18:54:10 +0800 Subject: [PATCH 032/105] fix unit tests --- .../ksp/compiler/util/SqlTypeMappings.kt | 10 +++++-- .../org/ktorm/ksp/compiler/BaseKspTest.kt | 2 +- .../ksp/compiler/parser/MetadataParserTest.kt | 26 ++--------------- .../ktorm/ksp/compiler/parser/SqlTypeTest.kt | 28 ++++++------------- 4 files changed, 20 insertions(+), 46 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt index 2c6978b80..8ba2db614 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt @@ -28,6 +28,7 @@ import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.MemberName import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview +import com.squareup.kotlinpoet.ksp.toClassName import com.squareup.kotlinpoet.ksp.toTypeName import org.ktorm.ksp.spi.ColumnMetadata import org.ktorm.schema.* @@ -107,9 +108,14 @@ internal fun ColumnMetadata.getRegisteringCodeBlock(): CodeBlock { val declaration = sqlType.declaration as KSClassDeclaration if (declaration.classKind == ClassKind.OBJECT) { - return CodeBlock.of("registerColumn(%S,·%T)", name, sqlType.toTypeName()) + return CodeBlock.of("registerColumn(%S,·%T)", name, declaration.toClassName()) } else { - return CodeBlock.of("registerColumn(%S,·%T(TODO))", name, sqlType.toTypeName()) + return CodeBlock.of("registerColumn(%S,·%T(%M<%T>()))", + name, + declaration.toClassName(), + MemberName("org.ktorm.schema", "typeRef"), + getKotlinType() + ) } } diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/BaseKspTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/BaseKspTest.kt index d8b7e7014..c14da5f20 100644 --- a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/BaseKspTest.kt +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/BaseKspTest.kt @@ -71,7 +71,7 @@ abstract class BaseKspTest { import org.ktorm.database.* import org.ktorm.dsl.* import org.ktorm.entity.* - import org.ktorm.ksp.api.* + import org.ktorm.ksp.annotation.* lateinit var database: Database diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt index 9caa63eed..22d5b644b 100644 --- a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt @@ -123,28 +123,6 @@ class MetadataParserTest : BaseKspTest() { } """.trimIndent()) - @Test - fun testSqlTypeShouldBeObject() = kspFailing("Parse sqlType error for property User.name: the sqlType class must be a Kotlin singleton object.", """ - @Table - interface User : Entity { - val id: Int - @Column(sqlType = org.ktorm.schema.EnumSqlType::class) - val name: String - } - """.trimIndent()) - - @Test - fun testSqlTypeShouldBeSqlType() = kspFailing("Parse sqlType error for property User.name: the sqlType class must be subtype of SqlType/SqlTypeFactory.", """ - @Table - interface User : Entity { - val id: Int - @Column(sqlType = Test::class) - val name: String - } - - object Test - """.trimIndent()) - @Test fun testReferencesWithColumn() = kspFailing("Parse ref column error for property User.profile: @Column and @References cannot be used together.", """ @Table @@ -163,7 +141,7 @@ class MetadataParserTest : BaseKspTest() { """.trimIndent()) @Test - fun testReferencesFromClassEntity() = kspFailing("Parse ref column error for property User.profile: @References can only be used in interface-based entities", """ + fun testReferencesFromClassEntity() = kspFailing("Parse ref column error for property User.profile: @References only allowed in interface-based entities", """ @Table class User( val id: Int, @@ -195,7 +173,7 @@ class MetadataParserTest : BaseKspTest() { """.trimIndent()) @Test - fun testReferencesToNonTableClass() = kspFailing("Parse ref column error for property User.profile: the referenced entity class must be annotated with @Table", """ + fun testReferencesToNonTableClass() = kspFailing("Parse ref column error for property User.profile: the referenced entity must be annotated with @Table", """ @Table interface User : Entity { val id: Int diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/SqlTypeTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/SqlTypeTest.kt index e2b5eca48..a828114e0 100644 --- a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/SqlTypeTest.kt +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/SqlTypeTest.kt @@ -101,14 +101,14 @@ class SqlTypeTest : BaseKspTest() { """.trimIndent()) @Test - fun testCustomSqlTypeFactory() = runKotlin(""" + fun testCustomSqlTypeWithConstructor() = runKotlin(""" @Table data class User( @PrimaryKey var id: Int, var username: String, var age: Int, - @Column(sqlType = IntEnumSqlTypeFactory::class) + @Column(sqlType = IntEnumSqlType::class) var gender: Gender ) @@ -117,26 +117,16 @@ class SqlTypeTest : BaseKspTest() { FEMALE } - object IntEnumSqlTypeFactory : SqlTypeFactory { - + class IntEnumSqlType>(val enumClass: Class) : org.ktorm.schema.SqlType(Types.INTEGER, "int") { @Suppress("UNCHECKED_CAST") - override fun createSqlType(property: KProperty1<*, T?>): org.ktorm.schema.SqlType { - val returnType = property.returnType.jvmErasure.java - if (returnType.isEnum) { - return IntEnumSqlType(returnType as Class>) as org.ktorm.schema.SqlType - } else { - throw IllegalArgumentException("The property is required to be typed of enum but actually: ${"$"}returnType") - } - } + constructor(typeRef: org.ktorm.schema.TypeReference) : this(typeRef.referencedType as Class) - private class IntEnumSqlType>(val enumClass: Class) : org.ktorm.schema.SqlType(Types.INTEGER, "int") { - override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: E) { - ps.setInt(index, parameter.ordinal) - } + override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: E) { + ps.setInt(index, parameter.ordinal) + } - override fun doGetResult(rs: ResultSet, index: Int): E? { - return enumClass.enumConstants[rs.getInt(index)] - } + override fun doGetResult(rs: ResultSet, index: Int): E? { + return enumClass.enumConstants[rs.getInt(index)] } } From 2b9636f20d95ca3ee42c298964e5871d9bbe83be Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 8 Jul 2023 20:15:54 +0800 Subject: [PATCH 033/105] test generic --- .../ktorm/ksp/compiler/parser/SqlTypeTest.kt | 31 ++++++------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/SqlTypeTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/SqlTypeTest.kt index a828114e0..8b50e1fa4 100644 --- a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/SqlTypeTest.kt +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/SqlTypeTest.kt @@ -108,35 +108,24 @@ class SqlTypeTest : BaseKspTest() { var id: Int, var username: String, var age: Int, - @Column(sqlType = IntEnumSqlType::class) - var gender: Gender + @Column(sqlType = ExSqlType::class) + var ex: Map ) - enum class Gender { - MALE, - FEMALE - } - - class IntEnumSqlType>(val enumClass: Class) : org.ktorm.schema.SqlType(Types.INTEGER, "int") { - @Suppress("UNCHECKED_CAST") - constructor(typeRef: org.ktorm.schema.TypeReference) : this(typeRef.referencedType as Class) - - override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: E) { - ps.setInt(index, parameter.ordinal) + class ExSqlType(val typeRef: org.ktorm.schema.TypeReference) : org.ktorm.schema.SqlType(Types.OTHER, "json") { + override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: C) { + TODO("not implemented.") } - override fun doGetResult(rs: ResultSet, index: Int): E? { - return enumClass.enumConstants[rs.getInt(index)] + override fun doGetResult(rs: ResultSet, index: Int): C? { + TODO("not implemented.") } } fun run() { - assert(Users.gender.sqlType::class.simpleName == "IntEnumSqlType") - assert(Users.gender.sqlType.typeCode == Types.INTEGER) - assert(Users.gender.sqlType.typeName == "int") - - database.users.add(User(100, "Vincent", 28, Gender.MALE)) - assert(database.users.first { it.id eq 100 } == User(100, "Vincent", 28, Gender.MALE)) + assert(Users.ex.sqlType::class.simpleName == "ExSqlType") + assert(Users.ex.sqlType.typeCode == Types.OTHER) + assert(Users.ex.sqlType.typeName == "json") } """.trimIndent()) } From 9db1251d029e512f5eb13c4b49c0fe5552be1992 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 8 Jul 2023 20:27:36 +0800 Subject: [PATCH 034/105] add sqltype check test --- .../ksp/compiler/parser/MetadataParserTest.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt index 22d5b644b..cc0f95cfb 100644 --- a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt @@ -123,6 +123,42 @@ class MetadataParserTest : BaseKspTest() { } """.trimIndent()) + @Test + fun testAbstractSqlType() = kspFailing("Parse sqlType error for property User.ex: the sqlType class cannot be abstract.", """ + @Table + interface User : Entity { + @PrimaryKey + var id: Int + var name: String + @Column(sqlType = ExSqlType::class) + var ex: Map + } + + abstract class ExSqlType : org.ktorm.schema.SqlType(Types.OTHER, "json") + """.trimIndent()) + + @Test + fun testSqlTypeWithoutConstructor() = kspFailing("Parse sqlType error for property User.ex: the sqlType must be a Kotlin singleton object or a normal class with a constructor that accepts a single org.ktorm.schema.TypeReference argument.", """ + @Table + interface User : Entity { + @PrimaryKey + var id: Int + var name: String + @Column(sqlType = ExSqlType::class) + var ex: Map + } + + class ExSqlType : org.ktorm.schema.SqlType(Types.OTHER, "json") { + override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: Any) { + TODO("not implemented.") + } + + override fun doGetResult(rs: ResultSet, index: Int): Any? { + TODO("not implemented.") + } + } + """.trimIndent()) + @Test fun testReferencesWithColumn() = kspFailing("Parse ref column error for property User.profile: @Column and @References cannot be used together.", """ @Table From 8f5b6cf23507966f796690c43f56dea5278e7c4c Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 9 Jul 2023 23:15:09 +0800 Subject: [PATCH 035/105] format generated code by ktlint --- .../main/kotlin/org/ktorm/schema/BaseTable.kt | 3 +- .../ktorm-ksp-compiler.gradle.kts | 12 +++++-- .../ksp/compiler/KtormProcessorProvider.kt | 36 +++++++++++++------ .../ktorm-ksp-compiler/.editorconfig | 11 ++++++ .../generator/AddFunctionGeneratorTest.kt | 1 - 5 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 ktorm-ksp-compiler/src/main/resources/ktorm-ksp-compiler/.editorconfig diff --git a/ktorm-core/src/main/kotlin/org/ktorm/schema/BaseTable.kt b/ktorm-core/src/main/kotlin/org/ktorm/schema/BaseTable.kt index 2ad21514e..ec62f3db1 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/schema/BaseTable.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/schema/BaseTable.kt @@ -274,8 +274,9 @@ public abstract class BaseTable( stack.push(root.toString(withAlias = false)) if (tableName == root.tableName && catalog == root.catalog && schema == root.schema) { + val route = stack.asReversed().joinToString(separator = " --> ") throw IllegalStateException( - "Circular reference detected, current table: '$this', reference route: ${stack.asReversed()}" + "Circular reference detected, current table: '$this', reference route: $route" ) } diff --git a/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts b/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts index 4d440ca62..145366083 100644 --- a/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts +++ b/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts @@ -11,10 +11,16 @@ dependencies { implementation(project(":ktorm-ksp-spi")) implementation("com.google.devtools.ksp:symbol-processing-api:1.7.22-1.0.8") implementation("com.squareup:kotlinpoet-ksp:1.11.0") - implementation("com.facebook:ktfmt:0.40") implementation("org.atteo:evo-inflector:1.3") - testImplementation("com.github.tschuchortdev:kotlin-compile-testing:1.4.8") - testImplementation("com.github.tschuchortdev:kotlin-compile-testing-ksp:1.4.8") + implementation("com.pinterest.ktlint:ktlint-core:0.48.0") { + exclude(group = "org.jetbrains.kotlin", module = "kotlin-compiler-embeddable") + } + implementation("com.pinterest.ktlint:ktlint-ruleset-standard:0.48.0") { + exclude(group = "org.jetbrains.kotlin", module = "kotlin-compiler-embeddable") + } + + testImplementation("com.github.tschuchortdev:kotlin-compile-testing:1.4.9") + testImplementation("com.github.tschuchortdev:kotlin-compile-testing-ksp:1.4.9") testImplementation("com.h2database:h2:1.4.198") testImplementation("org.slf4j:slf4j-simple:1.7.25") } diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt index 097f68a71..a40e718e3 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt @@ -16,24 +16,36 @@ package org.ktorm.ksp.compiler -import com.facebook.ktfmt.format.Formatter -import com.facebook.ktfmt.format.FormattingOptions import com.google.devtools.ksp.processing.* import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSFile +import com.pinterest.ktlint.core.KtLintRuleEngine +import com.pinterest.ktlint.core.RuleSetProviderV2 +import com.pinterest.ktlint.core.api.EditorConfigDefaults import com.squareup.kotlinpoet.FileSpec +import org.ec4j.core.EditorConfigLoader +import org.ec4j.core.Resource.Resources import org.ktorm.ksp.annotation.Table import org.ktorm.ksp.compiler.generator.FileGenerator import org.ktorm.ksp.compiler.parser.MetadataParser import org.ktorm.ksp.compiler.util.isValid import org.ktorm.ksp.spi.TableMetadata +import java.util.* import kotlin.reflect.jvm.jvmName /** * Ktorm KSP symbol processor provider. */ public class KtormProcessorProvider : SymbolProcessorProvider { + private val ktLintRuleEngine = KtLintRuleEngine( + ruleProviders = ServiceLoader.load(RuleSetProviderV2::class.java).flatMap { it.getRuleProviders() }.toSet(), + editorConfigDefaults = EditorConfigDefaults( + EditorConfigLoader.default_().load( + Resources.ofClassPath(javaClass.classLoader, "/ktorm-ksp-compiler/.editorconfig", Charsets.UTF_8) + ) + ) + ) override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { for (generator in FileGenerator.extCodeGenerators) { @@ -65,7 +77,7 @@ public class KtormProcessorProvider : SymbolProcessorProvider { // Generate file spec by kotlinpoet. val fileSpec = FileGenerator.generate(table, environment) - // Beautify the generated code by facebook ktfmt. + // Beautify the generated code by ktlint. val formattedCode = formatCode(fileSpec, environment.logger) // Output the formatted code. @@ -75,17 +87,19 @@ public class KtormProcessorProvider : SymbolProcessorProvider { } private fun formatCode(fileSpec: FileSpec, logger: KSPLogger): String { - // Use the Kotlin official code style. - val options = FormattingOptions(style = FormattingOptions.Style.GOOGLE, maxWidth = 120, blockIndent = 4) - - // Remove tailing commas in parameter lists. - val code = fileSpec.toString().replace(Regex(""",\s*\)"""), ")") - try { - return Formatter.format(options, code) + // Manually fix some code styles before formatting. + val code = fileSpec.toString() + .replace(Regex("""\(\s*"""), "(") + .replace(Regex("""\s*\)"""), ")") + .replace(Regex(""",\s*"""), ", ") + .replace(Regex(""",\s*\)"""), ")") + .replace(Regex("""\s*get\(\)\s="""), " get() =") + + return ktLintRuleEngine.format(code) } catch (e: Exception) { logger.exception(e) - return code + return fileSpec.toString() } } diff --git a/ktorm-ksp-compiler/src/main/resources/ktorm-ksp-compiler/.editorconfig b/ktorm-ksp-compiler/src/main/resources/ktorm-ksp-compiler/.editorconfig new file mode 100644 index 000000000..c0238f544 --- /dev/null +++ b/ktorm-ksp-compiler/src/main/resources/ktorm-ksp-compiler/.editorconfig @@ -0,0 +1,11 @@ +# ktlint config used to format the generated code. +[*.{kt,kts}] +ktlint_code_style = official +indent_size = 4 +indent_style = space +max_line_length = 120 +insert_final_newline = true +ktlint_function_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than = 4 +ktlint_function_signature_body_expression_wrapping = multiline +ij_kotlin_allow_trailing_comma = false +ij_kotlin_allow_trailing_comma_on_call_site = false diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGeneratorTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGeneratorTest.kt index d96205024..cd0520217 100644 --- a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGeneratorTest.kt +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGeneratorTest.kt @@ -24,7 +24,6 @@ class AddFunctionGeneratorTest : BaseKspTest() { assert(users[1] == User(id = 2, username = "lucy", age = 22)) assert(users[2] == User(id = 3, username = "mike", age = 22)) assert(users[3] == User(id = 4, username = "test", age = 100)) - } """.trimIndent()) From 4acae28dcf510f8edb9dfa032d043bba8a68c6ed Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 9 Jul 2023 23:33:05 +0800 Subject: [PATCH 036/105] fix ext code generator test --- .../{ => META-INF}/services/org.ktorm.ksp.spi.ExtCodeGenerator | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ktorm-ksp-compiler/src/test/resources/{ => META-INF}/services/org.ktorm.ksp.spi.ExtCodeGenerator (100%) diff --git a/ktorm-ksp-compiler/src/test/resources/services/org.ktorm.ksp.spi.ExtCodeGenerator b/ktorm-ksp-compiler/src/test/resources/META-INF/services/org.ktorm.ksp.spi.ExtCodeGenerator similarity index 100% rename from ktorm-ksp-compiler/src/test/resources/services/org.ktorm.ksp.spi.ExtCodeGenerator rename to ktorm-ksp-compiler/src/test/resources/META-INF/services/org.ktorm.ksp.spi.ExtCodeGenerator From d5a0b249081c9a44f219925a08e161adabccc256 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 10 Jul 2023 10:29:06 +0800 Subject: [PATCH 037/105] fix detekt issue --- .../kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt index a40e718e3..f246dcf1c 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt @@ -96,7 +96,7 @@ public class KtormProcessorProvider : SymbolProcessorProvider { .replace(Regex(""",\s*\)"""), ")") .replace(Regex("""\s*get\(\)\s="""), " get() =") - return ktLintRuleEngine.format(code) + return ktLintRuleEngine.format(code) } catch (e: Exception) { logger.exception(e) return fileSpec.toString() From 4d67dfde5728525a39b32562cb442bc32e261193 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 15 Jul 2023 09:39:36 +0800 Subject: [PATCH 038/105] fix getGeneratedKey --- ktorm-core/src/main/kotlin/org/ktorm/dsl/Dml.kt | 2 +- .../ktorm/ksp/compiler/generator/AddFunctionGenerator.kt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ktorm-core/src/main/kotlin/org/ktorm/dsl/Dml.kt b/ktorm-core/src/main/kotlin/org/ktorm/dsl/Dml.kt index fca3d6307..bb3268e99 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/dsl/Dml.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/dsl/Dml.kt @@ -195,7 +195,7 @@ public fun > Database.insertAndGenerateKey(table: T, block: Ass /** * Get generated key from the row set. */ -internal fun CachedRowSet.getGeneratedKey(primaryKey: Column): T? { +public fun CachedRowSet.getGeneratedKey(primaryKey: Column): T? { if (metaData.columnCount == 1) { return primaryKey.sqlType.getResult(this, 1) } diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt index 868794259..00e097ab4 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt @@ -165,8 +165,7 @@ internal object AddFunctionGenerator { format = """ val (effects, rowSet) = database.executeUpdateAndRetrieveKeys(expression) if (rowSet.next()) { - // TODO: use CachedRowSet.getGeneratedKey - val generatedKey = sourceTable.%columnName:N.sqlType.getResult(rowSet, 1) + val generatedKey = rowSet.%getGeneratedKey:M(sourceTable.%columnName:N) if (generatedKey != null) { if (database.logger.isDebugEnabled()) { database.logger.debug("Generated Key: ${'$'}generatedKey") @@ -182,7 +181,8 @@ internal object AddFunctionGenerator { arguments = mapOf( "columnName" to primaryKeys[0].columnPropertyName, - "propertyName" to primaryKeys[0].entityProperty.simpleName.asString() + "propertyName" to primaryKeys[0].entityProperty.simpleName.asString(), + "getGeneratedKey" to MemberName("org.ktorm.dsl", "getGeneratedKey", true) ) ) From cb48aab1815fbe799eed08fd7b2b8733c847e545 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 15 Jul 2023 22:30:01 +0800 Subject: [PATCH 039/105] generate refs class --- .../ksp/compiler/generator/FileGenerator.kt | 5 ++++ .../compiler/generator/RefsClassGenerator.kt | 20 ++++++++++++++++ .../generator/RefsPropertyGenerator.kt | 23 +++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt index cd3e2d144..36fb33d39 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt @@ -36,6 +36,11 @@ internal object FileGenerator { .addProperty(EntitySequencePropertyGenerator.generate(table)) if (table.entityClass.classKind == ClassKind.INTERFACE) { + if (table.columns.any { it.isReference }) { + fileSpec.addProperty(RefsPropertyGenerator.generate(table)) + fileSpec.addType(RefsClassGenerator.generate(table)) + } + fileSpec.addFunction(PseudoConstructorFunctionGenerator.generate(table)) fileSpec.addFunction(CopyFunctionGenerator.generate(table)) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt new file mode 100644 index 000000000..aadc5f7be --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt @@ -0,0 +1,20 @@ +package org.ktorm.ksp.compiler.generator + +import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.FunSpec +import com.squareup.kotlinpoet.TypeSpec +import org.ktorm.ksp.spi.TableMetadata + +/** + * Created by vince at Jul 15, 2023. + */ +internal object RefsClassGenerator { + + fun generate(table: TableMetadata): TypeSpec { + val tableClass = ClassName(table.entityClass.packageName.asString(), table.tableClassName) + return TypeSpec.classBuilder("${table.tableClassName}Refs") + .addKdoc("Wrapper class that provides a convenient way to access reference tables.") + .primaryConstructor(FunSpec.constructorBuilder().addParameter("t", tableClass).build()) + .build() + } +} \ No newline at end of file diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt new file mode 100644 index 000000000..7680258ce --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt @@ -0,0 +1,23 @@ +package org.ktorm.ksp.compiler.generator + +import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.FunSpec +import com.squareup.kotlinpoet.PropertySpec +import org.ktorm.ksp.spi.TableMetadata + +/** + * Created by vince at Jul 15, 2023. + */ +internal object RefsPropertyGenerator { + + fun generate(table: TableMetadata): PropertySpec { + val tableClass = ClassName(table.entityClass.packageName.asString(), table.tableClassName) + val refsClass = ClassName(table.entityClass.packageName.asString(), "${table.tableClassName}Refs") + + return PropertySpec.builder("refs", refsClass) + .addKdoc("Return the refs object that provides a convenient way to access reference tables.") + .receiver(tableClass) + .getter(FunSpec.getterBuilder().addStatement("return·%T(this)", refsClass).build()) + .build() + } +} \ No newline at end of file From bf2acff01247eff849fecbb1ceac43b608aabf34 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 16 Jul 2023 11:34:26 +0800 Subject: [PATCH 040/105] property name for refs --- .../kotlin/org/ktorm/ksp/annotation/References.kt | 9 +++++++++ .../main/kotlin/org/ktorm/ksp/annotation/Table.kt | 2 +- .../org/ktorm/ksp/compiler/parser/MetadataParser.kt | 12 ++++++++++-- .../kotlin/org/ktorm/ksp/compiler/util/Namings.kt | 6 ++++++ .../kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt | 5 +++++ .../main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt | 7 ++++++- 6 files changed, 37 insertions(+), 4 deletions(-) diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt index 03f2c5e94..a24173eff 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt @@ -52,4 +52,13 @@ public annotation class References( * an implementation class name of `org.ktorm.ksp.spi.CodingNamingStrategy`. */ val propertyName: String = "", + + /** + * The name of the corresponding property in the Refs wrapper class. + * + * If not specified, the name will be the annotated property's name. This behavior can be configured by KSP option + * `ktorm.codingNamingStrategy`, which accepts an implementation class name of + * `org.ktorm.ksp.spi.CodingNamingStrategy`. + */ + val propertyNameForRefs: String = "", ) diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt index a51e61f4f..e5105a492 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt @@ -80,5 +80,5 @@ public annotation class Table( /** * Specify properties that should be ignored for generating column definitions. */ - val ignoreProperties: Array = [] + val ignoreProperties: Array = [], ) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index 80ea7bfd7..ee59790dd 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -149,7 +149,8 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn sqlType = parseColumnSqlType(property), isReference = false, referenceTable = null, - columnPropertyName = propertyName + columnPropertyName = propertyName, + columnPropertyNameForRefs = null ) } @@ -254,6 +255,12 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn propertyName = _codingNamingStrategy.getRefColumnPropertyName(table.entityClass, property, referenceTable) } + var propertyNameForRefs = reference.propertyNameForRefs + if (propertyNameForRefs.isEmpty()) { + propertyNameForRefs = _codingNamingStrategy + .getRefColumnPropertyNameForRefs(table.entityClass, property, referenceTable) + } + return ColumnMetadata( entityProperty = property, table = table, @@ -262,7 +269,8 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn sqlType = primaryKeys[0].sqlType, isReference = true, referenceTable = referenceTable, - columnPropertyName = propertyName + columnPropertyName = propertyName, + columnPropertyNameForRefs = propertyNameForRefs ) } diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt index e0b715d93..1619bdd4e 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt @@ -75,6 +75,12 @@ internal object DefaultCodingNamingStrategy : CodingNamingStrategy { val pk = ref.columns.single { it.isPrimaryKey } return prop.simpleName.asString() + pk.columnPropertyName.replaceFirstChar { it.uppercase() } } + + override fun getRefColumnPropertyNameForRefs( + c: KSClassDeclaration, prop: KSPropertyDeclaration, ref: TableMetadata + ): String { + return prop.simpleName.asString() + } } internal object CamelCase { diff --git a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt index 69f6b9a13..cf0fb3919 100644 --- a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt +++ b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt @@ -43,4 +43,9 @@ public interface CodingNamingStrategy { * Generate the reference column property name. */ public fun getRefColumnPropertyName(c: KSClassDeclaration, prop: KSPropertyDeclaration, ref: TableMetadata): String + + /** + * Generate the property name in the Refs wrapper class. + */ + public fun getRefColumnPropertyNameForRefs(c: KSClassDeclaration, prop: KSPropertyDeclaration, ref: TableMetadata): String } diff --git a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt index 9d4019366..2343fa513 100644 --- a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt +++ b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt @@ -62,5 +62,10 @@ public data class ColumnMetadata( /** * The name of the corresponding column property in the generated table class. */ - val columnPropertyName: String + val columnPropertyName: String, + + /** + * The name of the corresponding property in the Refs wrapper class. + */ + val columnPropertyNameForRefs: String? ) From 6321d110ab024e40387be8e387a2548e886eeaea Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 16 Jul 2023 15:46:09 +0800 Subject: [PATCH 041/105] generate ref table property --- .../compiler/generator/RefsClassGenerator.kt | 25 ++++++++++++++----- .../generator/RefsPropertyGenerator.kt | 2 +- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt index aadc5f7be..4c8161774 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt @@ -1,8 +1,6 @@ package org.ktorm.ksp.compiler.generator -import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.FunSpec -import com.squareup.kotlinpoet.TypeSpec +import com.squareup.kotlinpoet.* import org.ktorm.ksp.spi.TableMetadata /** @@ -12,9 +10,24 @@ internal object RefsClassGenerator { fun generate(table: TableMetadata): TypeSpec { val tableClass = ClassName(table.entityClass.packageName.asString(), table.tableClassName) - return TypeSpec.classBuilder("${table.tableClassName}Refs") - .addKdoc("Wrapper class that provides a convenient way to access reference tables.") + + val typeSpec = TypeSpec.classBuilder("${table.tableClassName}Refs") + .addKdoc("Wrapper class that provides a convenient way to access referenced tables.") .primaryConstructor(FunSpec.constructorBuilder().addParameter("t", tableClass).build()) - .build() + + for (column in table.columns) { + val propertyNameForRefs = column.columnPropertyNameForRefs ?: continue + val refTable = column.referenceTable ?: continue + val refTableClass = ClassName(refTable.entityClass.packageName.asString(), refTable.tableClassName) + + val propertySpec = PropertySpec.builder(propertyNameForRefs, refTableClass) + .addKdoc("Return the referenced table [${refTable.tableClassName}].") + .initializer(CodeBlock.of("t.%N.referenceTable as %T", column.columnPropertyName, refTableClass)) + .build() + + typeSpec.addProperty(propertySpec) + } + + return typeSpec.build() } } \ No newline at end of file diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt index 7680258ce..c87a065c1 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt @@ -15,7 +15,7 @@ internal object RefsPropertyGenerator { val refsClass = ClassName(table.entityClass.packageName.asString(), "${table.tableClassName}Refs") return PropertySpec.builder("refs", refsClass) - .addKdoc("Return the refs object that provides a convenient way to access reference tables.") + .addKdoc("Return the refs object that provides a convenient way to access referenced tables.") .receiver(tableClass) .getter(FunSpec.getterBuilder().addStatement("return·%T(this)", refsClass).build()) .build() From c2968e8879945cd70fa57c3bdf7c18fe9ad6f17d Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 16 Jul 2023 15:59:56 +0800 Subject: [PATCH 042/105] rename --- .../org/ktorm/ksp/annotation/References.kt | 4 ++-- .../compiler/generator/RefsClassGenerator.kt | 3 +-- .../ksp/compiler/parser/MetadataParser.kt | 21 +++++++++---------- .../org/ktorm/ksp/compiler/util/Namings.kt | 2 +- .../org/ktorm/ksp/spi/CodingNamingStrategy.kt | 4 ++-- .../org/ktorm/ksp/spi/ColumnMetadata.kt | 4 ++-- 6 files changed, 18 insertions(+), 20 deletions(-) diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt index a24173eff..b38a7e5bf 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt @@ -54,11 +54,11 @@ public annotation class References( val propertyName: String = "", /** - * The name of the corresponding property in the Refs wrapper class. + * The name of the corresponding referenced table property in the Refs wrapper class. * * If not specified, the name will be the annotated property's name. This behavior can be configured by KSP option * `ktorm.codingNamingStrategy`, which accepts an implementation class name of * `org.ktorm.ksp.spi.CodingNamingStrategy`. */ - val propertyNameForRefs: String = "", + val refTablePropertyName: String = "", ) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt index 4c8161774..26af09f52 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt @@ -16,11 +16,10 @@ internal object RefsClassGenerator { .primaryConstructor(FunSpec.constructorBuilder().addParameter("t", tableClass).build()) for (column in table.columns) { - val propertyNameForRefs = column.columnPropertyNameForRefs ?: continue val refTable = column.referenceTable ?: continue val refTableClass = ClassName(refTable.entityClass.packageName.asString(), refTable.tableClassName) - val propertySpec = PropertySpec.builder(propertyNameForRefs, refTableClass) + val propertySpec = PropertySpec.builder(column.refTablePropertyName!!, refTableClass) .addKdoc("Return the referenced table [${refTable.tableClassName}].") .initializer(CodeBlock.of("t.%N.referenceTable as %T", column.columnPropertyName, refTableClass)) .build() diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index ee59790dd..98ffac5d3 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -150,7 +150,7 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn isReference = false, referenceTable = null, columnPropertyName = propertyName, - columnPropertyNameForRefs = null + refTablePropertyName = null ) } @@ -230,8 +230,8 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn ) } - val referenceTable = parseTableMetadata(refEntityClass) - val primaryKeys = referenceTable.columns.filter { it.isPrimaryKey } + val refTable = parseTableMetadata(refEntityClass) + val primaryKeys = refTable.columns.filter { it.isPrimaryKey } if (primaryKeys.isEmpty()) { throw IllegalStateException( "Parse ref column error for property $propName: the referenced table doesn't have a primary key." @@ -247,18 +247,17 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn val reference = property.getAnnotationsByType(References::class).first() var name = reference.name if (name.isEmpty()) { - name = _databaseNamingStrategy.getRefColumnName(table.entityClass, property, referenceTable) + name = _databaseNamingStrategy.getRefColumnName(table.entityClass, property, refTable) } var propertyName = reference.propertyName if (propertyName.isEmpty()) { - propertyName = _codingNamingStrategy.getRefColumnPropertyName(table.entityClass, property, referenceTable) + propertyName = _codingNamingStrategy.getRefColumnPropertyName(table.entityClass, property, refTable) } - var propertyNameForRefs = reference.propertyNameForRefs - if (propertyNameForRefs.isEmpty()) { - propertyNameForRefs = _codingNamingStrategy - .getRefColumnPropertyNameForRefs(table.entityClass, property, referenceTable) + var refTablePropertyName = reference.refTablePropertyName + if (refTablePropertyName.isEmpty()) { + refTablePropertyName = _codingNamingStrategy.getRefTablePropertyName(table.entityClass, property, refTable) } return ColumnMetadata( @@ -268,9 +267,9 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn isPrimaryKey = property.isAnnotationPresent(PrimaryKey::class), sqlType = primaryKeys[0].sqlType, isReference = true, - referenceTable = referenceTable, + referenceTable = refTable, columnPropertyName = propertyName, - columnPropertyNameForRefs = propertyNameForRefs + refTablePropertyName = refTablePropertyName ) } diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt index 1619bdd4e..3172f66f2 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt @@ -76,7 +76,7 @@ internal object DefaultCodingNamingStrategy : CodingNamingStrategy { return prop.simpleName.asString() + pk.columnPropertyName.replaceFirstChar { it.uppercase() } } - override fun getRefColumnPropertyNameForRefs( + override fun getRefTablePropertyName( c: KSClassDeclaration, prop: KSPropertyDeclaration, ref: TableMetadata ): String { return prop.simpleName.asString() diff --git a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt index cf0fb3919..ecf1b9db6 100644 --- a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt +++ b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt @@ -45,7 +45,7 @@ public interface CodingNamingStrategy { public fun getRefColumnPropertyName(c: KSClassDeclaration, prop: KSPropertyDeclaration, ref: TableMetadata): String /** - * Generate the property name in the Refs wrapper class. + * Generate the name of the referenced table property in the Refs wrapper class. */ - public fun getRefColumnPropertyNameForRefs(c: KSClassDeclaration, prop: KSPropertyDeclaration, ref: TableMetadata): String + public fun getRefTablePropertyName(c: KSClassDeclaration, prop: KSPropertyDeclaration, ref: TableMetadata): String } diff --git a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt index 2343fa513..acc9cb2a3 100644 --- a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt +++ b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt @@ -65,7 +65,7 @@ public data class ColumnMetadata( val columnPropertyName: String, /** - * The name of the corresponding property in the Refs wrapper class. + * The name of the corresponding referenced table property in the Refs wrapper class. */ - val columnPropertyNameForRefs: String? + val refTablePropertyName: String? ) From a78354639bea509c3372792e776b96cc9278300d Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 16 Jul 2023 17:18:24 +0800 Subject: [PATCH 043/105] generate refs class --- .../org/ktorm/ksp/compiler/KtormProcessorProvider.kt | 2 ++ .../ksp/compiler/generator/RefsClassGenerator.kt | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt index f246dcf1c..c9aa0010f 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt @@ -95,6 +95,8 @@ public class KtormProcessorProvider : SymbolProcessorProvider { .replace(Regex(""",\s*"""), ", ") .replace(Regex(""",\s*\)"""), ")") .replace(Regex("""\s*get\(\)\s="""), " get() =") + .replace(Regex("""\s+=\s+"""), " = ") + .replace("import org.ktorm.ksp.`annotation`", "import org.ktorm.ksp.annotation") return ktLintRuleEngine.format(code) } catch (e: Exception) { diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt index 26af09f52..1395ad3d8 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt @@ -2,6 +2,7 @@ package org.ktorm.ksp.compiler.generator import com.squareup.kotlinpoet.* import org.ktorm.ksp.spi.TableMetadata +import org.ktorm.schema.Table /** * Created by vince at Jul 15, 2023. @@ -27,6 +28,17 @@ internal object RefsClassGenerator { typeSpec.addProperty(propertySpec) } + val funSpec = FunSpec.builder("toList") + .addKdoc("Return all referenced tables as a list.") + .returns(typeNameOf>>()) + .addCode("return·listOf(") + + for (column in table.columns) { + val refTablePropertyName = column.refTablePropertyName ?: continue + funSpec.addCode("%N, ", refTablePropertyName) + } + + typeSpec.addFunction(funSpec.addCode(")").build()) return typeSpec.build() } } \ No newline at end of file From efd67119d648d96365e7d24fb3e62110509e5408 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 16 Jul 2023 17:51:24 +0800 Subject: [PATCH 044/105] fix code style --- .../compiler/generator/AddFunctionGenerator.kt | 17 ++++++++--------- .../compiler/generator/RefsClassGenerator.kt | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt index 00e097ab4..443bb2df8 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt @@ -76,17 +76,16 @@ internal object AddFunctionGenerator { internal fun checkForDml(): CodeBlock { val code = """ - val isModified = - expression.where != null || - expression.groupBy.isNotEmpty() || - expression.having != null || - expression.isDistinct || - expression.orderBy.isNotEmpty() || - expression.offset != null || - expression.limit != null + val isModified = expression.where != null + || expression.groupBy.isNotEmpty() + || expression.having != null + || expression.isDistinct + || expression.orderBy.isNotEmpty() + || expression.offset != null + || expression.limit != null if (isModified) { - val msg = + val msg = "" + "Entity manipulation functions are not supported by this sequence object. " + "Please call on the origin sequence returned from database.sequenceOf(table)" throw UnsupportedOperationException(msg) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt index 1395ad3d8..ce97545b3 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt @@ -21,7 +21,7 @@ internal object RefsClassGenerator { val refTableClass = ClassName(refTable.entityClass.packageName.asString(), refTable.tableClassName) val propertySpec = PropertySpec.builder(column.refTablePropertyName!!, refTableClass) - .addKdoc("Return the referenced table [${refTable.tableClassName}].") + .addKdoc("Return the referenced table of [${table.tableClassName}.${column.columnPropertyName}].") .initializer(CodeBlock.of("t.%N.referenceTable as %T", column.columnPropertyName, refTableClass)) .build() From 89343369798134eba331d4c62f8b92f519534403 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 16 Jul 2023 18:02:50 +0800 Subject: [PATCH 045/105] fix code style --- .../kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt index c9aa0010f..5b2c5f98a 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt @@ -94,7 +94,7 @@ public class KtormProcessorProvider : SymbolProcessorProvider { .replace(Regex("""\s*\)"""), ")") .replace(Regex(""",\s*"""), ", ") .replace(Regex(""",\s*\)"""), ")") - .replace(Regex("""\s*get\(\)\s="""), " get() =") + .replace(Regex("""\s+get\(\)\s="""), " get() =") .replace(Regex("""\s+=\s+"""), " = ") .replace("import org.ktorm.ksp.`annotation`", "import org.ktorm.ksp.annotation") From 3bf7c08a59399932a5ecb71d82f8ddadf0ebe3a5 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 16 Jul 2023 19:08:56 +0800 Subject: [PATCH 046/105] test refs --- .../generator/RefsClassGeneratorTest.kt | 47 +++++++++++++++++++ .../src/test/resources/drop-ksp-data.sql | 1 + .../src/test/resources/init-ksp-data.sql | 10 ++++ 3 files changed, 58 insertions(+) create mode 100644 ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGeneratorTest.kt diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGeneratorTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGeneratorTest.kt new file mode 100644 index 000000000..f3f331087 --- /dev/null +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGeneratorTest.kt @@ -0,0 +1,47 @@ +package org.ktorm.ksp.compiler.generator + +import org.junit.Test +import org.ktorm.ksp.compiler.BaseKspTest + +/** + * Created by vince at Jul 16, 2023. + */ +class RefsClassGeneratorTest : BaseKspTest() { + + @Test + fun testRefs() = runKotlin( + """ + @Table + interface Employee: Entity { + @PrimaryKey + var id: Int + var name: String + var job: String + var managerId: Int? + var hireDate: LocalDate + var salary: Long + @References + var department: Department + } + + @Table + interface Department: Entity { + @PrimaryKey + var id: Int + var name: String + var location: String + } + + fun run() { + val employees = database.employees + .filter { it.refs.department.name eq "tech" } + .filter { it.refs.department.location eq "Guangzhou" } + .sortedBy { it.id } + .toList() + + assert(employees.size == 2) + assert(employees[0].name == "vince") + assert(employees[1].name == "marry") + } + """.trimIndent()) +} \ No newline at end of file diff --git a/ktorm-ksp-compiler/src/test/resources/drop-ksp-data.sql b/ktorm-ksp-compiler/src/test/resources/drop-ksp-data.sql index 72e77692a..08b01358e 100644 --- a/ktorm-ksp-compiler/src/test/resources/drop-ksp-data.sql +++ b/ktorm-ksp-compiler/src/test/resources/drop-ksp-data.sql @@ -1,3 +1,4 @@ drop table if exists "user"; drop table if exists "employee"; +drop table if exists "department"; drop table if exists "province"; diff --git a/ktorm-ksp-compiler/src/test/resources/init-ksp-data.sql b/ktorm-ksp-compiler/src/test/resources/init-ksp-data.sql index 112e7518b..462c05b39 100644 --- a/ktorm-ksp-compiler/src/test/resources/init-ksp-data.sql +++ b/ktorm-ksp-compiler/src/test/resources/init-ksp-data.sql @@ -32,6 +32,16 @@ values ('vince', 'engineer', null, '2018-01-01', 100, 1), ('tom', 'director', null, '2018-01-01', 200, 2), ('penny', 'assistant', 3, '2019-01-01', 100, 2); +create table "department"( + "id" int not null primary key auto_increment, + "name" varchar(128) not null, + "location" varchar(128) not null, + "mixedCase" varchar(128) +); + +insert into "department"("name", "location") values ('tech', 'Guangzhou'); +insert into "department"("name", "location") values ('finance', 'Beijing'); + create table "province" ( "country" varchar(128) not null, From 4a122ffcf68fa946e8c0e3952e92fcd1e3479253 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 16 Jul 2023 21:14:05 +0800 Subject: [PATCH 047/105] fix detekt issues --- .../compiler/generator/RefsClassGenerator.kt | 18 +++++++- .../generator/RefsPropertyGenerator.kt | 18 +++++++- .../ksp/compiler/parser/MetadataParser.kt | 42 ++++++++----------- 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt index ce97545b3..b1d8a2616 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.ktorm.ksp.compiler.generator import com.squareup.kotlinpoet.* @@ -41,4 +57,4 @@ internal object RefsClassGenerator { typeSpec.addFunction(funSpec.addCode(")").build()) return typeSpec.build() } -} \ No newline at end of file +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt index c87a065c1..d0a278fc1 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.ktorm.ksp.compiler.generator import com.squareup.kotlinpoet.ClassName @@ -20,4 +36,4 @@ internal object RefsPropertyGenerator { .getter(FunSpec.getterBuilder().addStatement("return·%T(this)", refsClass).build()) .build() } -} \ No newline at end of file +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index 98ffac5d3..80329e673 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -172,17 +172,15 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn } if (sqlType == null) { - throw IllegalArgumentException( - "Parse sqlType error for property $propName: cannot infer sqlType, please specify manually." - ) + val msg = "Parse sqlType error for property $propName: cannot infer sqlType, please specify manually." + throw IllegalArgumentException(msg) } val declaration = sqlType.declaration as KSClassDeclaration if (declaration.classKind != OBJECT) { if (declaration.isAbstract()) { - throw IllegalArgumentException( - "Parse sqlType error for property $propName: the sqlType class cannot be abstract." - ) + val msg = "Parse sqlType error for property $propName: the sqlType class cannot be abstract." + throw IllegalArgumentException(msg) } val hasConstructor = declaration.getConstructors() @@ -204,44 +202,41 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn private fun parseRefColumnMetadata(property: KSPropertyDeclaration, table: TableMetadata): ColumnMetadata { val propName = property.qualifiedName?.asString() if (property.isAnnotationPresent(Column::class)) { - throw IllegalStateException( - "Parse ref column error for property $propName: @Column and @References cannot be used together." - ) + val msg = "Parse ref column error for property $propName: @Column and @References cannot be used together." + throw IllegalStateException(msg) } if (table.entityClass.classKind != INTERFACE) { - throw IllegalStateException( + val msg = "Parse ref column error for property $propName: @References only allowed in interface-based entities." - ) + throw IllegalStateException(msg) } val refEntityClass = property._type.declaration as KSClassDeclaration table.checkCircularRef(refEntityClass) if (refEntityClass.classKind != INTERFACE) { - throw IllegalStateException( - "Parse ref column error for property $propName: the referenced entity class must be an interface." - ) + val msg = "Parse ref column error for property $propName: the referenced entity class must be an interface." + throw IllegalStateException(msg) } if (!refEntityClass.isAnnotationPresent(Table::class)) { - throw IllegalStateException( + val msg = "Parse ref column error for property $propName: the referenced entity must be annotated with @Table." - ) + throw IllegalStateException(msg) } val refTable = parseTableMetadata(refEntityClass) val primaryKeys = refTable.columns.filter { it.isPrimaryKey } if (primaryKeys.isEmpty()) { - throw IllegalStateException( - "Parse ref column error for property $propName: the referenced table doesn't have a primary key." - ) + val msg = "Parse ref column error for property $propName: the referenced table doesn't have a primary key." + throw IllegalStateException(msg) } if (primaryKeys.size > 1) { - throw IllegalStateException( + val msg = "Parse ref column error for property $propName: the referenced table cannot have compound primary keys." - ) + throw IllegalStateException(msg) } val reference = property.getAnnotationsByType(References::class).first() @@ -281,9 +276,8 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn if (className == refClassName) { val route = stack.asReversed().joinToString(separator = " --> ") - throw IllegalStateException( - "Circular reference is not allowed, current table: $className, reference route: $route." - ) + val msg = "Circular reference is not allowed, current table: $className, reference route: $route." + throw IllegalStateException(msg) } val refTable = ref.getAnnotationsByType(Table::class).firstOrNull() From a9fdcf670da49daffc279533ce8e6884d072b94d Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 6 Aug 2023 10:46:20 +0800 Subject: [PATCH 048/105] add log --- .../kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt | 3 +++ .../kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt | 2 ++ 2 files changed, 5 insertions(+) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt index 36fb33d39..db98a361e 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt @@ -28,6 +28,9 @@ internal object FileGenerator { val extCodeGenerators = ServiceLoader.load(ExtCodeGenerator::class.java).toList() fun generate(table: TableMetadata, environment: SymbolProcessorEnvironment): FileSpec { + val fileName = table.entityClass.packageName.asString().replace('.', '/') + table.tableClassName + ".kt" + environment.logger.info("[ktorm-ksp-compiler] generate file: $fileName") + val fileSpec = FileSpec.builder(table.entityClass.packageName.asString(), table.tableClassName) .addFileComment("Auto-generated by ktorm-ksp-compiler, DO NOT EDIT!") .addAnnotation( diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index 80329e673..650b58825 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -37,6 +37,7 @@ import kotlin.reflect.jvm.jvmName internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEnvironment) { private val _resolver = resolver private val _options = environment.options + private val _logger = environment.logger private val _databaseNamingStrategy = loadDatabaseNamingStrategy() private val _codingNamingStrategy = loadCodingNamingStrategy() private val _tablesCache = HashMap() @@ -87,6 +88,7 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn throw IllegalStateException("$name must extends from org.ktorm.entity.Entity.") } + _logger.info("[ktorm-ksp-compiler] parse table metadata for entity: ${cls.qualifiedName!!.asString()}") val table = cls.getAnnotationsByType(Table::class).first() val tableDef = TableMetadata( entityClass = cls, From 2f27c68bf328dde9109038aa73a843dec5ad94e7 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 6 Aug 2023 16:59:20 +0800 Subject: [PATCH 049/105] load ktlint standard rule set manually --- .../kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt index 5b2c5f98a..6095f0ea8 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt @@ -21,8 +21,8 @@ import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSFile import com.pinterest.ktlint.core.KtLintRuleEngine -import com.pinterest.ktlint.core.RuleSetProviderV2 import com.pinterest.ktlint.core.api.EditorConfigDefaults +import com.pinterest.ktlint.ruleset.standard.StandardRuleSetProvider import com.squareup.kotlinpoet.FileSpec import org.ec4j.core.EditorConfigLoader import org.ec4j.core.Resource.Resources @@ -39,7 +39,8 @@ import kotlin.reflect.jvm.jvmName */ public class KtormProcessorProvider : SymbolProcessorProvider { private val ktLintRuleEngine = KtLintRuleEngine( - ruleProviders = ServiceLoader.load(RuleSetProviderV2::class.java).flatMap { it.getRuleProviders() }.toSet(), + // ruleProviders = ServiceLoader.load(RuleSetProviderV2::class.java).flatMap { it.getRuleProviders() }.toSet(), + ruleProviders = StandardRuleSetProvider().getRuleProviders(), editorConfigDefaults = EditorConfigDefaults( EditorConfigLoader.default_().load( Resources.ofClassPath(javaClass.classLoader, "/ktorm-ksp-compiler/.editorconfig", Charsets.UTF_8) From 9ae41cbf67142a758f57e0c20025b3189596d21d Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 6 Aug 2023 17:18:30 +0800 Subject: [PATCH 050/105] fix service loader class loader in ksp envrionment --- .../org/ktorm/ksp/compiler/KtormProcessorProvider.kt | 8 +++++--- .../org/ktorm/ksp/compiler/generator/FileGenerator.kt | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt index 6095f0ea8..169794bc6 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt @@ -21,8 +21,8 @@ import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSFile import com.pinterest.ktlint.core.KtLintRuleEngine +import com.pinterest.ktlint.core.RuleSetProviderV2 import com.pinterest.ktlint.core.api.EditorConfigDefaults -import com.pinterest.ktlint.ruleset.standard.StandardRuleSetProvider import com.squareup.kotlinpoet.FileSpec import org.ec4j.core.EditorConfigLoader import org.ec4j.core.Resource.Resources @@ -39,8 +39,10 @@ import kotlin.reflect.jvm.jvmName */ public class KtormProcessorProvider : SymbolProcessorProvider { private val ktLintRuleEngine = KtLintRuleEngine( - // ruleProviders = ServiceLoader.load(RuleSetProviderV2::class.java).flatMap { it.getRuleProviders() }.toSet(), - ruleProviders = StandardRuleSetProvider().getRuleProviders(), + ruleProviders = ServiceLoader + .load(RuleSetProviderV2::class.java, javaClass.classLoader) + .flatMap { it.getRuleProviders() } + .toSet(), editorConfigDefaults = EditorConfigDefaults( EditorConfigLoader.default_().load( Resources.ofClassPath(javaClass.classLoader, "/ktorm-ksp-compiler/.editorconfig", Charsets.UTF_8) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt index db98a361e..8815c7a97 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt @@ -25,7 +25,7 @@ import org.ktorm.ksp.spi.TableMetadata import java.util.* internal object FileGenerator { - val extCodeGenerators = ServiceLoader.load(ExtCodeGenerator::class.java).toList() + val extCodeGenerators = ServiceLoader.load(ExtCodeGenerator::class.java, javaClass.classLoader).toList() fun generate(table: TableMetadata, environment: SymbolProcessorEnvironment): FileSpec { val fileName = table.entityClass.packageName.asString().replace('.', '/') + table.tableClassName + ".kt" From bae463d7ac87ddb504273ce9323ee908fff28642 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 6 Aug 2023 17:43:58 +0800 Subject: [PATCH 051/105] fix log --- .../kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt | 2 +- .../main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt index 8815c7a97..9fd230996 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt @@ -28,7 +28,7 @@ internal object FileGenerator { val extCodeGenerators = ServiceLoader.load(ExtCodeGenerator::class.java, javaClass.classLoader).toList() fun generate(table: TableMetadata, environment: SymbolProcessorEnvironment): FileSpec { - val fileName = table.entityClass.packageName.asString().replace('.', '/') + table.tableClassName + ".kt" + val fileName = table.entityClass.packageName.asString().replace('.', '/') + "/" + table.tableClassName + ".kt" environment.logger.info("[ktorm-ksp-compiler] generate file: $fileName") val fileSpec = FileSpec.builder(table.entityClass.packageName.asString(), table.tableClassName) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index 650b58825..a4bd5cab1 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -88,7 +88,7 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn throw IllegalStateException("$name must extends from org.ktorm.entity.Entity.") } - _logger.info("[ktorm-ksp-compiler] parse table metadata for entity: ${cls.qualifiedName!!.asString()}") + _logger.info("[ktorm-ksp-compiler] parse table metadata from entity: ${cls.qualifiedName!!.asString()}") val table = cls.getAnnotationsByType(Table::class).first() val tableDef = TableMetadata( entityClass = cls, From 7e430e036e350f8e3640b04da1ef427e94946156 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 13 Aug 2023 17:21:20 +0800 Subject: [PATCH 052/105] init maven plugin module --- ...ktorm-ksp-compiler-maven-plugin.gradle.kts | 12 +++++++ .../maven/KtormKspMavenPluginExtension.kt | 31 +++++++++++++++++++ settings.gradle.kts | 1 + 3 files changed, 44 insertions(+) create mode 100644 ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts create mode 100644 ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt diff --git a/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts b/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts new file mode 100644 index 000000000..fc700e364 --- /dev/null +++ b/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts @@ -0,0 +1,12 @@ + +plugins { + id("ktorm.base") + id("ktorm.publish") + id("ktorm.source-header-check") +} + +dependencies { + compileOnly(kotlin("maven-plugin")) + compileOnly("org.apache.maven:maven-core:3.9.3") + implementation("com.google.devtools.ksp:symbol-processing:1.7.22-1.0.8") +} diff --git a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt new file mode 100644 index 000000000..d2de2d32e --- /dev/null +++ b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt @@ -0,0 +1,31 @@ +package org.ktorm.ksp.compiler.maven + +import org.apache.maven.plugin.MojoExecution +import org.apache.maven.plugin.MojoExecutionException +import org.apache.maven.project.MavenProject +import org.apache.maven.repository.RepositorySystem +import org.codehaus.plexus.component.annotations.Component +import org.codehaus.plexus.component.annotations.Requirement +import org.jetbrains.kotlin.maven.KotlinMavenPluginExtension +import org.jetbrains.kotlin.maven.PluginOption + +/** + * Extension that enables KSP for the kotlin maven plugin + */ +@Component(role = KotlinMavenPluginExtension::class, hint = "ksp") +public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { + @Requirement + private lateinit var repositorySystem: RepositorySystem + + override fun getCompilerPluginId(): String { + return "com.google.devtools.ksp.symbol-processing" + } + + override fun isApplicable(project: MavenProject, execution: MojoExecution): Boolean { + return true + } + + override fun getPluginOptions(project: MavenProject, execution: MojoExecution): List { + throw MojoExecutionException("test ktorm ksp") + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 1a5d4b011..76766f334 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,6 +8,7 @@ include("ktorm-global") include("ktorm-jackson") include("ktorm-ksp-annotations") include("ktorm-ksp-compiler") +include("ktorm-ksp-compiler-maven-plugin") include("ktorm-ksp-spi") include("ktorm-support-mysql") include("ktorm-support-oracle") From ef8838ef28400987b4541981a03f61d621d40921 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 13 Aug 2023 18:09:36 +0800 Subject: [PATCH 053/105] use ksp cmdline --- .../ktorm-ksp-compiler-maven-plugin.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts b/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts index fc700e364..2b56e90f0 100644 --- a/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts +++ b/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts @@ -8,5 +8,5 @@ plugins { dependencies { compileOnly(kotlin("maven-plugin")) compileOnly("org.apache.maven:maven-core:3.9.3") - implementation("com.google.devtools.ksp:symbol-processing:1.7.22-1.0.8") + implementation("com.google.devtools.ksp:symbol-processing-cmdline:1.7.22-1.0.8") } From eeb62b7bfd542c0fc889b6242dd3eab1ee80cdbb Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 13 Aug 2023 20:55:06 +0800 Subject: [PATCH 054/105] download ktlint programatically --- .../maven/KtormKspMavenPluginExtension.kt | 8 +++++++- .../resources/META-INF/plexus/components.xml | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 ktorm-ksp-compiler-maven-plugin/src/main/resources/META-INF/plexus/components.xml diff --git a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt index d2de2d32e..4b162531f 100644 --- a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt +++ b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt @@ -1,5 +1,6 @@ package org.ktorm.ksp.compiler.maven +import org.apache.maven.artifact.resolver.ArtifactResolutionRequest import org.apache.maven.plugin.MojoExecution import org.apache.maven.plugin.MojoExecutionException import org.apache.maven.project.MavenProject @@ -26,6 +27,11 @@ public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { } override fun getPluginOptions(project: MavenProject, execution: MojoExecution): List { - throw MojoExecutionException("test ktorm ksp") + val request = ArtifactResolutionRequest() + request.artifact = repositorySystem.createArtifactWithClassifier("com.pinterest", "ktlint", "0.50.0", "jar", "all") + request.remoteRepositories = project.remoteArtifactRepositories + + val resolved = repositorySystem.resolve(request) + throw MojoExecutionException("test ktorm ksp: ${resolved.artifacts.map { it.file }}") } } diff --git a/ktorm-ksp-compiler-maven-plugin/src/main/resources/META-INF/plexus/components.xml b/ktorm-ksp-compiler-maven-plugin/src/main/resources/META-INF/plexus/components.xml new file mode 100644 index 000000000..831c70493 --- /dev/null +++ b/ktorm-ksp-compiler-maven-plugin/src/main/resources/META-INF/plexus/components.xml @@ -0,0 +1,17 @@ + + + + + org.jetbrains.kotlin.maven.KotlinMavenPluginExtension + ksp + org.ktorm.ksp.compiler.maven.KtormKspMavenPluginExtension + false + + + org.apache.maven.repository.RepositorySystem + repositorySystem + + + + + From ea6b7b2804ae6154156fbac87dc98bcc72199e70 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 14 Aug 2023 23:06:25 +0800 Subject: [PATCH 055/105] parse user optionns --- .../maven/KtormKspMavenPluginExtension.kt | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt index 4b162531f..9a1810ac3 100644 --- a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt +++ b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt @@ -1,8 +1,7 @@ package org.ktorm.ksp.compiler.maven -import org.apache.maven.artifact.resolver.ArtifactResolutionRequest +import com.google.devtools.ksp.KspCliOption import org.apache.maven.plugin.MojoExecution -import org.apache.maven.plugin.MojoExecutionException import org.apache.maven.project.MavenProject import org.apache.maven.repository.RepositorySystem import org.codehaus.plexus.component.annotations.Component @@ -27,11 +26,24 @@ public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { } override fun getPluginOptions(project: MavenProject, execution: MojoExecution): List { - val request = ArtifactResolutionRequest() - request.artifact = repositorySystem.createArtifactWithClassifier("com.pinterest", "ktlint", "0.50.0", "jar", "all") - request.remoteRepositories = project.remoteArtifactRepositories +// val request = ArtifactResolutionRequest() +// request.artifact = repositorySystem.createArtifactWithClassifier("com.pinterest", "ktlint", "0.50.0", "jar", "all") +// request.remoteRepositories = project.remoteArtifactRepositories +// +// val resolved = repositorySystem.resolve(request) +// throw MojoExecutionException("test ktorm ksp: ${resolved.artifacts.map { it.file }}") + return emptyList() + } + + private fun parseUserOptions(execution: MojoExecution): Map> { + val pluginOptions = execution.configuration.getChild("pluginOptions") ?: return emptyMap() + val availableOptions = KspCliOption.values().associateBy { it.optionName } + val pattern = Regex("([^:]+):([^=]+)=(.*)") - val resolved = repositorySystem.resolve(request) - throw MojoExecutionException("test ktorm ksp: ${resolved.artifacts.map { it.file }}") + return pluginOptions.children + .mapNotNull { pattern.matchEntire(it.value) } + .map { it.destructured } + .filter { (plugin, key, _) -> plugin == "ksp" && key in availableOptions } + .groupBy({ (_, key, _) -> availableOptions[key]!! }, { (_, _, value) -> value }) } } From bed742173d6e6cd3001d0a4d3c1dd8fbd5129a83 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 20 Aug 2023 16:46:40 +0800 Subject: [PATCH 056/105] build ksp options --- ...ktorm-ksp-compiler-maven-plugin.gradle.kts | 2 + .../maven/KtormKspMavenPluginExtension.kt | 63 ++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts b/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts index 2b56e90f0..0f7549ffd 100644 --- a/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts +++ b/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts @@ -7,6 +7,8 @@ plugins { dependencies { compileOnly(kotlin("maven-plugin")) + compileOnly(kotlin("compiler")) compileOnly("org.apache.maven:maven-core:3.9.3") implementation("com.google.devtools.ksp:symbol-processing-cmdline:1.7.22-1.0.8") + implementation(project(":ktorm-ksp-compiler")) } diff --git a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt index 9a1810ac3..e0229c298 100644 --- a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt +++ b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt @@ -1,6 +1,7 @@ package org.ktorm.ksp.compiler.maven import com.google.devtools.ksp.KspCliOption +import org.apache.maven.artifact.resolver.ArtifactResolutionRequest import org.apache.maven.plugin.MojoExecution import org.apache.maven.project.MavenProject import org.apache.maven.repository.RepositorySystem @@ -8,6 +9,7 @@ import org.codehaus.plexus.component.annotations.Component import org.codehaus.plexus.component.annotations.Requirement import org.jetbrains.kotlin.maven.KotlinMavenPluginExtension import org.jetbrains.kotlin.maven.PluginOption +import java.io.File /** * Extension that enables KSP for the kotlin maven plugin @@ -22,7 +24,7 @@ public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { } override fun isApplicable(project: MavenProject, execution: MojoExecution): Boolean { - return true + return execution.mojoDescriptor.goal == "compile" || execution.mojoDescriptor.goal == "test-compile" } override fun getPluginOptions(project: MavenProject, execution: MojoExecution): List { @@ -32,7 +34,8 @@ public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { // // val resolved = repositorySystem.resolve(request) // throw MojoExecutionException("test ktorm ksp: ${resolved.artifacts.map { it.file }}") - return emptyList() + val options = buildDefaultOptions(project, execution) + return options.map { (option, value) -> PluginOption("ksp", compilerPluginId, option.optionName, value) } } private fun parseUserOptions(execution: MojoExecution): Map> { @@ -46,4 +49,60 @@ public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { .filter { (plugin, key, _) -> plugin == "ksp" && key in availableOptions } .groupBy({ (_, key, _) -> availableOptions[key]!! }, { (_, _, value) -> value }) } + + private fun buildDefaultOptions(project: MavenProject, execution: MojoExecution): Map { + val baseDir = project.basedir.path + val buildDir = project.build.directory + + if (execution.mojoDescriptor.goal == "compile") { + return mapOf( + KspCliOption.CLASS_OUTPUT_DIR_OPTION to project.build.outputDirectory, + KspCliOption.JAVA_OUTPUT_DIR_OPTION to path(buildDir, "generated-sources", "ksp-java"), + KspCliOption.KOTLIN_OUTPUT_DIR_OPTION to path(buildDir, "generated-sources", "ksp"), + KspCliOption.RESOURCE_OUTPUT_DIR_OPTION to project.build.outputDirectory, + KspCliOption.CACHES_DIR_OPTION to path(buildDir, "kspCaches"), + KspCliOption.PROJECT_BASE_DIR_OPTION to baseDir, + KspCliOption.KSP_OUTPUT_DIR_OPTION to path(buildDir, "ksp"), + KspCliOption.PROCESSOR_CLASSPATH_OPTION to buildProcessorClasspath(project, execution), + KspCliOption.WITH_COMPILATION_OPTION to "true" + ) + } + + if (execution.mojoDescriptor.goal == "test-compile") { + return mapOf( + KspCliOption.CLASS_OUTPUT_DIR_OPTION to project.build.testOutputDirectory, + KspCliOption.JAVA_OUTPUT_DIR_OPTION to path(buildDir, "generated-test-sources", "ksp-java"), + KspCliOption.KOTLIN_OUTPUT_DIR_OPTION to path(buildDir, "generated-test-sources", "ksp"), + KspCliOption.RESOURCE_OUTPUT_DIR_OPTION to project.build.testOutputDirectory, + KspCliOption.CACHES_DIR_OPTION to path(buildDir, "kspCaches"), + KspCliOption.PROJECT_BASE_DIR_OPTION to baseDir, + KspCliOption.KSP_OUTPUT_DIR_OPTION to path(buildDir, "ksp-test"), + KspCliOption.PROCESSOR_CLASSPATH_OPTION to buildProcessorClasspath(project, execution), + KspCliOption.WITH_COMPILATION_OPTION to "true" + ) + } + + return emptyMap() + } + + private fun path(parent: String, vararg children: String): String { + val file = children.fold(File(parent)) { acc, child -> File(acc, child) } + return file.path + } + + private fun buildProcessorClasspath(project: MavenProject, execution: MojoExecution): String { + val files = ArrayList() + for (dependency in execution.plugin.dependencies) { + val request = ArtifactResolutionRequest() + request.artifact = repositorySystem.createDependencyArtifact(dependency) + request.localRepository = repositorySystem.createDefaultLocalRepository() + request.remoteRepositories = project.pluginArtifactRepositories + request.isResolveTransitively = true + + val resolved = repositorySystem.resolve(request) + files += resolved.artifacts.mapNotNull { it.file }.filter { it.exists() } + } + + return files.joinToString(File.pathSeparator) { it.path } + } } From aa22bb3d1000bec1bd5d0f79909a1c2513411d98 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 20 Aug 2023 21:56:17 +0800 Subject: [PATCH 057/105] upgrade to kotlin 1.9.0 --- .github/workflows/build.yml | 2 +- buildSrc/build.gradle.kts | 6 ++--- .../src/main/kotlin/ktorm.base.gradle.kts | 4 ++-- .../kotlin/ktorm.tuples-codegen.gradle.kts | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- ktorm-jackson/ktorm-jackson.gradle.kts | 2 +- ...ktorm-ksp-compiler-maven-plugin.gradle.kts | 2 +- .../maven/KtormKspMavenPluginExtension.kt | 22 ++++++++++++++----- .../ktorm-ksp-compiler.gradle.kts | 10 ++++----- .../ksp/compiler/KtormProcessorProvider.kt | 11 +++++----- ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts | 2 +- settings.gradle.kts | 2 +- 12 files changed, 39 insertions(+), 28 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 637261b0d..24d9d052e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: true matrix: - java: [8, 11, 17, 19] + java: [8, 11, 17, 20] steps: - name: Checkout Code uses: actions/checkout@v3 diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index e624db5df..9c56d76a6 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,6 +1,6 @@ plugins { - id("org.gradle.kotlin.kotlin-dsl") version "2.4.1" + `kotlin-dsl` } repositories { @@ -9,7 +9,7 @@ repositories { } dependencies { - api("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.22") + api("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0") api("org.moditect:moditect-gradle-plugin:1.0.0-rc3") - api("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.20.0") + api("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.1") } diff --git a/buildSrc/src/main/kotlin/ktorm.base.gradle.kts b/buildSrc/src/main/kotlin/ktorm.base.gradle.kts index 227aa9b72..ae3c5af8a 100644 --- a/buildSrc/src/main/kotlin/ktorm.base.gradle.kts +++ b/buildSrc/src/main/kotlin/ktorm.base.gradle.kts @@ -20,8 +20,8 @@ dependencies { } detekt { - source = files("src/main/kotlin") - config = files("${project.rootDir}/detekt.yml") + source.from("src/main/kotlin") + config.from("${project.rootDir}/detekt.yml") } tasks { diff --git a/buildSrc/src/main/kotlin/ktorm.tuples-codegen.gradle.kts b/buildSrc/src/main/kotlin/ktorm.tuples-codegen.gradle.kts index 57c0a7ffc..6e4cdf009 100644 --- a/buildSrc/src/main/kotlin/ktorm.tuples-codegen.gradle.kts +++ b/buildSrc/src/main/kotlin/ktorm.tuples-codegen.gradle.kts @@ -3,7 +3,7 @@ plugins { id("kotlin") } -val generatedSourceDir = "${project.buildDir.absolutePath}/generated/source/main/kotlin" +val generatedSourceDir = "${project.layout.buildDirectory.asFile.get()}/generated/source/main/kotlin" val maxTupleNumber = 9 fun generateTuple(writer: java.io.Writer, tupleNumber: Int) { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f42e62f37..27313fbc8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/ktorm-jackson/ktorm-jackson.gradle.kts b/ktorm-jackson/ktorm-jackson.gradle.kts index 06c086ce5..7827835c8 100644 --- a/ktorm-jackson/ktorm-jackson.gradle.kts +++ b/ktorm-jackson/ktorm-jackson.gradle.kts @@ -13,7 +13,7 @@ dependencies { api("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.3") } -val generatedSourceDir = "${project.buildDir.absolutePath}/generated/source/main/kotlin" +val generatedSourceDir = "${project.layout.buildDirectory.asFile.get()}/generated/source/main/kotlin" val generatePackageVersion by tasks.registering(Copy::class) { from("src/main/kotlin/org/ktorm/jackson/PackageVersion.kt.tmpl") diff --git a/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts b/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts index 0f7549ffd..7a0794b0a 100644 --- a/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts +++ b/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts @@ -9,6 +9,6 @@ dependencies { compileOnly(kotlin("maven-plugin")) compileOnly(kotlin("compiler")) compileOnly("org.apache.maven:maven-core:3.9.3") - implementation("com.google.devtools.ksp:symbol-processing-cmdline:1.7.22-1.0.8") + implementation("com.google.devtools.ksp:symbol-processing-cmdline:1.9.0-1.0.13") implementation(project(":ktorm-ksp-compiler")) } diff --git a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt index e0229c298..cf7c6a2fd 100644 --- a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt +++ b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.ktorm.ksp.compiler.maven import com.google.devtools.ksp.KspCliOption @@ -28,12 +44,6 @@ public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { } override fun getPluginOptions(project: MavenProject, execution: MojoExecution): List { -// val request = ArtifactResolutionRequest() -// request.artifact = repositorySystem.createArtifactWithClassifier("com.pinterest", "ktlint", "0.50.0", "jar", "all") -// request.remoteRepositories = project.remoteArtifactRepositories -// -// val resolved = repositorySystem.resolve(request) -// throw MojoExecutionException("test ktorm ksp: ${resolved.artifacts.map { it.file }}") val options = buildDefaultOptions(project, execution) return options.map { (option, value) -> PluginOption("ksp", compilerPluginId, option.optionName, value) } } diff --git a/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts b/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts index 145366083..34bcaaeed 100644 --- a/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts +++ b/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts @@ -9,18 +9,18 @@ dependencies { implementation(project(":ktorm-core")) implementation(project(":ktorm-ksp-annotations")) implementation(project(":ktorm-ksp-spi")) - implementation("com.google.devtools.ksp:symbol-processing-api:1.7.22-1.0.8") + implementation("com.google.devtools.ksp:symbol-processing-api:1.9.0-1.0.13") implementation("com.squareup:kotlinpoet-ksp:1.11.0") implementation("org.atteo:evo-inflector:1.3") - implementation("com.pinterest.ktlint:ktlint-core:0.48.0") { + implementation("com.pinterest.ktlint:ktlint-rule-engine:0.50.0") { exclude(group = "org.jetbrains.kotlin", module = "kotlin-compiler-embeddable") } - implementation("com.pinterest.ktlint:ktlint-ruleset-standard:0.48.0") { + implementation("com.pinterest.ktlint:ktlint-ruleset-standard:0.50.0") { exclude(group = "org.jetbrains.kotlin", module = "kotlin-compiler-embeddable") } - testImplementation("com.github.tschuchortdev:kotlin-compile-testing:1.4.9") - testImplementation("com.github.tschuchortdev:kotlin-compile-testing-ksp:1.4.9") + testImplementation("com.github.tschuchortdev:kotlin-compile-testing:1.5.0") + testImplementation("com.github.tschuchortdev:kotlin-compile-testing-ksp:1.5.0") testImplementation("com.h2database:h2:1.4.198") testImplementation("org.slf4j:slf4j-simple:1.7.25") } diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt index 169794bc6..75f1ddb55 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt @@ -20,9 +20,10 @@ import com.google.devtools.ksp.processing.* import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSFile -import com.pinterest.ktlint.core.KtLintRuleEngine -import com.pinterest.ktlint.core.RuleSetProviderV2 -import com.pinterest.ktlint.core.api.EditorConfigDefaults +import com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3 +import com.pinterest.ktlint.rule.engine.api.Code +import com.pinterest.ktlint.rule.engine.api.EditorConfigDefaults +import com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine import com.squareup.kotlinpoet.FileSpec import org.ec4j.core.EditorConfigLoader import org.ec4j.core.Resource.Resources @@ -40,7 +41,7 @@ import kotlin.reflect.jvm.jvmName public class KtormProcessorProvider : SymbolProcessorProvider { private val ktLintRuleEngine = KtLintRuleEngine( ruleProviders = ServiceLoader - .load(RuleSetProviderV2::class.java, javaClass.classLoader) + .load(RuleSetProviderV3::class.java, javaClass.classLoader) .flatMap { it.getRuleProviders() } .toSet(), editorConfigDefaults = EditorConfigDefaults( @@ -101,7 +102,7 @@ public class KtormProcessorProvider : SymbolProcessorProvider { .replace(Regex("""\s+=\s+"""), " = ") .replace("import org.ktorm.ksp.`annotation`", "import org.ktorm.ksp.annotation") - return ktLintRuleEngine.format(code) + return ktLintRuleEngine.format(Code.fromSnippet(code)) } catch (e: Exception) { logger.exception(e) return fileSpec.toString() diff --git a/ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts b/ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts index 3bbbfa191..86f5b1ce5 100644 --- a/ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts +++ b/ktorm-ksp-spi/ktorm-ksp-spi.gradle.kts @@ -6,6 +6,6 @@ plugins { } dependencies { - api("com.google.devtools.ksp:symbol-processing-api:1.7.22-1.0.8") + api("com.google.devtools.ksp:symbol-processing-api:1.9.0-1.0.13") api("com.squareup:kotlinpoet-ksp:1.11.0") } diff --git a/settings.gradle.kts b/settings.gradle.kts index 76766f334..20dab7391 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,6 @@ plugins { - id("com.gradle.enterprise") version("3.9") + id("com.gradle.enterprise") version("3.14.1") } include("ktorm-core") From 35f5082a5e4b11d167b90054dfb0e6ba7766f679 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 20 Aug 2023 22:49:10 +0800 Subject: [PATCH 058/105] configure java compatibility --- buildSrc/src/main/kotlin/ktorm.base.gradle.kts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/ktorm.base.gradle.kts b/buildSrc/src/main/kotlin/ktorm.base.gradle.kts index ae3c5af8a..709052020 100644 --- a/buildSrc/src/main/kotlin/ktorm.base.gradle.kts +++ b/buildSrc/src/main/kotlin/ktorm.base.gradle.kts @@ -24,6 +24,11 @@ detekt { config.from("${project.rootDir}/detekt.yml") } +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + tasks { compileKotlin { kotlinOptions { @@ -36,7 +41,6 @@ tasks { compileTestKotlin { kotlinOptions { jvmTarget = "1.8" - freeCompilerArgs = listOf("-Xjvm-default=all") } } From 24c03d05e4d6b5cc1e7b391c24105b224dc85920 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 20 Aug 2023 23:31:26 +0800 Subject: [PATCH 059/105] use ktlint_official code style --- ktorm-core/ktorm-core.gradle.kts | 2 +- ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts | 2 +- .../src/main/resources/ktorm-ksp-compiler/.editorconfig | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ktorm-core/ktorm-core.gradle.kts b/ktorm-core/ktorm-core.gradle.kts index 12f505c7c..f405baddb 100644 --- a/ktorm-core/ktorm-core.gradle.kts +++ b/ktorm-core/ktorm-core.gradle.kts @@ -11,7 +11,7 @@ dependencies { compileOnly("org.springframework:spring-jdbc:5.0.10.RELEASE") compileOnly("org.springframework:spring-tx:5.0.10.RELEASE") testImplementation("com.h2database:h2:1.4.198") - testImplementation("org.slf4j:slf4j-simple:1.7.25") + testImplementation("org.slf4j:slf4j-simple:2.0.3") } val testOutput by configurations.creating { diff --git a/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts b/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts index 34bcaaeed..6fc55fa03 100644 --- a/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts +++ b/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts @@ -22,5 +22,5 @@ dependencies { testImplementation("com.github.tschuchortdev:kotlin-compile-testing:1.5.0") testImplementation("com.github.tschuchortdev:kotlin-compile-testing-ksp:1.5.0") testImplementation("com.h2database:h2:1.4.198") - testImplementation("org.slf4j:slf4j-simple:1.7.25") + testImplementation("org.slf4j:slf4j-simple:2.0.3") } diff --git a/ktorm-ksp-compiler/src/main/resources/ktorm-ksp-compiler/.editorconfig b/ktorm-ksp-compiler/src/main/resources/ktorm-ksp-compiler/.editorconfig index c0238f544..9e72d1b64 100644 --- a/ktorm-ksp-compiler/src/main/resources/ktorm-ksp-compiler/.editorconfig +++ b/ktorm-ksp-compiler/src/main/resources/ktorm-ksp-compiler/.editorconfig @@ -1,6 +1,6 @@ # ktlint config used to format the generated code. [*.{kt,kts}] -ktlint_code_style = official +ktlint_code_style = ktlint_official indent_size = 4 indent_style = space max_line_length = 120 From f609d9588a0800d48209be751a054f1ca797039b Mon Sep 17 00:00:00 2001 From: vince Date: Tue, 22 Aug 2023 22:51:28 +0800 Subject: [PATCH 060/105] fix detekt rules --- .../src/main/kotlin/ktorm.base.gradle.kts | 4 +- detekt.yml | 42 +++++++++---------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/buildSrc/src/main/kotlin/ktorm.base.gradle.kts b/buildSrc/src/main/kotlin/ktorm.base.gradle.kts index 709052020..453a58840 100644 --- a/buildSrc/src/main/kotlin/ktorm.base.gradle.kts +++ b/buildSrc/src/main/kotlin/ktorm.base.gradle.kts @@ -20,8 +20,8 @@ dependencies { } detekt { - source.from("src/main/kotlin") - config.from("${project.rootDir}/detekt.yml") + source.setFrom("src/main/kotlin") + config.setFrom("${project.rootDir}/detekt.yml") } java { diff --git a/detekt.yml b/detekt.yml index 7b401e2d0..100b11a48 100644 --- a/detekt.yml +++ b/detekt.yml @@ -52,14 +52,14 @@ complexity: active: true threshold: 12 includeStaticDeclarations: false - ComplexMethod: + CyclomaticComplexMethod: active: true threshold: 20 ignoreSingleWhenExpression: true ignoreSimpleWhenEntries: true LabeledExpression: active: true - ignoredLabels: "" + ignoredLabels: [] LargeClass: active: true threshold: 600 @@ -131,7 +131,7 @@ exceptions: active: true ExceptionRaisedInUnexpectedLocation: active: true - methodNames: 'toString,hashCode,equals,finalize' + methodNames: ['toString', 'hashCode', 'equals', 'finalize'] InstanceOfCheckForException: active: true NotImplementedDeclaration: @@ -144,14 +144,14 @@ exceptions: active: true SwallowedException: active: true - ignoredExceptionTypes: 'InterruptedException,NumberFormatException,ParseException,MalformedURLException' + ignoredExceptionTypes: ['InterruptedException', 'NumberFormatException', 'ParseException', 'MalformedURLException'] ThrowingExceptionFromFinally: active: true ThrowingExceptionInMain: active: true ThrowingExceptionsWithoutMessageOrCause: active: true - exceptions: 'IllegalArgumentException,IllegalStateException,IOException' + exceptions: ['IllegalArgumentException', 'IllegalStateException', 'IOException'] ThrowingNewInstanceOfSameException: active: true TooGenericExceptionCaught: @@ -195,7 +195,6 @@ formatting: active: true autoCorrect: false indentSize: 4 - continuationIndentSize: 4 MaximumLineLength: active: false maxLineLength: 120 @@ -284,7 +283,7 @@ naming: enumEntryPattern: '^[A-Z][_a-zA-Z0-9]*' ForbiddenClassName: active: false - forbiddenName: '' + forbiddenName: [] FunctionMaxLength: active: true maximumFunctionNameLength: 64 @@ -295,12 +294,10 @@ naming: active: true functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$' excludeClassPattern: '$^' - ignoreOverridden: true FunctionParameterNaming: active: true parameterPattern: '[a-z][A-Za-z0-9]*' excludeClassPattern: '$^' - ignoreOverridden: true MatchingDeclarationName: active: true MemberNameEqualsClassName: @@ -330,7 +327,6 @@ naming: variablePattern: '[a-z][A-Za-z0-9]*' privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' excludeClassPattern: '$^' - ignoreOverridden: true performance: active: true @@ -345,8 +341,6 @@ performance: potential-bugs: active: true - DuplicateCaseInWhenExpression: - active: true EqualsAlwaysReturnsTrueOrFalse: active: true EqualsWithHashCodeExist: @@ -382,7 +376,7 @@ style: active: true DataClassContainsFunctions: active: false - conversionFunctionPrefix: 'as' + conversionFunctionPrefix: ['as'] EqualsNullCall: active: true EqualsOnSignatureLine: @@ -394,22 +388,22 @@ style: includeLineWrapping: false ForbiddenComment: active: true - values: 'TODO:,FIXME:,STOPSHIP:' + comments: ['FIXME:', 'STOPSHIP:', 'TODO:'] ForbiddenImport: active: false - imports: '' + imports: [] ForbiddenVoid: active: true FunctionOnlyReturningConstant: active: true ignoreOverridableFunction: true - excludedFunctions: 'describeContents' + excludedFunctions: ['describeContents'] LoopWithTooManyJumpStatements: active: true maxJumpCount: 2 MagicNumber: active: true - ignoreNumbers: '-1,0,1,2,3,60' + ignoreNumbers: ['-1', '0', '1', '2', '3', '60'] ignoreHashCodeFunction: true ignorePropertyDeclaration: false ignoreConstantDeclaration: true @@ -417,8 +411,10 @@ style: ignoreAnnotation: false ignoreNamedArgument: true ignoreEnums: false - MandatoryBracesIfStatements: + BracesOnIfStatements: active: true + singleLine: 'never' + multiLine: 'always' MaxLineLength: active: true maxLineLength: 120 @@ -439,8 +435,10 @@ style: active: true OptionalUnit: active: true - OptionalWhenBraces: - active: false + BracesOnWhenStatements: + active: true + singleLine: 'never' + multiLine: 'consistent' PreferToOverPairSyntax: active: false ProtectedMemberInFinalClass: @@ -450,7 +448,7 @@ style: ReturnCount: active: false max: 2 - excludedFunctions: "equals" + excludedFunctions: ["equals"] excludeLabeled: false excludeReturnFromLambda: true SafeCast: @@ -496,4 +494,4 @@ style: active: true WildcardImport: active: false - excludeImports: 'java.util.*,kotlinx.android.synthetic.*' + excludeImports: ['java.util.*', 'kotlinx.android.synthetic.*'] From 9d1793918713dd979ed5504ab9a4b6e754caced7 Mon Sep 17 00:00:00 2001 From: vince Date: Tue, 22 Aug 2023 22:59:11 +0800 Subject: [PATCH 061/105] fix code style --- detekt.yml | 4 ++-- .../ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/detekt.yml b/detekt.yml index 100b11a48..cb0d52b2a 100644 --- a/detekt.yml +++ b/detekt.yml @@ -436,9 +436,9 @@ style: OptionalUnit: active: true BracesOnWhenStatements: - active: true + active: false singleLine: 'never' - multiLine: 'consistent' + multiLine: 'necessary' PreferToOverPairSyntax: active: false ProtectedMemberInFinalClass: diff --git a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt index cf7c6a2fd..777c35880 100644 --- a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt +++ b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt @@ -28,7 +28,7 @@ import org.jetbrains.kotlin.maven.PluginOption import java.io.File /** - * Extension that enables KSP for the kotlin maven plugin + * Extension that enables KSP for the kotlin maven plugin. */ @Component(role = KotlinMavenPluginExtension::class, hint = "ksp") public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { @@ -48,6 +48,7 @@ public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { return options.map { (option, value) -> PluginOption("ksp", compilerPluginId, option.optionName, value) } } + @Suppress("UnusedPrivateMember") private fun parseUserOptions(execution: MojoExecution): Map> { val pluginOptions = execution.configuration.getChild("pluginOptions") ?: return emptyMap() val availableOptions = KspCliOption.values().associateBy { it.optionName } From 55fef795dc7535e50c7084abe2c8b708f67ab081 Mon Sep 17 00:00:00 2001 From: vince Date: Wed, 23 Aug 2023 22:00:41 +0800 Subject: [PATCH 062/105] fix compile error for jdk 20 --- ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt b/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt index 0d9924e89..d6ee5e78e 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt @@ -20,6 +20,7 @@ import java.io.InputStream import java.io.Reader import java.math.BigDecimal import java.math.BigInteger +import java.net.URI import java.net.URL import java.sql.* import java.sql.Date @@ -1153,7 +1154,7 @@ public open class CachedRowSet(rs: ResultSet) : ResultSet { return when (val value = getColumnValue(columnIndex)) { null -> null is URL -> value - is String -> URL(value) + is String -> URI(value).toURL() else -> throw SQLException("Cannot convert ${value.javaClass.name} value to URL.") } } From 9d6b8f364a43234a86ad972f08c0c2d3fe5d07d3 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 26 Aug 2023 10:43:01 +0800 Subject: [PATCH 063/105] add test jvm args --- ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts b/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts index 6fc55fa03..2285feb5e 100644 --- a/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts +++ b/ktorm-ksp-compiler/ktorm-ksp-compiler.gradle.kts @@ -24,3 +24,9 @@ dependencies { testImplementation("com.h2database:h2:1.4.198") testImplementation("org.slf4j:slf4j-simple:2.0.3") } + +if (JavaVersion.current() >= JavaVersion.VERSION_1_9) { + tasks.test { + jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED") + } +} From 5c3416ffb6b030f3bbb3ef65f860e101bbd37c5d Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 26 Aug 2023 12:50:11 +0800 Subject: [PATCH 064/105] fix failed tests --- .../src/test/kotlin/org/ktorm/ksp/compiler/BaseKspTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/BaseKspTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/BaseKspTest.kt index c14da5f20..5b882e889 100644 --- a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/BaseKspTest.kt +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/BaseKspTest.kt @@ -41,7 +41,7 @@ abstract class BaseKspTest { protected fun kspFailing(message: String, @Language("kotlin") code: String, vararg options: Pair) { val result = compile(code, mapOf(*options)) - assert(result.exitCode == KotlinCompilation.ExitCode.OK) + assert(result.exitCode == KotlinCompilation.ExitCode.COMPILATION_ERROR) assert(result.messages.contains("e: Error occurred in KSP, check log for detail")) assert(result.messages.contains(message)) } From b194c68149e1046acadc656af9e68366886ddd15 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 27 Aug 2023 22:49:15 +0800 Subject: [PATCH 065/105] code formatter interface --- .../ksp/compiler/KtormProcessorProvider.kt | 46 ++++--------------- .../ksp/compiler/formatter/CodeFormatter.kt | 12 +++++ .../compiler/formatter/KtLintCodeFormatter.kt | 43 +++++++++++++++++ 3 files changed, 65 insertions(+), 36 deletions(-) create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/CodeFormatter.kt create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt index 75f1ddb55..1658eeb10 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt @@ -20,36 +20,19 @@ import com.google.devtools.ksp.processing.* import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSFile -import com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3 -import com.pinterest.ktlint.rule.engine.api.Code -import com.pinterest.ktlint.rule.engine.api.EditorConfigDefaults -import com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine -import com.squareup.kotlinpoet.FileSpec -import org.ec4j.core.EditorConfigLoader -import org.ec4j.core.Resource.Resources import org.ktorm.ksp.annotation.Table +import org.ktorm.ksp.compiler.formatter.CodeFormatter +import org.ktorm.ksp.compiler.formatter.KtLintCodeFormatter import org.ktorm.ksp.compiler.generator.FileGenerator import org.ktorm.ksp.compiler.parser.MetadataParser import org.ktorm.ksp.compiler.util.isValid import org.ktorm.ksp.spi.TableMetadata -import java.util.* import kotlin.reflect.jvm.jvmName /** * Ktorm KSP symbol processor provider. */ public class KtormProcessorProvider : SymbolProcessorProvider { - private val ktLintRuleEngine = KtLintRuleEngine( - ruleProviders = ServiceLoader - .load(RuleSetProviderV3::class.java, javaClass.classLoader) - .flatMap { it.getRuleProviders() } - .toSet(), - editorConfigDefaults = EditorConfigDefaults( - EditorConfigLoader.default_().load( - Resources.ofClassPath(javaClass.classLoader, "/ktorm-ksp-compiler/.editorconfig", Charsets.UTF_8) - ) - ) - ) override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { for (generator in FileGenerator.extCodeGenerators) { @@ -81,8 +64,8 @@ public class KtormProcessorProvider : SymbolProcessorProvider { // Generate file spec by kotlinpoet. val fileSpec = FileGenerator.generate(table, environment) - // Beautify the generated code by ktlint. - val formattedCode = formatCode(fileSpec, environment.logger) + // Beautify the generated code. + val formattedCode = getCodeFormatter(environment).format(fileSpec.toString()) // Output the formatted code. val dependencies = Dependencies(false, *table.getDependencyFiles().toTypedArray()) @@ -90,23 +73,14 @@ public class KtormProcessorProvider : SymbolProcessorProvider { file.writer(Charsets.UTF_8).use { it.write(formattedCode) } } - private fun formatCode(fileSpec: FileSpec, logger: KSPLogger): String { + private fun getCodeFormatter(environment: SymbolProcessorEnvironment): CodeFormatter { try { - // Manually fix some code styles before formatting. - val code = fileSpec.toString() - .replace(Regex("""\(\s*"""), "(") - .replace(Regex("""\s*\)"""), ")") - .replace(Regex(""",\s*"""), ", ") - .replace(Regex(""",\s*\)"""), ")") - .replace(Regex("""\s+get\(\)\s="""), " get() =") - .replace(Regex("""\s+=\s+"""), " = ") - .replace("import org.ktorm.ksp.`annotation`", "import org.ktorm.ksp.annotation") - - return ktLintRuleEngine.format(Code.fromSnippet(code)) - } catch (e: Exception) { - logger.exception(e) - return fileSpec.toString() + return KtLintCodeFormatter(environment) + } catch (_: ClassNotFoundException) { + } catch (_: NoClassDefFoundError) { } + + return CodeFormatter { code -> code } } private fun TableMetadata.getDependencyFiles(): List { diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/CodeFormatter.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/CodeFormatter.kt new file mode 100644 index 000000000..8c1473220 --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/CodeFormatter.kt @@ -0,0 +1,12 @@ +package org.ktorm.ksp.compiler.formatter + +/** + * Code formatter interface. + */ +internal fun interface CodeFormatter { + + /** + * Format the generated code to the community recommended coding style. + */ + fun format(code: String): String +} diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt new file mode 100644 index 000000000..17d592c5d --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt @@ -0,0 +1,43 @@ +package org.ktorm.ksp.compiler.formatter + +import com.google.devtools.ksp.processing.SymbolProcessorEnvironment +import com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3 +import com.pinterest.ktlint.rule.engine.api.Code +import com.pinterest.ktlint.rule.engine.api.EditorConfigDefaults +import com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine +import org.ec4j.core.EditorConfigLoader +import org.ec4j.core.Resource.Resources +import java.util.* + +internal class KtLintCodeFormatter(val environment: SymbolProcessorEnvironment) : CodeFormatter { + private val ktLintRuleEngine = KtLintRuleEngine( + ruleProviders = ServiceLoader + .load(RuleSetProviderV3::class.java, javaClass.classLoader) + .flatMap { it.getRuleProviders() } + .toSet(), + editorConfigDefaults = EditorConfigDefaults( + EditorConfigLoader.default_().load( + Resources.ofClassPath(javaClass.classLoader, "/ktorm-ksp-compiler/.editorconfig", Charsets.UTF_8) + ) + ) + ) + + override fun format(code: String): String { + try { + // Manually fix some code styles before formatting. + val snippet = code + .replace(Regex("""\(\s*"""), "(") + .replace(Regex("""\s*\)"""), ")") + .replace(Regex(""",\s*"""), ", ") + .replace(Regex(""",\s*\)"""), ")") + .replace(Regex("""\s+get\(\)\s="""), " get() =") + .replace(Regex("""\s+=\s+"""), " = ") + .replace("import org.ktorm.ksp.`annotation`", "import org.ktorm.ksp.annotation") + + return ktLintRuleEngine.format(Code.fromSnippet(snippet)) + } catch (e: Throwable) { + environment.logger.exception(e) + return code + } + } +} From 6f6f633dc8413e86bdd2d9faa66596bac42d7ab2 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 28 Aug 2023 21:42:12 +0800 Subject: [PATCH 066/105] fix code style --- .../ksp/compiler/formatter/CodeFormatter.kt | 16 ++++++++++++++++ .../compiler/formatter/KtLintCodeFormatter.kt | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/CodeFormatter.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/CodeFormatter.kt index 8c1473220..a7a750109 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/CodeFormatter.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/CodeFormatter.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.ktorm.ksp.compiler.formatter /** diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt index 17d592c5d..1e8f9ffbf 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.ktorm.ksp.compiler.formatter import com.google.devtools.ksp.processing.SymbolProcessorEnvironment From 5a51dc935cf74e8e1b064809fee259cf94071ff2 Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 1 Sep 2023 21:07:17 +0800 Subject: [PATCH 067/105] implement ksp maven plugin extensionn --- .../org/ktorm/database/TransactionManager.kt | 2 +- .../kotlin/org/ktorm/database/DatabaseTest.kt | 2 +- .../maven/KtormKspMavenPluginExtension.kt | 18 ++++++++++++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/ktorm-core/src/main/kotlin/org/ktorm/database/TransactionManager.kt b/ktorm-core/src/main/kotlin/org/ktorm/database/TransactionManager.kt index 6c872891a..67c412cfe 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/database/TransactionManager.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/database/TransactionManager.kt @@ -103,7 +103,7 @@ public enum class TransactionIsolation(public val level: Int) { * Find an enum value by the specific isolation level. */ public fun valueOf(level: Int): TransactionIsolation { - return values().first { it.level == level } + return entries.first { it.level == level } } } } diff --git a/ktorm-core/src/test/kotlin/org/ktorm/database/DatabaseTest.kt b/ktorm-core/src/test/kotlin/org/ktorm/database/DatabaseTest.kt index adcfe324f..ef3a3bf55 100644 --- a/ktorm-core/src/test/kotlin/org/ktorm/database/DatabaseTest.kt +++ b/ktorm-core/src/test/kotlin/org/ktorm/database/DatabaseTest.kt @@ -114,7 +114,7 @@ class DatabaseTest : BaseTest() { companion object { fun forCode(code: Int): Status { - return values().first { it.code == code } + return entries.first { it.code == code } } } } diff --git a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt index 777c35880..58c146ad0 100644 --- a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt +++ b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt @@ -44,20 +44,30 @@ public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { } override fun getPluginOptions(project: MavenProject, execution: MojoExecution): List { - val options = buildDefaultOptions(project, execution) + val userOptions = parseUserOptions(execution) + val options = buildDefaultOptions(project, execution).filterKeys { it !in userOptions } + + for (key in listOf(KspCliOption.JAVA_OUTPUT_DIR_OPTION, KspCliOption.KOTLIN_OUTPUT_DIR_OPTION)) { + if (execution.mojoDescriptor.goal == "compile") { + project.addCompileSourceRoot(options[key] ?: userOptions[key]!![0]) + } + if (execution.mojoDescriptor.goal == "test-compile") { + project.addTestCompileSourceRoot(options[key] ?: userOptions[key]!![0]) + } + } + return options.map { (option, value) -> PluginOption("ksp", compilerPluginId, option.optionName, value) } } - @Suppress("UnusedPrivateMember") private fun parseUserOptions(execution: MojoExecution): Map> { val pluginOptions = execution.configuration.getChild("pluginOptions") ?: return emptyMap() - val availableOptions = KspCliOption.values().associateBy { it.optionName } + val availableOptions = KspCliOption.entries.associateBy { it.optionName } val pattern = Regex("([^:]+):([^=]+)=(.*)") return pluginOptions.children .mapNotNull { pattern.matchEntire(it.value) } .map { it.destructured } - .filter { (plugin, key, _) -> plugin == "ksp" && key in availableOptions } + .filter { (plugin, key, value) -> plugin == "ksp" && key in availableOptions && value.isNotBlank() } .groupBy({ (_, key, _) -> availableOptions[key]!! }, { (_, _, value) -> value }) } From 3bddef42163ac73da671f5439297b5cb69c3714f Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 2 Sep 2023 12:16:33 +0800 Subject: [PATCH 068/105] resolve ktlint executable jar --- .../maven/KtormKspMavenPluginExtension.kt | 139 +++++++++++++----- .../resources/META-INF/plexus/components.xml | 4 + 2 files changed, 106 insertions(+), 37 deletions(-) diff --git a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt index 58c146ad0..e5cf1e96f 100644 --- a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt +++ b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt @@ -18,7 +18,9 @@ package org.ktorm.ksp.compiler.maven import com.google.devtools.ksp.KspCliOption import org.apache.maven.artifact.resolver.ArtifactResolutionRequest +import org.apache.maven.execution.MavenSession import org.apache.maven.plugin.MojoExecution +import org.apache.maven.plugin.MojoExecutionException import org.apache.maven.project.MavenProject import org.apache.maven.repository.RepositorySystem import org.codehaus.plexus.component.annotations.Component @@ -34,6 +36,8 @@ import java.io.File public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { @Requirement private lateinit var repositorySystem: RepositorySystem + @Requirement + private lateinit var mavenSession: MavenSession override fun getCompilerPluginId(): String { return "com.google.devtools.ksp.symbol-processing" @@ -45,7 +49,7 @@ public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { override fun getPluginOptions(project: MavenProject, execution: MojoExecution): List { val userOptions = parseUserOptions(execution) - val options = buildDefaultOptions(project, execution).filterKeys { it !in userOptions } + val options = buildPluginOptions(project, execution, userOptions) for (key in listOf(KspCliOption.JAVA_OUTPUT_DIR_OPTION, KspCliOption.KOTLIN_OUTPUT_DIR_OPTION)) { if (execution.mojoDescriptor.goal == "compile") { @@ -71,59 +75,120 @@ public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { .groupBy({ (_, key, _) -> availableOptions[key]!! }, { (_, _, value) -> value }) } - private fun buildDefaultOptions(project: MavenProject, execution: MojoExecution): Map { + private fun buildPluginOptions( + project: MavenProject, execution: MojoExecution, userOptions: Map> + ): Map { val baseDir = project.basedir.path val buildDir = project.build.directory + val options = LinkedHashMap() if (execution.mojoDescriptor.goal == "compile") { - return mapOf( - KspCliOption.CLASS_OUTPUT_DIR_OPTION to project.build.outputDirectory, - KspCliOption.JAVA_OUTPUT_DIR_OPTION to path(buildDir, "generated-sources", "ksp-java"), - KspCliOption.KOTLIN_OUTPUT_DIR_OPTION to path(buildDir, "generated-sources", "ksp"), - KspCliOption.RESOURCE_OUTPUT_DIR_OPTION to project.build.outputDirectory, - KspCliOption.CACHES_DIR_OPTION to path(buildDir, "kspCaches"), - KspCliOption.PROJECT_BASE_DIR_OPTION to baseDir, - KspCliOption.KSP_OUTPUT_DIR_OPTION to path(buildDir, "ksp"), - KspCliOption.PROCESSOR_CLASSPATH_OPTION to buildProcessorClasspath(project, execution), - KspCliOption.WITH_COMPILATION_OPTION to "true" - ) + if (KspCliOption.CLASS_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.CLASS_OUTPUT_DIR_OPTION] = project.build.outputDirectory + } + if (KspCliOption.JAVA_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.JAVA_OUTPUT_DIR_OPTION] = path(buildDir, "generated-sources", "ksp-java") + } + if (KspCliOption.KOTLIN_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.KOTLIN_OUTPUT_DIR_OPTION] = path(buildDir, "generated-sources", "ksp") + } + if (KspCliOption.RESOURCE_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.RESOURCE_OUTPUT_DIR_OPTION] = project.build.outputDirectory + } + if (KspCliOption.CACHES_DIR_OPTION !in userOptions) { + options[KspCliOption.CACHES_DIR_OPTION] = path(buildDir, "ksp-caches") + } + if (KspCliOption.PROJECT_BASE_DIR_OPTION !in userOptions) { + options[KspCliOption.PROJECT_BASE_DIR_OPTION] = baseDir + } + if (KspCliOption.KSP_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.KSP_OUTPUT_DIR_OPTION] = path(buildDir, "ksp") + } + if (KspCliOption.PROCESSOR_CLASSPATH_OPTION !in userOptions) { + options[KspCliOption.PROCESSOR_CLASSPATH_OPTION] = processorClasspath(project, execution) + } + if (KspCliOption.WITH_COMPILATION_OPTION !in userOptions) { + options[KspCliOption.WITH_COMPILATION_OPTION] = "true" + } + + val apOptions = userOptions[KspCliOption.PROCESSING_OPTIONS_OPTION] ?: emptyList() + if (apOptions.none { it.startsWith("ktorm.ktlintExecutable=") }) { + options[KspCliOption.PROCESSING_OPTIONS_OPTION] = "ktorm.ktlintExecutable=${ktlintExecutable(project)}" + } } if (execution.mojoDescriptor.goal == "test-compile") { - return mapOf( - KspCliOption.CLASS_OUTPUT_DIR_OPTION to project.build.testOutputDirectory, - KspCliOption.JAVA_OUTPUT_DIR_OPTION to path(buildDir, "generated-test-sources", "ksp-java"), - KspCliOption.KOTLIN_OUTPUT_DIR_OPTION to path(buildDir, "generated-test-sources", "ksp"), - KspCliOption.RESOURCE_OUTPUT_DIR_OPTION to project.build.testOutputDirectory, - KspCliOption.CACHES_DIR_OPTION to path(buildDir, "kspCaches"), - KspCliOption.PROJECT_BASE_DIR_OPTION to baseDir, - KspCliOption.KSP_OUTPUT_DIR_OPTION to path(buildDir, "ksp-test"), - KspCliOption.PROCESSOR_CLASSPATH_OPTION to buildProcessorClasspath(project, execution), - KspCliOption.WITH_COMPILATION_OPTION to "true" - ) - } + if (KspCliOption.CLASS_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.CLASS_OUTPUT_DIR_OPTION] = project.build.testOutputDirectory + } + if (KspCliOption.JAVA_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.JAVA_OUTPUT_DIR_OPTION] = path(buildDir, "generated-test-sources", "ksp-java") + } + if (KspCliOption.KOTLIN_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.KOTLIN_OUTPUT_DIR_OPTION] = path(buildDir, "generated-test-sources", "ksp") + } + if (KspCliOption.RESOURCE_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.RESOURCE_OUTPUT_DIR_OPTION] = project.build.testOutputDirectory + } + if (KspCliOption.CACHES_DIR_OPTION !in userOptions) { + options[KspCliOption.CACHES_DIR_OPTION] = path(buildDir, "ksp-caches") + } + if (KspCliOption.PROJECT_BASE_DIR_OPTION !in userOptions) { + options[KspCliOption.PROJECT_BASE_DIR_OPTION] = baseDir + } + if (KspCliOption.KSP_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.KSP_OUTPUT_DIR_OPTION] = path(buildDir, "ksp-test") + } + if (KspCliOption.PROCESSOR_CLASSPATH_OPTION !in userOptions) { + options[KspCliOption.PROCESSOR_CLASSPATH_OPTION] = processorClasspath(project, execution) + } + if (KspCliOption.WITH_COMPILATION_OPTION !in userOptions) { + options[KspCliOption.WITH_COMPILATION_OPTION] = "true" + } - return emptyMap() - } + val apOptions = userOptions[KspCliOption.PROCESSING_OPTIONS_OPTION] ?: emptyList() + if (apOptions.none { it.startsWith("ktorm.ktlintExecutable=") }) { + options[KspCliOption.PROCESSING_OPTIONS_OPTION] = "ktorm.ktlintExecutable=${ktlintExecutable(project)}" + } + } - private fun path(parent: String, vararg children: String): String { - val file = children.fold(File(parent)) { acc, child -> File(acc, child) } - return file.path + return options } - private fun buildProcessorClasspath(project: MavenProject, execution: MojoExecution): String { + private fun processorClasspath(project: MavenProject, execution: MojoExecution): String { val files = ArrayList() for (dependency in execution.plugin.dependencies) { - val request = ArtifactResolutionRequest() - request.artifact = repositorySystem.createDependencyArtifact(dependency) - request.localRepository = repositorySystem.createDefaultLocalRepository() - request.remoteRepositories = project.pluginArtifactRepositories - request.isResolveTransitively = true + val r = ArtifactResolutionRequest() + r.artifact = repositorySystem.createDependencyArtifact(dependency) + r.localRepository = mavenSession.localRepository + r.remoteRepositories = project.pluginArtifactRepositories + r.isResolveTransitively = true - val resolved = repositorySystem.resolve(request) + val resolved = repositorySystem.resolve(r) files += resolved.artifacts.mapNotNull { it.file }.filter { it.exists() } } return files.joinToString(File.pathSeparator) { it.path } } + + private fun ktlintExecutable(project: MavenProject): String { + val r = ArtifactResolutionRequest() + r.artifact = repositorySystem.createArtifactWithClassifier("com.pinterest", "ktlint", "0.50.0", "jar", "all") + r.localRepository = mavenSession.localRepository + r.remoteRepositories = project.pluginArtifactRepositories + r.isResolveTransitively = false + + val resolved = repositorySystem.resolve(r) + val file = resolved.artifacts.mapNotNull { it.file }.firstOrNull { it.exists() } + if (file != null) { + return file.path + } else { + throw MojoExecutionException("Resolve ktlint executable jar failed.") + } + } + + private fun path(parent: String, vararg children: String): String { + val file = children.fold(File(parent)) { acc, child -> File(acc, child) } + return file.path + } } diff --git a/ktorm-ksp-compiler-maven-plugin/src/main/resources/META-INF/plexus/components.xml b/ktorm-ksp-compiler-maven-plugin/src/main/resources/META-INF/plexus/components.xml index 831c70493..3571e922a 100644 --- a/ktorm-ksp-compiler-maven-plugin/src/main/resources/META-INF/plexus/components.xml +++ b/ktorm-ksp-compiler-maven-plugin/src/main/resources/META-INF/plexus/components.xml @@ -11,6 +11,10 @@ org.apache.maven.repository.RepositorySystem repositorySystem + + org.apache.maven.execution.MavenSession + mavenSession + From 751a0941e9af52dd7f3fa247753f1a612b82c79d Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 2 Sep 2023 18:56:32 +0800 Subject: [PATCH 069/105] standalone ktlint formatter --- ...ktorm-ksp-compiler-maven-plugin.gradle.kts | 5 +- .../ksp/compiler/KtormProcessorProvider.kt | 42 +++++--- .../compiler/formatter/KtLintCodeFormatter.kt | 2 +- .../StandaloneKtLintCodeFormatter.kt | 101 ++++++++++++++++++ 4 files changed, 131 insertions(+), 19 deletions(-) create mode 100644 ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt diff --git a/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts b/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts index 7a0794b0a..3c2766dba 100644 --- a/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts +++ b/ktorm-ksp-compiler-maven-plugin/ktorm-ksp-compiler-maven-plugin.gradle.kts @@ -10,5 +10,8 @@ dependencies { compileOnly(kotlin("compiler")) compileOnly("org.apache.maven:maven-core:3.9.3") implementation("com.google.devtools.ksp:symbol-processing-cmdline:1.9.0-1.0.13") - implementation(project(":ktorm-ksp-compiler")) + implementation(project(":ktorm-ksp-compiler")) { + exclude(group = "com.pinterest.ktlint", module = "ktlint-rule-engine") + exclude(group = "com.pinterest.ktlint", module = "ktlint-ruleset-standard") + } } diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt index 1658eeb10..db501103e 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt @@ -23,6 +23,7 @@ import com.google.devtools.ksp.symbol.KSFile import org.ktorm.ksp.annotation.Table import org.ktorm.ksp.compiler.formatter.CodeFormatter import org.ktorm.ksp.compiler.formatter.KtLintCodeFormatter +import org.ktorm.ksp.compiler.formatter.StandaloneKtLintCodeFormatter import org.ktorm.ksp.compiler.generator.FileGenerator import org.ktorm.ksp.compiler.parser.MetadataParser import org.ktorm.ksp.compiler.util.isValid @@ -48,32 +49,39 @@ public class KtormProcessorProvider : SymbolProcessorProvider { private fun doProcess(resolver: Resolver, environment: SymbolProcessorEnvironment): List { val (symbols, deferral) = resolver.getSymbolsWithAnnotation(Table::class.jvmName).partition { it.isValid() } + if (symbols.isNotEmpty()) { + val parser = MetadataParser(resolver, environment) + val formatter = getCodeFormatter(environment) - val parser = MetadataParser(resolver, environment) - for (symbol in symbols) { - if (symbol is KSClassDeclaration) { + for (symbol in symbols) { + if (symbol !is KSClassDeclaration) { + continue + } + + // Parse table metadata from the symbol. val table = parser.parseTableMetadata(symbol) - generateFile(table, environment) - } - } - return deferral - } + // Generate file spec by kotlinpoet. + val fileSpec = FileGenerator.generate(table, environment) - private fun generateFile(table: TableMetadata, environment: SymbolProcessorEnvironment) { - // Generate file spec by kotlinpoet. - val fileSpec = FileGenerator.generate(table, environment) + // Beautify the generated code. + val formattedCode = formatter.format(fileSpec.toString()) - // Beautify the generated code. - val formattedCode = getCodeFormatter(environment).format(fileSpec.toString()) + // Output the formatted code. + val dependencies = Dependencies(false, *table.getDependencyFiles().toTypedArray()) + val file = environment.codeGenerator.createNewFile(dependencies, fileSpec.packageName, fileSpec.name) + file.bufferedWriter(Charsets.UTF_8).use { it.write(formattedCode) } + } + } - // Output the formatted code. - val dependencies = Dependencies(false, *table.getDependencyFiles().toTypedArray()) - val file = environment.codeGenerator.createNewFile(dependencies, fileSpec.packageName, fileSpec.name) - file.writer(Charsets.UTF_8).use { it.write(formattedCode) } + return deferral } private fun getCodeFormatter(environment: SymbolProcessorEnvironment): CodeFormatter { + if (!environment.options["ktorm.ktlintExecutable"].isNullOrBlank()) { + return StandaloneKtLintCodeFormatter(environment) + } + try { return KtLintCodeFormatter(environment) } catch (_: ClassNotFoundException) { diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt index 1e8f9ffbf..aeeee6626 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt @@ -33,7 +33,7 @@ internal class KtLintCodeFormatter(val environment: SymbolProcessorEnvironment) .toSet(), editorConfigDefaults = EditorConfigDefaults( EditorConfigLoader.default_().load( - Resources.ofClassPath(javaClass.classLoader, "/ktorm-ksp-compiler/.editorconfig", Charsets.UTF_8) + Resources.ofClassPath(javaClass.classLoader, "ktorm-ksp-compiler/.editorconfig", Charsets.UTF_8) ) ) ) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt new file mode 100644 index 000000000..4c714ea7a --- /dev/null +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt @@ -0,0 +1,101 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.ktorm.ksp.compiler.formatter + +import com.google.devtools.ksp.processing.SymbolProcessorEnvironment +import java.io.File + +internal class StandaloneKtLintCodeFormatter(val environment: SymbolProcessorEnvironment) : CodeFormatter { + private val command = buildCommand() + + init { + environment.logger.info("[ktorm-ksp-compiler] init standalone ktlint code formatter with command: $command") + } + + override fun format(code: String): String { + try { + val p = Runtime.getRuntime().exec(command) + p.outputStream.bufferedWriter(Charsets.UTF_8).use { it.write(preprocessCode(code)) } + p.waitFor() + + if (p.exitValue() == 0) { + return p.inputStream.bufferedReader(Charsets.UTF_8).use { it.readText() } + } else { + val msg = p.errorStream.bufferedReader(Charsets.UTF_8).use { it.readText() } + environment.logger.error("[ktorm-ksp-compiler] ktlint exit with code: ${p.exitValue()}\n$msg") + return code + } + } catch (e: Throwable) { + environment.logger.exception(e) + return code + } + } + + private fun buildCommand(): String { + val isJava8 = + try { Class.forName("java.lang.reflect.InaccessibleObjectException"); false } + catch (_: ClassNotFoundException) { true } + + val java = findJavaExecutable() + val ktlint = environment.options["ktorm.ktlintExecutable"]!! + val config = createEditorConfigFile() + + if (isJava8) { + return "$java -jar $ktlint --format --stdin --log-level=none --editorconfig=$config" + } else { + val jvmArgs = "--add-opens java.base/java.lang=ALL-UNNAMED" + return "$java $jvmArgs -jar $ktlint --format --stdin --log-level=none --editorconfig=$config" + } + } + + private fun findJavaExecutable(): String { + var file = File(File(System.getProperty("java.home"), "bin"), "java") + if (!file.exists()) { + file = File(File(System.getProperty("java.home"), "bin"), "java.exe") + } + + if (file.exists()) { + return file.path + } else { + throw IllegalStateException("Could not find java executable.") + } + } + + private fun createEditorConfigFile(): String { + val file = File.createTempFile("ktlint", ".editorconfig") + file.deleteOnExit() + + file.outputStream().use { output -> + javaClass.classLoader.getResourceAsStream("ktorm-ksp-compiler/.editorconfig")!!.use { input -> + input.copyTo(output) + } + } + + return file.path + } + + private fun preprocessCode(code: String): String { + return code + .replace(Regex("""\(\s*"""), "(") + .replace(Regex("""\s*\)"""), ")") + .replace(Regex(""",\s*"""), ", ") + .replace(Regex(""",\s*\)"""), ")") + .replace(Regex("""\s+get\(\)\s="""), " get() =") + .replace(Regex("""\s+=\s+"""), " = ") + .replace("import org.ktorm.ksp.`annotation`", "import org.ktorm.ksp.annotation") + } +} From be2e63dc2573bd43bca89199378b339d367e2c0a Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 2 Sep 2023 19:55:40 +0800 Subject: [PATCH 070/105] fix detekt issue --- .../maven/KtormKspMavenPluginExtension.kt | 152 ++++++++++-------- .../StandaloneKtLintCodeFormatter.kt | 17 +- 2 files changed, 91 insertions(+), 78 deletions(-) diff --git a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt index e5cf1e96f..f278e76d5 100644 --- a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt +++ b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt @@ -49,18 +49,26 @@ public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { override fun getPluginOptions(project: MavenProject, execution: MojoExecution): List { val userOptions = parseUserOptions(execution) - val options = buildPluginOptions(project, execution, userOptions) - for (key in listOf(KspCliOption.JAVA_OUTPUT_DIR_OPTION, KspCliOption.KOTLIN_OUTPUT_DIR_OPTION)) { - if (execution.mojoDescriptor.goal == "compile") { + if (execution.mojoDescriptor.goal == "compile") { + val options = buildPluginOptions(project, execution, userOptions) + for (key in listOf(KspCliOption.JAVA_OUTPUT_DIR_OPTION, KspCliOption.KOTLIN_OUTPUT_DIR_OPTION)) { project.addCompileSourceRoot(options[key] ?: userOptions[key]!![0]) } - if (execution.mojoDescriptor.goal == "test-compile") { + + return options.map { (option, value) -> PluginOption("ksp", compilerPluginId, option.optionName, value) } + } + + if (execution.mojoDescriptor.goal == "test-compile") { + val options = buildTestPluginOptions(project, execution, userOptions) + for (key in listOf(KspCliOption.JAVA_OUTPUT_DIR_OPTION, KspCliOption.KOTLIN_OUTPUT_DIR_OPTION)) { project.addTestCompileSourceRoot(options[key] ?: userOptions[key]!![0]) } + + return options.map { (option, value) -> PluginOption("ksp", compilerPluginId, option.optionName, value) } } - return options.map { (option, value) -> PluginOption("ksp", compilerPluginId, option.optionName, value) } + return emptyList() } private fun parseUserOptions(execution: MojoExecution): Map> { @@ -82,74 +90,80 @@ public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { val buildDir = project.build.directory val options = LinkedHashMap() - if (execution.mojoDescriptor.goal == "compile") { - if (KspCliOption.CLASS_OUTPUT_DIR_OPTION !in userOptions) { - options[KspCliOption.CLASS_OUTPUT_DIR_OPTION] = project.build.outputDirectory - } - if (KspCliOption.JAVA_OUTPUT_DIR_OPTION !in userOptions) { - options[KspCliOption.JAVA_OUTPUT_DIR_OPTION] = path(buildDir, "generated-sources", "ksp-java") - } - if (KspCliOption.KOTLIN_OUTPUT_DIR_OPTION !in userOptions) { - options[KspCliOption.KOTLIN_OUTPUT_DIR_OPTION] = path(buildDir, "generated-sources", "ksp") - } - if (KspCliOption.RESOURCE_OUTPUT_DIR_OPTION !in userOptions) { - options[KspCliOption.RESOURCE_OUTPUT_DIR_OPTION] = project.build.outputDirectory - } - if (KspCliOption.CACHES_DIR_OPTION !in userOptions) { - options[KspCliOption.CACHES_DIR_OPTION] = path(buildDir, "ksp-caches") - } - if (KspCliOption.PROJECT_BASE_DIR_OPTION !in userOptions) { - options[KspCliOption.PROJECT_BASE_DIR_OPTION] = baseDir - } - if (KspCliOption.KSP_OUTPUT_DIR_OPTION !in userOptions) { - options[KspCliOption.KSP_OUTPUT_DIR_OPTION] = path(buildDir, "ksp") - } - if (KspCliOption.PROCESSOR_CLASSPATH_OPTION !in userOptions) { - options[KspCliOption.PROCESSOR_CLASSPATH_OPTION] = processorClasspath(project, execution) - } - if (KspCliOption.WITH_COMPILATION_OPTION !in userOptions) { - options[KspCliOption.WITH_COMPILATION_OPTION] = "true" - } + if (KspCliOption.CLASS_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.CLASS_OUTPUT_DIR_OPTION] = project.build.outputDirectory + } + if (KspCliOption.JAVA_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.JAVA_OUTPUT_DIR_OPTION] = path(buildDir, "generated-sources", "ksp-java") + } + if (KspCliOption.KOTLIN_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.KOTLIN_OUTPUT_DIR_OPTION] = path(buildDir, "generated-sources", "ksp") + } + if (KspCliOption.RESOURCE_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.RESOURCE_OUTPUT_DIR_OPTION] = project.build.outputDirectory + } + if (KspCliOption.CACHES_DIR_OPTION !in userOptions) { + options[KspCliOption.CACHES_DIR_OPTION] = path(buildDir, "ksp-caches") + } + if (KspCliOption.PROJECT_BASE_DIR_OPTION !in userOptions) { + options[KspCliOption.PROJECT_BASE_DIR_OPTION] = baseDir + } + if (KspCliOption.KSP_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.KSP_OUTPUT_DIR_OPTION] = path(buildDir, "ksp") + } + if (KspCliOption.PROCESSOR_CLASSPATH_OPTION !in userOptions) { + options[KspCliOption.PROCESSOR_CLASSPATH_OPTION] = processorClasspath(project, execution) + } + if (KspCliOption.WITH_COMPILATION_OPTION !in userOptions) { + options[KspCliOption.WITH_COMPILATION_OPTION] = "true" + } - val apOptions = userOptions[KspCliOption.PROCESSING_OPTIONS_OPTION] ?: emptyList() - if (apOptions.none { it.startsWith("ktorm.ktlintExecutable=") }) { - options[KspCliOption.PROCESSING_OPTIONS_OPTION] = "ktorm.ktlintExecutable=${ktlintExecutable(project)}" - } + val apOptions = userOptions[KspCliOption.PROCESSING_OPTIONS_OPTION] ?: emptyList() + if (apOptions.none { it.startsWith("ktorm.ktlintExecutable=") }) { + options[KspCliOption.PROCESSING_OPTIONS_OPTION] = "ktorm.ktlintExecutable=${ktlintExecutable(project)}" } - if (execution.mojoDescriptor.goal == "test-compile") { - if (KspCliOption.CLASS_OUTPUT_DIR_OPTION !in userOptions) { - options[KspCliOption.CLASS_OUTPUT_DIR_OPTION] = project.build.testOutputDirectory - } - if (KspCliOption.JAVA_OUTPUT_DIR_OPTION !in userOptions) { - options[KspCliOption.JAVA_OUTPUT_DIR_OPTION] = path(buildDir, "generated-test-sources", "ksp-java") - } - if (KspCliOption.KOTLIN_OUTPUT_DIR_OPTION !in userOptions) { - options[KspCliOption.KOTLIN_OUTPUT_DIR_OPTION] = path(buildDir, "generated-test-sources", "ksp") - } - if (KspCliOption.RESOURCE_OUTPUT_DIR_OPTION !in userOptions) { - options[KspCliOption.RESOURCE_OUTPUT_DIR_OPTION] = project.build.testOutputDirectory - } - if (KspCliOption.CACHES_DIR_OPTION !in userOptions) { - options[KspCliOption.CACHES_DIR_OPTION] = path(buildDir, "ksp-caches") - } - if (KspCliOption.PROJECT_BASE_DIR_OPTION !in userOptions) { - options[KspCliOption.PROJECT_BASE_DIR_OPTION] = baseDir - } - if (KspCliOption.KSP_OUTPUT_DIR_OPTION !in userOptions) { - options[KspCliOption.KSP_OUTPUT_DIR_OPTION] = path(buildDir, "ksp-test") - } - if (KspCliOption.PROCESSOR_CLASSPATH_OPTION !in userOptions) { - options[KspCliOption.PROCESSOR_CLASSPATH_OPTION] = processorClasspath(project, execution) - } - if (KspCliOption.WITH_COMPILATION_OPTION !in userOptions) { - options[KspCliOption.WITH_COMPILATION_OPTION] = "true" - } + return options + } - val apOptions = userOptions[KspCliOption.PROCESSING_OPTIONS_OPTION] ?: emptyList() - if (apOptions.none { it.startsWith("ktorm.ktlintExecutable=") }) { - options[KspCliOption.PROCESSING_OPTIONS_OPTION] = "ktorm.ktlintExecutable=${ktlintExecutable(project)}" - } + private fun buildTestPluginOptions( + project: MavenProject, execution: MojoExecution, userOptions: Map> + ): Map { + val baseDir = project.basedir.path + val buildDir = project.build.directory + val options = LinkedHashMap() + + if (KspCliOption.CLASS_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.CLASS_OUTPUT_DIR_OPTION] = project.build.testOutputDirectory + } + if (KspCliOption.JAVA_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.JAVA_OUTPUT_DIR_OPTION] = path(buildDir, "generated-test-sources", "ksp-java") + } + if (KspCliOption.KOTLIN_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.KOTLIN_OUTPUT_DIR_OPTION] = path(buildDir, "generated-test-sources", "ksp") + } + if (KspCliOption.RESOURCE_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.RESOURCE_OUTPUT_DIR_OPTION] = project.build.testOutputDirectory + } + if (KspCliOption.CACHES_DIR_OPTION !in userOptions) { + options[KspCliOption.CACHES_DIR_OPTION] = path(buildDir, "ksp-caches") + } + if (KspCliOption.PROJECT_BASE_DIR_OPTION !in userOptions) { + options[KspCliOption.PROJECT_BASE_DIR_OPTION] = baseDir + } + if (KspCliOption.KSP_OUTPUT_DIR_OPTION !in userOptions) { + options[KspCliOption.KSP_OUTPUT_DIR_OPTION] = path(buildDir, "ksp-test") + } + if (KspCliOption.PROCESSOR_CLASSPATH_OPTION !in userOptions) { + options[KspCliOption.PROCESSOR_CLASSPATH_OPTION] = processorClasspath(project, execution) + } + if (KspCliOption.WITH_COMPILATION_OPTION !in userOptions) { + options[KspCliOption.WITH_COMPILATION_OPTION] = "true" + } + + val apOptions = userOptions[KspCliOption.PROCESSING_OPTIONS_OPTION] ?: emptyList() + if (apOptions.none { it.startsWith("ktorm.ktlintExecutable=") }) { + options[KspCliOption.PROCESSING_OPTIONS_OPTION] = "ktorm.ktlintExecutable=${ktlintExecutable(project)}" } return options diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt index 4c714ea7a..d494d915d 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt @@ -23,12 +23,12 @@ internal class StandaloneKtLintCodeFormatter(val environment: SymbolProcessorEnv private val command = buildCommand() init { - environment.logger.info("[ktorm-ksp-compiler] init standalone ktlint code formatter with command: $command") + environment.logger.info("[ktorm-ksp-compiler] init ktlint formatter with command: ${command.joinToString(" ")}") } override fun format(code: String): String { try { - val p = Runtime.getRuntime().exec(command) + val p = ProcessBuilder(command).start() p.outputStream.bufferedWriter(Charsets.UTF_8).use { it.write(preprocessCode(code)) } p.waitFor() @@ -45,20 +45,19 @@ internal class StandaloneKtLintCodeFormatter(val environment: SymbolProcessorEnv } } - private fun buildCommand(): String { - val isJava8 = - try { Class.forName("java.lang.reflect.InaccessibleObjectException"); false } - catch (_: ClassNotFoundException) { true } + private fun buildCommand(): List { + val n = "java.lang.reflect.InaccessibleObjectException" + val isJava8 = try { Class.forName(n); false } catch (_: ClassNotFoundException) { true } val java = findJavaExecutable() val ktlint = environment.options["ktorm.ktlintExecutable"]!! val config = createEditorConfigFile() if (isJava8) { - return "$java -jar $ktlint --format --stdin --log-level=none --editorconfig=$config" + return listOf(java, "-jar", ktlint, "-F", "--stdin", "--log-level=none", "--editorconfig=$config") } else { - val jvmArgs = "--add-opens java.base/java.lang=ALL-UNNAMED" - return "$java $jvmArgs -jar $ktlint --format --stdin --log-level=none --editorconfig=$config" + val jvmArgs = arrayOf("--add-opens", "java.base/java.lang=ALL-UNNAMED") + return listOf(java, *jvmArgs, "-jar", ktlint, "-F", "--stdin", "--log-level=none", "--editorconfig=$config") } } From 71b51fe466b8f5c17c0920d132cc6afe94d166ab Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 2 Sep 2023 20:13:37 +0800 Subject: [PATCH 071/105] fix failed tests --- .../org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt index aeeee6626..1e8f9ffbf 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt @@ -33,7 +33,7 @@ internal class KtLintCodeFormatter(val environment: SymbolProcessorEnvironment) .toSet(), editorConfigDefaults = EditorConfigDefaults( EditorConfigLoader.default_().load( - Resources.ofClassPath(javaClass.classLoader, "ktorm-ksp-compiler/.editorconfig", Charsets.UTF_8) + Resources.ofClassPath(javaClass.classLoader, "/ktorm-ksp-compiler/.editorconfig", Charsets.UTF_8) ) ) ) From b8dd64f42efd248d6b817dbf7f099abde02c8e76 Mon Sep 17 00:00:00 2001 From: vince Date: Mon, 4 Sep 2023 22:25:41 +0800 Subject: [PATCH 072/105] ignore ktlint violations --- .../formatter/StandaloneKtLintCodeFormatter.kt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt index d494d915d..652567039 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt @@ -32,12 +32,20 @@ internal class StandaloneKtLintCodeFormatter(val environment: SymbolProcessorEnv p.outputStream.bufferedWriter(Charsets.UTF_8).use { it.write(preprocessCode(code)) } p.waitFor() + val formattedCode = p.inputStream.bufferedReader(Charsets.UTF_8).use { it.readText() } if (p.exitValue() == 0) { - return p.inputStream.bufferedReader(Charsets.UTF_8).use { it.readText() } + // Exit normally. + return formattedCode } else { - val msg = p.errorStream.bufferedReader(Charsets.UTF_8).use { it.readText() } - environment.logger.error("[ktorm-ksp-compiler] ktlint exit with code: ${p.exitValue()}\n$msg") - return code + if (formattedCode.isNotBlank()) { + // Some violations exist but the code is still formatted. + return formattedCode + } else { + // Exit exceptionally. + val msg = p.errorStream.bufferedReader(Charsets.UTF_8).use { it.readText() } + environment.logger.error("[ktorm-ksp-compiler] ktlint exit with code: ${p.exitValue()}\n$msg") + return code + } } } catch (e: Throwable) { environment.logger.exception(e) From fa0965e8264de599b108390c7f8fa2f09e73392c Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 9 Sep 2023 09:52:55 +0800 Subject: [PATCH 073/105] long array sql type --- .../org/ktorm/support/postgresql/SqlTypes.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt index aef420611..d548ed75d 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt @@ -24,6 +24,34 @@ import java.sql.PreparedStatement import java.sql.ResultSet import java.sql.Types +/** + * Define a column typed [LongArraySqlType]. + */ +public fun BaseTable<*>.longArray(name: String): Column { + return registerColumn(name, LongArraySqlType) +} + +/** + * [SqlType] implementation represents PostgreSQL `bigint[]` type. + */ +public object LongArraySqlType : SqlType(Types.ARRAY, "bigint[]") { + + override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: LongArray) { + ps.setObject(index, parameter) + } + + @Suppress("UNCHECKED_CAST") + override fun doGetResult(rs: ResultSet, index: Int): LongArray? { + val sqlArray = rs.getArray(index) ?: return null + try { + val objectArray = sqlArray.array as Array? + return objectArray?.map { it as Long }?.toLongArray() + } finally { + sqlArray.free() + } + } +} + /** * Represent values of PostgreSQL `text[]` SQL type. */ From 78aa56acee7bf7c18dd5acdb305c68f0cea011f8 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 9 Sep 2023 10:00:56 +0800 Subject: [PATCH 074/105] int array sql type --- .../org/ktorm/support/postgresql/SqlTypes.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt index d548ed75d..7e88850bc 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt @@ -24,6 +24,34 @@ import java.sql.PreparedStatement import java.sql.ResultSet import java.sql.Types +/** + * Define a column typed [IntArraySqlType]. + */ +public fun BaseTable<*>.intArray(name: String): Column { + return registerColumn(name, IntArraySqlType) +} + +/** + * [SqlType] implementation represents PostgreSQL `integer[]` type. + */ +public object IntArraySqlType : SqlType(Types.ARRAY, "integer[]") { + + override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: IntArray) { + ps.setObject(index, parameter) + } + + @Suppress("UNCHECKED_CAST") + override fun doGetResult(rs: ResultSet, index: Int): IntArray? { + val sqlArray = rs.getArray(index) ?: return null + try { + val objectArray = sqlArray.array as Array? + return objectArray?.map { it as Int }?.toIntArray() + } finally { + sqlArray.free() + } + } +} + /** * Define a column typed [LongArraySqlType]. */ From 66ed31252b7e148a83db5e3fc896b97df0bead0b Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 9 Sep 2023 10:04:53 +0800 Subject: [PATCH 075/105] short array sql type --- .../org/ktorm/support/postgresql/SqlTypes.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt index 7e88850bc..eb955c9fd 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt @@ -24,6 +24,34 @@ import java.sql.PreparedStatement import java.sql.ResultSet import java.sql.Types +/** + * Define a column typed [ShortArraySqlType]. + */ +public fun BaseTable<*>.shortArray(name: String): Column { + return registerColumn(name, ShortArraySqlType) +} + +/** + * [SqlType] implementation represents PostgreSQL `smallint[]` type. + */ +public object ShortArraySqlType : SqlType(Types.ARRAY, "smallint[]") { + + override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: ShortArray) { + ps.setObject(index, parameter) + } + + @Suppress("UNCHECKED_CAST") + override fun doGetResult(rs: ResultSet, index: Int): ShortArray? { + val sqlArray = rs.getArray(index) ?: return null + try { + val objectArray = sqlArray.array as Array? + return objectArray?.map { it as Short }?.toShortArray() + } finally { + sqlArray.free() + } + } +} + /** * Define a column typed [IntArraySqlType]. */ From 2b5c3d2cd53ab8619e724933fea5ee6acf26e2e3 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 9 Sep 2023 10:24:53 +0800 Subject: [PATCH 076/105] double array sql type --- .../org/ktorm/support/postgresql/SqlTypes.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt index eb955c9fd..f93fe045a 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt @@ -108,6 +108,34 @@ public object LongArraySqlType : SqlType(Types.ARRAY, "bigint[]") { } } +/** + * Define a column typed [DoubleArraySqlType]. + */ +public fun BaseTable<*>.doubleArray(name: String): Column { + return registerColumn(name, DoubleArraySqlType) +} + +/** + * [SqlType] implementation represents PostgreSQL `double[]` type. + */ +public object DoubleArraySqlType : SqlType(Types.ARRAY, "double[]") { + + override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: DoubleArray) { + ps.setObject(index, parameter) + } + + @Suppress("UNCHECKED_CAST") + override fun doGetResult(rs: ResultSet, index: Int): DoubleArray? { + val sqlArray = rs.getArray(index) ?: return null + try { + val objectArray = sqlArray.array as Array? + return objectArray?.map { it as Double }?.toDoubleArray() + } finally { + sqlArray.free() + } + } +} + /** * Represent values of PostgreSQL `text[]` SQL type. */ From cb412364419732342bbca287f7f666096667e131 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 9 Sep 2023 10:28:57 +0800 Subject: [PATCH 077/105] float array sql type --- .../org/ktorm/support/postgresql/SqlTypes.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt index f93fe045a..15fd6ba38 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt @@ -108,6 +108,34 @@ public object LongArraySqlType : SqlType(Types.ARRAY, "bigint[]") { } } +/** + * Define a column typed [FloatArraySqlType]. + */ +public fun BaseTable<*>.floatArray(name: String): Column { + return registerColumn(name, FloatArraySqlType) +} + +/** + * [SqlType] implementation represents PostgreSQL `real[]` type. + */ +public object FloatArraySqlType : SqlType(Types.FLOAT, "real[]") { + + override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: FloatArray) { + ps.setObject(index, parameter) + } + + @Suppress("UNCHECKED_CAST") + override fun doGetResult(rs: ResultSet, index: Int): FloatArray? { + val sqlArray = rs.getArray(index) ?: return null + try { + val objectArray = sqlArray.array as Array? + return objectArray?.map { it as Float }?.toFloatArray() + } finally { + sqlArray.free() + } + } +} + /** * Define a column typed [DoubleArraySqlType]. */ From 04d66beda54549096b6ceb036f140c90850ade6e Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 9 Sep 2023 10:32:57 +0800 Subject: [PATCH 078/105] boolean array sql type --- .../org/ktorm/support/postgresql/SqlTypes.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt index 15fd6ba38..0bfbdd962 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt @@ -164,6 +164,34 @@ public object DoubleArraySqlType : SqlType(Types.ARRAY, "double[]") } } +/** + * Define a column typed [BooleanArraySqlType]. + */ +public fun BaseTable<*>.booleanArray(name: String): Column { + return registerColumn(name, BooleanArraySqlType) +} + +/** + * [SqlType] implementation represents PostgreSQL `boolean[]` type. + */ +public object BooleanArraySqlType : SqlType(Types.ARRAY, "boolean[]") { + + override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: BooleanArray) { + ps.setObject(index, parameter) + } + + @Suppress("UNCHECKED_CAST") + override fun doGetResult(rs: ResultSet, index: Int): BooleanArray? { + val sqlArray = rs.getArray(index) ?: return null + try { + val objectArray = sqlArray.array as Array? + return objectArray?.map { it as Boolean }?.toBooleanArray() + } finally { + sqlArray.free() + } + } +} + /** * Represent values of PostgreSQL `text[]` SQL type. */ From fe78c99289ae0af3c135e0e99ce9327104b8cb04 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 9 Sep 2023 12:00:48 +0800 Subject: [PATCH 079/105] test arrays --- .../org/ktorm/support/postgresql/SqlTypes.kt | 2 +- .../ktorm/support/postgresql/ArraysTest.kt | 62 +++++++++++++++++++ .../ktorm/support/postgresql/HStoreTest.kt | 24 +------ .../test/resources/drop-postgresql-data.sql | 1 + .../test/resources/init-postgresql-data.sql | 18 ++++-- 5 files changed, 79 insertions(+), 28 deletions(-) create mode 100644 ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/ArraysTest.kt diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt index 0bfbdd962..e23bede84 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt @@ -146,7 +146,7 @@ public fun BaseTable<*>.doubleArray(name: String): Column { /** * [SqlType] implementation represents PostgreSQL `double[]` type. */ -public object DoubleArraySqlType : SqlType(Types.ARRAY, "double[]") { +public object DoubleArraySqlType : SqlType(Types.ARRAY, "float8[]") { override fun doSetParameter(ps: PreparedStatement, index: Int, parameter: DoubleArray) { ps.setObject(index, parameter) diff --git a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/ArraysTest.kt b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/ArraysTest.kt new file mode 100644 index 000000000..b3bca85be --- /dev/null +++ b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/ArraysTest.kt @@ -0,0 +1,62 @@ +package org.ktorm.support.postgresql + +import org.junit.Test +import org.ktorm.dsl.* +import org.ktorm.entity.tupleOf +import org.ktorm.schema.Table +import org.ktorm.schema.int + +/** + * Created by vince at Sep 09, 2023. + */ +class ArraysTest : BasePostgreSqlTest() { + + object Arrays : Table("t_array") { + val id = int("id").primaryKey() + val shorts = shortArray("shorts") + val ints = intArray("ints") + val longs = longArray("longs") + val floats = floatArray("floats") + val doubles = doubleArray("doubles") + val booleans = booleanArray("booleans") + val texts = textArray("texts") + } + + @Test + fun testArrays() { + database.insert(Arrays) { + set(it.shorts, shortArrayOf(1, 2, 3, 4)) + set(it.ints, intArrayOf(1, 2, 3, 4)) + set(it.longs, longArrayOf(1, 2, 3, 4)) + set(it.floats, floatArrayOf(1.0F, 2.0F, 3.0F, 4.0F)) + set(it.doubles, doubleArrayOf(1.0, 2.0, 3.0, 4.0)) + set(it.booleans, booleanArrayOf(false, true)) + set(it.texts, arrayOf("1", "2", "3", "4")) + } + + val results = database + .from(Arrays) + .select(Arrays.columns) + .where(Arrays.id eq 1) + .map { row -> + tupleOf( + row[Arrays.shorts], + row[Arrays.ints], + row[Arrays.longs], + row[Arrays.floats], + row[Arrays.doubles], + row[Arrays.booleans], + row[Arrays.texts] + ) + } + + val (shorts, ints, longs, floats, doubles, booleans, texts) = results[0] + assert(shorts.contentEquals(shortArrayOf(1, 2, 3, 4))) + assert(ints.contentEquals(intArrayOf(1, 2, 3, 4))) + assert(longs.contentEquals(longArrayOf(1, 2, 3, 4))) + assert(floats.contentEquals(floatArrayOf(1.0F, 2.0F, 3.0F, 4.0F))) + assert(doubles.contentEquals(doubleArrayOf(1.0, 2.0, 3.0, 4.0))) + assert(booleans.contentEquals(booleanArrayOf(false, true))) + assert(texts.contentEquals(arrayOf("1", "2", "3", "4"))) + } +} \ No newline at end of file diff --git a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/HStoreTest.kt b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/HStoreTest.kt index b4449e694..124a90f02 100644 --- a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/HStoreTest.kt +++ b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/HStoreTest.kt @@ -4,6 +4,7 @@ import org.hamcrest.CoreMatchers import org.hamcrest.MatcherAssert import org.junit.Test import org.ktorm.dsl.* +import org.ktorm.entity.tupleOf import org.ktorm.schema.ColumnDeclaring import org.ktorm.schema.Table import org.ktorm.schema.int @@ -13,7 +14,6 @@ class HStoreTest : BasePostgreSqlTest() { object Metadatas : Table("t_metadata") { val id = int("id").primaryKey() val attributes = hstore("attrs") - val numbers = textArray("numbers") } @Test @@ -148,26 +148,4 @@ class HStoreTest : BasePostgreSqlTest() { val updatedAttributes = get { it.attributes } ?: error("Cannot get the attributes!") MatcherAssert.assertThat(updatedAttributes, CoreMatchers.equalTo(emptyMap())) } - - @Test - fun testTextArray() { - database.update(Metadatas) { - set(it.numbers, arrayOf("a", "b")) - where { it.id eq 1 } - } - - val numbers = get { it.numbers } ?: error("Cannot get the numbers!") - MatcherAssert.assertThat(numbers, CoreMatchers.equalTo(arrayOf("a", "b"))) - } - - @Test - fun testTextArrayIsNull() { - database.update(Metadatas) { - set(it.numbers, null) - where { it.id eq 1 } - } - - val numbers = get { it.numbers } - MatcherAssert.assertThat(numbers, CoreMatchers.nullValue()) - } } \ No newline at end of file diff --git a/ktorm-support-postgresql/src/test/resources/drop-postgresql-data.sql b/ktorm-support-postgresql/src/test/resources/drop-postgresql-data.sql index cfe4c8f5b..0bfc34ecf 100644 --- a/ktorm-support-postgresql/src/test/resources/drop-postgresql-data.sql +++ b/ktorm-support-postgresql/src/test/resources/drop-postgresql-data.sql @@ -2,6 +2,7 @@ drop table if exists t_department; drop table if exists t_employee; drop table if exists t_multi_generated_key; drop table if exists t_metadata; +drop table if exists t_array; drop table if exists t_enum; drop type if exists mood; drop table if exists t_json; diff --git a/ktorm-support-postgresql/src/test/resources/init-postgresql-data.sql b/ktorm-support-postgresql/src/test/resources/init-postgresql-data.sql index a4decd685..d627581a3 100644 --- a/ktorm-support-postgresql/src/test/resources/init-postgresql-data.sql +++ b/ktorm-support-postgresql/src/test/resources/init-postgresql-data.sql @@ -27,8 +27,18 @@ create table t_multi_generated_key( create table t_metadata( id serial primary key, - attrs hstore, - numbers text[] + attrs hstore +); + +create table t_array( + id serial primary key, + shorts smallint[], + ints integer[], + longs bigint[], + floats real[], + doubles float8[], + booleans boolean[], + texts text[] ); create type mood as enum ('SAD', 'HAPPY'); @@ -60,8 +70,8 @@ values ('tom', 'director', null, '2018-01-01', 200, 2); insert into t_employee(name, job, manager_id, hire_date, salary, department_id) values ('penny', 'assistant', 3, '2019-01-01', 100, 2); -insert into t_metadata(attrs, numbers) -values ('a=>1, b=>2, c=>NULL'::hstore, array['a', 'b', 'c']); +insert into t_metadata(attrs) +values ('a=>1, b=>2, c=>NULL'::hstore); insert into t_enum(current_mood) values ('HAPPY') From b6a99110a8781eb6ca5af0fa712c0aa84cfbf9be Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 9 Sep 2023 18:39:58 +0800 Subject: [PATCH 080/105] array_position for text --- .../org/ktorm/support/postgresql/Functions.kt | 68 ++++++++++--------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt index 5c953b744..c0fb89922 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt @@ -16,47 +16,53 @@ package org.ktorm.support.postgresql -import org.ktorm.dsl.cast import org.ktorm.expression.ArgumentExpression import org.ktorm.expression.FunctionExpression import org.ktorm.schema.ColumnDeclaring import org.ktorm.schema.IntSqlType -import org.ktorm.schema.SqlType -import org.ktorm.schema.TextSqlType +import org.ktorm.schema.VarcharSqlType /** - * PostgreSQL array_position function for enums, translated to `array_position(value, cast(column as text))`. - * Uses the `name` attribute of the enums as actual value for the query. - */ -public fun > arrayPosition(value: Array, column: ColumnDeclaring): FunctionExpression = - arrayPosition(value.map { it?.name }.toTypedArray(), column.cast(TextSqlType)) - -/** - * PostgreSQL array_position function for enums, translated to `array_position(value, cast(column as text))`. - * Uses the `name` attribute of the enums as actual value for the query. + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ -public inline fun > arrayPosition( - value: Collection, - column: ColumnDeclaring -): FunctionExpression = - arrayPosition(value.map { it?.name }.toTypedArray(), column.cast(TextSqlType)) +public fun arrayPosition( + array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null +): FunctionExpression { + // array_position(array, value[, offset]) + return FunctionExpression( + functionName = "array_position", + arguments = listOfNotNull( + array.asExpression(), + value.asExpression(), + offset?.let { ArgumentExpression(it, IntSqlType) } + ), + sqlType = IntSqlType + ) +} /** - * PostgreSQL array_position function, translated to `array_position(value, column)`. + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ -public fun arrayPosition(value: TextArray, column: ColumnDeclaring): FunctionExpression = - arrayPosition(value, column, TextArraySqlType) +public fun arrayPosition( + array: ColumnDeclaring, value: String, offset: Int? = null +): FunctionExpression { + return arrayPosition(array, ArgumentExpression(value, VarcharSqlType), offset) +} /** - * PostgreSQL array_position function, translated to `array_position(value, column)`. + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ -public fun arrayPosition( - value: Array, - column: ColumnDeclaring, - arraySqlType: SqlType> -): FunctionExpression = - FunctionExpression( - functionName = "array_position", - arguments = listOf(ArgumentExpression(value, arraySqlType), column.asExpression()), - sqlType = IntSqlType - ) +public fun arrayPosition( + array: TextArray, value: ColumnDeclaring, offset: Int? = null +): FunctionExpression { + return arrayPosition(ArgumentExpression(array, TextArraySqlType), value, offset) +} From 27951f8ce77f6bb6bd0bbd2190413f9b39248bb6 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 9 Sep 2023 18:47:38 +0800 Subject: [PATCH 081/105] array_position for short --- .../org/ktorm/support/postgresql/Functions.kt | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt index c0fb89922..3b268fabd 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt @@ -20,8 +20,54 @@ import org.ktorm.expression.ArgumentExpression import org.ktorm.expression.FunctionExpression import org.ktorm.schema.ColumnDeclaring import org.ktorm.schema.IntSqlType +import org.ktorm.schema.ShortSqlType import org.ktorm.schema.VarcharSqlType +/** + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 + */ +public fun arrayPosition( + array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null +): FunctionExpression { + // array_position(array, value[, offset]) + return FunctionExpression( + functionName = "array_position", + arguments = listOfNotNull( + array.asExpression(), + value.asExpression(), + offset?.let { ArgumentExpression(it, IntSqlType) } + ), + sqlType = IntSqlType + ) +} + +/** + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 + */ +public fun arrayPosition( + array: ColumnDeclaring, value: Short, offset: Int? = null +): FunctionExpression { + return arrayPosition(array, ArgumentExpression(value, ShortSqlType), offset) +} + +/** + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 + */ +public fun arrayPosition( + array: ShortArray, value: ColumnDeclaring, offset: Int? = null +): FunctionExpression { + return arrayPosition(ArgumentExpression(array, ShortArraySqlType), value, offset) +} + /** * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. From 1c45b0cd833fa5136a08fca88a7dee8c56f084d3 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 9 Sep 2023 18:50:18 +0800 Subject: [PATCH 082/105] array_position for int --- .../org/ktorm/support/postgresql/Functions.kt | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt index 3b268fabd..ac1c4a7e1 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt @@ -68,6 +68,51 @@ public fun arrayPosition( return arrayPosition(ArgumentExpression(array, ShortArraySqlType), value, offset) } +/** + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 + */ +public fun arrayPosition( + array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null +): FunctionExpression { + // array_position(array, value[, offset]) + return FunctionExpression( + functionName = "array_position", + arguments = listOfNotNull( + array.asExpression(), + value.asExpression(), + offset?.let { ArgumentExpression(it, IntSqlType) } + ), + sqlType = IntSqlType + ) +} + +/** + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 + */ +public fun arrayPosition( + array: ColumnDeclaring, value: Int, offset: Int? = null +): FunctionExpression { + return arrayPosition(array, ArgumentExpression(value, IntSqlType), offset) +} + +/** + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 + */ +public fun arrayPosition( + array: IntArray, value: ColumnDeclaring, offset: Int? = null +): FunctionExpression { + return arrayPosition(ArgumentExpression(array, IntArraySqlType), value, offset) +} + /** * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. From 687af3d48273967293b875e1d8e9d0f2a0822a58 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 9 Sep 2023 18:52:18 +0800 Subject: [PATCH 083/105] array_position for long --- .../org/ktorm/support/postgresql/Functions.kt | 50 +++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt index ac1c4a7e1..0f9480867 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt @@ -18,10 +18,7 @@ package org.ktorm.support.postgresql import org.ktorm.expression.ArgumentExpression import org.ktorm.expression.FunctionExpression -import org.ktorm.schema.ColumnDeclaring -import org.ktorm.schema.IntSqlType -import org.ktorm.schema.ShortSqlType -import org.ktorm.schema.VarcharSqlType +import org.ktorm.schema.* /** * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. @@ -113,6 +110,51 @@ public fun arrayPosition( return arrayPosition(ArgumentExpression(array, IntArraySqlType), value, offset) } +/** + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 + */ +public fun arrayPosition( + array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null +): FunctionExpression { + // array_position(array, value[, offset]) + return FunctionExpression( + functionName = "array_position", + arguments = listOfNotNull( + array.asExpression(), + value.asExpression(), + offset?.let { ArgumentExpression(it, IntSqlType) } + ), + sqlType = IntSqlType + ) +} + +/** + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 + */ +public fun arrayPosition( + array: ColumnDeclaring, value: Long, offset: Int? = null +): FunctionExpression { + return arrayPosition(array, ArgumentExpression(value, LongSqlType), offset) +} + +/** + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 + */ +public fun arrayPosition( + array: LongArray, value: ColumnDeclaring, offset: Int? = null +): FunctionExpression { + return arrayPosition(ArgumentExpression(array, LongArraySqlType), value, offset) +} + /** * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. From 0ce6d32dc3ceff3a2325dc2322dd081acb0e2815 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 9 Sep 2023 18:55:25 +0800 Subject: [PATCH 084/105] array_position for boolean --- .../org/ktorm/support/postgresql/Functions.kt | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt index 0f9480867..c26e1c259 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt @@ -155,6 +155,51 @@ public fun arrayPosition( return arrayPosition(ArgumentExpression(array, LongArraySqlType), value, offset) } +/** + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 + */ +public fun arrayPosition( + array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null +): FunctionExpression { + // array_position(array, value[, offset]) + return FunctionExpression( + functionName = "array_position", + arguments = listOfNotNull( + array.asExpression(), + value.asExpression(), + offset?.let { ArgumentExpression(it, IntSqlType) } + ), + sqlType = IntSqlType + ) +} + +/** + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 + */ +public fun arrayPosition( + array: ColumnDeclaring, value: Boolean, offset: Int? = null +): FunctionExpression { + return arrayPosition(array, ArgumentExpression(value, BooleanSqlType), offset) +} + +/** + * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. + * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. + * + * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 + */ +public fun arrayPosition( + array: BooleanArray, value: ColumnDeclaring, offset: Int? = null +): FunctionExpression { + return arrayPosition(ArgumentExpression(array, BooleanArraySqlType), value, offset) +} + /** * Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present. * If the third argument is given, the search begins at that subscript. The array must be one-dimensional. From f28840805bf6caff3f63dbc82f265c99e770c18b Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 9 Sep 2023 20:01:38 +0800 Subject: [PATCH 085/105] array_position impl --- .../org/ktorm/support/postgresql/Functions.kt | 93 +++++++------------ 1 file changed, 33 insertions(+), 60 deletions(-) diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt index c26e1c259..8d0e7dd27 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt @@ -29,16 +29,7 @@ import org.ktorm.schema.* public fun arrayPosition( array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { - // array_position(array, value[, offset]) - return FunctionExpression( - functionName = "array_position", - arguments = listOfNotNull( - array.asExpression(), - value.asExpression(), - offset?.let { ArgumentExpression(it, IntSqlType) } - ), - sqlType = IntSqlType - ) + return arrayPositionImpl(array, value, offset) } /** @@ -50,7 +41,7 @@ public fun arrayPosition( public fun arrayPosition( array: ColumnDeclaring, value: Short, offset: Int? = null ): FunctionExpression { - return arrayPosition(array, ArgumentExpression(value, ShortSqlType), offset) + return arrayPositionImpl(array, ArgumentExpression(value, ShortSqlType), offset) } /** @@ -62,7 +53,7 @@ public fun arrayPosition( public fun arrayPosition( array: ShortArray, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { - return arrayPosition(ArgumentExpression(array, ShortArraySqlType), value, offset) + return arrayPositionImpl(ArgumentExpression(array, ShortArraySqlType), value, offset) } /** @@ -74,16 +65,7 @@ public fun arrayPosition( public fun arrayPosition( array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { - // array_position(array, value[, offset]) - return FunctionExpression( - functionName = "array_position", - arguments = listOfNotNull( - array.asExpression(), - value.asExpression(), - offset?.let { ArgumentExpression(it, IntSqlType) } - ), - sqlType = IntSqlType - ) + return arrayPositionImpl(array, value, offset) } /** @@ -95,7 +77,7 @@ public fun arrayPosition( public fun arrayPosition( array: ColumnDeclaring, value: Int, offset: Int? = null ): FunctionExpression { - return arrayPosition(array, ArgumentExpression(value, IntSqlType), offset) + return arrayPositionImpl(array, ArgumentExpression(value, IntSqlType), offset) } /** @@ -107,7 +89,7 @@ public fun arrayPosition( public fun arrayPosition( array: IntArray, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { - return arrayPosition(ArgumentExpression(array, IntArraySqlType), value, offset) + return arrayPositionImpl(ArgumentExpression(array, IntArraySqlType), value, offset) } /** @@ -119,16 +101,7 @@ public fun arrayPosition( public fun arrayPosition( array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { - // array_position(array, value[, offset]) - return FunctionExpression( - functionName = "array_position", - arguments = listOfNotNull( - array.asExpression(), - value.asExpression(), - offset?.let { ArgumentExpression(it, IntSqlType) } - ), - sqlType = IntSqlType - ) + return arrayPositionImpl(array, value, offset) } /** @@ -140,7 +113,7 @@ public fun arrayPosition( public fun arrayPosition( array: ColumnDeclaring, value: Long, offset: Int? = null ): FunctionExpression { - return arrayPosition(array, ArgumentExpression(value, LongSqlType), offset) + return arrayPositionImpl(array, ArgumentExpression(value, LongSqlType), offset) } /** @@ -152,7 +125,7 @@ public fun arrayPosition( public fun arrayPosition( array: LongArray, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { - return arrayPosition(ArgumentExpression(array, LongArraySqlType), value, offset) + return arrayPositionImpl(ArgumentExpression(array, LongArraySqlType), value, offset) } /** @@ -164,16 +137,7 @@ public fun arrayPosition( public fun arrayPosition( array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { - // array_position(array, value[, offset]) - return FunctionExpression( - functionName = "array_position", - arguments = listOfNotNull( - array.asExpression(), - value.asExpression(), - offset?.let { ArgumentExpression(it, IntSqlType) } - ), - sqlType = IntSqlType - ) + return arrayPositionImpl(array, value, offset) } /** @@ -185,7 +149,7 @@ public fun arrayPosition( public fun arrayPosition( array: ColumnDeclaring, value: Boolean, offset: Int? = null ): FunctionExpression { - return arrayPosition(array, ArgumentExpression(value, BooleanSqlType), offset) + return arrayPositionImpl(array, ArgumentExpression(value, BooleanSqlType), offset) } /** @@ -197,7 +161,7 @@ public fun arrayPosition( public fun arrayPosition( array: BooleanArray, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { - return arrayPosition(ArgumentExpression(array, BooleanArraySqlType), value, offset) + return arrayPositionImpl(ArgumentExpression(array, BooleanArraySqlType), value, offset) } /** @@ -209,16 +173,7 @@ public fun arrayPosition( public fun arrayPosition( array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { - // array_position(array, value[, offset]) - return FunctionExpression( - functionName = "array_position", - arguments = listOfNotNull( - array.asExpression(), - value.asExpression(), - offset?.let { ArgumentExpression(it, IntSqlType) } - ), - sqlType = IntSqlType - ) + return arrayPositionImpl(array, value, offset) } /** @@ -230,7 +185,7 @@ public fun arrayPosition( public fun arrayPosition( array: ColumnDeclaring, value: String, offset: Int? = null ): FunctionExpression { - return arrayPosition(array, ArgumentExpression(value, VarcharSqlType), offset) + return arrayPositionImpl(array, ArgumentExpression(value, VarcharSqlType), offset) } /** @@ -242,5 +197,23 @@ public fun arrayPosition( public fun arrayPosition( array: TextArray, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { - return arrayPosition(ArgumentExpression(array, TextArraySqlType), value, offset) + return arrayPositionImpl(ArgumentExpression(array, TextArraySqlType), value, offset) +} + +/** + * array_position implementation. + */ +private fun arrayPositionImpl( + array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null +): FunctionExpression { + // array_position(array, value[, offset]) + return FunctionExpression( + functionName = "array_position", + arguments = listOfNotNull( + array.asExpression(), + value.asExpression(), + offset?.let { ArgumentExpression(it, IntSqlType) } + ), + sqlType = IntSqlType + ) } From 0a35211c0f4a649ce69fc08426cae53d506c2e01 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 9 Sep 2023 23:33:45 +0800 Subject: [PATCH 086/105] test array position --- .../org/ktorm/support/postgresql/Functions.kt | 15 +++++ .../support/postgresql/BasePostgreSqlTest.kt | 13 ---- .../ktorm/support/postgresql/CommonTest.kt | 10 +++ .../ktorm/support/postgresql/FunctionsTest.kt | 64 ++++++++++--------- 4 files changed, 60 insertions(+), 42 deletions(-) diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt index 8d0e7dd27..b64e2abcb 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt @@ -26,6 +26,7 @@ import org.ktorm.schema.* * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("shortArrayPosition") public fun arrayPosition( array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { @@ -38,6 +39,7 @@ public fun arrayPosition( * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("shortArrayPosition") public fun arrayPosition( array: ColumnDeclaring, value: Short, offset: Int? = null ): FunctionExpression { @@ -50,6 +52,7 @@ public fun arrayPosition( * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("shortArrayPosition") public fun arrayPosition( array: ShortArray, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { @@ -62,6 +65,7 @@ public fun arrayPosition( * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("intArrayPosition") public fun arrayPosition( array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { @@ -74,6 +78,7 @@ public fun arrayPosition( * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("intArrayPosition") public fun arrayPosition( array: ColumnDeclaring, value: Int, offset: Int? = null ): FunctionExpression { @@ -86,6 +91,7 @@ public fun arrayPosition( * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("intArrayPosition") public fun arrayPosition( array: IntArray, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { @@ -98,6 +104,7 @@ public fun arrayPosition( * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("longArrayPosition") public fun arrayPosition( array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { @@ -110,6 +117,7 @@ public fun arrayPosition( * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("longArrayPosition") public fun arrayPosition( array: ColumnDeclaring, value: Long, offset: Int? = null ): FunctionExpression { @@ -122,6 +130,7 @@ public fun arrayPosition( * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("longArrayPosition") public fun arrayPosition( array: LongArray, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { @@ -134,6 +143,7 @@ public fun arrayPosition( * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("booleanArrayPosition") public fun arrayPosition( array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { @@ -146,6 +156,7 @@ public fun arrayPosition( * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("booleanArrayPosition") public fun arrayPosition( array: ColumnDeclaring, value: Boolean, offset: Int? = null ): FunctionExpression { @@ -158,6 +169,7 @@ public fun arrayPosition( * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("booleanArrayPosition") public fun arrayPosition( array: BooleanArray, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { @@ -170,6 +182,7 @@ public fun arrayPosition( * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("textArrayPosition") public fun arrayPosition( array: ColumnDeclaring, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { @@ -182,6 +195,7 @@ public fun arrayPosition( * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("textArrayPosition") public fun arrayPosition( array: ColumnDeclaring, value: String, offset: Int? = null ): FunctionExpression { @@ -194,6 +208,7 @@ public fun arrayPosition( * * array_position(ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'], 'mon') → 2 */ +@JvmName("textArrayPosition") public fun arrayPosition( array: TextArray, value: ColumnDeclaring, offset: Int? = null ): FunctionExpression { diff --git a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/BasePostgreSqlTest.kt b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/BasePostgreSqlTest.kt index 68d3178d8..b602dda7b 100644 --- a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/BasePostgreSqlTest.kt +++ b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/BasePostgreSqlTest.kt @@ -2,9 +2,6 @@ package org.ktorm.support.postgresql import org.ktorm.BaseTest import org.ktorm.database.Database -import org.ktorm.schema.Table -import org.ktorm.schema.enum -import org.ktorm.schema.int import org.testcontainers.containers.PostgreSQLContainer import kotlin.concurrent.thread @@ -27,14 +24,4 @@ abstract class BasePostgreSqlTest : BaseTest() { Runtime.getRuntime().addShutdownHook(thread(start = false) { stop() }) } } - - enum class Mood { - HAPPY, - SAD - } - - object TableWithEnum : Table("t_enum") { - val id = int("id").primaryKey() - val current_mood = enum("current_mood") - } } diff --git a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/CommonTest.kt b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/CommonTest.kt index 1edd2a6df..8c146c03e 100644 --- a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/CommonTest.kt +++ b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/CommonTest.kt @@ -7,6 +7,7 @@ import org.ktorm.database.use import org.ktorm.dsl.* import org.ktorm.entity.* import org.ktorm.schema.Table +import org.ktorm.schema.enum import org.ktorm.schema.int import org.ktorm.schema.varchar import java.util.concurrent.ExecutionException @@ -147,7 +148,16 @@ class CommonTest : BasePostgreSqlTest() { println(e.message) assert("too long" in e.message!!) } + } + + enum class Mood { + HAPPY, + SAD + } + object TableWithEnum : Table("t_enum") { + val id = int("id").primaryKey() + val current_mood = enum("current_mood") } @Test diff --git a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/FunctionsTest.kt b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/FunctionsTest.kt index 4f3619f79..30d494ba7 100644 --- a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/FunctionsTest.kt +++ b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/FunctionsTest.kt @@ -2,47 +2,53 @@ package org.ktorm.support.postgresql import org.junit.Test import org.ktorm.dsl.* +import org.ktorm.entity.tupleOf +import org.ktorm.schema.Table +import org.ktorm.schema.int import kotlin.test.assertEquals class FunctionsTest : BasePostgreSqlTest() { - @Test - fun testArrayPositionEnumCollection() { - database.insert(TableWithEnum) { - set(it.current_mood, Mood.SAD) - } - database.insert(TableWithEnum) { - set(it.current_mood, Mood.HAPPY) - } - val moodsSorted = database - .from(TableWithEnum) - .select() - .orderBy(arrayPosition(listOf(Mood.SAD, Mood.HAPPY), TableWithEnum.current_mood).asc()) - .map { row -> - row[TableWithEnum.current_mood] - } - - assertEquals(listOf(Mood.SAD, Mood.HAPPY, Mood.HAPPY), moodsSorted) + object Arrays : Table("t_array") { + val id = int("id").primaryKey() + val shorts = shortArray("shorts") + val ints = intArray("ints") + val longs = longArray("longs") + val floats = floatArray("floats") + val doubles = doubleArray("doubles") + val booleans = booleanArray("booleans") + val texts = textArray("texts") } @Test - fun testArrayPositionEnumArray() { - database.insert(TableWithEnum) { - set(it.current_mood, Mood.SAD) - } - database.insert(TableWithEnum) { - set(it.current_mood, Mood.HAPPY) + fun testArrayPosition() { + database.insert(Arrays) { + set(it.shorts, shortArrayOf(1, 2, 3, 4)) + set(it.ints, intArrayOf(1, 2, 3, 4)) + set(it.longs, longArrayOf(1, 2, 3, 4)) + set(it.floats, floatArrayOf(1.0F, 2.0F, 3.0F, 4.0F)) + set(it.doubles, doubleArrayOf(1.0, 2.0, 3.0, 4.0)) + set(it.booleans, booleanArrayOf(false, true)) + set(it.texts, arrayOf("1", "2", "3", "4")) } - val moodsSorted = database - .from(TableWithEnum) - .select() - .orderBy(arrayPosition(arrayOf(Mood.SAD, Mood.HAPPY), TableWithEnum.current_mood).asc()) + val results = database + .from(Arrays) + .select( + arrayPosition(Arrays.shorts, 2), + arrayPosition(Arrays.ints, 2, 1), + arrayPosition(Arrays.longs, 2), + arrayPosition(Arrays.booleans, true), + arrayPosition(Arrays.texts, "2") + ) + .where(Arrays.id eq 1) .map { row -> - row[TableWithEnum.current_mood] + tupleOf(row.getInt(1), row.getInt(2), row.getInt(3), row.getInt(4), row.getInt(5)) } - assertEquals(listOf(Mood.SAD, Mood.HAPPY, Mood.HAPPY), moodsSorted) + println(results) + assert(results.size == 1) + assert(results[0] == tupleOf(1, 1, 1, 1, 2)) // text[] is one-based, others are zero-based. } @Test From 61ccfd27f500022150407b882012fe6a07059b71 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 20 Apr 2024 18:37:41 +0800 Subject: [PATCH 087/105] update copyright year --- buildSrc/src/main/kotlin/ktorm.source-header-check.gradle.kts | 2 +- buildSrc/src/main/kotlin/ktorm.tuples-codegen.gradle.kts | 2 +- ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt | 2 +- .../src/main/kotlin/org/ktorm/database/CachedRowSetMetadata.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/database/Database.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/database/JdbcExtensions.kt | 2 +- .../main/kotlin/org/ktorm/database/JdbcTransactionManager.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/database/Keywords.kt | 2 +- .../org/ktorm/database/SpringManagedTransactionManager.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/database/SqlDialect.kt | 2 +- .../src/main/kotlin/org/ktorm/database/TransactionManager.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/dsl/Aggregation.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/dsl/CaseWhen.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/dsl/CountExpression.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/dsl/Dml.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/dsl/Operators.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/dsl/Query.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/dsl/QueryRowSet.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/dsl/QuerySource.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/dsl/WindowFunctions.kt | 2 +- .../src/main/kotlin/org/ktorm/entity/DefaultMethodHandler.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/entity/Entity.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/entity/EntityDml.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/entity/EntityExtensions.kt | 2 +- .../src/main/kotlin/org/ktorm/entity/EntityExtensionsApi.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/entity/EntityGrouping.kt | 2 +- .../src/main/kotlin/org/ktorm/entity/EntityImplementation.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/entity/EntitySequence.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/entity/Reflections.kt | 2 +- .../main/kotlin/org/ktorm/expression/SqlExpressionVisitor.kt | 2 +- .../org/ktorm/expression/SqlExpressionVisitorInterceptor.kt | 2 +- .../src/main/kotlin/org/ktorm/expression/SqlExpressions.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/expression/SqlFormatter.kt | 2 +- .../src/main/kotlin/org/ktorm/logging/AndroidLoggerAdapter.kt | 2 +- .../src/main/kotlin/org/ktorm/logging/CommonsLoggerAdapter.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/logging/ConsoleLogger.kt | 2 +- .../src/main/kotlin/org/ktorm/logging/JdkLoggerAdapter.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/logging/Logger.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/logging/NoOpLogger.kt | 2 +- .../src/main/kotlin/org/ktorm/logging/Slf4jLoggerAdapter.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/schema/BaseTable.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/schema/Column.kt | 2 +- .../src/main/kotlin/org/ktorm/schema/ColumnBindingHandler.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/schema/RefCounter.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/schema/SqlType.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/schema/SqlTypes.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/schema/Table.kt | 2 +- ktorm-core/src/main/kotlin/org/ktorm/schema/TypeReference.kt | 2 +- ktorm-global/src/main/kotlin/org/ktorm/global/Aggregations.kt | 2 +- ktorm-global/src/main/kotlin/org/ktorm/global/Dml.kt | 2 +- ktorm-global/src/main/kotlin/org/ktorm/global/EntitySequence.kt | 2 +- ktorm-global/src/main/kotlin/org/ktorm/global/Global.kt | 2 +- ktorm-global/src/main/kotlin/org/ktorm/global/Query.kt | 2 +- .../src/main/kotlin/org/ktorm/jackson/EntityDeserializers.kt | 2 +- .../src/main/kotlin/org/ktorm/jackson/EntitySerializers.kt | 2 +- .../main/kotlin/org/ktorm/jackson/EntityTypeResolverBuilder.kt | 2 +- .../src/main/kotlin/org/ktorm/jackson/JacksonExtensions.kt | 2 +- ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JsonSqlType.kt | 2 +- ktorm-jackson/src/main/kotlin/org/ktorm/jackson/KtormModule.kt | 2 +- .../src/main/kotlin/org/ktorm/jackson/PackageVersion.kt.tmpl | 2 +- .../src/main/kotlin/org/ktorm/ksp/annotation/Column.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/annotation/Ignore.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/annotation/PrimaryKey.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/annotation/References.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/annotation/Table.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt | 2 +- .../ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt | 2 +- .../kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt | 2 +- .../kotlin/org/ktorm/ksp/compiler/formatter/CodeFormatter.kt | 2 +- .../org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt | 2 +- .../ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt | 2 +- .../org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt | 2 +- .../ktorm/ksp/compiler/generator/ComponentFunctionGenerator.kt | 2 +- .../org/ktorm/ksp/compiler/generator/CopyFunctionGenerator.kt | 2 +- .../ksp/compiler/generator/EntitySequencePropertyGenerator.kt | 2 +- .../kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt | 2 +- .../compiler/generator/PseudoConstructorFunctionGenerator.kt | 2 +- .../org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt | 2 +- .../org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt | 2 +- .../org/ktorm/ksp/compiler/generator/TableClassGenerator.kt | 2 +- .../org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt | 2 +- .../main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt | 2 +- .../main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt | 2 +- .../main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/spi/DatabaseNamingStrategy.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/spi/ExtCodeGenerator.kt | 2 +- .../src/main/kotlin/org/ktorm/ksp/spi/TableMetadata.kt | 2 +- .../src/main/kotlin/org/ktorm/support/mysql/BulkInsert.kt | 2 +- .../src/main/kotlin/org/ktorm/support/mysql/DefaultValue.kt | 2 +- .../src/main/kotlin/org/ktorm/support/mysql/Functions.kt | 2 +- .../src/main/kotlin/org/ktorm/support/mysql/Global.kt | 2 +- .../src/main/kotlin/org/ktorm/support/mysql/InsertOrUpdate.kt | 2 +- .../src/main/kotlin/org/ktorm/support/mysql/Lock.kt | 2 +- .../src/main/kotlin/org/ktorm/support/mysql/MatchAgainst.kt | 2 +- .../src/main/kotlin/org/ktorm/support/mysql/MySqlDialect.kt | 2 +- .../kotlin/org/ktorm/support/mysql/MySqlExpressionVisitor.kt | 2 +- .../src/main/kotlin/org/ktorm/support/mysql/MySqlFormatter.kt | 2 +- .../src/main/kotlin/org/ktorm/support/mysql/NaturalJoin.kt | 2 +- .../src/main/kotlin/org/ktorm/support/oracle/OracleDialect.kt | 2 +- .../src/main/kotlin/org/ktorm/support/oracle/OracleFormatter.kt | 2 +- .../src/main/kotlin/org/ktorm/support/postgresql/BulkInsert.kt | 2 +- .../main/kotlin/org/ktorm/support/postgresql/DefaultValue.kt | 2 +- .../main/kotlin/org/ktorm/support/postgresql/EarthDistance.kt | 2 +- .../src/main/kotlin/org/ktorm/support/postgresql/Functions.kt | 2 +- .../src/main/kotlin/org/ktorm/support/postgresql/Global.kt | 2 +- .../src/main/kotlin/org/ktorm/support/postgresql/HStore.kt | 2 +- .../src/main/kotlin/org/ktorm/support/postgresql/ILike.kt | 2 +- .../main/kotlin/org/ktorm/support/postgresql/InsertOrUpdate.kt | 2 +- .../src/main/kotlin/org/ktorm/support/postgresql/Lock.kt | 2 +- .../kotlin/org/ktorm/support/postgresql/PostgreSqlDialect.kt | 2 +- .../org/ktorm/support/postgresql/PostgreSqlExpressionVisitor.kt | 2 +- .../kotlin/org/ktorm/support/postgresql/PostgreSqlFormatter.kt | 2 +- .../src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt | 2 +- .../src/main/kotlin/org/ktorm/support/sqlite/BulkInsert.kt | 2 +- .../src/main/kotlin/org/ktorm/support/sqlite/Functions.kt | 2 +- .../src/main/kotlin/org/ktorm/support/sqlite/InsertOrUpdate.kt | 2 +- .../src/main/kotlin/org/ktorm/support/sqlite/SQLiteDialect.kt | 2 +- .../kotlin/org/ktorm/support/sqlite/SQLiteExpressionVisitor.kt | 2 +- .../src/main/kotlin/org/ktorm/support/sqlite/SQLiteFormatter.kt | 2 +- .../main/kotlin/org/ktorm/support/sqlserver/SqlServerDialect.kt | 2 +- .../kotlin/org/ktorm/support/sqlserver/SqlServerFormatter.kt | 2 +- .../src/main/kotlin/org/ktorm/support/sqlserver/SqlTypes.kt | 2 +- 125 files changed, 125 insertions(+), 125 deletions(-) diff --git a/buildSrc/src/main/kotlin/ktorm.source-header-check.gradle.kts b/buildSrc/src/main/kotlin/ktorm.source-header-check.gradle.kts index 392ca572c..8590632f5 100644 --- a/buildSrc/src/main/kotlin/ktorm.source-header-check.gradle.kts +++ b/buildSrc/src/main/kotlin/ktorm.source-header-check.gradle.kts @@ -5,7 +5,7 @@ plugins { val licenseHeaderText = """ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/buildSrc/src/main/kotlin/ktorm.tuples-codegen.gradle.kts b/buildSrc/src/main/kotlin/ktorm.tuples-codegen.gradle.kts index 6e4cdf009..0ab69909b 100644 --- a/buildSrc/src/main/kotlin/ktorm.tuples-codegen.gradle.kts +++ b/buildSrc/src/main/kotlin/ktorm.tuples-codegen.gradle.kts @@ -282,7 +282,7 @@ val generateTuples by tasks.registering { outputFile.bufferedWriter().use { writer -> writer.write(""" /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt b/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt index d6ee5e78e..bf54dd33f 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSetMetadata.kt b/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSetMetadata.kt index cf3e359d9..ce14f5ec3 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSetMetadata.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSetMetadata.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/database/Database.kt b/ktorm-core/src/main/kotlin/org/ktorm/database/Database.kt index 070216a11..b903d0d04 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/database/Database.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/database/Database.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/database/JdbcExtensions.kt b/ktorm-core/src/main/kotlin/org/ktorm/database/JdbcExtensions.kt index b59ad85f7..5a986ea9b 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/database/JdbcExtensions.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/database/JdbcExtensions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/database/JdbcTransactionManager.kt b/ktorm-core/src/main/kotlin/org/ktorm/database/JdbcTransactionManager.kt index 9596689d0..f88cf4346 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/database/JdbcTransactionManager.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/database/JdbcTransactionManager.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/database/Keywords.kt b/ktorm-core/src/main/kotlin/org/ktorm/database/Keywords.kt index e59bfe56b..48935076b 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/database/Keywords.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/database/Keywords.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/database/SpringManagedTransactionManager.kt b/ktorm-core/src/main/kotlin/org/ktorm/database/SpringManagedTransactionManager.kt index 37c518b41..1df52ba2f 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/database/SpringManagedTransactionManager.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/database/SpringManagedTransactionManager.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/database/SqlDialect.kt b/ktorm-core/src/main/kotlin/org/ktorm/database/SqlDialect.kt index c131ad6d0..a8e13f167 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/database/SqlDialect.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/database/SqlDialect.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/database/TransactionManager.kt b/ktorm-core/src/main/kotlin/org/ktorm/database/TransactionManager.kt index 67c412cfe..f7a9eae8d 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/database/TransactionManager.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/database/TransactionManager.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/dsl/Aggregation.kt b/ktorm-core/src/main/kotlin/org/ktorm/dsl/Aggregation.kt index 4479a625f..5bf1d6a96 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/dsl/Aggregation.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/dsl/Aggregation.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/dsl/CaseWhen.kt b/ktorm-core/src/main/kotlin/org/ktorm/dsl/CaseWhen.kt index cde1868bc..26cb22e3b 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/dsl/CaseWhen.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/dsl/CaseWhen.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/dsl/CountExpression.kt b/ktorm-core/src/main/kotlin/org/ktorm/dsl/CountExpression.kt index bd3f24a36..11c5ec260 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/dsl/CountExpression.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/dsl/CountExpression.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/dsl/Dml.kt b/ktorm-core/src/main/kotlin/org/ktorm/dsl/Dml.kt index bb3268e99..f30ce1b1a 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/dsl/Dml.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/dsl/Dml.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/dsl/Operators.kt b/ktorm-core/src/main/kotlin/org/ktorm/dsl/Operators.kt index 7461d99e1..152d6ce2d 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/dsl/Operators.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/dsl/Operators.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/dsl/Query.kt b/ktorm-core/src/main/kotlin/org/ktorm/dsl/Query.kt index 1bfd7eb12..652a18e91 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/dsl/Query.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/dsl/Query.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/dsl/QueryRowSet.kt b/ktorm-core/src/main/kotlin/org/ktorm/dsl/QueryRowSet.kt index a13eff7e3..7c5b25f8b 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/dsl/QueryRowSet.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/dsl/QueryRowSet.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/dsl/QuerySource.kt b/ktorm-core/src/main/kotlin/org/ktorm/dsl/QuerySource.kt index 3c90e7e89..490d80ac6 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/dsl/QuerySource.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/dsl/QuerySource.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/dsl/WindowFunctions.kt b/ktorm-core/src/main/kotlin/org/ktorm/dsl/WindowFunctions.kt index ba70a5320..0376e4547 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/dsl/WindowFunctions.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/dsl/WindowFunctions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/entity/DefaultMethodHandler.kt b/ktorm-core/src/main/kotlin/org/ktorm/entity/DefaultMethodHandler.kt index f92a07d73..184a0ad78 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/entity/DefaultMethodHandler.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/entity/DefaultMethodHandler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/entity/Entity.kt b/ktorm-core/src/main/kotlin/org/ktorm/entity/Entity.kt index ce2d1cc62..2630ad24f 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/entity/Entity.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/entity/Entity.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityDml.kt b/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityDml.kt index 2e827d3b0..bfed33b71 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityDml.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityDml.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityExtensions.kt b/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityExtensions.kt index e2d341043..caf34f73f 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityExtensions.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityExtensions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityExtensionsApi.kt b/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityExtensionsApi.kt index d3e4cf2b1..b0134fc3b 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityExtensionsApi.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityExtensionsApi.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityGrouping.kt b/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityGrouping.kt index 27165d38b..3e6e528e9 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityGrouping.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityGrouping.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityImplementation.kt b/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityImplementation.kt index 7bbd8a082..a1b1f769e 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityImplementation.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/entity/EntityImplementation.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/entity/EntitySequence.kt b/ktorm-core/src/main/kotlin/org/ktorm/entity/EntitySequence.kt index 608751092..080442cfa 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/entity/EntitySequence.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/entity/EntitySequence.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/entity/Reflections.kt b/ktorm-core/src/main/kotlin/org/ktorm/entity/Reflections.kt index 5b3e12d92..e0e8f1a47 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/entity/Reflections.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/entity/Reflections.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlExpressionVisitor.kt b/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlExpressionVisitor.kt index 967b239ad..91f560165 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlExpressionVisitor.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlExpressionVisitor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlExpressionVisitorInterceptor.kt b/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlExpressionVisitorInterceptor.kt index f89829ad7..f60f3ba0e 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlExpressionVisitorInterceptor.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlExpressionVisitorInterceptor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlExpressions.kt b/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlExpressions.kt index ddc1ad7d5..8e9701ed9 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlExpressions.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlExpressions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlFormatter.kt b/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlFormatter.kt index 9d55740d4..a3db1b64e 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlFormatter.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/expression/SqlFormatter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/logging/AndroidLoggerAdapter.kt b/ktorm-core/src/main/kotlin/org/ktorm/logging/AndroidLoggerAdapter.kt index f6f6532d5..acd993053 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/logging/AndroidLoggerAdapter.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/logging/AndroidLoggerAdapter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/logging/CommonsLoggerAdapter.kt b/ktorm-core/src/main/kotlin/org/ktorm/logging/CommonsLoggerAdapter.kt index 8284631fb..aa711a3e9 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/logging/CommonsLoggerAdapter.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/logging/CommonsLoggerAdapter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/logging/ConsoleLogger.kt b/ktorm-core/src/main/kotlin/org/ktorm/logging/ConsoleLogger.kt index 8771a0aff..22c5c77f5 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/logging/ConsoleLogger.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/logging/ConsoleLogger.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/logging/JdkLoggerAdapter.kt b/ktorm-core/src/main/kotlin/org/ktorm/logging/JdkLoggerAdapter.kt index 5eabaea4d..c0eff0dc0 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/logging/JdkLoggerAdapter.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/logging/JdkLoggerAdapter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/logging/Logger.kt b/ktorm-core/src/main/kotlin/org/ktorm/logging/Logger.kt index 2a75dcf1b..aa51068ea 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/logging/Logger.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/logging/Logger.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/logging/NoOpLogger.kt b/ktorm-core/src/main/kotlin/org/ktorm/logging/NoOpLogger.kt index c741fec17..8e4e577eb 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/logging/NoOpLogger.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/logging/NoOpLogger.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/logging/Slf4jLoggerAdapter.kt b/ktorm-core/src/main/kotlin/org/ktorm/logging/Slf4jLoggerAdapter.kt index f508a2331..037270123 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/logging/Slf4jLoggerAdapter.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/logging/Slf4jLoggerAdapter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/schema/BaseTable.kt b/ktorm-core/src/main/kotlin/org/ktorm/schema/BaseTable.kt index ec62f3db1..b1f425b99 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/schema/BaseTable.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/schema/BaseTable.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/schema/Column.kt b/ktorm-core/src/main/kotlin/org/ktorm/schema/Column.kt index 7fd907e99..6d4f80951 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/schema/Column.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/schema/Column.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/schema/ColumnBindingHandler.kt b/ktorm-core/src/main/kotlin/org/ktorm/schema/ColumnBindingHandler.kt index a8ddc2680..de2d6f4b6 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/schema/ColumnBindingHandler.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/schema/ColumnBindingHandler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/schema/RefCounter.kt b/ktorm-core/src/main/kotlin/org/ktorm/schema/RefCounter.kt index c712414ba..b7c29abe1 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/schema/RefCounter.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/schema/RefCounter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/schema/SqlType.kt b/ktorm-core/src/main/kotlin/org/ktorm/schema/SqlType.kt index 369dd5acc..97ff0d14f 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/schema/SqlType.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/schema/SqlType.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/schema/SqlTypes.kt b/ktorm-core/src/main/kotlin/org/ktorm/schema/SqlTypes.kt index 6c953e45b..507a297b9 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/schema/SqlTypes.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/schema/SqlTypes.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/schema/Table.kt b/ktorm-core/src/main/kotlin/org/ktorm/schema/Table.kt index 33588ab43..7ad6581c0 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/schema/Table.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/schema/Table.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-core/src/main/kotlin/org/ktorm/schema/TypeReference.kt b/ktorm-core/src/main/kotlin/org/ktorm/schema/TypeReference.kt index aa8441a1b..fe5ad5aeb 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/schema/TypeReference.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/schema/TypeReference.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-global/src/main/kotlin/org/ktorm/global/Aggregations.kt b/ktorm-global/src/main/kotlin/org/ktorm/global/Aggregations.kt index 17de9abec..b82c02b94 100644 --- a/ktorm-global/src/main/kotlin/org/ktorm/global/Aggregations.kt +++ b/ktorm-global/src/main/kotlin/org/ktorm/global/Aggregations.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-global/src/main/kotlin/org/ktorm/global/Dml.kt b/ktorm-global/src/main/kotlin/org/ktorm/global/Dml.kt index eb15d0771..5bc5024c7 100644 --- a/ktorm-global/src/main/kotlin/org/ktorm/global/Dml.kt +++ b/ktorm-global/src/main/kotlin/org/ktorm/global/Dml.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-global/src/main/kotlin/org/ktorm/global/EntitySequence.kt b/ktorm-global/src/main/kotlin/org/ktorm/global/EntitySequence.kt index ac2741b60..5cec7acc1 100644 --- a/ktorm-global/src/main/kotlin/org/ktorm/global/EntitySequence.kt +++ b/ktorm-global/src/main/kotlin/org/ktorm/global/EntitySequence.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-global/src/main/kotlin/org/ktorm/global/Global.kt b/ktorm-global/src/main/kotlin/org/ktorm/global/Global.kt index 2191a274f..c49a15ecb 100644 --- a/ktorm-global/src/main/kotlin/org/ktorm/global/Global.kt +++ b/ktorm-global/src/main/kotlin/org/ktorm/global/Global.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-global/src/main/kotlin/org/ktorm/global/Query.kt b/ktorm-global/src/main/kotlin/org/ktorm/global/Query.kt index 9f985e409..01f7e9fcc 100644 --- a/ktorm-global/src/main/kotlin/org/ktorm/global/Query.kt +++ b/ktorm-global/src/main/kotlin/org/ktorm/global/Query.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/EntityDeserializers.kt b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/EntityDeserializers.kt index 3cfb580e2..6776f7764 100644 --- a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/EntityDeserializers.kt +++ b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/EntityDeserializers.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/EntitySerializers.kt b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/EntitySerializers.kt index dd3b29a7c..aeab57ece 100644 --- a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/EntitySerializers.kt +++ b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/EntitySerializers.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/EntityTypeResolverBuilder.kt b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/EntityTypeResolverBuilder.kt index b46a27a8c..6e9f171d2 100644 --- a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/EntityTypeResolverBuilder.kt +++ b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/EntityTypeResolverBuilder.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JacksonExtensions.kt b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JacksonExtensions.kt index 2f6d3bf81..43c4ea554 100644 --- a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JacksonExtensions.kt +++ b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JacksonExtensions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JsonSqlType.kt b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JsonSqlType.kt index 168cb61e3..2006cdd5d 100644 --- a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JsonSqlType.kt +++ b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/JsonSqlType.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/KtormModule.kt b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/KtormModule.kt index 38735777d..7c8e9ce4a 100644 --- a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/KtormModule.kt +++ b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/KtormModule.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/PackageVersion.kt.tmpl b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/PackageVersion.kt.tmpl index d5fc3977c..65e770734 100644 --- a/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/PackageVersion.kt.tmpl +++ b/ktorm-jackson/src/main/kotlin/org/ktorm/jackson/PackageVersion.kt.tmpl @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt index 0d1e3a62b..0eaa98484 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Column.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Ignore.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Ignore.kt index f8724d1f6..f5d1cb322 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Ignore.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Ignore.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/PrimaryKey.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/PrimaryKey.kt index 604a8eb17..843a1c7d7 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/PrimaryKey.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/PrimaryKey.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt index b38a7e5bf..a0f2dd688 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/References.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt index e5105a492..457410424 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Table.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt index 527db1dc3..c2b259c89 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt index f278e76d5..0825f9d82 100644 --- a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt +++ b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt index db501103e..2679fc0d2 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/KtormProcessorProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/CodeFormatter.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/CodeFormatter.kt index a7a750109..993b3b5f8 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/CodeFormatter.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/CodeFormatter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt index 1e8f9ffbf..1e4501bc3 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/KtLintCodeFormatter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt index 652567039..471b4e8f2 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/formatter/StandaloneKtLintCodeFormatter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt index 443bb2df8..0d3d0f3a0 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGenerator.kt index 4cb0cef60..0846cd735 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/ComponentFunctionGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGenerator.kt index 60e0a7cea..c26e32250 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/CopyFunctionGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/EntitySequencePropertyGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/EntitySequencePropertyGenerator.kt index 0aedb86d5..c2c7331ff 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/EntitySequencePropertyGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/EntitySequencePropertyGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt index 9fd230996..2630b3086 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/FileGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt index 458fe79d4..046467ced 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/PseudoConstructorFunctionGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt index b1d8a2616..7a2f7d714 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsClassGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt index d0a278fc1..2cb815b40 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/RefsPropertyGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt index e7a989862..98609c1e8 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/TableClassGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt index 9a99efa32..1312690c9 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index a4bd5cab1..c958ecc2e 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt index 564c4b740..2fedffb0e 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt index 3172f66f2..398a822e0 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/Namings.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt index 8ba2db614..c99976941 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/SqlTypeMappings.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt index ecf1b9db6..ea80147ab 100644 --- a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt +++ b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/CodingNamingStrategy.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt index acc9cb2a3..8e01f9ad6 100644 --- a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt +++ b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ColumnMetadata.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/DatabaseNamingStrategy.kt b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/DatabaseNamingStrategy.kt index 8e748bfac..af41ccb97 100644 --- a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/DatabaseNamingStrategy.kt +++ b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/DatabaseNamingStrategy.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ExtCodeGenerator.kt b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ExtCodeGenerator.kt index 6c1132430..c6b57c28a 100644 --- a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ExtCodeGenerator.kt +++ b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/ExtCodeGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/TableMetadata.kt b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/TableMetadata.kt index 1359b4505..25ed0b159 100644 --- a/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/TableMetadata.kt +++ b/ktorm-ksp-spi/src/main/kotlin/org/ktorm/ksp/spi/TableMetadata.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/BulkInsert.kt b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/BulkInsert.kt index 63b3719ed..5f04f19ae 100644 --- a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/BulkInsert.kt +++ b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/BulkInsert.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/DefaultValue.kt b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/DefaultValue.kt index e368503f9..451f2acbf 100644 --- a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/DefaultValue.kt +++ b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/DefaultValue.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/Functions.kt b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/Functions.kt index 8b9f4669b..14f1217cb 100644 --- a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/Functions.kt +++ b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/Functions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/Global.kt b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/Global.kt index 44cd6c7f9..81cc1728e 100644 --- a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/Global.kt +++ b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/Global.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/InsertOrUpdate.kt b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/InsertOrUpdate.kt index 1a562c7d7..08360347a 100644 --- a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/InsertOrUpdate.kt +++ b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/InsertOrUpdate.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/Lock.kt b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/Lock.kt index 11d56e6cd..63a85cdc9 100644 --- a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/Lock.kt +++ b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/Lock.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MatchAgainst.kt b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MatchAgainst.kt index bf01d1734..b89a9143c 100644 --- a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MatchAgainst.kt +++ b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MatchAgainst.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MySqlDialect.kt b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MySqlDialect.kt index 628c87397..e996fd5e6 100644 --- a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MySqlDialect.kt +++ b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MySqlDialect.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MySqlExpressionVisitor.kt b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MySqlExpressionVisitor.kt index b90c87763..9b63ed1ac 100644 --- a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MySqlExpressionVisitor.kt +++ b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MySqlExpressionVisitor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MySqlFormatter.kt b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MySqlFormatter.kt index d98598828..e8866060f 100644 --- a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MySqlFormatter.kt +++ b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/MySqlFormatter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/NaturalJoin.kt b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/NaturalJoin.kt index af80fb112..e414e5bd1 100644 --- a/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/NaturalJoin.kt +++ b/ktorm-support-mysql/src/main/kotlin/org/ktorm/support/mysql/NaturalJoin.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-oracle/src/main/kotlin/org/ktorm/support/oracle/OracleDialect.kt b/ktorm-support-oracle/src/main/kotlin/org/ktorm/support/oracle/OracleDialect.kt index 80bc3706f..b5517119e 100644 --- a/ktorm-support-oracle/src/main/kotlin/org/ktorm/support/oracle/OracleDialect.kt +++ b/ktorm-support-oracle/src/main/kotlin/org/ktorm/support/oracle/OracleDialect.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-oracle/src/main/kotlin/org/ktorm/support/oracle/OracleFormatter.kt b/ktorm-support-oracle/src/main/kotlin/org/ktorm/support/oracle/OracleFormatter.kt index 7e14f624c..214e63e3b 100644 --- a/ktorm-support-oracle/src/main/kotlin/org/ktorm/support/oracle/OracleFormatter.kt +++ b/ktorm-support-oracle/src/main/kotlin/org/ktorm/support/oracle/OracleFormatter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/BulkInsert.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/BulkInsert.kt index 328a19be9..927b71477 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/BulkInsert.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/BulkInsert.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/DefaultValue.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/DefaultValue.kt index 29fdb80a7..9d8ca157c 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/DefaultValue.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/DefaultValue.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/EarthDistance.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/EarthDistance.kt index 1222cfd70..ab2b2ea7d 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/EarthDistance.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/EarthDistance.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt index b64e2abcb..24234785e 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Functions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Global.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Global.kt index 3b4279b53..9596c5fa3 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Global.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Global.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/HStore.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/HStore.kt index eb824cf87..8b4217350 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/HStore.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/HStore.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/ILike.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/ILike.kt index d0c1e11e3..c09b34bf9 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/ILike.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/ILike.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/InsertOrUpdate.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/InsertOrUpdate.kt index f48eaa345..707672dc1 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/InsertOrUpdate.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/InsertOrUpdate.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Lock.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Lock.kt index 81a8441fb..e50715981 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Lock.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/Lock.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/PostgreSqlDialect.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/PostgreSqlDialect.kt index 419932146..90fbccbaa 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/PostgreSqlDialect.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/PostgreSqlDialect.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/PostgreSqlExpressionVisitor.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/PostgreSqlExpressionVisitor.kt index 6a28b95da..13e04cc8f 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/PostgreSqlExpressionVisitor.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/PostgreSqlExpressionVisitor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/PostgreSqlFormatter.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/PostgreSqlFormatter.kt index c40454ff2..671f6d636 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/PostgreSqlFormatter.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/PostgreSqlFormatter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt index e23bede84..d878c94e7 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/BulkInsert.kt b/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/BulkInsert.kt index 0d3f7fbff..1f4123870 100644 --- a/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/BulkInsert.kt +++ b/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/BulkInsert.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/Functions.kt b/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/Functions.kt index 978d5d62e..e133ffe21 100644 --- a/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/Functions.kt +++ b/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/Functions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/InsertOrUpdate.kt b/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/InsertOrUpdate.kt index 768b8416f..04b2a3719 100644 --- a/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/InsertOrUpdate.kt +++ b/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/InsertOrUpdate.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/SQLiteDialect.kt b/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/SQLiteDialect.kt index bc5239f84..eb1b4b22d 100644 --- a/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/SQLiteDialect.kt +++ b/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/SQLiteDialect.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/SQLiteExpressionVisitor.kt b/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/SQLiteExpressionVisitor.kt index eebd4306c..cbab778c1 100644 --- a/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/SQLiteExpressionVisitor.kt +++ b/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/SQLiteExpressionVisitor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/SQLiteFormatter.kt b/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/SQLiteFormatter.kt index 0adbc7c9e..cbcc9350c 100644 --- a/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/SQLiteFormatter.kt +++ b/ktorm-support-sqlite/src/main/kotlin/org/ktorm/support/sqlite/SQLiteFormatter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-sqlserver/src/main/kotlin/org/ktorm/support/sqlserver/SqlServerDialect.kt b/ktorm-support-sqlserver/src/main/kotlin/org/ktorm/support/sqlserver/SqlServerDialect.kt index e0f97de64..7f289d7f4 100644 --- a/ktorm-support-sqlserver/src/main/kotlin/org/ktorm/support/sqlserver/SqlServerDialect.kt +++ b/ktorm-support-sqlserver/src/main/kotlin/org/ktorm/support/sqlserver/SqlServerDialect.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-sqlserver/src/main/kotlin/org/ktorm/support/sqlserver/SqlServerFormatter.kt b/ktorm-support-sqlserver/src/main/kotlin/org/ktorm/support/sqlserver/SqlServerFormatter.kt index a41ca9061..6cacf1339 100644 --- a/ktorm-support-sqlserver/src/main/kotlin/org/ktorm/support/sqlserver/SqlServerFormatter.kt +++ b/ktorm-support-sqlserver/src/main/kotlin/org/ktorm/support/sqlserver/SqlServerFormatter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ktorm-support-sqlserver/src/main/kotlin/org/ktorm/support/sqlserver/SqlTypes.kt b/ktorm-support-sqlserver/src/main/kotlin/org/ktorm/support/sqlserver/SqlTypes.kt index 40a1ed8dd..3039daeff 100644 --- a/ktorm-support-sqlserver/src/main/kotlin/org/ktorm/support/sqlserver/SqlTypes.kt +++ b/ktorm-support-sqlserver/src/main/kotlin/org/ktorm/support/sqlserver/SqlTypes.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 5ff986f1d2f2cae7434554d1fe5df47c962386bc Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 20 Apr 2024 19:10:10 +0800 Subject: [PATCH 088/105] fix detekt issue --- .github/workflows/build.yml | 2 +- detekt.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 24d9d052e..ec5ca24f9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: true matrix: - java: [8, 11, 17, 20] + java: [8, 11, 17, 21, 22] steps: - name: Checkout Code uses: actions/checkout@v3 diff --git a/detekt.yml b/detekt.yml index cb0d52b2a..6e1c8b3b4 100644 --- a/detekt.yml +++ b/detekt.yml @@ -72,7 +72,7 @@ complexity: constructorThreshold: 6 ignoreDefaultParameters: true MethodOverloading: - active: true + active: false threshold: 7 NestedBlockDepth: active: true From 8c95e85566ecd2218a6fceece479b1fee8edee01 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 20 Apr 2024 19:12:39 +0800 Subject: [PATCH 089/105] fix jdk version --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ec5ca24f9..24d9d052e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: true matrix: - java: [8, 11, 17, 21, 22] + java: [8, 11, 17, 20] steps: - name: Checkout Code uses: actions/checkout@v3 From 034b6f3563c1f173955323cd8281429cb61acf4f Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 21 Apr 2024 16:24:07 +0800 Subject: [PATCH 090/105] upgrade testcontainers for Apple Silicon --- .../ktorm-support-mysql.gradle.kts | 2 +- .../ktorm-support-oracle.gradle.kts | 2 +- .../ktorm/support/oracle/BaseOracleTest.kt | 44 ++++++++++++------- .../org/ktorm/support/oracle/CommonTest.kt | 2 +- .../ktorm-support-postgresql.gradle.kts | 2 +- .../ktorm-support-sqlserver.gradle.kts | 2 +- 6 files changed, 34 insertions(+), 20 deletions(-) diff --git a/ktorm-support-mysql/ktorm-support-mysql.gradle.kts b/ktorm-support-mysql/ktorm-support-mysql.gradle.kts index 9bee95e83..7ec63785d 100644 --- a/ktorm-support-mysql/ktorm-support-mysql.gradle.kts +++ b/ktorm-support-mysql/ktorm-support-mysql.gradle.kts @@ -10,6 +10,6 @@ dependencies { api(project(":ktorm-core")) testImplementation(project(":ktorm-core", configuration = "testOutput")) testImplementation(project(":ktorm-jackson")) - testImplementation("org.testcontainers:mysql:1.15.1") + testImplementation("org.testcontainers:mysql:1.19.7") testImplementation("mysql:mysql-connector-java:8.0.23") } diff --git a/ktorm-support-oracle/ktorm-support-oracle.gradle.kts b/ktorm-support-oracle/ktorm-support-oracle.gradle.kts index 88df99709..9cc0fab84 100644 --- a/ktorm-support-oracle/ktorm-support-oracle.gradle.kts +++ b/ktorm-support-oracle/ktorm-support-oracle.gradle.kts @@ -9,6 +9,6 @@ plugins { dependencies { api(project(":ktorm-core")) testImplementation(project(":ktorm-core", configuration = "testOutput")) - testImplementation("org.testcontainers:oracle-xe:1.15.1") + testImplementation("org.testcontainers:oracle-xe:1.19.7") testImplementation(files("lib/ojdbc6-11.2.0.3.jar")) } diff --git a/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/BaseOracleTest.kt b/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/BaseOracleTest.kt index ac7d5b1df..00dd8ff82 100644 --- a/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/BaseOracleTest.kt +++ b/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/BaseOracleTest.kt @@ -1,21 +1,14 @@ package org.ktorm.support.oracle -import org.junit.ClassRule import org.ktorm.BaseTest import org.ktorm.database.Database import org.testcontainers.containers.OracleContainer +import kotlin.concurrent.thread abstract class BaseOracleTest : BaseTest() { override fun init() { - database = Database.connect( - url = container.jdbcUrl, - driver = container.driverClassName, - user = container.username, - password = container.password, - alwaysQuoteIdentifiers = true - ) - + database = Database.connect(jdbcUrl, driverClassName, username, password, alwaysQuoteIdentifiers = true) execSqlScript("init-oracle-data.sql") } @@ -23,11 +16,32 @@ abstract class BaseOracleTest : BaseTest() { execSqlScript("drop-oracle-data.sql") } - companion object { - @JvmField - @ClassRule - val container = OracleContainer("zerda/oracle-database:11.2.0.2-xe") - // At least 1 GB memory is required by Oracle. - .withCreateContainerCmdModifier { cmd -> cmd.hostConfig?.withShmSize((1 * 1024 * 1024 * 1024).toLong()) } + /** + * Unfortunately Oracle databases aren’t compatible with the new Apple Silicon CPU architecture, + * so if you are using a brand-new MacBook, you need to install colima. + * + * 1. Installation: https://github.com/abiosoft/colima#installation + * 2. Run Colima with the command: `colima start --arch x86_64 --cpu 2 --memory 4 --disk 16 --network-address` + * 3. Set env vars like below: + * + * ```sh + * export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock + * export TESTCONTAINERS_HOST_OVERRIDE=$(colima ls -j | jq -r '.address') + * export DOCKER_HOST="unix://${HOME}/.colima/default/docker.sock" + * ``` + * + * See https://java.testcontainers.org/supported_docker_environment/#colima + */ + companion object : OracleContainer("gvenzl/oracle-xe:11.2.0.2") { + init { + // Configure the container. + usingSid() + withCreateContainerCmdModifier { cmd -> cmd.hostConfig?.withShmSize((1 * 1024 * 1024 * 1024).toLong()) } + + // Start the container when it's first used. + start() + // Stop the container when the process exits. + Runtime.getRuntime().addShutdownHook(thread(start = false) { stop() }) + } } } \ No newline at end of file diff --git a/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/CommonTest.kt b/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/CommonTest.kt index e375e29e5..fe846429d 100644 --- a/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/CommonTest.kt +++ b/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/CommonTest.kt @@ -106,7 +106,7 @@ class CommonTest : BaseOracleTest() { @Test fun testSchema() { - val t = object : Table("t_department", schema = container.username.uppercase()) { + val t = object : Table("t_department", schema = username.uppercase()) { val id = int("id").primaryKey().bindTo { it.id } val name = varchar("name").bindTo { it.name } } diff --git a/ktorm-support-postgresql/ktorm-support-postgresql.gradle.kts b/ktorm-support-postgresql/ktorm-support-postgresql.gradle.kts index 9fcb7edf4..6ce10fd3a 100644 --- a/ktorm-support-postgresql/ktorm-support-postgresql.gradle.kts +++ b/ktorm-support-postgresql/ktorm-support-postgresql.gradle.kts @@ -10,7 +10,7 @@ dependencies { api(project(":ktorm-core")) testImplementation(project(":ktorm-core", configuration = "testOutput")) testImplementation(project(":ktorm-jackson")) - testImplementation("org.testcontainers:postgresql:1.15.1") + testImplementation("org.testcontainers:postgresql:1.19.7") testImplementation("org.postgresql:postgresql:42.2.5") testImplementation("com.zaxxer:HikariCP:4.0.3") testImplementation("com.mchange:c3p0:0.9.5.5") diff --git a/ktorm-support-sqlserver/ktorm-support-sqlserver.gradle.kts b/ktorm-support-sqlserver/ktorm-support-sqlserver.gradle.kts index ed99e1e71..82d9db968 100644 --- a/ktorm-support-sqlserver/ktorm-support-sqlserver.gradle.kts +++ b/ktorm-support-sqlserver/ktorm-support-sqlserver.gradle.kts @@ -9,6 +9,6 @@ plugins { dependencies { api(project(":ktorm-core")) testImplementation(project(":ktorm-core", configuration = "testOutput")) - testImplementation("org.testcontainers:mssqlserver:1.15.1") + testImplementation("org.testcontainers:mssqlserver:1.19.7") testImplementation("com.microsoft.sqlserver:mssql-jdbc:7.2.2.jre8") } From eba9ffea1546b8440009836a79779d5adcfcdb54 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 21 Apr 2024 16:43:20 +0800 Subject: [PATCH 091/105] test reuse --- .../src/test/kotlin/org/ktorm/support/oracle/BaseOracleTest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/BaseOracleTest.kt b/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/BaseOracleTest.kt index 00dd8ff82..4dffa66a0 100644 --- a/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/BaseOracleTest.kt +++ b/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/BaseOracleTest.kt @@ -36,6 +36,7 @@ abstract class BaseOracleTest : BaseTest() { init { // Configure the container. usingSid() + withReuse(true) withCreateContainerCmdModifier { cmd -> cmd.hostConfig?.withShmSize((1 * 1024 * 1024 * 1024).toLong()) } // Start the container when it's first used. From d9aa91adf0cce12e25bcf94a8df624fed7f4ba82 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 21 Apr 2024 20:14:40 +0800 Subject: [PATCH 092/105] fix failed tests --- .../ktorm/support/oracle/BaseOracleTest.kt | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/BaseOracleTest.kt b/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/BaseOracleTest.kt index 4dffa66a0..7b6ccdce2 100644 --- a/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/BaseOracleTest.kt +++ b/ktorm-support-oracle/src/test/kotlin/org/ktorm/support/oracle/BaseOracleTest.kt @@ -1,9 +1,9 @@ package org.ktorm.support.oracle +import org.junit.ClassRule import org.ktorm.BaseTest import org.ktorm.database.Database import org.testcontainers.containers.OracleContainer -import kotlin.concurrent.thread abstract class BaseOracleTest : BaseTest() { @@ -32,17 +32,20 @@ abstract class BaseOracleTest : BaseTest() { * * See https://java.testcontainers.org/supported_docker_environment/#colima */ - companion object : OracleContainer("gvenzl/oracle-xe:11.2.0.2") { - init { - // Configure the container. - usingSid() - withReuse(true) - withCreateContainerCmdModifier { cmd -> cmd.hostConfig?.withShmSize((1 * 1024 * 1024 * 1024).toLong()) } - - // Start the container when it's first used. - start() - // Stop the container when the process exits. - Runtime.getRuntime().addShutdownHook(thread(start = false) { stop() }) - } + companion object { + @JvmField + @ClassRule + val container: OracleContainer + = OracleContainer("gvenzl/oracle-xe:11.2.0.2") + .usingSid() + .withCreateContainerCmdModifier { cmd -> cmd.hostConfig?.withShmSize((1 * 1024 * 1024 * 1024).toLong()) } + + val jdbcUrl: String get() = container.jdbcUrl + + val driverClassName: String get() = container.driverClassName + + val username: String get() = container.username + + val password: String get() = container.password } } \ No newline at end of file From bf83999c1713652a322da9fd436a84457bc5db7a Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 27 Apr 2024 10:33:09 +0800 Subject: [PATCH 093/105] rm unused suppressing --- ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt b/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt index bf54dd33f..257813fcf 100644 --- a/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt +++ b/ktorm-core/src/main/kotlin/org/ktorm/database/CachedRowSet.kt @@ -46,7 +46,7 @@ import javax.sql.rowset.serial.* * * @since 2.7 */ -@Suppress("LargeClass", "MethodOverloading") +@Suppress("LargeClass") public open class CachedRowSet(rs: ResultSet) : ResultSet { private val _typeMap = readTypeMap(rs) private val _metadata = readMetadata(rs) From 34765fd4ee83e23ff34674cc8e5b283b74ab4114 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 27 Apr 2024 17:47:56 +0800 Subject: [PATCH 094/105] fix suppressing --- .../src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt index c2b259c89..3b2f095ea 100644 --- a/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt +++ b/ktorm-ksp-annotations/src/main/kotlin/org/ktorm/ksp/annotation/Undefined.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:Suppress("NoMultipleSpaces") - package org.ktorm.ksp.annotation import sun.misc.Unsafe @@ -147,7 +145,7 @@ public object Undefined { return defineClass(name, bytes, null) } - @Suppress("MagicNumber") + @Suppress("MagicNumber", "NoMultipleSpaces") private fun generateByteCode(className: ByteArray, superClassName: ByteArray): ByteBuffer { val buf = ByteBuffer.allocate(1024) buf.putInt(0xCAFEBABE.toInt()) // magic From fbe4ed1734fb857a96f0b1b8931803d908b33d32 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 27 Apr 2024 19:56:58 +0800 Subject: [PATCH 095/105] fix codestyle --- .../org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt index 0825f9d82..a99177273 100644 --- a/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt +++ b/ktorm-ksp-compiler-maven-plugin/src/main/kotlin/org/ktorm/ksp/compiler/maven/KtormKspMavenPluginExtension.kt @@ -36,6 +36,7 @@ import java.io.File public class KtormKspMavenPluginExtension : KotlinMavenPluginExtension { @Requirement private lateinit var repositorySystem: RepositorySystem + @Requirement private lateinit var mavenSession: MavenSession From 7bbc06f2aadc49b1dabd9b4ee48cc966aa5aa61c Mon Sep 17 00:00:00 2001 From: vince Date: Thu, 2 May 2024 19:55:30 +0800 Subject: [PATCH 096/105] refactor add function --- .../generator/AddFunctionGenerator.kt | 138 +++++++++++------- .../generator/UpdateFunctionGenerator.kt | 17 ++- .../generator/AddFunctionGeneratorTest.kt | 60 +++++++- 3 files changed, 153 insertions(+), 62 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt index 0d3d0f3a0..066782ded 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt @@ -24,7 +24,6 @@ import org.ktorm.dsl.AliasRemover import org.ktorm.entity.EntitySequence import org.ktorm.expression.ColumnAssignmentExpression import org.ktorm.expression.InsertExpression -import org.ktorm.ksp.compiler.util._type import org.ktorm.ksp.spi.ColumnMetadata import org.ktorm.ksp.spi.TableMetadata import org.ktorm.schema.Column @@ -34,44 +33,59 @@ internal object AddFunctionGenerator { fun generate(table: TableMetadata): FunSpec { val primaryKeys = table.columns.filter { it.isPrimaryKey } - val useGeneratedKey = primaryKeys.size == 1 - && primaryKeys[0].entityProperty.isMutable - && primaryKeys[0].entityProperty._type.isMarkedNullable - + val useGeneratedKey = primaryKeys.size == 1 && primaryKeys[0].entityProperty.isMutable val entityClass = table.entityClass.toClassName() val tableClass = ClassName(table.entityClass.packageName.asString(), table.tableClassName) return FunSpec.builder("add") .addKdoc(kdoc(table, useGeneratedKey)) .receiver(EntitySequence::class.asClassName().parameterizedBy(entityClass, tableClass)) - .addParameter("entity", entityClass) - .addParameter(ParameterSpec.builder("isDynamic", typeNameOf()).defaultValue("false").build()) + .addParameters(parameters(entityClass, useGeneratedKey)) .returns(Int::class.asClassName()) .addCode(checkForDml()) - .addCode(addValFun()) - .addCode(addAssignments(table, useGeneratedKey)) + .addCode(addValFun(table, useGeneratedKey)) + .addCode(addAssignments(table)) .addCode(createExpression()) .addCode(executeUpdate(useGeneratedKey, primaryKeys)) .build() } private fun kdoc(table: TableMetadata, useGeneratedKey: Boolean): String { - var kdoc = "" + - "Insert the given entity into this sequence and return the affected record number. " + - "If [isDynamic] is set to true, the generated SQL will include only the non-null columns. " - if (useGeneratedKey) { val pk = table.columns.single { it.isPrimaryKey } val pkName = table.entityClass.simpleName.asString() + "." + pk.entityProperty.simpleName.asString() - - kdoc += "\n\n" + - "Note that this function will obtain the generated primary key from the database and fill it into " + - "the property [$pkName] after the insertion completes. But this requires us not to set " + - "the primary key’s value beforehand, otherwise, if you do that, the given value will be " + - "inserted into the database, and no keys generated." + return """ + Insert the given entity into the table that the sequence object represents. + + @param entity the entity to be inserted. + @param isDynamic whether only non-null columns should be inserted. + @param useGeneratedKey whether to obtain the generated primary key value and fill it into the property [$pkName] after insertion. + @return the affected record number. + """.trimIndent() + } else { + return """ + Insert the given entity into the table that the sequence object represents. + + @param entity the entity to be inserted. + @param isDynamic whether only non-null columns should be inserted. + @return the affected record number. + """.trimIndent() } + } - return kdoc + private fun parameters(entityClass: ClassName, useGeneratedKey: Boolean): List { + if (useGeneratedKey) { + return listOf( + ParameterSpec.builder("entity", entityClass).build(), + ParameterSpec.builder("isDynamic", typeNameOf()).defaultValue("false").build(), + ParameterSpec.builder("useGeneratedKey", typeNameOf()).defaultValue("false").build() + ) + } else { + return listOf( + ParameterSpec.builder("entity", entityClass).build(), + ParameterSpec.builder("isDynamic", typeNameOf()).defaultValue("false").build() + ) + } } internal fun checkForDml(): CodeBlock { @@ -83,7 +97,6 @@ internal object AddFunctionGenerator { || expression.orderBy.isNotEmpty() || expression.offset != null || expression.limit != null - if (isModified) { val msg = "" + "Entity manipulation functions are not supported by this sequence object. " + @@ -97,38 +110,58 @@ internal object AddFunctionGenerator { return CodeBlock.of(code) } - internal fun addValFun(): CodeBlock { - val code = """ - fun MutableList<%1T<*>>.addVal(column: %2T, value: T?, isDynamic: Boolean) { - if (!isDynamic || value != null) { + private fun addValFun(table: TableMetadata, useGeneratedKey: Boolean): CodeBlock { + if (useGeneratedKey) { + val pk = table.columns.single { it.isPrimaryKey } + val code = """ + fun MutableList<%1T<*>>.addVal(column: %2T, value: T?) { + if (useGeneratedKey && column === sourceTable.%3N) { + return + } + + if (isDynamic && value == null) { + return + } + this += %1T(column.asExpression(), column.wrapArgument(value)) } - } - + + + """.trimIndent() + return CodeBlock.of( + code, + ColumnAssignmentExpression::class.asClassName(), + Column::class.asClassName(), + pk.columnPropertyName + ) + } else { + val code = """ + fun MutableList<%1T<*>>.addVal(column: %2T, value: T?) { + if (isDynamic && value == null) { + return + } - """.trimIndent() - - return CodeBlock.of(code, ColumnAssignmentExpression::class.asClassName(), Column::class.asClassName()) + this += %1T(column.asExpression(), column.wrapArgument(value)) + } + + + """.trimIndent() + return CodeBlock.of(code, ColumnAssignmentExpression::class.asClassName(), Column::class.asClassName()) + } } - private fun addAssignments(table: TableMetadata, useGeneratedKey: Boolean): CodeBlock { + private fun addAssignments(table: TableMetadata): CodeBlock { return buildCodeBlock { addStatement("val assignments = ArrayList<%T<*>>()", ColumnAssignmentExpression::class.asClassName()) for (column in table.columns) { - val forceDynamic = useGeneratedKey - && column.isPrimaryKey && column.entityProperty._type.isMarkedNullable - addStatement( - "assignments.addVal(sourceTable.%N, entity.%N, %L)", + "assignments.addVal(sourceTable.%N, entity.%N)", column.columnPropertyName, - column.entityProperty.simpleName.asString(), - if (forceDynamic) "isDynamic·=·true" else "isDynamic" + column.entityProperty.simpleName.asString() ) } - add("\n") - beginControlFlow("if (assignments.isEmpty())") addStatement("return 0") endControlFlow() @@ -138,15 +171,16 @@ internal object AddFunctionGenerator { } private fun createExpression(): CodeBlock { - val code = """ - val expression = database.dialect.createExpressionVisitor(%T).visit( - %T(sourceTable.asExpression(), assignments) + return buildCodeBlock { + addStatement( + "val visitor = database.dialect.createExpressionVisitor(%T)", + AliasRemover::class.asClassName() ) - - - """.trimIndent() - - return CodeBlock.of(code, AliasRemover::class.asClassName(), InsertExpression::class.asClassName()) + addStatement( + "val expression = visitor.visit(%T(sourceTable.asExpression(), assignments))", + InsertExpression::class.asClassName() + ) + } } private fun executeUpdate(useGeneratedKey: Boolean, primaryKeys: List): CodeBlock { @@ -154,17 +188,14 @@ internal object AddFunctionGenerator { if (!useGeneratedKey) { addStatement("return database.executeUpdate(expression)") } else { - // If the primary key value is manually specified, not obtain the generated key. - beginControlFlow("if (entity.%N != null)", primaryKeys[0].entityProperty.simpleName.asString()) + beginControlFlow("if (!useGeneratedKey)") addStatement("return database.executeUpdate(expression)") - - // Else obtain the generated key value. nextControlFlow("else") addNamed( format = """ val (effects, rowSet) = database.executeUpdateAndRetrieveKeys(expression) if (rowSet.next()) { - val generatedKey = rowSet.%getGeneratedKey:M(sourceTable.%columnName:N) + val generatedKey = rowSet.%getGeneratedKey:M(sourceTable.%columnPropertyName:N) if (generatedKey != null) { if (database.logger.isDebugEnabled()) { database.logger.debug("Generated Key: ${'$'}generatedKey") @@ -179,12 +210,11 @@ internal object AddFunctionGenerator { """.trimIndent(), arguments = mapOf( - "columnName" to primaryKeys[0].columnPropertyName, "propertyName" to primaryKeys[0].entityProperty.simpleName.asString(), + "columnPropertyName" to primaryKeys[0].columnPropertyName, "getGeneratedKey" to MemberName("org.ktorm.dsl", "getGeneratedKey", true) ) ) - endControlFlow() } } diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt index 1312690c9..152d78084 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt @@ -26,6 +26,7 @@ import org.ktorm.expression.ColumnAssignmentExpression import org.ktorm.expression.UpdateExpression import org.ktorm.ksp.compiler.util.* import org.ktorm.ksp.spi.TableMetadata +import org.ktorm.schema.Column @OptIn(KotlinPoetKspPreview::class) internal object UpdateFunctionGenerator { @@ -45,7 +46,7 @@ internal object UpdateFunctionGenerator { .addParameter(ParameterSpec.builder("isDynamic", typeNameOf()).defaultValue("false").build()) .returns(Int::class.asClassName()) .addCode(AddFunctionGenerator.checkForDml()) - .addCode(AddFunctionGenerator.addValFun()) + .addCode(addValFun()) .addCode(addAssignments(table)) .addCode(buildConditions(table)) .addCode(createExpression()) @@ -53,6 +54,20 @@ internal object UpdateFunctionGenerator { .build() } + private fun addValFun(): CodeBlock { + val code = """ + fun MutableList<%1T<*>>.addVal(column: %2T, value: T?, isDynamic: Boolean) { + if (!isDynamic || value != null) { + this += %1T(column.asExpression(), column.wrapArgument(value)) + } + } + + + """.trimIndent() + + return CodeBlock.of(code, ColumnAssignmentExpression::class.asClassName(), Column::class.asClassName()) + } + private fun addAssignments(table: TableMetadata): CodeBlock { return buildCodeBlock { addStatement("val assignments = ArrayList<%T<*>>()", ColumnAssignmentExpression::class.asClassName()) diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGeneratorTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGeneratorTest.kt index cd0520217..aaa3613e9 100644 --- a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGeneratorTest.kt +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGeneratorTest.kt @@ -6,17 +6,19 @@ import org.ktorm.ksp.compiler.BaseKspTest class AddFunctionGeneratorTest : BaseKspTest() { @Test - fun `sequence add function`() = runKotlin(""" + fun testGenerateKey() = runKotlin(""" @Table data class User( @PrimaryKey - var id: Int?, + var id: Int, var username: String, var age: Int, ) fun run() { - database.users.add(User(null, "test", 100)) + val user = User(0, "test", 100) + database.users.add(user, useGeneratedKey = true) + assert(user.id == 4) val users = database.users.toList() assert(users.size == 4) @@ -28,19 +30,63 @@ class AddFunctionGeneratorTest : BaseKspTest() { """.trimIndent()) @Test - fun `modified entity sequence call add fun`() = runKotlin(""" + fun testNoGenerateKey() = runKotlin(""" @Table data class User( @PrimaryKey - var id: Int?, + var id: Int, var username: String, - var age: Int + var age: Int, + ) + + fun run() { + database.users.add(User(99, "test", 100)) + + val users = database.users.toList() + assert(users.size == 4) + assert(users[0] == User(id = 1, username = "jack", age = 20)) + assert(users[1] == User(id = 2, username = "lucy", age = 22)) + assert(users[2] == User(id = 3, username = "mike", age = 22)) + assert(users[3] == User(id = 99, username = "test", age = 100)) + } + """.trimIndent()) + + @Test + fun testNoGenerateKey1() = runKotlin(""" + @Table + data class User( + @PrimaryKey + val id: Int, + val username: String, + val age: Int, + ) + + fun run() { + database.users.add(User(99, "test", 100)) + + val users = database.users.toList() + assert(users.size == 4) + assert(users[0] == User(id = 1, username = "jack", age = 20)) + assert(users[1] == User(id = 2, username = "lucy", age = 22)) + assert(users[2] == User(id = 3, username = "mike", age = 22)) + assert(users[3] == User(id = 99, username = "test", age = 100)) + } + """.trimIndent()) + + @Test + fun testSequenceModified() = runKotlin(""" + @Table + data class User( + @PrimaryKey + val id: Int, + val username: String, + val age: Int, ) fun run() { try { val users = database.users.filter { it.id eq 1 } - users.add(User(null, "lucy", 10)) + users.add(User(99, "lucy", 10)) throw AssertionError("fail") } catch (_: UnsupportedOperationException) { } From 47aeefcff3bef228a6a3a5972fafa3845866a299 Mon Sep 17 00:00:00 2001 From: vince Date: Fri, 3 May 2024 22:01:53 +0800 Subject: [PATCH 097/105] refactor update function --- .../generator/AddFunctionGenerator.kt | 2 +- .../generator/UpdateFunctionGenerator.kt | 82 +++++++------------ .../generator/UpdateFunctionGeneratorTest.kt | 4 +- 3 files changed, 34 insertions(+), 54 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt index 066782ded..4952f024a 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/AddFunctionGenerator.kt @@ -110,7 +110,7 @@ internal object AddFunctionGenerator { return CodeBlock.of(code) } - private fun addValFun(table: TableMetadata, useGeneratedKey: Boolean): CodeBlock { + internal fun addValFun(table: TableMetadata, useGeneratedKey: Boolean): CodeBlock { if (useGeneratedKey) { val pk = table.columns.single { it.isPrimaryKey } val code = """ diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt index 152d78084..508d8a8a2 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGenerator.kt @@ -24,17 +24,20 @@ import org.ktorm.dsl.AliasRemover import org.ktorm.entity.EntitySequence import org.ktorm.expression.ColumnAssignmentExpression import org.ktorm.expression.UpdateExpression -import org.ktorm.ksp.compiler.util.* +import org.ktorm.ksp.compiler.util._type import org.ktorm.ksp.spi.TableMetadata -import org.ktorm.schema.Column @OptIn(KotlinPoetKspPreview::class) internal object UpdateFunctionGenerator { fun generate(table: TableMetadata): FunSpec { - val kdoc = "" + - "Update the given entity to the database and return the affected record number. " + - "If [isDynamic] is set to true, the generated SQL will include only the non-null columns. " + val kdoc = """ + Update the given entity to the database. + + @param entity the entity to be updated. + @param isDynamic whether only non-null columns should be updated. + @return the affected record number. + """.trimIndent() val entityClass = table.entityClass.toClassName() val tableClass = ClassName(table.entityClass.packageName.asString(), table.tableClassName) @@ -46,28 +49,13 @@ internal object UpdateFunctionGenerator { .addParameter(ParameterSpec.builder("isDynamic", typeNameOf()).defaultValue("false").build()) .returns(Int::class.asClassName()) .addCode(AddFunctionGenerator.checkForDml()) - .addCode(addValFun()) + .addCode(AddFunctionGenerator.addValFun(table, useGeneratedKey = false)) .addCode(addAssignments(table)) - .addCode(buildConditions(table)) - .addCode(createExpression()) + .addCode(createExpression(table)) .addStatement("return database.executeUpdate(expression)") .build() } - private fun addValFun(): CodeBlock { - val code = """ - fun MutableList<%1T<*>>.addVal(column: %2T, value: T?, isDynamic: Boolean) { - if (!isDynamic || value != null) { - this += %1T(column.asExpression(), column.wrapArgument(value)) - } - } - - - """.trimIndent() - - return CodeBlock.of(code, ColumnAssignmentExpression::class.asClassName(), Column::class.asClassName()) - } - private fun addAssignments(table: TableMetadata): CodeBlock { return buildCodeBlock { addStatement("val assignments = ArrayList<%T<*>>()", ColumnAssignmentExpression::class.asClassName()) @@ -78,14 +66,12 @@ internal object UpdateFunctionGenerator { } addStatement( - "assignments.addVal(sourceTable.%N, entity.%N, isDynamic)", + "assignments.addVal(sourceTable.%N, entity.%N)", column.columnPropertyName, - column.entityProperty.simpleName.asString(), + column.entityProperty.simpleName.asString() ) } - add("\n") - beginControlFlow("if (assignments.isEmpty())") addStatement("return 0") endControlFlow() @@ -94,20 +80,22 @@ internal object UpdateFunctionGenerator { } } - private fun buildConditions(table: TableMetadata): CodeBlock { + private fun createExpression(table: TableMetadata): CodeBlock { return buildCodeBlock { - add("«val conditions = listOf(") + addStatement( + "val visitor = database.dialect.createExpressionVisitor(%T)", + AliasRemover::class.asClassName() + ) - for (column in table.columns) { - if (!column.isPrimaryKey) { - continue - } + add("«val conditions = ") + val primaryKeys = table.columns.filter { it.isPrimaryKey } + for ((i, column) in primaryKeys.withIndex()) { val condition: String if (column.entityProperty._type.isMarkedNullable) { - condition = "sourceTable.%N·%M·entity.%N!!," + condition = "(sourceTable.%N·%M·entity.%N!!)" } else { - condition = "sourceTable.%N·%M·entity.%N," + condition = "(sourceTable.%N·%M·entity.%N)" } add( @@ -116,26 +104,18 @@ internal object UpdateFunctionGenerator { MemberName("org.ktorm.dsl", "eq", true), column.entityProperty.simpleName.asString() ) + + if (i < primaryKeys.lastIndex) { + add("·%M·", MemberName("org.ktorm.dsl", "and", true)) + } } - add(")\n»") - } - } + add("\n»") - private fun createExpression(): CodeBlock { - val code = """ - val expression = database.dialect.createExpressionVisitor(%T).visit( - %T(sourceTable.asExpression(), assignments, conditions.%M().asExpression()) + addStatement( + "val expression = visitor.visit(%T(sourceTable.asExpression(), assignments, conditions))", + UpdateExpression::class.asClassName() ) - - - """.trimIndent() - - return CodeBlock.of( - code, - AliasRemover::class.asClassName(), - UpdateExpression::class.asClassName(), - MemberName("org.ktorm.dsl", "combineConditions", true) - ) + } } } diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGeneratorTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGeneratorTest.kt index 37a164e75..ca9fd2f27 100644 --- a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGeneratorTest.kt +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/generator/UpdateFunctionGeneratorTest.kt @@ -10,7 +10,7 @@ class UpdateFunctionGeneratorTest : BaseKspTest() { @Table data class User( @PrimaryKey - var id: Int?, + var id: Int, var username: String, var age: Int, ) @@ -32,7 +32,7 @@ class UpdateFunctionGeneratorTest : BaseKspTest() { @Table data class User( @PrimaryKey - var id: Int?, + var id: Int, var username: String, var age: Int ) From e35ff789dda4980333b68a86c104d2cbfd3a8dc7 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 5 May 2024 10:41:50 +0800 Subject: [PATCH 098/105] fix typo --- .../main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt | 2 +- .../kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index c958ecc2e..920a2585f 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -85,7 +85,7 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn if (cls.classKind == INTERFACE && !cls.isSubclassOf>()) { val name = cls.qualifiedName!!.asString() - throw IllegalStateException("$name must extends from org.ktorm.entity.Entity.") + throw IllegalStateException("$name must extend from org.ktorm.entity.Entity.") } _logger.info("[ktorm-ksp-compiler] parse table metadata from entity: ${cls.qualifiedName!!.asString()}") diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt index cc0f95cfb..0f7c1e43d 100644 --- a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt @@ -15,7 +15,7 @@ class MetadataParserTest : BaseKspTest() { """.trimIndent()) @Test - fun testInterfaceNotExtendingEntity() = kspFailing("User must extends from org.ktorm.entity.Entity.", """ + fun testInterfaceNotExtendingEntity() = kspFailing("User must extend from org.ktorm.entity.Entity.", """ @Table interface User { val id: Int From b63332ba44b9f054f935519d36c7bef1ad8ffc28 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 5 May 2024 11:53:25 +0800 Subject: [PATCH 099/105] check abstract class --- .../ktorm/ksp/compiler/parser/MetadataParser.kt | 17 ++++++++++------- .../ksp/compiler/parser/MetadataParserTest.kt | 11 ++++++++++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index 920a2585f..68fc353d2 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -73,22 +73,25 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn } fun parseTableMetadata(cls: KSClassDeclaration): TableMetadata { - val r = _tablesCache[cls.qualifiedName!!.asString()] + val className = cls.qualifiedName!!.asString() + val r = _tablesCache[className] if (r != null) { return r } if (cls.classKind != CLASS && cls.classKind != INTERFACE) { - val name = cls.qualifiedName!!.asString() - throw IllegalStateException("$name is expected to be a class or interface but actually ${cls.classKind}.") + throw IllegalStateException("$className should be a class or interface but actually ${cls.classKind}.") } if (cls.classKind == INTERFACE && !cls.isSubclassOf>()) { - val name = cls.qualifiedName!!.asString() - throw IllegalStateException("$name must extend from org.ktorm.entity.Entity.") + throw IllegalStateException("$className must extend from org.ktorm.entity.Entity.") } - _logger.info("[ktorm-ksp-compiler] parse table metadata from entity: ${cls.qualifiedName!!.asString()}") + if (cls.classKind == CLASS && cls.isAbstract()) { + throw IllegalStateException("$className cannot be an abstract class.") + } + + _logger.info("[ktorm-ksp-compiler] parse table metadata from entity: $className") val table = cls.getAnnotationsByType(Table::class).first() val tableDef = TableMetadata( entityClass = cls, @@ -111,7 +114,7 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn } } - _tablesCache[cls.qualifiedName!!.asString()] = tableDef + _tablesCache[className] = tableDef return tableDef } diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt index 0f7c1e43d..f57891cb1 100644 --- a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt @@ -9,7 +9,7 @@ import org.ktorm.ksp.compiler.BaseKspTest class MetadataParserTest : BaseKspTest() { @Test - fun testEnumClass() = kspFailing("Gender is expected to be a class or interface but actually ENUM_CLASS.", """ + fun testEnumClass() = kspFailing("Gender should be a class or interface but actually ENUM_CLASS.", """ @Table enum class Gender { MALE, FEMALE } """.trimIndent()) @@ -23,6 +23,15 @@ class MetadataParserTest : BaseKspTest() { } """.trimIndent()) + @Test + fun testAbstractClass() = kspFailing("User cannot be an abstract class.", """ + @Table + abstract class User { + var id: Int = 0 + var name: String = "" + } + """.trimIndent()) + @Test fun testClassIgnoreProperties() = runKotlin(""" @Table(ignoreProperties = ["name"]) From f0b08682afde1abad9ca691895d4453a2e2bb1bb Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 5 May 2024 12:11:34 +0800 Subject: [PATCH 100/105] update error notice --- .../main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt | 2 +- .../kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index 68fc353d2..10bed688a 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -84,7 +84,7 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn } if (cls.classKind == INTERFACE && !cls.isSubclassOf>()) { - throw IllegalStateException("$className must extend from org.ktorm.entity.Entity.") + throw IllegalStateException("$className should extend from org.ktorm.entity.Entity.") } if (cls.classKind == CLASS && cls.isAbstract()) { diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt index f57891cb1..9834afff2 100644 --- a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt @@ -15,7 +15,7 @@ class MetadataParserTest : BaseKspTest() { """.trimIndent()) @Test - fun testInterfaceNotExtendingEntity() = kspFailing("User must extend from org.ktorm.entity.Entity.", """ + fun testInterfaceNotExtendingEntity() = kspFailing("User should extend from org.ktorm.entity.Entity.", """ @Table interface User { val id: Int From 24f4324100dae36ffb2ea99e0228ce35c5121cc7 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 5 May 2024 12:26:23 +0800 Subject: [PATCH 101/105] fix naming --- .../ktorm/ksp/compiler/parser/MetadataParser.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index 10bed688a..09f9f4343 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -93,7 +93,7 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn _logger.info("[ktorm-ksp-compiler] parse table metadata from entity: $className") val table = cls.getAnnotationsByType(Table::class).first() - val tableDef = TableMetadata( + val tableMetadata = TableMetadata( entityClass = cls, name = table.name.ifEmpty { _databaseNamingStrategy.getTableName(cls) }, alias = table.alias.takeIf { it.isNotEmpty() }, @@ -105,17 +105,17 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn columns = ArrayList() ) - val columns = tableDef.columns as MutableList - for (property in cls.getProperties(tableDef.ignoreProperties)) { + val columns = tableMetadata.columns as MutableList + for (property in cls.getProperties(tableMetadata.ignoreProperties)) { if (property.isAnnotationPresent(References::class)) { - columns += parseRefColumnMetadata(property, tableDef) + columns += parseRefColumnMetadata(property, tableMetadata) } else { - columns += parseColumnMetadata(property, tableDef) + columns += parseColumnMetadata(property, tableMetadata) } } - _tablesCache[className] = tableDef - return tableDef + _tablesCache[className] = tableMetadata + return tableMetadata } private fun KSClassDeclaration.getProperties(ignoreProperties: Set): Sequence { From 9f3efe63dfd0c8a9f593e41959a2c1453a0f983e Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 5 May 2024 18:31:57 +0800 Subject: [PATCH 102/105] fix naming --- .../kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt | 3 ++- .../kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt index 09f9f4343..55b94489b 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/parser/MetadataParser.kt @@ -134,6 +134,7 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn } private fun parseColumnMetadata(property: KSPropertyDeclaration, table: TableMetadata): ColumnMetadata { + // @Column annotation is optional. val column = property.getAnnotationsByType(Column::class).firstOrNull() var name = column?.name @@ -195,7 +196,7 @@ internal class MetadataParser(resolver: Resolver, environment: SymbolProcessorEn if (!hasConstructor) { val msg = "" + - "Parse sqlType error for property $propName: the sqlType must be a Kotlin singleton object or " + + "Parse sqlType error for property $propName: the sqlType should be a Kotlin singleton object or " + "a normal class with a constructor that accepts a single org.ktorm.schema.TypeReference argument." throw IllegalArgumentException(msg) } diff --git a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt index 9834afff2..38b9f7dbb 100644 --- a/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt +++ b/ktorm-ksp-compiler/src/test/kotlin/org/ktorm/ksp/compiler/parser/MetadataParserTest.kt @@ -147,7 +147,7 @@ class MetadataParserTest : BaseKspTest() { """.trimIndent()) @Test - fun testSqlTypeWithoutConstructor() = kspFailing("Parse sqlType error for property User.ex: the sqlType must be a Kotlin singleton object or a normal class with a constructor that accepts a single org.ktorm.schema.TypeReference argument.", """ + fun testSqlTypeWithoutConstructor() = kspFailing("Parse sqlType error for property User.ex: the sqlType should be a Kotlin singleton object or a normal class with a constructor that accepts a single org.ktorm.schema.TypeReference argument.", """ @Table interface User : Entity { @PrimaryKey From 7f8ad54a8d49da97ec7a752de8ff2dd93b1462f0 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 5 May 2024 21:32:41 +0800 Subject: [PATCH 103/105] fix jvmName --> qualifiedName --- .../main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt index 2fedffb0e..fc96866aa 100644 --- a/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt +++ b/ktorm-ksp-compiler/src/main/kotlin/org/ktorm/ksp/compiler/util/KspExtensions.kt @@ -22,7 +22,6 @@ import com.google.devtools.ksp.KspExperimental import com.google.devtools.ksp.isAnnotationPresent import com.google.devtools.ksp.symbol.* import com.google.devtools.ksp.visitor.KSValidateVisitor -import kotlin.reflect.jvm.jvmName /** * Return the resolved [KSType] of this property. @@ -54,7 +53,7 @@ internal fun KSType.isInline(): Boolean { * Check if this class is a subclass of [T]. */ internal inline fun KSClassDeclaration.isSubclassOf(): Boolean { - return findSuperTypeReference(T::class.jvmName) != null + return findSuperTypeReference(T::class.qualifiedName!!) != null } /** From a394bb5440e0f919982732a5dfb30f5c13b63492 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 12 May 2024 17:08:54 +0800 Subject: [PATCH 104/105] update comment --- .../src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt index d878c94e7..2ddb7081b 100644 --- a/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt +++ b/ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/SqlTypes.kt @@ -144,7 +144,7 @@ public fun BaseTable<*>.doubleArray(name: String): Column { } /** - * [SqlType] implementation represents PostgreSQL `double[]` type. + * [SqlType] implementation represents PostgreSQL `float8[]` type. */ public object DoubleArraySqlType : SqlType(Types.ARRAY, "float8[]") { From 3cf3f4464a9fceed515770868df05d358ce0c038 Mon Sep 17 00:00:00 2001 From: vince Date: Sun, 12 May 2024 19:41:51 +0800 Subject: [PATCH 105/105] update comment --- .../test/kotlin/org/ktorm/support/postgresql/FunctionsTest.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/FunctionsTest.kt b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/FunctionsTest.kt index 30d494ba7..92d49e17d 100644 --- a/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/FunctionsTest.kt +++ b/ktorm-support-postgresql/src/test/kotlin/org/ktorm/support/postgresql/FunctionsTest.kt @@ -48,7 +48,9 @@ class FunctionsTest : BasePostgreSqlTest() { println(results) assert(results.size == 1) - assert(results[0] == tupleOf(1, 1, 1, 1, 2)) // text[] is one-based, others are zero-based. + + // text[] is one-based, others are zero-based. See https://stackoverflow.com/questions/69649737/postgres-array-positionarray-element-sometimes-0-indexed + assert(results[0] == tupleOf(1, 1, 1, 1, 2)) } @Test