github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/processors/query/query-params-impl.go (about) 1 /* 2 * Copyright (c) 2021-present unTill Pro, Ltd. 3 */ 4 5 package queryprocessor 6 7 import ( 8 "fmt" 9 10 coreutils "github.com/voedger/voedger/pkg/utils" 11 ) 12 13 type queryParams struct { 14 elements []IElement 15 filters []IFilter 16 orderBy []IOrderBy 17 startFrom int64 18 count int64 19 } 20 21 func (p queryParams) Elements() []IElement { return p.elements } 22 func (p queryParams) Filters() []IFilter { return p.filters } 23 func (p queryParams) OrderBy() []IOrderBy { return p.orderBy } 24 func (p queryParams) StartFrom() int64 { return p.startFrom } 25 func (p queryParams) Count() int64 { return p.count } 26 27 func newQueryParams(data coreutils.MapObject, elementFactory ElementFactory, filterFactory FilterFactory, orderByFactory OrderByFactory, rootFieldsKinds FieldsKinds) (res IQueryParams, err error) { 28 qp := queryParams{} 29 if err = qp.fillArray(data, "elements", func(elem coreutils.MapObject) error { 30 element, err := elementFactory(elem) 31 if err == nil { 32 qp.elements = append(qp.elements, element) 33 } 34 return err 35 }); err != nil { 36 return nil, fmt.Errorf("elements: %w", err) 37 } 38 if err = qp.fillArray(data, "filters", func(elem coreutils.MapObject) error { 39 filter, err := filterFactory(elem) 40 if err == nil { 41 qp.filters = append(qp.filters, filter) 42 } 43 return err 44 }); err != nil { 45 return nil, fmt.Errorf("filters: %w", err) 46 } 47 if err = qp.fillArray(data, "orderBy", func(elem coreutils.MapObject) error { 48 orderBy, err := orderByFactory(elem) 49 if err == nil { 50 qp.orderBy = append(qp.orderBy, orderBy) 51 } 52 return err 53 }); err != nil { 54 return nil, fmt.Errorf("orderBy: %w", err) 55 } 56 if qp.count, _, err = data.AsInt64("count"); err != nil { 57 return nil, err 58 } 59 if qp.startFrom, _, err = data.AsInt64("startFrom"); err != nil { 60 return nil, err 61 } 62 return qp, qp.validate(rootFieldsKinds) 63 } 64 65 func (p *queryParams) fillArray(data coreutils.MapObject, fieldName string, cb func(elem coreutils.MapObject) error) error { 66 elems, _, err := data.AsObjects(fieldName) 67 for _, elemIntf := range elems { 68 elem, ok := elemIntf.(map[string]interface{}) 69 if !ok { 70 return fmt.Errorf("each member must be an object: %w", ErrWrongType) 71 } 72 if err = cb(elem); err != nil { 73 break 74 } 75 } 76 return err 77 } 78 79 func (p queryParams) validate(rootFieldsKinds FieldsKinds) (err error) { 80 pathPresent := make(map[string]bool) 81 for _, e := range p.elements { 82 if pathPresent[e.Path().Name()] { 83 return fmt.Errorf("elements: path '%s' must be unique", e.Path().Name()) 84 } 85 pathPresent[e.Path().Name()] = true 86 } 87 fields := make(map[string]bool) 88 for _, e := range p.elements { 89 if !e.Path().IsRoot() { 90 continue 91 } 92 for _, field := range e.ResultFields() { 93 if _, ok := rootFieldsKinds[field.Field()]; !ok { 94 return fmt.Errorf("elements: root element fields has field '%s' that is unexpected in root fields, please remove it: %w", field.Field(), ErrUnexpected) 95 } 96 fields[field.Field()] = true 97 } 98 for _, field := range e.RefFields() { 99 fields[field.Key()] = true 100 } 101 } 102 validateFilter := func(filter, field string) (err error) { 103 if _, ok := fields[field]; !ok { 104 return fmt.Errorf("'%s' filter has field '%s' that is absent in root element fields/refs, please add or change it: %w", filter, field, ErrUnexpected) 105 } 106 return nil 107 } 108 err = validateFilters(p.filters, validateFilter) 109 if err != nil { 110 return fmt.Errorf("filters: %w", err) 111 } 112 return p.validateOrderBy(fields) 113 } 114 115 func validateFilters(filters []IFilter, validateFilter func(filter, field string) (err error)) (err error) { 116 for _, f := range filters { 117 if err != nil { 118 return 119 } 120 switch filter := f.(type) { 121 case *EqualsFilter: 122 err = validateFilter(filterKind_Eq, filter.field) 123 case *NotEqualsFilter: 124 err = validateFilter(filterKind_NotEq, filter.field) 125 case *GreaterFilter: 126 err = validateFilter(filterKind_Gt, filter.field) 127 case *LessFilter: 128 err = validateFilter(filterKind_Lt, filter.field) 129 case *AndFilter: 130 err = validateFilters(filter.filters, validateFilter) 131 if err != nil { 132 err = fmt.Errorf("'%s' filter: %w", filterKind_And, err) 133 } 134 case *OrFilter: 135 err = validateFilters(filter.filters, validateFilter) 136 if err != nil { 137 err = fmt.Errorf("'%s' filter: %w", filterKind_Or, err) 138 } 139 } 140 } 141 return err 142 } 143 144 func (p queryParams) validateOrderBy(fields map[string]bool) (err error) { 145 for _, o := range p.orderBy { 146 if _, ok := fields[o.Field()]; !ok { 147 return fmt.Errorf("orderBy has field '%s' that is absent in root element fields/refs, please add or change it: %w", o.Field(), ErrUnexpected) 148 } 149 } 150 return nil 151 }