ormtable

package
v1.0.0-beta.3 Latest Latest
Warning

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

Go to latest
Published: May 11, 2023 License: Apache-2.0 Imports: 20 Imported by: 12

Documentation

Overview

Package ormtable defines the interfaces and implementations of tables and indexes.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultJSONValidator

func DefaultJSONValidator(message proto.Message) error

DefaultJSONValidator is the default validator used when calling Table.ValidateJSON(). It will call methods with the signature `ValidateBasic() error` and/or `Validate() error` to validate the message.

func WrapContextDefault

func WrapContextDefault(backend ReadBackend) context.Context

WrapContextDefault performs the default wrapping of a backend in a context. This should be used primarily for testing purposes and production code should use some other framework specific wrapping (for instance using "store keys").

Types

type AutoIncrementTable

type AutoIncrementTable interface {
	Table

	// InsertReturningPKey inserts the provided entry in the store and returns the newly
	// generated primary key for the message or an error.
	InsertReturningPKey(ctx context.Context, message proto.Message) (newPK uint64, err error)

	// LastInsertedSequence retrieves the sequence number of the last entry inserted into the table.
	// The LastInsertedSequence is 0 if no entries have been inserted into the table.
	LastInsertedSequence(ctx context.Context) (uint64, error)
}

type Backend

type Backend interface {
	ReadBackend

	// CommitmentStore returns the merklized commitment store.
	CommitmentStore() kv.Store

	// IndexStore returns the index store if a separate one exists,
	// otherwise it the commitment store.
	IndexStore() kv.Store

	// ValidateHooks returns a ValidateHooks instance or nil.
	ValidateHooks() ValidateHooks

	// WithValidateHooks returns a copy of this backend with the provided validate hooks.
	WithValidateHooks(ValidateHooks) Backend

	// WriteHooks returns a WriteHooks instance of nil.
	WriteHooks() WriteHooks

	// WithWriteHooks returns a copy of this backend with the provided write hooks.
	WithWriteHooks(WriteHooks) Backend
}

Backend defines the type used for read-write ORM operations. Unlike ReadBackend, write access to the underlying kv-store is hidden so that this can be fully encapsulated by the ORM.

func NewBackend

func NewBackend(options BackendOptions) Backend

NewBackend creates a new Backend.

type BackendOptions

type BackendOptions struct {
	// CommitmentStore is the commitment store.
	CommitmentStore kv.Store

	// IndexStore is the optional index store.
	// If it is nil the CommitmentStore will be used.
	IndexStore kv.Store

	// ValidateHooks are optional hooks into ORM insert, update and delete operations.
	ValidateHooks ValidateHooks

	WriteHooks WriteHooks
}

BackendOptions defines options for creating a Backend. Context can optionally define two stores - a commitment store that is backed by a merkle tree and an index store that isn't. If the index store is not defined, the commitment store will be used for all operations.

type BackendResolver

type BackendResolver func(context.Context) (ReadBackend, error)

BackendResolver resolves a backend from the context or returns an error. Callers should type cast the returned ReadBackend to Backend to test whether the backend is writable.

type Index

type Index interface {
	// List does iteration over the index with the provided prefix key and options.
	// Prefix key values must correspond in type to the index's fields and the
	// number of values provided cannot exceed the number of fields in the index,
	// although fewer values can be provided.
	List(ctx context.Context, prefixKey []interface{}, options ...ormlist.Option) (Iterator, error)

	// ListRange does range iteration over the index with the provided from and to
	// values and options.
	//
	// From and to values must correspond in type to the index's fields and the number of values
	// provided cannot exceed the number of fields in the index, although fewer
	// values can be provided.
	//
	// Range iteration can only be done for from and to values which are
	// well-ordered, meaning that any unordered components must be equal. Ex.
	// the bytes type is considered unordered, so a range iterator is created
	// over an index with a bytes field, both start and end must have the same
	// value for bytes.
	//
	// Range iteration is inclusive at both ends.
	ListRange(ctx context.Context, from, to []interface{}, options ...ormlist.Option) (Iterator, error)

	// DeleteBy deletes any entries which match the provided prefix key.
	DeleteBy(context context.Context, prefixKey ...interface{}) error

	// DeleteRange deletes any entries between the provided range keys.
	DeleteRange(context context.Context, from, to []interface{}) error

	// MessageType returns the protobuf message type of the index.
	MessageType() protoreflect.MessageType

	// Fields returns the canonical field names of the index.
	Fields() string
	// contains filtered or unexported methods
}

Index defines an index on a table. Index instances are stateless, with all state existing only in the store passed to index methods.

type Iterator

