query

package
v0.0.0-...-8b9b725 Latest Latest
Warning

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

Go to latest
Published: Apr 7, 2019 License: MIT, MIT Imports: 7 Imported by: 74

Documentation

Index

Constants

View Source
const KeysOnlyBufSize = 128
View Source
const NormalBufSize = 1

Variables

View Source
var (
	Equal              = Op("==")
	NotEqual           = Op("!=")
	GreaterThan        = Op(">")
	GreaterThanOrEqual = Op(">=")
	LessThan           = Op("<")
	LessThanOrEqual    = Op("<=")
)

Functions

This section is empty.

Types

type Entry

type Entry struct {
	Key        string    // cant be ds.Key because circular imports ...!!!
	Value      []byte    // Will be nil if KeysOnly has been passed.
	Expiration time.Time // Entry expiration timestamp if requested and supported (see TTLDatastore).
}

Entry is a query result entry.

func ResultEntriesFrom

func ResultEntriesFrom(keys []string, vals [][]byte) []Entry

type Filter

type Filter interface {
	// Filter returns whether an entry passes the filter
	Filter(e Entry) bool
}

Filter is an object that tests ResultEntries

type FilterKeyCompare

type FilterKeyCompare struct {
	Op  Op
	Key string
}

func (FilterKeyCompare) Filter

func (f FilterKeyCompare) Filter(e Entry) bool

type FilterKeyPrefix

type FilterKeyPrefix struct {
	Prefix string
}

func (FilterKeyPrefix) Filter

func (f FilterKeyPrefix) Filter(e Entry) bool

type FilterValueCompare

type FilterValueCompare struct {
	Op          Op
	Value       interface{}
	TypedFilter Filter
}

FilterValueCompare is used to signal to datastores they should apply internal comparisons. unfortunately, there is no way to apply comparisons* to interface{} types in Go, so if the datastore doesnt have a special way to handle these comparisons, you must provided the TypedFilter to actually do filtering.

[*] other than == and !=, which use reflect.DeepEqual.

func (FilterValueCompare) Filter

func (f FilterValueCompare) Filter(e Entry) bool

type Iterator

type Iterator struct {
	Next  func() (Result, bool)
	Close func() error // note: might be called more than once
}

type Op

type Op string

Op is a comparison operator

type Order

type Order interface {
	Compare(a, b Entry) int
}

Order is an object used to order objects

type OrderByFunction

type OrderByFunction func(a, b Entry) int

OrderByFunction orders the results based on the result of the given function.

func (OrderByFunction) Compare

func (o OrderByFunction) Compare(a, b Entry) int

type OrderByKey

type OrderByKey struct{}

OrderByKey

func (OrderByKey) Compare

func (o OrderByKey) Compare(a, b Entry) int

type OrderByKeyDescending

type OrderByKeyDescending struct{}

OrderByKeyDescending

func (OrderByKeyDescending) Compare

func (o OrderByKeyDescending) Compare(a, b Entry) int

type OrderByValue

type OrderByValue struct{}

OrderByValue is used to signal to datastores they should apply internal orderings.

func (OrderByValue) Compare

func (o OrderByValue) Compare(a, b Entry) int

type OrderByValueDescending

type OrderByValueDescending struct{}

OrderByValueDescending is used to signal to datastores they should apply internal orderings.

func (OrderByValueDescending) Compare

func (o OrderByValueDescending) Compare(a, b Entry) int

type Query

type Query struct {
	Prefix            string   // namespaces the query to results whose keys have Prefix
	Filters           []Filter // filter results. apply sequentially
	Orders            []Order  // order results. apply hierarchically
	Limit             int      // maximum number of results
	Offset            int      // skip given number of results
	KeysOnly          bool     // return only keys.
	ReturnExpirations bool     // return expirations (see TTLDatastore)
}

Query represents storage for any key-value pair.

tl;dr:

queries are supported across datastores.
Cheap on top of relational dbs, and expensive otherwise.
Pick the right tool for the job!

In addition to the key-value store get and set semantics, datastore provides an interface to retrieve multiple records at a time through the use of queries. The datastore Query model gleans a common set of operations performed when querying. To avoid pasting here years of database research, let’s summarize the operations datastore supports.

Query Operations:

  • namespace - scope the query, usually by object type
  • filters - select a subset of values by applying constraints
  • orders - sort the results by applying sort conditions
  • limit - impose a numeric limit on the number of results
  • offset - skip a number of results (for efficient pagination)

