github.com/vescale/zgraph@v0.0.0-20230410094002-959c02d50f95/compiler/macro_expansion_test.go (about)

     1  // Copyright 2022 zGraph Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package compiler
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/stretchr/testify/assert"
    21  	"github.com/vescale/zgraph/parser"
    22  	"github.com/vescale/zgraph/parser/ast"
    23  	"github.com/vescale/zgraph/parser/opcode"
    24  )
    25  
    26  func TestMacroExpansion(t *testing.T) {
    27  	assert := assert.New(t)
    28  
    29  	cases := []struct {
    30  		query string
    31  		check func(node ast.Node)
    32  	}{
    33  		{
    34  			query: `PATH has_parent AS () -[:has_father|has_mother]-> (:Person)
    35  					SELECT ancestor.name
    36  					  FROM MATCH (p1:Person) -/:has_parent+/-> (ancestor)
    37  						 , MATCH (p2:Person) -/:has_parent+/-> (ancestor)
    38  					 WHERE p1.name = 'Mario'
    39  					   AND p2.name = 'Luigi'`,
    40  			check: func(node ast.Node) {
    41  				stmt := node.(*ast.SelectStmt)
    42  				assert.Equal(1, len(stmt.PathPatternMacros))
    43  				expr := stmt.From.Matches[0].Paths[0].Connections[0].(*ast.ReachabilityPathExpr)
    44  				assert.Equal(expr.Macros["has_parent"], stmt.PathPatternMacros[0].Path)
    45  			},
    46  		},
    47  		{
    48  			query: `PATH connects_to AS (:Generator) -[:has_connector]-> (c:Connector) <-[:has_connector]- (:Generator)
    49  					  WHERE c.status = 'OPERATIONAL'
    50  					SELECT generatorA.location, generatorB.location
    51  					  FROM MATCH (generatorA) -/:connects_to+/-> (generatorB)`,
    52  			check: func(node ast.Node) {
    53  				stmt := node.(*ast.SelectStmt)
    54  				assert.Equal(1, len(stmt.PathPatternMacros))
    55  				expr := stmt.From.Matches[0].Paths[0].Connections[0].(*ast.ReachabilityPathExpr)
    56  				assert.Equal(expr.Macros["connects_to"], stmt.PathPatternMacros[0].Path)
    57  				assert.NotNil(stmt.Where)
    58  			},
    59  		},
    60  		{
    61  			query: `PATH connects_to AS (:Generator) -[:has_connector]-> (c:Connector) <-[:has_connector]- (:Generator)
    62  					  WHERE c.status = 'OPERATIONAL'
    63  					PATH has_parent AS () -[:has_father|has_mother]-> (:Person)
    64  					SELECT generatorA.location, generatorB.location
    65  					  FROM MATCH (generatorA) -/:connects_to|has_parent+/-> (generatorB)`,
    66  			check: func(node ast.Node) {
    67  				stmt := node.(*ast.SelectStmt)
    68  				assert.Equal(2, len(stmt.PathPatternMacros))
    69  				expr := stmt.From.Matches[0].Paths[0].Connections[0].(*ast.ReachabilityPathExpr)
    70  				assert.Equal(expr.Macros["connects_to"], stmt.PathPatternMacros[0].Path)
    71  				assert.Equal(expr.Macros["has_parent"], stmt.PathPatternMacros[1].Path)
    72  				assert.NotNil(stmt.Where)
    73  			},
    74  		},
    75  		{
    76  			query: `PATH connects_to AS (:Generator) -[:has_connector]-> (c:Connector) <-[:has_connector]- (:Generator)
    77  					  WHERE c.status = 'OPERATIONAL'
    78  					PATH has_parent AS () -[f:has_father|has_mother]-> (:Person)
    79  					  WHERE f.age > 30
    80  					SELECT generatorA.location, generatorB.location
    81  					  FROM MATCH (generatorA) -/:connects_to|has_parent+/-> (generatorB)`,
    82  			check: func(node ast.Node) {
    83  				stmt := node.(*ast.SelectStmt)
    84  				assert.Equal(2, len(stmt.PathPatternMacros))
    85  				expr := stmt.From.Matches[0].Paths[0].Connections[0].(*ast.ReachabilityPathExpr)
    86  				assert.Equal(expr.Macros["connects_to"], stmt.PathPatternMacros[0].Path)
    87  				assert.Equal(expr.Macros["has_parent"], stmt.PathPatternMacros[1].Path)
    88  				assert.NotNil(stmt.Where)
    89  				logicalAnd := stmt.Where.(*ast.BinaryExpr)
    90  				assert.Equal(opcode.LogicAnd, logicalAnd.Op)
    91  			},
    92  		},
    93  		{
    94  			query: `PATH connects_to AS (:Generator) -[:has_connector]-> (c:Connector) <-[:has_connector]- (:Generator)
    95  					  WHERE c.status = 'OPERATIONAL'
    96  					PATH has_parent AS () -[f:has_father|has_mother]-> (:Person)
    97  					  WHERE f.age > 30
    98  					SELECT generatorA.location, generatorB.location
    99  					  FROM MATCH (generatorA) -/:connects_to|has_parent+/-> (generatorB)
   100  					 WHERE a > 10`,
   101  			check: func(node ast.Node) {
   102  				stmt := node.(*ast.SelectStmt)
   103  				assert.Equal(2, len(stmt.PathPatternMacros))
   104  				expr := stmt.From.Matches[0].Paths[0].Connections[0].(*ast.ReachabilityPathExpr)
   105  				assert.Equal(expr.Macros["connects_to"], stmt.PathPatternMacros[0].Path)
   106  				assert.Equal(expr.Macros["has_parent"], stmt.PathPatternMacros[1].Path)
   107  				assert.NotNil(stmt.Where)
   108  				logicalAnd := stmt.Where.(*ast.BinaryExpr)
   109  				assert.Equal(opcode.LogicAnd, logicalAnd.Op)
   110  				logicalEq := logicalAnd.L.(*ast.BinaryExpr)
   111  				assert.Equal(opcode.GT, logicalEq.Op) //  a > 10
   112  				logicalAnd = logicalAnd.R.(*ast.BinaryExpr)
   113  				assert.Equal(opcode.LogicAnd, logicalAnd.Op)
   114  			},
   115  		},
   116  	}
   117  
   118  	for _, c := range cases {
   119  		parser := parser.New()
   120  		stmt, err := parser.ParseOneStmt(c.query)
   121  		assert.Nil(err)
   122  
   123  		exp := NewMacroExpansion()
   124  		n, ok := stmt.Accept(exp)
   125  		assert.True(ok)
   126  		c.check(n)
   127  	}
   128  }