driver

package
v0.37.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 12, 2024 License: Apache-2.0 Imports: 14 Imported by: 24

Documentation

Overview

Package driver defines interfaces to be implemented by docstore drivers, which will be used by the docstore package to interact with the underlying services. Application code should use package docstore.

Index

Constants

View Source
const EqualOp = "="

EqualOp is the name of the equality operator. It is defined here to avoid confusion between "=" and "==".

Variables

This section is empty.

Functions

func AsFunc

func AsFunc(val interface{}) func(interface{}) bool

AsFunc creates and returns an "as function" that behaves as follows: If its argument is a pointer to the same type as val, the argument is set to val and the function returns true. Otherwise, the function returns false.

func CompareNumbers

func CompareNumbers(n1, n2 interface{}) (int, error)

CompareNumbers returns -1, 1 or 0 depending on whether n1 is less than, greater than or equal to n2. n1 and n2 must be signed integer, unsigned integer, or floating-point values, but they need not be the same type.

If both types are integers or both floating-point, CompareNumbers behaves like Go comparisons on those types. If one operand is integer and the other is floating-point, CompareNumbers correctly compares the mathematical values of the numbers, without loss of precision.

func CompareTimes

func CompareTimes(t1, t2 time.Time) int

CompareTimes returns -1, 1 or 0 depending on whether t1 is before, after or equal to t2.

func Decode

func Decode(v reflect.Value, d Decoder) error

Decode decodes the value held in the Decoder d into v. Decode creates slices, maps and pointer elements as needed. It treats values that implement encoding.BinaryUnmarshaler, encoding.TextUnmarshaler and proto.Message specially; see Encode.

func Encode

func Encode(v reflect.Value, e Encoder) error

Encode encodes the value using the given Encoder. It traverses the value, iterating over arrays, slices, maps and the exported fields of structs. If it encounters a non-nil pointer, it encodes the value that it points to. Encode treats a few interfaces specially:

If the value implements encoding.BinaryMarshaler, Encode invokes MarshalBinary on it and encodes the resulting byte slice.

If the value implements encoding.TextMarshaler, Encode invokes MarshalText on it and encodes the resulting string.

If the value implements proto.Message, Encode invokes proto.Marshal on it and encodes the resulting byte slice. Here proto is the package "google.golang.org/protobuf/proto".

Not every map key type can be encoded. Only strings, integers (signed or unsigned), and types that implement encoding.TextMarshaler are permitted as map keys. These restrictions match exactly those of the encoding/json package.

func FieldPathEqualsField

func FieldPathEqualsField(fp []string, s string) bool

FieldPathEqualsField reports whether a field path equals a field. This is a convenience for FieldPathsEqual(fp, []string{s}).

func FieldPathsEqual

func FieldPathsEqual(fp1, fp2 []string) bool

FieldPathsEqual reports whether two field paths are equal.

func GroupByFieldPath

func GroupByFieldPath(gets []*Action) [][]*Action

GroupByFieldPath collect the Get actions into groups with the same set of field paths.

func IsEmptyValue

func IsEmptyValue(v reflect.Value) bool

IsEmptyValue returns whether or not v is a zero value of its type. Copied from encoding/json, go 1.12.

func SplitActions

func SplitActions(actions []*Action, split func(a, b *Action) bool) [][]*Action

SplitActions divides the actions slice into sub-slices much like strings.Split. The split function should report whether two consecutive actions should be split, that is, should be in different sub-slices. The first argument to split is the last action of the sub-slice currently under construction; the second argument is the action being considered for addition to that sub-slice. SplitActions doesn't change the order of the input slice.

func UniqueString

func UniqueString() string

UniqueString generates a string that is unique with high probability. Driver implementations can use it to generate keys for Create actions.

Types

type Action

type Action struct {
	Kind       ActionKind  // the kind of action
	Doc        Document    // the document on which to perform the action
	Key        interface{} // the document key returned by Collection.Key, to avoid recomputing it
	FieldPaths [][]string  // field paths to retrieve, for Get only
	Mods       []Mod       // modifications to make, for Update only
	Index      int         // the index of the action in the original action list
}

An Action describes a single operation on a single document.

func GroupActions

func GroupActions(actions []*Action) (beforeGets, getList, writeList, afterGets []*Action)

GroupActions separates actions into four sets: writes, gets that must happen before the writes, gets that must happen after the writes, and gets that can happen concurrently with the writes.

type ActionKind

type ActionKind int

ActionKind describes the type of an action.

