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