From ba6dc52780da0c6ecc87737070c09926a6bb40ef Mon Sep 17 00:00:00 2001 From: Claude Brisson <claude@renegat.net> Date: Tue, 5 Oct 2021 01:03:42 +0200 Subject: [PATCH] [wip] Modality format (compilation of generated sources seems ok) --- build.gradle.kts | 9 +- gradle.properties | 3 + ksplit.sh | 8 +- .../kotlin/com/republicate/kddl/modality.kt | 103 +++++++++++++----- 4 files changed, 92 insertions(+), 31 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index b4755c3..eddd4e4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,7 @@ plugins { idea application - kotlin("multiplatform") version "1.4.10" + kotlin("multiplatform") version "1.5.31" `maven-publish` } group = "com.republicate.kddl" @@ -40,8 +40,11 @@ kotlin { // from(zipTree(file.absoluteFile)) // } // } - - kotlinOptions.jvmTarget = "1.8" + kotlinOptions { + jvmTarget = "1.8" + apiVersion = "1.5" + languageVersion = "1.5" + } } } withJava() diff --git a/gradle.properties b/gradle.properties index ad6abc4..dcaad4b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,9 @@ +kotlin_version=1.5.31 kotlin.code.style=official kotlin.js.generate.executable.default=false kotlin.mpp.stability.nowarn=true +kotlin.mpp.enableGranularSourceSetsMetadata=true +kotlin.native.enableDependencyPropagation=false #version_agl = 3.5.1-cb4 version_agl = 3.5.1 diff --git a/ksplit.sh b/ksplit.sh index 3c35126..3015b56 100755 --- a/ksplit.sh +++ b/ksplit.sh @@ -7,9 +7,11 @@ mkdir -p $KSPKIT_TMP DEST=$(pwd) pushd . cd $KSPKIT_TMP -cat /dev/stdin | tail -n +2 | csplit -n5 -sz '// Database.*' '{*}' -for file in $(ls) do +cat /dev/stdin | csplit - -n5 -sz '/\/\/ Database.*/' '{*}' +for file in $(ls) +do dst=$(head -2 $file | tail -1 | sed -r -e 's|// Schema ||') - mv $file $DEST/${dst^}.java + echo mv $file $DEST/${dst^}.kt + mv $file $DEST/${dst^}.kt done popd diff --git a/src/commonMain/kotlin/com/republicate/kddl/modality.kt b/src/commonMain/kotlin/com/republicate/kddl/modality.kt index 7f1daf6..39aff87 100644 --- a/src/commonMain/kotlin/com/republicate/kddl/modality.kt +++ b/src/commonMain/kotlin/com/republicate/kddl/modality.kt @@ -1,5 +1,6 @@ package com.republicate.kddl +import java.util.Locale import net.akehurst.language.agl.processor.Agl import net.akehurst.language.api.processor.LanguageProcessor @@ -37,7 +38,13 @@ class ModalityFormatter : KDDLFormatter() { ret.append("// Schema ${schema.name}$EOL") ret.append("${indent}package _package_.${schema.db.name}.${schema.name}$EOL$EOL") ret.append("import com.republicate.modality.Instance$EOL") -// ret.append("import com.republicate.modality.util.ConversionUtils$EOL") + ret.append("import com.republicate.modality.Model$EOL") + ret.append("import java.util.Date$EOL") // CB TODO - kotlinx-datetime objects are not yet serializable (v0.3.0 at the time of writing) + ret.append(EOL) + // CB TODO - temporary hack, fixing needed in upstream Modality + ret.append("fun Instance.getInt(key: String): Int = getInteger(key)$EOL") + ret.append("fun Instance.now(): Date = Date()$EOL") + ret.append(EOL) ret.append( schema.tables.map { @@ -47,16 +54,18 @@ class ModalityFormatter : KDDLFormatter() { return ret.toString() } + fun rawType(type: String?): String? = type?.replace(Regex("\\(.*\\)"), "") + override fun format(indent: String, table: Table): String { val ret = StringBuilder() if (table !is JoinTable) { // TODO something to do for static atomic id generator with isDefaultKey() - ret.append("${indent}public class ${table.name}") + ret.append("${indent}public class ${table.name.capitalize()}") ret.append("(model: Model") val pk = table.getPrimaryKey() val defaultPk = pk.size == 1 && pk.first().isDefaultKey() - if ( !pk.isEmpty() && !defaultPk) ret.append(", ") for ( pkField in pk ) { + ret.append(", ") ret.append(format("", pkField, true)) } ret.append("): Instance(model.getEntity(\"${table.name.decapitalize()}\"))") @@ -76,6 +85,17 @@ class ModalityFormatter : KDDLFormatter() { ret.append("$EOL$indent }") } + ret.append("$EOL$EOL$indent fun getInt(key: String) = super.getInteger(key)$EOL") + + fields.filter { + rawType(it.type)?.equals("enum") ?: false + }.forEach { + ret.append("$EOL$indent enum class ${it.name.capitalize()} { ") +// ret.append("/*${it.type.replace(Regex("^.*\\((.*)\\)"), "$1")}*/") + val values = it.type.replace(Regex("^.*\\((.*)\\)"), "$1").split(",").joinToString { it.removeSurrounding("'", "'").uppercase(Locale.ROOT) } + ret.append("$values }") + } + for (field in fields) { ret.append(EOL) ret.append(format("${indent} ", field)) @@ -91,11 +111,12 @@ class ModalityFormatter : KDDLFormatter() { } private val typeMap = mapOf( + "char" to "String", "varchar" to "String", "text" to "String", "boolean" to "Boolean", - "date" to "LocalDate", - "datetime" to "LocalDateTime", + "date" to "Date", + "datetime" to "Date", "integer" to "Int", "long" to "Long", "float" to "Float", @@ -104,12 +125,14 @@ class ModalityFormatter : KDDLFormatter() { "numeric" to "Double", "serial" to "Long", "time" to "String", - "datetimetz" to "Instant", + "datetimetz" to "Date", "json" to "Json", - "jsonb" to "Json" + "jsonb" to "Json", + "enum" to "Enum" ) private val defaultMap = mapOf( + "char" to "\"\"", "varchar" to "\"\"", "text" to "\"\"", "boolean" to "false", @@ -135,8 +158,12 @@ class ModalityFormatter : KDDLFormatter() { fun format(indent: String, field: Field, typeParam: Boolean): String { val ret = StringBuilder(indent) field.apply { - val rawType = type?.replace(Regex("\\(\\d+(?:,\\d+)*\\)"), "") - val kotlinType = typeMap[rawType] ?: "UnknownType[${rawType}]" + val raw = rawType(type) + val kotlinType = when(raw) { + null -> "UnknownType[${raw}]" + "enum" -> name.capitalize() + else -> typeMap[raw] + } val mandatory = nonNull || primaryKey && !isDefaultKey() if (!typeParam) { if (primaryKey) ret.append("val ") @@ -145,23 +172,49 @@ class ModalityFormatter : KDDLFormatter() { val suffix = if(typeParam) "Param" else "" ret.append("${name}${suffix}: ${kotlinType}") if (!mandatory) ret.append("?") - if (!typeParam && default != null) { - val def = default.toString() - ret.append( - " = ${ - when { - def.startsWith("'") -> "\"${def.removeSurrounding("'", "'")}\"" - else -> def - } - }" - ) - } else if (mandatory) { - ret.append(" // = ${defaultMap[rawType] ?: "UnknownDefault[${rawType}]"}") - } + // OLD default handling +// if (!typeParam && default != null) { +// val def = default.toString() +// ret.append( +// " = ${ +// when { +// def.startsWith("'") -> "\"${def.removeSurrounding("'", "'")}\"" +// else -> def +// } +// }" +// ) +// } + if (!typeParam) { - ret.append("$EOL$indent get() = get${kotlinType}(\"${name}\")") - if (mandatory) ret.append("!!") - if (!primaryKey) ret.append("$EOL$indent set(value) = put(\"${name}\", value)") +// OLD: ret.append("$EOL$indent get() = get$kotlinType(\"${name}\")") + // CB TODO - by not returning null (for a bran new instance) for a mandatory field with a default, there is a small risk of introducing side effects + var def = when(default) { + null -> "" + is Boolean -> default.toString() + is Number -> default.toString() + // is String -> ret.append("DEFAULT ${defaultMap[default] ?: default}") + is String -> "\"${default.toString()}\"" + is Function -> "$default()" + is Function0<*> -> "${(default as Function0<String>).invoke()}" + else -> throw RuntimeException("Unhandled default value type: $default") + } + if (!def.isEmpty()) ret.append("$EOL // @@@@@@@@@@@@@@@@@@@@@@@@ type = $type, default = $default ; def = $def") + val getter = when(raw) { + null -> "UnknownGetter[${raw}]" + "enum" -> "${name.capitalize()}.valueOf(super.getString(\"${name}\")${ if(mandatory) if (!def.isEmpty()) " ?: $def " else "!!" else "" })" + else -> "get$kotlinType(\"${name}\")${ if (mandatory) if(!def.isEmpty()) " ?: $def" else "!!" else "" }" + } + ret.append("$EOL$indent get() = $getter") + if (!primaryKey) { +// OLD: ret.append("$EOL$indent set(value) { put(\"${name}\", value) }") + val setter = when(raw) { + null -> "UnknownSetter[$type]" + "enum" -> "super.put(\"${name}\", value?.name)" + "date", "datetime", "datetimez" -> "super.put(\"${name}\", value?.toInstant().toString())" + else -> "super.put(\"${name}\", value)" + } + ret.append("$EOL$indent set(value) { $setter }") + } } } return ret.toString() -- GitLab