github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/sys/sqlquery/impl_records.go (about) 1 /* 2 * Copyright (c) 2022-present unTill Pro, Ltd. 3 */ 4 5 package sqlquery 6 7 import ( 8 "encoding/json" 9 "errors" 10 "fmt" 11 12 "github.com/blastrain/vitess-sqlparser/sqlparser" 13 14 "github.com/voedger/voedger/pkg/appdef" 15 "github.com/voedger/voedger/pkg/istructs" 16 "github.com/voedger/voedger/pkg/istructsmem" 17 coreutils "github.com/voedger/voedger/pkg/utils" 18 ) 19 20 func readRecords(wsid istructs.WSID, qName appdef.QName, expr sqlparser.Expr, appStructs istructs.IAppStructs, f *filter, callback istructs.ExecQueryCallback) error { 21 rr := make([]istructs.RecordGetBatchItem, 0) 22 23 findIDs := func(expr sqlparser.Expr) error { 24 switch r := expr.(type) { 25 case *sqlparser.ComparisonExpr: 26 if r.Left.(*sqlparser.ColName).Name.Lowered() != "id" { 27 return fmt.Errorf("unsupported column name: %s", r.Left.(*sqlparser.ColName).Name.String()) 28 } 29 switch r.Operator { 30 case sqlparser.EqualStr: 31 id, err := parseInt64(r.Right.(*sqlparser.SQLVal).Val) 32 if err != nil { 33 return err 34 } 35 rr = append(rr, istructs.RecordGetBatchItem{ID: istructs.RecordID(id)}) 36 case sqlparser.InStr: 37 for _, v := range r.Right.(sqlparser.ValTuple) { 38 id, err := parseInt64(v.(*sqlparser.SQLVal).Val) 39 if err != nil { 40 return err 41 } 42 rr = append(rr, istructs.RecordGetBatchItem{ID: istructs.RecordID(id)}) 43 } 44 default: 45 return fmt.Errorf("unsupported operation: %s", r.Operator) 46 } 47 case nil: 48 default: 49 return fmt.Errorf("unsupported expression: %T", r) 50 } 51 return nil 52 } 53 err := findIDs(expr) 54 if err != nil { 55 return err 56 } 57 58 if expr == nil { 59 r, e := appStructs.Records().GetSingleton(wsid, qName) 60 if e != nil { 61 if errors.Is(e, istructsmem.ErrNameNotFound) { 62 return fmt.Errorf("'%s' is not a singleton. Please specify at least one record ID", qName) 63 } 64 return e 65 } 66 rr = append(rr, istructs.RecordGetBatchItem{ID: r.ID()}) 67 } 68 69 if len(rr) == 0 { 70 return errors.New("you have to provide at least one record ID") 71 } 72 73 err = appStructs.Records().GetBatch(wsid, true, rr) 74 if err != nil { 75 return err 76 } 77 78 t := appStructs.AppDef().Type(qName) 79 80 if !f.acceptAll { 81 for field := range f.fields { 82 if t.(appdef.IFields).Field(field) == nil { 83 return fmt.Errorf("field '%s' not found in def", field) 84 } 85 } 86 } 87 88 for _, r := range rr { 89 if r.Record.QName() == appdef.NullQName { 90 return fmt.Errorf("record with ID '%d' not found", r.Record.ID()) 91 } 92 if r.Record.QName() != qName { 93 return fmt.Errorf("record with ID '%d' has mismatching QName '%s'", r.Record.ID(), r.Record.QName()) 94 } 95 96 data := coreutils.FieldsToMap(r.Record, appStructs.AppDef(), getFilter(f.filter)) 97 bb, e := json.Marshal(data) 98 if e != nil { 99 return e 100 } 101 102 e = callback(&result{value: string(bb)}) 103 if e != nil { 104 return e 105 } 106 } 107 108 return nil 109 }