diff --git a/bitcask/LICENSE b/bitcask/LICENSE deleted file mode 100644 index 0211f54..0000000 --- a/bitcask/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 kayos (kayos@tcp.direct) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/loader/open.go b/loader/open.go index 60b3f79..70aebf5 100644 --- a/loader/open.go +++ b/loader/open.go @@ -41,7 +41,17 @@ func OpenKeeper(path string, opts ...any) (database.Keeper, error) { if keeperCreator = registry.GetKeeper(meta.KeeperType); keeperCreator == nil { return nil, fmt.Errorf("keeper type %s not found in registry", meta.KeeperType) } - keeper, err := keeperCreator(path, meta.DefStoreOpts) + + var ( + keeper database.Keeper + ) + + if len(opts) > 0 { + keeper, err = keeperCreator(path, opts...) + } else { + keeper, err = keeperCreator(path) + } + if err != nil { return nil, fmt.Errorf("error substantiating keeper: %w", err) } diff --git a/loader/open_test.go b/loader/open_test.go index 76a844c..eecfdd3 100644 --- a/loader/open_test.go +++ b/loader/open_test.go @@ -66,3 +66,35 @@ func TestOpenKeeper(t *testing.T) { t.Errorf("expected yeet2, got %s", val) } } + +func TestOpenKeeperWithOpts(t *testing.T) { + nmK := database.NewMockKeeper("yeeties") + _ = nmK.WithNew("yeets").Put([]byte("yeets"), []byte("yeets")) + _ = nmK.WithNew("yeets1").Put([]byte("yeet1"), []byte("yeet1")) + tmp := filepath.Join(t.TempDir(), "meta.json") + if err := nmK.WriteMeta(tmp); err != nil { + t.Fatalf("error writing meta: %v", err) + } + keeper, err := OpenKeeper(tmp, "yeeterson mcgee", "yeet it") + if err != nil { + t.Fatalf("error opening keeper: %v", err) + } + for _, store := range keeper.AllStores() { + found := 0 + for _, opt := range store.(*database.MockFiler).Opts { + if opt == "yeet it" { + found++ + } + if opt == "yeeterson mcgee" { + found++ + } + t.Logf("found option: %v", opt) + } + if found > 2 { + t.Fatal("too many options") + } + if found != 2 { + t.Fatal("not enough options") + } + } +} diff --git a/test/mock.go b/test/mock.go index e3aa0a7..c2b5cf5 100644 --- a/test/mock.go +++ b/test/mock.go @@ -3,7 +3,9 @@ package database import ( "encoding/json" "errors" + "fmt" "os" + "slices" "sync" "time" @@ -23,6 +25,7 @@ type MockFiler struct { name string values map[string][]byte closed bool + Opts []MockOpt mu sync.RWMutex } @@ -37,8 +40,8 @@ func (m *MockKeeper) WriteMeta(path string) error { mockMu.Lock() mockKeepers[m.name] = m.AllStores() mockMu.Unlock() - registry.RegisterKeeper(m.name, func(path string, _ ...any) (database.Keeper, error) { - return NewMockKeeper(m.name), nil + registry.RegisterKeeper(m.name, func(path string, opts ...any) (database.Keeper, error) { + return NewMockKeeper(m.name, opts...), nil }) return json.NewEncoder(f).Encode(m.Meta()) @@ -109,27 +112,68 @@ func (m *MockFiler) Len() int { return l } +type MockOpt string + type MockKeeper struct { - name string - path string - stores map[string]database.Filer - mu sync.RWMutex + name string + path string + defOpts []MockOpt + stores map[string]database.Filer + mu sync.RWMutex } -func NewMockKeeper(name string) *MockKeeper { - return &MockKeeper{ +func NewMockKeeper(name string, defopts ...any) *MockKeeper { + opts := make([]MockOpt, 0, len(defopts)) + for _, opt := range defopts { + if opt == nil { + println("nil opt") + continue + } + if strOpt, strOK := opt.(string); strOK { + opt = MockOpt(strOpt) + } + if _, ok := opt.(MockOpt); !ok { + panic(fmt.Errorf("%w: (%T): %v", ErrBadOptions, opt, opt)) + } + opts = append(opts, opt.(MockOpt)) + } + + mk := &MockKeeper{ name: name, stores: make(map[string]database.Filer), } + + if len(opts) > 0 { + mk.defOpts = opts + } + + return mk } func (m *MockKeeper) Path() string { return m.path } +var ErrBadOptions = errors.New("bad mock filer options") + func (m *MockKeeper) Init(name string, options ...any) error { m.mu.Lock() m.stores[name] = &MockFiler{name: name, values: make(map[string][]byte)} + if len(options) > 0 { + for _, opt := range options { + strOpt, strOK := opt.(string) + mockOpt, mockOK := opt.(MockOpt) + if !strOK && !mockOK { + return ErrBadOptions + } + if strOK { + mockOpt = MockOpt(strOpt) + } + m.stores[name].(*MockFiler).Opts = append(m.stores[name].(*MockFiler).Opts, mockOpt) + } + } else if m.defOpts != nil { + m.stores[name].(*MockFiler).Opts = append(m.stores[name].(*MockFiler).Opts, m.defOpts...) + } m.mu.Unlock() return nil } @@ -171,10 +215,18 @@ func (m *MockKeeper) Destroy(name string) error { } func (m *MockKeeper) Discover() ([]string, error) { + getStores := func() []string { + names := make([]string, 0, len(m.stores)) + for name := range m.stores { + names = append(names, name) + } + return names + } + m.mu.RLock() if m.stores != nil && len(m.stores) > 0 { m.mu.RUnlock() - return nil, nil + return getStores(), nil } mockMu.RLock() stores, ok := mockKeepers[m.name] @@ -182,16 +234,22 @@ func (m *MockKeeper) Discover() ([]string, error) { if ok { m.mu.RUnlock() m.mu.Lock() + for _, s := range stores { + if m.defOpts != nil { + for _, v := range m.defOpts { + if !slices.Contains(s.(*MockFiler).Opts, v) { + s.(*MockFiler).Opts = append(s.(*MockFiler).Opts, v) + } + } + } + } m.stores = stores m.mu.Unlock() m.mu.RLock() } - names := make([]string, 0, len(m.stores)) - for name := range m.stores { - names = append(names, name) - } + m.mu.RUnlock() - return names, nil + return getStores(), nil } func (m *MockKeeper) AllStores() map[string]database.Filer {