github.com/cilium/statedb@v0.3.2/any_table.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package statedb
     5  
     6  import (
     7  	"fmt"
     8  	"iter"
     9  )
    10  
    11  // AnyTable allows any-typed access to a StateDB table. This is intended
    12  // for building generic tooling for accessing the table and should be
    13  // avoided if possible.
    14  type AnyTable struct {
    15  	Meta TableMeta
    16  }
    17  
    18  func (t AnyTable) All(txn ReadTxn) iter.Seq2[any, Revision] {
    19  	all, _ := t.AllWatch(txn)
    20  	return all
    21  }
    22  
    23  func (t AnyTable) AllWatch(txn ReadTxn) (iter.Seq2[any, Revision], <-chan struct{}) {
    24  	indexTxn := txn.getTxn().mustIndexReadTxn(t.Meta, PrimaryIndexPos)
    25  	return partSeq[any](indexTxn.Iterator()), indexTxn.RootWatch()
    26  }
    27  
    28  func (t AnyTable) UnmarshalYAML(data []byte) (any, error) {
    29  	return t.Meta.unmarshalYAML(data)
    30  }
    31  
    32  func (t AnyTable) Insert(txn WriteTxn, obj any) (old any, hadOld bool, err error) {
    33  	var iobj object
    34  	iobj, hadOld, err = txn.getTxn().insert(t.Meta, Revision(0), obj)
    35  	if hadOld {
    36  		old = iobj.data
    37  	}
    38  	return
    39  }
    40  
    41  func (t AnyTable) Delete(txn WriteTxn, obj any) (old any, hadOld bool, err error) {
    42  	var iobj object
    43  	iobj, hadOld, err = txn.getTxn().delete(t.Meta, Revision(0), obj)
    44  	if hadOld {
    45  		old = iobj.data
    46  	}
    47  	return
    48  }
    49  
    50  func (t AnyTable) Get(txn ReadTxn, index string, key string) (any, Revision, bool, error) {
    51  	itxn, rawKey, err := t.queryIndex(txn, index, key)
    52  	if err != nil {
    53  		return nil, 0, false, err
    54  	}
    55  	if itxn.unique {
    56  		obj, _, ok := itxn.Get(rawKey)
    57  		return obj.data, obj.revision, ok, nil
    58  	}
    59  	// For non-unique indexes we need to prefix search and make sure to fully
    60  	// match the secondary key.
    61  	iter, _ := itxn.Prefix(rawKey)
    62  	for {
    63  		k, obj, ok := iter.Next()
    64  		if !ok {
    65  			break
    66  		}
    67  		secondary, _ := decodeNonUniqueKey(k)
    68  		if len(secondary) == len(rawKey) {
    69  			return obj.data, obj.revision, true, nil
    70  		}
    71  	}
    72  	return nil, 0, false, nil
    73  }
    74  
    75  func (t AnyTable) Prefix(txn ReadTxn, index string, key string) (iter.Seq2[any, Revision], error) {
    76  	itxn, rawKey, err := t.queryIndex(txn, index, key)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	iter, _ := itxn.Prefix(rawKey)
    81  	if itxn.unique {
    82  		return partSeq[any](iter), nil
    83  	}
    84  	return nonUniqueSeq[any](iter, true, rawKey), nil
    85  }
    86  
    87  func (t AnyTable) LowerBound(txn ReadTxn, index string, key string) (iter.Seq2[any, Revision], error) {
    88  	itxn, rawKey, err := t.queryIndex(txn, index, key)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	iter := itxn.LowerBound(rawKey)
    93  	if itxn.unique {
    94  		return partSeq[any](iter), nil
    95  	}
    96  	return nonUniqueLowerBoundSeq[any](iter, rawKey), nil
    97  }
    98  
    99  func (t AnyTable) List(txn ReadTxn, index string, key string) (iter.Seq2[any, Revision], error) {
   100  	itxn, rawKey, err := t.queryIndex(txn, index, key)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	iter, _ := itxn.Prefix(rawKey)
   105  	if itxn.unique {
   106  		// Unique index means that there can be only a single matching object.
   107  		// Doing a Get() is more efficient than constructing an iterator.
   108  		value, _, ok := itxn.Get(rawKey)
   109  		return func(yield func(any, Revision) bool) {
   110  			if ok {
   111  				yield(value.data, value.revision)
   112  			}
   113  		}, nil
   114  	}
   115  	return nonUniqueSeq[any](iter, false, rawKey), nil
   116  }
   117  
   118  func (t AnyTable) queryIndex(txn ReadTxn, index string, key string) (indexReadTxn, []byte, error) {
   119  	indexer := t.Meta.getIndexer(index)
   120  	if indexer == nil {
   121  		return indexReadTxn{}, nil, fmt.Errorf("invalid index %q", index)
   122  	}
   123  	rawKey, err := indexer.fromString(key)
   124  	if err != nil {
   125  		return indexReadTxn{}, nil, err
   126  	}
   127  	itxn, err := txn.getTxn().indexReadTxn(t.Meta, indexer.pos)
   128  	return itxn, rawKey, err
   129  }
   130  
   131  func (t AnyTable) Changes(txn WriteTxn) (anyChangeIterator, error) {
   132  	return t.Meta.anyChanges(txn)
   133  }
   134  
   135  func (t AnyTable) TableHeader() []string {
   136  	zero := t.Meta.proto()
   137  	if tw, ok := zero.(TableWritable); ok {
   138  		return tw.TableHeader()
   139  	}
   140  	return nil
   141  }
   142  
   143  func (t AnyTable) Proto() any {
   144  	return t.Meta.proto()
   145  }