fix gridfs save/delete bugs

This commit is contained in:
☙◦ The Tablet ❀ GamerGirlandCo ◦❧ 2025-04-18 18:27:39 -04:00
parent 6e865b733d
commit 95b6e3f1bf
Signed by: tablet
GPG Key ID: 924A5F6AF051E87C
2 changed files with 81 additions and 102 deletions

View File

@ -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
View File

@ -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
} }