fix gridfs save/delete bugs
This commit is contained in:
parent
6e865b733d
commit
95b6e3f1bf
@ -199,6 +199,9 @@ func doSave(c *mongo.Collection, isNew bool, opts *SaveOptions, arg interface{})
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//_, err = c.ReplaceOne(context.TO_DO(), bson.D{{Key: "_id", Value: d.(HasID).Id()}}, d.serializeToStore())
|
//_, err = c.ReplaceOne(context.TO_DO(), bson.D{{Key: "_id", Value: d.(HasID).Id()}}, d.serializeToStore())
|
||||||
|
_, im, _ := ModelRegistry.HasByName(asModel.getModel().getTypeName())
|
||||||
|
_ = gridFsSave(asHasId, *im)
|
||||||
|
|
||||||
_, err = c.UpdateOne(context.TODO(), bson.D{{Key: "_id", Value: d.(HasID).Id()}}, bson.M{
|
_, err = c.UpdateOne(context.TODO(), bson.D{{Key: "_id", Value: d.(HasID).Id()}}, bson.M{
|
||||||
"$set": d.serializeToStore(),
|
"$set": d.serializeToStore(),
|
||||||
})
|
})
|
||||||
|
180
gridfs.go
180
gridfs.go
@ -21,13 +21,12 @@ type GridFSFile struct {
|
|||||||
Length int `bson:"length"`
|
Length int `bson:"length"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFmt(format string, value any) string {
|
func parseFmt(format string, value any) (string, error) {
|
||||||
tmpl, err := template.New("filename").Parse(format)
|
tmpl, err := template.New("filename").Parse(format)
|
||||||
panik(err)
|
panik(err)
|
||||||
w := new(strings.Builder)
|
w := new(strings.Builder)
|
||||||
err = tmpl.Execute(w, value)
|
err = tmpl.Execute(w, value)
|
||||||
panik(err)
|
return w.String(), err
|
||||||
return w.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func bucket(gfsRef gridFSReference) *mongo.GridFSBucket {
|
func bucket(gfsRef gridFSReference) *mongo.GridFSBucket {
|
||||||
@ -35,6 +34,32 @@ func bucket(gfsRef gridFSReference) *mongo.GridFSBucket {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasTag(rtype reflect.Type, imodel Model) bool {
|
||||||
|
if rtype.Kind() == reflect.Pointer {
|
||||||
|
rtype = rtype.Elem()
|
||||||
|
}
|
||||||
|
if rtype.Kind() == reflect.Slice {
|
||||||
|
return hasTag(rtype.Elem(), imodel)
|
||||||
|
} else if rtype.Kind() == reflect.Struct {
|
||||||
|
for i := 0; i < rtype.NumField(); i++ {
|
||||||
|
f := rtype.Field(i)
|
||||||
|
tags, err := structtag.Parse(string(f.Tag))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if _, err = tags.Get("gridfs"); err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for kk := range imodel.gridFSReferences {
|
||||||
|
if strings.HasPrefix(kk, f.Name) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func gridFsLoad(val any, g gridFSReference, field string) any {
|
func gridFsLoad(val any, g gridFSReference, field string) any {
|
||||||
doc := reflect.ValueOf(val)
|
doc := reflect.ValueOf(val)
|
||||||
rdoc := reflect.ValueOf(val)
|
rdoc := reflect.ValueOf(val)
|
||||||
@ -81,7 +106,11 @@ func gridFsLoad(val any, g gridFSReference, field string) any {
|
|||||||
default:
|
default:
|
||||||
b := bucket(g)
|
b := bucket(g)
|
||||||
var found GridFSFile
|
var found GridFSFile
|
||||||
cursor, err := b.Find(context.TODO(), bson.M{"filename": parseFmt(g.FilenameFmt, val)})
|
fname, err := parseFmt(g.FilenameFmt, val)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cursor, err := b.Find(context.TODO(), bson.M{"filename": fname})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -105,7 +134,7 @@ func gridFsLoad(val any, g gridFSReference, field string) any {
|
|||||||
return doc.Interface()
|
return doc.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
func gridFsDel(val any, imodel Model) error {
|
func gridFsGen(val any, imodel Model, isSaving bool) error {
|
||||||
var rerr error
|
var rerr error
|
||||||
v := reflect.ValueOf(val)
|
v := reflect.ValueOf(val)
|
||||||
el := v
|
el := v
|
||||||
@ -130,17 +159,39 @@ func gridFsDel(val any, imodel Model) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var inner = func(b *mongo.GridFSBucket, it reflect.Value) error {
|
var inner = func(b *mongo.GridFSBucket, it reflect.Value) error {
|
||||||
filename := parseFmt(gfsRef.FilenameFmt, it.Interface())
|
filename, err2 := parseFmt(gfsRef.FilenameFmt, it.Interface())
|
||||||
|
if err2 != nil {
|
||||||
|
return err2
|
||||||
|
}
|
||||||
contents := GridFSFile{}
|
contents := GridFSFile{}
|
||||||
curs, err2 := b.Find(context.TODO(), bson.M{"filename": filename})
|
curs, err2 := b.Find(context.TODO(), bson.M{"filename": filename})
|
||||||
|
|
||||||
if !errors.Is(err2, mongo.ErrNoDocuments) {
|
if !errors.Is(err2, mongo.ErrNoDocuments) {
|
||||||
_ = curs.Decode(&contents)
|
for {
|
||||||
if !reflect.ValueOf(contents).IsZero() {
|
if !curs.Next(context.TODO()) {
|
||||||
return b.Delete(context.TODO(), contents.ID)
|
break
|
||||||
|
}
|
||||||
|
_ = curs.Decode(&contents)
|
||||||
|
if !reflect.ValueOf(contents).IsZero() {
|
||||||
|
b.Delete(context.TODO(), contents.ID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return nil
|
if isSaving {
|
||||||
|
c := it.Field(gfsRef.Idx)
|
||||||
|
var rdr io.Reader
|
||||||
|
|
||||||
|
if c.Type().AssignableTo(reflect.TypeOf([]byte{})) {
|
||||||
|
rdr = bytes.NewReader(c.Interface().([]byte))
|
||||||
|
} else if c.Type().AssignableTo(reflect.TypeOf("")) {
|
||||||
|
rdr = strings.NewReader(c.Interface().(string))
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("gridfs loader type '%s' not supported", c.Type().String())
|
||||||
|
}
|
||||||
|
_, err = b.UploadFromStream(context.TODO(), filename, rdr)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
if gfsRef != nil {
|
if gfsRef != nil {
|
||||||
b := bucket(*gfsRef)
|
b := bucket(*gfsRef)
|
||||||
@ -148,29 +199,31 @@ func gridFsDel(val any, imodel Model) error {
|
|||||||
for j := 0; j < fv.Len(); j++ {
|
for j := 0; j < fv.Len(); j++ {
|
||||||
lerr := inner(b, fv.Index(j))
|
lerr := inner(b, fv.Index(j))
|
||||||
if lerr != nil {
|
if lerr != nil {
|
||||||
return lerr
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if fv.Kind() == reflect.Struct {
|
} else if fv.Kind() == reflect.Struct {
|
||||||
lerr := inner(b, fv)
|
lerr := inner(b, fv)
|
||||||
if lerr != nil {
|
if lerr != nil {
|
||||||
return lerr
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lerr := inner(b, el)
|
lerr := inner(b, el)
|
||||||
if lerr != nil {
|
if lerr != nil {
|
||||||
return lerr
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = gridFsDel(fv.Interface(), imodel)
|
if hasTag(ft.Type, imodel) {
|
||||||
if err != nil {
|
err = gridFsGen(fv.Interface(), imodel, isSaving)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
for i := 0; i < el.Len(); i++ {
|
for i := 0; i < el.Len(); i++ {
|
||||||
rerr = gridFsDel(el.Index(i).Interface(), imodel)
|
rerr = gridFsGen(el.Index(i).Interface(), imodel, isSaving)
|
||||||
if rerr != nil {
|
if rerr != nil {
|
||||||
return rerr
|
return rerr
|
||||||
}
|
}
|
||||||
@ -181,91 +234,14 @@ func gridFsDel(val any, imodel Model) error {
|
|||||||
return rerr
|
return rerr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func gridFsDel(val any, imodel Model) error {
|
||||||
|
return gridFsGen(val, imodel, false)
|
||||||
|
}
|
||||||
|
|
||||||
func gridFsSave(val any, imodel Model) error {
|
func gridFsSave(val any, imodel Model) error {
|
||||||
var rerr error
|
t := reflect.TypeOf(val)
|
||||||
v := reflect.ValueOf(val)
|
if hasTag(t, imodel) {
|
||||||
el := v
|
return gridFsGen(val, imodel, true)
|
||||||
if v.Kind() == reflect.Pointer {
|
|
||||||
el = el.Elem()
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
switch el.Kind() {
|
|
||||||
case reflect.Struct:
|
|
||||||
for i := 0; i < el.NumField(); i++ {
|
|
||||||
ft := el.Type().Field(i)
|
|
||||||
fv := el.Field(i)
|
|
||||||
if !ft.IsExported() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
_, err := structtag.Parse(string(ft.Tag))
|
|
||||||
panik(err)
|
|
||||||
var gfsRef *gridFSReference
|
|
||||||
for kk, vv := range imodel.gridFSReferences {
|
|
||||||
if strings.HasPrefix(kk, ft.Name) {
|
|
||||||
gfsRef = &vv
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var inner = func(b *mongo.GridFSBucket, it reflect.Value) error {
|
|
||||||
filename := parseFmt(gfsRef.FilenameFmt, it.Interface())
|
|
||||||
contents := GridFSFile{}
|
|
||||||
curs, err2 := b.Find(context.TODO(), bson.M{"filename": filename})
|
|
||||||
|
|
||||||
if !errors.Is(err2, mongo.ErrNoDocuments) {
|
|
||||||
_ = curs.Decode(&contents)
|
|
||||||
if !reflect.ValueOf(contents).IsZero() {
|
|
||||||
_ = b.Delete(context.TODO(), contents.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c := it.Field(gfsRef.Idx)
|
|
||||||
var rdr io.Reader
|
|
||||||
|
|
||||||
if c.Type().AssignableTo(reflect.TypeOf([]byte{})) {
|
|
||||||
rdr = bytes.NewReader(c.Interface().([]byte))
|
|
||||||
} else if c.Type().AssignableTo(reflect.TypeOf("")) {
|
|
||||||
rdr = strings.NewReader(c.Interface().(string))
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("gridfs loader type '%s' not supported", c.Type().String())
|
|
||||||
}
|
|
||||||
_, err = b.UploadFromStream(context.TODO(), filename, rdr)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if gfsRef != nil {
|
|
||||||
b := bucket(*gfsRef)
|
|
||||||
if fv.Kind() == reflect.Slice {
|
|
||||||
for j := 0; j < fv.Len(); j++ {
|
|
||||||
lerr := inner(b, fv.Index(j))
|
|
||||||
if lerr != nil {
|
|
||||||
return lerr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if fv.Kind() == reflect.Struct {
|
|
||||||
lerr := inner(b, fv)
|
|
||||||
if lerr != nil {
|
|
||||||
return lerr
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lerr := inner(b, el)
|
|
||||||
if lerr != nil {
|
|
||||||
return lerr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err = gridFsSave(fv.Interface(), imodel)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case reflect.Slice:
|
|
||||||
for i := 0; i < el.Len(); i++ {
|
|
||||||
rerr = gridFsSave(el.Index(i).Interface(), imodel)
|
|
||||||
if rerr != nil {
|
|
||||||
return rerr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return rerr
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user