github.com/CiscoM31/godata@v1.0.10/orderby_parser.go (about)

     1  package godata
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  )
     7  
     8  const (
     9  	ASC  = "asc"
    10  	DESC = "desc"
    11  )
    12  
    13  type OrderByItem struct {
    14  	Field *Token            // The raw value of the orderby field or expression.
    15  	Tree  *GoDataExpression // The orderby expression parsed as a tree.
    16  	Order string            // Ascending or descending order.
    17  }
    18  
    19  func ParseOrderByString(ctx context.Context, orderby string) (*GoDataOrderByQuery, error) {
    20  	return GlobalExpressionParser.ParseOrderByString(ctx, orderby)
    21  }
    22  
    23  // The value of the $orderby System Query option contains a comma-separated
    24  // list of expressions whose primitive result values are used to sort the items.
    25  // The service MUST order by the specified property in ascending order.
    26  // 4.01 services MUST support case-insensitive values for asc and desc.
    27  func (p *ExpressionParser) ParseOrderByString(ctx context.Context, orderby string) (*GoDataOrderByQuery, error) {
    28  	items := strings.Split(orderby, ",")
    29  
    30  	result := make([]*OrderByItem, 0)
    31  
    32  	for _, v := range items {
    33  		v = strings.TrimSpace(v)
    34  
    35  		cfg, hasComplianceConfig := ctx.Value(odataCompliance).(OdataComplianceConfig)
    36  		if !hasComplianceConfig {
    37  			// Strict ODATA compliance by default.
    38  			cfg = ComplianceStrict
    39  		}
    40  
    41  		if len(v) == 0 && cfg&ComplianceIgnoreInvalidComma == 0 {
    42  			return nil, BadRequestError("Extra comma in $orderby.")
    43  		}
    44  
    45  		var order string
    46  		vLower := strings.ToLower(v)
    47  		if strings.HasSuffix(vLower, " "+ASC) {
    48  			order = ASC
    49  		} else if strings.HasSuffix(vLower, " "+DESC) {
    50  			order = DESC
    51  		}
    52  		if order == "" {
    53  			order = ASC // default order
    54  		} else {
    55  			v = v[:len(v)-len(order)]
    56  			v = strings.TrimSpace(v)
    57  		}
    58  
    59  		if tree, err := p.ParseExpressionString(ctx, v); err != nil {
    60  			switch e := err.(type) {
    61  			case *GoDataError:
    62  				return nil, &GoDataError{
    63  					ResponseCode: e.ResponseCode,
    64  					Message:      "Invalid $orderby query option",
    65  					Cause:        e,
    66  				}
    67  			default:
    68  				return nil, &GoDataError{
    69  					ResponseCode: 500,
    70  					Message:      "Invalid $orderby query option",
    71  					Cause:        e,
    72  				}
    73  			}
    74  		} else {
    75  			result = append(result, &OrderByItem{
    76  				Field: &Token{Value: unescapeUtfEncoding(v)},
    77  				Tree:  tree,
    78  				Order: order,
    79  			})
    80  
    81  		}
    82  	}
    83  
    84  	return &GoDataOrderByQuery{result, orderby}, nil
    85  }
    86  
    87  func SemanticizeOrderByQuery(orderby *GoDataOrderByQuery, service *GoDataService, entity *GoDataEntityType) error {
    88  	if orderby == nil {
    89  		return nil
    90  	}
    91  
    92  	for _, item := range orderby.OrderByItems {
    93  		if prop, ok := service.PropertyLookup[entity][item.Field.Value]; ok {
    94  			item.Field.SemanticType = SemanticTypeProperty
    95  			item.Field.SemanticReference = prop
    96  		} else {
    97  			return BadRequestError("No property " + item.Field.Value + " for entity " + entity.Name)
    98  		}
    99  	}
   100  
   101  	return nil
   102  }