const (
	Create ActionKind = iota
	Replace
	Put
	Get
	Delete
	Update
)

Values for ActionKind.

func (ActionKind) String

func (i ActionKind) String() string

type ActionListError

type ActionListError []struct {
	Index int
	Err   error
}

An ActionListError contains all the errors encountered from a call to RunActions, and the positions of the corresponding actions.

func NewActionListError

func NewActionListError(errs []error) ActionListError

NewActionListError creates an ActionListError from a slice of errors. If the ith element err of the slice is non-nil, the resulting ActionListError will have an item {i, err}.

type Collection

type Collection interface {
	// Key returns the document key, or nil if the document doesn't have one, which
	// means it is absent or zero value, such as 0, a nil interface value, and any
	// empty array or string.
	//
	// If the collection is able to generate a key for a Create action, then
	// it should not return an error if the key is missing. If the collection
	// can't generate a missing key, it should return an error.
	//
	// The returned key must be comparable.
	//
	// The returned key should not be encoded with the driver's codec; it should
	// be the user-supplied Go value.
	Key(Document) (interface{}, error)

	// RevisionField returns the name of the field used to hold revisions.
	// If the empty string is returned, docstore.DefaultRevisionField will be used.
	RevisionField() string

	// RunActions executes a slice of actions.
	//
	// If unordered is false, it must appear as if the actions were executed in the
	// order they appear in the slice, from the client's point of view. The actions
	// need not happen atomically, nor does eventual consistency in the service
	// need to be taken into account. For example, after a write returns
	// successfully, the driver can immediately perform a read on the same document,
	// even though the service's semantics does not guarantee that the read will see
	// the write. RunActions should return immediately after the first action that fails.
	// The returned slice should have a single element.
	//
	// opts controls the behavior of RunActions and is guaranteed to be non-nil.
	RunActions(ctx context.Context, actions []*Action, opts *RunActionsOptions) ActionListError

	// RunGetQuery executes a Query.
	//
	// Implementations can choose to execute the Query as one single request or
	// multiple ones, depending on their service offerings. The portable type
	// exposes OpenCensus metrics for the call to RunGetQuery (but not for
	// subsequent calls to DocumentIterator.Next), so drivers should prefer to
	// make at least one RPC during RunGetQuery itself instead of lazily waiting
	// for the first call to Next.
	RunGetQuery(context.Context, *Query) (DocumentIterator, error)

	// QueryPlan returns the plan for the query.
	QueryPlan(*Query) (string, error)

	// RevisionToBytes converts a revision to a byte slice.
	RevisionToBytes(interface{}) ([]byte, error)

	// BytesToRevision converts a []byte to a revision.
	BytesToRevision([]byte) (interface{}, error)

	// As converts i to driver-specific types.
	// See https://gocloud.dev/concepts/as/ for background information.
	As(i interface{}) bool

	// ErrorAs allows drivers to expose driver-specific types for returned
	// errors.
	//
	// See https://gocloud.dev/concepts/as/ for background information.
	ErrorAs(err error, i interface{}) bool

	// ErrorCode should return a code that describes the error, which was returned by
	// one of the other methods in this interface.
	ErrorCode(error) gcerrors.ErrorCode

	// Close cleans up any resources used by the Collection. Once Close is called,
	// there will be no method calls to the Collection other than As, ErrorAs, and
	// ErrorCode.
	Close() error
}

A Collection is a set of documents.

type Decoder

type Decoder interface {
	// The AsXXX methods each report whether the value being decoded can be represented as
	// a particular Go type. If so, the method should return the value as that type, and true;
	// otherwise it should return the zero value and false.
	AsString() (string, bool)
	AsInt() (int64, bool)
	AsUint() (uint64, bool)
	AsFloat() (float64, bool)
	AsBytes() ([]byte, bool)
	AsBool() (bool, bool)
	AsNull() bool

	// ListLen should return the length of the value being decoded and true, if the
	// value can be decoded into a slice or array. Otherwise, ListLen should return
	// (0, false).
	ListLen() (int, bool)

	// If ListLen returned true, then DecodeList will be called. It should iterate
	// over the value being decoded in sequence from index 0, invoking the callback
	// for each element with the element's index and a Decoder for the element.
	// If the callback returns false, DecodeList should return immediately.
	DecodeList(func(int, Decoder) bool)

	// MapLen should return the number of fields of the value being decoded and true,
	// if the value can be decoded into a map or struct. Otherwise, it should return
	// (0, false).
	MapLen() (int, bool)

	// DecodeMap iterates over the fields of the value being decoded, invoke the
	// callback on each with field name, a Decoder for the field value, and a bool
	// to indicate whether or not to use exact match for the field names. It will
	// be called when MapLen returns true or decoding a struct. If the callback
	// returns false, DecodeMap should return immediately.
	DecodeMap(func(string, Decoder, bool) bool)

	// AsInterface should decode the value into the Go value that best represents it.
	AsInterface() (interface{}, error)

	// If the decoder wants to decode a value in a special way it should do so here
	// and return true, the decoded value, and any error from the decoding.
	// Otherwise, it should return false.
	AsSpecial(reflect.Value) (bool, interface{}, error)

	// String should return a human-readable representation of the Decoder, for error messages.
	String() string
}

