Skip to content

Commit

Permalink
Add experimental draft support for GPML-style graph query
Browse files Browse the repository at this point in the history
  • Loading branch information
jpschorr committed Jun 24, 2022
1 parent 6ad876a commit d6264c1
Show file tree
Hide file tree
Showing 9 changed files with 993 additions and 8 deletions.
48 changes: 46 additions & 2 deletions lang/resources/org/partiql/type-domains/partiql.ion
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,56 @@ may then be further optimized by selecting better implementations of each operat
// UNPIVOT <expr> [AS <id>] [AT <id>] [BY <id>]
(unpivot expr::expr as_alias::(? symbol) at_alias::(? symbol) by_alias::(? symbol))

// <from_source> JOIN [INNER | LEFT | RIGHT | FULL] <from_source> ON <expr>
(join type::join_type left::from_source right::from_source predicate::(? expr)))
// <from_source> JOIN [INNER | LEFT | RIGHT | FULL] <from_source> ON <expr>
(join type::join_type left::from_source right::from_source predicate::(? expr))

// <expr> MATCH <graph_pattern>
(graph_match expr::expr graph_expr::graph_match_expr))

// Indicates the logical type of join.
(sum join_type (inner) (left) (right) (full))

// A quantifier for graph edges or patterns. (e.g., the `{2,5}` in `MATCH (x)->{2,5}->(y)`)
(product graph_match_quantifier lower::int upper::(? int))

// A single node in a graph pattern.
(product graph_match_node
predicate::(? expr) // an optional node pre-filter
variable::(? symbol) // the optional element variable of the node match
label::(* symbol 0)) // the optional label(s) to match for the node

// A single edge in a graph pattern.
(product graph_match_edge
direction::graph_match_direction // edge direction
quantifier::(? graph_match_quantifier) // an optional quantifier for the edge match
predicate::(? expr) // an optional edge pre-filter
variable::(? symbol) // the optional element variable of the edge match
label::(* symbol 0)) // the optional label(s) to match for the edge

// The direction of an edge
(sum graph_match_direction
(edge_left)
(edge_undirected)
(edge_right)
(edge_left_or_undirected)
(edge_undirected_or_right)
(edge_left_or_right)
(edge_left_or_undirected_or_right))

(sum graph_match_pattern_part
(node node::graph_match_node)
(edge edge::graph_match_edge)
(pattern pattern::graph_match_pattern))

// A single graph match pattern.
(product graph_match_pattern
quantifier::(? graph_match_quantifier) // an optional quantifier for the entire pattern match
parts::(* graph_match_pattern_part 1)) // the ordered pattern parts

// A graph match clause.
(product graph_match_expr patterns::(*graph_match_pattern 1))


// A generic pair of expressions. Used in the `struct`, `searched_case` and `simple_case` expr variants above.
(product expr_pair first::expr second::expr)

Expand Down
1 change: 1 addition & 0 deletions lang/src/org/partiql/lang/ast/StatementToExprNode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ private class StatementTransformer(val ion: IonSystem) {
condition = predicate?.toExprNode() ?: Literal(ion.newBool(true), metaContainerOf(StaticTypeMeta(StaticType.BOOL))),
metas = metas
)
is PartiqlAst.FromSource.GraphMatch -> error("$this node has no representation in prior ASTs.")
}
}

Expand Down
36 changes: 36 additions & 0 deletions lang/src/org/partiql/lang/errors/ErrorCode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,42 @@ enum class ErrorCode(
"expected identifier for alias"
),

PARSE_EXPECTED_IDENT_FOR_MATCH(
ErrorCategory.PARSER,
LOC_TOKEN,
"expected identifier for match"
),

PARSE_EXPECTED_LEFT_PAREN_FOR_MATCH_NODE(
ErrorCategory.PARSER,
LOC_TOKEN,
"expected left parenthesis for match node"
),

PARSE_EXPECTED_RIGHT_PAREN_FOR_MATCH_NODE(
ErrorCategory.PARSER,
LOC_TOKEN,
"expected right parenthesis for match node"
),

PARSE_EXPECTED_LEFT_BRACKET_FOR_MATCH_EDGE(
ErrorCategory.PARSER,
LOC_TOKEN,
"expected left bracket for match edge"
),

PARSE_EXPECTED_RIGHT_BRACKET_FOR_MATCH_EDGE(
ErrorCategory.PARSER,
LOC_TOKEN,
"expected right bracket for match edge"
),

PARSE_EXPECTED_EDGE_PATTERN_MATCH_EDGE(
ErrorCategory.PARSER,
LOC_TOKEN,
"expected edge pattern for match edge"
),

PARSE_EXPECTED_AS_FOR_LET(
ErrorCategory.PARSER,
LOC_TOKEN,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ class GroupByPathExpressionVisitorTransform(

is PartiqlAst.FromSource.Unpivot ->
listOfNotNull(fromSource.asAlias?.text, fromSource.atAlias?.text)

is PartiqlAst.FromSource.GraphMatch ->
TODO("Handle MATCH for GROUP BY")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,8 @@ private object FromSourceToBexpr : PartiqlAst.FromSource.Converter<PartiqlLogica
node.metas
)
}

override fun convertGraphMatch(node: PartiqlAst.FromSource.GraphMatch): PartiqlLogical.Bexpr {
TODO("Support for MATCH")
}
}
11 changes: 8 additions & 3 deletions lang/src/org/partiql/lang/syntax/LexerConstants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -499,15 +499,20 @@ internal val DATE_TIME_PART_KEYWORDS: Set<String> = DateTimePart.values()
"+", "-", "not"
)

/** All operators with special parsing rules. */
@JvmField internal val MATCH_OPERATORS = setOf(
"~"
)

/** All operators with special parsing rules. */
@JvmField internal val SPECIAL_OPERATORS = SPECIAL_INFIX_OPERATORS + setOf(
"@"
)

@JvmField internal val ALL_SINGLE_LEXEME_OPERATORS =
SINGLE_LEXEME_BINARY_OPERATORS + UNARY_OPERATORS + SPECIAL_OPERATORS
SINGLE_LEXEME_BINARY_OPERATORS + UNARY_OPERATORS + SPECIAL_OPERATORS + MATCH_OPERATORS
@JvmField internal val ALL_OPERATORS =
BINARY_OPERATORS + UNARY_OPERATORS + SPECIAL_OPERATORS
BINARY_OPERATORS + UNARY_OPERATORS + SPECIAL_OPERATORS + MATCH_OPERATORS

/**
* Operator precedence groups
Expand Down Expand Up @@ -585,7 +590,7 @@ internal const val DIGIT_CHARS = "0" + NON_ZERO_DIGIT_CHARS

@JvmField internal val E_NOTATION_CHARS = allCase("E")

internal const val NON_OVERLOADED_OPERATOR_CHARS = "^%=@+"
internal const val NON_OVERLOADED_OPERATOR_CHARS = "^%=@+~"
internal const val OPERATOR_CHARS = NON_OVERLOADED_OPERATOR_CHARS + "-*/<>|!"

@JvmField internal val ALPHA_CHARS = allCase("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
Expand Down
Loading

0 comments on commit d6264c1

Please sign in to comment.