diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index ef59a67..ae1945f 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -24,15 +24,15 @@ runtimes: lint: enabled: - actionlint@1.7.6 - - checkov@3.2.350 + - checkov@3.2.352 - git-diff-check - gofmt@1.20.4 - golangci-lint@1.63.4 - markdownlint@0.43.0 - osv-scanner@1.9.2 - prettier@3.4.2 - - renovate@39.92.0 - - trufflehog@3.88.1 + - renovate@39.106.0 + - trufflehog@3.88.2 - yamllint@1.35.1 actions: diff --git a/CHANGELOG.md b/CHANGELOG.md index 0255986..d997318 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ - fix: alter schema on reverse edge after querying schema [#55](https://github.com/hypermodeinc/modusDB/pull/55) +- feat: update interface to engine and namespace + [#57](https://github.com/hypermodeinc/modusDB/pull/57) + ## 2025-01-02 - Version 0.1.0 Baseline for the changelog. diff --git a/README.md b/README.md index 6251714..f392352 100644 --- a/README.md +++ b/README.md @@ -46,13 +46,13 @@ type User struct { } func main() { - db, err := New(NewDefaultConfig("/tmp/modusdb")) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig("/local/modusdb")) if err != nil { panic(err) } - defer db.Close() + defer engine.Close() - gid, user, err := modusdb.Upsert(db, User{ + gid, user, err := modusdb.Upsert(ns, User{ Id: "123", Name: "A", Age: 10, @@ -62,13 +62,13 @@ func main() { } fmt.Println(user) - _, queriedUser, err := modusdb.Get[User](db, gid) + _, queriedUser, err := modusdb.Get[User](ns, gid) if err != nil { panic(err) } fmt.Println(queriedUser) - _, _, err = modusdb.Delete[User](db, gid) + _, _, err = modusdb.Delete[User](ns, gid) if err != nil { panic(err) } @@ -86,7 +86,7 @@ like to get involved. Modus and its components are Copyright 2025 Hypermode Inc., and licensed under the terms of the Apache License, Version 2.0. See the [LICENSE](./LICENSE) file for a complete copy of the license. If you have any questions about modus licensing, or need an alternate license or other arrangement, -please contact us at hello@hypermode.com. +please contact us at . ## Acknowledgements diff --git a/api.go b/api.go index b880474..69143ee 100644 --- a/api.go +++ b/api.go @@ -18,52 +18,52 @@ import ( "github.com/hypermodeinc/modusdb/api/structreflect" ) -func Create[T any](db *DB, object T, ns ...uint64) (uint64, T, error) { - db.mutex.Lock() - defer db.mutex.Unlock() - if len(ns) > 1 { +func Create[T any](engine *Engine, object T, nsId ...uint64) (uint64, T, error) { + engine.mutex.Lock() + defer engine.mutex.Unlock() + if len(nsId) > 1 { return 0, object, fmt.Errorf("only one namespace is allowed") } - ctx, n, err := getDefaultNamespace(db, ns...) + ctx, ns, err := getDefaultNamespace(engine, nsId...) if err != nil { return 0, object, err } - gid, err := db.z.nextUID() + gid, err := engine.z.nextUID() if err != nil { return 0, object, err } dms := make([]*dql.Mutation, 0) sch := &schema.ParsedSchema{} - err = generateSetDqlMutationsAndSchema[T](ctx, n, object, gid, &dms, sch) + err = generateSetDqlMutationsAndSchema[T](ctx, ns, object, gid, &dms, sch) if err != nil { return 0, object, err } - err = n.alterSchemaWithParsed(ctx, sch) + err = engine.alterSchemaWithParsed(ctx, sch) if err != nil { return 0, object, err } - err = applyDqlMutations(ctx, db, dms) + err = applyDqlMutations(ctx, engine, dms) if err != nil { return 0, object, err } - return getByGid[T](ctx, n, gid) + return getByGid[T](ctx, ns, gid) } -func Upsert[T any](db *DB, object T, ns ...uint64) (uint64, T, bool, error) { +func Upsert[T any](engine *Engine, object T, nsId ...uint64) (uint64, T, bool, error) { var wasFound bool - db.mutex.Lock() - defer db.mutex.Unlock() - if len(ns) > 1 { + engine.mutex.Lock() + defer engine.mutex.Unlock() + if len(nsId) > 1 { return 0, object, false, fmt.Errorf("only one namespace is allowed") } - ctx, n, err := getDefaultNamespace(db, ns...) + ctx, ns, err := getDefaultNamespace(engine, nsId...) if err != nil { return 0, object, false, err } @@ -82,18 +82,18 @@ func Upsert[T any](db *DB, object T, ns ...uint64) (uint64, T, bool, error) { dms := make([]*dql.Mutation, 0) sch := &schema.ParsedSchema{} - err = generateSetDqlMutationsAndSchema[T](ctx, n, object, gid, &dms, sch) + err = generateSetDqlMutationsAndSchema[T](ctx, ns, object, gid, &dms, sch) if err != nil { return 0, object, false, err } - err = n.alterSchemaWithParsed(ctx, sch) + err = ns.engine.alterSchemaWithParsed(ctx, sch) if err != nil { return 0, object, false, err } if gid != 0 || cf != nil { - gid, err = getExistingObject[T](ctx, n, gid, cf, object) + gid, err = getExistingObject[T](ctx, ns, gid, cf, object) if err != nil && err != apiutils.ErrNoObjFound { return 0, object, false, err } @@ -101,24 +101,24 @@ func Upsert[T any](db *DB, object T, ns ...uint64) (uint64, T, bool, error) { } if gid == 0 { - gid, err = db.z.nextUID() + gid, err = engine.z.nextUID() if err != nil { return 0, object, false, err } } dms = make([]*dql.Mutation, 0) - err = generateSetDqlMutationsAndSchema[T](ctx, n, object, gid, &dms, sch) + err = generateSetDqlMutationsAndSchema[T](ctx, ns, object, gid, &dms, sch) if err != nil { return 0, object, false, err } - err = applyDqlMutations(ctx, db, dms) + err = applyDqlMutations(ctx, engine, dms) if err != nil { return 0, object, false, err } - gid, object, err = getByGid[T](ctx, n, gid) + gid, object, err = getByGid[T](ctx, ns, gid) if err != nil { return 0, object, false, err } @@ -126,62 +126,62 @@ func Upsert[T any](db *DB, object T, ns ...uint64) (uint64, T, bool, error) { return gid, object, wasFound, nil } -func Get[T any, R UniqueField](db *DB, uniqueField R, ns ...uint64) (uint64, T, error) { - db.mutex.Lock() - defer db.mutex.Unlock() +func Get[T any, R UniqueField](engine *Engine, uniqueField R, nsId ...uint64) (uint64, T, error) { + engine.mutex.Lock() + defer engine.mutex.Unlock() var obj T - if len(ns) > 1 { + if len(nsId) > 1 { return 0, obj, fmt.Errorf("only one namespace is allowed") } - ctx, n, err := getDefaultNamespace(db, ns...) + ctx, ns, err := getDefaultNamespace(engine, nsId...) if err != nil { return 0, obj, err } if uid, ok := any(uniqueField).(uint64); ok { - return getByGid[T](ctx, n, uid) + return getByGid[T](ctx, ns, uid) } if cf, ok := any(uniqueField).(ConstrainedField); ok { - return getByConstrainedField[T](ctx, n, cf) + return getByConstrainedField[T](ctx, ns, cf) } return 0, obj, fmt.Errorf("invalid unique field type") } -func Query[T any](db *DB, queryParams QueryParams, ns ...uint64) ([]uint64, []T, error) { - db.mutex.Lock() - defer db.mutex.Unlock() - if len(ns) > 1 { +func Query[T any](engine *Engine, queryParams QueryParams, nsId ...uint64) ([]uint64, []T, error) { + engine.mutex.Lock() + defer engine.mutex.Unlock() + if len(nsId) > 1 { return nil, nil, fmt.Errorf("only one namespace is allowed") } - ctx, n, err := getDefaultNamespace(db, ns...) + ctx, ns, err := getDefaultNamespace(engine, nsId...) if err != nil { return nil, nil, err } - return executeQuery[T](ctx, n, queryParams, true) + return executeQuery[T](ctx, ns, queryParams, true) } -func Delete[T any, R UniqueField](db *DB, uniqueField R, ns ...uint64) (uint64, T, error) { - db.mutex.Lock() - defer db.mutex.Unlock() +func Delete[T any, R UniqueField](engine *Engine, uniqueField R, nsId ...uint64) (uint64, T, error) { + engine.mutex.Lock() + defer engine.mutex.Unlock() var zeroObj T - if len(ns) > 1 { + if len(nsId) > 1 { return 0, zeroObj, fmt.Errorf("only one namespace is allowed") } - ctx, n, err := getDefaultNamespace(db, ns...) + ctx, ns, err := getDefaultNamespace(engine, nsId...) if err != nil { return 0, zeroObj, err } if uid, ok := any(uniqueField).(uint64); ok { - uid, obj, err := getByGid[T](ctx, n, uid) + uid, obj, err := getByGid[T](ctx, ns, uid) if err != nil { return 0, zeroObj, err } - dms := generateDeleteDqlMutations(n, uid) + dms := generateDeleteDqlMutations(ns, uid) - err = applyDqlMutations(ctx, db, dms) + err = applyDqlMutations(ctx, engine, dms) if err != nil { return 0, zeroObj, err } @@ -190,14 +190,14 @@ func Delete[T any, R UniqueField](db *DB, uniqueField R, ns ...uint64) (uint64, } if cf, ok := any(uniqueField).(ConstrainedField); ok { - uid, obj, err := getByConstrainedField[T](ctx, n, cf) + uid, obj, err := getByConstrainedField[T](ctx, ns, cf) if err != nil { return 0, zeroObj, err } - dms := generateDeleteDqlMutations(n, uid) + dms := generateDeleteDqlMutations(ns, uid) - err = applyDqlMutations(ctx, db, dms) + err = applyDqlMutations(ctx, engine, dms) if err != nil { return 0, zeroObj, err } diff --git a/api_mutation_helpers.go b/api_mutation_helpers.go index f205d8a..1a6388b 100644 --- a/api_mutation_helpers.go +++ b/api_mutation_helpers.go @@ -14,10 +14,10 @@ import ( "github.com/hypermodeinc/modusdb/api/structreflect" ) -func processStructValue(ctx context.Context, value any, n *Namespace) (any, error) { +func processStructValue(ctx context.Context, value any, ns *Namespace) (any, error) { if reflect.TypeOf(value).Kind() == reflect.Struct { value = reflect.ValueOf(value).Interface() - newGid, err := getUidOrMutate(ctx, n.db, n, value) + newGid, err := getUidOrMutate(ctx, ns.engine, ns, value) if err != nil { return nil, err } @@ -26,19 +26,19 @@ func processStructValue(ctx context.Context, value any, n *Namespace) (any, erro return value, nil } -func processPointerValue(ctx context.Context, value any, n *Namespace) (any, error) { +func processPointerValue(ctx context.Context, value any, ns *Namespace) (any, error) { reflectValueType := reflect.TypeOf(value) if reflectValueType.Kind() == reflect.Pointer { reflectValueType = reflectValueType.Elem() if reflectValueType.Kind() == reflect.Struct { value = reflect.ValueOf(value).Elem().Interface() - return processStructValue(ctx, value, n) + return processStructValue(ctx, value, ns) } } return value, nil } -func getUidOrMutate[T any](ctx context.Context, db *DB, n *Namespace, object T) (uint64, error) { +func getUidOrMutate[T any](ctx context.Context, engine *Engine, ns *Namespace, object T) (uint64, error) { gid, cfKeyValue, err := structreflect.GetUniqueConstraint[T](object) if err != nil { return 0, err @@ -50,17 +50,17 @@ func getUidOrMutate[T any](ctx context.Context, db *DB, n *Namespace, object T) dms := make([]*dql.Mutation, 0) sch := &schema.ParsedSchema{} - err = generateSetDqlMutationsAndSchema(ctx, n, object, gid, &dms, sch) + err = generateSetDqlMutationsAndSchema(ctx, ns, object, gid, &dms, sch) if err != nil { return 0, err } - err = n.alterSchemaWithParsed(ctx, sch) + err = engine.alterSchemaWithParsed(ctx, sch) if err != nil { return 0, err } if gid != 0 || cf != nil { - gid, err = getExistingObject(ctx, n, gid, cf, object) + gid, err = getExistingObject(ctx, ns, gid, cf, object) if err != nil && err != apiutils.ErrNoObjFound { return 0, err } @@ -69,18 +69,18 @@ func getUidOrMutate[T any](ctx context.Context, db *DB, n *Namespace, object T) } } - gid, err = db.z.nextUID() + gid, err = engine.z.nextUID() if err != nil { return 0, err } dms = make([]*dql.Mutation, 0) - err = generateSetDqlMutationsAndSchema(ctx, n, object, gid, &dms, sch) + err = generateSetDqlMutationsAndSchema(ctx, ns, object, gid, &dms, sch) if err != nil { return 0, err } - err = applyDqlMutations(ctx, db, dms) + err = applyDqlMutations(ctx, engine, dms) if err != nil { return 0, err } @@ -88,21 +88,21 @@ func getUidOrMutate[T any](ctx context.Context, db *DB, n *Namespace, object T) return gid, nil } -func applyDqlMutations(ctx context.Context, db *DB, dms []*dql.Mutation) error { +func applyDqlMutations(ctx context.Context, engine *Engine, dms []*dql.Mutation) error { edges, err := query.ToDirectedEdges(dms, nil) if err != nil { return err } - if !db.isOpen { - return ErrClosedDB + if !engine.isOpen.Load() { + return ErrClosedEngine } - startTs, err := db.z.nextTs() + startTs, err := engine.z.nextTs() if err != nil { return err } - commitTs, err := db.z.nextTs() + commitTs, err := engine.z.nextTs() if err != nil { return err } diff --git a/api_query_execution.go b/api_query_execution.go index d6e0323..4e90527 100644 --- a/api_query_execution.go +++ b/api_query_execution.go @@ -20,34 +20,34 @@ import ( "github.com/hypermodeinc/modusdb/api/structreflect" ) -func getByGid[T any](ctx context.Context, n *Namespace, gid uint64) (uint64, T, error) { - return executeGet[T](ctx, n, gid) +func getByGid[T any](ctx context.Context, ns *Namespace, gid uint64) (uint64, T, error) { + return executeGet[T](ctx, ns, gid) } -func getByGidWithObject[T any](ctx context.Context, n *Namespace, gid uint64, obj T) (uint64, T, error) { - return executeGetWithObject[T](ctx, n, obj, false, gid) +func getByGidWithObject[T any](ctx context.Context, ns *Namespace, gid uint64, obj T) (uint64, T, error) { + return executeGetWithObject[T](ctx, ns, obj, false, gid) } -func getByConstrainedField[T any](ctx context.Context, n *Namespace, cf ConstrainedField) (uint64, T, error) { - return executeGet[T](ctx, n, cf) +func getByConstrainedField[T any](ctx context.Context, ns *Namespace, cf ConstrainedField) (uint64, T, error) { + return executeGet[T](ctx, ns, cf) } -func getByConstrainedFieldWithObject[T any](ctx context.Context, n *Namespace, +func getByConstrainedFieldWithObject[T any](ctx context.Context, ns *Namespace, cf ConstrainedField, obj T) (uint64, T, error) { - return executeGetWithObject[T](ctx, n, obj, false, cf) + return executeGetWithObject[T](ctx, ns, obj, false, cf) } -func executeGet[T any, R UniqueField](ctx context.Context, n *Namespace, args ...R) (uint64, T, error) { +func executeGet[T any, R UniqueField](ctx context.Context, ns *Namespace, args ...R) (uint64, T, error) { var obj T if len(args) != 1 { - return 0, obj, fmt.Errorf("expected 1 argument, got %d", len(args)) + return 0, obj, fmt.Errorf("expected 1 argument, got %ds", len(args)) } - return executeGetWithObject(ctx, n, obj, true, args...) + return executeGetWithObject(ctx, ns, obj, true, args...) } -func executeGetWithObject[T any, R UniqueField](ctx context.Context, n *Namespace, +func executeGetWithObject[T any, R UniqueField](ctx context.Context, ns *Namespace, obj T, withReverse bool, args ...R) (uint64, T, error) { t := reflect.TypeOf(obj) @@ -79,7 +79,7 @@ func executeGetWithObject[T any, R UniqueField](ctx context.Context, n *Namespac return 0, obj, fmt.Errorf("constraint not defined for field %s", cf.Key) } - resp, err := n.queryWithLock(ctx, query) + resp, err := ns.engine.queryWithLock(ctx, ns, query) if err != nil { return 0, obj, err } @@ -107,7 +107,7 @@ func executeGetWithObject[T any, R UniqueField](ctx context.Context, n *Namespac return structreflect.ConvertDynamicToTyped[T](result.Obj[0], t) } -func executeQuery[T any](ctx context.Context, n *Namespace, queryParams QueryParams, +func executeQuery[T any](ctx context.Context, ns *Namespace, queryParams QueryParams, withReverse bool) ([]uint64, []T, error) { var obj T t := reflect.TypeOf(obj) @@ -143,7 +143,7 @@ func executeQuery[T any](ctx context.Context, n *Namespace, queryParams QueryPar query := querygen.FormatObjsQuery(t.Name(), filterQueryFunc, paginationAndSorting, readFromQuery) - resp, err := n.queryWithLock(ctx, query) + resp, err := ns.engine.queryWithLock(ctx, ns, query) if err != nil { return nil, nil, err } @@ -186,13 +186,13 @@ func executeQuery[T any](ctx context.Context, n *Namespace, queryParams QueryPar return gids, objs, nil } -func getExistingObject[T any](ctx context.Context, n *Namespace, gid uint64, cf *ConstrainedField, +func getExistingObject[T any](ctx context.Context, ns *Namespace, gid uint64, cf *ConstrainedField, object T) (uint64, error) { var err error if gid != 0 { - gid, _, err = getByGidWithObject[T](ctx, n, gid, object) + gid, _, err = getByGidWithObject[T](ctx, ns, gid, object) } else if cf != nil { - gid, _, err = getByConstrainedFieldWithObject[T](ctx, n, *cf, object) + gid, _, err = getByConstrainedFieldWithObject[T](ctx, ns, *cf, object) } if err != nil { return 0, err @@ -200,8 +200,8 @@ func getExistingObject[T any](ctx context.Context, n *Namespace, gid uint64, cf return gid, nil } -func getSchema(ctx context.Context, n *Namespace) (*querygen.SchemaResponse, error) { - resp, err := n.queryWithLock(ctx, querygen.SchemaQuery) +func getSchema(ctx context.Context, ns *Namespace) (*querygen.SchemaResponse, error) { + resp, err := ns.engine.queryWithLock(ctx, ns, querygen.SchemaQuery) if err != nil { return nil, err } diff --git a/api_test.go b/api_test.go index 0891069..537a4e8 100644 --- a/api_test.go +++ b/api_test.go @@ -28,11 +28,11 @@ type User struct { } func TestFirstTimeUser(t *testing.T) { - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - gid, user, err := modusdb.Create(db, User{ + gid, user, err := modusdb.Create(engine, User{ Name: "A", Age: 10, ClerkId: "123", @@ -44,7 +44,7 @@ func TestFirstTimeUser(t *testing.T) { require.Equal(t, 10, user.Age) require.Equal(t, "123", user.ClerkId) - gid, queriedUser, err := modusdb.Get[User](db, gid) + gid, queriedUser, err := modusdb.Get[User](engine, gid) require.NoError(t, err) require.Equal(t, queriedUser.Gid, gid) @@ -52,7 +52,7 @@ func TestFirstTimeUser(t *testing.T) { require.Equal(t, "A", queriedUser.Name) require.Equal(t, "123", queriedUser.ClerkId) - gid, queriedUser2, err := modusdb.Get[User](db, modusdb.ConstrainedField{ + gid, queriedUser2, err := modusdb.Get[User](engine, modusdb.ConstrainedField{ Key: "clerk_id", Value: "123", }) @@ -63,10 +63,10 @@ func TestFirstTimeUser(t *testing.T) { require.Equal(t, "A", queriedUser2.Name) require.Equal(t, "123", queriedUser2.ClerkId) - _, _, err = modusdb.Delete[User](db, gid) + _, _, err = modusdb.Delete[User](engine, gid) require.NoError(t, err) - _, queriedUser3, err := modusdb.Get[User](db, gid) + _, queriedUser3, err := modusdb.Get[User](engine, gid) require.Error(t, err) require.Equal(t, "no object found", err.Error()) require.Equal(t, queriedUser3, User{}) @@ -75,14 +75,14 @@ func TestFirstTimeUser(t *testing.T) { func TestCreateApi(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) user := User{ Name: "B", @@ -90,7 +90,7 @@ func TestCreateApi(t *testing.T) { ClerkId: "123", } - gid, user, err := modusdb.Create(db, user, db1.ID()) + gid, user, err := modusdb.Create(engine, user, ns1.ID()) require.NoError(t, err) require.Equal(t, "B", user.Name) @@ -104,76 +104,43 @@ func TestCreateApi(t *testing.T) { User.clerk_id } }` - resp, err := db1.Query(ctx, query) + resp, err := ns1.Query(ctx, query) require.NoError(t, err) require.JSONEq(t, `{"me":[{"uid":"0x2","User.name":"B","User.age":20,"User.clerk_id":"123"}]}`, string(resp.GetJson())) - - // TODO schema{} should work - schemaQuery := `schema{}` - resp, err = db1.Query(ctx, schemaQuery) - require.NoError(t, err) - - require.JSONEq(t, - `{ - "types": [ - { - "name": "User", - "fields": [ - {"name": "User.name"}, - {"name": "User.age"}, - {"name": "User.clerk_id"} - ] - }, - { - "name": "dgraph.graphql", - "fields": [ - {"name": "dgraph.graphql.schema"}, - {"name": "dgraph.graphql.xid"} - ] - }, - { - "name": "dgraph.graphql.persisted_query", - "fields": [ - {"name": "dgraph.graphql.p_query"} - ] - } - ] - }`, - string(resp.GetJson())) } func TestCreateApiWithNonStruct(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) user := User{ Name: "B", Age: 20, } - _, _, err = modusdb.Create[*User](db, &user, db1.ID()) + _, _, err = modusdb.Create[*User](engine, &user, ns1.ID()) require.Error(t, err) require.Equal(t, "expected struct, got ptr", err.Error()) } func TestGetApi(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) user := User{ Name: "B", @@ -181,10 +148,10 @@ func TestGetApi(t *testing.T) { ClerkId: "123", } - gid, _, err := modusdb.Create(db, user, db1.ID()) + gid, _, err := modusdb.Create(engine, user, ns1.ID()) require.NoError(t, err) - gid, queriedUser, err := modusdb.Get[User](db, gid, db1.ID()) + gid, queriedUser, err := modusdb.Get[User](engine, gid, ns1.ID()) require.NoError(t, err) require.Equal(t, queriedUser.Gid, gid) @@ -195,14 +162,14 @@ func TestGetApi(t *testing.T) { func TestGetApiWithConstrainedField(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) user := User{ Name: "B", @@ -210,13 +177,13 @@ func TestGetApiWithConstrainedField(t *testing.T) { ClerkId: "123", } - _, _, err = modusdb.Create(db, user, db1.ID()) + _, _, err = modusdb.Create(engine, user, ns1.ID()) require.NoError(t, err) - gid, queriedUser, err := modusdb.Get[User](db, modusdb.ConstrainedField{ + gid, queriedUser, err := modusdb.Get[User](engine, modusdb.ConstrainedField{ Key: "clerk_id", Value: "123", - }, db1.ID()) + }, ns1.ID()) require.NoError(t, err) require.Equal(t, queriedUser.Gid, gid) @@ -227,14 +194,14 @@ func TestGetApiWithConstrainedField(t *testing.T) { func TestDeleteApi(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) user := User{ Name: "B", @@ -242,21 +209,21 @@ func TestDeleteApi(t *testing.T) { ClerkId: "123", } - gid, _, err := modusdb.Create(db, user, db1.ID()) + gid, _, err := modusdb.Create(engine, user, ns1.ID()) require.NoError(t, err) - _, _, err = modusdb.Delete[User](db, gid, db1.ID()) + _, _, err = modusdb.Delete[User](engine, gid, ns1.ID()) require.NoError(t, err) - _, queriedUser, err := modusdb.Get[User](db, gid, db1.ID()) + _, queriedUser, err := modusdb.Get[User](engine, gid, ns1.ID()) require.Error(t, err) require.Equal(t, "no object found", err.Error()) require.Equal(t, queriedUser, User{}) - _, queriedUser, err = modusdb.Get[User](db, modusdb.ConstrainedField{ + _, queriedUser, err = modusdb.Get[User](engine, modusdb.ConstrainedField{ Key: "clerk_id", Value: "123", - }, db1.ID()) + }, ns1.ID()) require.Error(t, err) require.Equal(t, "no object found", err.Error()) require.Equal(t, queriedUser, User{}) @@ -264,14 +231,14 @@ func TestDeleteApi(t *testing.T) { func TestUpsertApi(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) user := User{ Name: "B", @@ -279,16 +246,16 @@ func TestUpsertApi(t *testing.T) { ClerkId: "123", } - gid, user, _, err := modusdb.Upsert(db, user, db1.ID()) + gid, user, _, err := modusdb.Upsert(engine, user, ns1.ID()) require.NoError(t, err) require.Equal(t, user.Gid, gid) user.Age = 21 - gid, _, _, err = modusdb.Upsert(db, user, db1.ID()) + gid, _, _, err = modusdb.Upsert(engine, user, ns1.ID()) require.NoError(t, err) require.Equal(t, user.Gid, gid) - _, queriedUser, err := modusdb.Get[User](db, gid, db1.ID()) + _, queriedUser, err := modusdb.Get[User](engine, gid, ns1.ID()) require.NoError(t, err) require.Equal(t, user.Gid, queriedUser.Gid) require.Equal(t, 21, queriedUser.Age) @@ -298,14 +265,14 @@ func TestUpsertApi(t *testing.T) { func TestQueryApi(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) users := []User{ {Name: "A", Age: 10, ClerkId: "123"}, @@ -316,11 +283,11 @@ func TestQueryApi(t *testing.T) { } for _, user := range users { - _, _, err = modusdb.Create(db, user, db1.ID()) + _, _, err = modusdb.Create(engine, user, ns1.ID()) require.NoError(t, err) } - gids, queriedUsers, err := modusdb.Query[User](db, modusdb.QueryParams{}, db1.ID()) + gids, queriedUsers, err := modusdb.Query[User](engine, modusdb.QueryParams{}, ns1.ID()) require.NoError(t, err) require.Len(t, queriedUsers, 5) require.Len(t, gids, 5) @@ -330,7 +297,7 @@ func TestQueryApi(t *testing.T) { require.Equal(t, "D", queriedUsers[3].Name) require.Equal(t, "E", queriedUsers[4].Name) - gids, queriedUsers, err = modusdb.Query[User](db, modusdb.QueryParams{ + gids, queriedUsers, err = modusdb.Query[User](engine, modusdb.QueryParams{ Filter: &modusdb.Filter{ Field: "age", String: modusdb.StringPredicate{ @@ -340,7 +307,7 @@ func TestQueryApi(t *testing.T) { GreaterOrEqual: fmt.Sprintf("%d", 20), }, }, - }, db1.ID()) + }, ns1.ID()) require.NoError(t, err) require.Len(t, queriedUsers, 4) @@ -353,14 +320,14 @@ func TestQueryApi(t *testing.T) { func TestQueryApiWithPaginiationAndSorting(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) users := []User{ {Name: "A", Age: 10, ClerkId: "123"}, @@ -371,11 +338,11 @@ func TestQueryApiWithPaginiationAndSorting(t *testing.T) { } for _, user := range users { - _, _, err = modusdb.Create(db, user, db1.ID()) + _, _, err = modusdb.Create(engine, user, ns1.ID()) require.NoError(t, err) } - gids, queriedUsers, err := modusdb.Query[User](db, modusdb.QueryParams{ + gids, queriedUsers, err := modusdb.Query[User](engine, modusdb.QueryParams{ Filter: &modusdb.Filter{ Field: "age", String: modusdb.StringPredicate{ @@ -386,7 +353,7 @@ func TestQueryApiWithPaginiationAndSorting(t *testing.T) { Limit: 3, Offset: 1, }, - }, db1.ID()) + }, ns1.ID()) require.NoError(t, err) require.Len(t, queriedUsers, 3) @@ -395,7 +362,7 @@ func TestQueryApiWithPaginiationAndSorting(t *testing.T) { require.Equal(t, "D", queriedUsers[1].Name) require.Equal(t, "E", queriedUsers[2].Name) - gids, queriedUsers, err = modusdb.Query[User](db, modusdb.QueryParams{ + gids, queriedUsers, err = modusdb.Query[User](engine, modusdb.QueryParams{ Pagination: &modusdb.Pagination{ Limit: 3, Offset: 1, @@ -403,7 +370,7 @@ func TestQueryApiWithPaginiationAndSorting(t *testing.T) { Sorting: &modusdb.Sorting{ OrderAscField: "age", }, - }, db1.ID()) + }, ns1.ID()) require.NoError(t, err) require.Len(t, queriedUsers, 3) @@ -429,23 +396,23 @@ type Branch struct { func TestReverseEdgeGet(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) - projGid, project, err := modusdb.Create(db, Project{ + projGid, project, err := modusdb.Create(engine, Project{ Name: "P", ClerkId: "456", Branches: []Branch{ {Name: "B", ClerkId: "123"}, {Name: "B2", ClerkId: "456"}, }, - }, db1.ID()) + }, ns1.ID()) require.NoError(t, err) require.Equal(t, "P", project.Name) @@ -462,7 +429,7 @@ func TestReverseEdgeGet(t *testing.T) { }, } - branch1Gid, branch1, err := modusdb.Create(db, branch1, db1.ID()) + branch1Gid, branch1, err := modusdb.Create(engine, branch1, ns1.ID()) require.NoError(t, err) require.Equal(t, "B", branch1.Name) @@ -478,13 +445,13 @@ func TestReverseEdgeGet(t *testing.T) { }, } - branch2Gid, branch2, err := modusdb.Create(db, branch2, db1.ID()) + branch2Gid, branch2, err := modusdb.Create(engine, branch2, ns1.ID()) require.NoError(t, err) require.Equal(t, "B2", branch2.Name) require.Equal(t, branch2.Gid, branch2Gid) require.Equal(t, projGid, branch2.Proj.Gid) - getProjGid, queriedProject, err := modusdb.Get[Project](db, projGid, db1.ID()) + getProjGid, queriedProject, err := modusdb.Get[Project](engine, projGid, ns1.ID()) require.NoError(t, err) require.Equal(t, projGid, getProjGid) require.Equal(t, "P", queriedProject.Name) @@ -492,7 +459,7 @@ func TestReverseEdgeGet(t *testing.T) { require.Equal(t, "B", queriedProject.Branches[0].Name) require.Equal(t, "B2", queriedProject.Branches[1].Name) - queryBranchesGids, queriedBranches, err := modusdb.Query[Branch](db, modusdb.QueryParams{}, db1.ID()) + queryBranchesGids, queriedBranches, err := modusdb.Query[Branch](engine, modusdb.QueryParams{}, ns1.ID()) require.NoError(t, err) require.Len(t, queriedBranches, 2) require.Len(t, queryBranchesGids, 2) @@ -502,10 +469,10 @@ func TestReverseEdgeGet(t *testing.T) { // max depth is 2, so we should not see the branches within project require.Len(t, queriedBranches[0].Proj.Branches, 0) - _, _, err = modusdb.Delete[Project](db, projGid, db1.ID()) + _, _, err = modusdb.Delete[Project](engine, projGid, ns1.ID()) require.NoError(t, err) - queryBranchesGids, queriedBranches, err = modusdb.Query[Branch](db, modusdb.QueryParams{}, db1.ID()) + queryBranchesGids, queriedBranches, err = modusdb.Query[Branch](engine, modusdb.QueryParams{}, ns1.ID()) require.NoError(t, err) require.Len(t, queriedBranches, 2) require.Len(t, queryBranchesGids, 2) @@ -515,14 +482,14 @@ func TestReverseEdgeGet(t *testing.T) { func TestReverseEdgeQuery(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) projects := []Project{ {Name: "P1", ClerkId: "456"}, @@ -533,7 +500,7 @@ func TestReverseEdgeQuery(t *testing.T) { clerkCounter := 100 for _, project := range projects { - projGid, project, err := modusdb.Create(db, project, db1.ID()) + projGid, project, err := modusdb.Create(engine, project, ns1.ID()) require.NoError(t, err) require.Equal(t, project.Name, project.Name) require.Equal(t, project.Gid, projGid) @@ -546,7 +513,7 @@ func TestReverseEdgeQuery(t *testing.T) { clerkCounter += 2 for _, branch := range branches { - branchGid, branch, err := modusdb.Create(db, branch, db1.ID()) + branchGid, branch, err := modusdb.Create(engine, branch, ns1.ID()) require.NoError(t, err) require.Equal(t, branch.Name, branch.Name) require.Equal(t, branch.Gid, branchGid) @@ -554,7 +521,7 @@ func TestReverseEdgeQuery(t *testing.T) { } } - queriedProjectsGids, queriedProjects, err := modusdb.Query[Project](db, modusdb.QueryParams{}, db1.ID()) + queriedProjectsGids, queriedProjects, err := modusdb.Query[Project](engine, modusdb.QueryParams{}, ns1.ID()) require.NoError(t, err) require.Len(t, queriedProjects, 2) require.Len(t, queriedProjectsGids, 2) @@ -570,14 +537,14 @@ func TestReverseEdgeQuery(t *testing.T) { func TestNestedObjectMutation(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) branch := Branch{ Name: "B", @@ -588,7 +555,7 @@ func TestNestedObjectMutation(t *testing.T) { }, } - gid, branch, err := modusdb.Create(db, branch, db1.ID()) + gid, branch, err := modusdb.Create(engine, branch, ns1.ID()) require.NoError(t, err) require.Equal(t, "B", branch.Name) @@ -608,14 +575,14 @@ func TestNestedObjectMutation(t *testing.T) { } } }` - resp, err := db1.Query(ctx, query) + resp, err := ns1.Query(ctx, query) require.NoError(t, err) require.JSONEq(t, `{"me":[{"uid":"0x2","Branch.name":"B","Branch.clerk_id":"123","Branch.proj": {"uid":"0x3","Project.name":"P","Project.clerk_id":"456"}}]}`, string(resp.GetJson())) - gid, queriedBranch, err := modusdb.Get[Branch](db, gid, db1.ID()) + gid, queriedBranch, err := modusdb.Get[Branch](engine, gid, ns1.ID()) require.NoError(t, err) require.Equal(t, queriedBranch.Gid, gid) require.Equal(t, "B", queriedBranch.Name) @@ -624,19 +591,19 @@ func TestNestedObjectMutation(t *testing.T) { func TestLinkingObjectsByConstrainedFields(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) - projGid, project, err := modusdb.Create(db, Project{ + projGid, project, err := modusdb.Create(engine, Project{ Name: "P", ClerkId: "456", - }, db1.ID()) + }, ns1.ID()) require.NoError(t, err) require.Equal(t, "P", project.Name) @@ -651,7 +618,7 @@ func TestLinkingObjectsByConstrainedFields(t *testing.T) { }, } - gid, branch, err := modusdb.Create(db, branch, db1.ID()) + gid, branch, err := modusdb.Create(engine, branch, ns1.ID()) require.NoError(t, err) require.Equal(t, "B", branch.Name) @@ -671,14 +638,14 @@ func TestLinkingObjectsByConstrainedFields(t *testing.T) { } } }` - resp, err := db1.Query(ctx, query) + resp, err := ns1.Query(ctx, query) require.NoError(t, err) require.JSONEq(t, `{"me":[{"uid":"0x3","Branch.name":"B","Branch.clerk_id":"123","Branch.proj": {"uid":"0x2","Project.name":"P","Project.clerk_id":"456"}}]}`, string(resp.GetJson())) - gid, queriedBranch, err := modusdb.Get[Branch](db, gid, db1.ID()) + gid, queriedBranch, err := modusdb.Get[Branch](engine, gid, ns1.ID()) require.NoError(t, err) require.Equal(t, queriedBranch.Gid, gid) require.Equal(t, "B", queriedBranch.Name) @@ -687,19 +654,19 @@ func TestLinkingObjectsByConstrainedFields(t *testing.T) { func TestLinkingObjectsByGid(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) - projGid, project, err := modusdb.Create(db, Project{ + projGid, project, err := modusdb.Create(engine, Project{ Name: "P", ClerkId: "456", - }, db1.ID()) + }, ns1.ID()) require.NoError(t, err) require.Equal(t, "P", project.Name) @@ -713,7 +680,7 @@ func TestLinkingObjectsByGid(t *testing.T) { }, } - gid, branch, err := modusdb.Create(db, branch, db1.ID()) + gid, branch, err := modusdb.Create(engine, branch, ns1.ID()) require.NoError(t, err) require.Equal(t, "B", branch.Name) @@ -733,14 +700,14 @@ func TestLinkingObjectsByGid(t *testing.T) { } } }` - resp, err := db1.Query(ctx, query) + resp, err := ns1.Query(ctx, query) require.NoError(t, err) require.JSONEq(t, `{"me":[{"uid":"0x3","Branch.name":"B","Branch.clerk_id":"123", "Branch.proj":{"uid":"0x2","Project.name":"P","Project.clerk_id":"456"}}]}`, string(resp.GetJson())) - gid, queriedBranch, err := modusdb.Get[Branch](db, gid, db1.ID()) + gid, queriedBranch, err := modusdb.Get[Branch](engine, gid, ns1.ID()) require.NoError(t, err) require.Equal(t, queriedBranch.Gid, gid) require.Equal(t, "B", queriedBranch.Name) @@ -761,14 +728,14 @@ type BadBranch struct { func TestNestedObjectMutationWithBadType(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) branch := BadBranch{ Name: "B", @@ -779,7 +746,7 @@ func TestNestedObjectMutationWithBadType(t *testing.T) { }, } - _, _, err = modusdb.Create(db, branch, db1.ID()) + _, _, err = modusdb.Create(engine, branch, ns1.ID()) require.Error(t, err) require.Equal(t, fmt.Sprintf(apiutils.NoUniqueConstr, "BadProject"), err.Error()) @@ -788,7 +755,7 @@ func TestNestedObjectMutationWithBadType(t *testing.T) { ClerkId: "456", } - _, _, err = modusdb.Create(db, proj, db1.ID()) + _, _, err = modusdb.Create(engine, proj, ns1.ID()) require.Error(t, err) require.Equal(t, fmt.Sprintf(apiutils.NoUniqueConstr, "BadProject"), err.Error()) @@ -802,14 +769,14 @@ type Document struct { func TestVectorIndexSearchTyped(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) documents := []Document{ {Text: "apple", TextVec: []float32{0.1, 0.1, 0.0}}, @@ -822,7 +789,7 @@ func TestVectorIndexSearchTyped(t *testing.T) { } for _, doc := range documents { - _, _, err = modusdb.Create(db, doc, db1.ID()) + _, _, err = modusdb.Create(engine, doc, ns1.ID()) require.NoError(t, err) } @@ -833,7 +800,7 @@ func TestVectorIndexSearchTyped(t *testing.T) { } }` - resp, err := db1.Query(ctx, query) + resp, err := ns1.Query(ctx, query) require.NoError(t, err) require.JSONEq(t, `{ "documents":[ @@ -852,7 +819,7 @@ func TestVectorIndexSearchTyped(t *testing.T) { } }` - resp, err = db1.Query(ctx, query2) + resp, err = ns1.Query(ctx, query2) require.NoError(t, err) require.JSONEq(t, `{ "documents":[ @@ -867,14 +834,14 @@ func TestVectorIndexSearchTyped(t *testing.T) { func TestVectorIndexSearchWithQuery(t *testing.T) { ctx := context.Background() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(ctx)) + require.NoError(t, ns1.DropData(ctx)) documents := []Document{ {Text: "apple", TextVec: []float32{0.1, 0.1, 0.0}}, @@ -887,11 +854,11 @@ func TestVectorIndexSearchWithQuery(t *testing.T) { } for _, doc := range documents { - _, _, err = modusdb.Create(db, doc, db1.ID()) + _, _, err = modusdb.Create(engine, doc, ns1.ID()) require.NoError(t, err) } - gids, docs, err := modusdb.Query[Document](db, modusdb.QueryParams{ + gids, docs, err := modusdb.Query[Document](engine, modusdb.QueryParams{ Filter: &modusdb.Filter{ Field: "textVec", Vector: modusdb.VectorPredicate{ @@ -899,7 +866,7 @@ func TestVectorIndexSearchWithQuery(t *testing.T) { TopK: 5, }, }, - }, db1.ID()) + }, ns1.ID()) require.NoError(t, err) require.Len(t, docs, 5) diff --git a/api_types.go b/api_types.go index 8102771..d2b9408 100644 --- a/api_types.go +++ b/api_types.go @@ -75,32 +75,32 @@ type VectorPredicate struct { type ModusDbOption func(*modusDbOptions) type modusDbOptions struct { - namespace uint64 + ns uint64 } -func WithNamespace(namespace uint64) ModusDbOption { +func WithNamespace(ns uint64) ModusDbOption { return func(o *modusDbOptions) { - o.namespace = namespace + o.ns = ns } } -func getDefaultNamespace(db *DB, ns ...uint64) (context.Context, *Namespace, error) { +func getDefaultNamespace(engine *Engine, nsId ...uint64) (context.Context, *Namespace, error) { dbOpts := &modusDbOptions{ - namespace: db.defaultNamespace.ID(), + ns: engine.db0.ID(), } - for _, ns := range ns { + for _, ns := range nsId { WithNamespace(ns)(dbOpts) } - n, err := db.getNamespaceWithLock(dbOpts.namespace) + d, err := engine.getNamespaceWithLock(dbOpts.ns) if err != nil { return nil, nil, err } ctx := context.Background() - ctx = x.AttachNamespace(ctx, n.ID()) + ctx = x.AttachNamespace(ctx, d.ID()) - return ctx, n, nil + return ctx, d, nil } func filterToQueryFunc(typeName string, f Filter) querygen.QueryFunc { diff --git a/config.go b/config.go index 76d3d1b..0eac913 100644 --- a/config.go +++ b/config.go @@ -20,8 +20,8 @@ func NewDefaultConfig(dir string) Config { return Config{dataDir: dir, limitNormalizeNode: 10000} } -func (cc Config) WithLimitNormalizeNode(n int) Config { - cc.limitNormalizeNode = n +func (cc Config) WithLimitNormalizeNode(d int) Config { + cc.limitNormalizeNode = d return cc } diff --git a/db.go b/db.go deleted file mode 100644 index d092ecd..0000000 --- a/db.go +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2025 Hypermode Inc. - * Licensed under the terms of the Apache License, Version 2.0 - * See the LICENSE file that accompanied this code for further details. - * - * SPDX-FileCopyrightText: 2025 Hypermode Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -package modusdb - -import ( - "context" - "errors" - "fmt" - "path" - "sync" - "sync/atomic" - - "github.com/dgraph-io/badger/v4" - "github.com/dgraph-io/dgo/v240/protos/api" - "github.com/dgraph-io/dgraph/v24/edgraph" - "github.com/dgraph-io/dgraph/v24/posting" - "github.com/dgraph-io/dgraph/v24/protos/pb" - "github.com/dgraph-io/dgraph/v24/schema" - "github.com/dgraph-io/dgraph/v24/worker" - "github.com/dgraph-io/dgraph/v24/x" - "github.com/dgraph-io/ristretto/v2/z" -) - -var ( - // This ensures that we only have one instance of modusDB in this process. - singleton atomic.Bool - - ErrSingletonOnly = errors.New("only one modusDB instance is supported") - ErrEmptyDataDir = errors.New("data directory is required") - ErrClosedDB = errors.New("modusDB instance is closed") - ErrNonExistentNamespace = errors.New("namespace does not exist") -) - -// DB is an instance of modusDB. -// For now, we only support one instance of modusDB per process. -type DB struct { - mutex sync.RWMutex - isOpen bool - - z *zero - - // points to default / 0 / galaxy namespace - defaultNamespace *Namespace -} - -// New returns a new modusDB instance. -func New(conf Config) (*DB, error) { - // Ensure that we do not create another instance of modusDB in the same process - if !singleton.CompareAndSwap(false, true) { - return nil, ErrSingletonOnly - } - - if err := conf.validate(); err != nil { - return nil, err - } - - // setup data directories - worker.Config.PostingDir = path.Join(conf.dataDir, "p") - worker.Config.WALDir = path.Join(conf.dataDir, "w") - x.WorkerConfig.TmpDir = path.Join(conf.dataDir, "t") - - // TODO: optimize these and more options - x.WorkerConfig.Badger = badger.DefaultOptions("").FromSuperFlag(worker.BadgerDefaults) - x.Config.MaxRetries = 10 - x.Config.Limit = z.NewSuperFlag("max-pending-queries=100000") - x.Config.LimitNormalizeNode = conf.limitNormalizeNode - - // initialize each package - edgraph.Init() - worker.State.InitStorage() - worker.InitForLite(worker.State.Pstore) - schema.Init(worker.State.Pstore) - posting.Init(worker.State.Pstore, 0) // TODO: set cache size - - db := &DB{isOpen: true} - if err := db.reset(); err != nil { - return nil, fmt.Errorf("error resetting db: %w", err) - } - - x.UpdateHealthStatus(true) - - db.defaultNamespace = &Namespace{id: 0, db: db} - return db, nil -} - -func (db *DB) CreateNamespace() (*Namespace, error) { - db.mutex.RLock() - defer db.mutex.RUnlock() - - if !db.isOpen { - return nil, ErrClosedDB - } - - startTs, err := db.z.nextTs() - if err != nil { - return nil, err - } - nsID, err := db.z.nextNS() - if err != nil { - return nil, err - } - - if err := worker.ApplyInitialSchema(nsID, startTs); err != nil { - return nil, fmt.Errorf("error applying initial schema: %w", err) - } - for _, pred := range schema.State().Predicates() { - worker.InitTablet(pred) - } - - return &Namespace{id: nsID, db: db}, nil -} - -func (db *DB) GetNamespace(nsID uint64) (*Namespace, error) { - db.mutex.RLock() - defer db.mutex.RUnlock() - - return db.getNamespaceWithLock(nsID) -} - -func (db *DB) getNamespaceWithLock(nsID uint64) (*Namespace, error) { - if !db.isOpen { - return nil, ErrClosedDB - } - - if nsID > db.z.lastNS { - return nil, ErrNonExistentNamespace - } - - // TODO: when delete namespace is implemented, check if the namespace exists - - return &Namespace{id: nsID, db: db}, nil -} - -// DropAll drops all the data and schema in the modusDB instance. -func (db *DB) DropAll(ctx context.Context) error { - db.mutex.Lock() - defer db.mutex.Unlock() - - if !db.isOpen { - return ErrClosedDB - } - - p := &pb.Proposal{Mutations: &pb.Mutations{ - GroupId: 1, - DropOp: pb.Mutations_ALL, - }} - if err := worker.ApplyMutations(ctx, p); err != nil { - return fmt.Errorf("error applying mutation: %w", err) - } - if err := db.reset(); err != nil { - return fmt.Errorf("error resetting db: %w", err) - } - - // TODO: insert drop record - return nil -} - -func (db *DB) DropData(ctx context.Context) error { - return db.defaultNamespace.DropData(ctx) -} - -func (db *DB) AlterSchema(ctx context.Context, sch string) error { - return db.defaultNamespace.AlterSchema(ctx, sch) -} - -func (db *DB) Query(ctx context.Context, q string) (*api.Response, error) { - return db.defaultNamespace.Query(ctx, q) -} - -func (db *DB) Mutate(ctx context.Context, ms []*api.Mutation) (map[string]uint64, error) { - return db.defaultNamespace.Mutate(ctx, ms) -} - -func (db *DB) Load(ctx context.Context, schemaPath, dataPath string) error { - return db.defaultNamespace.Load(ctx, schemaPath, dataPath) -} - -func (db *DB) LoadData(inCtx context.Context, dataDir string) error { - return db.defaultNamespace.LoadData(inCtx, dataDir) -} - -// Close closes the modusDB instance. -func (db *DB) Close() { - db.mutex.Lock() - defer db.mutex.Unlock() - - if !db.isOpen { - return - } - - if !singleton.CompareAndSwap(true, false) { - panic("modusDB instance was not properly opened") - } - - db.isOpen = false - x.UpdateHealthStatus(false) - posting.Cleanup() - worker.State.Dispose() -} - -func (db *DB) reset() error { - z, restart, err := newZero() - if err != nil { - return fmt.Errorf("error initializing zero: %w", err) - } - - if !restart { - if err := worker.ApplyInitialSchema(0, 1); err != nil { - return fmt.Errorf("error applying initial schema: %w", err) - } - } - - if err := schema.LoadFromDb(context.Background()); err != nil { - return fmt.Errorf("error loading schema: %w", err) - } - for _, pred := range schema.State().Predicates() { - worker.InitTablet(pred) - } - - db.z = z - return nil -} diff --git a/engine.go b/engine.go new file mode 100644 index 0000000..9be39a3 --- /dev/null +++ b/engine.go @@ -0,0 +1,384 @@ +/* + * Copyright 2025 Hypermode Inc. + * Licensed under the terms of the Apache License, Version 2.0 + * See the LICENSE file that accompanied this code for further details. + * + * SPDX-FileCopyrightText: 2025 Hypermode Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +package modusdb + +import ( + "context" + "errors" + "fmt" + "path" + "strconv" + "sync" + "sync/atomic" + + "github.com/dgraph-io/badger/v4" + "github.com/dgraph-io/dgo/v240/protos/api" + "github.com/dgraph-io/dgraph/v24/dql" + "github.com/dgraph-io/dgraph/v24/edgraph" + "github.com/dgraph-io/dgraph/v24/posting" + "github.com/dgraph-io/dgraph/v24/protos/pb" + "github.com/dgraph-io/dgraph/v24/query" + "github.com/dgraph-io/dgraph/v24/schema" + "github.com/dgraph-io/dgraph/v24/worker" + "github.com/dgraph-io/dgraph/v24/x" + "github.com/dgraph-io/ristretto/v2/z" +) + +var ( + // This ensures that we only have one instance of modusDB in this process. + singleton atomic.Bool + + ErrSingletonOnly = errors.New("only one modusDB engine is supported") + ErrEmptyDataDir = errors.New("data directory is required") + ErrClosedEngine = errors.New("modusDB engine is closed") + ErrNonExistentDB = errors.New("namespace does not exist") +) + +// Engine is an instance of modusDB. +// For now, we only support one instance of modusDB per process. +type Engine struct { + mutex sync.RWMutex + isOpen atomic.Bool + + z *zero + + // points to default / 0 / galaxy namespace + db0 *Namespace +} + +// NewEngine returns a new modusDB instance. +func NewEngine(conf Config) (*Engine, error) { + // Ensure that we do not create another instance of modusDB in the same process + if !singleton.CompareAndSwap(false, true) { + return nil, ErrSingletonOnly + } + + if err := conf.validate(); err != nil { + return nil, err + } + + // setup data directories + worker.Config.PostingDir = path.Join(conf.dataDir, "p") + worker.Config.WALDir = path.Join(conf.dataDir, "w") + x.WorkerConfig.TmpDir = path.Join(conf.dataDir, "t") + + // TODO: optimize these and more options + x.WorkerConfig.Badger = badger.DefaultOptions("").FromSuperFlag(worker.BadgerDefaults) + x.Config.MaxRetries = 10 + x.Config.Limit = z.NewSuperFlag("max-pending-queries=100000") + x.Config.LimitNormalizeNode = conf.limitNormalizeNode + + // initialize each package + edgraph.Init() + worker.State.InitStorage() + worker.InitForLite(worker.State.Pstore) + schema.Init(worker.State.Pstore) + posting.Init(worker.State.Pstore, 0) // TODO: set cache size + + engine := &Engine{} + engine.isOpen.Store(true) + if err := engine.reset(); err != nil { + return nil, fmt.Errorf("error resetting db: %w", err) + } + + x.UpdateHealthStatus(true) + + engine.db0 = &Namespace{id: 0, engine: engine} + return engine, nil +} + +func (engine *Engine) CreateNamespace() (*Namespace, error) { + engine.mutex.RLock() + defer engine.mutex.RUnlock() + + if !engine.isOpen.Load() { + return nil, ErrClosedEngine + } + + startTs, err := engine.z.nextTs() + if err != nil { + return nil, err + } + nsID, err := engine.z.nextNamespace() + if err != nil { + return nil, err + } + + if err := worker.ApplyInitialSchema(nsID, startTs); err != nil { + return nil, fmt.Errorf("error applying initial schema: %w", err) + } + for _, pred := range schema.State().Predicates() { + worker.InitTablet(pred) + } + + return &Namespace{id: nsID, engine: engine}, nil +} + +func (engine *Engine) GetNamespace(nsID uint64) (*Namespace, error) { + engine.mutex.RLock() + defer engine.mutex.RUnlock() + + return engine.getNamespaceWithLock(nsID) +} + +func (engine *Engine) getNamespaceWithLock(nsID uint64) (*Namespace, error) { + if !engine.isOpen.Load() { + return nil, ErrClosedEngine + } + + if nsID > engine.z.lastNamespace { + return nil, ErrNonExistentDB + } + + // TODO: when delete namespace is implemented, check if the namespace exists + + return &Namespace{id: nsID, engine: engine}, nil +} + +func (engine *Engine) GetDefaultNamespace() *Namespace { + return engine.db0 +} + +// DropAll drops all the data and schema in the modusDB instance. +func (engine *Engine) DropAll(ctx context.Context) error { + engine.mutex.Lock() + defer engine.mutex.Unlock() + + if !engine.isOpen.Load() { + return ErrClosedEngine + } + + p := &pb.Proposal{Mutations: &pb.Mutations{ + GroupId: 1, + DropOp: pb.Mutations_ALL, + }} + if err := worker.ApplyMutations(ctx, p); err != nil { + return fmt.Errorf("error applying mutation: %w", err) + } + if err := engine.reset(); err != nil { + return fmt.Errorf("error resetting db: %w", err) + } + + // TODO: insert drop record + return nil +} + +func (engine *Engine) dropData(ctx context.Context, ns *Namespace) error { + engine.mutex.Lock() + defer engine.mutex.Unlock() + + if !engine.isOpen.Load() { + return ErrClosedEngine + } + + p := &pb.Proposal{Mutations: &pb.Mutations{ + GroupId: 1, + DropOp: pb.Mutations_DATA, + DropValue: strconv.FormatUint(ns.ID(), 10), + }} + + if err := worker.ApplyMutations(ctx, p); err != nil { + return fmt.Errorf("error applying mutation: %w", err) + } + + // TODO: insert drop record + // TODO: should we reset back the timestamp as well? + return nil +} + +func (engine *Engine) alterSchema(ctx context.Context, ns *Namespace, sch string) error { + engine.mutex.Lock() + defer engine.mutex.Unlock() + + if !engine.isOpen.Load() { + return ErrClosedEngine + } + + sc, err := schema.ParseWithNamespace(sch, ns.ID()) + if err != nil { + return fmt.Errorf("error parsing schema: %w", err) + } + return engine.alterSchemaWithParsed(ctx, sc) +} + +func (engine *Engine) alterSchemaWithParsed(ctx context.Context, sc *schema.ParsedSchema) error { + for _, pred := range sc.Preds { + worker.InitTablet(pred.Predicate) + } + + startTs, err := engine.z.nextTs() + if err != nil { + return err + } + + p := &pb.Proposal{Mutations: &pb.Mutations{ + GroupId: 1, + StartTs: startTs, + Schema: sc.Preds, + Types: sc.Types, + }} + if err := worker.ApplyMutations(ctx, p); err != nil { + return fmt.Errorf("error applying mutation: %w", err) + } + return nil +} + +func (engine *Engine) query(ctx context.Context, ns *Namespace, q string) (*api.Response, error) { + engine.mutex.RLock() + defer engine.mutex.RUnlock() + + return engine.queryWithLock(ctx, ns, q) +} + +func (engine *Engine) queryWithLock(ctx context.Context, ns *Namespace, q string) (*api.Response, error) { + if !engine.isOpen.Load() { + return nil, ErrClosedEngine + } + + ctx = x.AttachNamespace(ctx, ns.ID()) + return (&edgraph.Server{}).QueryNoAuth(ctx, &api.Request{ + ReadOnly: true, + Query: q, + StartTs: engine.z.readTs(), + }) +} + +func (engine *Engine) mutate(ctx context.Context, ns *Namespace, ms []*api.Mutation) (map[string]uint64, error) { + if len(ms) == 0 { + return nil, nil + } + + engine.mutex.Lock() + defer engine.mutex.Unlock() + dms := make([]*dql.Mutation, 0, len(ms)) + for _, mu := range ms { + dm, err := edgraph.ParseMutationObject(mu, false) + if err != nil { + return nil, fmt.Errorf("error parsing mutation: %w", err) + } + dms = append(dms, dm) + } + newUids, err := query.ExtractBlankUIDs(ctx, dms) + if err != nil { + return nil, err + } + if len(newUids) > 0 { + num := &pb.Num{Val: uint64(len(newUids)), Type: pb.Num_UID} + res, err := engine.z.nextUIDs(num) + if err != nil { + return nil, err + } + + curId := res.StartId + for k := range newUids { + x.AssertTruef(curId != 0 && curId <= res.EndId, "not enough uids generated") + newUids[k] = curId + curId++ + } + } + + return engine.mutateWithDqlMutation(ctx, ns, dms, newUids) +} + +func (engine *Engine) mutateWithDqlMutation(ctx context.Context, ns *Namespace, dms []*dql.Mutation, + newUids map[string]uint64) (map[string]uint64, error) { + edges, err := query.ToDirectedEdges(dms, newUids) + if err != nil { + return nil, fmt.Errorf("error converting to directed edges: %w", err) + } + ctx = x.AttachNamespace(ctx, ns.ID()) + + if !engine.isOpen.Load() { + return nil, ErrClosedEngine + } + + startTs, err := engine.z.nextTs() + if err != nil { + return nil, err + } + commitTs, err := engine.z.nextTs() + if err != nil { + return nil, err + } + + m := &pb.Mutations{ + GroupId: 1, + StartTs: startTs, + Edges: edges, + } + + m.Edges, err = query.ExpandEdges(ctx, m) + if err != nil { + return nil, fmt.Errorf("error expanding edges: %w", err) + } + + for _, edge := range m.Edges { + worker.InitTablet(edge.Attr) + } + + p := &pb.Proposal{Mutations: m, StartTs: startTs} + if err := worker.ApplyMutations(ctx, p); err != nil { + return nil, err + } + + return newUids, worker.ApplyCommited(ctx, &pb.OracleDelta{ + Txns: []*pb.TxnStatus{{StartTs: startTs, CommitTs: commitTs}}, + }) +} + +func (engine *Engine) Load(ctx context.Context, schemaPath, dataPath string) error { + return engine.db0.Load(ctx, schemaPath, dataPath) +} + +func (engine *Engine) LoadData(inCtx context.Context, dataDir string) error { + return engine.db0.LoadData(inCtx, dataDir) +} + +// Close closes the modusDB instance. +func (engine *Engine) Close() { + engine.mutex.Lock() + defer engine.mutex.Unlock() + + if !engine.isOpen.Load() { + return + } + + if !singleton.CompareAndSwap(true, false) { + panic("modusDB instance was not properly opened") + } + + engine.isOpen.Store(false) + x.UpdateHealthStatus(false) + posting.Cleanup() + worker.State.Dispose() +} + +func (ns *Engine) reset() error { + z, restart, err := newZero() + if err != nil { + return fmt.Errorf("error initializing zero: %w", err) + } + + if !restart { + if err := worker.ApplyInitialSchema(0, 1); err != nil { + return fmt.Errorf("error applying initial schema: %w", err) + } + } + + if err := schema.LoadFromDb(context.Background()); err != nil { + return fmt.Errorf("error loading schema: %w", err) + } + for _, pred := range schema.State().Predicates() { + worker.InitTablet(pred) + } + + ns.z = z + return nil +} diff --git a/db_test.go b/engine_test.go similarity index 61% rename from db_test.go rename to engine_test.go index 5de5d68..9eee107 100644 --- a/db_test.go +++ b/engine_test.go @@ -25,14 +25,14 @@ import ( func TestRestart(t *testing.T) { dataDir := t.TempDir() - db, err := modusdb.New(modusdb.NewDefaultConfig(dataDir)) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(dataDir)) require.NoError(t, err) - defer func() { db.Close() }() + defer func() { engine.Close() }() - require.NoError(t, db.DropAll(context.Background())) - require.NoError(t, db.AlterSchema(context.Background(), "name: string @index(term) .")) + require.NoError(t, engine.DropAll(context.Background())) + require.NoError(t, engine.GetDefaultNamespace().AlterSchema(context.Background(), "name: string @index(term) .")) - _, err = db.Mutate(context.Background(), []*api.Mutation{ + _, err = engine.GetDefaultNamespace().Mutate(context.Background(), []*api.Mutation{ { Set: []*api.NQuad{ { @@ -51,27 +51,27 @@ func TestRestart(t *testing.T) { name } }` - qresp, err := db.Query(context.Background(), query) + qresp, err := engine.GetDefaultNamespace().Query(context.Background(), query) require.NoError(t, err) require.JSONEq(t, `{"me":[{"name":"A"}]}`, string(qresp.GetJson())) - db.Close() - db, err = modusdb.New(modusdb.NewDefaultConfig(dataDir)) + engine.Close() + engine, err = modusdb.NewEngine(modusdb.NewDefaultConfig(dataDir)) require.NoError(t, err) - qresp, err = db.Query(context.Background(), query) + qresp, err = engine.GetDefaultNamespace().Query(context.Background(), query) require.NoError(t, err) require.JSONEq(t, `{"me":[{"name":"A"}]}`, string(qresp.GetJson())) - require.NoError(t, db.DropAll(context.Background())) + require.NoError(t, engine.DropAll(context.Background())) } func TestSchemaQuery(t *testing.T) { - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - require.NoError(t, db.DropAll(context.Background())) - require.NoError(t, db.AlterSchema(context.Background(), ` + require.NoError(t, engine.DropAll(context.Background())) + require.NoError(t, engine.GetDefaultNamespace().AlterSchema(context.Background(), ` name: string @index(exact) . age: int . married: bool . @@ -79,7 +79,7 @@ func TestSchemaQuery(t *testing.T) { dob: datetime . `)) - resp, err := db.Query(context.Background(), `schema(pred: [name, age]) {type}`) + resp, err := engine.GetDefaultNamespace().Query(context.Background(), `schema(pred: [name, age]) {type}`) require.NoError(t, err) require.JSONEq(t, @@ -95,15 +95,15 @@ func TestBasicVector(t *testing.T) { } vectBytes := buf.Bytes() - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - require.NoError(t, db.DropAll(context.Background())) - require.NoError(t, db.AlterSchema(context.Background(), + require.NoError(t, engine.DropAll(context.Background())) + require.NoError(t, engine.GetDefaultNamespace().AlterSchema(context.Background(), `project_description_v: float32vector @index(hnsw(exponent: "5", metric: "euclidean")) .`)) - uids, err := db.Mutate(context.Background(), []*api.Mutation{{ + uids, err := engine.GetDefaultNamespace().Mutate(context.Background(), []*api.Mutation{{ Set: []*api.NQuad{{ Subject: "_:vector", Predicate: "project_description_v", @@ -119,7 +119,7 @@ func TestBasicVector(t *testing.T) { t.Fatalf("Expected non-zero uid") } - resp, err := db.Query(context.Background(), fmt.Sprintf(`query { + resp, err := engine.GetDefaultNamespace().Query(context.Background(), fmt.Sprintf(`query { q (func: uid(%v)) { project_description_v } diff --git a/live.go b/live.go index d786fab..911a9a4 100644 --- a/live.go +++ b/live.go @@ -246,7 +246,7 @@ func (l *liveLoader) uid(ns uint64, val string) (string, error) { return uid, nil } - asUID, err := l.n.db.LeaseUIDs(1) + asUID, err := l.n.engine.LeaseUIDs(1) if err != nil { return "", fmt.Errorf("error allocating UID: %w", err) } diff --git a/live_benchmark_test.go b/live_benchmark_test.go index 62aee86..fd1572f 100644 --- a/live_benchmark_test.go +++ b/live_benchmark_test.go @@ -49,9 +49,9 @@ func BenchmarkDatabaseOperations(b *testing.B) { runtime.ReadMemStats(&ms) initialAlloc := ms.Alloc - db, err := modusdb.New(modusdb.NewDefaultConfig(b.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(b.TempDir())) require.NoError(b, err) - defer db.Close() + defer engine.Close() b.ResetTimer() for i := 0; i < b.N; i++ { @@ -60,7 +60,7 @@ func BenchmarkDatabaseOperations(b *testing.B) { dataFile := filepath.Join(dataFolder, "data.rdf") require.NoError(b, os.WriteFile(schemaFile, []byte(DbSchema), 0600)) require.NoError(b, os.WriteFile(dataFile, []byte(SmallData), 0600)) - require.NoError(b, db.Load(context.Background(), schemaFile, dataFile)) + require.NoError(b, engine.Load(context.Background(), schemaFile, dataFile)) } reportMemStats(b, initialAlloc) }) @@ -75,16 +75,16 @@ func BenchmarkDatabaseOperations(b *testing.B) { initialAlloc := ms.Alloc // Setup database with data once - db, err := modusdb.New(modusdb.NewDefaultConfig(b.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(b.TempDir())) require.NoError(b, err) - defer db.Close() + defer engine.Close() dataFolder := b.TempDir() schemaFile := filepath.Join(dataFolder, "data.schema") dataFile := filepath.Join(dataFolder, "data.rdf") require.NoError(b, os.WriteFile(schemaFile, []byte(DbSchema), 0600)) require.NoError(b, os.WriteFile(dataFile, []byte(SmallData), 0600)) - require.NoError(b, db.Load(context.Background(), schemaFile, dataFile)) + require.NoError(b, engine.Load(context.Background(), schemaFile, dataFile)) const query = `{ caro(func: allofterms(name@en, "Marc Caro")) { @@ -112,7 +112,7 @@ func BenchmarkDatabaseOperations(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - resp, err := db.Query(context.Background(), query) + resp, err := engine.GetDefaultNamespace().Query(context.Background(), query) require.NoError(b, err) require.JSONEq(b, expected, string(resp.Json)) } diff --git a/live_test.go b/live_test.go index 4b7cf88..9b44a62 100644 --- a/live_test.go +++ b/live_test.go @@ -49,16 +49,16 @@ const ( func TestLiveLoaderSmall(t *testing.T) { - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() dataFolder := t.TempDir() schemaFile := filepath.Join(dataFolder, "data.schema") dataFile := filepath.Join(dataFolder, "data.rdf") require.NoError(t, os.WriteFile(schemaFile, []byte(DbSchema), 0600)) require.NoError(t, os.WriteFile(dataFile, []byte(SmallData), 0600)) - require.NoError(t, db.Load(context.Background(), schemaFile, dataFile)) + require.NoError(t, engine.Load(context.Background(), schemaFile, dataFile)) const query = `{ caro(func: allofterms(name@en, "Marc Caro")) { @@ -84,15 +84,15 @@ func TestLiveLoaderSmall(t *testing.T) { ] }` - resp, err := db.Query(context.Background(), query) + resp, err := engine.GetDefaultNamespace().Query(context.Background(), query) require.NoError(t, err) require.JSONEq(t, expected, string(resp.Json)) } func TestLiveLoader1Million(t *testing.T) { - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() baseDir := t.TempDir() schResp, err := grab.Get(baseDir, oneMillionSchema) @@ -100,12 +100,12 @@ func TestLiveLoader1Million(t *testing.T) { dataResp, err := grab.Get(baseDir, oneMillionRDF) require.NoError(t, err) - require.NoError(t, db.DropAll(context.Background())) - require.NoError(t, db.Load(context.Background(), schResp.Filename, dataResp.Filename)) + require.NoError(t, engine.DropAll(context.Background())) + require.NoError(t, engine.Load(context.Background(), schResp.Filename, dataResp.Filename)) for _, tt := range common.OneMillionTCs { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) - resp, err := db.Query(ctx, tt.Query) + resp, err := engine.GetDefaultNamespace().Query(ctx, tt.Query) cancel() if ctx.Err() == context.DeadlineExceeded { diff --git a/namespace.go b/namespace.go index 710a1e0..b40bbf8 100644 --- a/namespace.go +++ b/namespace.go @@ -11,189 +11,34 @@ package modusdb import ( "context" - "fmt" - "strconv" "github.com/dgraph-io/dgo/v240/protos/api" - "github.com/dgraph-io/dgraph/v24/dql" - "github.com/dgraph-io/dgraph/v24/edgraph" - "github.com/dgraph-io/dgraph/v24/protos/pb" - "github.com/dgraph-io/dgraph/v24/query" - "github.com/dgraph-io/dgraph/v24/schema" - "github.com/dgraph-io/dgraph/v24/worker" - "github.com/dgraph-io/dgraph/v24/x" ) // Namespace is one of the namespaces in modusDB. type Namespace struct { - id uint64 - db *DB + id uint64 + engine *Engine } -func (n *Namespace) ID() uint64 { - return n.id +func (ns *Namespace) ID() uint64 { + return ns.id } // DropData drops all the data in the modusDB instance. -func (n *Namespace) DropData(ctx context.Context) error { - n.db.mutex.Lock() - defer n.db.mutex.Unlock() - - if !n.db.isOpen { - return ErrClosedDB - } - - p := &pb.Proposal{Mutations: &pb.Mutations{ - GroupId: 1, - DropOp: pb.Mutations_DATA, - DropValue: strconv.FormatUint(n.ID(), 10), - }} - - if err := worker.ApplyMutations(ctx, p); err != nil { - return fmt.Errorf("error applying mutation: %w", err) - } - - // TODO: insert drop record - // TODO: should we reset back the timestamp as well? - return nil +func (ns *Namespace) DropData(ctx context.Context) error { + return ns.engine.dropData(ctx, ns) } -func (n *Namespace) AlterSchema(ctx context.Context, sch string) error { - n.db.mutex.Lock() - defer n.db.mutex.Unlock() - - if !n.db.isOpen { - return ErrClosedDB - } - - sc, err := schema.ParseWithNamespace(sch, n.ID()) - if err != nil { - return fmt.Errorf("error parsing schema: %w", err) - } - return n.alterSchemaWithParsed(ctx, sc) +func (ns *Namespace) AlterSchema(ctx context.Context, sch string) error { + return ns.engine.alterSchema(ctx, ns, sch) } -func (n *Namespace) alterSchemaWithParsed(ctx context.Context, sc *schema.ParsedSchema) error { - for _, pred := range sc.Preds { - worker.InitTablet(pred.Predicate) - } - - startTs, err := n.db.z.nextTs() - if err != nil { - return err - } - - p := &pb.Proposal{Mutations: &pb.Mutations{ - GroupId: 1, - StartTs: startTs, - Schema: sc.Preds, - Types: sc.Types, - }} - if err := worker.ApplyMutations(ctx, p); err != nil { - return fmt.Errorf("error applying mutation: %w", err) - } - return nil -} - -func (n *Namespace) Mutate(ctx context.Context, ms []*api.Mutation) (map[string]uint64, error) { - if len(ms) == 0 { - return nil, nil - } - - n.db.mutex.Lock() - defer n.db.mutex.Unlock() - dms := make([]*dql.Mutation, 0, len(ms)) - for _, mu := range ms { - dm, err := edgraph.ParseMutationObject(mu, false) - if err != nil { - return nil, fmt.Errorf("error parsing mutation: %w", err) - } - dms = append(dms, dm) - } - newUids, err := query.ExtractBlankUIDs(ctx, dms) - if err != nil { - return nil, err - } - if len(newUids) > 0 { - num := &pb.Num{Val: uint64(len(newUids)), Type: pb.Num_UID} - res, err := n.db.z.nextUIDs(num) - if err != nil { - return nil, err - } - - curId := res.StartId - for k := range newUids { - x.AssertTruef(curId != 0 && curId <= res.EndId, "not enough uids generated") - newUids[k] = curId - curId++ - } - } - - return n.mutateWithDqlMutation(ctx, dms, newUids) -} - -func (n *Namespace) mutateWithDqlMutation(ctx context.Context, dms []*dql.Mutation, - newUids map[string]uint64) (map[string]uint64, error) { - edges, err := query.ToDirectedEdges(dms, newUids) - if err != nil { - return nil, err - } - ctx = x.AttachNamespace(ctx, n.ID()) - - if !n.db.isOpen { - return nil, ErrClosedDB - } - - startTs, err := n.db.z.nextTs() - if err != nil { - return nil, err - } - commitTs, err := n.db.z.nextTs() - if err != nil { - return nil, err - } - - m := &pb.Mutations{ - GroupId: 1, - StartTs: startTs, - Edges: edges, - } - m.Edges, err = query.ExpandEdges(ctx, m) - if err != nil { - return nil, fmt.Errorf("error expanding edges: %w", err) - } - - for _, edge := range m.Edges { - worker.InitTablet(edge.Attr) - } - - p := &pb.Proposal{Mutations: m, StartTs: startTs} - if err := worker.ApplyMutations(ctx, p); err != nil { - return nil, err - } - - return newUids, worker.ApplyCommited(ctx, &pb.OracleDelta{ - Txns: []*pb.TxnStatus{{StartTs: startTs, CommitTs: commitTs}}, - }) +func (ns *Namespace) Mutate(ctx context.Context, ms []*api.Mutation) (map[string]uint64, error) { + return ns.engine.mutate(ctx, ns, ms) } // Query performs query or mutation or upsert on the given modusDB instance. -func (n *Namespace) Query(ctx context.Context, query string) (*api.Response, error) { - n.db.mutex.RLock() - defer n.db.mutex.RUnlock() - - return n.queryWithLock(ctx, query) -} - -func (n *Namespace) queryWithLock(ctx context.Context, query string) (*api.Response, error) { - if !n.db.isOpen { - return nil, ErrClosedDB - } - - ctx = x.AttachNamespace(ctx, n.ID()) - return (&edgraph.Server{}).QueryNoAuth(ctx, &api.Request{ - ReadOnly: true, - Query: query, - StartTs: n.db.z.readTs(), - }) +func (ns *Namespace) Query(ctx context.Context, query string) (*api.Response, error) { + return ns.engine.query(ctx, ns, query) } diff --git a/namespace_test.go b/namespace_test.go index 3f808bc..0e554b0 100644 --- a/namespace_test.go +++ b/namespace_test.go @@ -19,18 +19,18 @@ import ( "github.com/hypermodeinc/modusdb" ) -func TestNonGalaxyNamespace(t *testing.T) { - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) +func TestNonGalaxyDB(t *testing.T) { + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(context.Background())) - require.NoError(t, db1.AlterSchema(context.Background(), "name: string @index(exact) .")) + require.NoError(t, ns1.DropData(context.Background())) + require.NoError(t, ns1.AlterSchema(context.Background(), "name: string @index(exact) .")) - _, err = db1.Mutate(context.Background(), []*api.Mutation{ + _, err = ns1.Mutate(context.Background(), []*api.Mutation{ { Set: []*api.NQuad{ { @@ -48,24 +48,24 @@ func TestNonGalaxyNamespace(t *testing.T) { name } }` - resp, err := db1.Query(context.Background(), query) + resp, err := ns1.Query(context.Background(), query) require.NoError(t, err) require.JSONEq(t, `{"me":[{"name":"A"}]}`, string(resp.GetJson())) } func TestDropData(t *testing.T) { - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db1.DropData(context.Background())) - require.NoError(t, db1.AlterSchema(context.Background(), "name: string @index(exact) .")) + require.NoError(t, ns1.DropData(context.Background())) + require.NoError(t, ns1.AlterSchema(context.Background(), "name: string @index(exact) .")) - _, err = db1.Mutate(context.Background(), []*api.Mutation{ + _, err = ns1.Mutate(context.Background(), []*api.Mutation{ { Set: []*api.NQuad{ { @@ -83,30 +83,30 @@ func TestDropData(t *testing.T) { name } }` - resp, err := db1.Query(context.Background(), query) + resp, err := ns1.Query(context.Background(), query) require.NoError(t, err) require.JSONEq(t, `{"me":[{"name":"A"}]}`, string(resp.GetJson())) - require.NoError(t, db1.DropData(context.Background())) + require.NoError(t, ns1.DropData(context.Background())) - resp, err = db1.Query(context.Background(), query) + resp, err = ns1.Query(context.Background(), query) require.NoError(t, err) require.JSONEq(t, `{"me":[]}`, string(resp.GetJson())) } -func TestMultipleNamespaces(t *testing.T) { - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) +func TestMultipleDBs(t *testing.T) { + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db0, err := db.GetNamespace(0) + db0, err := engine.GetNamespace(0) require.NoError(t, err) - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db.DropAll(context.Background())) + require.NoError(t, engine.DropAll(context.Background())) require.NoError(t, db0.AlterSchema(context.Background(), "name: string @index(exact) .")) - require.NoError(t, db1.AlterSchema(context.Background(), "name: string @index(exact) .")) + require.NoError(t, ns1.AlterSchema(context.Background(), "name: string @index(exact) .")) _, err = db0.Mutate(context.Background(), []*api.Mutation{ { @@ -121,7 +121,7 @@ func TestMultipleNamespaces(t *testing.T) { }) require.NoError(t, err) - _, err = db1.Mutate(context.Background(), []*api.Mutation{ + _, err = ns1.Mutate(context.Background(), []*api.Mutation{ { Set: []*api.NQuad{ { @@ -143,29 +143,29 @@ func TestMultipleNamespaces(t *testing.T) { require.NoError(t, err) require.JSONEq(t, `{"me":[{"name":"A"}]}`, string(resp.GetJson())) - resp, err = db1.Query(context.Background(), query) + resp, err = ns1.Query(context.Background(), query) require.NoError(t, err) require.JSONEq(t, `{"me":[{"name":"B"}]}`, string(resp.GetJson())) - require.NoError(t, db1.DropData(context.Background())) - resp, err = db1.Query(context.Background(), query) + require.NoError(t, ns1.DropData(context.Background())) + resp, err = ns1.Query(context.Background(), query) require.NoError(t, err) require.JSONEq(t, `{"me":[]}`, string(resp.GetJson())) } -func TestQueryWrongNamespace(t *testing.T) { - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) +func TestQueryWrongDB(t *testing.T) { + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db0, err := db.GetNamespace(0) + db0, err := engine.GetNamespace(0) require.NoError(t, err) - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db.DropAll(context.Background())) + require.NoError(t, engine.DropAll(context.Background())) require.NoError(t, db0.AlterSchema(context.Background(), "name: string @index(exact) .")) - require.NoError(t, db1.AlterSchema(context.Background(), "name: string @index(exact) .")) + require.NoError(t, ns1.AlterSchema(context.Background(), "name: string @index(exact) .")) _, err = db0.Mutate(context.Background(), []*api.Mutation{ { @@ -187,24 +187,24 @@ func TestQueryWrongNamespace(t *testing.T) { } }` - resp, err := db1.Query(context.Background(), query) + resp, err := ns1.Query(context.Background(), query) require.NoError(t, err) require.JSONEq(t, `{"me":[]}`, string(resp.GetJson())) } -func TestTwoNamespaces(t *testing.T) { - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) +func TestTwoDBs(t *testing.T) { + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - db0, err := db.GetNamespace(0) + db0, err := engine.GetNamespace(0) require.NoError(t, err) - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - require.NoError(t, db.DropAll(context.Background())) + require.NoError(t, engine.DropAll(context.Background())) require.NoError(t, db0.AlterSchema(context.Background(), "foo: string @index(exact) .")) - require.NoError(t, db1.AlterSchema(context.Background(), "bar: string @index(exact) .")) + require.NoError(t, ns1.AlterSchema(context.Background(), "bar: string @index(exact) .")) _, err = db0.Mutate(context.Background(), []*api.Mutation{ { @@ -219,7 +219,7 @@ func TestTwoNamespaces(t *testing.T) { }) require.NoError(t, err) - _, err = db1.Mutate(context.Background(), []*api.Mutation{ + _, err = ns1.Mutate(context.Background(), []*api.Mutation{ { Set: []*api.NQuad{ { @@ -246,23 +246,23 @@ func TestTwoNamespaces(t *testing.T) { bar } }` - resp, err = db1.Query(context.Background(), query) + resp, err = ns1.Query(context.Background(), query) require.NoError(t, err) require.JSONEq(t, `{"me":[{"bar":"B"}]}`, string(resp.GetJson())) } -func TestNamespaceDBRestart(t *testing.T) { +func TestDBDBRestart(t *testing.T) { dataDir := t.TempDir() - db, err := modusdb.New(modusdb.NewDefaultConfig(dataDir)) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(dataDir)) require.NoError(t, err) - defer func() { db.Close() }() + defer func() { engine.Close() }() - db1, err := db.CreateNamespace() + ns1, err := engine.CreateNamespace() require.NoError(t, err) - ns1 := db1.ID() + ns1Id := ns1.ID() - require.NoError(t, db1.AlterSchema(context.Background(), "bar: string @index(exact) .")) - _, err = db1.Mutate(context.Background(), []*api.Mutation{ + require.NoError(t, ns1.AlterSchema(context.Background(), "bar: string @index(exact) .")) + _, err = ns1.Mutate(context.Background(), []*api.Mutation{ { Set: []*api.NQuad{ { @@ -275,15 +275,15 @@ func TestNamespaceDBRestart(t *testing.T) { }) require.NoError(t, err) - db.Close() - db, err = modusdb.New(modusdb.NewDefaultConfig(dataDir)) + engine.Close() + engine, err = modusdb.NewEngine(modusdb.NewDefaultConfig(dataDir)) require.NoError(t, err) - db2, err := db.CreateNamespace() + db2, err := engine.CreateNamespace() require.NoError(t, err) - require.Greater(t, db2.ID(), ns1) + require.Greater(t, db2.ID(), ns1Id) - db1, err = db.GetNamespace(ns1) + ns1, err = engine.GetNamespace(ns1Id) require.NoError(t, err) query := `{ @@ -291,7 +291,7 @@ func TestNamespaceDBRestart(t *testing.T) { bar } }` - resp, err := db1.Query(context.Background(), query) + resp, err := ns1.Query(context.Background(), query) require.NoError(t, err) require.JSONEq(t, `{"me":[{"bar":"B"}]}`, string(resp.GetJson())) } diff --git a/vector_test.go b/vector_test.go index e62057d..f5574f9 100644 --- a/vector_test.go +++ b/vector_test.go @@ -29,20 +29,20 @@ const ( ) func TestVectorDelete(t *testing.T) { - db, err := modusdb.New(modusdb.NewDefaultConfig(t.TempDir())) + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) require.NoError(t, err) - defer db.Close() + defer engine.Close() - require.NoError(t, db.DropAll(context.Background())) - require.NoError(t, db.AlterSchema(context.Background(), + require.NoError(t, engine.DropAll(context.Background())) + require.NoError(t, engine.GetDefaultNamespace().AlterSchema(context.Background(), fmt.Sprintf(vectorSchemaWithIndex, "vtest", "4", "euclidean"))) // insert random vectors - assignIDs, err := db.LeaseUIDs(numVectors + 1) + assignIDs, err := engine.LeaseUIDs(numVectors + 1) require.NoError(t, err) //nolint:gosec rdf, vectors := dgraphapi.GenerateRandomVectors(int(assignIDs.StartId)-10, int(assignIDs.EndId)-10, 10, "vtest") - _, err = db.Mutate(context.Background(), []*api.Mutation{{SetNquads: []byte(rdf)}}) + _, err = engine.GetDefaultNamespace().Mutate(context.Background(), []*api.Mutation{{SetNquads: []byte(rdf)}}) require.NoError(t, err) // check the count of the vectors inserted @@ -51,7 +51,7 @@ func TestVectorDelete(t *testing.T) { count(uid) } }` - resp, err := db.Query(context.Background(), q1) + resp, err := engine.GetDefaultNamespace().Query(context.Background(), q1) require.NoError(t, err) require.JSONEq(t, fmt.Sprintf(`{"vector":[{"count":%d}]}`, numVectors), string(resp.Json)) @@ -64,11 +64,11 @@ func TestVectorDelete(t *testing.T) { } }` - require.Equal(t, vectors, queryVectors(t, db, vectorQuery)) + require.Equal(t, vectors, queryVectors(t, engine, vectorQuery)) triples := strings.Split(rdf, "\n") deleteTriple := func(idx int) string { - _, err := db.Mutate(context.Background(), []*api.Mutation{{ + _, err := engine.GetDefaultNamespace().Mutate(context.Background(), []*api.Mutation{{ DelNquads: []byte(triples[idx]), }}) require.NoError(t, err) @@ -80,7 +80,7 @@ func TestVectorDelete(t *testing.T) { } }`, uid[1:len(uid)-1]) - res, err := db.Query(context.Background(), q2) + res, err := engine.GetDefaultNamespace().Query(context.Background(), q2) require.NoError(t, err) require.JSONEq(t, `{"vector":[]}`, string(res.Json)) return triples[idx] @@ -96,17 +96,17 @@ func TestVectorDelete(t *testing.T) { for i := 0; i < len(triples)-2; i++ { triple := deleteTriple(i) vectorQuery := fmt.Sprintf(q3, strings.Split(triple, `"`)[1]) - respVectors := queryVectors(t, db, vectorQuery) + respVectors := queryVectors(t, engine, vectorQuery) require.Len(t, respVectors, 1) require.Contains(t, vectors, respVectors[0]) } triple := deleteTriple(len(triples) - 2) - _ = queryVectors(t, db, fmt.Sprintf(q3, strings.Split(triple, `"`)[1])) + _ = queryVectors(t, engine, fmt.Sprintf(q3, strings.Split(triple, `"`)[1])) } -func queryVectors(t *testing.T, db *modusdb.DB, query string) [][]float32 { - resp, err := db.Query(context.Background(), query) +func queryVectors(t *testing.T, engine *modusdb.Engine, query string) [][]float32 { + resp, err := engine.GetDefaultNamespace().Query(context.Background(), query) require.NoError(t, err) var data struct { diff --git a/zero.go b/zero.go index 130e030..7dc7bad 100644 --- a/zero.go +++ b/zero.go @@ -1,7 +1,7 @@ /* * Copyright 2025 Hypermode Inc. * Licensed under the terms of the Apache License, Version 2.0 - * See the LICENSE file that accompanied this code for further details. + * See the LICEDBE file that accompanied this code for further details. * * SPDX-FileCopyrightText: 2025 Hypermode Inc. * SPDX-License-Identifier: Apache-2.0 @@ -34,9 +34,9 @@ const ( zeroStateKey = "0-dgraph.modusdb.zero" ) -func (db *DB) LeaseUIDs(numUIDs uint64) (*pb.AssignedIds, error) { +func (ns *Engine) LeaseUIDs(numUIDs uint64) (*pb.AssignedIds, error) { num := &pb.Num{Val: numUIDs, Type: pb.Num_UID} - return db.z.nextUIDs(num) + return ns.z.nextUIDs(num) } type zero struct { @@ -46,7 +46,7 @@ type zero struct { minLeasedTs uint64 maxLeasedTs uint64 - lastNS uint64 + lastNamespace uint64 } func newZero() (*zero, bool, error) { @@ -62,13 +62,13 @@ func newZero() (*zero, bool, error) { z.maxLeasedUID = initialUID z.minLeasedTs = initialTs z.maxLeasedTs = initialTs - z.lastNS = 0 + z.lastNamespace = 0 } else { z.minLeasedUID = zs.MaxUID z.maxLeasedUID = zs.MaxUID z.minLeasedTs = zs.MaxTxnTs z.maxLeasedTs = zs.MaxTxnTs - z.lastNS = zs.MaxNsID + z.lastNamespace = zs.MaxNsID } posting.Oracle().ProcessDelta(&pb.OracleDelta{MaxAssigned: z.minLeasedTs - 1}) worker.SetMaxUID(z.minLeasedUID - 1) @@ -133,12 +133,12 @@ func (z *zero) nextUIDs(num *pb.Num) (*pb.AssignedIds, error) { return resp, nil } -func (z *zero) nextNS() (uint64, error) { - z.lastNS++ +func (z *zero) nextNamespace() (uint64, error) { + z.lastNamespace++ if err := z.writeZeroState(); err != nil { return 0, fmt.Errorf("error leasing namespace ID: %w", err) } - return z.lastNS, nil + return z.lastNamespace, nil } func readZeroState() (*pb.MembershipState, error) { @@ -165,7 +165,7 @@ func readZeroState() (*pb.MembershipState, error) { } func (z *zero) writeZeroState() error { - zeroState := &pb.MembershipState{MaxUID: z.maxLeasedUID, MaxTxnTs: z.maxLeasedTs, MaxNsID: z.lastNS} + zeroState := &pb.MembershipState{MaxUID: z.maxLeasedUID, MaxTxnTs: z.maxLeasedTs, MaxNsID: z.lastNamespace} data, err := proto.Marshal(zeroState) if err != nil { return fmt.Errorf("error marshalling zero state: %w", err)