go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/gae/service/datastore/raw_interface.go (about)

     1  // Copyright 2015 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package datastore
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  )
    21  
    22  // Cursor wraps datastore.Cursor.
    23  type Cursor interface {
    24  	fmt.Stringer
    25  }
    26  
    27  // CursorCB is used to obtain a Cursor while Run'ing a query on either
    28  // Interface or RawInterface.
    29  //
    30  // it can be invoked to obtain the current cursor.
    31  type CursorCB func() (Cursor, error)
    32  
    33  // RawRunCB is the callback signature provided to RawInterface.Run
    34  //
    35  //   - key is the Key of the entity
    36  //   - val is the data of the entity (or nil, if the query was keys-only)
    37  //
    38  // Return nil to continue iterating through the query results, or an error to
    39  // stop. If you return the error `Stop`, then Run will stop the query and
    40  // return nil.
    41  type RawRunCB func(key *Key, val PropertyMap, getCursor CursorCB) error
    42  
    43  // GetMultiCB is the callback signature provided to RawInterface.GetMulti
    44  //
    45  //   - idx is the index of the entity, ranging from 0 through len-1.
    46  //   - val is the data of the entity
    47  //   - It may be nil if some of the keys to the GetMulti were bad, since all
    48  //     keys are validated before the RPC occurs!
    49  //   - err is an error associated with this entity (e.g. ErrNoSuchEntity).
    50  //
    51  // The callback is called once per element. It may be called concurrently, and
    52  // may be called out of order. The "idx" variable describes which element is
    53  // being processed. If any callbacks are invoked, exactly one callback will be
    54  // invoked for each supplied element.
    55  type GetMultiCB func(idx int, val PropertyMap, err error)
    56  
    57  // NewKeyCB is the callback signature provided to RawInterface.PutMulti and
    58  // RawInterface.AllocateIDs. It is invoked once for each positional key that
    59  // was generated as the result of a call.
    60  //
    61  //   - idx is the index of the entity, ranging from 0 through len-1.
    62  //   - key is the new key for the entity (if the original was incomplete)
    63  //   - It may be nil if some of the keys/vals to the PutMulti were bad, since
    64  //     all keys are validated before the RPC occurs!
    65  //   - err is an error associated with putting this entity.
    66  //
    67  // The callback is called once per element. It may be called concurrently, and
    68  // may be called out of order. The "idx" variable describes which element is
    69  // being processed. If any callbacks are invoked, exactly one callback will be
    70  // invoked for each supplied element.
    71  type NewKeyCB func(idx int, key *Key, err error)
    72  
    73  // DeleteMultiCB is the callback signature provided to RawInterface.DeleteMulti
    74  //
    75  //   - idx is the index of the entity, ranging from 0 through len-1.
    76  //   - err is an error associated with deleting this entity.
    77  //
    78  // The callback is called once per element. It may be called concurrently, and
    79  // may be called out of order. The "idx" variable describes which element is
    80  // being processed. If any callbacks are invoked, exactly one callback will be
    81  // invoked for each supplied element.
    82  type DeleteMultiCB func(idx int, err error)
    83  
    84  // Constraints represent implementation constraints.
    85  //
    86  // A zero-value Constraints is valid, and indicates that no constraints are
    87  // present.
    88  type Constraints struct {
    89  	// MaxGetSize is the maximum number of entities that can be referenced in a
    90  	// single GetMulti call. If <= 0, no constraint is applied.
    91  	MaxGetSize int
    92  	// MaxPutSize is the maximum number of entities that can be referenced in a
    93  	// single PutMulti call. If <= 0, no constraint is applied.
    94  	MaxPutSize int
    95  	// MaxDeleteSize is the maximum number of entities that can be referenced in a
    96  	// single DeleteMulti call. If <= 0, no constraint is applied.
    97  	MaxDeleteSize int
    98  }
    99  
   100  type nullMetaGetterType struct{}
   101  
   102  func (nullMetaGetterType) GetMeta(string) (any, bool) { return nil, false }
   103  
   104  var nullMetaGetter MetaGetter = nullMetaGetterType{}
   105  
   106  // MultiMetaGetter is a carrier for metadata, used with RawInterface.GetMulti
   107  //
   108  // It's OK to default-construct this. GetMeta will just return
   109  // (nil, ErrMetaFieldUnset) for every index.
   110  type MultiMetaGetter []MetaGetter
   111  
   112  // NewMultiMetaGetter returns a new MultiMetaGetter object. data may be nil.
   113  func NewMultiMetaGetter(data []PropertyMap) MultiMetaGetter {
   114  	if len(data) == 0 {
   115  		return nil
   116  	}
   117  	inner := make(MultiMetaGetter, len(data))
   118  	for i, pm := range data {
   119  		inner[i] = pm
   120  	}
   121  	return inner
   122  }
   123  
   124  // GetMeta is like PropertyLoadSaver.GetMeta, but it also takes an index
   125  // indicating which slot you want metadata for. If idx isn't there, this
   126  // returns (nil, ErrMetaFieldUnset).
   127  func (m MultiMetaGetter) GetMeta(idx int, key string) (any, bool) {
   128  	return m.GetSingle(idx).GetMeta(key)
   129  }
   130  
   131  // GetSingle gets a single MetaGetter at the specified index.
   132  func (m MultiMetaGetter) GetSingle(idx int) MetaGetter {
   133  	if idx >= len(m) || m[idx] == nil {
   134  		return nullMetaGetter
   135  	}
   136  	return m[idx]
   137  }
   138  
   139  // RawInterface implements the datastore functionality without any of the fancy
   140  // reflection stuff. This is so that Filters can avoid doing lots of redundant
   141  // reflection work. See datastore.Interface for a more user-friendly interface.
   142  type RawInterface interface {
   143  	// AllocateIDs allows you to allocate IDs from the datastore without putting
   144  	// any data. The supplied keys must be PartialValid and share the same entity
   145  	// type.
   146  	//
   147  	// If there's no error, the keys in the slice will be replaced with keys
   148  	// containing integer IDs assigned to them.
   149  	AllocateIDs(keys []*Key, cb NewKeyCB) error
   150  
   151  	// RunInTransaction runs f in a transaction.
   152  	//
   153  	// opts may be nil.
   154  	//
   155  	// NOTE: Implementations and filters are guaranteed that:
   156  	//   - f is not nil
   157  	RunInTransaction(f func(c context.Context) error, opts *TransactionOptions) error
   158  
   159  	// DecodeCursor converts a string returned by a Cursor into a Cursor instance.
   160  	// It will return an error if the supplied string is not valid, or could not
   161  	// be decoded by the implementation.
   162  	DecodeCursor(s string) (Cursor, error)
   163  
   164  	// Run executes the given query, and calls `cb` for each successfully item.
   165  	//
   166  	// NOTE: Implementations and filters are guaranteed that:
   167  	//   - query is not nil
   168  	//   - cb is not nil
   169  	Run(q *FinalizedQuery, cb RawRunCB) error
   170  
   171  	// Count executes the given query and returns the number of entries which
   172  	// match it.
   173  	Count(q *FinalizedQuery) (int64, error)
   174  
   175  	// GetMulti retrieves items from the datastore.
   176  	//
   177  	// If there was a server error, it will be returned directly. Otherwise,
   178  	// callback will execute once per key/value pair, returning either the
   179  	// operation result or individual error for each position. If the callback
   180  	// receives an error, it will immediately forward that error and stop
   181  	// subsequent callbacks.
   182  	//
   183  	// meta is used to propagate metadata from higher levels.
   184  	//
   185  	// NOTE: Implementations and filters are guaranteed that:
   186  	//   - len(keys) > 0
   187  	//   - all keys are Valid, !Incomplete, and in the current namespace
   188  	//   - cb is not nil
   189  	GetMulti(keys []*Key, meta MultiMetaGetter, cb GetMultiCB) error
   190  
   191  	// PutMulti writes items to the datastore.
   192  	//
   193  	// If there was a server error, it will be returned directly. Otherwise,
   194  	// callback will execute once per key/value pair, returning either the
   195  	// operation result or individual error for each position. If the callback
   196  	// receives an error, it will immediately forward that error and stop
   197  	// subsequent callbacks.
   198  	//
   199  	// NOTE: Implementations and filters are guaranteed that:
   200  	//   - len(keys) > 0
   201  	//   - len(keys) == len(vals)
   202  	//   - all keys are Valid and in the current namespace
   203  	//   - cb is not nil
   204  	PutMulti(keys []*Key, vals []PropertyMap, cb NewKeyCB) error
   205  
   206  	// DeleteMulti removes items from the datastore.
   207  	//
   208  	// If there was a server error, it will be returned directly. Otherwise,
   209  	// callback will execute once per key/value pair, returning either the
   210  	// operation result or individual error for each position. If the callback
   211  	// receives an error, it will immediately forward that error and stop
   212  	// subsequent callbacks.
   213  	//
   214  	// NOTE: Implementations and filters are guaranteed that
   215  	//   - len(keys) > 0
   216  	//   - all keys are Valid, !Incomplete, and in the current namespace
   217  	//   - none keys of the keys are 'special' (use a kind prefixed with '__')
   218  	//   - cb is not nil
   219  	DeleteMulti(keys []*Key, cb DeleteMultiCB) error
   220  
   221  	// WithoutTransaction returns a derived Context without a transaction applied.
   222  	// This may be called even when outside of a transaction, in which case the
   223  	// input Context is a valid return value.
   224  	WithoutTransaction() context.Context
   225  
   226  	// CurrentTransaction returns a reference to the current Transaction, or nil
   227  	// if the Context does not have a current Transaction.
   228  	CurrentTransaction() Transaction
   229  
   230  	// Constraints returns this implementation's constraints.
   231  	Constraints() Constraints
   232  
   233  	// GetTestable returns the Testable interface for the implementation, or nil
   234  	// if there is none.
   235  	GetTestable() Testable
   236  }