wip: testing
parent
145a4f3049
commit
f7cbd9fca2
|
@ -2,7 +2,6 @@ package mdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
|
|
||||||
"git.crumpington.com/private/mdb/keyedmutex"
|
"git.crumpington.com/private/mdb/keyedmutex"
|
||||||
)
|
)
|
||||||
|
@ -179,7 +178,6 @@ func (c *Collection[T]) loadData() {
|
||||||
toRemove := []int{}
|
toRemove := []int{}
|
||||||
for i, idx := range c.indices {
|
for i, idx := range c.indices {
|
||||||
if err := idx.load(c.items.m); err != nil {
|
if err := idx.load(c.items.m); err != nil {
|
||||||
log.Printf("Removing index %d because of error: %v", i, err)
|
|
||||||
toRemove = append([]int{i}, toRemove...)
|
toRemove = append([]int{i}, toRemove...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,6 @@ func (idx *itemMap[T]) mapGet(id uint64) (*T, bool) {
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
func (idx *itemMap[T]) nextID() uint64 {
|
func (idx *itemMap[T]) nextID() uint64 {
|
||||||
n := rand.Int63n(256)
|
n := 1 + rand.Int63n(256)
|
||||||
return atomic.AddUint64(&idx.maxID, uint64(n))
|
return atomic.AddUint64(&idx.maxID, uint64(n))
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,12 @@ func (m *MapIndex[K, T]) EqualsMap(data map[K]*T) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, exp := range data {
|
for key, exp := range data {
|
||||||
val, ok := m.m[key]
|
val, ok := m.Get(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("No value for %v. Expected: %v", key, *exp)
|
return fmt.Errorf("No value for %v. Expected: %v", key, *exp)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(*val, *exp) {
|
if !reflect.DeepEqual(val, *exp) {
|
||||||
return fmt.Errorf("Value mismatch %v: %v != %v", key, *val, *exp)
|
return fmt.Errorf("Value mismatch %v: %v != %v", key, val, *exp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
464
mapindex_test.go
464
mapindex_test.go
|
@ -1,323 +1,195 @@
|
||||||
package mdb
|
package mdb
|
||||||
|
|
||||||
/*
|
import (
|
||||||
func TestMapIndex(t *testing.T) {
|
"fmt"
|
||||||
type Item struct {
|
"reflect"
|
||||||
ID uint64
|
"testing"
|
||||||
Name string
|
)
|
||||||
ExtID string
|
|
||||||
}
|
|
||||||
|
|
||||||
checkIdxOne := func(idx *MapIndex[string, Item], expectedList ...Item) error {
|
func TestFullMapIndex(t *testing.T) {
|
||||||
expected := make(map[string]Item, len(expectedList))
|
|
||||||
for _, i := range expectedList {
|
|
||||||
expected[i.ExtID] = i
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(expected) != len(idx.m) {
|
// Test against the emailMap index.
|
||||||
return fmt.Errorf("Expected %d items, but got %d.", len(expected), len(idx.m))
|
run := func(name string, inner func(t *testing.T, db *DB) map[string]*User) {
|
||||||
}
|
testWithDB(t, name, func(t *testing.T, db *DB) {
|
||||||
|
expected := inner(t, db)
|
||||||
|
|
||||||
for _, e := range expected {
|
if err := db.Users.emailMap.EqualsMap(expected); err != nil {
|
||||||
i, ok := idx.Get(e.ExtID)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("Missing item: %v", e)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(i, e) {
|
|
||||||
return fmt.Errorf("Items not equal: %v != %v", i, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
checkIdx := func(idx *MapIndex[string, Item], expectedList ...Item) error {
|
|
||||||
idx.c.db.waitForWAL()
|
|
||||||
|
|
||||||
if err := checkIdxOne(idx, expectedList...); err != nil {
|
|
||||||
return fmt.Errorf("%w: original", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reload the database, collection, and index and re-test.
|
|
||||||
db := NewPrimary(idx.c.db.root)
|
|
||||||
c := NewCollection(db, "collection", func(i *Item) uint64 { return i.ID })
|
|
||||||
idx = NewMapIndex(c,
|
|
||||||
"ExtID",
|
|
||||||
func(i *Item) string { return i.ExtID },
|
|
||||||
func(i *Item) bool { return i.ExtID != "" })
|
|
||||||
db.Start()
|
|
||||||
return checkIdxOne(idx, expectedList...)
|
|
||||||
}
|
|
||||||
|
|
||||||
run := func(name string, inner func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item])) {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
root := filepath.Join(os.TempDir(), randString())
|
|
||||||
defer os.RemoveAll(root)
|
|
||||||
|
|
||||||
db := NewPrimary(root)
|
|
||||||
defer db.Close()
|
|
||||||
c := NewCollection(db, "collection", func(i *Item) uint64 { return i.ID })
|
|
||||||
idx := NewMapIndex(c,
|
|
||||||
"ExtID",
|
|
||||||
func(i *Item) string { return i.ExtID },
|
|
||||||
func(i *Item) bool { return i.ExtID != "" })
|
|
||||||
db.Start()
|
|
||||||
inner(t, c, idx)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
run("insert item not in index", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
item := Item{4, "4", ""}
|
|
||||||
c.Insert(item)
|
|
||||||
if err := checkIdx(idx); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
run("insert item in index", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
item1 := Item{4, "4", ""}
|
|
||||||
item2 := Item{5, "5", "abcd"}
|
|
||||||
c.Insert(item1)
|
|
||||||
c.Insert(item2)
|
|
||||||
if err := checkIdx(idx, item2); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
run("insert several items", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
item1 := Item{4, "4", ""}
|
|
||||||
item2 := Item{5, "5", "abcd"}
|
|
||||||
item3 := Item{6, "6", ""}
|
|
||||||
item4 := Item{7, "7", "xyz"}
|
|
||||||
item5 := Item{8, "8", ""}
|
|
||||||
item6 := Item{9, "9", "mmm"}
|
|
||||||
c.Insert(item1)
|
|
||||||
c.Insert(item2)
|
|
||||||
c.Insert(item3)
|
|
||||||
c.Insert(item4)
|
|
||||||
c.Insert(item5)
|
|
||||||
c.Insert(item6)
|
|
||||||
if err := checkIdx(idx, item2, item4, item6); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
run("insert with conflict", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
item1 := Item{1, "1", "one"}
|
|
||||||
item2 := Item{2, "2", "one"}
|
|
||||||
c.Insert(item1)
|
|
||||||
if _, err := c.Insert(item2); !errors.Is(err, ErrDuplicate) {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
run("update into index", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
item1 := Item{1, "1", ""}
|
|
||||||
c.Insert(item1)
|
|
||||||
|
|
||||||
if err := checkIdx(idx); err != nil {
|
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := c.Update(1, func(i Item) (Item, error) {
|
db.Close()
|
||||||
i.ExtID = "xx"
|
db = OpenDB(db.root, true)
|
||||||
return i, nil
|
|
||||||
|
if err := db.Users.emailMap.EqualsMap(expected); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
run("insert", func(t *testing.T, db *DB) map[string]*User {
|
||||||
|
users := map[string]*User{}
|
||||||
|
|
||||||
|
for i := uint64(1); i < 10; i++ {
|
||||||
|
user := &User{
|
||||||
|
ID: db.Users.c.NextID(),
|
||||||
|
Email: fmt.Sprintf("a.%d@c.com", i),
|
||||||
|
Name: fmt.Sprintf("name.%d", i),
|
||||||
|
ExtID: fmt.Sprintf("EXTID.%d", i),
|
||||||
|
}
|
||||||
|
|
||||||
|
user2, err := db.Users.c.Insert(*user)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(*user, user2) {
|
||||||
|
t.Fatal(*user, user2)
|
||||||
|
}
|
||||||
|
users[user.Email] = user
|
||||||
|
}
|
||||||
|
|
||||||
|
return users
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: insert duplicate
|
||||||
|
|
||||||
|
run("delete", func(t *testing.T, db *DB) map[string]*User {
|
||||||
|
users := map[string]*User{}
|
||||||
|
|
||||||
|
for i := uint64(1); i < 10; i++ {
|
||||||
|
user := &User{
|
||||||
|
ID: db.Users.c.NextID(),
|
||||||
|
Email: fmt.Sprintf("a.%d@c.com", i),
|
||||||
|
Name: fmt.Sprintf("name.%d", i),
|
||||||
|
ExtID: fmt.Sprintf("EXTID.%d", i),
|
||||||
|
}
|
||||||
|
|
||||||
|
user2, err := db.Users.c.Insert(*user)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(*user, user2) {
|
||||||
|
t.Fatal(*user, user2)
|
||||||
|
}
|
||||||
|
users[user.Email] = user
|
||||||
|
}
|
||||||
|
|
||||||
|
var id string
|
||||||
|
for key := range users {
|
||||||
|
id = key
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(users, id)
|
||||||
|
db.Users.emailMap.Delete(id)
|
||||||
|
|
||||||
|
return users
|
||||||
|
})
|
||||||
|
|
||||||
|
run("update non-indexed field", func(t *testing.T, db *DB) map[string]*User {
|
||||||
|
users := map[string]*User{}
|
||||||
|
|
||||||
|
for i := uint64(1); i < 10; i++ {
|
||||||
|
user := &User{
|
||||||
|
ID: db.Users.c.NextID(),
|
||||||
|
Email: fmt.Sprintf("a.%d@c.com", i),
|
||||||
|
Name: fmt.Sprintf("name.%d", i),
|
||||||
|
ExtID: fmt.Sprintf("EXTID.%d", i),
|
||||||
|
}
|
||||||
|
|
||||||
|
user2, err := db.Users.c.Insert(*user)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(*user, user2) {
|
||||||
|
t.Fatal(*user, user2)
|
||||||
|
}
|
||||||
|
users[user.Email] = user
|
||||||
|
}
|
||||||
|
|
||||||
|
var id string
|
||||||
|
for key := range users {
|
||||||
|
id = key
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
err := db.Users.emailMap.Update(id, func(u User) (User, error) {
|
||||||
|
u.Name = "UPDATED"
|
||||||
|
return u, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
item1.ExtID = "xx"
|
users[id].Name = "UPDATED"
|
||||||
if err := checkIdx(idx, item1); err != nil {
|
|
||||||
t.Fatal(err)
|
return users
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
run("update out of index", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
run("update indexed field", func(t *testing.T, db *DB) map[string]*User {
|
||||||
c.Insert(Item{1, "1", ""})
|
users := map[string]*User{}
|
||||||
c.Insert(Item{2, "2", "two"}) // In index.
|
|
||||||
c.Insert(Item{3, "3", ""})
|
|
||||||
|
|
||||||
err := c.Update(1, func(in Item) (Item, error) {
|
for i := uint64(1); i < 10; i++ {
|
||||||
in.Name = "ONE"
|
user := &User{
|
||||||
return in, nil
|
ID: db.Users.c.NextID(),
|
||||||
|
Email: fmt.Sprintf("a.%d@c.com", i),
|
||||||
|
Name: fmt.Sprintf("name.%d", i),
|
||||||
|
ExtID: fmt.Sprintf("EXTID.%d", i),
|
||||||
|
}
|
||||||
|
|
||||||
|
user2, err := db.Users.c.Insert(*user)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(*user, user2) {
|
||||||
|
t.Fatal(*user, user2)
|
||||||
|
}
|
||||||
|
users[user.Email] = user
|
||||||
|
}
|
||||||
|
|
||||||
|
var id uint64
|
||||||
|
var email string
|
||||||
|
for key := range users {
|
||||||
|
email = key
|
||||||
|
id = users[key].ID
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
err := db.Users.c.Update(id, func(u User) (User, error) {
|
||||||
|
u.Email = "test@x.com"
|
||||||
|
return u, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := checkIdx(idx, Item{2, "2", "two"}); err != nil {
|
user := users[email]
|
||||||
t.Fatal(err)
|
user.Email = "test@x.com"
|
||||||
}
|
delete(users, email)
|
||||||
|
users[user.Email] = user
|
||||||
|
|
||||||
|
return users
|
||||||
})
|
})
|
||||||
|
|
||||||
run("update out of index conflict", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
// update index field change key error
|
||||||
c.Insert(Item{1, "1", ""})
|
|
||||||
c.Insert(Item{2, "2", "two"}) // In index.
|
|
||||||
c.Insert(Item{3, "3", ""})
|
|
||||||
|
|
||||||
err := c.Update(1, func(in Item) (Item, error) {
|
// update error from func
|
||||||
in.ExtID = "two"
|
// update w/ ErrAbortUpdate
|
||||||
return in, nil
|
// update not found.
|
||||||
})
|
// update conflict.
|
||||||
if !errors.Is(err, ErrDuplicate) {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
run("update within index", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
c.Insert(Item{1, "1", "one"})
|
|
||||||
c.Insert(Item{2, "2", "two"}) // In index.
|
|
||||||
c.Insert(Item{3, "3", ""})
|
|
||||||
|
|
||||||
err := c.Update(2, func(in Item) (Item, error) {
|
|
||||||
in.ExtID = "TWO"
|
|
||||||
return in, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := checkIdx(idx, Item{1, "1", "one"}, Item{2, "2", "TWO"}); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
run("update using index", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
c.Insert(Item{1, "1", "one"})
|
|
||||||
c.Insert(Item{2, "2", "two"}) // In index.
|
|
||||||
c.Insert(Item{3, "3", ""})
|
|
||||||
|
|
||||||
err := idx.Update("one", func(in Item) (Item, error) {
|
|
||||||
in.Name = "_1_"
|
|
||||||
return in, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := checkIdx(idx, Item{1, "_1_", "one"}, Item{2, "2", "two"}); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
run("update using index not found", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
c.Insert(Item{1, "1", "one"})
|
|
||||||
c.Insert(Item{3, "3", ""})
|
|
||||||
|
|
||||||
err := idx.Update("onex", func(in Item) (Item, error) {
|
|
||||||
in.Name = "_1_"
|
|
||||||
return in, nil
|
|
||||||
})
|
|
||||||
if !errors.Is(err, ErrNotFound) {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
run("update using index caller error", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
c.Insert(Item{1, "1", "one"})
|
|
||||||
c.Insert(Item{3, "3", ""})
|
|
||||||
|
|
||||||
myErr := errors.New("Mine")
|
|
||||||
|
|
||||||
err := idx.Update("one", func(in Item) (Item, error) {
|
|
||||||
in.Name = "_1_"
|
|
||||||
return in, myErr
|
|
||||||
})
|
|
||||||
if !errors.Is(err, myErr) {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
run("update using index mismatched IDs", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
c.Insert(Item{1, "1", "one"})
|
|
||||||
|
|
||||||
err := idx.Update("one", func(in Item) (Item, error) {
|
|
||||||
in.ExtID = "onex"
|
|
||||||
return in, nil
|
|
||||||
})
|
|
||||||
if !errors.Is(err, ErrMismatchedIDs) {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
run("delete out of index", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
c.Insert(Item{1, "1", "one"})
|
|
||||||
c.Insert(Item{2, "2", "two"}) // In index.
|
|
||||||
c.Insert(Item{3, "3", ""})
|
|
||||||
c.Delete(3)
|
|
||||||
|
|
||||||
if err := checkIdx(idx, Item{1, "1", "one"}, Item{2, "2", "two"}); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
run("delete from index", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
c.Insert(Item{1, "1", "one"})
|
|
||||||
c.Insert(Item{2, "2", "two"}) // In index.
|
|
||||||
c.Insert(Item{3, "3", ""})
|
|
||||||
c.Delete(2)
|
|
||||||
|
|
||||||
if err := checkIdx(idx, Item{1, "1", "one"}); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
run("delete using index", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
c.Insert(Item{1, "1", "one"})
|
|
||||||
c.Insert(Item{2, "2", "two"}) // In index.
|
|
||||||
c.Insert(Item{3, "3", ""})
|
|
||||||
idx.Delete("two")
|
|
||||||
|
|
||||||
if err := checkIdx(idx, Item{1, "1", "one"}); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
run("delete using index not found", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
c.Insert(Item{1, "1", "one"})
|
|
||||||
c.Insert(Item{2, "2", "two"}) // In index.
|
|
||||||
c.Insert(Item{3, "3", ""})
|
|
||||||
idx.Delete("onex")
|
|
||||||
|
|
||||||
if err := checkIdx(idx, Item{1, "1", "one"}, Item{2, "2", "two"}); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
run("check name", func(t *testing.T, c *Collection[Item], idx *MapIndex[string, Item]) {
|
|
||||||
if idx.name() != "ExtID" {
|
|
||||||
t.Fatal(idx.name())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMapIndexLoadError(t *testing.T) {
|
func TestPartialMapIndex(t *testing.T) {
|
||||||
type Item struct {
|
// insert into index
|
||||||
ID uint64
|
// insert into index conflict
|
||||||
Name string
|
// insert outside index
|
||||||
ExtID string
|
// insert and delete in index
|
||||||
}
|
// insert and delete outside index
|
||||||
|
// insert withing index
|
||||||
root := filepath.Join(os.TempDir(), randString())
|
// update out of index
|
||||||
defer os.RemoveAll(root)
|
// update into index
|
||||||
|
// update error from func
|
||||||
db := NewPrimary(root)
|
// udpate ErrAbortUpdate
|
||||||
c := NewCollection(db, "collection", func(i *Item) uint64 { return i.ID })
|
// update not found
|
||||||
db.Start()
|
// update conflict in to in
|
||||||
defer db.Close()
|
// update conflict out to in
|
||||||
|
|
||||||
c.Insert(Item{1, "one", "x"})
|
|
||||||
c.Insert(Item{2, "two", "x"})
|
|
||||||
c.Insert(Item{3, "three", "y"})
|
|
||||||
c.Insert(Item{4, "x", ""})
|
|
||||||
|
|
||||||
idx := NewMapIndex(c,
|
|
||||||
"ExtID",
|
|
||||||
func(i *Item) string { return i.ExtID },
|
|
||||||
func(i *Item) bool { return i.ExtID != "" })
|
|
||||||
err := idx.load(c.items.m)
|
|
||||||
if !errors.Is(err, ErrDuplicate) {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
|
@ -125,6 +125,8 @@ func OpenDB(root string, primary bool) *DB {
|
||||||
db.Accounts = Accounts{}
|
db.Accounts = Accounts{}
|
||||||
db.Accounts.c = NewCollection(db.Database, "accounts", accountGetID)
|
db.Accounts.c = NewCollection(db.Database, "accounts", accountGetID)
|
||||||
|
|
||||||
|
db.Start()
|
||||||
|
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue