store: add Wrappers support, create Namespace wrapper
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
parent
0d1ef31764
commit
c3def24bf4
@ -36,16 +36,6 @@ func (m *memoryStore) key(prefix, key string) string {
|
||||
return filepath.Join(prefix, key)
|
||||
}
|
||||
|
||||
func (m *memoryStore) prefix(database, table string) string {
|
||||
if len(database) == 0 {
|
||||
database = m.opts.Database
|
||||
}
|
||||
if len(table) == 0 {
|
||||
table = m.opts.Table
|
||||
}
|
||||
return filepath.Join(database, table)
|
||||
}
|
||||
|
||||
func (m *memoryStore) exists(prefix, key string) error {
|
||||
key = m.key(prefix, key)
|
||||
|
||||
@ -127,37 +117,45 @@ func (m *memoryStore) Name() string {
|
||||
}
|
||||
|
||||
func (m *memoryStore) Exists(ctx context.Context, key string, opts ...ExistsOption) error {
|
||||
prefix := m.prefix(m.opts.Database, m.opts.Table)
|
||||
return m.exists(prefix, key)
|
||||
options := NewExistsOptions(opts...)
|
||||
if options.Namespace == "" {
|
||||
options.Namespace = m.opts.Namespace
|
||||
}
|
||||
return m.exists(options.Namespace, key)
|
||||
}
|
||||
|
||||
func (m *memoryStore) Read(ctx context.Context, key string, val interface{}, opts ...ReadOption) error {
|
||||
readOpts := NewReadOptions(opts...)
|
||||
prefix := m.prefix(readOpts.Database, readOpts.Table)
|
||||
return m.get(prefix, key, val)
|
||||
options := NewReadOptions(opts...)
|
||||
if options.Namespace == "" {
|
||||
options.Namespace = m.opts.Namespace
|
||||
}
|
||||
return m.get(options.Namespace, key, val)
|
||||
}
|
||||
|
||||
func (m *memoryStore) Write(ctx context.Context, key string, val interface{}, opts ...WriteOption) error {
|
||||
writeOpts := NewWriteOptions(opts...)
|
||||
options := NewWriteOptions(opts...)
|
||||
if options.Namespace == "" {
|
||||
options.Namespace = m.opts.Namespace
|
||||
}
|
||||
|
||||
prefix := m.prefix(writeOpts.Database, writeOpts.Table)
|
||||
|
||||
key = m.key(prefix, key)
|
||||
key = m.key(options.Namespace, key)
|
||||
|
||||
buf, err := m.opts.Codec.Marshal(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.store.Set(key, buf, writeOpts.TTL)
|
||||
m.store.Set(key, buf, options.TTL)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memoryStore) Delete(ctx context.Context, key string, opts ...DeleteOption) error {
|
||||
deleteOptions := NewDeleteOptions(opts...)
|
||||
options := NewDeleteOptions(opts...)
|
||||
if options.Namespace == "" {
|
||||
options.Namespace = m.opts.Namespace
|
||||
}
|
||||
|
||||
prefix := m.prefix(deleteOptions.Database, deleteOptions.Table)
|
||||
m.delete(prefix, key)
|
||||
m.delete(options.Namespace, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -166,25 +164,27 @@ func (m *memoryStore) Options() Options {
|
||||
}
|
||||
|
||||
func (m *memoryStore) List(ctx context.Context, opts ...ListOption) ([]string, error) {
|
||||
listOptions := NewListOptions(opts...)
|
||||
options := NewListOptions(opts...)
|
||||
if options.Namespace == "" {
|
||||
options.Namespace = m.opts.Namespace
|
||||
}
|
||||
|
||||
prefix := m.prefix(listOptions.Database, listOptions.Table)
|
||||
keys := m.list(prefix, listOptions.Limit, listOptions.Offset)
|
||||
keys := m.list(options.Namespace, options.Limit, options.Offset)
|
||||
|
||||
if len(listOptions.Prefix) > 0 {
|
||||
if len(options.Prefix) > 0 {
|
||||
var prefixKeys []string
|
||||
for _, k := range keys {
|
||||
if strings.HasPrefix(k, listOptions.Prefix) {
|
||||
if strings.HasPrefix(k, options.Prefix) {
|
||||
prefixKeys = append(prefixKeys, k)
|
||||
}
|
||||
}
|
||||
keys = prefixKeys
|
||||
}
|
||||
|
||||
if len(listOptions.Suffix) > 0 {
|
||||
if len(options.Suffix) > 0 {
|
||||
var suffixKeys []string
|
||||
for _, k := range keys {
|
||||
if strings.HasSuffix(k, listOptions.Suffix) {
|
||||
if strings.HasSuffix(k, options.Suffix) {
|
||||
suffixKeys = append(suffixKeys, k)
|
||||
}
|
||||
}
|
||||
|
@ -9,11 +9,11 @@ import (
|
||||
)
|
||||
|
||||
func TestMemoryReInit(t *testing.T) {
|
||||
s := store.NewStore(store.Table("aaa"))
|
||||
if err := s.Init(store.Table("")); err != nil {
|
||||
s := store.NewStore(store.Namespace("aaa"))
|
||||
if err := s.Init(store.Namespace("")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(s.Options().Table) > 0 {
|
||||
if len(s.Options().Namespace) > 0 {
|
||||
t.Error("Init didn't reinitialise the store")
|
||||
}
|
||||
}
|
||||
@ -28,7 +28,7 @@ func TestMemoryBasic(t *testing.T) {
|
||||
|
||||
func TestMemoryPrefix(t *testing.T) {
|
||||
s := store.NewStore()
|
||||
if err := s.Init(store.Table("some-prefix")); err != nil {
|
||||
if err := s.Init(store.Namespace("some-prefix")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
basictest(s, t)
|
||||
@ -36,7 +36,7 @@ func TestMemoryPrefix(t *testing.T) {
|
||||
|
||||
func TestMemoryNamespace(t *testing.T) {
|
||||
s := store.NewStore()
|
||||
if err := s.Init(store.Database("some-namespace")); err != nil {
|
||||
if err := s.Init(store.Namespace("some-namespace")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
basictest(s, t)
|
||||
@ -44,7 +44,7 @@ func TestMemoryNamespace(t *testing.T) {
|
||||
|
||||
func TestMemoryNamespacePrefix(t *testing.T) {
|
||||
s := store.NewStore()
|
||||
if err := s.Init(store.Table("some-prefix"), store.Database("some-namespace")); err != nil {
|
||||
if err := s.Init(store.Namespace("some-namespace")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
basictest(s, t)
|
||||
|
261
store/options.go
261
store/options.go
@ -28,13 +28,12 @@ type Options struct {
|
||||
TLSConfig *tls.Config
|
||||
// Name specifies store name
|
||||
Name string
|
||||
// Database specifies store database
|
||||
Database string
|
||||
// Table specifies store table
|
||||
Table string
|
||||
// Nodes contains store address
|
||||
// TODO: replace with Addrs
|
||||
Nodes []string
|
||||
// Namespace of the records
|
||||
Namespace string
|
||||
// Addrs contains store address
|
||||
Addrs []string
|
||||
//Wrappers store wrapper that called before actual functions
|
||||
//Wrappers []Wrapper
|
||||
}
|
||||
|
||||
// NewOptions creates options struct
|
||||
@ -90,13 +89,20 @@ func Meter(m meter.Meter) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// Name the name
|
||||
// Name the name of the store
|
||||
func Name(n string) Option {
|
||||
return func(o *Options) {
|
||||
o.Name = n
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace sets namespace of the store
|
||||
func Namespace(ns string) Option {
|
||||
return func(o *Options) {
|
||||
o.Namespace = ns
|
||||
}
|
||||
}
|
||||
|
||||
// Tracer sets the tracer
|
||||
func Tracer(t tracer.Tracer) Option {
|
||||
return func(o *Options) {
|
||||
@ -104,27 +110,21 @@ func Tracer(t tracer.Tracer) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// Nodes contains the addresses or other connection information of the backing storage.
|
||||
// Addrs contains the addresses or other connection information of the backing storage.
|
||||
// For example, an etcd implementation would contain the nodes of the cluster.
|
||||
// A SQL implementation could contain one or more connection strings.
|
||||
func Nodes(a ...string) Option {
|
||||
func Addrs(addrs ...string) Option {
|
||||
return func(o *Options) {
|
||||
o.Nodes = a
|
||||
o.Addrs = addrs
|
||||
}
|
||||
}
|
||||
|
||||
// Database allows multiple isolated stores to be kept in one backend, if supported.
|
||||
func Database(db string) Option {
|
||||
return func(o *Options) {
|
||||
o.Database = db
|
||||
}
|
||||
}
|
||||
|
||||
// Table is analag for a table in database backends or a key prefix in KV backends
|
||||
func Table(t string) Option {
|
||||
return func(o *Options) {
|
||||
o.Table = t
|
||||
}
|
||||
// ReadOptions configures an individual Read operation
|
||||
type ReadOptions struct {
|
||||
// Context holds external options
|
||||
Context context.Context
|
||||
// Namespace holds namespace
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// NewReadOptions fills ReadOptions struct with opts slice
|
||||
@ -136,29 +136,35 @@ func NewReadOptions(opts ...ReadOption) ReadOptions {
|
||||
return options
|
||||
}
|
||||
|
||||
// ReadOptions configures an individual Read operation
|
||||
type ReadOptions struct {
|
||||
// Context holds external options
|
||||
Context context.Context
|
||||
// Database holds the database name
|
||||
Database string
|
||||
// Table holds table name
|
||||
Table string
|
||||
// Namespace holds namespace
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// ReadOption sets values in ReadOptions
|
||||
type ReadOption func(r *ReadOptions)
|
||||
|
||||
// ReadFrom the database and table
|
||||
func ReadFrom(database, table string) ReadOption {
|
||||
return func(r *ReadOptions) {
|
||||
r.Database = database
|
||||
r.Table = table
|
||||
// ReadContext pass context.Context to ReadOptions
|
||||
func ReadContext(ctx context.Context) ReadOption {
|
||||
return func(o *ReadOptions) {
|
||||
o.Context = ctx
|
||||
}
|
||||
}
|
||||
|
||||
// ReadNamespace pass namespace to ReadOptions
|
||||
func ReadNamespace(ns string) ReadOption {
|
||||
return func(o *ReadOptions) {
|
||||
o.Namespace = ns
|
||||
}
|
||||
}
|
||||
|
||||
// WriteOptions configures an individual Write operation
|
||||
type WriteOptions struct {
|
||||
// Context holds external options
|
||||
Context context.Context
|
||||
// Metadata contains additional metadata
|
||||
Metadata metadata.Metadata
|
||||
// Namespace holds namespace
|
||||
Namespace string
|
||||
// TTL specifies key TTL
|
||||
TTL time.Duration
|
||||
}
|
||||
|
||||
// NewWriteOptions fills WriteOptions struct with opts slice
|
||||
func NewWriteOptions(opts ...WriteOption) WriteOptions {
|
||||
options := WriteOptions{}
|
||||
@ -168,47 +174,45 @@ func NewWriteOptions(opts ...WriteOption) WriteOptions {
|
||||
return options
|
||||
}
|
||||
|
||||
// WriteOptions configures an individual Write operation
|
||||
type WriteOptions struct {
|
||||
// Context holds external options
|
||||
Context context.Context
|
||||
// Metadata contains additional metadata
|
||||
Metadata metadata.Metadata
|
||||
// Database holds database name
|
||||
Database string
|
||||
// Table holds table name
|
||||
Table string
|
||||
// Namespace holds namespace
|
||||
Namespace string
|
||||
// TTL specifies key TTL
|
||||
TTL time.Duration
|
||||
}
|
||||
|
||||
// WriteOption sets values in WriteOptions
|
||||
type WriteOption func(w *WriteOptions)
|
||||
|
||||
// WriteTo the database and table
|
||||
func WriteTo(database, table string) WriteOption {
|
||||
return func(w *WriteOptions) {
|
||||
w.Database = database
|
||||
w.Table = table
|
||||
}
|
||||
}
|
||||
|
||||
// WriteTTL is the time the record expires
|
||||
func WriteTTL(d time.Duration) WriteOption {
|
||||
return func(w *WriteOptions) {
|
||||
w.TTL = d
|
||||
// WriteContext pass context.Context to wirte options
|
||||
func WriteContext(ctx context.Context) WriteOption {
|
||||
return func(o *WriteOptions) {
|
||||
o.Context = ctx
|
||||
}
|
||||
}
|
||||
|
||||
// WriteMetadata add metadata.Metadata
|
||||
func WriteMetadata(md metadata.Metadata) WriteOption {
|
||||
return func(w *WriteOptions) {
|
||||
w.Metadata = metadata.Copy(md)
|
||||
return func(o *WriteOptions) {
|
||||
o.Metadata = metadata.Copy(md)
|
||||
}
|
||||
}
|
||||
|
||||
// WriteTTL is the time the record expires
|
||||
func WriteTTL(d time.Duration) WriteOption {
|
||||
return func(o *WriteOptions) {
|
||||
o.TTL = d
|
||||
}
|
||||
}
|
||||
|
||||
// WriteNamespace pass namespace to write options
|
||||
func WriteNamespace(ns string) WriteOption {
|
||||
return func(o *WriteOptions) {
|
||||
o.Namespace = ns
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteOptions configures an individual Delete operation
|
||||
type DeleteOptions struct {
|
||||
// Context holds external options
|
||||
Context context.Context
|
||||
// Namespace holds namespace
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// NewDeleteOptions fills DeleteOptions struct with opts slice
|
||||
func NewDeleteOptions(opts ...DeleteOption) DeleteOptions {
|
||||
options := DeleteOptions{}
|
||||
@ -218,29 +222,33 @@ func NewDeleteOptions(opts ...DeleteOption) DeleteOptions {
|
||||
return options
|
||||
}
|
||||
|
||||
// DeleteOptions configures an individual Delete operation
|
||||
type DeleteOptions struct {
|
||||
// Context holds external options
|
||||
Context context.Context
|
||||
// Database holds database name
|
||||
Database string
|
||||
// Table holds table name
|
||||
Table string
|
||||
// Namespace holds namespace
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// DeleteOption sets values in DeleteOptions
|
||||
type DeleteOption func(d *DeleteOptions)
|
||||
|
||||
// DeleteFrom the database and table
|
||||
func DeleteFrom(database, table string) DeleteOption {
|
||||
return func(d *DeleteOptions) {
|
||||
d.Database = database
|
||||
d.Table = table
|
||||
// DeleteContext pass context.Context to delete options
|
||||
func DeleteContext(ctx context.Context) DeleteOption {
|
||||
return func(o *DeleteOptions) {
|
||||
o.Context = ctx
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteNamespace pass namespace to delete options
|
||||
func DeleteNamespace(ns string) DeleteOption {
|
||||
return func(o *DeleteOptions) {
|
||||
o.Namespace = ns
|
||||
}
|
||||
}
|
||||
|
||||
// ListOptions configures an individual List operation
|
||||
type ListOptions struct {
|
||||
Context context.Context
|
||||
Prefix string
|
||||
Suffix string
|
||||
Namespace string
|
||||
Limit uint
|
||||
Offset uint
|
||||
}
|
||||
|
||||
// NewListOptions fills ListOptions struct with opts slice
|
||||
func NewListOptions(opts ...ListOption) ListOptions {
|
||||
options := ListOptions{}
|
||||
@ -250,59 +258,50 @@ func NewListOptions(opts ...ListOption) ListOptions {
|
||||
return options
|
||||
}
|
||||
|
||||
// ListOptions configures an individual List operation
|
||||
type ListOptions struct {
|
||||
Context context.Context
|
||||
Database string
|
||||
Prefix string
|
||||
Suffix string
|
||||
Namespace string
|
||||
Table string
|
||||
Limit uint
|
||||
Offset uint
|
||||
}
|
||||
|
||||
// ListOption sets values in ListOptions
|
||||
type ListOption func(l *ListOptions)
|
||||
|
||||
// ListFrom the database and table
|
||||
func ListFrom(database, table string) ListOption {
|
||||
return func(l *ListOptions) {
|
||||
l.Database = database
|
||||
l.Table = table
|
||||
// ListContext pass context.Context to list options
|
||||
func ListContext(ctx context.Context) ListOption {
|
||||
return func(o *ListOptions) {
|
||||
o.Context = ctx
|
||||
}
|
||||
}
|
||||
|
||||
// ListPrefix returns all keys that are prefixed with key
|
||||
func ListPrefix(p string) ListOption {
|
||||
return func(l *ListOptions) {
|
||||
l.Prefix = p
|
||||
func ListPrefix(s string) ListOption {
|
||||
return func(o *ListOptions) {
|
||||
o.Prefix = s
|
||||
}
|
||||
}
|
||||
|
||||
// ListSuffix returns all keys that end with key
|
||||
func ListSuffix(s string) ListOption {
|
||||
return func(l *ListOptions) {
|
||||
l.Suffix = s
|
||||
return func(o *ListOptions) {
|
||||
o.Suffix = s
|
||||
}
|
||||
}
|
||||
|
||||
// ListLimit limits the number of returned keys to l
|
||||
func ListLimit(l uint) ListOption {
|
||||
return func(lo *ListOptions) {
|
||||
lo.Limit = l
|
||||
// ListLimit limits the number of returned keys
|
||||
func ListLimit(n uint) ListOption {
|
||||
return func(o *ListOptions) {
|
||||
o.Limit = n
|
||||
}
|
||||
}
|
||||
|
||||
// ListOffset starts returning responses from o. Use in conjunction with Limit for pagination.
|
||||
func ListOffset(o uint) ListOption {
|
||||
return func(l *ListOptions) {
|
||||
l.Offset = o
|
||||
// ListOffset use with Limit for pagination
|
||||
func ListOffset(n uint) ListOption {
|
||||
return func(o *ListOptions) {
|
||||
o.Offset = n
|
||||
}
|
||||
}
|
||||
|
||||
// ExistsOption specifies Exists call options
|
||||
type ExistsOption func(*ExistsOptions)
|
||||
// ListNamespace pass namespace to list options
|
||||
func ListNamespace(ns string) ListOption {
|
||||
return func(o *ListOptions) {
|
||||
o.Namespace = ns
|
||||
}
|
||||
}
|
||||
|
||||
// ExistsOptions holds options for Exists method
|
||||
type ExistsOptions struct {
|
||||
@ -312,6 +311,9 @@ type ExistsOptions struct {
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// ExistsOption specifies Exists call options
|
||||
type ExistsOption func(*ExistsOptions)
|
||||
|
||||
// NewExistsOptions helper for Exists method
|
||||
func NewExistsOptions(opts ...ExistsOption) ExistsOptions {
|
||||
options := ExistsOptions{
|
||||
@ -322,3 +324,24 @@ func NewExistsOptions(opts ...ExistsOption) ExistsOptions {
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
// ExistsContext pass context.Context to exist options
|
||||
func ExistsContext(ctx context.Context) ExistsOption {
|
||||
return func(o *ExistsOptions) {
|
||||
o.Context = ctx
|
||||
}
|
||||
}
|
||||
|
||||
// ExistsNamespace pass namespace to exist options
|
||||
func ExistsNamespace(ns string) ExistsOption {
|
||||
return func(o *ExistsOptions) {
|
||||
o.Namespace = ns
|
||||
}
|
||||
}
|
||||
|
||||
// WrapStore adds a store Wrapper to a list of options passed into the store
|
||||
//func WrapStore(w Wrapper) Option {
|
||||
// return func(o *Options) {
|
||||
// o.Wrappers = append(o.Wrappers, w)
|
||||
// }
|
||||
//}
|
||||
|
84
store/wrapper.go
Normal file
84
store/wrapper.go
Normal file
@ -0,0 +1,84 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// LogfFunc function used for Logf method
|
||||
//type LogfFunc func(ctx context.Context, level Level, msg string, args ...interface{})
|
||||
|
||||
//type Wrapper interface {
|
||||
// Logf logs message with needed level
|
||||
//Logf(LogfFunc) LogfFunc
|
||||
//}
|
||||
|
||||
type NamespaceStore struct {
|
||||
s Store
|
||||
ns string
|
||||
}
|
||||
|
||||
var (
|
||||
_ Store = &NamespaceStore{}
|
||||
)
|
||||
|
||||
func NewNamespaceStore(s Store, ns string) Store {
|
||||
return &NamespaceStore{s: s, ns: ns}
|
||||
}
|
||||
|
||||
func (w *NamespaceStore) Init(opts ...Option) error {
|
||||
return w.s.Init(opts...)
|
||||
}
|
||||
|
||||
func (w *NamespaceStore) Connect(ctx context.Context) error {
|
||||
return w.s.Connect(ctx)
|
||||
}
|
||||
|
||||
func (w *NamespaceStore) Disconnect(ctx context.Context) error {
|
||||
return w.s.Disconnect(ctx)
|
||||
}
|
||||
|
||||
func (w *NamespaceStore) Read(ctx context.Context, key string, val interface{}, opts ...ReadOption) error {
|
||||
return w.s.Read(ctx, key, val, append(opts, ReadNamespace(w.ns))...)
|
||||
}
|
||||
|
||||
func (w *NamespaceStore) Write(ctx context.Context, key string, val interface{}, opts ...WriteOption) error {
|
||||
return w.s.Write(ctx, key, val, append(opts, WriteNamespace(w.ns))...)
|
||||
}
|
||||
|
||||
func (w *NamespaceStore) Delete(ctx context.Context, key string, opts ...DeleteOption) error {
|
||||
return w.s.Delete(ctx, key, append(opts, DeleteNamespace(w.ns))...)
|
||||
}
|
||||
|
||||
func (w *NamespaceStore) Exists(ctx context.Context, key string, opts ...ExistsOption) error {
|
||||
return w.s.Exists(ctx, key, append(opts, ExistsNamespace(w.ns))...)
|
||||
}
|
||||
|
||||
func (w *NamespaceStore) List(ctx context.Context, opts ...ListOption) ([]string, error) {
|
||||
return w.s.List(ctx, append(opts, ListNamespace(w.ns))...)
|
||||
}
|
||||
|
||||
func (w *NamespaceStore) Options() Options {
|
||||
return w.s.Options()
|
||||
}
|
||||
|
||||
func (w *NamespaceStore) Name() string {
|
||||
return w.s.Name()
|
||||
}
|
||||
|
||||
func (w *NamespaceStore) String() string {
|
||||
return w.s.String()
|
||||
}
|
||||
|
||||
//type NamespaceWrapper struct{}
|
||||
|
||||
//func NewNamespaceWrapper() Wrapper {
|
||||
// return &NamespaceWrapper{}
|
||||
//}
|
||||
|
||||
/*
|
||||
func (w *OmitWrapper) Logf(fn LogfFunc) LogfFunc {
|
||||
return func(ctx context.Context, level Level, msg string, args ...interface{}) {
|
||||
fn(ctx, level, msg, getArgs(args)...)
|
||||
}
|
||||
}
|
||||
*/
|
Loading…
Reference in New Issue
Block a user