github.com/vescale/zgraph@v0.0.0-20230410094002-959c02d50f95/compiler/property_preparation.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 "github.com/pingcap/errors" 19 "github.com/vescale/zgraph/catalog" 20 "github.com/vescale/zgraph/meta" 21 "github.com/vescale/zgraph/parser/ast" 22 "github.com/vescale/zgraph/parser/model" 23 "github.com/vescale/zgraph/stmtctx" 24 "github.com/vescale/zgraph/storage/kv" 25 ) 26 27 // PropertyPreparation is used to create property lazily. In zGraph: only Graph/Label/Index 28 // objects are required to create explicitly. All properties will be created at the first 29 // time to be used. 30 // The PropertyPreparation will visit the whole AST and find 31 type PropertyPreparation struct { 32 sc *stmtctx.Context 33 // Missing properties (lower case) 34 missing []string 35 graph *catalog.Graph 36 } 37 38 func NewPropertyPreparation(sc *stmtctx.Context) *PropertyPreparation { 39 return &PropertyPreparation{ 40 sc: sc, 41 graph: sc.CurrentGraph(), 42 } 43 } 44 45 func (p *PropertyPreparation) Enter(n ast.Node) (node ast.Node, skipChildren bool) { 46 switch node := n.(type) { 47 case *ast.InsertStmt: 48 if !node.IntoGraphName.IsEmpty() { 49 p.graph = p.sc.Catalog().Graph(node.IntoGraphName.L) 50 } 51 case *ast.PropertyAccess: 52 p.checkExistence(node.PropertyName) 53 54 } 55 return n, false 56 } 57 58 func (p *PropertyPreparation) checkExistence(propName model.CIStr) { 59 prop := p.graph.Property(propName.L) 60 if prop == nil { 61 p.missing = append(p.missing, propName.L) 62 } 63 } 64 65 func (p *PropertyPreparation) Leave(n ast.Node) (node ast.Node, ok bool) { 66 return n, true 67 } 68 69 // CreateMissing creates the missing properties. 70 func (p *PropertyPreparation) CreateMissing() error { 71 if len(p.missing) == 0 { 72 return nil 73 } 74 75 p.sc.Catalog().MDLock() 76 defer p.sc.Catalog().MDUnlock() 77 78 var patch *catalog.PatchProperties 79 err := kv.Txn(p.sc.Store(), func(txn kv.Transaction) error { 80 graphInfo := p.graph.Meta() 81 nextPropID := graphInfo.NextPropID 82 meta := meta.New(txn) 83 var properties []*model.PropertyInfo 84 for _, propName := range p.missing { 85 nextPropID++ 86 propertyInfo := &model.PropertyInfo{ 87 ID: nextPropID, 88 Name: model.NewCIStr(propName), 89 } 90 err := meta.CreateProperty(graphInfo.ID, propertyInfo) 91 if err != nil { 92 return errors.Annotatef(err, "create property") 93 } 94 properties = append(properties, propertyInfo) 95 } 96 97 cloned := graphInfo.Clone() 98 cloned.NextPropID = nextPropID 99 err := meta.UpdateGraph(cloned) 100 if err != nil { 101 return errors.Annotatef(err, "update graph") 102 } 103 104 patch = &catalog.PatchProperties{ 105 MaxPropID: nextPropID, 106 GraphID: graphInfo.ID, 107 Properties: properties, 108 } 109 return nil 110 }) 111 if err != nil { 112 return errors.Trace(err) 113 } 114 115 p.sc.Catalog().Apply(&catalog.Patch{ 116 Type: catalog.PatchTypeCreateProperties, 117 Data: patch, 118 }) 119 120 return nil 121 }