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  }