datastore.go 4.07 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1
package datastore
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
2 3

import (
Juan Batiz-Benet's avatar
go fmt  
Juan Batiz-Benet committed
4
	"errors"
5 6

	query "github.com/jbenet/go-datastore/query"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
7 8 9
)

/*
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
10
Datastore represents storage for any key-value pair.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

Datastores are general enough to be backed by all kinds of different storage:
in-memory caches, databases, a remote datastore, flat files on disk, etc.

The general idea is to wrap a more complicated storage facility in a simple,
uniform interface, keeping the freedom of using the right tools for the job.
In particular, a Datastore can aggregate other datastores in interesting ways,
like sharded (to distribute load) or tiered access (caches before databases).

While Datastores should be written general enough to accept all sorts of
values, some implementations will undoubtedly have to be specific (e.g. SQL
databases where fields should be decomposed into columns), particularly to
support queries efficiently. Moreover, certain datastores may enforce certain
types of values (e.g. requiring an io.Reader, a specific struct, etc) or
serialization formats (JSON, Protobufs, etc).

IMPORTANT: No Datastore should ever Panic! This is a cross-module interface,
and thus it should behave predictably and handle exceptional conditions with
proper error reporting. Thus, all Datastore calls may return errors, which
should be checked by callers.
*/
type Datastore interface {
Juan Batiz-Benet's avatar
go fmt  
Juan Batiz-Benet committed
33 34 35 36 37 38 39 40 41
	// Put stores the object `value` named by `key`.
	//
	// The generalized Datastore interface does not impose a value type,
	// allowing various datastore middleware implementations (which do not
	// handle the values directly) to be composed together.
	//
	// Ultimately, the lowest-level datastore will need to do some value checking
	// or risk getting incorrect values. It may also be useful to expose a more
	// type-safe interface to your application, and do the checking up-front.
42
	Put(key Key, value interface{}) error
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
43

Juan Batiz-Benet's avatar
go fmt  
Juan Batiz-Benet committed
44 45 46
	// Get retrieves the object `value` named by `key`.
	// Get will return ErrNotFound if the key is not mapped to a value.
	Get(key Key) (value interface{}, err error)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
47

Juan Batiz-Benet's avatar
go fmt  
Juan Batiz-Benet committed
48 49 50 51 52
	// Has returns whether the `key` is mapped to a `value`.
	// In some contexts, it may be much cheaper only to check for existence of
	// a value, rather than retrieving the value itself. (e.g. HTTP HEAD).
	// The default implementation is found in `GetBackedHas`.
	Has(key Key) (exists bool, err error)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
53

Juan Batiz-Benet's avatar
go fmt  
Juan Batiz-Benet committed
54
	// Delete removes the value for given `key`.
55
	Delete(key Key) error
Jeromy's avatar
Jeromy committed
56

57 58 59 60 61 62 63 64 65 66 67 68
	// Query searches the datastore and returns a query result. This function
	// may return before the query actually runs. To wait for the query:
	//
	//   result, _ := ds.Query(q)
	//
	//   // use the channel interface; result may come in at different times
	//   for entry := range result.Entries() { ... }
	//
	//	 // or wait for the query to be completely done
	//   result.Wait()
	//   result.AllEntries()
	//
69
	Query(q query.Query) (query.Results, error)
Jeromy's avatar
Jeromy committed
70 71 72 73
}

type BatchingDatastore interface {
	Datastore
Jeromy's avatar
Jeromy committed
74

Jeromy's avatar
Jeromy committed
75
	Batch() (Batch, error)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
76 77
}

Jeromy's avatar
Jeromy committed
78 79
var ErrBatchUnsupported = errors.New("this datastore does not support batching")

Juan Batiz-Benet's avatar
linting  
Juan Batiz-Benet committed
80 81
// ThreadSafeDatastore is an interface that all threadsafe datastore should
// implement to leverage type safety checks.
82 83 84 85 86
type ThreadSafeDatastore interface {
	Datastore
	IsThreadSafe()
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
87
// Errors
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
88 89 90

// ErrNotFound is returned by Get, Has, and Delete when a datastore does not
// map the given key to a value.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
91
var ErrNotFound = errors.New("datastore: key not found")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
92 93 94 95

// ErrInvalidType is returned by Put when a given value is incopatible with
// the type the datastore supports. This means a conversion (or serialization)
// is needed beforehand.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
96
var ErrInvalidType = errors.New("datastore: invalid type error")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
97

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
98 99 100 101 102 103 104
// GetBackedHas provides a default Datastore.Has implementation.
// It exists so Datastore.Has implementations can use it, like so:
//
// func (*d SomeDatastore) Has(key Key) (exists bool, err error) {
//   return GetBackedHas(d, key)
// }
func GetBackedHas(ds Datastore, key Key) (bool, error) {
Juan Batiz-Benet's avatar
go fmt  
Juan Batiz-Benet committed
105 106 107 108 109 110 111 112 113
	_, err := ds.Get(key)
	switch err {
	case nil:
		return true, nil
	case ErrNotFound:
		return false, nil
	default:
		return false, err
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
114
}
Jeromy's avatar
Jeromy committed
115

Jeromy's avatar
Jeromy committed
116
type Batch interface {
Jeromy's avatar
Jeromy committed
117 118 119 120 121 122
	Put(key Key, val interface{}) error

	Delete(key Key) error

	Commit() error
}