store

package
v0.4.7 Latest Latest
Warning

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

Go to latest
Published: Sep 1, 2023 License: MIT Imports: 7 Imported by: 5

README

Resgate logo

Storage utilities for Go RES Service
Synchronize Your Clients

License Reference


Package store provides handlers and interfaces for working with database storage.

For more details and comments on the interfaces, see the go.dev reference.

Store interface

A store contains resources of a single type. It can be seen as a row in an Excel sheet or SQL table, or a document in a MongoDB collection.

Any database can be used with a wrapper that implements the following interface:

// Store is a CRUD interface for storing resources of a specific type.
type Store interface {
    Read(id string) ReadTxn
    Write(id string) WriteTxn
    OnChange(func(id string, before, after interface{}))
}

// ReadTxn represents a read transaction.
type ReadTxn interface {
    ID() string
    Close() error
    Exists() bool
    Value() (interface{}, error)
}

// WriteTxn represents a write transaction.
type WriteTxn interface {
    ReadTxn
    Create(interface{}) error
    Update(interface{}) error
    Delete() error
}

QueryStore interface

A query store provides the methods for making queries to an underlying database, and listen for changes that might affect the results.

// QueryStore is an interface for quering the resource in a store.
type QueryStore interface {
    Query(query url.Values) (interface{}, error)
    OnQueryChange(func(QueryChange))
}

// QueryChange represents a change to a resource that may affects queries.
type QueryChange interface {
    ID() string
    Before() interface{}
    After() interface{}
    Events(q url.Values) (events []ResultEvent, reset bool, err error)
}

// ResultEvent represents an event on a query result.
type ResultEvent struct {
    Name string
    Idx int
    Value interface{}
    Changed map[string]interface{}
}

Implementations

Use these examples as inspiration for your database implementation.

Name Description Documentation
mockstore Mock store implementation for testing Reference
badgerstore BadgerDB store implementation Reference

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotFound  = res.ErrNotFound
	ErrDuplicate = &res.Error{Code: res.CodeInvalidParams, Message: "Duplicate resource"}
)

Predefined errors

View Source
var DeleteValue = Value{
	RawMessage: json.RawMessage(`{"action":"delete"}`),
	Type:       ValueTypeDelete,
}

DeleteValue is a predeclared delete action value

Functions

This section is empty.

Types

type Handler

type Handler struct {
	Store       Store
	Transformer Transformer
	Default     interface{}
}

Handler is a res.Service handler that fetches resources, and listens for updates from a Store.

func (Handler) SetOption

func (sh Handler) SetOption(h *res.Handler)

SetOption is to implement the res.Option interface

func (Handler) WithDefault added in v0.4.4

func (sh Handler) WithDefault(def interface{}) Handler

WithDefault returns a new Handler value with Default value set to default. The default value should be pre-transformed.

func (Handler) WithStore

func (sh Handler) WithStore(store Store) Handler

WithStore returns a new Handler value with Store set to store.

func (Handler) WithTransformer

func (sh Handler) WithTransformer(transformer Transformer) Handler

WithTransformer returns a new Handler value with Transformer set to transformer.

type IDToRIDCollectionTransformer

type IDToRIDCollectionTransformer func(id string) string

IDToRIDCollectionTransformer is a QueryTransformer that handles the common case of transforming a slice of id strings:

[]string{"1", "2"}

into slice of resource references:

[]res.Ref{"library.book.1", "library.book.2"}

The function converts a single ID returned by a the store into an external resource ID.

func (IDToRIDCollectionTransformer) TransformEvents

func (t IDToRIDCollectionTransformer) TransformEvents(evs []ResultEvent) ([]ResultEvent, error)

TransformEvents transforms events for a []string collection into events for a []res.Ref collection.

func (IDToRIDCollectionTransformer) TransformResult

func (t IDToRIDCollectionTransformer) TransformResult(v interface{}) (interface{}, error)

TransformResult transforms a slice of id strings into a slice of resource references.

