From 510a126f4ba5bcf7398b59b9b3c8013a425f03a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=98=99=E2=97=A6=20The=20Tablet=20=E2=9D=80=20GamerGirla?= =?UTF-8?q?ndCo=20=E2=97=A6=E2=9D=A7?= Date: Thu, 10 Apr 2025 00:32:59 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fix references in nested structs not being registered properly - rework struct tag parsing - remove debug logs - fix bug where an unrelated field with the same prefix as another population path is erroneously marked as populated --- document_internals.go | 5 +- query.go | 6 +- registry.go | 129 ++++++++++++++++++++++-------------------- 3 files changed, 71 insertions(+), 69 deletions(-) diff --git a/document_internals.go b/document_internals.go index 21f9912..991827d 100644 --- a/document_internals.go +++ b/document_internals.go @@ -9,7 +9,6 @@ import ( "go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo/options" "reflect" - "strings" "time" ) @@ -80,11 +79,9 @@ func serializeIDs(input interface{}, isJson bool, populated map[string]bool, par } var ip bool for k1, v1 := range populated { - if k1 == descent || k1 == parent { + if k1 == descent { ip = v1 break - } else if strings.HasPrefix(k1, descent) { - ip = v1 } } if terr == nil { diff --git a/query.go b/query.go index e50fd41..7d202a8 100644 --- a/query.go +++ b/query.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "errors" - "fmt" "github.com/fatih/structtag" "go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/v2/mongo" @@ -186,8 +185,6 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter } if hatred.CanSet() { if reflect.ValueOf(t).Kind() == reflect.Pointer { - fmt.Println(reflect.ValueOf(t).Elem().Type().String()) - fmt.Println(rv.Type().String()) if hatred.Kind() == reflect.Pointer { hatred.Set(reflect.ValueOf(t)) } else { @@ -292,6 +289,9 @@ func readFields(field string, m *Model) (Reference, string) { } } } + } else if ok { + r = m.references[field] + break } if keptKey != "" { break diff --git a/registry.go b/registry.go index af8e002..18fdddd 100644 --- a/registry.go +++ b/registry.go @@ -6,6 +6,7 @@ import ( "log" "reflect" "sync" + "time" "github.com/fatih/structtag" "go.mongodb.org/mongo-driver/v2/bson" @@ -111,82 +112,86 @@ func makeRef(idx int, modelName string, fieldName string, ht reflect.Type) Refer panic("model name was empty") } -func parseTags(t reflect.Type, v reflect.Value, lastParsed string, eqCount int) (map[string][]InternalIndex, map[string]Reference, map[string]gridFSReference, string) { +type parseResult []string + +func (p parseResult) includes(str string) bool { + for _, v := range p { + if v == str { + return true + } + } + return false +} + +func parseTags(t reflect.Type, v reflect.Value, lastParsed parseResult, depth int) (map[string][]InternalIndex, map[string]Reference, map[string]gridFSReference, string) { coll := "" refs := make(map[string]Reference) idcs := make(map[string][]InternalIndex) gfsRefs := make(map[string]gridFSReference) - + if depth >= 4 { + return idcs, refs, gfsRefs, coll + } for i := 0; i < v.NumField(); i++ { sft := t.Field(i) ft := sft.Type tags, err := structtag.Parse(string(sft.Tag)) panik(err) - shouldContinue := true - for { - if !shouldContinue { - break + switch ft.Kind() { + case reflect.Slice: + ft = ft.Elem() + fallthrough + case reflect.Pointer: + if ft.Kind() == reflect.Pointer { + ft = ft.Elem() } - switch ft.Kind() { - case reflect.Slice: - ft = ft.Elem() - count := eqCount - if lastParsed != ft.String() { - count = 0 - } else { - count = count + 1 - } - if /*_, ok := tags.Get("ref"); ok != nil && */ count < 3 { - if ft.Kind() == reflect.Struct { - ii2, rr2, gg2, _ := parseTags(ft, reflect.New(ft).Elem(), ft.String(), count) - for k, vv := range ii2 { - idcs[sft.Name+"."+k] = vv - } - for k, vv := range rr2 { - refs[sft.Name+"."+k] = vv - } - for k, vv := range gg2 { - gfsRefs[sft.Name+"."+k] = vv - } - } - } - continue - case reflect.Pointer: - ft = ft.Elem() - fallthrough - case reflect.Struct: - if ft.ConvertibleTo(reflect.TypeOf(Document{})) { - collTag, err := tags.Get("coll") - panik(err) - coll = collTag.Name - idxTag, err := tags.Get("idx") - if err == nil { - idcs[sft.Type.Name()] = scanIndex(idxTag.Value()) - } - shouldContinue = false - break - } - if refTag, ok := tags.Get("ref"); ok == nil { - sname := sft.Name - refs[sname] = makeRef(i, refTag.Name, sft.Name, sft.Type) - } - if gtag, ok := tags.Get("gridfs"); ok == nil { - sname := sft.Name + "@" + gtag.Name - gfsRefs[sname] = makeGfsRef(gtag, i) - } - fallthrough - default: + fallthrough + case reflect.Struct: + if ft.ConvertibleTo(reflect.TypeOf(Document{})) { + collTag, err := tags.Get("coll") + panik(err) + coll = collTag.Name idxTag, err := tags.Get("idx") if err == nil { - idcs[sft.Name] = scanIndex(idxTag.Value()) + idcs[sft.Type.Name()] = scanIndex(idxTag.Value()) } - if gtag, ok := tags.Get("gridfs"); ok == nil { - sname := sft.Name + "@" + gtag.Name - gfsRefs[sname] = makeGfsRef(gtag, i) - } - shouldContinue = false + continue } + if lastParsed.includes(sft.Name) { + continue + } + blip := lastParsed + blip = append(blip, sft.Name) + if ft.Kind() == reflect.Struct && ft != reflect.TypeFor[time.Time]() { + ii2, rr2, gg2, _ := parseTags(ft, reflect.New(ft).Elem(), blip, depth+1) + for k, vv := range ii2 { + idcs[sft.Name+"."+k] = vv + } + for k, vv := range rr2 { + refs[sft.Name+"."+k] = vv + } + for k, vv := range gg2 { + gfsRefs[sft.Name+"."+k] = vv + } + } + if refTag, ok := tags.Get("ref"); ok == nil { + sname := sft.Name + refs[sname] = makeRef(i, refTag.Name, sft.Name, sft.Type) + } + if gtag, ok := tags.Get("gridfs"); ok == nil { + sname := sft.Name + "@" + gtag.Name + gfsRefs[sname] = makeGfsRef(gtag, i) + } + fallthrough + default: + idxTag, err := tags.Get("idx") + if err == nil { + idcs[sft.Name] = scanIndex(idxTag.Value()) + } + if gtag, ok := tags.Get("gridfs"); ok == nil { + sname := sft.Name + "@" + gtag.Name + gfsRefs[sname] = makeGfsRef(gtag, i) + } } } return idcs, refs, gfsRefs, coll @@ -304,7 +309,7 @@ func (r TModelRegistry) Model(mdl ...any) { if idx < 0 { panic("A model must embed the Document struct!") } - inds, refs, gfs, coll := parseTags(t, v, "", 0) + inds, refs, gfs, coll := parseTags(t, v, make(parseResult, 0), 0) if coll == "" { panic(fmt.Sprintf("a Document needs to be given a collection name! (passed type: %s)", n)) }