Skip to content

Commit

Permalink
Parse relationship mapping definition
Browse files Browse the repository at this point in the history
Co-authored-by: Philip Stutz <philip.stutz@gmail.com>
  • Loading branch information
s1ck and pstutz committed Oct 11, 2018
1 parent e81d573 commit f813c3a
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ trait TestNameFixture extends BaseTestSuite {
private var __testName: Option[String] = None

override protected def runTest(testName: String, args: Args): Status = {
val colonIndex = testName.indexOf(separator)
val separatorIndex = testName.indexOf(separator)

val name = colonIndex match {
val name = separatorIndex match {
case -1 => testName
case _ => testName.substring(colonIndex + separator.length)
case _ => testName.substring(separatorIndex + separator.length).trim.stripMargin
}
__testName = Some(name)
try {
Expand Down
26 changes: 10 additions & 16 deletions sql-ddl/src/main/scala/org/opencypher/sql/ddl/DdlAst.scala
Original file line number Diff line number Diff line change
Expand Up @@ -136,24 +136,18 @@ case class NodeMappingDefinition(
maybePropertyMapping: Option[PropertyToColumnMappingDefinition] = None
) extends DdlAst

case class RelMappingDefinition(
relName: String,
tableName: String,
startNodeIdMappings: List[IdMapping],
endNodeIdMappings: List[IdMapping]
) extends DdlAst

case class IdMapping(
labelNames: Set[String],
nodePropertyNames: List[String],
relPropertyNames: List[String]
)
case class SourceViewDefinition(name: String, alias: String) extends DdlAst

case class JoinOnDefinition(joinPredicates: List[(ColumnIdentifier, ColumnIdentifier)]) extends DdlAst

case class EntityMappingDefinition(
case class LabelToViewDefinition(
labelSet: Set[String],
sourceView: String,
sourceViewAlias: String,
joinOnDefinition: JoinOnDefinition
sourceView: SourceViewDefinition,
joinOn: JoinOnDefinition
) extends DdlAst

case class RelationshipMappingDefinition(
sourceView: SourceViewDefinition,
startNodeMappingDefinition: LabelToViewDefinition,
endNodeMappingDefinition: LabelToViewDefinition
) extends DdlAst
42 changes: 25 additions & 17 deletions sql-ddl/src/main/scala/org/opencypher/sql/ddl/DdlParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,26 @@ object DdlParser {
val character = P(CharIn('a' to 'z', 'A' to 'Z'))
val identifier = P(character ~ P(character | digit | "_").repX)

val catalogKeyword = P(IgnoreCase("CATALOG"))
val createKeyword = P(IgnoreCase("CREATE"))
val labelKeyword = P(IgnoreCase("LABEL"))
val graphKeyword = P(IgnoreCase("GRAPH"))
val schemaKeyword = P(IgnoreCase("SCHEMA"))
val keyKeyword = P(IgnoreCase("KEY"))
val withKeyword = P(IgnoreCase("WITH"))
val fromKeyword = P(IgnoreCase("FROM"))
val nodeKeyword = P(IgnoreCase("NODE"))
val setKeyword = P(IgnoreCase("SET"))
val setsKeyword = P(IgnoreCase("SETS"))
val joinKeyword = P(IgnoreCase("JOIN"))
val onKeyword = P(IgnoreCase("ON"))
val andKeyword = P(IgnoreCase("AND"))
val asKeyword = P(IgnoreCase("AS"))
val viewKeyword = P(IgnoreCase("VIEW"))
def keyword(k: String): P[Unit] = P(IgnoreCase(k))

val catalogKeyword = keyword("CATALOG")
val createKeyword = keyword("CREATE")
val labelKeyword = keyword("LABEL")
val graphKeyword = keyword("GRAPH")
val schemaKeyword = keyword("SCHEMA")
val keyKeyword = keyword("KEY")
val withKeyword = keyword("WITH")
val fromKeyword = keyword("FROM")
val nodeKeyword = keyword("NODE")
val nodesKeyword = keyword("NODES")
val setKeyword = keyword("SET")
val setsKeyword = keyword("SETS")
val joinKeyword = keyword("JOIN")
val onKeyword = keyword("ON")
val andKeyword = keyword("AND")
val asKeyword = keyword("AS")
val startKeyword = keyword("START")
val endKeyword = keyword("END")

val cypherType = P(
(IgnoreCase("STRING")
Expand Down Expand Up @@ -160,7 +164,11 @@ object DdlParser {
val joinTuple: P[(ColumnIdentifier, ColumnIdentifier)] = P(columnIdentifier ~ "=" ~ columnIdentifier)
val joinOnDefinition: P[JoinOnDefinition] = P(joinKeyword ~ onKeyword ~ joinTuple.rep(min = 1, sep = andKeyword)).map(_.toList).map(JoinOnDefinition)

val entityMappingDefinition: P[EntityMappingDefinition] = P(labelKeyword ~ setKeyword ~ nodeDefinition ~ fromKeyword ~ viewKeyword ~ identifier.! ~ identifier.! ~ joinOnDefinition).map(EntityMappingDefinition.tupled)
val sourceViewDefinition: P[SourceViewDefinition] = P(identifier.! ~ identifier.!).map(SourceViewDefinition.tupled)

val labelToViewDefinition: P[LabelToViewDefinition] = P(labelKeyword ~ setKeyword ~ nodeDefinition ~ fromKeyword ~ sourceViewDefinition ~ joinOnDefinition).map(LabelToViewDefinition.tupled)

val relationshipMappingDefinition: P[RelationshipMappingDefinition] = P(fromKeyword ~ sourceViewDefinition ~ startKeyword ~ nodesKeyword ~ labelToViewDefinition ~ endKeyword ~ nodesKeyword ~ labelToViewDefinition).map(RelationshipMappingDefinition.tupled)

// TODO: this allows WITH SCHEMA with missing identifier and missing inline schema -> forbid
val graphDefinition: P[GraphDefinition] = P(createKeyword ~ graphKeyword ~ identifier.! ~
Expand Down
51 changes: 41 additions & 10 deletions sql-ddl/src/test/scala/org/opencypher/sql/ddl/DdlSchemaTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,20 @@ import org.scalatest.mockito.MockitoSugar

class DdlSchemaTest extends BaseTestSuite with MockitoSugar with TestNameFixture {

override val separator = "parses "

private def success[T, Elem](parser: fastparse.core.Parser[T, Elem, String], expectation: T): Unit = {
parser.parse(testName) should matchPattern {
override val separator = "parses"

private def success[T, Elem](
parser: fastparse.core.Parser[T, Elem, String],
input: String,
expectation: T
): Unit = success(parser, expectation, input)

private def success[T, Elem](
parser: fastparse.core.Parser[T, Elem, String],
expectation: T,
input: String = testName
): Unit = {
parser.parse(input) should matchPattern {
case Success(`expectation`, _) =>
}
}
Expand Down Expand Up @@ -324,15 +334,36 @@ class DdlSchemaTest extends BaseTestSuite with MockitoSugar with TestNameFixture
(List("view_a", "COLUMN_C"), List("view_b", "COLUMN_D")))))
}

it("parses LABEL SET (A, B) FROM VIEW foo alias_foo JOIN ON alias_foo.COLUMN_A = edge.COLUMN_A") {
success(entityMappingDefinition, EntityMappingDefinition(
labelSet = Set("A", "B"),
sourceView = "foo",
sourceViewAlias = "alias_foo",
joinOnDefinition = JoinOnDefinition(List((List("alias_foo", "COLUMN_A"), List("edge", "COLUMN_A")))))
it("parses LABEL SET (A, B) FROM foo alias_foo JOIN ON alias_foo.COLUMN_A = edge.COLUMN_A") {
success(labelToViewDefinition, LabelToViewDefinition(
Set("A", "B"),
SourceViewDefinition("foo", "alias_foo"),
JoinOnDefinition(List((List("alias_foo", "COLUMN_A"), List("edge", "COLUMN_A")))))
)
}

it("parses a complete relationship mapping definition") {
val input =
"""|FROM baz alias_baz
| START NODES
| LABEL SET (A, B) FROM foo alias_foo JOIN ON alias_foo.COLUMN_A = edge.COLUMN_A
| END NODES
| LABEL SET (C) FROM bar alias_bar JOIN ON alias_bar.COLUMN_A = edge.COLUMN_A
""".stripMargin

success(relationshipMappingDefinition, input, RelationshipMappingDefinition(
sourceView = SourceViewDefinition("baz", "alias_baz"),
startNodeMappingDefinition = LabelToViewDefinition(
Set("A", "B"),
SourceViewDefinition("foo", "alias_foo"),
JoinOnDefinition(List((List("alias_foo", "COLUMN_A"), List("edge", "COLUMN_A"))))),
endNodeMappingDefinition = LabelToViewDefinition(
Set("C"),
SourceViewDefinition("bar", "alias_bar"),
JoinOnDefinition(List((List("alias_bar", "COLUMN_A"), List("edge", "COLUMN_A")))))
))
}

ignore("parses") {
val input =
"""|RELATIONSHIP LABEL SETS (
Expand Down

0 comments on commit f813c3a

Please sign in to comment.