Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add experimental draft support for GPML-style graph query #652

Merged
merged 5 commits into from
Jun 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 58 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,68 @@ 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))

// The direction of an edge
// | Orientation | Edge pattern | Abbreviation |
// |---------------------------+--------------+--------------|
// | Pointing left | <−[ spec ]− | <− |
// | Undirected | ~[ spec ]~ | ~ |
// | Pointing right | −[ spec ]−> | −> |
// | Left or undirected | <~[ spec ]~ | <~ |
// | Undirected or right | ~[ spec ]~> | ~> |
// | Left or right | <−[ spec ]−> | <−> |
// | Left, undirected or right | −[ spec ]− | − |
//
// Fig. 5. Table of edge patterns:
// https://arxiv.org/abs/2112.06217
(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))

// A part of a graph pattern
(sum graph_match_pattern_part
// A single node in a graph pattern.
(node
predicate::(? expr) // an optional node pre-filter, e.g.: `WHERE c.name='Alarm'` in `MATCH (c WHERE c.name='Alarm')`
variable::(? symbol) // the optional element variable of the node match, e.g.: `x` in `MATCH (x)`
label::(* symbol 0)) // the optional label(s) to match for the node, e.g.: `Entity` in `MATCH (x:Entity)`

// A single edge in a graph pattern.
(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, e.g.: `WHERE t.capacity>100` in `MATCH −[t:hasSupply WHERE t.capacity>100]−>`
variable::(? symbol) // the optional element variable of the edge match, e.g.: `t` in `MATCH −[t]−>`
label::(* symbol 0)) // the optional label(s) to match for the edge. e.g.: `Target` in `MATCH −[t:Target]−>`
// A sub-pattern.
(pattern pattern::graph_match_pattern))

// 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 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 as defined in GPML
// See https://arxiv.org/abs/2112.06217
(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"
)

/** Operators specific to the `MATCH` clause. */
@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 + "-*/<>|!"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, just noticed the OPERATOR_CHARS variable isn't used anywhere. Can it be removed?


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