From 72b88b402c89ef9b96e63bd0a789e9f9664d179c Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Sat, 16 May 2020 18:53:26 +0200 Subject: [PATCH 01/29] WIP --- .../kotlin/com/zynger/floorplan/Dbml2Viz.kt | 73 +++++++++++++++++++ plan.md | 8 ++ 2 files changed, 81 insertions(+) create mode 100644 floorplan-cli/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt create mode 100644 plan.md diff --git a/floorplan-cli/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt b/floorplan-cli/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt new file mode 100644 index 0000000..bb16b9f --- /dev/null +++ b/floorplan-cli/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt @@ -0,0 +1,73 @@ +package com.zynger.floorplan + +import java.io.File + +data class Index(val name: String, val columnNames: List? = null, val unique: Boolean = false){ + // TODO should we enforce column names? + //(urn) [name:'index_TimeToLives_urn', unique] +} +data class Column(val name: String, val type: String, val note: String? = null, val primaryKey: Boolean = false) { + // address varchar(255) [unique, not null, note: 'to include unit number'] +} +data class Table(val name: String, val columns: List, val indexes: List = emptyList()) + +fun main() { +// val src = File("samples/dbml/single-table.dbml") +// src.readLines().forEach { println(it) } + + val table1 = Table( + "TimeToLives", + listOf( + Column("urn", "varchar"), + Column("expireAt", "int"), + Column("id", "int", primaryKey = true) + ), + listOf( + Index("index_TimeToLives_urn", listOf("urn"), unique = true) + ) + ) + val tables = listOf(table1) + + println( + """ + digraph { + graph [pad="0.5", nodesep="0.5", ranksep="2"]; + node [shape=plain]; + rankdir=LR; + """.trimIndent() + ) + println() + + tables.forEach { println(it.render()) } + + println() + println("}") +} + +private fun Table.render(): String { + return buildString { + appendln("$name [label=<") + appendln("") + appendln("") + columns.forEach { + append("") + } + if (!indexes.isEmpty()) { + appendln("") + indexes.forEach { index -> + append("") + } + } + append("
$name
") + if (it.primaryKey) { + append("") + } + append("${it.name}: ${it.type}") + if (it.primaryKey) { + append("") + } + appendln("
Indices
") + append(index.name) + appendln("
>];") + } +} diff --git a/plan.md b/plan.md new file mode 100644 index 0000000..6231083 --- /dev/null +++ b/plan.md @@ -0,0 +1,8 @@ +Convert the output of FloorPlan (DBML) to GraphViz () input format, a .gv file. +Once with that, we can generate an SVG for the ER diagram with +``` +dot input.gv -Tsvg -o out.svg +``` +And plot it into a mkdocs or another markdown viewer (like github). + +Source blog: https://spin.atomicobject.com/2017/11/15/table-rel-diagrams-graphviz/ From 475644c5900f0ca8ca22ab58eba7ded539a15962 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Sat, 16 May 2020 19:03:27 +0200 Subject: [PATCH 02/29] Add hacky prototype --- dbml2viz/build.gradle | 24 +++++++++++++++++++ .../kotlin/com/zynger/floorplan/Dbml2Viz.kt | 21 +++++++++++++++- settings.gradle | 1 + 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 dbml2viz/build.gradle rename {floorplan-cli => dbml2viz}/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt (75%) diff --git a/dbml2viz/build.gradle b/dbml2viz/build.gradle new file mode 100644 index 0000000..44cb10c --- /dev/null +++ b/dbml2viz/build.gradle @@ -0,0 +1,24 @@ +plugins { + id 'application' + id 'java' + id 'org.jetbrains.kotlin.jvm' +} + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() + jcenter() +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + testImplementation "junit:junit:4.12" +} + +compileKotlin { + kotlinOptions.jvmTarget = "1.8" +} +compileTestKotlin { + kotlinOptions.jvmTarget = "1.8" +} diff --git a/floorplan-cli/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt similarity index 75% rename from floorplan-cli/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt rename to dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt index bb16b9f..51321dc 100644 --- a/floorplan-cli/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt +++ b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt @@ -26,7 +26,26 @@ fun main() { Index("index_TimeToLives_urn", listOf("urn"), unique = true) ) ) - val tables = listOf(table1) + val table2 = Table( + "TrackPolicies", + listOf( + Column("id", "int", primaryKey = true), + Column("urn", "varchar"), + Column("monetizable", "int"), + Column("blocked", "int"), + Column("snipped", "int"), + Column("syncable", "int"), + Column("sub_mid_tier", "int"), + Column("sub_high_tier", "int"), + Column("policy", "varchar"), + Column("monetization_model", "varchar"), + Column("last_updated", "int") + ), + listOf( + Index("index_TrackPolicies_urn", listOf("urn"), unique = true) + ) + ) + val tables = listOf(table1, table2) println( """ diff --git a/settings.gradle b/settings.gradle index 01f1655..810d5b7 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,4 @@ rootProject.name = 'floorplan' include 'core' +include 'dbml2viz' include 'floorplan-cli' From f4270f8c9dd6c7525b8d573a660b49788428900e Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Sat, 16 May 2020 19:09:08 +0200 Subject: [PATCH 03/29] Pull out dbml-parser module --- dbml-parser/build.gradle | 23 +++++++++++++++++++ .../kotlin/com/zynger/floorplan/Column.kt | 10 ++++++++ .../main/kotlin/com/zynger/floorplan/Index.kt | 6 +++++ .../main/kotlin/com/zynger/floorplan/Table.kt | 7 ++++++ dbml2viz/build.gradle | 1 + .../kotlin/com/zynger/floorplan/Dbml2Viz.kt | 9 -------- settings.gradle | 1 + 7 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 dbml-parser/build.gradle create mode 100644 dbml-parser/src/main/kotlin/com/zynger/floorplan/Column.kt create mode 100644 dbml-parser/src/main/kotlin/com/zynger/floorplan/Index.kt create mode 100644 dbml-parser/src/main/kotlin/com/zynger/floorplan/Table.kt diff --git a/dbml-parser/build.gradle b/dbml-parser/build.gradle new file mode 100644 index 0000000..ce06f61 --- /dev/null +++ b/dbml-parser/build.gradle @@ -0,0 +1,23 @@ +plugins { + id 'java' + id 'org.jetbrains.kotlin.jvm' +} + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() + jcenter() +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + testImplementation "junit:junit:4.12" +} + +compileKotlin { + kotlinOptions.jvmTarget = "1.8" +} +compileTestKotlin { + kotlinOptions.jvmTarget = "1.8" +} diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Column.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Column.kt new file mode 100644 index 0000000..747a1af --- /dev/null +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Column.kt @@ -0,0 +1,10 @@ +package com.zynger.floorplan + +data class Column( + val name: String, + val type: String, + val note: String? = null, + val primaryKey: Boolean = false +) { + // address varchar(255) [unique, not null, note: 'to include unit number'] +} \ No newline at end of file diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Index.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Index.kt new file mode 100644 index 0000000..1cda27d --- /dev/null +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Index.kt @@ -0,0 +1,6 @@ +package com.zynger.floorplan + +data class Index(val name: String, val columnNames: List? = null, val unique: Boolean = false){ + // TODO should we enforce column names? + //(urn) [name:'index_TimeToLives_urn', unique] +} diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Table.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Table.kt new file mode 100644 index 0000000..4de9604 --- /dev/null +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Table.kt @@ -0,0 +1,7 @@ +package com.zynger.floorplan + +data class Table( + val name: String, + val columns: List, + val indexes: List = emptyList() +) \ No newline at end of file diff --git a/dbml2viz/build.gradle b/dbml2viz/build.gradle index 44cb10c..9bde86c 100644 --- a/dbml2viz/build.gradle +++ b/dbml2viz/build.gradle @@ -13,6 +13,7 @@ repositories { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + implementation project(":dbml-parser") testImplementation "junit:junit:4.12" } diff --git a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt index 51321dc..57fd372 100644 --- a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt +++ b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt @@ -2,15 +2,6 @@ package com.zynger.floorplan import java.io.File -data class Index(val name: String, val columnNames: List? = null, val unique: Boolean = false){ - // TODO should we enforce column names? - //(urn) [name:'index_TimeToLives_urn', unique] -} -data class Column(val name: String, val type: String, val note: String? = null, val primaryKey: Boolean = false) { - // address varchar(255) [unique, not null, note: 'to include unit number'] -} -data class Table(val name: String, val columns: List, val indexes: List = emptyList()) - fun main() { // val src = File("samples/dbml/single-table.dbml") // src.readLines().forEach { println(it) } diff --git a/settings.gradle b/settings.gradle index 810d5b7..a8f9af4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,5 @@ rootProject.name = 'floorplan' include 'core' +include 'dbml-parser' include 'dbml2viz' include 'floorplan-cli' From b2b7fe6076a3b05c3ebad324e141e30ec643c555 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Sat, 16 May 2020 19:15:49 +0200 Subject: [PATCH 04/29] Specify main class --- dbml2viz/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dbml2viz/build.gradle b/dbml2viz/build.gradle index 9bde86c..cb57e45 100644 --- a/dbml2viz/build.gradle +++ b/dbml2viz/build.gradle @@ -11,6 +11,10 @@ repositories { jcenter() } +application { + mainClassName = "com.zynger.floorplan.Dbml2VizKt" +} + dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" implementation project(":dbml-parser") From acf0f4e81e516bc1ff730159478c1f03a7104a61 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Sat, 16 May 2020 19:26:40 +0200 Subject: [PATCH 05/29] Render references --- .../kotlin/com/zynger/floorplan/Reference.kt | 15 ++++++++++++ .../kotlin/com/zynger/floorplan/Dbml2Viz.kt | 23 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt new file mode 100644 index 0000000..cddb664 --- /dev/null +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt @@ -0,0 +1,15 @@ +package com.zynger.floorplan + +// Ref: trending_shows.show_id - shows.id [delete: cascade, update: cascade] +data class Reference( + val fromTable: String, + val fromColumn: String, + val toTable: String, + val toColumn: String, + val referenceOrder: ReferenceOrder = ReferenceOrder.OneToOne // TODO adjust later to parse ref. order +) + +enum class ReferenceOrder { + // > many-to-one; < one-to-many; - one-to-one + OneToOne, OneToMany, ManyToOne +} diff --git a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt index 57fd372..76a3929 100644 --- a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt +++ b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt @@ -36,7 +36,16 @@ fun main() { Index("index_TrackPolicies_urn", listOf("urn"), unique = true) ) ) + + val reference1 = Reference( + fromTable = "TrackPolicies", + fromColumn = "urn", + toTable = "TimeToLives", + toColumn = "urn" + ) + val tables = listOf(table1, table2) + val references = listOf(reference1) println( """ @@ -51,9 +60,23 @@ fun main() { tables.forEach { println(it.render()) } println() + references.forEach { println(it.render()) } + println("}") } +private fun Reference.render(): String { + // Foo:2 -> Baz:a [taillabel="a to b" labeltooltip="this is a tooltip"]; + return "$fromTable:$fromColumn -> $toTable:$toColumn [label=\"${referenceOrder.label}\"]" +} + +private val ReferenceOrder.label: String + get() = when (this) { + ReferenceOrder.OneToOne -> "1-1" + ReferenceOrder.OneToMany -> "1-*" + ReferenceOrder.ManyToOne -> "*-*" + } + private fun Table.render(): String { return buildString { appendln("$name [label=<") From f1087deb2b8b8697f2579ec9cb2c5d8f578bc6b2 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Sun, 17 May 2020 19:33:59 +0200 Subject: [PATCH 06/29] Parse references --- .../kotlin/com/zynger/floorplan/Parser.kt | 23 +++++++++++++++++++ .../kotlin/com/zynger/floorplan/Reference.kt | 14 ++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt new file mode 100644 index 0000000..8e9813c --- /dev/null +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt @@ -0,0 +1,23 @@ +package com.zynger.floorplan + +class Parser { + + fun parse(dbmlInput: String) { + val tableMatches = TABLE_REGEX.findAll(dbmlInput).toList() + + val references = REFERENCE_REGEX.findAll(dbmlInput).map { + Reference( + fromTable = it.groups[1]!!.value, + fromColumn = it.groups[2]!!.value, + toTable = it.groups[4]!!.value, + toColumn = it.groups[5]!!.value, + referenceOrder = ReferenceOrder.fromString(it.groups[3]!!.value) + ) + }.toList() + } + + companion object { + private val TABLE_REGEX = Regex("""[Tt]able\s+(."\w+"|\w+.)\s*(\s*as\s+[\w]+|\s*as\s+"[\w]+"|)(\s\[.*]|)\s*\{(\s|\n|[^}]*)}""") + private val REFERENCE_REGEX = Regex("""[Rr]ef:\s*("\w+"|\w+)\.("\w+"|\w+)\s+([-<>])\s+("\w+"|\w+)\.("\w+"|\w+)""") + } +} diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt index cddb664..ef5f82a 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt @@ -1,5 +1,7 @@ package com.zynger.floorplan +import java.lang.IllegalArgumentException + // Ref: trending_shows.show_id - shows.id [delete: cascade, update: cascade] data class Reference( val fromTable: String, @@ -11,5 +13,15 @@ data class Reference( enum class ReferenceOrder { // > many-to-one; < one-to-many; - one-to-one - OneToOne, OneToMany, ManyToOne + OneToOne, OneToMany, ManyToOne; + companion object { + fun fromString(str: String): ReferenceOrder { + return when (str.trim()) { + "-" -> OneToOne + ">" -> ManyToOne + "<" -> OneToMany + else -> throw IllegalArgumentException("Could not parse $str as reference order.") + } + } + } } From 2530d554a3b4986e6d8bca7edb29df10d5aee99f Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Sun, 17 May 2020 19:35:35 +0200 Subject: [PATCH 07/29] Add raw value captured from parser --- dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt | 5 +++-- .../src/main/kotlin/com/zynger/floorplan/Reference.kt | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt index 8e9813c..0c22299 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt @@ -7,11 +7,12 @@ class Parser { val references = REFERENCE_REGEX.findAll(dbmlInput).map { Reference( + rawValue = it.groups[0]!!.value, fromTable = it.groups[1]!!.value, fromColumn = it.groups[2]!!.value, + referenceOrder = ReferenceOrder.fromString(it.groups[3]!!.value), toTable = it.groups[4]!!.value, - toColumn = it.groups[5]!!.value, - referenceOrder = ReferenceOrder.fromString(it.groups[3]!!.value) + toColumn = it.groups[5]!!.value ) }.toList() } diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt index ef5f82a..bb5b12d 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt @@ -4,6 +4,7 @@ import java.lang.IllegalArgumentException // Ref: trending_shows.show_id - shows.id [delete: cascade, update: cascade] data class Reference( + val rawValue: String, val fromTable: String, val fromColumn: String, val toTable: String, From b3f34baca3c5bfa2dec058a9bb25e2531322f143 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Sun, 17 May 2020 19:39:44 +0200 Subject: [PATCH 08/29] Parse tables - no columns or indexes --- .../src/main/kotlin/com/zynger/floorplan/Parser.kt | 9 ++++++++- .../src/main/kotlin/com/zynger/floorplan/Table.kt | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt index 0c22299..3e9cf79 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt @@ -3,7 +3,14 @@ package com.zynger.floorplan class Parser { fun parse(dbmlInput: String) { - val tableMatches = TABLE_REGEX.findAll(dbmlInput).toList() + val tables = TABLE_REGEX.findAll(dbmlInput).map { + Table( + rawValue = it.groups[0]!!.value, + name = it.groups[1]!!.value.trim(), + columns = emptyList(), + indexes = emptyList() + ) + }.toList() val references = REFERENCE_REGEX.findAll(dbmlInput).map { Reference( diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Table.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Table.kt index 4de9604..f4dcece 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Table.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Table.kt @@ -1,6 +1,7 @@ package com.zynger.floorplan data class Table( + val rawValue: String, val name: String, val columns: List, val indexes: List = emptyList() From 64d3031f7505191dc8cf8815ad93624816e8e034 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Sun, 17 May 2020 21:32:58 +0200 Subject: [PATCH 09/29] Add Project definition and cleanup app run --- .../kotlin/com/zynger/floorplan/Column.kt | 8 +- .../kotlin/com/zynger/floorplan/Parser.kt | 76 ++++++++++++++--- .../kotlin/com/zynger/floorplan/Project.kt | 6 ++ .../kotlin/com/zynger/floorplan/Dbml2Viz.kt | 81 +++++++++---------- 4 files changed, 115 insertions(+), 56 deletions(-) create mode 100644 dbml-parser/src/main/kotlin/com/zynger/floorplan/Project.kt diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Column.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Column.kt index 747a1af..6b0a046 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Column.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Column.kt @@ -1,10 +1,14 @@ package com.zynger.floorplan data class Column( + val rawValue: String, val name: String, val type: String, val note: String? = null, - val primaryKey: Boolean = false + val primaryKey: Boolean = false, + val notNull: Boolean = false, + val increment: Boolean = false, + val reference: Reference? = null // not null when this column references another through a column attribute ) { - // address varchar(255) [unique, not null, note: 'to include unit number'] + // example column: address varchar(255) [unique, not null, note: 'to include unit number'] } \ No newline at end of file diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt index 3e9cf79..3294d5f 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt @@ -1,18 +1,77 @@ package com.zynger.floorplan -class Parser { +object Parser { - fun parse(dbmlInput: String) { - val tables = TABLE_REGEX.findAll(dbmlInput).map { + private val TABLE_REGEX = Regex("""[Tt]able\s+(."\w+"|\w+.)\s*(\s*as\s+[\w]+|\s*as\s+"[\w]+"|)(\s\[.*]|)\s*\{(\s|\n|[^}]*)}""") + private val REFERENCE_REGEX = Regex("""[Rr]ef:\s*("\w+"|\w+)\.("\w+"|\w+)\s+([-<>])\s+("\w+"|\w+)\.("\w+"|\w+)""") + private val COLUMN_REGEX = Regex("""("\w+"|\w+)+\s+("\w+"|\w+)(\s+\[[^]]*]|)[ ]*\n""") + private val COLUMN_REFERENCE_REGEX = Regex("""((ref)\s*:\s*([<>-])\s*("\w+"|\w+)\.("\w+"|\w+))""") + + fun parse(dbmlInput: String): Project { + val tables = parseTables(dbmlInput) + val columnReferences = tables.map { it.columns }.flatten().mapNotNull { it.reference } + val references = parseReferences(dbmlInput) + columnReferences + return Project(tables, references) + } + + private fun parseTables(dbmlInput: String): List { + // TODO: aliases and table notes also get parsed; should we update the modeling to include them? + + return TABLE_REGEX.findAll(dbmlInput).map { + val tableName = it.groups[1]!!.value.trim() + val tableContent = it.groups[4]!!.value.run { + // TODO BUG, hack: the TABLE_REGEX doesn't take in account the Indexes block properly + val indexesMatchResult = Regex("""Indexes\s+\{""").find(this) + if (indexesMatchResult != null) { + this.substringBefore(indexesMatchResult.value) + } else { + this + } + } Table( rawValue = it.groups[0]!!.value, - name = it.groups[1]!!.value.trim(), - columns = emptyList(), + name = tableName, + columns = parseColumns(tableName, tableContent), indexes = emptyList() ) }.toList() + } + + private fun parseColumns(tableName: String, columnsInput: String): List { + return COLUMN_REGEX.findAll(columnsInput).map { + val rawValue = it.groups[0]!!.value + val name = it.groups[1]!!.value + val type = it.groups[2]!!.value + val columnProperties = it.groups[3]!!.value.trim() + val notNull = columnProperties.contains("not null") + val pk = columnProperties.contains("pk") + val increment = columnProperties.contains("increment") + val reference: Reference? = if (COLUMN_REFERENCE_REGEX.containsMatchIn(columnProperties)) { + val referenceProperties = COLUMN_REFERENCE_REGEX.find(columnProperties)!! + Reference( + rawValue = referenceProperties.groups[0]!!.value, + fromTable = tableName, + fromColumn = name, + referenceOrder = ReferenceOrder.fromString(referenceProperties.groups[3]!!.value), + toTable = referenceProperties.groups[4]!!.value, + toColumn = referenceProperties.groups[5]!!.value + ) + } else null + + Column( + rawValue = rawValue, + name = name, + type = type, + primaryKey = pk, + notNull = notNull, + increment = increment, + reference = reference + ) + }.toList() + } - val references = REFERENCE_REGEX.findAll(dbmlInput).map { + private fun parseReferences(dbmlInput: String): List { + return REFERENCE_REGEX.findAll(dbmlInput).map { Reference( rawValue = it.groups[0]!!.value, fromTable = it.groups[1]!!.value, @@ -23,9 +82,4 @@ class Parser { ) }.toList() } - - companion object { - private val TABLE_REGEX = Regex("""[Tt]able\s+(."\w+"|\w+.)\s*(\s*as\s+[\w]+|\s*as\s+"[\w]+"|)(\s\[.*]|)\s*\{(\s|\n|[^}]*)}""") - private val REFERENCE_REGEX = Regex("""[Rr]ef:\s*("\w+"|\w+)\.("\w+"|\w+)\s+([-<>])\s+("\w+"|\w+)\.("\w+"|\w+)""") - } } diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Project.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Project.kt new file mode 100644 index 0000000..928fef0 --- /dev/null +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Project.kt @@ -0,0 +1,6 @@ +package com.zynger.floorplan + +data class Project( + val tables: List
, + val reference: List +) diff --git a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt index 76a3929..8313d45 100644 --- a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt +++ b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt @@ -3,49 +3,11 @@ package com.zynger.floorplan import java.io.File fun main() { -// val src = File("samples/dbml/single-table.dbml") -// src.readLines().forEach { println(it) } - - val table1 = Table( - "TimeToLives", - listOf( - Column("urn", "varchar"), - Column("expireAt", "int"), - Column("id", "int", primaryKey = true) - ), - listOf( - Index("index_TimeToLives_urn", listOf("urn"), unique = true) - ) - ) - val table2 = Table( - "TrackPolicies", - listOf( - Column("id", "int", primaryKey = true), - Column("urn", "varchar"), - Column("monetizable", "int"), - Column("blocked", "int"), - Column("snipped", "int"), - Column("syncable", "int"), - Column("sub_mid_tier", "int"), - Column("sub_high_tier", "int"), - Column("policy", "varchar"), - Column("monetization_model", "varchar"), - Column("last_updated", "int") - ), - listOf( - Index("index_TrackPolicies_urn", listOf("urn"), unique = true) - ) - ) - - val reference1 = Reference( - fromTable = "TrackPolicies", - fromColumn = "urn", - toTable = "TimeToLives", - toColumn = "urn" - ) - - val tables = listOf(table1, table2) - val references = listOf(reference1) + val src = sample() +// val src = File("samples/dbml/db-track-pol.dbml").readText() + val project = Parser.parse(src) + val tables = project.tables + val references = project.reference println( """ @@ -104,3 +66,36 @@ private fun Table.render(): String { append("
>];") } } + +fun sample(): String { + return """ +Table posts { + id int [pk, increment] + title varchar [not null] +} + +table comments { + id int [pk,increment] + comment varchar + post_id int [not null,ref: > posts.id] +} +table tags as aliasForTagsTable{ + id int [pk, increment, not null] + title varchar [not null] +} + +table post_tags [note: 'hey table note']{ + id int [pk] + post_id int + tag_id int +} + + + + +Ref: "tags"."id" < "post_tags"."tag_id" + +Ref: "posts"."id" < "post_tags"."post_id" +Ref: "posts"."id" - "post_tags"."post_id" + """.trimIndent() +} \ No newline at end of file From e7388237bfcc4a4f75e2d7a405880115ade00618 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Sun, 17 May 2020 21:33:30 +0200 Subject: [PATCH 10/29] Add TODO --- dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt index 8313d45..468c6ab 100644 --- a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt +++ b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt @@ -9,6 +9,8 @@ fun main() { val tables = project.tables val references = project.reference + // TODO write to .gv file instead of stdout + println( """ digraph { From d90792db6f9b54d91bca2d2c9cda929aba10a905 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Sun, 17 May 2020 21:40:07 +0200 Subject: [PATCH 11/29] Add TODO --- dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt | 2 +- dbml-parser/src/main/kotlin/com/zynger/floorplan/Table.kt | 2 +- dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt index 3294d5f..271cc92 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt @@ -32,7 +32,7 @@ object Parser { rawValue = it.groups[0]!!.value, name = tableName, columns = parseColumns(tableName, tableContent), - indexes = emptyList() + indexes = emptyList() // TODO include indexes parsing ) }.toList() } diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Table.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Table.kt index f4dcece..92f440c 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Table.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Table.kt @@ -5,4 +5,4 @@ data class Table( val name: String, val columns: List, val indexes: List = emptyList() -) \ No newline at end of file +) diff --git a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt index 468c6ab..bc5b97c 100644 --- a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt +++ b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt @@ -10,7 +10,7 @@ fun main() { val references = project.reference // TODO write to .gv file instead of stdout - + println( """ digraph { From 25b3a9ec915d751e816b3db37b4bfa793fca3bf8 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Mon, 18 May 2020 11:31:27 +0200 Subject: [PATCH 12/29] Extract objects --- .../kotlin/com/zynger/floorplan/Parser.kt | 80 ++----------------- .../com/zynger/floorplan/lex/ColumnParser.kt | 43 ++++++++++ .../zynger/floorplan/lex/ReferenceParser.kt | 21 +++++ .../com/zynger/floorplan/lex/TableParser.kt | 30 +++++++ 4 files changed, 99 insertions(+), 75 deletions(-) create mode 100644 dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt create mode 100644 dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ReferenceParser.kt create mode 100644 dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/TableParser.kt diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt index 271cc92..2c8a5e5 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt @@ -1,85 +1,15 @@ package com.zynger.floorplan -object Parser { +import com.zynger.floorplan.lex.ReferenceParser +import com.zynger.floorplan.lex.TableParser - private val TABLE_REGEX = Regex("""[Tt]able\s+(."\w+"|\w+.)\s*(\s*as\s+[\w]+|\s*as\s+"[\w]+"|)(\s\[.*]|)\s*\{(\s|\n|[^}]*)}""") - private val REFERENCE_REGEX = Regex("""[Rr]ef:\s*("\w+"|\w+)\.("\w+"|\w+)\s+([-<>])\s+("\w+"|\w+)\.("\w+"|\w+)""") - private val COLUMN_REGEX = Regex("""("\w+"|\w+)+\s+("\w+"|\w+)(\s+\[[^]]*]|)[ ]*\n""") - private val COLUMN_REFERENCE_REGEX = Regex("""((ref)\s*:\s*([<>-])\s*("\w+"|\w+)\.("\w+"|\w+))""") +object Parser { fun parse(dbmlInput: String): Project { - val tables = parseTables(dbmlInput) + val tables = TableParser.parseTables(dbmlInput) val columnReferences = tables.map { it.columns }.flatten().mapNotNull { it.reference } - val references = parseReferences(dbmlInput) + columnReferences + val references = ReferenceParser.parseReferences(dbmlInput) + columnReferences return Project(tables, references) } - private fun parseTables(dbmlInput: String): List { - // TODO: aliases and table notes also get parsed; should we update the modeling to include them? - - return TABLE_REGEX.findAll(dbmlInput).map { - val tableName = it.groups[1]!!.value.trim() - val tableContent = it.groups[4]!!.value.run { - // TODO BUG, hack: the TABLE_REGEX doesn't take in account the Indexes block properly - val indexesMatchResult = Regex("""Indexes\s+\{""").find(this) - if (indexesMatchResult != null) { - this.substringBefore(indexesMatchResult.value) - } else { - this - } - } - Table( - rawValue = it.groups[0]!!.value, - name = tableName, - columns = parseColumns(tableName, tableContent), - indexes = emptyList() // TODO include indexes parsing - ) - }.toList() - } - - private fun parseColumns(tableName: String, columnsInput: String): List { - return COLUMN_REGEX.findAll(columnsInput).map { - val rawValue = it.groups[0]!!.value - val name = it.groups[1]!!.value - val type = it.groups[2]!!.value - val columnProperties = it.groups[3]!!.value.trim() - val notNull = columnProperties.contains("not null") - val pk = columnProperties.contains("pk") - val increment = columnProperties.contains("increment") - val reference: Reference? = if (COLUMN_REFERENCE_REGEX.containsMatchIn(columnProperties)) { - val referenceProperties = COLUMN_REFERENCE_REGEX.find(columnProperties)!! - Reference( - rawValue = referenceProperties.groups[0]!!.value, - fromTable = tableName, - fromColumn = name, - referenceOrder = ReferenceOrder.fromString(referenceProperties.groups[3]!!.value), - toTable = referenceProperties.groups[4]!!.value, - toColumn = referenceProperties.groups[5]!!.value - ) - } else null - - Column( - rawValue = rawValue, - name = name, - type = type, - primaryKey = pk, - notNull = notNull, - increment = increment, - reference = reference - ) - }.toList() - } - - private fun parseReferences(dbmlInput: String): List { - return REFERENCE_REGEX.findAll(dbmlInput).map { - Reference( - rawValue = it.groups[0]!!.value, - fromTable = it.groups[1]!!.value, - fromColumn = it.groups[2]!!.value, - referenceOrder = ReferenceOrder.fromString(it.groups[3]!!.value), - toTable = it.groups[4]!!.value, - toColumn = it.groups[5]!!.value - ) - }.toList() - } } diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt new file mode 100644 index 0000000..5e21e1d --- /dev/null +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt @@ -0,0 +1,43 @@ +package com.zynger.floorplan.lex + +import com.zynger.floorplan.Column +import com.zynger.floorplan.Reference +import com.zynger.floorplan.ReferenceOrder + +object ColumnParser { + private val COLUMN_REGEX = Regex("""("\w+"|\w+)+\s+("\w+"|\w+)(\s+\[[^]]*]|)[ ]*\n""") + private val COLUMN_REFERENCE_REGEX = Regex("""((ref)\s*:\s*([<>-])\s*("\w+"|\w+)\.("\w+"|\w+))""") + + fun parseColumns(tableName: String, columnsInput: String): List { + return COLUMN_REGEX.findAll(columnsInput).map { + val rawValue = it.groups[0]!!.value + val name = it.groups[1]!!.value + val type = it.groups[2]!!.value + val columnProperties = it.groups[3]!!.value.trim() + val notNull = columnProperties.contains("not null") + val pk = columnProperties.contains("pk") + val increment = columnProperties.contains("increment") + val reference: Reference? = if (COLUMN_REFERENCE_REGEX.containsMatchIn(columnProperties)) { + val referenceProperties = COLUMN_REFERENCE_REGEX.find(columnProperties)!! + Reference( + rawValue = referenceProperties.groups[0]!!.value, + fromTable = tableName, + fromColumn = name, + referenceOrder = ReferenceOrder.fromString(referenceProperties.groups[3]!!.value), + toTable = referenceProperties.groups[4]!!.value, + toColumn = referenceProperties.groups[5]!!.value + ) + } else null + + Column( + rawValue = rawValue, + name = name, + type = type, + primaryKey = pk, + notNull = notNull, + increment = increment, + reference = reference + ) + }.toList() + } +} diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ReferenceParser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ReferenceParser.kt new file mode 100644 index 0000000..17d2fda --- /dev/null +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ReferenceParser.kt @@ -0,0 +1,21 @@ +package com.zynger.floorplan.lex + +import com.zynger.floorplan.Reference +import com.zynger.floorplan.ReferenceOrder + +object ReferenceParser { + private val REFERENCE_REGEX = Regex("""[Rr]ef:\s*("\w+"|\w+)\.("\w+"|\w+)\s+([-<>])\s+("\w+"|\w+)\.("\w+"|\w+)""") + + fun parseReferences(dbmlInput: String): List { + return REFERENCE_REGEX.findAll(dbmlInput).map { + Reference( + rawValue = it.groups[0]!!.value, + fromTable = it.groups[1]!!.value, + fromColumn = it.groups[2]!!.value, + referenceOrder = ReferenceOrder.fromString(it.groups[3]!!.value), + toTable = it.groups[4]!!.value, + toColumn = it.groups[5]!!.value + ) + }.toList() + } +} diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/TableParser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/TableParser.kt new file mode 100644 index 0000000..0b5d0e4 --- /dev/null +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/TableParser.kt @@ -0,0 +1,30 @@ +package com.zynger.floorplan.lex + +import com.zynger.floorplan.Table + +object TableParser { + private val TABLE_REGEX = Regex("""[Tt]able\s+(."\w+"|\w+.)\s*(\s*as\s+[\w]+|\s*as\s+"[\w]+"|)(\s\[.*]|)\s*\{(\s|\n|[^}]*)}""") + + fun parseTables(dbmlInput: String): List
{ + // TODO: aliases and table notes also get parsed; should we update the modeling to include them? + + return TABLE_REGEX.findAll(dbmlInput).map { + val tableName = it.groups[1]!!.value.trim() + val tableContent = it.groups[4]!!.value.run { + // TODO BUG, hack: the TABLE_REGEX doesn't take in account the Indexes block properly + val indexesMatchResult = Regex("""Indexes\s+\{""").find(this) + if (indexesMatchResult != null) { + this.substringBefore(indexesMatchResult.value) + } else { + this + } + } + Table( + rawValue = it.groups[0]!!.value, + name = tableName, + columns = ColumnParser.parseColumns(tableName, tableContent), + indexes = emptyList() // TODO include indexes parsing + ) + }.toList() + } +} \ No newline at end of file From d93f2d385f7c4bf80e01ddd75021948e201b0f0f Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Mon, 18 May 2020 11:48:07 +0200 Subject: [PATCH 13/29] Add test for LoneReference parser --- .../kotlin/com/zynger/floorplan/Parser.kt | 4 +- ...erenceParser.kt => LoneReferenceParser.kt} | 14 +- .../floorplan/lex/LoneReferenceParserTest.kt | 208 ++++++++++++++++++ 3 files changed, 219 insertions(+), 7 deletions(-) rename dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/{ReferenceParser.kt => LoneReferenceParser.kt} (56%) create mode 100644 dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/LoneReferenceParserTest.kt diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt index 2c8a5e5..cd873b8 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt @@ -1,6 +1,6 @@ package com.zynger.floorplan -import com.zynger.floorplan.lex.ReferenceParser +import com.zynger.floorplan.lex.LoneReferenceParser import com.zynger.floorplan.lex.TableParser object Parser { @@ -8,7 +8,7 @@ object Parser { fun parse(dbmlInput: String): Project { val tables = TableParser.parseTables(dbmlInput) val columnReferences = tables.map { it.columns }.flatten().mapNotNull { it.reference } - val references = ReferenceParser.parseReferences(dbmlInput) + columnReferences + val references = LoneReferenceParser.parseReferences(dbmlInput) + columnReferences return Project(tables, references) } diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ReferenceParser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/LoneReferenceParser.kt similarity index 56% rename from dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ReferenceParser.kt rename to dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/LoneReferenceParser.kt index 17d2fda..efddbaf 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ReferenceParser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/LoneReferenceParser.kt @@ -3,19 +3,23 @@ package com.zynger.floorplan.lex import com.zynger.floorplan.Reference import com.zynger.floorplan.ReferenceOrder -object ReferenceParser { +object LoneReferenceParser { private val REFERENCE_REGEX = Regex("""[Rr]ef:\s*("\w+"|\w+)\.("\w+"|\w+)\s+([-<>])\s+("\w+"|\w+)\.("\w+"|\w+)""") fun parseReferences(dbmlInput: String): List { return REFERENCE_REGEX.findAll(dbmlInput).map { Reference( rawValue = it.groups[0]!!.value, - fromTable = it.groups[1]!!.value, - fromColumn = it.groups[2]!!.value, + fromTable = it.groups[1]!!.value.removeSurroundQuotes(), + fromColumn = it.groups[2]!!.value.removeSurroundQuotes(), referenceOrder = ReferenceOrder.fromString(it.groups[3]!!.value), - toTable = it.groups[4]!!.value, - toColumn = it.groups[5]!!.value + toTable = it.groups[4]!!.value.removeSurroundQuotes(), + toColumn = it.groups[5]!!.value.removeSurroundQuotes() ) }.toList() } + + private fun String.removeSurroundQuotes(): String { + return this.removeSurrounding("\"") + } } diff --git a/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/LoneReferenceParserTest.kt b/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/LoneReferenceParserTest.kt new file mode 100644 index 0000000..4a30d63 --- /dev/null +++ b/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/LoneReferenceParserTest.kt @@ -0,0 +1,208 @@ +package com.zynger.floorplan.lex + +import com.zynger.floorplan.Reference +import com.zynger.floorplan.ReferenceOrder +import org.junit.Assert.assertEquals +import org.junit.Test + +class LoneReferenceParserTest { + + @Test + fun `when no references then empty list`() { + val input = """ + Table users { + id int [pk, increment] + } + """.trimIndent() + val references = LoneReferenceParser.parseReferences(input) + + assertEquals( + emptyList(), + references + ) + } + + @Test + fun `parses single lone reference with lowercase ref`() { + val referenceRawValue = "ref: posts.id - tags.post_id" + val input = """ + Table posts { + id int [pk, increment] + } + + Table tags { + id int [pk, increment] + post_id int + } + + $referenceRawValue + """.trimIndent() + val references = LoneReferenceParser.parseReferences(input) + + assertEquals( + listOf( + Reference( + referenceRawValue, + "posts", + "id", + "tags", + "post_id", + ReferenceOrder.OneToOne + ) + ), + references + ) + } + + @Test + fun `parses single lone reference with quotes surronding names`() { + val referenceRawValue = "Ref: \"posts\".id - tags.\"post_id\"" + val input = """ + Table posts { + id int [pk, increment] + } + + Table tags { + id int [pk, increment] + post_id int + } + + $referenceRawValue + """.trimIndent() + val references = LoneReferenceParser.parseReferences(input) + + assertEquals( + listOf( + Reference( + referenceRawValue, + "posts", + "id", + "tags", + "post_id", + ReferenceOrder.OneToOne + ) + ), + references + ) + } + + @Test + fun `parses single lone reference with one to one order`() { + val referenceRawValue = "Ref: posts.id - tags.post_id" + val input = """ + Table posts { + id int [pk, increment] + } + + Table tags { + id int [pk, increment] + post_id int + } + + $referenceRawValue + """.trimIndent() + val references = LoneReferenceParser.parseReferences(input) + + assertEquals( + listOf( + Reference( + referenceRawValue, + "posts", + "id", + "tags", + "post_id", + ReferenceOrder.OneToOne + ) + ), + references + ) + } + + @Test + fun `parses single lone reference with one to many order`() { + val referenceRawValue = "Ref: posts.id < tags.post_id" + val input = """ + Table posts { + id int [pk, increment] + } + + Table tags { + id int [pk, increment] + post_id int + } + + $referenceRawValue + """.trimIndent() + val references = LoneReferenceParser.parseReferences(input) + + assertEquals( + listOf( + Reference( + referenceRawValue, + "posts", + "id", + "tags", + "post_id", + ReferenceOrder.OneToMany + ) + ), + references + ) + } + + @Test + fun `parses single lone reference with many to one order`() { + val referenceRawValue = "Ref: posts.id > tags.post_id" + val input = """ + Table posts { + id int [pk, increment] + } + + Table tags { + id int [pk, increment] + post_id int + } + + $referenceRawValue + """.trimIndent() + val references = LoneReferenceParser.parseReferences(input) + + assertEquals( + listOf( + Reference( + referenceRawValue, + "posts", + "id", + "tags", + "post_id", + ReferenceOrder.ManyToOne + ) + ), + references + ) + } + + @Test + fun `parses multiple lone references`() { + val input = """ + Table posts { + id int [pk, increment] + } + + Table tags { + id int [pk, increment] + post_id int + } + + Table users { + id int [pk, increment] + } + + Ref: posts.id - tags.post_id + Ref: users.id - posts.id + """.trimIndent() + val references = LoneReferenceParser.parseReferences(input) + + assertEquals(2, references.size) + } +} \ No newline at end of file From 322e6a73b3ab9c5244b6145e5afc06ece95c3f11 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Mon, 18 May 2020 12:41:23 +0200 Subject: [PATCH 14/29] Remove plan file --- plan.md | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 plan.md diff --git a/plan.md b/plan.md deleted file mode 100644 index 6231083..0000000 --- a/plan.md +++ /dev/null @@ -1,8 +0,0 @@ -Convert the output of FloorPlan (DBML) to GraphViz () input format, a .gv file. -Once with that, we can generate an SVG for the ER diagram with -``` -dot input.gv -Tsvg -o out.svg -``` -And plot it into a mkdocs or another markdown viewer (like github). - -Source blog: https://spin.atomicobject.com/2017/11/15/table-rel-diagrams-graphviz/ From 8e2e39f7ff77546207190fcd463ab7443e4dee09 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Mon, 18 May 2020 12:42:47 +0200 Subject: [PATCH 15/29] Add test for reference notes --- .../floorplan/lex/LoneReferenceParserTest.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/LoneReferenceParserTest.kt b/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/LoneReferenceParserTest.kt index 4a30d63..929878d 100644 --- a/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/LoneReferenceParserTest.kt +++ b/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/LoneReferenceParserTest.kt @@ -205,4 +205,24 @@ class LoneReferenceParserTest { assertEquals(2, references.size) } + + @Test + fun `ignores reference notes`() { + val input = "Ref: trending_shows.show_id - shows.id [delete: cascade, update: cascade]" + val references = LoneReferenceParser.parseReferences(input) + + assertEquals( + listOf( + Reference( + "Ref: trending_shows.show_id - shows.id", + "trending_shows", + "show_id", + "shows", + "id", + ReferenceOrder.OneToOne + ) + ), + references + ) + } } \ No newline at end of file From 4451c69614a80ad6fe4c176da1b9764879b3f76f Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Mon, 18 May 2020 12:46:37 +0200 Subject: [PATCH 16/29] Pull out ColumnReferenceParser --- .../com/zynger/floorplan/lex/ColumnParser.kt | 14 +----------- .../floorplan/lex/ColumnReferenceParser.kt | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 13 deletions(-) create mode 100644 dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnReferenceParser.kt diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt index 5e21e1d..669a78e 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt @@ -2,11 +2,9 @@ package com.zynger.floorplan.lex import com.zynger.floorplan.Column import com.zynger.floorplan.Reference -import com.zynger.floorplan.ReferenceOrder object ColumnParser { private val COLUMN_REGEX = Regex("""("\w+"|\w+)+\s+("\w+"|\w+)(\s+\[[^]]*]|)[ ]*\n""") - private val COLUMN_REFERENCE_REGEX = Regex("""((ref)\s*:\s*([<>-])\s*("\w+"|\w+)\.("\w+"|\w+))""") fun parseColumns(tableName: String, columnsInput: String): List { return COLUMN_REGEX.findAll(columnsInput).map { @@ -17,17 +15,7 @@ object ColumnParser { val notNull = columnProperties.contains("not null") val pk = columnProperties.contains("pk") val increment = columnProperties.contains("increment") - val reference: Reference? = if (COLUMN_REFERENCE_REGEX.containsMatchIn(columnProperties)) { - val referenceProperties = COLUMN_REFERENCE_REGEX.find(columnProperties)!! - Reference( - rawValue = referenceProperties.groups[0]!!.value, - fromTable = tableName, - fromColumn = name, - referenceOrder = ReferenceOrder.fromString(referenceProperties.groups[3]!!.value), - toTable = referenceProperties.groups[4]!!.value, - toColumn = referenceProperties.groups[5]!!.value - ) - } else null + val reference: Reference? = ColumnReferenceParser.parse(tableName, name, columnProperties) Column( rawValue = rawValue, diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnReferenceParser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnReferenceParser.kt new file mode 100644 index 0000000..db67ee4 --- /dev/null +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnReferenceParser.kt @@ -0,0 +1,22 @@ +package com.zynger.floorplan.lex + +import com.zynger.floorplan.Reference +import com.zynger.floorplan.ReferenceOrder + +object ColumnReferenceParser { + private val COLUMN_REFERENCE_REGEX = Regex("""((ref)\s*:\s*([<>-])\s*("\w+"|\w+)\.("\w+"|\w+))""") + + fun parse(tableName: String, fromColumn: String, columnProperties: String): Reference? { + return if (COLUMN_REFERENCE_REGEX.containsMatchIn(columnProperties)) { + val referenceProperties = COLUMN_REFERENCE_REGEX.find(columnProperties)!! + Reference( + rawValue = referenceProperties.groups[0]!!.value, + fromTable = tableName, + fromColumn = fromColumn, + referenceOrder = ReferenceOrder.fromString(referenceProperties.groups[3]!!.value), + toTable = referenceProperties.groups[4]!!.value, + toColumn = referenceProperties.groups[5]!!.value + ) + } else null + } +} From 0f8165417996dbf05b63006cd74783ba8fa48467 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Mon, 18 May 2020 19:38:43 +0200 Subject: [PATCH 17/29] Simplify tests --- .../floorplan/lex/LoneReferenceParserTest.kt | 106 +++++------------- 1 file changed, 31 insertions(+), 75 deletions(-) diff --git a/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/LoneReferenceParserTest.kt b/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/LoneReferenceParserTest.kt index 929878d..b84906c 100644 --- a/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/LoneReferenceParserTest.kt +++ b/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/LoneReferenceParserTest.kt @@ -24,7 +24,6 @@ class LoneReferenceParserTest { @Test fun `parses single lone reference with lowercase ref`() { - val referenceRawValue = "ref: posts.id - tags.post_id" val input = """ Table posts { id int [pk, increment] @@ -35,28 +34,21 @@ class LoneReferenceParserTest { post_id int } - $referenceRawValue + ref: posts.id - tags.post_id """.trimIndent() val references = LoneReferenceParser.parseReferences(input) - assertEquals( - listOf( - Reference( - referenceRawValue, - "posts", - "id", - "tags", - "post_id", - ReferenceOrder.OneToOne - ) - ), - references - ) + assertEquals(1, references.size) + val reference = references.first() + assertEquals("posts", reference.fromTable) + assertEquals("id", reference.fromColumn) + assertEquals("tags", reference.toTable) + assertEquals("post_id", reference.toColumn) + assertEquals(ReferenceOrder.OneToOne, reference.referenceOrder) } @Test fun `parses single lone reference with quotes surronding names`() { - val referenceRawValue = "Ref: \"posts\".id - tags.\"post_id\"" val input = """ Table posts { id int [pk, increment] @@ -67,28 +59,21 @@ class LoneReferenceParserTest { post_id int } - $referenceRawValue + Ref: "posts".id - tags."post_id" """.trimIndent() val references = LoneReferenceParser.parseReferences(input) - assertEquals( - listOf( - Reference( - referenceRawValue, - "posts", - "id", - "tags", - "post_id", - ReferenceOrder.OneToOne - ) - ), - references - ) + assertEquals(1, references.size) + val reference = references.first() + assertEquals("posts", reference.fromTable) + assertEquals("id", reference.fromColumn) + assertEquals("tags", reference.toTable) + assertEquals("post_id", reference.toColumn) + assertEquals(ReferenceOrder.OneToOne, reference.referenceOrder) } @Test fun `parses single lone reference with one to one order`() { - val referenceRawValue = "Ref: posts.id - tags.post_id" val input = """ Table posts { id int [pk, increment] @@ -99,28 +84,18 @@ class LoneReferenceParserTest { post_id int } - $referenceRawValue + Ref: posts.id - tags.post_id """.trimIndent() + val references = LoneReferenceParser.parseReferences(input) - assertEquals( - listOf( - Reference( - referenceRawValue, - "posts", - "id", - "tags", - "post_id", - ReferenceOrder.OneToOne - ) - ), - references - ) + assertEquals(1, references.size) + val reference = references.first() + assertEquals(ReferenceOrder.OneToOne, reference.referenceOrder) } @Test fun `parses single lone reference with one to many order`() { - val referenceRawValue = "Ref: posts.id < tags.post_id" val input = """ Table posts { id int [pk, increment] @@ -131,28 +106,18 @@ class LoneReferenceParserTest { post_id int } - $referenceRawValue + Ref: posts.id < tags.post_id """.trimIndent() + val references = LoneReferenceParser.parseReferences(input) - assertEquals( - listOf( - Reference( - referenceRawValue, - "posts", - "id", - "tags", - "post_id", - ReferenceOrder.OneToMany - ) - ), - references - ) + assertEquals(1, references.size) + val reference = references.first() + assertEquals(ReferenceOrder.OneToMany, reference.referenceOrder) } @Test fun `parses single lone reference with many to one order`() { - val referenceRawValue = "Ref: posts.id > tags.post_id" val input = """ Table posts { id int [pk, increment] @@ -163,23 +128,14 @@ class LoneReferenceParserTest { post_id int } - $referenceRawValue + Ref: posts.id > tags.post_id """.trimIndent() + val references = LoneReferenceParser.parseReferences(input) - assertEquals( - listOf( - Reference( - referenceRawValue, - "posts", - "id", - "tags", - "post_id", - ReferenceOrder.ManyToOne - ) - ), - references - ) + assertEquals(1, references.size) + val reference = references.first() + assertEquals(ReferenceOrder.ManyToOne, reference.referenceOrder) } @Test From 7e709c1964b2526dcdbce6e330175adf7595fe12 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Mon, 18 May 2020 19:53:44 +0200 Subject: [PATCH 18/29] Cover ColumnReferenceParser with tests --- .../floorplan/lex/ColumnReferenceParser.kt | 14 +++-- .../lex/ColumnReferenceParserTest.kt | 61 +++++++++++++++++++ 2 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/ColumnReferenceParserTest.kt diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnReferenceParser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnReferenceParser.kt index db67ee4..a6ca541 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnReferenceParser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnReferenceParser.kt @@ -4,19 +4,23 @@ import com.zynger.floorplan.Reference import com.zynger.floorplan.ReferenceOrder object ColumnReferenceParser { - private val COLUMN_REFERENCE_REGEX = Regex("""((ref)\s*:\s*([<>-])\s*("\w+"|\w+)\.("\w+"|\w+))""") + private val COLUMN_REFERENCE_REGEX = Regex("""(([Rr]ef)\s*:\s*([<>-])\s*("\w+"|\w+)\.("\w+"|\w+))""") fun parse(tableName: String, fromColumn: String, columnProperties: String): Reference? { return if (COLUMN_REFERENCE_REGEX.containsMatchIn(columnProperties)) { val referenceProperties = COLUMN_REFERENCE_REGEX.find(columnProperties)!! Reference( rawValue = referenceProperties.groups[0]!!.value, - fromTable = tableName, - fromColumn = fromColumn, + fromTable = tableName.removeSurroundQuotes(), + fromColumn = fromColumn.removeSurroundQuotes(), referenceOrder = ReferenceOrder.fromString(referenceProperties.groups[3]!!.value), - toTable = referenceProperties.groups[4]!!.value, - toColumn = referenceProperties.groups[5]!!.value + toTable = referenceProperties.groups[4]!!.value.removeSurroundQuotes(), + toColumn = referenceProperties.groups[5]!!.value.removeSurroundQuotes() ) } else null } + + private fun String.removeSurroundQuotes(): String { + return this.removeSurrounding("\"") + } } diff --git a/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/ColumnReferenceParserTest.kt b/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/ColumnReferenceParserTest.kt new file mode 100644 index 0000000..6aba668 --- /dev/null +++ b/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/ColumnReferenceParserTest.kt @@ -0,0 +1,61 @@ +package com.zynger.floorplan.lex + +import com.zynger.floorplan.Reference +import com.zynger.floorplan.ReferenceOrder +import org.junit.Assert.assertEquals +import org.junit.Test + +class ColumnReferenceParserTest { + + companion object { + private const val TABLE_NAME = "myTable" + private const val FROM_COLUMN_NAME = "myColumn" + } + + @Test + fun `empty column notes` () { + val columnProperties = "" + val reference: Reference? = ColumnReferenceParser.parse(TABLE_NAME, FROM_COLUMN_NAME, columnProperties) + assertEquals(null, reference) + } + + @Test + fun `no reference column properties` () { + val columnProperties = "[note: 'not null']" + val reference: Reference? = ColumnReferenceParser.parse(TABLE_NAME, FROM_COLUMN_NAME, columnProperties) + assertEquals(null, reference) + } + + @Test + fun `irrelevant column properties` () { + val columnProperties = "[pk, increment, note: 'ref: something else']" + val reference: Reference? = ColumnReferenceParser.parse(TABLE_NAME, FROM_COLUMN_NAME, columnProperties) + assertEquals(null, reference) + } + + @Test + fun `parses reference`() { + val columnProperties = "post_id int [not null, Ref: - posts.id]" + val reference: Reference? = ColumnReferenceParser.parse(TABLE_NAME, FROM_COLUMN_NAME, columnProperties) + + reference!! + assertEquals(TABLE_NAME, reference.fromTable) + assertEquals(FROM_COLUMN_NAME, reference.fromColumn) + assertEquals("posts", reference.toTable) + assertEquals("id", reference.toColumn) + assertEquals(ReferenceOrder.OneToOne, reference.referenceOrder) + } + + @Test + fun `parses reference with quotes surronding names`() { + val columnProperties = "post_id int [not null, ref: > \"posts\".\"id\"]" + val reference: Reference? = ColumnReferenceParser.parse(TABLE_NAME, FROM_COLUMN_NAME, columnProperties) + + reference!! + assertEquals(TABLE_NAME, reference.fromTable) + assertEquals(FROM_COLUMN_NAME, reference.fromColumn) + assertEquals("posts", reference.toTable) + assertEquals("id", reference.toColumn) + assertEquals(ReferenceOrder.ManyToOne, reference.referenceOrder) + } +} From f9801be9450c1c5cd403ff6d9d2fb1b0b411fa57 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Mon, 18 May 2020 20:29:28 +0200 Subject: [PATCH 19/29] Tests for ColumnParser --- .../com/zynger/floorplan/lex/ColumnParser.kt | 8 +- .../zynger/floorplan/lex/ColumnParserTest.kt | 156 ++++++++++++++++++ 2 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/ColumnParserTest.kt diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt index 669a78e..615d0c2 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt @@ -6,10 +6,12 @@ import com.zynger.floorplan.Reference object ColumnParser { private val COLUMN_REGEX = Regex("""("\w+"|\w+)+\s+("\w+"|\w+)(\s+\[[^]]*]|)[ ]*\n""") + // TODO parse column default values + fun parseColumns(tableName: String, columnsInput: String): List { return COLUMN_REGEX.findAll(columnsInput).map { val rawValue = it.groups[0]!!.value - val name = it.groups[1]!!.value + val name = it.groups[1]!!.value.removeSurroundQuotes() val type = it.groups[2]!!.value val columnProperties = it.groups[3]!!.value.trim() val notNull = columnProperties.contains("not null") @@ -28,4 +30,8 @@ object ColumnParser { ) }.toList() } + + private fun String.removeSurroundQuotes(): String { + return this.removeSurrounding("\"") + } } diff --git a/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/ColumnParserTest.kt b/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/ColumnParserTest.kt new file mode 100644 index 0000000..9d0c6f9 --- /dev/null +++ b/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/ColumnParserTest.kt @@ -0,0 +1,156 @@ +package com.zynger.floorplan.lex + +import com.zynger.floorplan.Column +import org.junit.Assert.* +import org.junit.Test + +class ColumnParserTest { + + companion object { + private const val TABLE_NAME = "myTable" + } + + @Test + fun `empty columns`() { + val columnsInput = """ + """.trimIndent() + + val columns = ColumnParser.parseColumns(TABLE_NAME, columnsInput) + + assertEquals(emptyList(), columns) + } + + @Test + fun `parses name and type`() { + val columnsInput = """ + id int + name varchar + age int + customer bool + image blob + + """.trimIndent() + + val columns = ColumnParser.parseColumns(TABLE_NAME, columnsInput) + + assertEquals("id", columns[0].name) + assertEquals("int", columns[0].type) + + assertEquals("name", columns[1].name) + assertEquals("varchar", columns[1].type) + + assertEquals("age", columns[2].name) + assertEquals("int", columns[2].type) + + assertEquals("customer", columns[3].name) + assertEquals("bool", columns[3].type) + + assertEquals("image", columns[4].name) + assertEquals("blob", columns[4].type) + } + + @Test + fun `parses name without surrounding quotes`() { + val columnsInput = """ + "id" int + + """.trimIndent() + + val columns = ColumnParser.parseColumns(TABLE_NAME, columnsInput) + + assertEquals("id", columns[0].name) + assertEquals("int", columns[0].type) + } + + @Test + fun `parses primary key`() { + val columnsInput = """ + id int [pk] + + """.trimIndent() + + val columns = ColumnParser.parseColumns(TABLE_NAME, columnsInput) + + assertEquals(true, columns.first().primaryKey) + } + + @Test + fun `parses not null`() { + val columnsInput = """ + age int [not null] + + """.trimIndent() + + val columns = ColumnParser.parseColumns(TABLE_NAME, columnsInput) + + assertEquals(true, columns.first().notNull) + } + + @Test + fun `parses primary key, not null and increment`() { + val columnsInput = """ + id int [pk, increment, not null] + + """.trimIndent() + + val columns = ColumnParser.parseColumns(TABLE_NAME, columnsInput) + + assertEquals(true, columns.first().primaryKey) + assertEquals(true, columns.first().notNull) + assertEquals(true, columns.first().increment) + } + + @Test + fun `parses primary key, not null and increment ignoring spaces`() { + val columnsInput = """ + id int [pk,increment, not null] + + """.trimIndent() + + val columns = ColumnParser.parseColumns(TABLE_NAME, columnsInput) + + assertEquals(true, columns.first().primaryKey) + assertEquals(true, columns.first().notNull) + assertEquals(true, columns.first().increment) + } + + @Test + fun `parses auto increment`() { + val columnsInput = """ + age int [increment] + + """.trimIndent() + + val columns = ColumnParser.parseColumns(TABLE_NAME, columnsInput) + + assertEquals(true, columns.first().increment) + } + + @Test + fun `ignores column notes`() { + val columnsInput = """ + age int [increment, note: 'overage above 18'] + + """.trimIndent() + + val columns = ColumnParser.parseColumns(TABLE_NAME, columnsInput) + + assertEquals("age", columns.first().name) + assertEquals("int", columns.first().type) + assertEquals(true, columns.first().increment) + } + + @Test + fun `parses multiple columns`() { + val columnsInput = """ + id int [pk, increment, not null] + urn varchar [note: 'not null'] + monetizable int [default: `0`, note: 'nullable'] + + """.trimIndent() + + val columns = ColumnParser.parseColumns(TABLE_NAME, columnsInput) + + assertEquals(3, columns.size) + } +} \ No newline at end of file From 046946fc6934ae88fa6c5feab46b163224a7bbe2 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Mon, 18 May 2020 20:44:50 +0200 Subject: [PATCH 20/29] Add tests for TableParser --- .../zynger/floorplan/lex/TableParserTest.kt | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/TableParserTest.kt diff --git a/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/TableParserTest.kt b/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/TableParserTest.kt new file mode 100644 index 0000000..ed3c144 --- /dev/null +++ b/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/TableParserTest.kt @@ -0,0 +1,97 @@ +package com.zynger.floorplan.lex + +import com.zynger.floorplan.Index +import com.zynger.floorplan.Table +import org.junit.Assert.* +import org.junit.Test + +class TableParserTest { + + @Test + fun `no tables`() { + val input = """ + + """.trimIndent() + + val tables = TableParser.parseTables(input) + + assertEquals(emptyList
(), tables) + } + + @Test + fun `parses name of table`() { + val input = """ + Table posts { + id int [pk, increment] + title varchar [not null] + } + """.trimIndent() + + val tables = TableParser.parseTables(input) + + assertEquals("posts", tables[0].name) + } + + @Test + fun `parses name of multiple tables`() { + val input = """ + Table posts { + id int [pk, increment] + title varchar [not null] + } + + table comments { + id int [pk,increment] + comment varchar + post_id int [not null,ref: > posts.id] + } + table tags as aliasForTagsTable{ + id int [pk, increment, not null] + title varchar [not null] + } + + """.trimIndent() + + val tables = TableParser.parseTables(input) + + assertEquals("posts", tables[0].name) + assertEquals("comments", tables[1].name) + assertEquals("tags", tables[2].name) + } + + @Test + fun `passes column content to be parsed by delegation`() { + val input = """ + table post_tags [note: 'hey table note']{ + id int [pk] + post_id int + tag_id int + } + + + """.trimIndent() + + val tables = TableParser.parseTables(input) + + assertEquals(3, tables.first().columns.size) + } + + @Test + fun `ignores indexes`() { + val input = """ + table post_tags [note: 'hey table note']{ + id int [pk] + post_id int + tag_id int + + Indexes { + (post_id) [name:'index_post_tags_post_id', unique] + } + } + """.trimIndent() + + val tables = TableParser.parseTables(input) + + assertEquals(emptyList(), tables[0].indexes) + } +} \ No newline at end of file From c6fd2e82300b215c8de25ead6585cdfa92a42b4b Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Mon, 18 May 2020 21:34:43 +0200 Subject: [PATCH 21/29] Add graphviz-java dependency --- dbml2viz/build.gradle | 2 ++ .../src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/dbml2viz/build.gradle b/dbml2viz/build.gradle index cb57e45..9f602cf 100644 --- a/dbml2viz/build.gradle +++ b/dbml2viz/build.gradle @@ -17,6 +17,8 @@ application { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + implementation 'guru.nidi:graphviz-java:0.16.0' + implementation 'guru.nidi:graphviz-java-all-j2v8:0.16.0' implementation project(":dbml-parser") testImplementation "junit:junit:4.12" } diff --git a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt index bc5b97c..c1614b3 100644 --- a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt +++ b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt @@ -1,8 +1,20 @@ package com.zynger.floorplan +import guru.nidi.graphviz.attribute.Color +import guru.nidi.graphviz.engine.Format +import guru.nidi.graphviz.engine.Graphviz +import guru.nidi.graphviz.model.MutableGraph import java.io.File +import guru.nidi.graphviz.model.Factory.* fun main() { + val g: MutableGraph = mutGraph("example1").setDirected(true).add( + mutNode("a").add(Color.RED).addLink(mutNode("b")) + ) + println(Graphviz.fromGraph(g).width(200).render(Format.DOT).toString()) +} + +fun main2() { val src = sample() // val src = File("samples/dbml/db-track-pol.dbml").readText() val project = Parser.parse(src) From c47ed16d71aecf357e85deaf2ea33bf86496bba2 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Mon, 18 May 2020 22:26:16 +0200 Subject: [PATCH 22/29] Start playing with graphviz-java --- .../kotlin/com/zynger/floorplan/Dbml2Viz.kt | 74 +++++++++++++++++-- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt index c1614b3..5846c71 100644 --- a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt +++ b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt @@ -1,16 +1,80 @@ package com.zynger.floorplan -import guru.nidi.graphviz.attribute.Color +import guru.nidi.graphviz.attribute.* import guru.nidi.graphviz.engine.Format import guru.nidi.graphviz.engine.Graphviz -import guru.nidi.graphviz.model.MutableGraph +import guru.nidi.graphviz.model.* import java.io.File import guru.nidi.graphviz.model.Factory.* fun main() { - val g: MutableGraph = mutGraph("example1").setDirected(true).add( - mutNode("a").add(Color.RED).addLink(mutNode("b")) - ) + + val project = Parser.parse(sample()) + val tables = project.tables + val references = project.reference + + /* + g.graphAttrs() + .add(Color.WHITE.gradient(Color.rgb("888888")).background().angle(90)) + .nodeAttrs().add(Color.WHITE.fill()) + .nodes().forEach(node -> + node.add( + Color.named(node.name().toString()), + Style.lineWidth(4).and(Style.FILLED))); + */ + + val g: MutableGraph = mutGraph("example1").setDirected(true) + + with(g.graphAttrs()) { + add(GraphAttr.pad(0.5)) + add(Rank.sep(2.0)) + add(MapAttributes().add("nodesep", 0.5)) + } + with(g.nodeAttrs()) { + add(Shape.PLAIN) + } + // FIXME add rankdir=LR on graph root + +// g.add( +// mutNode("a").add(Color.RED).addLink(mutNode("b")) +// ) + + tables.forEach { + val htmlTable = buildString { + appendln("
") + appendln("") + it.columns.forEach { column -> + append("") + } + if (it.indexes.isNotEmpty()) { + appendln("") + it.indexes.forEach { index -> + append("") + } + } + append("
${it.name}
") + if (column.primaryKey) { + append("") + } + append("${column.name}: ${column.type}") + if (column.primaryKey) { + append("") + } + appendln("
Indices
") + append(index.name) + appendln("
") + } + val node = mutNode(it.name).add(Label.html(htmlTable)) + g.add(node) + } + +// references.forEach { +// val link = Link.between( +// port("${it.fromTable}:${it.fromColumn}"), +// node("${it.toTable}:${it.toColumn}") +// ).with(Label.of("helloLabel")) +// g.rootEdges().add(link) +// } println(Graphviz.fromGraph(g).width(200).render(Format.DOT).toString()) } From 2f96efceececd489b219b96adac625054af83ee1 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Tue, 19 May 2020 09:30:28 +0200 Subject: [PATCH 23/29] Disable parser and dbml2viz module usage --- settings.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/settings.gradle b/settings.gradle index a8f9af4..281530d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,5 @@ rootProject.name = 'floorplan' include 'core' -include 'dbml-parser' -include 'dbml2viz' +//include 'dbml-parser' +//include 'dbml2viz' include 'floorplan-cli' From f9beb6ded99850bda1db972df037c56e4652a50b Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Tue, 19 May 2020 11:20:12 +0200 Subject: [PATCH 24/29] Break Column RegEx --- .../com/zynger/floorplan/lex/ColumnParser.kt | 6 +++++- .../com/zynger/floorplan/lex/ColumnParserTest.kt | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt index 615d0c2..a83daac 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt @@ -2,9 +2,13 @@ package com.zynger.floorplan.lex import com.zynger.floorplan.Column import com.zynger.floorplan.Reference +import org.intellij.lang.annotations.Language object ColumnParser { - private val COLUMN_REGEX = Regex("""("\w+"|\w+)+\s+("\w+"|\w+)(\s+\[[^]]*]|)[ ]*\n""") + @Language("RegExp") private const val COLUMN_NAME = """("\w+"|\w+)+""" + @Language("RegExp") private const val COLUMN_TYPE = """("\w+"|\w+)""" + @Language("RegExp") private const val COLUMN_PROPERTIES = """\[[^]]*]""" + private val COLUMN_REGEX = Regex("""$COLUMN_NAME\s+$COLUMN_TYPE(\s+$COLUMN_PROPERTIES|)\s*\n""") // TODO parse column default values diff --git a/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/ColumnParserTest.kt b/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/ColumnParserTest.kt index 9d0c6f9..8cd040d 100644 --- a/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/ColumnParserTest.kt +++ b/dbml-parser/src/test/kotlin/com/zynger/floorplan/lex/ColumnParserTest.kt @@ -140,6 +140,21 @@ class ColumnParserTest { assertEquals(true, columns.first().increment) } + @Test + fun `ignores multiple spaces after properties`() { + val spaces = " " + val columnsInput = """ + age int [increment]$spaces + + """.trimIndent() + + val columns = ColumnParser.parseColumns(TABLE_NAME, columnsInput) + + assertEquals("age", columns.first().name) + assertEquals("int", columns.first().type) + assertEquals(true, columns.first().increment) + } + @Test fun `parses multiple columns`() { val columnsInput = """ From 9cf8f22acfef47c05f1973694d6a477a156b2c42 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Tue, 19 May 2020 11:24:25 +0200 Subject: [PATCH 25/29] Break Reference RegExes --- .../kotlin/com/zynger/floorplan/lex/ColumnReferenceParser.kt | 5 ++++- .../kotlin/com/zynger/floorplan/lex/LoneReferenceParser.kt | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnReferenceParser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnReferenceParser.kt index a6ca541..7b3ae5e 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnReferenceParser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnReferenceParser.kt @@ -2,9 +2,12 @@ package com.zynger.floorplan.lex import com.zynger.floorplan.Reference import com.zynger.floorplan.ReferenceOrder +import org.intellij.lang.annotations.Language object ColumnReferenceParser { - private val COLUMN_REFERENCE_REGEX = Regex("""(([Rr]ef)\s*:\s*([<>-])\s*("\w+"|\w+)\.("\w+"|\w+))""") + @Language("RegExp") private const val WORD = """("\w+"|\w+)+""" + @Language("RegExp") private const val REFERENCE_ORDER = """([-<>])""" + private val COLUMN_REFERENCE_REGEX = Regex("""(([Rr]ef)\s*:\s*$REFERENCE_ORDER\s*$WORD\.$WORD)""") fun parse(tableName: String, fromColumn: String, columnProperties: String): Reference? { return if (COLUMN_REFERENCE_REGEX.containsMatchIn(columnProperties)) { diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/LoneReferenceParser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/LoneReferenceParser.kt index efddbaf..93a0569 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/LoneReferenceParser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/LoneReferenceParser.kt @@ -2,9 +2,12 @@ package com.zynger.floorplan.lex import com.zynger.floorplan.Reference import com.zynger.floorplan.ReferenceOrder +import org.intellij.lang.annotations.Language object LoneReferenceParser { - private val REFERENCE_REGEX = Regex("""[Rr]ef:\s*("\w+"|\w+)\.("\w+"|\w+)\s+([-<>])\s+("\w+"|\w+)\.("\w+"|\w+)""") + @Language("RegExp") private const val WORD = """("\w+"|\w+)+""" + @Language("RegExp") private const val REFERENCE_ORDER = """([-<>])""" + private val REFERENCE_REGEX = Regex("""[Rr]ef:\s*$WORD\.$WORD\s+$REFERENCE_ORDER\s+$WORD\.$WORD""") fun parseReferences(dbmlInput: String): List { return REFERENCE_REGEX.findAll(dbmlInput).map { From e0336cb76c8442661f969647a77624b91b4b7e5b Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Tue, 19 May 2020 11:26:29 +0200 Subject: [PATCH 26/29] Pull out constant --- .../src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt index a83daac..3edec00 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt @@ -5,8 +5,9 @@ import com.zynger.floorplan.Reference import org.intellij.lang.annotations.Language object ColumnParser { - @Language("RegExp") private const val COLUMN_NAME = """("\w+"|\w+)+""" - @Language("RegExp") private const val COLUMN_TYPE = """("\w+"|\w+)""" + @Language("RegExp") private const val WORD = """("\w+"|\w+)""" + @Language("RegExp") private const val COLUMN_NAME = """$WORD+""" + @Language("RegExp") private const val COLUMN_TYPE = WORD @Language("RegExp") private const val COLUMN_PROPERTIES = """\[[^]]*]""" private val COLUMN_REGEX = Regex("""$COLUMN_NAME\s+$COLUMN_TYPE(\s+$COLUMN_PROPERTIES|)\s*\n""") From eea474441cb5a53ede5c6c16a11f0b3c137b2530 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Tue, 19 May 2020 11:30:28 +0200 Subject: [PATCH 27/29] Break out Table RegEx --- .../main/kotlin/com/zynger/floorplan/lex/TableParser.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/TableParser.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/TableParser.kt index 0b5d0e4..c92ab29 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/TableParser.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/TableParser.kt @@ -1,9 +1,14 @@ package com.zynger.floorplan.lex import com.zynger.floorplan.Table +import org.intellij.lang.annotations.Language object TableParser { - private val TABLE_REGEX = Regex("""[Tt]able\s+(."\w+"|\w+.)\s*(\s*as\s+[\w]+|\s*as\s+"[\w]+"|)(\s\[.*]|)\s*\{(\s|\n|[^}]*)}""") + @Language("RegExp") private const val TABLE_NAME = """(."\w+"|\w+.)""" + @Language("RegExp") private const val TABLE_ALIAS = """(\s*as\s+[\w]+|\s*as\s+"[\w]+"|)""" + @Language("RegExp") private const val TABLE_NOTES = """(\s\[.*]|)""" + @Language("RegExp") private const val TABLE_CONTENT = """\{(\s|\n|[^}]*)}""" + private val TABLE_REGEX = Regex("""[Tt]able\s+$TABLE_NAME\s*$TABLE_ALIAS$TABLE_NOTES\s*$TABLE_CONTENT""") fun parseTables(dbmlInput: String): List { // TODO: aliases and table notes also get parsed; should we update the modeling to include them? From 29074cc7d6d30cad5d2f12c1c38354b2df940213 Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Tue, 19 May 2020 14:51:16 +0200 Subject: [PATCH 28/29] Remove dbml2viz references --- dbml2viz/build.gradle | 31 --- .../kotlin/com/zynger/floorplan/Dbml2Viz.kt | 179 ------------------ settings.gradle | 3 +- 3 files changed, 1 insertion(+), 212 deletions(-) delete mode 100644 dbml2viz/build.gradle delete mode 100644 dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt diff --git a/dbml2viz/build.gradle b/dbml2viz/build.gradle deleted file mode 100644 index 9f602cf..0000000 --- a/dbml2viz/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -plugins { - id 'application' - id 'java' - id 'org.jetbrains.kotlin.jvm' -} - -sourceCompatibility = 1.8 - -repositories { - mavenCentral() - jcenter() -} - -application { - mainClassName = "com.zynger.floorplan.Dbml2VizKt" -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - implementation 'guru.nidi:graphviz-java:0.16.0' - implementation 'guru.nidi:graphviz-java-all-j2v8:0.16.0' - implementation project(":dbml-parser") - testImplementation "junit:junit:4.12" -} - -compileKotlin { - kotlinOptions.jvmTarget = "1.8" -} -compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" -} diff --git a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt b/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt deleted file mode 100644 index 5846c71..0000000 --- a/dbml2viz/src/main/kotlin/com/zynger/floorplan/Dbml2Viz.kt +++ /dev/null @@ -1,179 +0,0 @@ -package com.zynger.floorplan - -import guru.nidi.graphviz.attribute.* -import guru.nidi.graphviz.engine.Format -import guru.nidi.graphviz.engine.Graphviz -import guru.nidi.graphviz.model.* -import java.io.File -import guru.nidi.graphviz.model.Factory.* - -fun main() { - - val project = Parser.parse(sample()) - val tables = project.tables - val references = project.reference - - /* - g.graphAttrs() - .add(Color.WHITE.gradient(Color.rgb("888888")).background().angle(90)) - .nodeAttrs().add(Color.WHITE.fill()) - .nodes().forEach(node -> - node.add( - Color.named(node.name().toString()), - Style.lineWidth(4).and(Style.FILLED))); - */ - - val g: MutableGraph = mutGraph("example1").setDirected(true) - - with(g.graphAttrs()) { - add(GraphAttr.pad(0.5)) - add(Rank.sep(2.0)) - add(MapAttributes().add("nodesep", 0.5)) - } - with(g.nodeAttrs()) { - add(Shape.PLAIN) - } - // FIXME add rankdir=LR on graph root - -// g.add( -// mutNode("a").add(Color.RED).addLink(mutNode("b")) -// ) - - tables.forEach { - val htmlTable = buildString { - appendln("
") - appendln("") - it.columns.forEach { column -> - append("") - } - if (it.indexes.isNotEmpty()) { - appendln("") - it.indexes.forEach { index -> - append("") - } - } - append("
${it.name}
") - if (column.primaryKey) { - append("") - } - append("${column.name}: ${column.type}") - if (column.primaryKey) { - append("") - } - appendln("
Indices
") - append(index.name) - appendln("
") - } - val node = mutNode(it.name).add(Label.html(htmlTable)) - g.add(node) - } - -// references.forEach { -// val link = Link.between( -// port("${it.fromTable}:${it.fromColumn}"), -// node("${it.toTable}:${it.toColumn}") -// ).with(Label.of("helloLabel")) -// g.rootEdges().add(link) -// } - println(Graphviz.fromGraph(g).width(200).render(Format.DOT).toString()) -} - -fun main2() { - val src = sample() -// val src = File("samples/dbml/db-track-pol.dbml").readText() - val project = Parser.parse(src) - val tables = project.tables - val references = project.reference - - // TODO write to .gv file instead of stdout - - println( - """ - digraph { - graph [pad="0.5", nodesep="0.5", ranksep="2"]; - node [shape=plain]; - rankdir=LR; - """.trimIndent() - ) - println() - - tables.forEach { println(it.render()) } - - println() - references.forEach { println(it.render()) } - - println("}") -} - -private fun Reference.render(): String { - // Foo:2 -> Baz:a [taillabel="a to b" labeltooltip="this is a tooltip"]; - return "$fromTable:$fromColumn -> $toTable:$toColumn [label=\"${referenceOrder.label}\"]" -} - -private val ReferenceOrder.label: String - get() = when (this) { - ReferenceOrder.OneToOne -> "1-1" - ReferenceOrder.OneToMany -> "1-*" - ReferenceOrder.ManyToOne -> "*-*" - } - -private fun Table.render(): String { - return buildString { - appendln("$name [label=<") - appendln("") - appendln("") - columns.forEach { - append("") - } - if (!indexes.isEmpty()) { - appendln("") - indexes.forEach { index -> - append("") - } - } - append("
$name
") - if (it.primaryKey) { - append("") - } - append("${it.name}: ${it.type}") - if (it.primaryKey) { - append("") - } - appendln("
Indices
") - append(index.name) - appendln("
>];") - } -} - -fun sample(): String { - return """ -Table posts { - id int [pk, increment] - title varchar [not null] -} - -table comments { - id int [pk,increment] - comment varchar - post_id int [not null,ref: > posts.id] -} -table tags as aliasForTagsTable{ - id int [pk, increment, not null] - title varchar [not null] -} - -table post_tags [note: 'hey table note']{ - id int [pk] - post_id int - tag_id int -} - - - - -Ref: "tags"."id" < "post_tags"."tag_id" - -Ref: "posts"."id" < "post_tags"."post_id" -Ref: "posts"."id" - "post_tags"."post_id" - """.trimIndent() -} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 281530d..ae37e69 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,4 @@ rootProject.name = 'floorplan' include 'core' -//include 'dbml-parser' -//include 'dbml2viz' +// include 'dbml-parser' include 'floorplan-cli' From 4137555712d19d6ffb5916a61ad25d19c118d1fb Mon Sep 17 00:00:00 2001 From: Julio Zynger Date: Tue, 19 May 2020 14:59:56 +0200 Subject: [PATCH 29/29] TODO cleanup --- dbml-parser/src/main/kotlin/com/zynger/floorplan/Index.kt | 2 +- dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt | 3 +-- settings.gradle | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Index.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Index.kt index 1cda27d..c0ca2a1 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Index.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Index.kt @@ -1,6 +1,6 @@ package com.zynger.floorplan data class Index(val name: String, val columnNames: List? = null, val unique: Boolean = false){ - // TODO should we enforce column names? + // TODO should we enforce that indexes must have column names? as to make the property not nullable //(urn) [name:'index_TimeToLives_urn', unique] } diff --git a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt index bb5b12d..65fbdb4 100644 --- a/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt +++ b/dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt @@ -9,11 +9,10 @@ data class Reference( val fromColumn: String, val toTable: String, val toColumn: String, - val referenceOrder: ReferenceOrder = ReferenceOrder.OneToOne // TODO adjust later to parse ref. order + val referenceOrder: ReferenceOrder ) enum class ReferenceOrder { - // > many-to-one; < one-to-many; - one-to-one OneToOne, OneToMany, ManyToOne; companion object { fun fromString(str: String): ReferenceOrder { diff --git a/settings.gradle b/settings.gradle index ae37e69..47bcca6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,4 @@ rootProject.name = 'floorplan' include 'core' -// include 'dbml-parser' +include 'dbml-parser' include 'floorplan-cli'