improve Save api

add a `SaveWith` function that accepts `SaveOptions` as a parameter, letting you tweak things like whether timestamps will be set before an insert or update operation
This commit is contained in:
☙◦ The Tablet ❀ GamerGirlandCo ◦❧ 2025-03-27 00:12:19 -04:00
parent bb37212be7
commit 11d31fbbc1
Signed by: tablet
GPG Key ID: 924A5F6AF051E87C
3 changed files with 31 additions and 11 deletions

View File

@ -21,6 +21,7 @@ type IDocument interface {
Delete() error Delete() error
Remove() error Remove() error
Save() error Save() error
SaveWith(opts *SaveOptions) error
setSelf(arg interface{}) setSelf(arg interface{})
getExists() bool getExists() bool
setExists(n bool) setExists(n bool)
@ -33,6 +34,10 @@ type IDocument interface {
setModel(m Model) setModel(m Model)
} }
type SaveOptions struct {
SetTimestamps bool
}
func (d *Document) getCreated() time.Time { func (d *Document) getCreated() time.Time {
return d.Created return d.Created
} }
@ -89,25 +94,33 @@ func (d *Document) Remove() error {
return d.Delete() return d.Delete()
} }
// Save - updates this Model in the database, // SaveWith - updates this Model in the database,
// or inserts it if it doesn't exist // or inserts it if it doesn't exist, using the provided
func (d *Document) Save() error { // SaveOptions
func (d *Document) SaveWith(opts *SaveOptions) error {
val := valueOf(d.self) val := valueOf(d.self)
if val.Kind() == reflect.Slice { if val.Kind() == reflect.Slice {
for i := 0; i < val.Len(); i++ { for i := 0; i < val.Len(); i++ {
cur := val.Index(i) cur := val.Index(i)
asHId := asId(cur.Interface()) if err := doSave(d.model.getColl(), !d.exists, opts, cur.Interface()); err != nil {
if err := doSave(d.model.getColl(), !d.exists && reflect.ValueOf(asHId.Id()).IsZero(), cur.Interface()); err != nil {
return err return err
} }
} }
return nil return nil
} else { } else {
asHId := asId(val.Interface()) return doSave(d.model.getColl(), !d.exists, opts, d.self)
return doSave(d.model.getColl(), !d.exists && reflect.ValueOf(asHId.Id()).IsZero(), d.self)
} }
} }
// Save - updates this Model in the database,
// or inserts it if it doesn't exist, using
// default SaveOptions
func (d *Document) Save() error {
return d.SaveWith(&SaveOptions{
SetTimestamps: true,
})
}
func (d *Document) serializeToStore() any { func (d *Document) serializeToStore() any {
return serializeIDs((d).self) return serializeIDs((d).self)
} }

View File

@ -102,7 +102,7 @@ func serializeIDs(input interface{}) interface{} {
} }
return ret return ret
} }
func doSave(c *mongo.Collection, isNew bool, arg interface{}) error { func doSave(c *mongo.Collection, isNew bool, opts *SaveOptions, arg interface{}) error {
var err error var err error
d, ok := arg.(IDocument) d, ok := arg.(IDocument)
if !ok { if !ok {
@ -118,10 +118,12 @@ func doSave(c *mongo.Collection, isNew bool, arg interface{}) error {
} }
var asHasId = vp.Interface().(HasID) var asHasId = vp.Interface().(HasID)
var asModel = vp.Interface().(IDocument) var asModel = vp.Interface().(IDocument)
if isNew { if isNew && opts.SetTimestamps {
d.setCreated(now) d.setCreated(now)
} }
if opts.SetTimestamps {
d.setModified(now) d.setModified(now)
}
idxs := d.getModel().getIdxs() idxs := d.getModel().getIdxs()
for _, i := range idxs { for _, i := range idxs {
_, err = c.Indexes().CreateOne(context.TODO(), *i) _, err = c.Indexes().CreateOne(context.TODO(), *i)

View File

@ -45,7 +45,12 @@ func asId(i interface{}) HasID {
var ok bool var ok bool
switch v.Kind() { switch v.Kind() {
case reflect.Struct: case reflect.Struct:
v = reflect.New(reflect.PointerTo(v.Type())) asHasId, ok = v.Interface().(HasID)
if ok {
return asHasId
}
v = reflect.New(v.Type())
v.Elem().Set(reflect.ValueOf(i))
fallthrough fallthrough
case reflect.Pointer: case reflect.Pointer:
asHasId, ok = v.Interface().(HasID) asHasId, ok = v.Interface().(HasID)