Skip to content
This repository was archived by the owner on Oct 14, 2018. It is now read-only.

Commit 341ae50

Browse files
committed
Create CLI.
1 parent 08c3d93 commit 341ae50

File tree

7 files changed

+108
-33
lines changed

7 files changed

+108
-33
lines changed

Readme.md

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,42 @@
1-
# db-codegen
1+
# scala-db-codegen
2+
3+
Generate Scala code from your database.
4+
Only tested with postgresql, but could in theory work with any jdbc compliant database.
5+
6+
## CLI
7+
8+
```shell
9+
$ db-codegen --help
10+
db-codegen 0.1.0
11+
Usage: db-codegen [options]
12+
--usage
13+
Print usage and exit
14+
--help | -h
15+
Print help message and exit
16+
--user <value>
17+
user on database server
18+
--password <value>
19+
password for user on database server
20+
--url <value>
21+
jdbc url
22+
--schema <value>
23+
schema on database
24+
--jdbc-driver <value>
25+
only tested with postgresql
26+
--imports <value>
27+
top level imports of generated file
28+
--package <value>
29+
package name for generated classes
30+
--type-map <value>
31+
Which types should write to which types? Format is: numeric,BigDecimal;int8,Long;...
32+
--excluded-tables <value>
33+
Do not generate classes for these tables.
34+
--file <value>
35+
Write generated code to this filename. Prints to stdout if not set.
36+
```
37+
38+
## Standalone library
39+
40+
TODO, look at source for now.
41+
242
3-
Generated "Type all the things" Scala code given a connection to a database.
4-
Only tested with postgresql.

build.sbt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,19 @@ lazy val publishSettings = Seq(
3333

3434
lazy val `launaskil-codegen` =
3535
(project in file("."))
36+
.settings(packSettings)
3637
.settings(publishSettings)
3738
.settings(
3839
name := "codegen",
3940
organization := "com.geirsson",
4041
scalaVersion := "2.11.8",
42+
packMain := Map("db-codegen" -> "com.geirsson.codegen.Codegen"),
4143
libraryDependencies ++= Seq(
4244
"com.geirsson" %% "scalafmt-core" % "0.3.0",
4345
"io.getquill" %% "quill-core" % "0.8.0",
4446
"com.h2database" % "h2" % "1.4.192",
4547
"org.postgresql" % "postgresql" % "9.4-1201-jdbc41",
46-
"com.github.alexarchambault" %% "case-app" % "1.1.0-RC3",
48+
"com.github.alexarchambault" %% "case-app" % "1.0.0-RC3",
4749
"org.scalatest" %% "scalatest" % "3.0.0" % "test"
4850
)
4951
)

project/plugins.sbt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "1.1")
22
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
3+
addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.8.0")

src/main/scala/com/geirsson/codegen/Codegen.scala

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,47 @@ import java.sql.Connection
88
import java.sql.DriverManager
99
import java.sql.ResultSet
1010

11+
import caseapp.AppOf
12+
import caseapp._
1113
import io.getquill.NamingStrategy
1214
import org.scalafmt.FormatResult
1315
import org.scalafmt.Scalafmt
1416
import org.scalafmt.ScalafmtStyle
1517