type IDToRIDModelTransformer

type IDToRIDModelTransformer func(id string) string

IDToRIDModelTransformer is a QueryTransformer that handles the common case of transforming a slice of unique id strings:

[]string{"1", "2"}

into a map of resource references with id as key:

map[string]res.Ref{"1": "library.book.1", "2": "library.book.2"}

The function converts a single ID returned by a the store into an external resource ID.

The behavior is undefined for slices containing duplicate id string.

func (IDToRIDModelTransformer) TransformEvents

func (t IDToRIDModelTransformer) TransformEvents(evs []ResultEvent) ([]ResultEvent, error)

TransformEvents transforms events for a []string collection into events for a map[string]res.Ref model.

func (IDToRIDModelTransformer) TransformResult

func (t IDToRIDModelTransformer) TransformResult(v interface{}) (interface{}, error)

TransformResult transforms a slice of id strings into a map of resource references with id as key.

type QueryChange

type QueryChange interface {
	// ID returns the ID of the changed resource triggering the event.
	ID() string

	// Before returns the resource value before the change. The value type is
	// defined by the underlying store. If the resource was created, Before will
	// return nil.
	Before() interface{}

	// After returns the resource value after the change. The value type is
	// defined by the underlying store. If the resource was deleted, After will
	// return nil.
	After() interface{}

	// Events returns a list of events that describes mutations of the results,
	// caused by the change, for a given query.
	//
	// If the query result is a collection, where the change caused a value to
	// move position, the "remove" event should come prior to the "add" event.
	//
	// The QueryStore implementation may return zero or nil events, even if the
	// query may be affected by the change, but must then have the returned
	// reset flag set to true.
	Events(q url.Values) (events []ResultEvent, reset bool, err error)
}

QueryChange represents a change to a resource that may affects queries.

type QueryHandler

type QueryHandler struct {
	// A QueryStore from where to fetch the resource references.
	QueryStore QueryStore
	// QueryRequestHandler transforms an external query request and path param
	// values into a query that can be handled by the QueryStore. The
	// QueryHandler will respond with a query resource.
	//
	// A non-empty normalized query string based on the url.Values must be
	// returned. See:
	// https://resgate.io/docs/specification/res-service-protocol/#get-request
	//
	// Must not be set if RequestHandler is set.
	QueryRequestHandler func(rname string, pathParams map[string]string, q url.Values) (url.Values, string, error)
	// RequestHandler transforms an external request and path param values into
	// a query that can be handled by the QueryStore.
	//
	// Must not be set if QueryRequestHandler is set.
	RequestHandler func(rname string, pathParams map[string]string) (url.Values, error)
	// Transformer transforms the internal query results and events into an
	// external resource, and events for the external resource.
	Transformer QueryTransformer
	// AffectedResources is called on query change, and should return a list of
	// resources affected by the change.
	//
	// This is only required if the resource contains path parameters.
	//
	// Example
	//
	// If a the handler listens for requests on: library.books.$firstLetter A
	// change of a book's name from "Alpha" to "Beta" should have
	// AffectedResources return the following:
	//
	//  []string{"library.books.a", "library.books.b"}
	AffectedResources func(res.Pattern, QueryChange) []string
}

QueryHandler is a res.Service handler for get requests that fetches the results from an underlying QueryStore. It also listens to changes in the QueryStore, and sends events if the change affects the query.

func (QueryHandler) SetOption

func (qh QueryHandler) SetOption(h *res.Handler)

SetOption is to implement the res.Option interface.

func (QueryHandler) WithAffectedResources

func (qh QueryHandler) WithAffectedResources(f func(res.Pattern, QueryChange) []string) QueryHandler

WithAffectedResources returns a new QueryHandler value with IDToRID set to f.

func (QueryHandler) WithQueryRequestHandler

func (qh QueryHandler) WithQueryRequestHandler(f func(rname string, pathParams map[string]string, q url.Values) (url.Values, string, error)) QueryHandler

