github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/state/impl_records_storage.go (about)

     1  /*
     2   * Copyright (c) 2022-present unTill Pro, Ltd.
     3   */
     4  
     5  package state
     6  
     7  import (
     8  	"fmt"
     9  
    10  	"github.com/voedger/voedger/pkg/appdef"
    11  	"github.com/voedger/voedger/pkg/istructs"
    12  )
    13  
    14  type recordsStorage struct {
    15  	recordsFunc      recordsFunc
    16  	cudFunc          CUDFunc
    17  	wsidFunc         WSIDFunc
    18  	wsTypeVailidator wsTypeVailidator
    19  }
    20  
    21  func newRecordsStorage(appStructsFunc AppStructsFunc, wsidFunc WSIDFunc, cudFunc CUDFunc) *recordsStorage {
    22  	return &recordsStorage{
    23  		recordsFunc:      func() istructs.IRecords { return appStructsFunc().Records() },
    24  		wsidFunc:         wsidFunc,
    25  		cudFunc:          cudFunc,
    26  		wsTypeVailidator: newWsTypeValidator(appStructsFunc),
    27  	}
    28  }
    29  
    30  func (s *recordsStorage) NewKeyBuilder(entity appdef.QName, _ istructs.IStateKeyBuilder) istructs.IStateKeyBuilder {
    31  	return &recordsKeyBuilder{
    32  		id:        istructs.NullRecordID,
    33  		singleton: appdef.NullQName,
    34  		wsid:      s.wsidFunc(),
    35  		entity:    entity,
    36  	}
    37  }
    38  
    39  func (s *recordsStorage) Get(key istructs.IStateKeyBuilder) (value istructs.IStateValue, err error) {
    40  	k := key.(*recordsKeyBuilder)
    41  	if k.singleton != appdef.NullQName {
    42  		err = s.wsTypeVailidator.validate(k.wsid, k.singleton)
    43  		if err != nil {
    44  			return nil, err
    45  		}
    46  		singleton, e := s.recordsFunc().GetSingleton(k.wsid, k.singleton)
    47  		if e != nil {
    48  			return nil, e
    49  		}
    50  		if singleton.QName() == appdef.NullQName {
    51  			return nil, nil
    52  		}
    53  		return &recordsValue{record: singleton}, nil
    54  	}
    55  	if k.id == istructs.NullRecordID {
    56  		// error message according to https://dev.untill.com/projects/#!637229
    57  		return nil, fmt.Errorf("value of one of RecordID fields is 0: %w", ErrNotFound)
    58  	}
    59  	record, err := s.recordsFunc().Get(k.wsid, true, k.id)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	if record.QName() == appdef.NullQName {
    64  		return nil, nil
    65  	}
    66  	return &recordsValue{record: record}, nil
    67  }
    68  
    69  func (s *recordsStorage) GetBatch(items []GetBatchItem) (err error) {
    70  	type getSingletonParams struct {
    71  		wsid    istructs.WSID
    72  		qname   appdef.QName
    73  		itemIdx int
    74  	}
    75  	wsidToItemIdx := make(map[istructs.WSID][]int)
    76  	batches := make(map[istructs.WSID][]istructs.RecordGetBatchItem)
    77  	gg := make([]getSingletonParams, 0)
    78  	for itemIdx, item := range items {
    79  		k := item.key.(*recordsKeyBuilder)
    80  		if k.singleton != appdef.NullQName {
    81  			err = s.wsTypeVailidator.validate(k.wsid, k.singleton)
    82  			if err != nil {
    83  				return err
    84  			}
    85  			gg = append(gg, getSingletonParams{
    86  				wsid:    k.wsid,
    87  				qname:   k.singleton,
    88  				itemIdx: itemIdx,
    89  			})
    90  			continue
    91  		}
    92  		if k.id == istructs.NullRecordID {
    93  			// error message according to https://dev.untill.com/projects/#!637229
    94  			return fmt.Errorf("value of one of RecordID fields is 0: %w", ErrNotFound)
    95  		}
    96  		wsidToItemIdx[k.wsid] = append(wsidToItemIdx[k.wsid], itemIdx)
    97  		batches[k.wsid] = append(batches[k.wsid], istructs.RecordGetBatchItem{ID: k.id})
    98  	}
    99  	for wsid, batch := range batches {
   100  		err = s.recordsFunc().GetBatch(wsid, true, batch)
   101  		if err != nil {
   102  			return
   103  		}
   104  		for i, batchItem := range batch {
   105  			if batchItem.Record.QName() == appdef.NullQName {
   106  				continue
   107  			}
   108  			items[wsidToItemIdx[wsid][i]].value = &recordsValue{record: batchItem.Record}
   109  		}
   110  	}
   111  	for _, g := range gg {
   112  		singleton, e := s.recordsFunc().GetSingleton(g.wsid, g.qname)
   113  		if e != nil {
   114  			return e
   115  		}
   116  		if singleton.QName() == appdef.NullQName {
   117  			continue
   118  		}
   119  		items[g.itemIdx].value = &recordsValue{record: singleton}
   120  	}
   121  	return err
   122  }
   123  func (s *recordsStorage) Validate([]ApplyBatchItem) (err error)   { return }
   124  func (s *recordsStorage) ApplyBatch([]ApplyBatchItem) (err error) { return }
   125  func (s *recordsStorage) ProvideValueBuilder(key istructs.IStateKeyBuilder, _ istructs.IStateValueBuilder) (istructs.IStateValueBuilder, error) {
   126  	kb := key.(*recordsKeyBuilder)
   127  	if kb.entity == appdef.NullQName {
   128  		return nil, errEntityRequiredForValueBuilder
   129  	}
   130  	err := s.wsTypeVailidator.validate(kb.wsid, kb.entity)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	rw := s.cudFunc().Create(kb.entity)
   135  	return &recordsValueBuilder{rw: rw}, nil
   136  }
   137  func (s *recordsStorage) ProvideValueBuilderForUpdate(_ istructs.IStateKeyBuilder, existingValue istructs.IStateValue, _ istructs.IStateValueBuilder) (istructs.IStateValueBuilder, error) {
   138  	return &recordsValueBuilder{rw: s.cudFunc().Update(existingValue.AsRecord(""))}, nil
   139  }