Skip to content

Commit

Permalink
Add mill plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
sake92 committed Aug 15, 2024
1 parent ab5fb76 commit 98f96c1
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .mill-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.11.5
0.11.11
9 changes: 9 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@





- start temp mujz/pagila in CI with docker
- generate pagila files with mill plugin
- test that we can read the db with generated files

109 changes: 90 additions & 19 deletions build.sc
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
import $ivy.`io.chris-kipp::mill-ci-release::0.1.9`
import $ivy.`de.tototec::de.tobiasroeser.mill.integrationtest::0.7.1`
import $ivy.`ba.sake::mill-hepek::0.0.2`

import mill._, mill.scalalib._, publish._, scalafmt._
import mill._, mill.scalalib._
import mill.scalalib.scalafmt._
import mill.scalalib.publish._
import mill.scalalib.api.ZincWorkerUtil.scalaNativeBinaryVersion
import de.tobiasroeser.mill.integrationtest._

import io.kipp.mill.ci.release.CiReleaseModule
import ba.sake.millhepek.MillHepekModule

object squery extends CommonScalaModule with SqueryPublishModule {
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")
)
)

def artifactName = "squery"

def ivyDeps = Agg(
Expand Down Expand Up @@ -34,19 +53,30 @@ object squery extends CommonScalaModule with SqueryPublishModule {
}
}

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

def moduleDeps = Seq(squery)
override 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"com.typesafe.scala-logging::scala-logging:3.9.4",
ivy"ch.qos.logback:logback-classic:1.4.6",
ivy"com.lihaoyi::os-lib:0.10.3",
ivy"org.apache.commons:commons-text:1.12.0"
)

object test extends ScalaTests with TestModule.Munit {

def ivyDeps = Agg(
ivy"org.scalameta::munit:1.0.0",
ivy"com.zaxxer:HikariCP:4.0.3",
Expand All @@ -57,6 +87,61 @@ object generator extends CommonScalaModule with SqueryPublishModule {
}
}

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

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

def millBinaryVersion(millVersion: String) =
scalaNativeBinaryVersion(millVersion)

override def scalaVersion = scala213

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

override 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"))
)

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

def moduleDeps = Seq(generator)

def ivyDeps = Agg(
ivy"org.postgresql:postgresql:42.6.0"
)

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

}