WithQueryRequestHandler returns a new QueryHandler value with QueryRequestHandler set to f.

func (QueryHandler) WithQueryStore

func (qh QueryHandler) WithQueryStore(qstore QueryStore) QueryHandler

WithQueryStore returns a new QueryHandler value with QueryStore set to qstore.

func (QueryHandler) WithRequestHandler

func (qh QueryHandler) WithRequestHandler(f func(rname string, pathParams map[string]string) (url.Values, error)) QueryHandler

WithRequestHandler returns a new QueryHandler value with RequestHandler set to f.

func (QueryHandler) WithTransformer

func (qh QueryHandler) WithTransformer(transformer QueryTransformer) QueryHandler

WithTransformer returns a new QueryHandler value with Tranformer set to transformer.

type QueryStore

type QueryStore interface {
	// Query returns a result based on the provided query values.
	//
	// The result type is determined by the QueryStore implementation, and must
	// remain the same for all calls regardless of query values. If error is
	// non-nil the returned interface{} is nil.
	Query(query url.Values) (interface{}, error)

	// OnQueryChange registers a callback that is called whenever a change to a
	// reasource has occurred that may affect the results returned by Query.
	OnQueryChange(func(QueryChange))
}

QueryStore is an interface for quering the resource in a store.

type QueryTransformer

type QueryTransformer interface {
	// TransformResults transforms a query result into an external resource to
	// send to the requesting client.
	TransformResult(v interface{}) (interface{}, error)

	// TransformEvents transform events, as returned from QueryChange.Events
	// into events for the external resource.
	TransformEvents(events []ResultEvent) ([]ResultEvent, error)
}

QueryTransformer is an interface with methods to transform and validate an incoming query so that it can be passed to a QueryStore. And transforming the results so that it can be returned as an external resource.

type ReadTxn

type ReadTxn interface {
	// ID returns the ID string of the resource.
	ID() string

	// Close closes the transaction, rendering it unusable for any subsequent
	// calls. Close will return an error if it has already been called.
	Close() error

	// Exists returns true if the value exists, or false on read error or if the
	// resource does not exist.
	Exists() bool

	// Value returns the stored value. Value returns ErrNotFound (or an error
	// that wraps ErrNotFound), if a resource with the provided ID does not
	// exist in the store.
	Value() (interface{}, error)
}

ReadTxn represents a read transaction.

type ResultEvent

type ResultEvent struct {
	// Name of the event.
	Name string

	// Index position where the resource is added or removed from the query
	// result.
	//
	// Only valid for "add" and "remove" events.
	Idx int

	// ID of resource being added or removed from the query result.
	//
	// Only valid for "add" and "remove" events.
	Value interface{}

	// Changed property values for the model emitting the event.
	//
	// Only valid for "change" events.
	Changed map[string]interface{}
}

ResultEvent represents an event on a query result.

See: https://resgate.io/docs/specification/res-service-protocol/#events

type Store

type Store interface {
	// Read will return a read transaction once there are no open write
	// transaction for the same resource. The transaction will last until Close
	// is called.
	Read(id string) ReadTxn

	// Write will return a write transaction once there are no open read or
	// write transactions for the same resource. The transaction will last until
	// Close is called.
	//
	// If the Store implementation does not support the caller generating its
	// own ID for resource creation, the implementation's Write method may
	// accept an empty ID string. In such case, any call to WriteTxn.Value,
	// WriteTxn.Update, and WriteTxn.Delete returns ErrNotFound (or an error
	// that wraps ErrNotFound), until WriteTxn.Create has been called. After
	// Create is called, the ID method should returns the new ID. If the Store
	// implementation does not support generating new IDs, a call to
	// WriteTxn.Create with an empty ID returns an error.
	Write(id string) WriteTxn

	// OnChange registers a callback that is called whenever a resource has been
	// modified. The callback parameters describes the ID of the modified
	// resource, and the value before and after modification.
	//
	// If the before-value is nil, the resource was created. If the after-value
	// is nil, the resource was deleted.
	OnChange(func(id string, before, after interface{}))
}

