You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
2.9 KiB
139 lines
2.9 KiB
package rel
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
Now NowFunc = func() time.Time {
|
|
return time.Now().Truncate(time.Second)
|
|
}
|
|
)
|
|
|
|
// NowFunc is the type of function that returns the current time.
|
|
type NowFunc func() time.Time
|
|
|
|
// Structset can be used as mutation for repository insert or update operation.
|
|
// This will save every field in struct and it's association as long as it's loaded.
|
|
// This is the default mutator used by repository.
|
|
type Structset struct {
|
|
doc *Document
|
|
skipZero bool
|
|
}
|
|
|
|
// Apply mutation.
|
|
func (s Structset) Apply(doc *Document, mut *Mutation) {
|
|
var (
|
|
pFields = s.doc.PrimaryFields()
|
|
t = Now()
|
|
)
|
|
|
|
for _, field := range s.doc.Fields() {
|
|
switch field {
|
|
case "created_at", "inserted_at":
|
|
if doc.Flag(HasCreatedAt) {
|
|
if value, ok := doc.Value(field); ok && value.(time.Time).IsZero() {
|
|
s.set(doc, mut, field, t, true)
|
|
continue
|
|
}
|
|
}
|
|
case "updated_at":
|
|
if doc.Flag(HasUpdatedAt) {
|
|
s.set(doc, mut, field, t, true)
|
|
continue
|
|
}
|
|
}
|
|
|
|
if len(pFields) == 1 && pFields[0] == field {
|
|
// allow setting primary key as long as it's not zero.
|
|
s.applyValue(doc, mut, field, true)
|
|
} else {
|
|
s.applyValue(doc, mut, field, s.skipZero)
|
|
}
|
|
}
|
|
|
|
if mut.Cascade {
|
|
s.applyAssoc(mut)
|
|
}
|
|
}
|
|
|
|
func (s Structset) set(doc *Document, mut *Mutation, field string, value interface{}, force bool) {
|
|
if (force || doc.v != s.doc.v) && !doc.SetValue(field, value) {
|
|
panic(fmt.Sprint("rel: cannot assign ", value, " as ", field, " into ", doc.Table()))
|
|
}
|
|
|
|
mut.Add(Set(field, value))
|
|
}
|
|
|
|
func (s Structset) applyValue(doc *Document, mut *Mutation, field string, skipZero bool) {
|
|
if value, ok := s.doc.Value(field); ok {
|
|
if skipZero && isZero(value) {
|
|
return
|
|
}
|
|
|
|
s.set(doc, mut, field, value, false)
|
|
}
|
|
}
|
|
|
|
func (s Structset) applyAssoc(mut *Mutation) {
|
|
for _, field := range s.doc.BelongsTo() {
|
|
s.buildAssoc(field, mut)
|
|
}
|
|
|
|
for _, field := range s.doc.HasOne() {
|
|
s.buildAssoc(field, mut)
|
|
}
|
|
|
|
for _, field := range s.doc.HasMany() {
|
|
s.buildAssocMany(field, mut)
|
|
}
|
|
}
|
|
|
|
func (s Structset) buildAssoc(field string, mut *Mutation) {
|
|
assoc := s.doc.Association(field)
|
|
if assoc.IsZero() {
|
|
return
|
|
}
|
|
|
|
var (
|
|
doc, _ = assoc.Document()
|
|
)
|
|
|
|
mut.SetAssoc(field, Apply(doc, newStructset(doc, s.skipZero)))
|
|
}
|
|
|
|
func (s Structset) buildAssocMany(field string, mut *Mutation) {
|
|
assoc := s.doc.Association(field)
|
|
if assoc.IsZero() {
|
|
return
|
|
}
|
|
|
|
var (
|
|
col, _ = assoc.Collection()
|
|
muts = make([]Mutation, col.Len())
|
|
)
|
|
|
|
for i := range muts {
|
|
var (
|
|
doc = col.Get(i)
|
|
)
|
|
|
|
muts[i] = Apply(doc, newStructset(doc, s.skipZero))
|
|
}
|
|
|
|
mut.SetAssoc(field, muts...)
|
|
}
|
|
|
|
func newStructset(doc *Document, skipZero bool) Structset {
|
|
return Structset{
|
|
doc: doc,
|
|
skipZero: skipZero,
|
|
}
|
|
}
|
|
|
|
// NewStructset from a struct.
|
|
func NewStructset(record interface{}, skipZero bool) Structset {
|
|
return newStructset(NewDocument(record), skipZero)
|
|
}
|