type Iterator interface {
	// Next advances the iterator and returns true if a valid entry is found.
	// Next must be called before starting iteration.
	Next() bool

	// Keys returns the current index key and primary key values that the
	// iterator points to.
	Keys() (indexKey, primaryKey []protoreflect.Value, err error)

	// UnmarshalMessage unmarshals the entry the iterator currently points to
	// the provided proto.Message.
	UnmarshalMessage(proto.Message) error

	// GetMessage retrieves the proto.Message that the iterator currently points
	// to.
	GetMessage() (proto.Message, error)

	// Cursor returns the cursor referencing the current iteration position
	// and can be used to restart iteration right after this position.
	Cursor() ormlist.CursorT

	// PageResponse returns a non-nil page response after Next() returns false
	// if pagination was requested in list options.
	PageResponse() *queryv1beta1.PageResponse

	// Close closes the iterator and must always be called when done using
	// the iterator. The defer keyword should generally be used for this.
	Close()
	// contains filtered or unexported methods
}

Iterator defines the interface for iterating over indexes.

WARNING: it is generally unsafe to mutate a table while iterating over it. Instead you should do reads and writes separately, or use a helper function like DeleteBy which does this efficiently.

type Options

type Options struct {
	// Prefix is an optional prefix used to build the table's prefix.
	Prefix []byte

	// MessageType is the protobuf message type of the table.
	MessageType protoreflect.MessageType

	// TableDescriptor is an optional table descriptor to be explicitly used
	// with the table. Generally this should be nil and the table descriptor
	// should be pulled from the table message option. TableDescriptor
	// cannot be used together with SingletonDescriptor.
	TableDescriptor *ormv1.TableDescriptor

	// SingletonDescriptor is an optional singleton descriptor to be explicitly used.
	// Generally this should be nil and the table descriptor
	// should be pulled from the singleton message option. SingletonDescriptor
	// cannot be used together with TableDescriptor.
	SingletonDescriptor *ormv1.SingletonDescriptor

	// TypeResolver is an optional type resolver to be used when unmarshaling
	// protobuf messages.
	TypeResolver TypeResolver

	// JSONValidator is an optional validator that can be used for validating
	// messaging when using ValidateJSON. If it is nil, DefaultJSONValidator
	// will be used
	JSONValidator func(proto.Message) error

	// BackendResolver is an optional function which retrieves a Backend from the context.
	// If it is nil, the default behavior will be to attempt to retrieve a
	// backend using the method that WrapContextDefault uses. This method
	// can be used to implement things like "store keys" which would allow a
	// table to only be used with a specific backend and to hide direct
	// access to the backend other than through the table interface.
	// Mutating operations will attempt to cast ReadBackend to Backend and
	// will return an error if that fails.
	BackendResolver BackendResolver
}

Options are options for building a Table.

type ReadBackend

type ReadBackend interface {
	// CommitmentStoreReader returns the reader for the commitment store.
	CommitmentStoreReader() kv.ReadonlyStore

	// IndexStoreReader returns the reader for the index store.
	IndexStoreReader() kv.ReadonlyStore
	// contains filtered or unexported methods
}

ReadBackend defines the type used for read-only ORM operations.

func NewReadBackend

func NewReadBackend(options ReadBackendOptions) ReadBackend

NewReadBackend creates a new ReadBackend.

type ReadBackendOptions

type ReadBackendOptions struct {
	// CommitmentStoreReader is a reader for the commitment store.
	CommitmentStoreReader kv.ReadonlyStore

	// IndexStoreReader is an optional reader for the index store.
	// If it is nil the CommitmentStoreReader will be used.
	IndexStoreReader kv.ReadonlyStore
}

ReadBackendOptions defines options for creating a ReadBackend. Read context can optionally define two stores - a commitment store that is backed by a merkle tree and an index store that isn't. If the index store is not defined, the commitment store will be used for all operations.

type Schema

type Schema interface {
	ormkv.EntryCodec

	// GetTable returns the table for the provided message type or nil.
	GetTable(message proto.Message) Table
}

type Table

