From 40b754668db148d4ca893596125405b907ed7833 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: Mon, 7 Apr 2025 02:08:56 -0400 Subject: [PATCH] rework Populate api --- document.go | 45 ++++++++++++++++++++ model.go | 8 ++-- query.go | 115 +++++++++++++++++++++++----------------------------- 3 files changed, 101 insertions(+), 67 deletions(-) diff --git a/document.go b/document.go index 197f695..91f3eee 100644 --- a/document.go +++ b/document.go @@ -3,7 +3,9 @@ package orm import ( "encoding/json" "go.mongodb.org/mongo-driver/v2/bson" + "log" "reflect" + "strings" "time" ) @@ -56,6 +58,7 @@ type IDocument interface { Remove() error Save() error SaveWith(opts *SaveOptions) error + Populate(fields ...string) SetSelf(arg interface{}) getExists() bool setExists(n bool) @@ -277,3 +280,45 @@ func (d *Document) Swap(field string, i, j int) error { return nil } + +func (d *Document) Populate(fields ...string) { + _, cm, _ := ModelRegistry.HasByName(d.model.typeName) + + if cm != nil { + rawDoc := d.raw + for _, field := range fields { + // 0 = fieldname, 1 = typename, 2 = bson name + + r, _ := readFields(field, cm) + + if r.exists { + // get self + // get ptr + // find + // unmarshal... + htt := r.HydratedType + if htt.Kind() == reflect.Pointer || htt.Kind() == reflect.Slice { + htt = htt.Elem() + } + if strings.HasSuffix(field, ".") || strings.HasPrefix(field, ".") { + log.Printf("WARN: invalid field name passed to Populate(). skipping...\n") + continue + } + + tto := r.HydratedType + if tto.Kind() == reflect.Pointer || tto.Kind() == reflect.Slice { + tto = tto.Elem() + } + _, refColl, _ := ModelRegistry.HasByName(tto.Name()) + var tmp1 interface{} + asIDocument, docOk := d.self.(IDocument) + if docOk { + asIDocument.markPopulated(field) + } + + tmp1 = populate(r, refColl.collection, rawDoc, field, reflect.ValueOf(d.self).Interface()) + d.self = tmp1 + } + } + } +} diff --git a/model.go b/model.go index 2166b01..435acae 100644 --- a/model.go +++ b/model.go @@ -115,9 +115,6 @@ func (m *Model) Find(query interface{}, opts *options.FindOptionsBuilder) (*Quer q, err := m.FindRaw(query, opts) //idoc := (*DocumentSlice)(qqv.Elem().UnsafePointer()) idoc := make(DocumentSlice, 0) - for i := 0; i < qqv.Elem().Len(); i++ { - idoc = append(idoc, qqv.Elem().Index(i).Interface().(IDocument)) - } if err == nil { rawRes := bson.A{} @@ -132,8 +129,12 @@ func (m *Model) Find(query interface{}, opts *options.FindOptionsBuilder) (*Quer qq.reOrganize() err = nil } + for i := 0; i < qqv.Elem().Len(); i++ { + idoc = append(idoc, qqv.Elem().Index(i).Interface().(IDocument)) + } for i, doc := range idoc { doc.setModel(*m) + doc.SetSelf(doc) doc.setRaw(rawRes[i]) } } @@ -190,6 +191,7 @@ func (m *Model) FindOne(query interface{}, options *options.FindOneOptionsBuilde if ok { idoc.setExists(true) idoc.setModel(*m) + idoc.setRaw(raw) } idoc.SetSelf(idoc) return qq, err diff --git a/query.go b/query.go index 1b7fd57..5b17ffd 100644 --- a/query.go +++ b/query.go @@ -8,7 +8,6 @@ import ( "github.com/fatih/structtag" "go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/v2/mongo" - "log" "reflect" "strings" ) @@ -36,6 +35,9 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter if srt.Kind() == reflect.Pointer { srt = rt.Elem() } + if rv.Kind() == reflect.Pointer && reflect.ValueOf(src).IsNil() { + return src + } if rv.Kind() != reflect.Pointer { rv = reflect.New(rt) rv.Elem().Set(reflect.ValueOf(src)) @@ -45,6 +47,7 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter type bsonWhat struct { What string } + var isNotStructOrSlice bool var w bsonWhat switch rawDoc.(type) { case bson.A: @@ -76,6 +79,9 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter for i, el := range rawDoc.(bson.A) { it := rahh.Index(i) popped := populate(r, rcoll, el, next, it.Interface()) + if pidoc, pok := popped.(IDocument); pok { + pidoc.setRaw(el) + } poppedVal := reflect.ValueOf(popped) if poppedVal.Kind() == reflect.Pointer { rvs = reflect.Append(rvs, poppedVal.Elem()) @@ -136,6 +142,14 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter } } intermediate := populate(r, rcoll, dd[fieldsMap[2]], next, sf.Interface()) + /*if iidoc, idocOk := intermediate.(IDocument); idocOk { + if (reflect.ValueOf(intermediate).CanAddr() && !reflect.ValueOf(intermediate).IsNil()) || !reflect.ValueOf(intermediate).IsZero() { + iiid, iok := intermediate.(HasID) + if intermediate != nil && iok && !reflect.ValueOf(iiid.Id()).IsZero() { + iidoc.setRaw(dd[fieldsMap[2]]) + } + } + }*/ if rsf.CanSet() { ival := reflect.ValueOf(intermediate) if ival.Kind() != reflect.Pointer && rsf.Kind() == reflect.Pointer { @@ -149,6 +163,7 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter src = intermediate } default: + isNotStructOrSlice = true tto := r.HydratedType if tto.Kind() == reflect.Pointer || tto.Kind() == reflect.Slice { tto = tto.Elem() @@ -159,9 +174,10 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter q := bson.M{"_id": rawDoc} reso := DB.Collection(rcoll).FindOne(context.TODO(), q) if !errors.Is(reso.Err(), mongo.ErrNoDocuments) { - var anotherMap bson.M + var anotherMap = make(bson.M) reso.Decode(&anotherMap) reflect.ValueOf(t).Elem().Set(reflect.ValueOf(rerere(anotherMap, tto)).Elem()) + t.setRaw(anotherMap) } hatred := rv if hatred.Kind() == reflect.Pointer { @@ -171,7 +187,12 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter if reflect.ValueOf(t).Kind() == reflect.Pointer { fmt.Println(reflect.ValueOf(t).Elem().Type().String()) fmt.Println(rv.Type().String()) - hatred.Set(reflect.ValueOf(t).Elem()) + if hatred.Kind() == reflect.Pointer { + hatred.Set(reflect.ValueOf(t)) + } else { + hatred.Set(reflect.ValueOf(t).Elem()) + } + recover() } else { hatred.Set(reflect.ValueOf(t)) } @@ -187,12 +208,18 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter sidoc, sok := rv.Interface().(IDocument) if sok { sidoc.SetSelf(rv.Interface()) + if !isNotStructOrSlice { + sidoc.setRaw(rawDoc) + } } return rv.Interface() } sidoc, sok := src.(IDocument) if sok { sidoc.SetSelf(src) + if !isNotStructOrSlice { + sidoc.setRaw(rawDoc) + } } return src } @@ -274,67 +301,31 @@ func readFields(field string, m *Model) (Reference, string) { // Populate populates document references via reflection func (q *Query) Populate(fields ...string) *Query { - _, cm, _ := ModelRegistry.HasByName(q.model.typeName) - - if cm != nil { - rawDoc := q.rawDoc - for _, field := range fields { - // 0 = fieldname, 1 = typename, 2 = bson name - - r, keptKey := readFields(field, cm) - - if r.exists { - // get self - // get ptr - // find - // unmarshal... - htt := r.HydratedType - if htt.Kind() == reflect.Pointer || htt.Kind() == reflect.Slice { - htt = htt.Elem() - } - if strings.HasSuffix(field, ".") || strings.HasPrefix(field, ".") { - log.Printf("WARN: invalid field name passed to Populate(). skipping...\n") - continue - } - - tto := r.HydratedType - if tto.Kind() == reflect.Pointer || tto.Kind() == reflect.Slice { - tto = tto.Elem() - } - _, refColl, _ := ModelRegistry.HasByName(tto.Name()) - var tmp1 interface{} - if arr, ok := rawDoc.(bson.A); ok { - typ := reflect.PointerTo(cm.Type) - slic := reflect.New(reflect.SliceOf(typ)) - for i, val2 := range arr { - ref := reflect.ValueOf(q.doc) - if ref.Kind() == reflect.Pointer { - ref = ref.Elem() - } - src := ref.Index(i).Interface() - inter := populate(r, refColl.collection, val2, field, src) - aid, docOk := inter.(IDocument) - if docOk { - aid.markPopulated(keptKey) - aid.markPopulated(field) - } - if reflect.ValueOf(inter).Kind() == reflect.Pointer { - slic.Elem().Set(reflect.Append(slic.Elem(), reflect.ValueOf(inter))) - } else { - slic.Elem().Set(reflect.Append(slic, reflect.ValueOf(inter))) - } - } - tmp1 = slic.Interface() + vvv := reflect.ValueOf(q.doc) + if vvv.Kind() == reflect.Pointer { + vvv = vvv.Elem() + } + if vvv.Kind() == reflect.Slice { + typ := reflect.PointerTo(q.model.Type) + slic := reflect.New(reflect.SliceOf(typ)) + for i := 0; i < vvv.Len(); i++ { + val2 := vvv.Index(i).Interface() + aid, docOk := val2.(IDocument) + if docOk { + rdoc := q.rawDoc.(bson.A) + aid.setRaw(rdoc[i]) + aid.Populate(fields...) + if reflect.ValueOf(aid).Kind() == reflect.Pointer { + slic.Elem().Set(reflect.Append(slic.Elem(), reflect.ValueOf(aid))) } else { - asIDocument, docOk := q.doc.(IDocument) - if docOk { - asIDocument.markPopulated(field) - } - tmp1 = populate(r, refColl.collection, rawDoc, field, reflect.ValueOf(q.doc).Interface()) + slic.Elem().Set(reflect.Append(slic, reflect.ValueOf(aid))) } - q.doc = tmp1 } } + q.doc = slic.Interface() + } else if asDoc, ok2 := q.doc.(IDocument); ok2 { + asDoc.setRaw(q.rawDoc) + asDoc.Populate(fields...) } return q } @@ -448,8 +439,6 @@ func rerere(input interface{}, resType reflect.Type) interface{} { fuck = fuck.Elem() } fv.Set(fuck) - } else { - fv.Set(reflect.Zero(ft.Type)) } shouldBreak = true } else { @@ -464,8 +453,6 @@ func rerere(input interface{}, resType reflect.Type) interface{} { } else { fv.Set(reflect.ValueOf(tmp)) } - } else { - fv.Set(reflect.Zero(ft.Type)) } } }