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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
- feat: add readfrom json tag to support reverse edges
[#49](https://github.com/hypermodeinc/modusDB/pull/49)

- chore: Refactoring package management #51 [#51](https://github.com/hypermodeinc/modusDB/pull/51)

## 2025-01-02 - Version 0.1.0

Baseline for the changelog.
Expand Down
22 changes: 9 additions & 13 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/dgraph-io/dgraph/v24/dql"
"github.com/dgraph-io/dgraph/v24/schema"
"github.com/hypermodeinc/modusdb/api/utils"
)

func Create[T any](db *DB, object T, ns ...uint64) (uint64, T, error) {
Expand All @@ -34,7 +35,7 @@ func Create[T any](db *DB, object T, ns ...uint64) (uint64, T, error) {

dms := make([]*dql.Mutation, 0)
sch := &schema.ParsedSchema{}
err = generateCreateDqlMutationsAndSchema[T](ctx, n, object, gid, &dms, sch)
err = generateSetDqlMutationsAndSchema[T](ctx, n, object, gid, &dms, sch)
if err != nil {
return 0, object, err
}
Expand Down Expand Up @@ -66,14 +67,14 @@ func Upsert[T any](db *DB, object T, ns ...uint64) (uint64, T, bool, error) {
return 0, object, false, err
}

gid, cf, err := getUniqueConstraint[T](object)
gid, cf, err := GetUniqueConstraint[T](object)
if err != nil {
return 0, object, false, err
}

dms := make([]*dql.Mutation, 0)
sch := &schema.ParsedSchema{}
err = generateCreateDqlMutationsAndSchema[T](ctx, n, object, gid, &dms, sch)
err = generateSetDqlMutationsAndSchema[T](ctx, n, object, gid, &dms, sch)
if err != nil {
return 0, object, false, err
}
Expand All @@ -83,19 +84,14 @@ func Upsert[T any](db *DB, object T, ns ...uint64) (uint64, T, bool, error) {
return 0, object, false, err
}

if gid != 0 {
gid, _, err = getByGidWithObject[T](ctx, n, gid, object)
if err != nil && err != ErrNoObjFound {
return 0, object, false, err
}
wasFound = err == nil
} else if cf != nil {
gid, _, err = getByConstrainedFieldWithObject[T](ctx, n, *cf, object)
if err != nil && err != ErrNoObjFound {
if gid != 0 || cf != nil {
gid, err = getExistingObject[T](ctx, n, gid, cf, object)
if err != nil && err != utils.ErrNoObjFound {
return 0, object, false, err
}
wasFound = err == nil
}

if gid == 0 {
gid, err = db.z.nextUID()
if err != nil {
Expand All @@ -104,7 +100,7 @@ func Upsert[T any](db *DB, object T, ns ...uint64) (uint64, T, bool, error) {
}

dms = make([]*dql.Mutation, 0)
err = generateCreateDqlMutationsAndSchema[T](ctx, n, object, gid, &dms, sch)
err = generateSetDqlMutationsAndSchema[T](ctx, n, object, gid, &dms, sch)
if err != nil {
return 0, object, false, err
}
Expand Down
71 changes: 71 additions & 0 deletions api/mutations/mutations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package mutations

import (
"fmt"
"reflect"
"strings"

"github.com/dgraph-io/dgo/v240/protos/api"
"github.com/dgraph-io/dgraph/v24/protos/pb"
"github.com/dgraph-io/dgraph/v24/schema"
"github.com/hypermodeinc/modusdb/api/utils"
)

func HandleReverseEdge(jsonName string, value reflect.Type, nsId uint64, sch *schema.ParsedSchema,
jsonToReverseEdgeTags map[string]string) error {
if jsonToReverseEdgeTags[jsonName] == "" {
return nil
}

if value.Kind() != reflect.Slice || value.Elem().Kind() != reflect.Struct {
return fmt.Errorf("reverse edge %s should be a slice of structs", jsonName)
}

reverseEdge := jsonToReverseEdgeTags[jsonName]
typeName := strings.Split(reverseEdge, ".")[0]
u := &pb.SchemaUpdate{
Predicate: utils.AddNamespace(nsId, reverseEdge),
ValueType: pb.Posting_UID,
Directive: pb.SchemaUpdate_REVERSE,
}

sch.Preds = append(sch.Preds, u)
sch.Types = append(sch.Types, &pb.TypeUpdate{
TypeName: utils.AddNamespace(nsId, typeName),
Fields: []*pb.SchemaUpdate{u},
})
return nil
}

func CreateNQuadAndSchema(value any, gid uint64, jsonName string, t reflect.Type,
nsId uint64) (*api.NQuad, *pb.SchemaUpdate, error) {
valType, err := utils.ValueToPosting_ValType(value)
if err != nil {
return nil, nil, err
}

val, err := utils.ValueToApiVal(value)
if err != nil {
return nil, nil, err
}

nquad := &api.NQuad{
Namespace: nsId,
Subject: fmt.Sprint(gid),
Predicate: utils.GetPredicateName(t.Name(), jsonName),
}

u := &pb.SchemaUpdate{
Predicate: utils.AddNamespace(nsId, utils.GetPredicateName(t.Name(), jsonName)),
ValueType: valType,
}

if valType == pb.Posting_UID {
nquad.ObjectId = fmt.Sprint(value)
u.Directive = pb.SchemaUpdate_REVERSE
} else {
nquad.ObjectValue = val
}

return nquad, u, nil
}
173 changes: 173 additions & 0 deletions api/query_gen/dql_query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
package query_gen

import (
"fmt"
"strconv"
"strings"
)

type QueryFunc func() string

const (
ObjQuery = `
{
obj(func: %s) {
gid: uid
expand(_all_) {
gid: uid
expand(_all_)
dgraph.type
}
dgraph.type
%s
}
}
`

ObjsQuery = `
{
objs(func: type("%s")%s) @filter(%s) {
gid: uid
expand(_all_) {
gid: uid
expand(_all_)
dgraph.type
}
dgraph.type
%s
}
}
`

ReverseEdgeQuery = `
%s: ~%s {
gid: uid
expand(_all_)
dgraph.type
}
`

FuncUid = `uid(%d)`
FuncEq = `eq(%s, %s)`
FuncSimilarTo = `similar_to(%s, %d, "[%s]")`
FuncAllOfTerms = `allofterms(%s, "%s")`
FuncAnyOfTerms = `anyofterms(%s, "%s")`
FuncAllOfText = `alloftext(%s, "%s")`
FuncAnyOfText = `anyoftext(%s, "%s")`
FuncRegExp = `regexp(%s, /%s/)`
FuncLe = `le(%s, %s)`
FuncGe = `ge(%s, %s)`
FuncGt = `gt(%s, %s)`
FuncLt = `lt(%s, %s)`
)

func BuildUidQuery(gid uint64) QueryFunc {
return func() string {
return fmt.Sprintf(FuncUid, gid)
}
}

func BuildEqQuery(key string, value any) QueryFunc {
return func() string {
return fmt.Sprintf(FuncEq, key, value)
}
}

func BuildSimilarToQuery(indexAttr string, topK int64, vec []float32) QueryFunc {
vecStrArr := make([]string, len(vec))
for i := range vec {
vecStrArr[i] = strconv.FormatFloat(float64(vec[i]), 'f', -1, 32)
}
vecStr := strings.Join(vecStrArr, ",")
return func() string {
return fmt.Sprintf(FuncSimilarTo, indexAttr, topK, vecStr)
}
}

func BuildAllOfTermsQuery(attr string, terms string) QueryFunc {
return func() string {
return fmt.Sprintf(FuncAllOfTerms, attr, terms)
}
}

func BuildAnyOfTermsQuery(attr string, terms string) QueryFunc {
return func() string {
return fmt.Sprintf(FuncAnyOfTerms, attr, terms)
}
}

func BuildAllOfTextQuery(attr, text string) QueryFunc {
return func() string {
return fmt.Sprintf(FuncAllOfText, attr, text)
}
}

func BuildAnyOfTextQuery(attr, text string) QueryFunc {
return func() string {
return fmt.Sprintf(FuncAnyOfText, attr, text)
}
}

func BuildRegExpQuery(attr, pattern string) QueryFunc {
return func() string {
return fmt.Sprintf(FuncRegExp, attr, pattern)
}
}

func BuildLeQuery(attr, value string) QueryFunc {
return func() string {
return fmt.Sprintf(FuncLe, attr, value)
}
}

func BuildGeQuery(attr, value string) QueryFunc {
return func() string {
return fmt.Sprintf(FuncGe, attr, value)
}
}

func BuildGtQuery(attr, value string) QueryFunc {
return func() string {
return fmt.Sprintf(FuncGt, attr, value)
}
}

func BuildLtQuery(attr, value string) QueryFunc {
return func() string {
return fmt.Sprintf(FuncLt, attr, value)
}
}

func And(qfs ...QueryFunc) QueryFunc {
return func() string {
qs := make([]string, len(qfs))
for i, qf := range qfs {
qs[i] = qf()
}
return strings.Join(qs, " AND ")
}
}

func Or(qfs ...QueryFunc) QueryFunc {
return func() string {
qs := make([]string, len(qfs))
for i, qf := range qfs {
qs[i] = qf()
}
return strings.Join(qs, " OR ")
}
}

func Not(qf QueryFunc) QueryFunc {
return func() string {
return "NOT " + qf()
}
}

func FormatObjQuery(qf QueryFunc, extraFields string) string {
return fmt.Sprintf(ObjQuery, qf(), extraFields)
}

func FormatObjsQuery(typeName string, qf QueryFunc, paginationAndSorting string, extraFields string) string {
return fmt.Sprintf(ObjsQuery, typeName, paginationAndSorting, qf(), extraFields)
}
Loading
Loading