Compare commits

..

No commits in common. "40b754668db148d4ca893596125405b907ed7833" and "4de1c20938bff4a71ac90156eeaf1a034df496f2" have entirely different histories.

5 changed files with 78 additions and 184 deletions

View File

@ -3,9 +3,7 @@ package orm
import ( import (
"encoding/json" "encoding/json"
"go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/v2/bson"
"log"
"reflect" "reflect"
"strings"
"time" "time"
) )
@ -17,7 +15,6 @@ type Document struct {
model *Model `bson:"-"` model *Model `bson:"-"`
exists bool `bson:"-"` exists bool `bson:"-"`
self any `bson:"-"` self any `bson:"-"`
raw any `bson:"-"`
populatedFields map[string]bool `bson:"-"` populatedFields map[string]bool `bson:"-"`
} }
@ -58,7 +55,6 @@ type IDocument interface {
Remove() error Remove() error
Save() error Save() error
SaveWith(opts *SaveOptions) error SaveWith(opts *SaveOptions) error
Populate(fields ...string)
SetSelf(arg interface{}) SetSelf(arg interface{})
getExists() bool getExists() bool
setExists(n bool) setExists(n bool)
@ -72,8 +68,6 @@ type IDocument interface {
markPopulated(field string) markPopulated(field string)
markDepopulated(field string) markDepopulated(field string)
newPopulationMap() newPopulationMap()
getRaw() any
setRaw(raw any)
} }
type SaveOptions struct { type SaveOptions struct {
@ -280,45 +274,3 @@ func (d *Document) Swap(field string, i, j int) error {
return nil 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
}
}
}
}

View File

@ -9,7 +9,6 @@ import (
"go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options" "go.mongodb.org/mongo-driver/v2/mongo/options"
"reflect" "reflect"
"strings"
"time" "time"
) )
@ -80,11 +79,9 @@ func serializeIDs(input interface{}, isJson bool, populated map[string]bool, par
} }
var ip bool var ip bool
for k1, v1 := range populated { for k1, v1 := range populated {
if k1 == descent || k1 == parent { if k1 == parent {
ip = v1 ip = v1
break break
} else if strings.HasPrefix(k1, descent) {
ip = v1
} }
} }
if terr == nil { if terr == nil {
@ -96,9 +93,7 @@ func serializeIDs(input interface{}, isJson bool, populated map[string]bool, par
rarr = append(rarr, getID(fv.Index(j).Interface())) rarr = append(rarr, getID(fv.Index(j).Interface()))
} else { } else {
if ip { if ip {
rarr = append(rarr, serializeIDs(fv.Index(j).Interface(), isJson, populated, descent)) ret0[bbson.Name] = serializeIDs(fv.Index(j).Interface(), isJson, populated, descent)
} else {
rarr = append(rarr, getID(fv.Index(j).Interface()))
} }
} }
} }
@ -106,15 +101,15 @@ func serializeIDs(input interface{}, isJson bool, populated map[string]bool, par
} else if !ok { } else if !ok {
panic(fmt.Sprintf("referenced model slice at '%s.%s' does not implement HasID", nameOf(input), ft.Name)) panic(fmt.Sprintf("referenced model slice at '%s.%s' does not implement HasID", nameOf(input), ft.Name))
} else { } else {
if reflect.ValueOf(ifc).IsNil() || reflect.ValueOf(ifc.Id()).IsZero() { if reflect.ValueOf(ifc).IsNil() {
ret0[bbson.Name] = nil ret0[bbson.Name] = nil
} else { } else {
if !isJson { if !isJson {
ret0[bbson.Name] = ifc.Id() ret0[bbson.Name] = ifc.Id()
} else { } else {
if ip && bbson.Name != "-" { if ip {
ret0[bbson.Name] = serializeIDs(fv.Interface(), isJson, populated, descent) ret0[bbson.Name] = serializeIDs(fv.Interface(), isJson, populated, descent)
} else if bbson.Name != "-" { } else {
ret0[bbson.Name] = ifc.Id() ret0[bbson.Name] = ifc.Id()
} }
} }
@ -318,11 +313,3 @@ func (d *Document) newPopulationMap() {
d.populatedFields = make(map[string]bool) d.populatedFields = make(map[string]bool)
} }
} }
func (d *Document) setRaw(raw any) {
d.raw = raw
}
func (d *Document) getRaw() any {
return d.raw
}

