-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds module to allow for creating an in-memory model of DBML schemas. To be done separately: - Add support for Index parsing (currently hack in place) - Parse column default values - Include table aliases and table notes in modeling - Pull out DBML modeling classes into shared module that Room translator can depend on (and remove duplication)
- Loading branch information
Showing
16 changed files
with
747 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
} |
14 changes: 14 additions & 0 deletions
14
dbml-parser/src/main/kotlin/com/zynger/floorplan/Column.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +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 notNull: Boolean = false, | ||
val increment: Boolean = false, | ||
val reference: Reference? = null // not null when this column references another through a column attribute | ||
) { | ||
// example column: address varchar(255) [unique, not null, note: 'to include unit number'] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.zynger.floorplan | ||
|
||
data class Index(val name: String, val columnNames: List<String>? = null, val unique: Boolean = false){ | ||
// TODO should we enforce that indexes must have column names? as to make the property not nullable | ||
//(urn) [name:'index_TimeToLives_urn', unique] | ||
} |
15 changes: 15 additions & 0 deletions
15
dbml-parser/src/main/kotlin/com/zynger/floorplan/Parser.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.zynger.floorplan | ||
|
||
import com.zynger.floorplan.lex.LoneReferenceParser | ||
import com.zynger.floorplan.lex.TableParser | ||
|
||
object Parser { | ||
|
||
fun parse(dbmlInput: String): Project { | ||
val tables = TableParser.parseTables(dbmlInput) | ||
val columnReferences = tables.map { it.columns }.flatten().mapNotNull { it.reference } | ||
val references = LoneReferenceParser.parseReferences(dbmlInput) + columnReferences | ||
return Project(tables, references) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.zynger.floorplan | ||
|
||
data class Project( | ||
val tables: List<Table>, | ||
val reference: List<Reference> | ||
) |
27 changes: 27 additions & 0 deletions
27
dbml-parser/src/main/kotlin/com/zynger/floorplan/Reference.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.zynger.floorplan | ||
|
||
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, | ||
val toColumn: String, | ||
val referenceOrder: ReferenceOrder | ||
) | ||
|
||
enum class ReferenceOrder { | ||
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.") | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.zynger.floorplan | ||
|
||
data class Table( | ||
val rawValue: String, | ||
val name: String, | ||
val columns: List<Column>, | ||
val indexes: List<Index> = emptyList() | ||
) |
42 changes: 42 additions & 0 deletions
42
dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnParser.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package com.zynger.floorplan.lex | ||
|
||
import com.zynger.floorplan.Column | ||
import com.zynger.floorplan.Reference | ||
import org.intellij.lang.annotations.Language | ||
|
||
object ColumnParser { | ||
@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""") | ||
|
||
// TODO parse column default values | ||
|
||
fun parseColumns(tableName: String, columnsInput: String): List<Column> { | ||
return COLUMN_REGEX.findAll(columnsInput).map { | ||
val rawValue = it.groups[0]!!.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") | ||
val pk = columnProperties.contains("pk") | ||
val increment = columnProperties.contains("increment") | ||
val reference: Reference? = ColumnReferenceParser.parse(tableName, name, columnProperties) | ||
|
||
Column( | ||
rawValue = rawValue, | ||
name = name, | ||
type = type, | ||
primaryKey = pk, | ||
notNull = notNull, | ||
increment = increment, | ||
reference = reference | ||
) | ||
}.toList() | ||
} | ||
|
||
private fun String.removeSurroundQuotes(): String { | ||
return this.removeSurrounding("\"") | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/ColumnReferenceParser.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.zynger.floorplan.lex | ||
|
||
import com.zynger.floorplan.Reference | ||
import com.zynger.floorplan.ReferenceOrder | ||
import org.intellij.lang.annotations.Language | ||
|
||
object ColumnReferenceParser { | ||
@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)) { | ||
val referenceProperties = COLUMN_REFERENCE_REGEX.find(columnProperties)!! | ||
Reference( | ||
rawValue = referenceProperties.groups[0]!!.value, | ||
fromTable = tableName.removeSurroundQuotes(), | ||
fromColumn = fromColumn.removeSurroundQuotes(), | ||
referenceOrder = ReferenceOrder.fromString(referenceProperties.groups[3]!!.value), | ||
toTable = referenceProperties.groups[4]!!.value.removeSurroundQuotes(), | ||
toColumn = referenceProperties.groups[5]!!.value.removeSurroundQuotes() | ||
) | ||
} else null | ||
} | ||
|
||
private fun String.removeSurroundQuotes(): String { | ||
return this.removeSurrounding("\"") | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/LoneReferenceParser.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.zynger.floorplan.lex | ||
|
||
import com.zynger.floorplan.Reference | ||
import com.zynger.floorplan.ReferenceOrder | ||
import org.intellij.lang.annotations.Language | ||
|
||
object LoneReferenceParser { | ||
@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<Reference> { | ||
return REFERENCE_REGEX.findAll(dbmlInput).map { | ||
Reference( | ||
rawValue = it.groups[0]!!.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.removeSurroundQuotes(), | ||
toColumn = it.groups[5]!!.value.removeSurroundQuotes() | ||
) | ||
}.toList() | ||
} | ||
|
||
private fun String.removeSurroundQuotes(): String { | ||
return this.removeSurrounding("\"") | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
dbml-parser/src/main/kotlin/com/zynger/floorplan/lex/TableParser.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.zynger.floorplan.lex | ||
|
||
import com.zynger.floorplan.Table | ||
import org.intellij.lang.annotations.Language | ||
|
||
object TableParser { | ||
@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<Table> { | ||
// 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() | ||
} | ||
} |
Oops, something went wrong.