Skip to content
This repository was archived by the owner on Sep 5, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .trunk/trunk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
}
Expand All @@ -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 <hello@hypermode.com>.

## Acknowledgements

Expand Down
92 changes: 46 additions & 46 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -82,106 +82,106 @@ 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
}
wasFound = err == nil
}

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
}

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
}
Expand All @@ -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
}
Expand Down
32 changes: 16 additions & 16 deletions api_mutation_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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
Expand All @@ -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
}
Expand All @@ -69,40 +69,40 @@ 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
}

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
}
Expand Down
Loading
Loading