16-
case class Codegen(options: CodegenOptions, namingStrategy: NamingStrategy) {
18+
case class Error(msg: String) extends Exception(msg)
19+
20+
@AppName("db-codegen")
21+
@AppVersion("0.1.0")
22+
@ProgName("db-codegen")
23+
case class CodegenOptions(
24+
@HelpMessage("user on database server") user: String = "postgres",
25+
@HelpMessage("password for user on database server") password: String =
26+
"postgres",
27+
@HelpMessage("jdbc url") url: String = "jdbc:postgresql:postgres",
28+
@HelpMessage("schema on database") schema: String = "public",
29+
@HelpMessage("only tested with postgresql") jdbcDriver: String =
30+
"org.postgresql.Driver",
31+
@HelpMessage(
32+
"top level imports of generated file"
33+
) imports: String = """|import java.util.Date
34+
|import io.getquill.WrappedValue""".stripMargin,
35+
@HelpMessage(
36+
"package name for generated classes"
37+
) `package`: String = "tables",
38+
@HelpMessage(
39+
"Which types should write to which types? Format is: numeric,BigDecimal;int8,Long;..."
40+
) typeMap: TypeMap = TypeMap.default,
41+
@HelpMessage(
42+
"Do not generate classes for these tables."
43+
) excludedTables: List[String] = List("schema_version"),
44+
@HelpMessage(
45+
"Write generated code to this filename. Prints to stdout if not set."
46+
) file: Option[String] = None
47+
) extends App {
48+
Codegen.cliRun(this)
49+
}
1750

51+
case class Codegen(options: CodegenOptions, namingStrategy: NamingStrategy) {
1852
import Codegen._
1953
val excludedTables = options.excludedTables.toSet
2054
val columnType2scalaType = options.typeMap.pairs.toMap
@@ -112,7 +146,9 @@ case class Codegen(options: CodegenOptions, namingStrategy: NamingStrategy) {
112146
nullable: Boolean,
113147
isPrimaryKey: Boolean,
114148
references: Option[SimpleColumn]) {
115-
val scalaType = columnType2scalaType(`type`)
149+
val scalaType = columnType2scalaType.getOrElse(`type`, {
150+
throw Error(s"ERROR: missing --type-map for type '${`type`}'")
151+
})
116152

117153
def toArg(namingStrategy: NamingStrategy, tableName: String): String = {
118154
s"${namingStrategy.column(columnName)}: ${this.toSimple.toType}"
@@ -154,10 +190,9 @@ case class Codegen(options: CodegenOptions, namingStrategy: NamingStrategy) {
154190
|}""".stripMargin
155191
}
156192
}
157-
158193
}
159194

160-
object Codegen {
195+
object Codegen extends AppOf[CodegenOptions] {
161196
val TABLE_NAME = "TABLE_NAME"
162197
val COLUMN_NAME = "COLUMN_NAME"
163198
val TYPE_NAME = "TYPE_NAME"
@@ -174,23 +209,26 @@ object Codegen {
174209
}
175210
}
176211

177-
import caseapp._
178-
179-
def main(args: Array[String]): Unit = {
180-
CaseApp.parse[CodegenOptions](args) match {
181-
case Right((options, _)) => run(options)
182-
case Left(msg) => System.err.println(msg)
212+
def cliRun(codegenOptions: CodegenOptions,
213+
outstream: PrintStream = System.out): Unit = {
214+
try {
215+
run(codegenOptions, outstream)
216+
} catch {
217+
case Error(msg) =>
218+
System.err.println(msg)
219+
System.exit(1)
183220
}
184221
}
185222

186223
def run(codegenOptions: CodegenOptions,
187224
outstream: PrintStream = System.out): Unit = {
188225
println("Starting...")
226+
189227
val startTime = System.currentTimeMillis()
190228
Class.forName(codegenOptions.jdbcDriver)
191229
val db: Connection =
192230
DriverManager.getConnection(codegenOptions.url,
193-
codegenOptions.username,
231+
codegenOptions.user,
194232
codegenOptions.password)
195233
val codegen = Codegen(codegenOptions, SnakeCaseReverse)
196234
val foreignKeys = codegen.getForeignKeys(db)

src/main/scala/com/geirsson/codegen/CodegenOptions.scala

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/main/scala/com/geirsson/codegen/TypeMap.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ object TypeMap {
99
ArgParser.instance[TypeMap] { s =>
1010
try {
1111
val pairs = s.split(";").map { pair =>
12-
val from :: to :: Nil = pair.split(",", 1).toList
12+
val from :: to :: Nil = pair.split(",", 2).toList
1313
from -> to
1414
}
1515
Right(TypeMap(pairs: _*))

src/test/scala/com/geirsson/codegen/CodegenTest.scala

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import java.io.PrintStream
55
import java.nio.charset.StandardCharsets
66
import java.sql.DriverManager
77

8+
import caseapp.CaseApp
89
import org.scalatest.FunSuite
910

1011
class CodegenTest extends FunSuite {
@@ -14,14 +15,24 @@ class CodegenTest extends FunSuite {
1415
code.parse[Source].get.structure
1516
}
1617

18+
test("--type-map") {
19+
val obtained =
20+
CaseApp.parse[CodegenOptions](
21+
Seq("--type-map", "numeric,BigDecimal;int8,Long"))
22+
val expected = Right(
23+
(CodegenOptions(
24+
typeMap = TypeMap("numeric" -> "BigDecimal", "int8" -> "Long")),
25+
Seq.empty[String]))
26+
assert(obtained === expected)
27+
}
28+
1729
test("testMain") {
1830
val options = CodegenOptions(
1931
`package` = "my.custom"
2032
)
2133
Class.forName(options.jdbcDriver)
2234
val conn =
23-
DriverManager
24-
.getConnection(options.url, options.username, options.password)
35+
DriverManager.getConnection(options.url, options.user, options.password)
2536
val stmt = conn.createStatement()
2637
val sql =
2738
"""

0 commit comments

Comments
 (0)