Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions PgCodeGen.scala
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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}")
}
Expand Down Expand Up @@ -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) =>
Expand Down Expand Up @@ -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(" *: ")
Expand All @@ -593,7 +593,7 @@ class PgCodeGen private (
}

private def writeStatements(table: Table): String =
if (table.isView) ""
if table.isView then ""
else {
import table.*

Expand All @@ -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(" *: ")})"
Expand All @@ -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

Expand All @@ -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)))
Expand Down Expand Up @@ -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(", ")
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 "")
)
}

Expand All @@ -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
Expand Down
21 changes: 11 additions & 10 deletions PgCodeGenTest.scala
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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}
Expand All @@ -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),
Expand Down
23 changes: 18 additions & 5 deletions test.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
#!/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-cli --power package \
$SCALA_CMD --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"
Expand All @@ -20,7 +30,7 @@ $CODEGEN_BIN \
TIMESTAMP_A=$(stat test-generated | grep Modify)

# run test for generated code
scala-cli run PgCodeGenTest.scala
$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"
Expand Down Expand Up @@ -87,7 +97,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

Expand All @@ -103,4 +116,4 @@ if $CODEGEN_BIN \
exit 1
else
echo "✅ Process failed as expected"
fi
fi
Loading