github.com/cornelk/go-cloud@v0.17.1/docstore/driver/driver.go (about)

     1  // Copyright 2019 The Go Cloud Development Kit 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  //     https://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 driver defines interfaces to be implemented by docstore drivers, which
    16  // will be used by the docstore package to interact with the underlying services.
    17  // Application code should use package docstore.
    18  package driver // import "github.com/cornelk/go-cloud/docstore/driver"
    19  
    20  import (
    21  	"context"
    22  
    23  	"github.com/cornelk/go-cloud/internal/gcerr"
    24  )
    25  
    26  // A Collection is a set of documents.
    27  type Collection interface {
    28  	// Key returns the document key, or nil if the document doesn't have one, which
    29  	// means it is absent or zero value, such as 0, a nil interface value, and any
    30  	// empty array or string.
    31  	//
    32  	// If the collection is able to generate a key for a Create action, then
    33  	// it should not return an error if the key is missing. If the collection
    34  	// can't generate a missing key, it should return an error.
    35  	//
    36  	// The returned key must be comparable.
    37  	//
    38  	// The returned key should not be encoded with the driver's codec; it should
    39  	// be the user-supplied Go value.
    40  	Key(Document) (interface{}, error)
    41  
    42  	// RevisionField returns the name of the field used to hold revisions.
    43  	// If the empty string is returned, docstore.DefaultRevisionField will be used.
    44  	RevisionField() string
    45  
    46  	// RunActions executes a slice of actions.
    47  	//
    48  	// If unordered is false, it must appear as if the actions were executed in the
    49  	// order they appear in the slice, from the client's point of view. The actions
    50  	// need not happen atomically, nor does eventual consistency in the service
    51  	// need to be taken into account. For example, after a write returns
    52  	// successfully, the driver can immediately perform a read on the same document,
    53  	// even though the service's semantics does not guarantee that the read will see
    54  	// the write. RunActions should return immediately after the first action that fails.
    55  	// The returned slice should have a single element.
    56  	//
    57  	// opts controls the behavior of RunActions and is guaranteed to be non-nil.
    58  	RunActions(ctx context.Context, actions []*Action, opts *RunActionsOptions) ActionListError
    59  
    60  	// RunGetQuery executes a Query.
    61  	//
    62  	// Implementations can choose to execute the Query as one single request or
    63  	// multiple ones, depending on their service offerings. The portable type
    64  	// exposes OpenCensus metrics for the call to RunGetQuery (but not for
    65  	// subsequent calls to DocumentIterator.Next), so drivers should prefer to
    66  	// make at least one RPC during RunGetQuery itself instead of lazily waiting
    67  	// for the first call to Next.
    68  	RunGetQuery(context.Context, *Query) (DocumentIterator, error)
    69  
    70  	// QueryPlan returns the plan for the query.
    71  	QueryPlan(*Query) (string, error)
    72  
    73  	// RevisionToBytes converts a revision to a byte slice.
    74  	RevisionToBytes(interface{}) ([]byte, error)
    75  
    76  	// BytesToRevision converts a []byte to a revision.
    77  	BytesToRevision([]byte) (interface{}, error)
    78  
    79  	// As converts i to driver-specific types.
    80  	// See https://github.com/cornelk/go-cloud/concepts/as/ for background information.
    81  	As(i interface{}) bool
    82  
    83  	// ErrorAs allows drivers to expose driver-specific types for returned
    84  	// errors.
    85  	//
    86  	// See https://github.com/cornelk/go-cloud/concepts/as/ for background information.
    87  	ErrorAs(err error, i interface{}) bool
    88  
    89  	// ErrorCode should return a code that describes the error, which was returned by
    90  	// one of the other methods in this interface.
    91  	ErrorCode(error) gcerr.ErrorCode
    92  
    93  	// Close cleans up any resources used by the Collection. Once Close is called,
    94  	// there will be no method calls to the Collection other than As, ErrorAs, and
    95  	// ErrorCode.
    96  	Close() error
    97  }
    98  
    99  // DeleteQueryer should be implemented by Collections that can handle Query.Delete
   100  // efficiently. If a Collection does not implement this interface, then Query.Delete
   101  // will be implemented by calling RunGetQuery and deleting the returned documents.
   102  type DeleteQueryer interface {
   103  	RunDeleteQuery(context.Context, *Query) error
   104  }
   105  
   106  // UpdateQueryer should be implemented by Collections that can handle Query.Update
   107  // efficiently. If a Collection does not implement this interface, then Query.Update
   108  // will be implemented by calling RunGetQuery and updating the returned documents.
   109  type UpdateQueryer interface {
   110  	RunUpdateQuery(context.Context, *Query, []Mod) error
   111  }
   112  
   113  // ActionKind describes the type of an action.
   114  type ActionKind int
   115  
   116  // Values for ActionKind.
   117  const (
   118  	Create ActionKind = iota
   119  	Replace
   120  	Put
   121  	Get
   122  	Delete
   123  	Update
   124  )
   125  
   126  //go:generate stringer -type=ActionKind
   127  
   128  // An Action describes a single operation on a single document.
   129  type Action struct {
   130  	Kind       ActionKind  // the kind of action
   131  	Doc        Document    // the document on which to perform the action
   132  	Key        interface{} // the document key returned by Collection.Key, to avoid recomputing it
   133  	FieldPaths [][]string  // field paths to retrieve, for Get only
   134  	Mods       []Mod       // modifications to make, for Update only
   135  	Index      int         // the index of the action in the original action list
   136  }
   137  
   138  // A Mod is a modification to a field path in a document.
   139  // At present, the only modifications supported are:
   140  // - set the value at the field path, or create the field path if it doesn't exist
   141  // - delete the field path (when Value is nil)
   142  type Mod struct {
   143  	FieldPath []string
   144  	Value     interface{}
   145  }
   146  
   147  // IncOp is a value representing an increment modification.
   148  type IncOp struct {
   149  	Amount interface{}
   150  }
   151  
   152  // An ActionListError contains all the errors encountered from a call to RunActions,
   153  // and the positions of the corresponding actions.
   154  type ActionListError []struct {
   155  	Index int
   156  	Err   error
   157  }
   158  
   159  // NewActionListError creates an ActionListError from a slice of errors.
   160  // If the ith element err of the slice is non-nil, the resulting ActionListError
   161  // will have an item {i, err}.
   162  func NewActionListError(errs []error) ActionListError {
   163  	var alerr ActionListError
   164  	for i, err := range errs {
   165  		if err != nil {
   166  			alerr = append(alerr, struct {
   167  				Index int
   168  				Err   error
   169  			}{i, err})
   170  		}
   171  	}
   172  	return alerr
   173  }
   174  
   175  // RunActionsOptions controls the behavior of RunActions.
   176  type RunActionsOptions struct {
   177  	// BeforeDo is a callback that must be called once, sequentially, before each one
   178  	// or group of the underlying service's actions is executed. asFunc allows
   179  	// drivers to expose driver-specific types.
   180  	BeforeDo func(asFunc func(interface{}) bool) error
   181  }
   182  
   183  // A Query defines a query operation to find documents within a collection based
   184  // on a set of requirements.
   185  type Query struct {
   186  	// FieldPaths contain a list of field paths the user selects to return in the
   187  	// query results. The returned documents should only have these fields
   188  	// populated.
   189  	FieldPaths [][]string
   190  
   191  	// Filters contain a list of filters for the query. If there are more than one
   192  	// filter, they should be combined with AND.
   193  	Filters []Filter
   194  
   195  	// Limit sets the maximum number of results returned by running the query. When
   196  	// Limit <= 0, the driver implementation should return all possible results.
   197  	Limit int
   198  
   199  	// OrderByField is the field to use for sorting the results.
   200  	OrderByField string
   201  
   202  	// OrderAscending specifies the sort direction.
   203  	OrderAscending bool
   204  
   205  	// BeforeQuery is a callback that must be called exactly once before the
   206  	// underlying service's query is executed. asFunc allows drivers to expose
   207  	// driver-specific types.
   208  	BeforeQuery func(asFunc func(interface{}) bool) error
   209  }
   210  
   211  // A Filter defines a filter expression used to filter the query result.
   212  // If the value is a number type, the filter uses numeric comparison.
   213  // If the value is a string type, the filter uses UTF-8 string comparison.
   214  // TODO(#1762): support comparison of other types.
   215  type Filter struct {
   216  	FieldPath []string    // the field path to filter
   217  	Op        string      // the operation, supports =, >, >=, <, <=
   218  	Value     interface{} // the value to compare using the operation
   219  }
   220  
   221  // A DocumentIterator iterates through the results (for Get action).
   222  type DocumentIterator interface {
   223  
   224  	// Next tries to get the next item in the query result and decodes into Document
   225  	// with the driver's codec.
   226  	// When there are no more results, it should return io.EOF.
   227  	// Once Next returns a non-nil error, it will never be called again.
   228  	Next(context.Context, Document) error
   229  
   230  	// Stop terminates the iterator before Next return io.EOF, allowing any cleanup
   231  	// needed.
   232  	Stop()
   233  
   234  	// As converts i to driver-specific types.
   235  	// See https://github.com/cornelk/go-cloud/concepts/as/ for background information.
   236  	As(i interface{}) bool
   237  }
   238  
   239  // EqualOp is the name of the equality operator.
   240  // It is defined here to avoid confusion between "=" and "==".
   241  const EqualOp = "="