diamond-orm/document.go

224 lines
4.7 KiB
Go
Raw Normal View History

package orm
import (
"reflect"
"time"
)
type Document struct {
// Created time. updated/added automatically.
Created time.Time `bson:"createdAt" json:"createdAt"`
// Modified time. updated/added automatically.
Modified time.Time `bson:"updatedAt" json:"updatedAt"`
model *Model
exists bool `bson:"-"`
self any `bson:"-"`
}
type IDocument interface {
Append(field string, a ...interface{}) error
Pull(field string, a ...any) error
Swap(field string, i, j int) error
Delete() error
Remove() error
Save() error
setSelf(arg interface{})
getExists() bool
setExists(n bool)
setModified(Modified time.Time)
setCreated(Modified time.Time)
getModified() time.Time
getCreated() time.Time
serializeToStore() any
getModel() *Model
setModel(m Model)
}
func (d *Document) getCreated() time.Time {
return d.Created
}
func (d *Document) setCreated(Created time.Time) {
d.Created = Created
}
func (d *Document) getModified() time.Time {
return d.Modified
}
func (d *Document) setModified(Modified time.Time) {
d.Modified = Modified
}
func (d *Document) setSelf(arg interface{}) {
d.self = arg
}
func (d *Document) getModel() *Model {
return d.model
}
func (d *Document) setModel(m Model) {
d.model = &m
}
func (d *Document) getExists() bool {
return d.exists
}
func (d *Document) setExists(n bool) {
d.exists = n
}
// Delete - deletes a model instance from the database
func (d *Document) Delete() error {
var err error
val := valueOf(d.self)
if val.Kind() == reflect.Slice {
for i := 0; i < val.Len(); i++ {
cur := val.Index(i)
if err = doDelete(d, cur.Interface()); err != nil {
return err
}
}
return nil
} else {
return doDelete(d, d.self)
}
}
// Remove - alias for Delete
func (d *Document) Remove() error {
return d.Delete()
}
// Save - updates this Model in the database,
// or inserts it if it doesn't exist
func (d *Document) Save() error {
val := valueOf(d.self)
if val.Kind() == reflect.Slice {
for i := 0; i < val.Len(); i++ {
cur := val.Index(i)
if err := doSave(d.model.getColl(), !d.exists, cur.Interface()); err != nil {
return err
}
}
return nil
} else {
return doSave(d.model.getColl(), !d.exists, d.self)
}
}
func (d *Document) serializeToStore() any {
return serializeIDs((d).self)
}
// Append appends one or more items to `field`.
// will error if this Model contains a reference
// to multiple documents, or if `field` is not a
// slice.
func (d *Document) Append(field string, a ...interface{}) error {
var d0 IDocument = d
d0.getCreated()
rv := reflect.ValueOf(d.self)
selfRef := rv
rt := reflect.TypeOf(d.self)
if selfRef.Kind() == reflect.Pointer {
selfRef = selfRef.Elem()
rt = rt.Elem()
}
if err := checkStruct(selfRef); err != nil {
return err
}
_, origV, err := getNested(field, selfRef)
if err != nil {
return err
}
origRef := makeSettable(*origV, (*origV).Interface())
fv := origRef
if fv.Kind() == reflect.Pointer {
fv = fv.Elem()
}
if fv.Kind() != reflect.Slice {
return ErrNotASlice
}
for _, b := range a {
val := reflect.ValueOf(incrementTagged(b))
fv.Set(reflect.Append(fv, val))
}
return nil
}
// Pull - removes elements from the subdocument slice stored in `field`.
func (d *Document) Pull(field string, a ...any) error {
rv := reflect.ValueOf(d.self)
selfRef := rv
rt := reflect.TypeOf(d.self)
if selfRef.Kind() == reflect.Pointer {
selfRef = selfRef.Elem()
rt = rt.Elem()
}
if err := checkStruct(selfRef); err != nil {
return err
}
_, origV, err := getNested(field, selfRef)
if err != nil {
return err
}
origRef := makeSettable(*origV, (*origV).Interface())
fv := origRef
if fv.Kind() == reflect.Pointer {
fv = fv.Elem()
}
if fv.Kind() != reflect.Slice {
return ErrNotASlice
}
outer:
for _, b := range a {
for i := 0; i < fv.Len(); i++ {
if reflect.DeepEqual(b, fv.Index(i).Interface()) {
fv.Set(pull(fv, i, fv.Index(i).Type()))
break outer
}
}
}
return nil
}
// Swap - swaps the elements at indexes `i` and `j` in the
// slice stored at `field`
func (d *Document) Swap(field string, i, j int) error {
rv := reflect.ValueOf(d.self)
selfRef := rv
rt := reflect.TypeOf(d.self)
if selfRef.Kind() == reflect.Pointer {
selfRef = selfRef.Elem()
rt = rt.Elem()
}
if err := checkStruct(selfRef); err != nil {
return err
}
_, origV, err := getNested(field, selfRef)
if err != nil {
return err
}
origRef := makeSettable(*origV, (*origV).Interface())
fv := origRef
if fv.Kind() == reflect.Pointer {
fv = fv.Elem()
}
if err = checkSlice(fv); err != nil {
return err
}
if i >= fv.Len() || j >= fv.Len() {
return ErrOutOfBounds
}
oi := fv.Index(i).Interface()
oj := fv.Index(j).Interface()
fv.Index(i).Set(reflect.ValueOf(oj))
fv.Index(j).Set(reflect.ValueOf(oi))
return nil
}