rework Populate api
This commit is contained in:
parent
5585634c83
commit
40b754668d
45
document.go
45
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
8
model.go
8
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
|
||||
|
115
query.go
115
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user