type Table interface {
	View

	ormkv.EntryCodec

	// Save saves the provided entry in the store either inserting it or
	// updating it if needed.
	//
	// If store implement the ValidateHooks interface, the appropriate ValidateInsert or
	// ValidateUpdate hook method will be called.
	//
	// Save attempts to be atomic with respect to the underlying store,
	// meaning that either the full save operation is written or the store is
	// left unchanged, unless there is an error with the underlying store.
	//
	// If a unique key constraint is violated, ormerrors.UniqueKeyViolation
	// (or an error wrapping it) will be returned.
	Save(context context.Context, message proto.Message) error

	// Insert inserts the provided entry in the store and fails if there is
	// an unique key violation. See Save for more details on behavior.
	//
	// If an entity with the same primary key exists, an error wrapping
	// ormerrors.AlreadyExists will be returned.
	Insert(ctx context.Context, message proto.Message) error

	// Update updates the provided entry in the store and fails if an entry
	// with a matching primary key does not exist. See Save for more details
	// on behavior.
	//
	// If an entity with the same primary key does not exist, ormerrors.NotFound
	// (or an error wrapping it) will be returned.
	Update(ctx context.Context, message proto.Message) error

	// Delete deletes the entry with the with primary key fields set on message
	// if one exists. Other fields besides the primary key fields will not
	// be used for retrieval.
	//
	// If store implement the ValidateHooks interface, the ValidateDelete hook method will
	// be called.
	//
	// Delete attempts to be atomic with respect to the underlying store,
	// meaning that either the full save operation is written or the store is
	// left unchanged, unless there is an error with the underlying store.
	Delete(ctx context.Context, message proto.Message) error

	// DefaultJSON returns default JSON that can be used as a template for
	// genesis files.
	//
	// For regular tables this an empty JSON array, but for singletons an
	// empty instance of the singleton is marshaled.
	DefaultJSON() json.RawMessage

	// ValidateJSON validates JSON streamed from the reader.
	ValidateJSON(io.Reader) error

	// ImportJSON imports JSON into the store, streaming one entry at a time.
	// Each table should be import from a separate JSON file to enable proper
	// streaming.
	//
	// Regular tables should be stored as an array of objects with each object
	// corresponding to a single record in the table.
	//
	// Auto-incrementing tables
	// can optionally have the last sequence value as the first element in the
	// array. If the last sequence value is provided, then each value of the
	// primary key in the file must be <= this last sequence value or omitted
	// entirely. If no last sequence value is provided, no entries should
	// contain the primary key as this will be auto-assigned.
	//
	// Singletons should define a single object and not an array.
	//
	// ImportJSON is not atomic with respect to the underlying store, meaning
	// that in the case of an error, some records may already have been
	// imported. It is assumed that ImportJSON is called in the context of some
	// larger transaction isolation.
	ImportJSON(context.Context, io.Reader) error

	// ExportJSON exports JSON in the format accepted by ImportJSON.
	// Auto-incrementing tables will export the last sequence number as the
	// first element in the JSON array.
	ExportJSON(context.Context, io.Writer) error

	// ID is the ID of this table within the schema of its FileDescriptor.
	ID() uint32

	Schema
}

Table is an abstract interface around a concrete table. Table instances are stateless, with all state existing only in the store passed to table and index methods.

func Build

func Build(options Options) (Table, error)

Build builds a Table instance from the provided Options.

type TypeResolver

TypeResolver is an interface that can be used for the protoreflect.UnmarshalOptions.Resolver option.

type UniqueIndex

type UniqueIndex interface {
	Index

	// Has returns true if the key values are present in the store for this index.
	Has(context context.Context, keyValues ...interface{}) (found bool, err error)

	// Get retrieves the message if one exists for the provided key values.
	Get(context context.Context, message proto.Message, keyValues ...interface{}) (found bool, err error)
}

UniqueIndex defines an unique index on a table.

type ValidateHooks

type ValidateHooks interface {
	// ValidateInsert is called before the message is inserted.
	// If error is not nil the insertion will fail.
	ValidateInsert(context.Context, proto.Message) error

	// ValidateUpdate is called before the existing message is updated with the new one.
	// If error is not nil the update will fail.
	ValidateUpdate(ctx context.Context, existing, new proto.Message) error

	// ValidateDelete is called before the message is deleted.
	// If error is not nil the deletion will fail.
	ValidateDelete(context.Context, proto.Message) error
}

ValidateHooks defines an interface for a table hooks which can intercept insert, update and delete operations and possibly return an error.

type View

type View interface {
	Index

	// Has returns true if there is an entity in the table with the same
	// primary key as message. Other fields besides the primary key fields will not
	// be used for retrieval.
	Has(ctx context.Context, message proto.Message) (found bool, err error)

	// Get retrieves the message if one exists for the primary key fields
	// set on the message. Other fields besides the primary key fields will not
	// be used for retrieval.
	Get(ctx context.Context, message proto.Message) (found bool, err error)

	// GetIndex returns the index referenced by the provided fields if
	// one exists or nil. Note that some concrete indexes can be retrieved by
	// multiple lists of fields.
	GetIndex(fields string) Index

	// GetUniqueIndex returns the unique index referenced by the provided fields if
	// one exists or nil. Note that some concrete indexes can be retrieved by
	// multiple lists of fields.
	GetUniqueIndex(fields string) UniqueIndex

	// Indexes returns all the concrete indexes for the table.
	Indexes() []Index

	// GetIndexByID returns the index with the provided ID or nil.
	GetIndexByID(id uint32) Index

	// PrimaryKey returns the primary key unique index.
	PrimaryKey() UniqueIndex
}

View defines a read-only table.

It exists as a separate interacted to support future scenarios where tables may be "supported" virtually to provide compatibility between systems, for instance to enable backwards compatibility when a major migration needs to be performed.

type WriteHooks

type WriteHooks interface {
	// OnInsert is called after an message is inserted into the store.
	OnInsert(context.Context, proto.Message)

	// OnUpdate is called after the entity is updated in the store.
	OnUpdate(ctx context.Context, existing, new proto.Message)

	// OnDelete is called after the entity is deleted from the store.
	OnDelete(context.Context, proto.Message)
}

WriteHooks defines an interface for listening to insertions, updates and deletes after they are written to the store. This can be used for indexing state in another database. Indexers should make sure they coordinate with transactions at live at the next level above the ORM as they write hooks may be called but the enclosing transaction may still fail. The context is provided in each method to help coordinate this.

Jump to

Keyboard shortcuts

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