Skip to content

Commit

Permalink
Fix codegen ordering. Fix duplicate enums. Add JSONB basic support
Browse files Browse the repository at this point in the history
  • Loading branch information
sake92 committed Sep 4, 2024
1 parent 22ab957 commit 9941165
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 74 deletions.
4 changes: 4 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@


jsonb

- include/exclude tables
- override types

- paging
Expand Down
103 changes: 36 additions & 67 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,40 @@ import io.kipp.mill.ci.release.CiReleaseModule
import ba.sake.millhepek.MillHepekModule

val scala213 = "2.13.14"

object squery extends CommonScalaModule with CiReleaseModule {

def pomSettings = PomSettings(
organization = "ba.sake",
url = "https://github.com/sake92/squery",
licenses = Seq(License.Common.Apache2),
versionControl = VersionControl.github("sake92", "squery"),
description = "Squery SQL library",
developers = Seq(
Developer("sake92", "Sakib Hadžiavdić", "https://sake.ba")
)
val scala3 = "3.4.2"
val pomSettingsValue = PomSettings(
organization = "ba.sake",
url = "https://github.com/sake92/squery",
licenses = Seq(License.Common.Apache2),
versionControl = VersionControl.github("sake92", "squery"),
description = "Squery SQL library",
developers = Seq(
Developer("sake92", "Sakib Hadžiavdić", "https://sake.ba")
)
)
val millVersion = "0.11.12"

object squery extends ScalaModule with ScalafmtModule with CiReleaseModule {
def artifactName = "squery"

def pomSettings = pomSettingsValue
def scalaVersion = scala3
def ivyDeps = Agg(
ivy"com.typesafe.scala-logging::scala-logging:3.9.4",
ivy"com.github.jsqlparser:jsqlparser:4.7",
ivy"org.scala-lang.modules::scala-collection-contrib:0.3.0"
)

def scalacOptions = Seq("-Ywarn-unused", "-deprecation", "-feature")

object `postgres-jawn` extends ScalaModule with ScalafmtModule with CiReleaseModule {
def artifactName = "squery-postgres-jawn"
def pomSettings = pomSettingsValue
def scalaVersion = scala3
def moduleDeps = Seq(squery)
def ivyDeps = Agg(
ivy"org.typelevel::jawn-ast::1.6.0"
)
}

object test extends ScalaTests with TestModule.Munit {
def ivyDeps = Agg(
ivy"org.scalameta::munit:1.0.0",
Expand All @@ -55,22 +65,10 @@ object squery extends CommonScalaModule with CiReleaseModule {
}
}

object generator extends ScalaModule with CiReleaseModule {
object generator extends ScalaModule with CiReleaseModule with ScalafmtModule {
def artifactName = "squery-generator"

def pomSettings = pomSettingsValue
def scalaVersion = scala213

def pomSettings = PomSettings(
organization = "ba.sake",
url = "https://github.com/sake92/squery",
licenses = Seq(License.Common.Apache2),
versionControl = VersionControl.github("sake92", "squery"),
description = "Squery Generator library",
developers = Seq(
Developer("sake92", "Sakib Hadžiavdić", "https://sake.ba")
)
)

def ivyDeps = Agg(
ivy"ba.sake::regenesca:0.1.0",
ivy"com.typesafe.scala-logging::scala-logging:3.9.4",
Expand All @@ -80,64 +78,38 @@ object generator extends ScalaModule with CiReleaseModule {
}

/* MILL PLUGIN */
val millVersion = "0.11.12"

object `mill-plugin` extends ScalaModule with CiReleaseModule with ScalafmtModule {

def artifactName =
s"mill-squery-generator_mill${millBinaryVersion(millVersion)}"
def millBinaryVersion(millVersion: String) =
scalaNativeBinaryVersion(millVersion)

def pomSettings = pomSettingsValue
def scalaVersion = scala213

def artifactName =
s"mill-squery-generator_mill${millBinaryVersion(millVersion)}"

def pomSettings = PomSettings(
description = "Mill plugin for generating squery source code",
organization = "ba.sake",
url = "https://github.com/sake92/squery",
licenses = Seq(License.`Apache-2.0`),
versionControl = VersionControl.github(owner = "sake92", repo = "squery"),
developers = Seq(Developer("sake92", "Sakib Hadziavdic", "https://github.com/sake92"))
)

def compileIvyDeps = super.compileIvyDeps() ++ Agg(
ivy"com.lihaoyi::mill-scalalib:${millVersion}"
)

def moduleDeps = Seq(generator)

def ivyDeps = Agg(
ivy"com.h2database:h2:2.3.232",
ivy"org.postgresql:postgresql:42.7.4",
ivy"mysql:mysql-connector-java:8.0.33",
ivy"org.mariadb.jdbc:mariadb-java-client:3.3.2",
ivy"com.oracle.database.jdbc:ojdbc8:23.3.0.23.09"
)

def scalacOptions = Seq("-Ywarn-unused", "-deprecation")

}

object `mill-plugin-itest` extends MillIntegrationTestModule {

def millTestVersion = millVersion

def pluginsUnderTest = Seq(`mill-plugin`)

def temporaryIvyModules = Seq(squery)

def testBase = millSourcePath / "src"

def testInvocations: T[Seq[(PathRef, Seq[TestInvocation.Targets])]] =
T {
Seq(
PathRef(testBase / "h2") -> Seq(
TestInvocation.Targets(Seq("verify"), noServer = true)
)
)
}

def testInvocations: T[Seq[(PathRef, Seq[TestInvocation.Targets])]] = T {
Seq(
PathRef(testBase / "h2") -> Seq(TestInvocation.Targets(Seq("verify"), noServer = true))
)
}
override def perTestResources = T.sources {
os.write(
T.dest / "versions.sc",
Expand All @@ -150,12 +122,9 @@ object `mill-plugin-itest` extends MillIntegrationTestModule {
}

/* DOCS */
object docs extends CommonScalaModule with MillHepekModule {
object docs extends ScalaModule with MillHepekModule with ScalafmtModule {
def scalaVersion = scala3
def ivyDeps = Agg(
ivy"ba.sake::hepek:0.24.1"
)
}

trait CommonScalaModule extends ScalaModule with ScalafmtModule {
def scalaVersion = "3.4.0"
}
8 changes: 6 additions & 2 deletions docs/src/files/tutorials/CodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,13 @@ object CodeGen extends TutorialPage {
import $$ivy.`org.postgresql:postgresql:42.7.4`
import $$ivy.`com.zaxxer:HikariCP:5.1.0`
import ba.sake.squery.generator.*
import com.zaxxer.hikari.HikariDataSource

val dataSource = com.zaxxer.hikari.HikariDataSource()
// if using Postgres JSONB
// import $$ivy.`ba.sake::squery-postgres-jawn:${Consts.ArtifactVersion}`
// import ba.sake.squery.postgres.jawn.*

val dataSource = HikariDataSource()
dataSource.setJdbcUrl("jdbc:postgresql://localhost:5432/mydb")
dataSource.setUsername("username")
dataSource.setPassword("password")
Expand All @@ -55,7 +60,6 @@ object CodeGen extends TutorialPage {
ctx.run {
MyTableCrudDao.findAll()
}
""".md
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ class PostgresDefExtractor(ds: DataSource) extends DbDefExtractor(ds) {
case "timestamp with time zone" => ColumnType.Predefined(t"Instant")
case "uuid" => ColumnType.Predefined(t"UUID")
case "bytea" => ColumnType.Predefined(t"Array[Byte]")
case "json" => ColumnType.Predefined(t"org.typelevel.jawn.ast.JValue")
case "jsonb" => ColumnType.Predefined(t"org.typelevel.jawn.ast.JValue")
case other => throw new RuntimeException(s"Unknown scalar type ${other}")
}
}
Expand Down
13 changes: 8 additions & 5 deletions generator/src/ba/sake/squery/generator/SqueryGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class SqueryGenerator(ds: DataSource, config: SqueryGeneratorConfig = SqueryGene
logger.info(s"Started generating schema '${schemaName}'")
val (modelFiles, daoFiles) =
generateSchema(schemaDef, dbType = dbDef.tpe, basePackage = "", fileGen = false)
// models first because of Ammonite eval order!
val allFiles = modelFiles ++ daoFiles
val allSources = generateBaseImports(dbDef.tpe).map(_.syntax) ++ allFiles.map(_.source.syntax)
logger.info(s"Finished generating schema '${schemaName}'")
Expand Down Expand Up @@ -86,7 +87,7 @@ class SqueryGenerator(ds: DataSource, config: SqueryGeneratorConfig = SqueryGene
_.columnDefs.map(_.scalaType).collect { case e: ColumnType.Enumeration =>
e
}
}
}.distinctBy(_.name)
val enumFiles = enumDefs.map { enumDef =>
val enumCaseDefs = Defn.RepeatedEnumCase(
List.empty,
Expand Down Expand Up @@ -198,18 +199,20 @@ class SqueryGenerator(ds: DataSource, config: SqueryGeneratorConfig = SqueryGene
"""
}

// object goes first, coz class references PK type
// so that it works in ammonite where definitions are parsed 1 by 1
val source =
if (fileGen)
source"""
package ${generatePkgSelect(s"${basePackage}.models")}
..${generateBaseImports(dbType)}
${caseClassDefn}
${objectDefn}
${caseClassDefn}
"""
else
source"""
${caseClassDefn}
${objectDefn}
${caseClassDefn}
"""
GeneratedFileSource(Paths.get(s"${caseClassName}.scala"), source)
}
Expand Down Expand Up @@ -515,13 +518,13 @@ class SqueryGenerator(ds: DataSource, config: SqueryGeneratorConfig = SqueryGene
source"""
package ${generatePkgSelect(s"${basePackage}.daos")}
..${generateDaoImports(dbType, basePackage)}
${daoClassDefn}
${daoObjectDefn}
${daoClassDefn}
"""
else
source"""
${daoClassDefn}
${daoObjectDefn}
${daoClassDefn}
"""
GeneratedFileSource(Paths.get(s"${daoClassName}.scala"), source)
}
Expand Down
13 changes: 13 additions & 0 deletions squery/postgres-jawn/src/ba/sake/postgres/jawn/reads.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ba.sake.squery.postgres.jawn

import java.{sql => jsql}
import org.typelevel.jawn.ast.*
import ba.sake.squery.read.*

given SqlRead[JValue] with {
def readByName(jRes: jsql.ResultSet, colName: String): Option[JValue] =
SqlRead[String].readByName(jRes, colName).map(JParser.parseUnsafe)

def readByIdx(jRes: jsql.ResultSet, colIdx: Int): Option[JValue] =
SqlRead[String].readByIdx(jRes, colIdx).map(JParser.parseUnsafe)
}
15 changes: 15 additions & 0 deletions squery/postgres-jawn/src/ba/sake/postgres/jawn/writes.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package ba.sake.squery.postgres.jawn

import java.{sql => jsql}
import org.typelevel.jawn.ast.*
import ba.sake.squery.write.*

given SqlWrite[JValue] with {
def write(
ps: jsql.PreparedStatement,
idx: Int,
valueOpt: Option[JValue]
): Unit = valueOpt match
case Some(value) => ps.setObject(idx, FastRenderer.render(value), jsql.Types.OTHER)
case None => ps.setNull(idx, jsql.Types.OTHER)
}

0 comments on commit 9941165

Please sign in to comment.