Store is a CRUD interface for storing resources of a specific type. The resources are identified by a unique ID string.

The value type returned by ReadTxn.Value, and passed to the OnChange callback, is determined by the Store, and remains the same for all calls. The Store expects that the same type is also passed as values to the WriteTxn.Create and WriteTxn.Update methods.

type Transformer

type Transformer interface {
	// RIDToID transforms an external resource ID to the internal ID, used by
	// the store. An empty ID will be interpreted as resource not found.
	RIDToID(rid string, pathParams map[string]string) string

	// IDToRID transforms an internal ID, used by the store, to an external
	// resource ID. Pattern is the full pattern for the resource ID.
	//
	// An empty RID will be interpreted as resource not found.
	IDToRID(id string, v interface{}, pattern res.Pattern) string

	// Transform transforms an internal value, persisted in the store, to an
	// external resource to send to the requesting client.
	Transform(id string, v interface{}) (interface{}, error)
}

Transformer is an interface with methods to transform a stored resource into a resource served by the service.

func IDTransformer

func IDTransformer(tagName string, transform func(id string, v interface{}) (interface{}, error)) Transformer

IDTransformer returns a transformer where the resource ID contains a single tag that is the internal ID.

// Assuming pattern is "library.book.$bookid"
IDTransformer("bookId", nil) // transforms "library.book.42" <=> "42"

func TransformFuncs

func TransformFuncs(ridToID func(rid string, pathParams map[string]string) string, idToRID func(id string, v interface{}, p res.Pattern) string, transform func(id string, v interface{}) (interface{}, error)) Transformer

TransformFuncs returns a Transformer that uses the provided functions. Any nil function will pass the value untransformed.

type Value

type Value struct {
	json.RawMessage
	Type  ValueType
	RID   string
	Inner json.RawMessage
}

Value represents a RES value https://github.com/resgateio/resgate/blob/master/docs/res-protocol.md#values

func (Value) Equal

func (v Value) Equal(w Value) bool

Equal reports whether v and w is equal in type and value

func (Value) MarshalJSON

func (v Value) MarshalJSON() ([]byte, error)

MarshalJSON returns the embedded json.RawMessage as the JSON encoding.

func (*Value) UnmarshalJSON

func (v *Value) UnmarshalJSON(data []byte) error

UnmarshalJSON sets *v to the RES value represented by the JSON encoded data

type ValueType

type ValueType byte

ValueType is an enum reprenting the value type

const (
	ValueTypeNone ValueType = iota
	ValueTypePrimitive
	ValueTypeReference
	ValueTypeSoftReference
	ValueTypeData
	ValueTypeDelete

	// Deprecated and replaced with ValueTypeReference.
	ValueTypeResource = ValueTypeReference
)

Value type constants

type WriteTxn

type WriteTxn interface {
	ReadTxn

	// Create adds a new value to the store.
	//
	// If a resource with the same ID already exists in the store, or if a
	// unique index is violated, Create returns ErrDuplicate (or an error that
	// wraps ErrDuplicate).
	//
	// If the value is successfully created, the Store OnChange callbacks will
	// be triggered on the calling goroutine with the before-value set to nil.
	Create(interface{}) error

	// Update replaces an existing value in the store.
	//
	// If the value does not exist, Update returns ErrNotFound (or an error that
	// wraps ErrNotFound).
	//
	// If the value is successfully updated, the Store OnChange callbacks will
	// be triggered on the calling goroutine.
	Update(interface{}) error

	// Delete deletes an existing value from the store.
	//
	// If the value does not exist, Delete returns ErrNotFound (or an error that
	// wraps ErrNotFound).
	//
	// If the value is successfully deleted, the Store OnChange callbacks will
	// be triggered on the calling goroutine with the after-value set to nil.
	Delete() error
}

WriteTxn represents a write transaction.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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