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

Support Spanner Graph(SQL/PGQ) schema statements #101

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
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
303 changes: 303 additions & 0 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ func (DropModel) isStatement() {}
func (Analyze) isStatement() {}
func (CreateVectorIndex) isStatement() {}
func (DropVectorIndex) isStatement() {}
func (CreatePropertyGraph) isStatement() {}
func (DropPropertyGraph) isStatement() {}
func (Insert) isStatement() {}
func (Delete) isStatement() {}
func (Update) isStatement() {}
Expand Down Expand Up @@ -380,6 +382,8 @@ func (DropModel) isDDL() {}
func (Analyze) isDDL() {}
func (CreateVectorIndex) isDDL() {}
func (DropVectorIndex) isDDL() {}
func (CreatePropertyGraph) isDDL() {}
func (DropPropertyGraph) isDDL() {}

// Constraint represents table constraint of CONSTARINT clause.
type Constraint interface {
Expand Down Expand Up @@ -3510,6 +3514,305 @@ type AlterSearchIndex struct {
IndexAlteration IndexAlteration
}

// ================================================================================
//
// GQL schema statements
//
// ================================================================================

// PropertyGraphLabelsOrProperties represents labels with properties or a single properties of node or edge.
type PropertyGraphLabelsOrProperties interface {
Node
isPropertyGraphLabelsOrProperties()
}

func (*PropertyGraphSingleProperties) isPropertyGraphLabelsOrProperties() {}
func (*PropertyGraphLabelAndPropertiesList) isPropertyGraphLabelsOrProperties() {}

// PropertyGraphElementLabel represents a element label definition.
type PropertyGraphElementLabel interface {
Node
isPropertyGraphElementLabel()
}

func (*PropertyGraphElementLabelLabelName) isPropertyGraphElementLabel() {}
func (*PropertyGraphElementLabelDefaultLabel) isPropertyGraphElementLabel() {}

// PropertyGraphElementKeys represents PropertyGraphNodeElementKey or PropertyGraphEdgeElementKeys.
type PropertyGraphElementKeys interface {
Node
isPropertyGraphElementKeys()
}

func (*PropertyGraphNodeElementKey) isPropertyGraphElementKeys() {}
func (*PropertyGraphEdgeElementKeys) isPropertyGraphElementKeys() {}

// PropertyGraphElementProperties represents a definition of properties.
// See https://cloud.google.com/spanner/docs/reference/standard-sql/graph-schema-statements#element_table_property_definition.
type PropertyGraphElementProperties interface {
Node
isPropertyGraphElementProperties()
}

func (*PropertyGraphNoProperties) isPropertyGraphElementProperties() {}
func (*PropertyGraphPropertiesAre) isPropertyGraphElementProperties() {}
func (*PropertyGraphDerivedPropertyList) isPropertyGraphElementProperties() {}

// CreatePropertyGraph is CREATE PROPERTY GRAPH statement node.
//
// CREATE {{if .OrReplace}}OR REPLACE{{end}} PROPERTY GRAPH
// {{if .IfNotExists}}IF NOT EXISTS{{end}}
// {{.Name | sql}}
// {{.Content | sql}}
type CreatePropertyGraph struct {
// pos = Create
// end = Content.end

Create token.Pos // position of "CREATE" keyword
OrReplace bool
IfNotExists bool
Name *Ident
Content *PropertyGraphContent
}

// PropertyGraphContent represents body of CREATE PROPERTY GRAPH statement.
//
// NODE TABLES {{.NodeTables | sql}} {{.EdgeTables | sqlOpt}}
type PropertyGraphContent struct {
// pos = NodeTables.pos
// end = (EdgeTables ?? NodeTables).end

NodeTables *PropertyGraphNodeTables
EdgeTables *PropertyGraphEdgeTables //optional
}

// PropertyGraphNodeTables is NODE TABLES node in CREATE PROPERTY GRAPH statement.
type PropertyGraphNodeTables struct {
// pos = Node
// end = Tables.end

Node token.Pos
Tables *PropertyGraphElementList
}

// PropertyGraphEdgeTables is EDGE TABLES node in CREATE PROPERTY GRAPH statement.
type PropertyGraphEdgeTables struct {
// pos = Edge
// end = Tables.end

Edge token.Pos
Tables *PropertyGraphElementList
}

// PropertyGraphElementList represents element list in NODE TABLES or EDGE TABLES.
//
// ({{.Elements | sqlJoin ", "}})
type PropertyGraphElementList struct {
// pos = Lparen
// end = Rparen + 1

Lparen, Rparen token.Pos
Elements []*PropertyGraphElement
}

// PropertyGraphElement represents a single element in NODE TABLES or EDGE TABLES.
//
// {{.Name | sql}} {{if .Alias | isnil | not)}}AS {{.Alias | sql}}{{end}}
// {{.Keys | sqlOpt}} {{.Properties | sqlOpt}}
type PropertyGraphElement struct {
// pos = Name.pos
// end = (Properties ?? Keys ?? Alias ?? Name).end

Name *Ident
Alias *Ident // optional
Keys PropertyGraphElementKeys // optional
Properties PropertyGraphLabelsOrProperties // optional
}

// PropertyGraphSingleProperties is wrapper node for PropertyGraphElementProperties in PropertyGraphElement.
// It implements PropertyGraphLabelsOrProperties.
//
// {{.Properties | sql}}
type PropertyGraphSingleProperties struct {
// pos = Properties.pos
// end = Properties.end

Properties PropertyGraphElementProperties
}

// PropertyGraphLabelAndPropertiesList represents whitespace-separated list of PropertyGraphLabelAndProperties.
// It implements PropertyGraphLabelsOrProperties.
//
// {{.LabelAndProperties | sqlJoin " "}}
type PropertyGraphLabelAndPropertiesList struct {
// pos = LabelAndProperties[0].pos
// end = LabelAndProperties[$].end

LabelAndProperties []*PropertyGraphLabelAndProperties
}

// PropertyGraphLabelAndProperties represents label and properties definition for a single label.
//
// {{.Label | sql}} {{.Properties | sqlOpt}}
type PropertyGraphLabelAndProperties struct {
// pos = Label.pos
// end = (Properties ?? Label).end

Label PropertyGraphElementLabel
Properties PropertyGraphElementProperties // optional
}

// PropertyGraphElementLabelLabelName represents LABEL label_name node.
//
// LABEL {{.Name | sql}}
type PropertyGraphElementLabelLabelName struct {
// pos = Label
// end = Name.end

Label token.Pos
Name *Ident
}

// PropertyGraphElementLabelDefaultLabel represents DEFAULT LABEL node.
//
// DEFAULT LABEL
type PropertyGraphElementLabelDefaultLabel struct {
// pos = Default
// end = Label + 5

Default token.Pos
Label token.Pos
}

// PropertyGraphNodeElementKey is a wrapper of PropertyGraphElementKey to implement PropertyGraphElementKeys
// without deeper AST hierarchy.
//
// {{.Key | sql}}
type PropertyGraphNodeElementKey struct {
// pos = Key.pos
// end = Key.end

Key *PropertyGraphElementKey
}

// PropertyGraphEdgeElementKeys represents PropertyGraphSourceKey and PropertyGraphDestinationKey with optional PropertyGraphElementKey.
//
// {{.Element | sqlOpt}} {{.Source | sql}} {{.Destination | sql}}
type PropertyGraphEdgeElementKeys struct {
// pos = Element.pos
// end = Destination.end
Element *PropertyGraphElementKey // optional
Source *PropertyGraphSourceKey
Destination *PropertyGraphDestinationKey
}

// PropertyGraphElementKey represents the key that identifies the node or edge element.
//
// KEY {{.Keys | sql}}
type PropertyGraphElementKey struct {
// pos = Key
// end = Keys.end

Key token.Pos
Keys *PropertyGraphColumnNameList
}

// PropertyGraphSourceKey represents the key for the source node of the edge.
//
// SOURCE KEY {{.Keys | sql}}
// REFERENCES {{.ElementReference | sql}} {{.ReferenceColumns | sqlOpt}}
type PropertyGraphSourceKey struct {
// pos = Source
// end = (ReferenceColumns ?? ElementReference).end

Source token.Pos
Keys *PropertyGraphColumnNameList
ElementReference *Ident
ReferenceColumns *PropertyGraphColumnNameList // optional
}

// PropertyGraphDestinationKey represents the key for the destination node of the edge.
//
// DESTINATION KEY {{.Keys | sql}}
// REFERENCES {{.ElementReference | sql}} {{.ReferenceColumns | sqlOpt}}
type PropertyGraphDestinationKey struct {
// pos = Destination
// end = (ReferenceColumns ?? ElementReference).end

Destination token.Pos
Keys *PropertyGraphColumnNameList
ElementReference *Ident
ReferenceColumns *PropertyGraphColumnNameList // optional
}

// PropertyGraphColumnNameList represents one or more columns to assign to a key.
//
// ({{.ColumnNameList | sqlJoin ", "}})
type PropertyGraphColumnNameList struct {
// pos = LParen
// end = RParen + 1
LParen, RParen token.Pos
ColumnNameList []*Ident
}

// PropertyGraphNoProperties represents the element doesn't have properties.
//
// NO PROPERTIES
type PropertyGraphNoProperties struct {
// pos = No
// end = Properties + 10

No, Properties token.Pos // position of "NO" and "PROPERTIES"
}

// PropertyGraphPropertiesAre defines which columns to include as element properties.
//
// PROPERTIES ARE ALL COLUMNS{{if .ExceptColumns | isnil | not}} EXCEPT {{.ExceptColumns | sql}}{{end}}
type PropertyGraphPropertiesAre struct {
// pos = Properties
// end = ExceptColumns.end || Columns + 7

Properties token.Pos // position of "PROPERTIES"
Columns token.Pos // position of "COLUMNS"
ExceptColumns *PropertyGraphColumnNameList // optional
}

// PropertyGraphDerivedPropertyList represents a list of PropertyGraphDerivedProperty.
// NOTE: In current syntax reference, "(" and ")" are missing.
//
// PROPERTIES ({{.DerivedProperties | sqlJoin ", "}})
type PropertyGraphDerivedPropertyList struct {
// pos = Properties
// end = Rparen

Properties token.Pos // position of "PROPERTIES"
Rparen token.Pos // position of ")"
DerivedProperties []*PropertyGraphDerivedProperty // len(DerivedProperties) > 0
}

// PropertyGraphDerivedProperty represents an expression that defines a property and can optionally reference the input table columns.
//
// {{.Expr | sql}} {{if .Alias}}AS {{.Alias | sql}}{{end}}
type PropertyGraphDerivedProperty struct {
// pos = Expr.pos
// end = (Alias ?? Expr).end

Expr Expr
Alias *Ident //optional
}

// DropPropertyGraph is DROP PROPERTY GRAPH statement node.
//
// DROP PROPERTY GRAPH {{if .IfExists}}IF EXISTS{{end}} {{.Name | sql}}
type DropPropertyGraph struct {
// pos = Drop
// end = Name.end

Drop token.Pos
IfExists bool
Name *Ident
}

// ================================================================================
//
// DML
Expand Down
23 changes: 23 additions & 0 deletions ast/ast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ func TestDDL(t *testing.T) {
DDL(&DropSequence{}).isDDL()
DDL(&CreateVectorIndex{}).isDDL()
DDL(&DropVectorIndex{}).isDDL()
DDL(&CreatePropertyGraph{}).isDDL()
DDL(&DropPropertyGraph{}).isDDL()
}

func TestConstraint(t *testing.T) {
Expand Down Expand Up @@ -212,3 +214,24 @@ func TestInsertInput(t *testing.T) {
InsertInput(&ValuesInput{}).isInsertInput()
InsertInput(&SubQueryInput{}).isInsertInput()
}

func TestPropertyGraphLabelsOrProperties(t *testing.T) {
PropertyGraphLabelsOrProperties(&PropertyGraphSingleProperties{}).isPropertyGraphLabelsOrProperties()
PropertyGraphLabelsOrProperties(&PropertyGraphLabelAndPropertiesList{}).isPropertyGraphLabelsOrProperties()
}

func TestPropertyGraphElementLabel(t *testing.T) {
PropertyGraphElementLabel(&PropertyGraphElementLabelLabelName{}).isPropertyGraphElementLabel()
PropertyGraphElementLabel(&PropertyGraphElementLabelDefaultLabel{}).isPropertyGraphElementLabel()
}

func TestPropertyGraphElementKeys(t *testing.T) {
PropertyGraphElementKeys(&PropertyGraphNodeElementKey{}).isPropertyGraphElementKeys()
PropertyGraphElementKeys(&PropertyGraphEdgeElementKeys{}).isPropertyGraphElementKeys()
}

func TestPropertyGraphElementProperties(t *testing.T) {
PropertyGraphElementProperties(&PropertyGraphNoProperties{}).isPropertyGraphElementProperties()
PropertyGraphElementProperties(&PropertyGraphPropertiesAre{}).isPropertyGraphElementProperties()
PropertyGraphElementProperties(&PropertyGraphDerivedPropertyList{}).isPropertyGraphElementProperties()
}
Loading
Loading