View File

@ -115,6 +115,9 @@ func (m *Model) Find(query interface{}, opts *options.FindOptionsBuilder) (*Quer
q, err := m.FindRaw(query, opts) q, err := m.FindRaw(query, opts)
//idoc := (*DocumentSlice)(qqv.Elem().UnsafePointer()) //idoc := (*DocumentSlice)(qqv.Elem().UnsafePointer())
idoc := make(DocumentSlice, 0) idoc := make(DocumentSlice, 0)
for i := 0; i < qqv.Elem().Len(); i++ {
idoc = append(idoc, qqv.Elem().Index(i).Interface().(IDocument))
}
if err == nil { if err == nil {
rawRes := bson.A{} rawRes := bson.A{}
@ -129,13 +132,8 @@ func (m *Model) Find(query interface{}, opts *options.FindOptionsBuilder) (*Quer
qq.reOrganize() qq.reOrganize()
err = nil err = nil
} }
for i := 0; i < qqv.Elem().Len(); i++ { for _, doc := range idoc {
idoc = append(idoc, qqv.Elem().Index(i).Interface().(IDocument))
}
for i, doc := range idoc {
doc.setModel(*m) doc.setModel(*m)
doc.SetSelf(doc)
doc.setRaw(rawRes[i])
} }
} }
@ -173,7 +171,6 @@ func (m *Model) FindOne(query interface{}, options *options.FindOneOptionsBuilde
} }
qqn := ModelRegistry.new_(m.typeName) qqn := ModelRegistry.new_(m.typeName)
idoc, ok := qqn.(IDocument) idoc, ok := qqn.(IDocument)
idoc.setRaw(raw)
qq := &Query{ qq := &Query{
collection: m.getColl(), collection: m.getColl(),
@ -191,7 +188,6 @@ func (m *Model) FindOne(query interface{}, options *options.FindOneOptionsBuilde
if ok { if ok {
idoc.setExists(true) idoc.setExists(true)
idoc.setModel(*m) idoc.setModel(*m)
idoc.setRaw(raw)
} }
idoc.SetSelf(idoc) idoc.SetSelf(idoc)
return qq, err return qq, err

165
query.go
View File

@ -8,6 +8,7 @@ import (
"github.com/fatih/structtag" "github.com/fatih/structtag"
"go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo"
"log"
"reflect" "reflect"
"strings" "strings"
) )
@ -35,9 +36,6 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter
if srt.Kind() == reflect.Pointer { if srt.Kind() == reflect.Pointer {
srt = rt.Elem() srt = rt.Elem()
} }
if rv.Kind() == reflect.Pointer && reflect.ValueOf(src).IsNil() {
return src
}
if rv.Kind() != reflect.Pointer { if rv.Kind() != reflect.Pointer {
rv = reflect.New(rt) rv = reflect.New(rt)
rv.Elem().Set(reflect.ValueOf(src)) rv.Elem().Set(reflect.ValueOf(src))
@ -47,7 +45,6 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter
type bsonWhat struct { type bsonWhat struct {
What string What string
} }
var isNotStructOrSlice bool
var w bsonWhat var w bsonWhat
switch rawDoc.(type) { switch rawDoc.(type) {
case bson.A: case bson.A:
@ -79,9 +76,6 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter
for i, el := range rawDoc.(bson.A) { for i, el := range rawDoc.(bson.A) {
it := rahh.Index(i) it := rahh.Index(i)
popped := populate(r, rcoll, el, next, it.Interface()) popped := populate(r, rcoll, el, next, it.Interface())
if pidoc, pok := popped.(IDocument); pok {
pidoc.setRaw(el)
}
poppedVal := reflect.ValueOf(popped) poppedVal := reflect.ValueOf(popped)
if poppedVal.Kind() == reflect.Pointer { if poppedVal.Kind() == reflect.Pointer {
rvs = reflect.Append(rvs, poppedVal.Elem()) rvs = reflect.Append(rvs, poppedVal.Elem())
@ -142,14 +136,6 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter
} }
} }
intermediate := populate(r, rcoll, dd[fieldsMap[2]], next, sf.Interface()) 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() { if rsf.CanSet() {
ival := reflect.ValueOf(intermediate) ival := reflect.ValueOf(intermediate)
if ival.Kind() != reflect.Pointer && rsf.Kind() == reflect.Pointer { if ival.Kind() != reflect.Pointer && rsf.Kind() == reflect.Pointer {
@ -163,7 +149,6 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter
src = intermediate src = intermediate
} }
default: default:
isNotStructOrSlice = true
tto := r.HydratedType tto := r.HydratedType
if tto.Kind() == reflect.Pointer || tto.Kind() == reflect.Slice { if tto.Kind() == reflect.Pointer || tto.Kind() == reflect.Slice {
tto = tto.Elem() tto = tto.Elem()
@ -174,10 +159,7 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter
q := bson.M{"_id": rawDoc} q := bson.M{"_id": rawDoc}
reso := DB.Collection(rcoll).FindOne(context.TODO(), q) reso := DB.Collection(rcoll).FindOne(context.TODO(), q)
if !errors.Is(reso.Err(), mongo.ErrNoDocuments) { if !errors.Is(reso.Err(), mongo.ErrNoDocuments) {
var anotherMap = make(bson.M) reso.Decode(t)
reso.Decode(&anotherMap)
reflect.ValueOf(t).Elem().Set(reflect.ValueOf(rerere(anotherMap, tto)).Elem())
t.setRaw(anotherMap)
} }
hatred := rv hatred := rv
if hatred.Kind() == reflect.Pointer { if hatred.Kind() == reflect.Pointer {
@ -187,12 +169,7 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter
if reflect.ValueOf(t).Kind() == reflect.Pointer { if reflect.ValueOf(t).Kind() == reflect.Pointer {
fmt.Println(reflect.ValueOf(t).Elem().Type().String()) fmt.Println(reflect.ValueOf(t).Elem().Type().String())
fmt.Println(rv.Type().String()) fmt.Println(rv.Type().String())
if hatred.Kind() == reflect.Pointer {
hatred.Set(reflect.ValueOf(t))
} else {
hatred.Set(reflect.ValueOf(t).Elem()) hatred.Set(reflect.ValueOf(t).Elem())
}
recover()
} else { } else {
hatred.Set(reflect.ValueOf(t)) hatred.Set(reflect.ValueOf(t))
} }
@ -208,18 +185,12 @@ func populate(r Reference, rcoll string, rawDoc interface{}, d string, src inter
sidoc, sok := rv.Interface().(IDocument) sidoc, sok := rv.Interface().(IDocument)
if sok { if sok {
sidoc.SetSelf(rv.Interface()) sidoc.SetSelf(rv.Interface())
if !isNotStructOrSlice {
sidoc.setRaw(rawDoc)
}
} }
return rv.Interface() return rv.Interface()
} }
sidoc, sok := src.(IDocument) sidoc, sok := src.(IDocument)
if sok { if sok {
sidoc.SetSelf(src) sidoc.SetSelf(src)
if !isNotStructOrSlice {
sidoc.setRaw(rawDoc)
}
} }
return src return src
} }
@ -256,76 +227,71 @@ func (q *Query) LoadFile(fields ...string) *Query {
return q return q
} }
func readFields(field string, m *Model) (Reference, string) {
var r Reference
var keptKey string
if m == nil {
return r, keptKey
}
for k2, v := range m.references {
if strings.HasPrefix(k2, field) {
r = v
keptKey = k2
break
} else if _, ok := m.references[field]; !ok {
splitSegs := strings.Split(field, ".")
for ii := 0; ii < len(splitSegs)-1; ii++ {
mr, ok2 := m.references[splitSegs[ii]]
if ok2 {
_, sec, _ := ModelRegistry.HasByName(mr.Model)
if sec != nil {
refff, ok3 := sec.references[splitSegs[ii+1]]
if ok3 {
r = refff
keptKey = k2
break
} else {
joined := strings.Join(splitSegs[ii+1:], ".")
inner1, innerKey := readFields(joined, sec)
if inner1.exists {
r = inner1
keptKey = innerKey
}
break
}
}
}
}
}
if keptKey != "" {
break
}
}
return r, keptKey
}
// Populate populates document references via reflection // Populate populates document references via reflection
func (q *Query) Populate(fields ...string) *Query { func (q *Query) Populate(fields ...string) *Query {
vvv := reflect.ValueOf(q.doc) _, cm, _ := ModelRegistry.HasByName(q.model.typeName)
if vvv.Kind() == reflect.Pointer {
vvv = vvv.Elem() if cm != nil {
rawDoc := q.rawDoc
for _, field := range fields {
// 0 = fieldname, 1 = typename, 2 = bson name
var r Reference
for k2, v := range cm.references {
if strings.HasPrefix(k2, field) {
r = v
break
} }
if vvv.Kind() == reflect.Slice { }
typ := reflect.PointerTo(q.model.Type)
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)) slic := reflect.New(reflect.SliceOf(typ))
for i := 0; i < vvv.Len(); i++ { for i, val2 := range arr {
val2 := vvv.Index(i).Interface() ref := reflect.ValueOf(q.doc)
aid, docOk := val2.(IDocument) if ref.Kind() == reflect.Pointer {
if docOk { ref = ref.Elem()
rdoc := q.rawDoc.(bson.A) }
aid.setRaw(rdoc[i]) src := ref.Index(i).Interface()
aid.Populate(fields...) inter := populate(r, refColl.collection, val2, field, src)
if reflect.ValueOf(aid).Kind() == reflect.Pointer { if reflect.ValueOf(inter).Kind() == reflect.Pointer {
slic.Elem().Set(reflect.Append(slic.Elem(), reflect.ValueOf(aid))) slic.Elem().Set(reflect.Append(slic.Elem(), reflect.ValueOf(inter)))
} else { } else {
slic.Elem().Set(reflect.Append(slic, reflect.ValueOf(aid))) slic.Elem().Set(reflect.Append(slic, reflect.ValueOf(inter)))
} }
} }
tmp1 = slic.Interface()
} else {
asIDocument, docOk := q.doc.(IDocument)
if docOk {
asIDocument.markPopulated(field)
}
tmp1 = populate(r, refColl.collection, rawDoc, field, reflect.ValueOf(q.doc).Interface())
}
q.doc = tmp1
}
} }
q.doc = slic.Interface()
} else if asDoc, ok2 := q.doc.(IDocument); ok2 {
asDoc.setRaw(q.rawDoc)
asDoc.Populate(fields...)
} }
return q return q
} }
@ -381,14 +347,7 @@ func rerere(input interface{}, resType reflect.Type) interface{} {
if resType.Kind() == reflect.Pointer { if resType.Kind() == reflect.Pointer {
resType = resType.Elem() resType = resType.Elem()
} }
var resV reflect.Value resV := reflect.New(resType)
newInstance := ModelRegistry.newForType(resType)
if newInstance == nil {
resV = reflect.New(resType)
} else {
resV = reflect.ValueOf(newInstance)
}
var rve = resV var rve = resV
if rve.Kind() == reflect.Pointer { if rve.Kind() == reflect.Pointer {
rve = resV.Elem() rve = resV.Elem()
@ -439,6 +398,8 @@ func rerere(input interface{}, resType reflect.Type) interface{} {
fuck = fuck.Elem() fuck = fuck.Elem()
} }
fv.Set(fuck) fv.Set(fuck)
} else {
fv.Set(reflect.Zero(ft.Type))
} }
shouldBreak = true shouldBreak = true
} else { } else {
@ -453,6 +414,8 @@ func rerere(input interface{}, resType reflect.Type) interface{} {
} else { } else {
fv.Set(reflect.ValueOf(tmp)) fv.Set(reflect.ValueOf(tmp))
} }
} else {
fv.Set(reflect.Zero(ft.Type))
} }
} }
} }

View File

@ -167,7 +167,7 @@ func parseTags(t reflect.Type, v reflect.Value, lastParsed string, eqCount int)
break break
} }
if refTag, ok := tags.Get("ref"); ok == nil { if refTag, ok := tags.Get("ref"); ok == nil {
sname := sft.Name sname := sft.Name + "@" + refTag.Name
refs[sname] = makeRef(i, refTag.Name, sft.Name, sft.Type) refs[sname] = makeRef(i, refTag.Name, sft.Name, sft.Type)
} }
if gtag, ok := tags.Get("gridfs"); ok == nil { if gtag, ok := tags.Get("gridfs"); ok == nil {
@ -244,10 +244,6 @@ func (r TModelRegistry) new_(n string) interface{} {
return nil return nil
} }
func (r TModelRegistry) newForType(rt reflect.Type) interface{} {
return r.new_(rt.Name())
}
func (r TModelRegistry) Get(name string) *Model { func (r TModelRegistry) Get(name string) *Model {
model, ok := r[name] model, ok := r[name]
if !ok { if !ok {