A Decoder decodes data that was produced by Encode back into Go values. Each Decoder instance is responsible for decoding one value.

type DeleteQueryer

type DeleteQueryer interface {
	RunDeleteQuery(context.Context, *Query) error
}

DeleteQueryer should be implemented by Collections that can handle Query.Delete efficiently. If a Collection does not implement this interface, then Query.Delete will be implemented by calling RunGetQuery and deleting the returned documents.

type Document

type Document struct {
	Origin interface{} // the argument to NewDocument
	// contains filtered or unexported fields
}

A Document is a lightweight wrapper around either a map[string]interface{} or a struct pointer. It provides operations to get and set fields and field paths.

func NewDocument

func NewDocument(doc interface{}) (Document, error)

NewDocument creates a new document from doc, which must be a non-nil map[string]interface{} or struct pointer.

func (Document) Decode

func (d Document) Decode(dec Decoder) error

Decode decodes the document using the given Decoder.

func (Document) Encode

func (d Document) Encode(e Encoder) error

Encode encodes the document using the given Encoder.

func (Document) FieldNames

func (d Document) FieldNames() []string

FieldNames returns names of the top-level fields of d.

func (Document) Get

func (d Document) Get(fp []string) (interface{}, error)

Get returns the value of the given field path in the document.

func (Document) GetField

func (d Document) GetField(field string) (interface{}, error)

GetField returns the value of the named document field.

func (Document) HasField

func (d Document) HasField(field string) bool

HasField returns whether or not d has a certain field.

func (Document) HasFieldFold

func (d Document) HasFieldFold(field string) bool

HasFieldFold is like HasField but matches case-insensitively for struct field.

func (Document) Set

func (d Document) Set(fp []string, val interface{}) error

Set sets the value of the field path in the document. This creates sub-maps as necessary, if possible.

func (Document) SetField

func (d Document) SetField(field string, value interface{}) error

SetField sets the field to value in the document.

type DocumentIterator

type DocumentIterator interface {

	// Next tries to get the next item in the query result and decodes into Document
	// with the driver's codec.
	// When there are no more results, it should return io.EOF.
	// Once Next returns a non-nil error, it will never be called again.
	Next(context.Context, Document) error

	// Stop terminates the iterator before Next return io.EOF, allowing any cleanup
	// needed.
	Stop()

	// As converts i to driver-specific types.
	// See https://gocloud.dev/concepts/as/ for background information.
	As(i interface{}) bool
}

A DocumentIterator iterates through the results (for Get action).

type Encoder

type Encoder interface {
	// These methods all encode and store a single Go value.
	EncodeNil()
	EncodeBool(bool)
	EncodeString(string)
	EncodeInt(int64)
	EncodeUint(uint64)
	EncodeFloat(float64)
	EncodeBytes([]byte)

	// EncodeList is called when a slice or array is encountered (except for a
	// []byte, which is handled by EncodeBytes). Its argument is the length of the
	// slice or array. The encoding algorithm will call the returned Encoder that
	// many times to encode the successive values of the list. After each such call,
	// ListIndex will be called with the index of the element just encoded.
	//
	// For example, []string{"a", "b"} will result in these calls:
	//     enc2 := enc.EncodeList(2)
	//     enc2.EncodeString("a")
	//     enc2.ListIndex(0)
	//     enc2.EncodeString("b")
	//     enc2.ListIndex(1)
	EncodeList(n int) Encoder
	ListIndex(i int)

	// EncodeMap is called when a map is encountered. Its argument is the number of
	// fields in the map. The encoding algorithm will call the returned Encoder that
	// many times to encode the successive values of the map. After each such call,
	// MapKey will be called with the key of the element just encoded.
	//
	// For example, map[string}int{"A": 1, "B": 2} will result in these calls:
	//     enc2 := enc.EncodeMap(2)
	//     enc2.EncodeInt(1)
	//     enc2.MapKey("A")
	//     enc2.EncodeInt(2)
	//     enc2.MapKey("B")
	//
	// EncodeMap is also called for structs. The map then consists of the exported
	// fields of the struct. For struct{A, B int}{1, 2}, if EncodeStruct returns
	// false, the same sequence of calls as above will occur.
	EncodeMap(n int) Encoder
	MapKey(string)

	// If the encoder wants to encode a value in a special way it should do so here
	// and return true along with any error from the encoding. Otherwise, it should
	// return false.
	EncodeSpecial(v reflect.Value) (bool, error)
}