datastore combines these operations into a simple Query class that allows applications to define their constraints in a simple, generic, way without introducing datastore specific calls, languages, etc.

Of course, different datastores provide relational query support across a wide spectrum, from full support in traditional databases to none at all in most key-value stores. Datastore aims to provide a common, simple interface for the sake of application evolution over time and keeping large code bases free of tool-specific code. It would be ridiculous to claim to support high- performance queries on architectures that obviously do not. Instead, datastore provides the interface, ideally translating queries to their native form (e.g. into SQL for MySQL).

However, on the wrong datastore, queries can potentially incur the high cost of performing the aforemantioned query operations on the data set directly in Go. It is the client’s responsibility to select the right tool for the job: pick a data storage solution that fits the application’s needs now, and wrap it with a datastore implementation. As the needs change, swap out datastore implementations to support your new use cases. Some applications, particularly in early development stages, can afford to incurr the cost of queries on non- relational databases (e.g. using a FSDatastore and not worry about a database at all). When it comes time to switch the tool for performance, updating the application code can be as simple as swapping the datastore in one place, not all over the application code base. This gain in engineering time, both at initial development and during later iterations, can significantly offset the cost of the layer of abstraction.

type Result

type Result struct {
	Entry

	Error error
}

Result is a special entry that includes an error, so that the client may be warned about internal errors.

type ResultBuilder

type ResultBuilder struct {
	Query   Query
	Process goprocess.Process
	Output  chan Result
}

ResultBuilder is what implementors use to construct results Implementors of datastores and their clients must respect the Process of the Request:

  • clients must call r.Process().Close() on an early exit, so implementations can reclaim resources.
  • if the Entries are read to completion (channel closed), Process should be closed automatically.
  • datastores must respect <-Process.Closing(), which intermediates an early close signal from the client.

func NewResultBuilder

func NewResultBuilder(q Query) *ResultBuilder

func (*ResultBuilder) Results

func (rb *ResultBuilder) Results() Results

Results returns a Results to to this builder.

type Results

type Results interface {
	Query() Query             // the query these Results correspond to
	Next() <-chan Result      // returns a channel to wait for the next result
	NextSync() (Result, bool) // blocks and waits to return the next result, second paramter returns false when results are exhausted
	Rest() ([]Entry, error)   // waits till processing finishes, returns all entries at once.
	Close() error             // client may call Close to signal early exit

	// Process returns a goprocess.Process associated with these results.
	// most users will not need this function (Close is all they want),
	// but it's here in case you want to connect the results to other
	// goprocess-friendly things.
	Process() goprocess.Process
}

Results is a set of Query results. This is the interface for clients. Example:

qr, _ := myds.Query(q)
for r := range qr.Next() {
  if r.Error != nil {
    // handle.
    break
  }

  fmt.Println(r.Entry.Key, r.Entry.Value)
}

or, wait on all results at once:

qr, _ := myds.Query(q)
es, _ := qr.Rest()
for _, e := range es {
  	fmt.Println(e.Key, e.Value)
}

func DerivedResults

func DerivedResults(qr Results, ch <-chan Result) Results

func NaiveFilter

func NaiveFilter(qr Results, filter Filter) Results

NaiveFilter applies a filter to the results.

func NaiveLimit

func NaiveLimit(qr Results, limit int) Results

NaiveLimit truncates the results to a given int limit

func NaiveOffset

func NaiveOffset(qr Results, offset int) Results

NaiveOffset skips a given number of results

func NaiveOrder

func NaiveOrder(qr Results, orders ...Order) Results

NaiveOrder reorders results according to given orders. WARNING: this is the only non-stream friendly operation!

func NaiveQueryApply

func NaiveQueryApply(q Query, qr Results) Results

func ResultsFromIterator

func ResultsFromIterator(q Query, iter Iterator) Results

func ResultsReplaceQuery

func ResultsReplaceQuery(r Results, q Query) Results

func ResultsWithChan

func ResultsWithChan(q Query, res <-chan Result) Results

ResultsWithChan returns a Results object from a channel of Result entries. Respects its own Close()

func ResultsWithEntries

func ResultsWithEntries(q Query, res []Entry) Results

ResultsWithEntries returns a Results object from a list of entries

Jump to

Keyboard shortcuts

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