From c3def24bf485f1f1797332017bec243870b3df8b Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Wed, 14 Jul 2021 17:11:37 +0300 Subject: [PATCH] store: add Wrappers support, create Namespace wrapper Signed-off-by: Vasiliy Tolstov --- store/memory.go | 60 +++++----- store/memory_test.go | 12 +- store/options.go | 261 +++++++++++++++++++++++-------------------- store/wrapper.go | 84 ++++++++++++++ 4 files changed, 262 insertions(+), 155 deletions(-) create mode 100644 store/wrapper.go diff --git a/store/memory.go b/store/memory.go index 9b65cf2d..e4d8ceb3 100644 --- a/store/memory.go +++ b/store/memory.go @@ -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) } } diff --git a/store/memory_test.go b/store/memory_test.go index d3e82e25..4669436f 100644 --- a/store/memory_test.go +++ b/store/memory_test.go @@ -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) diff --git a/store/options.go b/store/options.go index 54a4cd25..80011998 100644 --- a/store/options.go +++ b/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) +// } +//} diff --git a/store/wrapper.go b/store/wrapper.go new file mode 100644 index 00000000..44c2550e --- /dev/null +++ b/store/wrapper.go @@ -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)...) + } +} +*/