An Encoder encodes Go values in some other form (e.g. JSON, protocol buffers). The encoding protocol is designed to avoid losing type information by passing values using interface{}. An Encoder is responsible for storing the value it is encoding.

Because all drivers must support the same set of values, the encoding methods (with the exception of EncodeStruct) do not return errors. EncodeStruct is special because it is an escape hatch for arbitrary structs, not all of which may be encodable.

type Filter

type Filter struct {
	FieldPath []string    // the field path to filter
	Op        string      // the operation, supports `=`, `>`, `>=`, `<`, `<=`, `in`, `not-in`
	Value     interface{} // the value to compare using the operation
}

A Filter defines a filter expression used to filter the query result. If the value is a number type, the filter uses numeric comparison. If the value is a string type, the filter uses UTF-8 string comparison. TODO(#1762): support comparison of other types.

type IncOp

type IncOp struct {
	Amount interface{}
}

IncOp is a value representing an increment modification.

type Mod

type Mod struct {
	FieldPath []string
	Value     interface{}
}

A Mod is a modification to a field path in a document. At present, the only modifications supported are: - set the value at the field path, or create the field path if it doesn't exist - delete the field path (when Value is nil)

type Query

type Query struct {
	// FieldPaths contain a list of field paths the user selects to return in the
	// query results. The returned documents should only have these fields
	// populated.
	FieldPaths [][]string

	// Filters contain a list of filters for the query. If there are more than one
	// filter, they should be combined with AND.
	Filters []Filter

	// Offset (also commonly referred to as `Skip`) sets the number of results to skip
	// before returning results. When Offset <= 0, the driver implementation should
	// return all possible results.
	Offset int

	// Limit sets the maximum number of results returned by running the query. When
	// Limit <= 0, the driver implementation should return all possible results.
	Limit int

	// OrderByField is the field to use for sorting the results.
	OrderByField string

	// OrderAscending specifies the sort direction.
	OrderAscending bool

	// BeforeQuery is a callback that must be called exactly once before the
	// underlying service's query is executed. asFunc allows drivers to expose
	// driver-specific types.
	BeforeQuery func(asFunc func(interface{}) bool) error
}

A Query defines a query operation to find documents within a collection based on a set of requirements.

type RunActionsOptions

type RunActionsOptions struct {
	// BeforeDo is a callback that must be called once, sequentially, before each one
	// or group of the underlying service's actions is executed. asFunc allows
	// drivers to expose driver-specific types.
	BeforeDo func(asFunc func(interface{}) bool) error
}

RunActionsOptions controls the behavior of RunActions.

type Throttle

type Throttle struct {
	// contains filtered or unexported fields
}

Throttle is used to limit the number of outstanding activities, like RPCs. It acts like a combination of a semaphore and a WaitGroup.

func NewThrottle

func NewThrottle(max int) *Throttle

NewThrottle returns a Throttle that will allow max calls to Acquire that are not matched with Release calls before blocking. If max is <= 0, there is no throttling: Acquire always returns immediately.

func (*Throttle) Acquire

func (t *Throttle) Acquire()

Acquire blocks until a token is available, then acquires it and returns. Acquire is deliberately not sensitive to context.Context, because it assumes that whatever acquires a token will be context-sensitive, and thus will release the token when the context is done.

func (*Throttle) Release

func (t *Throttle) Release()

Release releases a token obtained by Acquire.

func (*Throttle) Wait

func (t *Throttle) Wait()

Wait blocks goroutine until the number of calls to Release matches the number of calls to Acquire.

type UpdateQueryer

type UpdateQueryer interface {
	RunUpdateQuery(context.Context, *Query, []Mod) error
}

UpdateQueryer should be implemented by Collections that can handle Query.Update efficiently. If a Collection does not implement this interface, then Query.Update will be implemented by calling RunGetQuery and updating the returned documents.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL