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

     1  /*
     2   * Copyright (c) 2022-present unTill Pro, Ltd.
     3   */
     4  
     5  package state
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  
    11  	"github.com/voedger/voedger/pkg/appdef"
    12  	"github.com/voedger/voedger/pkg/istructs"
    13  	"github.com/voedger/voedger/pkg/istructsmem"
    14  )
    15  
    16  type viewRecordsStorage struct {
    17  	ctx              context.Context
    18  	appStructsFunc   AppStructsFunc
    19  	wsidFunc         WSIDFunc
    20  	n10nFunc         N10nFunc
    21  	wsTypeVailidator wsTypeVailidator
    22  }
    23  
    24  func newViewRecordsStorage(ctx context.Context, appStructsFunc AppStructsFunc, wsidFunc WSIDFunc, n10nFunc N10nFunc) *viewRecordsStorage {
    25  	return &viewRecordsStorage{
    26  		ctx:              ctx,
    27  		appStructsFunc:   appStructsFunc,
    28  		wsidFunc:         wsidFunc,
    29  		n10nFunc:         n10nFunc,
    30  		wsTypeVailidator: newWsTypeValidator(appStructsFunc),
    31  	}
    32  }
    33  
    34  func (s *viewRecordsStorage) NewKeyBuilder(entity appdef.QName, _ istructs.IStateKeyBuilder) (newKeyBuilder istructs.IStateKeyBuilder) {
    35  	return &viewKeyBuilder{
    36  		IKeyBuilder: s.appStructsFunc().ViewRecords().KeyBuilder(entity),
    37  		view:        entity,
    38  		wsid:        s.wsidFunc(),
    39  	}
    40  }
    41  
    42  func (s *viewRecordsStorage) Get(key istructs.IStateKeyBuilder) (value istructs.IStateValue, err error) {
    43  	k := key.(*viewKeyBuilder)
    44  	err = s.wsTypeVailidator.validate(k.wsid, k.view)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	v, err := s.appStructsFunc().ViewRecords().Get(k.wsid, k.IKeyBuilder)
    49  	if err != nil {
    50  		if errors.Is(err, istructsmem.ErrRecordNotFound) {
    51  			return nil, nil
    52  		}
    53  		return nil, err
    54  	}
    55  	if v == nil {
    56  		return nil, nil
    57  	}
    58  	return &viewValue{
    59  		value: v,
    60  	}, nil
    61  }
    62  
    63  func (s *viewRecordsStorage) GetBatch(items []GetBatchItem) (err error) {
    64  	wsidToItemIdx := make(map[istructs.WSID][]int)
    65  	batches := make(map[istructs.WSID][]istructs.ViewRecordGetBatchItem)
    66  	for itemIdx, item := range items {
    67  		k := item.key.(*viewKeyBuilder)
    68  		if err = s.wsTypeVailidator.validate(k.wsid, k.view); err != nil {
    69  			return err
    70  		}
    71  		wsidToItemIdx[k.wsid] = append(wsidToItemIdx[k.wsid], itemIdx)
    72  		batches[k.wsid] = append(batches[k.wsid], istructs.ViewRecordGetBatchItem{Key: k.IKeyBuilder})
    73  	}
    74  	for wsid, batch := range batches {
    75  		err = s.appStructsFunc().ViewRecords().GetBatch(wsid, batch)
    76  		if err != nil {
    77  			return
    78  		}
    79  		for i, batchItem := range batch {
    80  			itemIndex := wsidToItemIdx[wsid][i]
    81  			if !batchItem.Ok {
    82  				continue
    83  			}
    84  			items[itemIndex].value = &viewValue{
    85  				value: batchItem.Value,
    86  			}
    87  		}
    88  	}
    89  	return err
    90  }
    91  func (s *viewRecordsStorage) Read(kb istructs.IStateKeyBuilder, callback istructs.ValueCallback) (err error) {
    92  	cb := func(k istructs.IKey, v istructs.IValue) (err error) {
    93  		return callback(k, &viewValue{
    94  			value: v,
    95  		})
    96  	}
    97  	k := kb.(*viewKeyBuilder)
    98  	if err = s.wsTypeVailidator.validate(k.wsid, k.view); err != nil {
    99  		return err
   100  	}
   101  	return s.appStructsFunc().ViewRecords().Read(s.ctx, k.wsid, k.IKeyBuilder, cb)
   102  }
   103  func (s *viewRecordsStorage) Validate([]ApplyBatchItem) (err error) { return err }
   104  func (s *viewRecordsStorage) ApplyBatch(items []ApplyBatchItem) (err error) {
   105  	batches := make(map[istructs.WSID][]istructs.ViewKV)
   106  	nn := make(map[n10n]istructs.Offset)
   107  	for _, item := range items {
   108  		k := item.key.(*viewKeyBuilder)
   109  		v := item.value.(*viewValueBuilder)
   110  		batches[k.wsid] = append(batches[k.wsid], istructs.ViewKV{Key: k.IKeyBuilder, Value: v.IValueBuilder})
   111  		if nn[n10n{wsid: k.wsid, view: k.view}] < v.offset {
   112  			nn[n10n{wsid: k.wsid, view: k.view}] = v.offset
   113  		}
   114  	}
   115  	var nullWsidBatch []istructs.ViewKV
   116  	for wsid, batch := range batches {
   117  		if wsid == istructs.NullWSID { // Actualizer offsets must be updated in the last order
   118  			nullWsidBatch = batch
   119  			continue
   120  		}
   121  		err = s.appStructsFunc().ViewRecords().PutBatch(wsid, batch)
   122  		if err != nil {
   123  			return err
   124  		}
   125  	}
   126  	if len(nullWsidBatch) > 0 {
   127  		err = s.appStructsFunc().ViewRecords().PutBatch(istructs.NullWSID, nullWsidBatch)
   128  		if err != nil {
   129  			return err
   130  		}
   131  	}
   132  	for n, newOffset := range nn {
   133  		s.n10nFunc(n.view, n.wsid, newOffset)
   134  	}
   135  	return err
   136  }
   137  func (s *viewRecordsStorage) ProvideValueBuilder(kb istructs.IStateKeyBuilder, _ istructs.IStateValueBuilder) (istructs.IStateValueBuilder, error) {
   138  	k := kb.(*viewKeyBuilder)
   139  	if err := s.wsTypeVailidator.validate(k.wsid, k.view); err != nil {
   140  		return nil, err
   141  	}
   142  	return &viewValueBuilder{
   143  		IValueBuilder: s.appStructsFunc().ViewRecords().NewValueBuilder(k.view),
   144  		offset:        istructs.NullOffset,
   145  		entity:        kb.Entity(),
   146  	}, nil
   147  }
   148  func (s *viewRecordsStorage) ProvideValueBuilderForUpdate(kb istructs.IStateKeyBuilder, existingValue istructs.IStateValue, _ istructs.IStateValueBuilder) (istructs.IStateValueBuilder, error) {
   149  	k := kb.(*viewKeyBuilder)
   150  	if err := s.wsTypeVailidator.validate(k.wsid, k.view); err != nil {
   151  		return nil, err
   152  	}
   153  	return &viewValueBuilder{
   154  		IValueBuilder: s.appStructsFunc().ViewRecords().UpdateValueBuilder(kb.(*viewKeyBuilder).view, existingValue.(*viewValue).value),
   155  		offset:        istructs.NullOffset,
   156  		entity:        kb.Entity(),
   157  	}, nil
   158  }