object `mill-plugin-itest` extends MillIntegrationTestModule {

override def millTestVersion = millVersion

override def pluginsUnderTest = Seq(`mill-plugin`)

def testBase = millSourcePath / "src"

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

/* DOCS */
object docs extends CommonScalaModule with MillHepekModule {
def ivyDeps = Agg(
ivy"ba.sake::hepek:0.24.1"
Expand All @@ -66,17 +151,3 @@ object docs extends CommonScalaModule with MillHepekModule {
trait CommonScalaModule extends ScalaModule with ScalafmtModule {
def scalaVersion = "3.4.0"
}

trait SqueryPublishModule extends 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")
)
)
}
45 changes: 24 additions & 21 deletions generator/src/ba/sake/squery/DbMetadataExtractor.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package ba.sake.squery.generator

import java.sql.{Array => _, *}
import java.sql.{Array => _, _}
import javax.sql.DataSource
import scala.util.*
import scala.util.chaining.*
import scala.util._
import scala.util.chaining._
import scala.collection.mutable.ArrayBuffer
import org.apache.commons.lang3.StringUtils
import org.apache.commons.text.CaseUtils
Expand Down Expand Up @@ -63,7 +63,7 @@ class DbMetadataExtractor(ds: DataSource) {

val res = ArrayBuffer.empty[ColumnDef]
Using.resource(databaseMetaData.getColumns(null, schemaName, tableName, null)) { resultSet =>
while resultSet.next() do {
while (resultSet.next()) {
val columnName = resultSet.getString("COLUMN_NAME")
val typeName = resultSet.getString("TYPE_NAME")
val jdbcType = resultSet.getInt("DATA_TYPE") // java.sql.Types
Expand Down Expand Up @@ -99,7 +99,7 @@ class DbMetadataExtractor(ds: DataSource) {
Using.resource(connection.createStatement()) { stmt =>
Using.resource(stmt.executeQuery(query)) { rs =>
val buff = ArrayBuffer.empty[((String, String), ColumnType)]
while rs.next() do {
while (rs.next()) {
val tableName = rs.getString("table_name")
val columnName = rs.getString("column_name")
val displayTypeOriginal = rs.getString("display_type_original")
Expand All @@ -119,14 +119,11 @@ class DbMetadataExtractor(ds: DataSource) {
displayTypeResolved: String,
arrayDim: Int
): ColumnType = {
if arrayDim > 0 then {
if (arrayDim > 0) {
val arrayScalarType = displayTypeOriginal.takeWhile(_ != '[')
resolveScalarType(arrayScalarType)
.map { scalarType =>
val scalarTypeName = scalarType match
case ColumnType.Predefined(name) => name
case ColumnType.Enumeration(name, _) => name
case ColumnType.Unknown(_) => "<UNKNOWN>"
val scalarTypeName = scalarType.name
val arrayType = ("Array[" * arrayDim) + scalarTypeName + ("]" * arrayDim)
// TODO array of enums/domain types?
ColumnType.Predefined(arrayType)
Expand Down Expand Up @@ -156,19 +153,20 @@ class DbMetadataExtractor(ds: DataSource) {
case "date" => ColumnType.Predefined("LocalDate")
case "timestamp without time zone" => ColumnType.Predefined("LocalDateTime")
case "timestamp with time zone" => ColumnType.Predefined("Instant")
case "uuid" => ColumnType.Predefined("UUID")
case "bytea" => ColumnType.Predefined("Array[Byte]")
case other => throw RuntimeException(s"Unknown scalar type ${other}")
case other => throw new RuntimeException(s"Unknown scalar type ${other}")
}
}

def resolveEnumType(connection: Connection, typeName: String): Try[ColumnType.Enumeration] =
Using(connection.createStatement()) { stmt =>
val resultSet = stmt.executeQuery(s"select unnest(enum_range(null, null::${typeName}))")
val enumValues = ArrayBuffer.empty[String]
while resultSet.next() do {
while (resultSet.next()) {
enumValues += resultSet.getString(1)
}
if enumValues.isEmpty then throw RuntimeException(s"Enum '${typeName}' has no values and cannot be generated.")
if (enumValues.isEmpty) throw new RuntimeException(s"Enum '${typeName}' has no values and cannot be generated.")
else ColumnType.Enumeration(typeName, enumValues.toSeq)
}

Expand All @@ -177,15 +175,18 @@ class DbMetadataExtractor(ds: DataSource) {
val metadata = resultSet.getMetaData()
val totalCols = metadata.getColumnCount()
var columnNames = Seq.empty[String]
for i <- 1 to totalCols do columnNames = columnNames.appended(metadata.getColumnName(i))
for (i <- 1 to totalCols) {
columnNames = columnNames.appended(metadata.getColumnName(i))
}

while (resultSet.next()) do
while (resultSet.next()) {
println("+" * 30)
for i <- 1 to totalCols do
for (i <- 1 to totalCols) {
val value = resultSet.getString(i)
print(s"${columnNames(i - 1)} = ${value}; ")
}
println()
end while
}
}
}

Expand All @@ -210,7 +211,9 @@ case class ColumnDef(
defaultValue: Option[String]
)

enum ColumnType:
case Predefined(name: String)
case Enumeration(name: String, values: Seq[String])
case Unknown(originalName: String)
sealed abstract class ColumnType
object ColumnType {
case class Predefined(name: String) extends ColumnType
case class Enumeration(name: String, values: Seq[String]) extends ColumnType
case class Unknown(originalName: String) extends ColumnType
}
Loading

0 comments on commit 98f96c1

Please sign in to comment.