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  }