diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 1ae24a0..3c8f002 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -16,7 +16,7 @@ plugins: # Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes) runtimes: enabled: - - go@1.23.3 + - go@1.24.0 - node@18.20.5 - python@3.10.8 diff --git a/api.go b/api.go index 4bbd0d7..09bc68e 100644 --- a/api.go +++ b/api.go @@ -7,7 +7,8 @@ package modusdb import ( "context" - "fmt" + "errors" + "reflect" "github.com/hypermodeinc/dgraph/v24/dql" "github.com/hypermodeinc/dgraph/v24/schema" @@ -20,7 +21,7 @@ func Create[T any](ctx context.Context, engine *Engine, object T, engine.mutex.Lock() defer engine.mutex.Unlock() if len(nsId) > 1 { - return 0, object, fmt.Errorf("only one namespace is allowed") + return 0, object, errors.New("only one namespace is allowed") } ctx, ns, err := getDefaultNamespace(ctx, engine, nsId...) if err != nil { @@ -59,7 +60,7 @@ func Upsert[T any](ctx context.Context, engine *Engine, object T, engine.mutex.Lock() defer engine.mutex.Unlock() if len(nsId) > 1 { - return 0, object, false, fmt.Errorf("only one namespace is allowed") + return 0, object, false, errors.New("only one namespace is allowed") } ctx, ns, err := getDefaultNamespace(ctx, engine, nsId...) @@ -131,7 +132,7 @@ func Get[T any, R UniqueField](ctx context.Context, engine *Engine, uniqueField defer engine.mutex.Unlock() var obj T if len(nsId) > 1 { - return 0, obj, fmt.Errorf("only one namespace is allowed") + return 0, obj, errors.New("only one namespace is allowed") } ctx, ns, err := getDefaultNamespace(ctx, engine, nsId...) if err != nil { @@ -142,10 +143,20 @@ func Get[T any, R UniqueField](ctx context.Context, engine *Engine, uniqueField } if cf, ok := any(uniqueField).(ConstrainedField); ok { - return getByConstrainedField[T](ctx, ns, cf) + objType := reflect.TypeOf(obj) + sch, err := getSchema(ctx, ns) + if err != nil { + return 0, obj, err + } + for _, t := range sch.Types { + if t.Name == objType.Name() { + return getByConstrainedField[T](ctx, ns, cf) + } + } + return 0, obj, errors.New("type not found") } - return 0, obj, fmt.Errorf("invalid unique field type") + return 0, obj, errors.New("invalid unique field type") } func Query[T any](ctx context.Context, engine *Engine, queryParams QueryParams, @@ -153,7 +164,7 @@ func Query[T any](ctx context.Context, engine *Engine, queryParams QueryParams, engine.mutex.Lock() defer engine.mutex.Unlock() if len(nsId) > 1 { - return nil, nil, fmt.Errorf("only one namespace is allowed") + return nil, nil, errors.New("only one namespace is allowed") } ctx, ns, err := getDefaultNamespace(ctx, engine, nsId...) if err != nil { @@ -169,7 +180,7 @@ func Delete[T any, R UniqueField](ctx context.Context, engine *Engine, uniqueFie defer engine.mutex.Unlock() var zeroObj T if len(nsId) > 1 { - return 0, zeroObj, fmt.Errorf("only one namespace is allowed") + return 0, zeroObj, errors.New("only one namespace is allowed") } ctx, ns, err := getDefaultNamespace(ctx, engine, nsId...) if err != nil { @@ -207,5 +218,5 @@ func Delete[T any, R UniqueField](ctx context.Context, engine *Engine, uniqueFie return uid, obj, nil } - return 0, zeroObj, fmt.Errorf("invalid unique field type") + return 0, zeroObj, errors.New("invalid unique field type") } diff --git a/unit_test/api_test.go b/unit_test/api_test.go index a404547..37c092b 100644 --- a/unit_test/api_test.go +++ b/unit_test/api_test.go @@ -59,6 +59,14 @@ func TestFirstTimeUser(t *testing.T) { require.Equal(t, "A", queriedUser2.Name) require.Equal(t, "123", queriedUser2.ClerkId) + // Search for a non-existent record + _, _, err = modusdb.Get[User](context.Background(), engine, modusdb.ConstrainedField{ + Key: "clerk_id", + Value: "456", + }) + require.Error(t, err) + require.Equal(t, "no object found", err.Error()) + _, _, err = modusdb.Delete[User](context.Background(), engine, gid) require.NoError(t, err) @@ -66,7 +74,25 @@ func TestFirstTimeUser(t *testing.T) { require.Error(t, err) require.Equal(t, "no object found", err.Error()) require.Equal(t, queriedUser3, User{}) +} +func TestGetBeforeObjectWrite(t *testing.T) { + ctx := context.Background() + engine, err := modusdb.NewEngine(modusdb.NewDefaultConfig(t.TempDir())) + require.NoError(t, err) + defer engine.Close() + ns, err := engine.CreateNamespace() + require.NoError(t, err) + + _, _, err = modusdb.Get[User](ctx, engine, uint64(1), ns.ID()) + require.Error(t, err) + + _, _, err = modusdb.Get[User](ctx, engine, modusdb.ConstrainedField{ + Key: "name", + Value: "test", + }, ns.ID()) + require.Error(t, err) + require.Equal(t, "type not found", err.Error()) } func TestCreateApi(t *testing.T) { @@ -125,6 +151,14 @@ func TestCreateApiWithNonStruct(t *testing.T) { _, _, err = modusdb.Create[*User](context.Background(), engine, &user, ns1.ID()) require.Error(t, err) require.Equal(t, "expected struct, got ptr", err.Error()) + + _, _, err = modusdb.Create[[]string](context.Background(), engine, []string{"foo", "bar"}, ns1.ID()) + require.Error(t, err) + require.Equal(t, "expected struct, got slice", err.Error()) + + _, _, err = modusdb.Create[float32](context.Background(), engine, 3.1415, ns1.ID()) + require.Error(t, err) + require.Equal(t, "expected struct, got float32", err.Error()) } func TestGetApi(t *testing.T) {