From eb5dc39ba716e6e5145100fd38655d46f4c9eaef Mon Sep 17 00:00:00 2001 From: Roman Langolf Date: Mon, 12 Jan 2026 13:16:05 +0700 Subject: [PATCH 1/2] update scala syntax and test on compilation --- PgCodeGen.scala | 38 +++++++++++++++++++------------------- PgCodeGenTest.scala | 21 +++++++++++---------- test.sh | 13 ++++++++----- 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/PgCodeGen.scala b/PgCodeGen.scala index 9f2a694..0c7b824 100644 --- a/PgCodeGen.scala +++ b/PgCodeGen.scala @@ -1,8 +1,8 @@ -//> using scala 3.7.1 +//> using scala 3.7.4 //> using dep com.indoorvivants.roach::core::0.1.0 //> using dep com.github.lolgab::scala-native-crypto::0.2.1 //> using platform native -//> using nativeVersion 0.5.8 +//> using nativeVersion 0.5.9 package com.anymindgroup @@ -140,9 +140,9 @@ class PgCodeGen private ( ): Type = (udt, maxCharLength, numPrecision, numScale) match { case (u @ ("bpchar" | "varchar"), Some(l), _, _) => Type(s"$u($l)") - case ("numeric", _, Some(p), Some(s)) => Type(s"numeric($p${if (s > 0) ", " + s.toString else ""})") + case ("numeric", _, Some(p), Some(s)) => Type(s"numeric($p${if s > 0 then ", " + s.toString else ""})") case _ => - val componentTypes = if (udt.startsWith("_")) List(Type(udt.stripPrefix("_"))) else Nil + val componentTypes = if udt.startsWith("_") then List(Type(udt.stripPrefix("_"))) else Nil Type(udt, componentTypes) } @@ -451,12 +451,12 @@ class PgCodeGen private ( ).collectFirst { // check by type name without a max length parameter if set, e.g. vacrhar instead of varchar(3) case (scalaType, pgTypes) if pgTypes.contains(t.name.takeWhile(_ != '(')) => - if (isNullable) s"Option[$scalaType]" else scalaType + if isNullable then s"Option[$scalaType]" else scalaType }.orElse { - enums.find(_.name == t.name).map(e => if (isNullable) s"Option[${e.scalaName}]" else e.scalaName) + enums.find(_.name == t.name).map(e => if isNullable then s"Option[${e.scalaName}]" else e.scalaName) }.toRight(s"No scala type found for type ${t.name}") case x :: Nil => - toScalaType(x, isNullable = false, enums).map(t => if (isNullable) s"Option[List[$t]]" else s"List[$t]") + toScalaType(x, isNullable = false, enums).map(t => if isNullable then s"Option[List[$t]]" else s"List[$t]") case x :: xs => Left(s"Unsupported type of multiple components: ${x :: xs}") } @@ -484,7 +484,7 @@ class PgCodeGen private ( } val rowUpdateClassData = - if (table.isView) (Nil, Nil) + if table.isView then (Nil, Nil) else primaryUniqueConstraint match { case Some(cstr) => @@ -583,7 +583,7 @@ class PgCodeGen private ( private def queryTypesStr(table: Table): (String, String) = { import table.* - if (autoIncFk.isEmpty) { + if autoIncFk.isEmpty then { (rowClassName, s"${rowClassName}.codec") } else { val autoIncFkCodecs = autoIncFk.map(_.codecName).mkString(" *: ") @@ -593,7 +593,7 @@ class PgCodeGen private ( } private def writeStatements(table: Table): String = - if (table.isView) "" + if table.isView then "" else { import table.* @@ -607,7 +607,7 @@ class PgCodeGen private ( } val returningType = generatedColumns .map(_.scalaType) - .mkString("", " *: ", if (generatedColumns.length > 1) " *: EmptyTuple" else "") + .mkString("", " *: ", if generatedColumns.length > 1 then " *: EmptyTuple" else "") val fragmentType = generatedColumns match { case Nil => "command" case _ => s"query(${generatedColumns.map(_.codecName).mkString(" *: ")})" @@ -631,7 +631,7 @@ class PgCodeGen private ( } val insertQ = s"""| def insertQuery(ignoreConflict: Boolean = true): $queryType = { - | val onConflictFr = if (ignoreConflict) const" ON CONFLICT DO NOTHING" else const"" + | val onConflictFr = if ignoreConflict then const" ON CONFLICT DO NOTHING" else const"" | sql\"INSERT INTO #$$tableName ($allColNames) VALUES ($${$insertCodec})$$onConflictFr$returningStatement\".$fragmentType | }""".stripMargin @@ -640,7 +640,7 @@ class PgCodeGen private ( | def insert[A](cols: Cols[A]): Command[A] = | sql\"INSERT INTO #$$tableName (#$${cols.name}) VALUES ($${cols.codec})\".command | - | def insert0[A, B](cols: Cols[A], rest: Fragment[B] = sql"ON CONFLICT DO NOTHING")(implicit + | def insert0[A, B](cols: Cols[A], rest: Fragment[B] = sql"ON CONFLICT DO NOTHING")(using | ev: Void =:= B | ): Command[A] = | (sql\"INSERT INTO #$$tableName (#$${cols.name}) VALUES ($${cols.codec}) " ~ rest).command.contramap[A](a => (a, ev.apply(Void))) @@ -678,7 +678,7 @@ class PgCodeGen private ( private def selectAllStatement(table: Table): String = { import table.* - val generatedColStm = if (generatedColumns.nonEmpty) { + val generatedColStm = if generatedColumns.nonEmpty then { val types = generatedColumns.map(_.codecName).mkString(" *: ") val sTypes = generatedColumns.map(_.scalaType).mkString(" *: ") val colNamesStr = (generatedColumns ++ columns).map(_.columnName).mkString(", ") @@ -915,7 +915,7 @@ object PgCodeGen { private val versioned = "^V([^_]+)__(.+)\\.sql$".r private val repeatable = "^R__(.+)\\.sql$".r - given Ordering[MigrationVersion] with + given Ordering[MigrationVersion]: def compare(x: MigrationVersion, y: MigrationVersion): Int = x.compare(y) def fromFileName(name: String): Either[String, MigrationVersion] = name match @@ -972,9 +972,9 @@ object PgCodeGen { val codecName: String = ( - (if (isEnum) s"${toScalaName(pgType.name).capitalize}.codec" else s"skunk.codec.all.${pgType.name}") + - (if (isArr) "._list" else "") + - (if (isNullable) ".opt" else "") + (if isEnum then s"${toScalaName(pgType.name).capitalize}.codec" else s"skunk.codec.all.${pgType.name}") + + (if isArr then "._list" else "") + + (if isNullable then ".opt" else "") ) } @@ -985,7 +985,7 @@ object PgCodeGen { case object AutoInc extends ColumnDefault def fromString(value: String): Option[ColumnDefault] = - if (value.contains("nextval")) Some(AutoInc) else None + if value.contains("nextval") then Some(AutoInc) else None } sealed trait Constraint { def name: String diff --git a/PgCodeGenTest.scala b/PgCodeGenTest.scala index cd8651d..975e558 100644 --- a/PgCodeGenTest.scala +++ b/PgCodeGenTest.scala @@ -1,5 +1,5 @@ -//> using scala 3.7.1 -//> using dep dev.rolang::dumbo:0.5.5 +//> using scala 3.7.4 +//> using dep dev.rolang::dumbo:0.6.1 //> using platform jvm //> using jvm system //> using file test-generated/generated @@ -16,10 +16,12 @@ import cats.effect.{ExitCode, IO, IOApp} import cats.effect.std.Console import cats.implicits.* import dumbo.ConnectionConfig +import dumbo.logging.Implicits.console import fs2.io.file.Path import generated.* import org.typelevel.otel4s.trace.Tracer.Implicits.noop import skunk.* +import skunk.Session.Credentials import skunk.codec.all.* import skunk.implicits.* import skunk.util.{Origin, Typer} @@ -44,14 +46,13 @@ object GeneratedCodeTest extends IOApp { _ <- awaitReadiness(testDbPort) _ <- migrate(testDbPort) _ <- Session - .single[IO]( - host = "localhost", - port = testDbPort, - user = "postgres", - database = "postgres", - password = Some("postgres"), - strategy = Typer.Strategy.SearchPath // to include custom types like enums, - ) + .Builder[IO] + .withHost("localhost") + .withPort(testDbPort) + .withDatabase("postgres") + .withCredentials(Credentials(user = "postgres", password = Some("postgres"))) + .withTypingStrategy(skunk.TypingStrategy.SearchPath) + .single .use { s => val (testRow, testUpdateFr) = TestRow( number = Some(1), diff --git a/test.sh b/test.sh index 1a5b5a3..5cdcece 100755 --- a/test.sh +++ b/test.sh @@ -3,9 +3,9 @@ set -e # generate binary CODEGEN_BIN=out/skunk-codegen-$(uname -m)-$(uname | tr '[:upper:]' '[:lower:]') -scala-cli --power package \ +scala --power package \ --native \ - --native-mode release-fast PgCodeGen.scala \ + --native-mode release-fast PgCodeGen.scala -source:future -Werror \ -o $CODEGEN_BIN -f echo "⏳Test generated code" @@ -20,7 +20,7 @@ $CODEGEN_BIN \ TIMESTAMP_A=$(stat test-generated | grep Modify) # run test for generated code -scala-cli run PgCodeGenTest.scala +scala run PgCodeGenTest.scala -source:future -Werror echo "✅ Test of generated code successful" echo "⏳running generator again with -force=true should re-run code generation" @@ -87,7 +87,10 @@ docker run --rm --name codegentest -e POSTGRES_PASSWORD=postgres -p 5555:5432 -d -exclude-tables=unsupported_yet \ -source-dir=test/migrations \ -use-connection=postgresql://postgres:postgres@localhost:5555/postgres \ - -force=true && echo "✅ Code generation for provided connection ok.") || (docker rm -f codegentest; exit 1) + -force=true && echo "✅ Code generation for provided connection ok.") || ( + docker rm -f codegentest + exit 1 +) docker rm -f codegentest @@ -103,4 +106,4 @@ if $CODEGEN_BIN \ exit 1 else echo "✅ Process failed as expected" -fi \ No newline at end of file +fi From e8c205d0aaed3f36634064037ec203ab6b013fbc Mon Sep 17 00:00:00 2001 From: Roman Langolf Date: Mon, 12 Jan 2026 13:27:53 +0700 Subject: [PATCH 2/2] update script to use variable for Scala command --- test.sh | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test.sh b/test.sh index 5cdcece..4a8f926 100755 --- a/test.sh +++ b/test.sh @@ -1,9 +1,19 @@ #!/usr/bin/env bash set -e +# pick scala runner (prefer scala-cli, fallback to scala); fail if none available +if command -v scala-cli >/dev/null 2>&1; then + SCALA_CMD=scala-cli +elif command -v scala >/dev/null 2>&1; then + SCALA_CMD=scala +else + echo "❌ Neither scala-cli nor scala found on PATH" >&2 + exit 1 +fi + # generate binary CODEGEN_BIN=out/skunk-codegen-$(uname -m)-$(uname | tr '[:upper:]' '[:lower:]') -scala --power package \ +$SCALA_CMD --power package \ --native \ --native-mode release-fast PgCodeGen.scala -source:future -Werror \ -o $CODEGEN_BIN -f @@ -20,7 +30,7 @@ $CODEGEN_BIN \ TIMESTAMP_A=$(stat test-generated | grep Modify) # run test for generated code -scala run PgCodeGenTest.scala -source:future -Werror +$SCALA_CMD run PgCodeGenTest.scala -source:future -Werror echo "✅ Test of generated code successful" echo "⏳running generator again with -force=true should re-run code generation"