Skip to content

Commit

Permalink
Merge pull request #89 from jiangz222/daily
Browse files Browse the repository at this point in the history
upsert support fileds
  • Loading branch information
jiangz222 authored Sep 19, 2020
2 parents 6f2cb7c + b5cff5e commit 32b96fd
Show file tree
Hide file tree
Showing 11 changed files with 515 additions and 118 deletions.
37 changes: 0 additions & 37 deletions .github/workflows/go.yml

This file was deleted.

24 changes: 21 additions & 3 deletions collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,31 @@ func interfaceToSliceInterface(docs interface{}) []interface{} {
}

// Upsert updates one documents if filter match, inserts one document if filter is not match
// The replacement parameter must be a document that will be used to replace the selected document. It cannot be nil
// and cannot contain any update operators
// Reference: https://docs.mongodb.com/manual/reference/operator/update/
func (c *Collection) Upsert(ctx context.Context, filter interface{}, replacement interface{}) (result *UpdateResult, err error) {
opts := options.Replace().SetUpsert(true)
res, err := c.collection.ReplaceOne(ctx, filter, replacement, opts)
func (c *Collection) Upsert(ctx context.Context, filter interface{}, replacement interface{}, opts ...opts.UpsertOptions) (result *UpdateResult, err error) {
h := replacement
if len(opts) > 0 && opts[0].UpsertHook != nil {
h = opts[0].UpsertHook
}
if err = hook.Do(h, hook.BeforeUpsert); err != nil {
return
}
if err = field.Do(replacement, field.BeforeUpsert); err != nil {
return
}
officialOpts := options.Replace().SetUpsert(true)
res, err := c.collection.ReplaceOne(ctx, filter, replacement, officialOpts)
if res != nil {
result = translateUpdateResult(res)
}
if err != nil {
return
}
if err = hook.Do(h, hook.AfterUpsert); err != nil {
return
}
return
}

Expand Down
27 changes: 20 additions & 7 deletions field/custom_field.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func (c CustomFields) CustomCreateTime(doc interface{}) {
return
}
fieldName := c.createAt
setTime(doc, fieldName)
setTime(doc, fieldName, false)
return
}

Expand All @@ -65,7 +65,7 @@ func (c CustomFields) CustomUpdateTime(doc interface{}) {
return
}
fieldName := c.updateAt
setTime(doc, fieldName)
setTime(doc, fieldName, true)
return
}

Expand All @@ -80,7 +80,8 @@ func (c CustomFields) CustomId(doc interface{}) {
}

// setTime changes the custom time fields
func setTime(doc interface{}, fieldName string) {
// The overWrite defines if change value when the filed has valid value
func setTime(doc interface{}, fieldName string, overWrite bool) {
if reflect.Ptr != reflect.TypeOf(doc).Kind() {
fmt.Println("not a point type")
return
Expand All @@ -91,9 +92,17 @@ func setTime(doc interface{}, fieldName string) {
tt := time.Now()
switch a := ca.Interface().(type) {
case time.Time:
ca.Set(reflect.ValueOf(tt))
if reflect.DeepEqual(ca.Interface().(time.Time), nilTime) {
ca.Set(reflect.ValueOf(tt))
} else if overWrite {
ca.Set(reflect.ValueOf(tt))
}
case int64:
ca.SetInt(tt.Unix())
if ca.Interface().(int64) == 0 {
ca.SetInt(tt.Unix())
} else if overWrite {
ca.SetInt(tt.Unix())
}
default:
fmt.Println("unsupported type to setTime", a)
}
Expand All @@ -111,9 +120,13 @@ func setId(doc interface{}, fieldName string) {
if ca.CanSet() {
switch a := ca.Interface().(type) {
case primitive.ObjectID:
ca.Set(reflect.ValueOf(primitive.NewObjectID()))
if ca.Interface().(primitive.ObjectID).IsZero() {
ca.Set(reflect.ValueOf(primitive.NewObjectID()))
}
case string:
ca.SetString(primitive.NewObjectID().String())
if ca.String() == "" {
ca.SetString(primitive.NewObjectID().String())
}
default:
fmt.Println("unsupported type to setId", a)
}
Expand Down
9 changes: 7 additions & 2 deletions field/default_field.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package field

import (
"go.mongodb.org/mongo-driver/bson/primitive"
"reflect"
"time"
)

Expand All @@ -27,10 +28,14 @@ func (df *DefaultField) DefaultUpdateAt() {

// DefaultCreateAt changes the default createAt field
func (df *DefaultField) DefaultCreateAt() {
df.CreateAt = time.Now().Local()
if reflect.DeepEqual(df.CreateAt, nilTime) {
df.CreateAt = time.Now().Local()
}
}

// DefaultCreateAt changes the default _id field
func (df *DefaultField) DefaultId() {
df.Id = primitive.NewObjectID()
if df.Id.IsZero() {
df.Id = primitive.NewObjectID()
}
}
44 changes: 37 additions & 7 deletions field/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,32 @@ package field

import (
"reflect"
"time"
)

var nilTime time.Time

type FieldType string

const (
BeforeInsert FieldType = "beforeInsert"
BeforeUpdate FieldType = "beforeUpdate"
BeforeUpsert FieldType = "beforeUpsert"
)

// filedHandler defines the relations between field type and handler
var fieldHandler = map[FieldType]func(doc interface{}) error{
BeforeInsert: beforeInsert,
BeforeUpdate: beforeUpdate,
BeforeUpsert: beforeUpsert,
}

// Do call the specific method to handle field based on fType
func Do(doc interface{}, fType FieldType) error {
to := reflect.TypeOf(doc)
if to == nil {
return nil
}
switch reflect.TypeOf(doc).Kind() {
case reflect.Slice:
return sliceHandle(doc, fType)
Expand Down Expand Up @@ -57,30 +66,51 @@ func sliceHandle(docs interface{}, fType FieldType) error {
}

// beforeInsert handles field before insert
// If value of field createAt is valid in doc, upsert doesn't change it
// If value of field id is valid in doc, upsert doesn't change it
// Change the value of field updateAt anyway
func beforeInsert(doc interface{}) error {
if ih, ok := doc.(DefaultFieldHook); ok {
ih.DefaultId()
ih.DefaultCreateAt()
ih.DefaultUpdateAt()
ih.DefaultId()
}
if ih, ok := doc.(CustomFieldsHook); ok {
fields := ih.CustomFields()
fields.(*CustomFields).CustomId(doc)
fields.(*CustomFields).CustomCreateTime(doc)
fields.(*CustomFields).CustomUpdateTime(doc)
fields.(*CustomFields).CustomId(doc)
}

return nil
}

// beforeUpdate handles field before update
func beforeUpdate(hook interface{}) error {
if ih, ok := hook.(DefaultFieldHook); ok {
func beforeUpdate(doc interface{}) error {
if ih, ok := doc.(DefaultFieldHook); ok {
ih.DefaultUpdateAt()
}
if ih, ok := hook.(CustomFieldsHook); ok {
if ih, ok := doc.(CustomFieldsHook); ok {
fields := ih.CustomFields()
fields.(*CustomFields).CustomUpdateTime(hook)
fields.(*CustomFields).CustomUpdateTime(doc)
}
return nil
}

// beforeUpsert handles field before upsert
// If value of field createAt is valid in doc, upsert doesn't change it
// If value of field id is valid in doc, upsert doesn't change it
// Change the value of field updateAt anyway
func beforeUpsert(doc interface{}) error {
if ih, ok := doc.(DefaultFieldHook); ok {
ih.DefaultId()
ih.DefaultCreateAt()
ih.DefaultUpdateAt()
}
if ih, ok := doc.(CustomFieldsHook); ok {
fields := ih.CustomFields()
fields.(*CustomFields).CustomId(doc)
fields.(*CustomFields).CustomCreateTime(doc)
fields.(*CustomFields).CustomUpdateTime(doc)
}
return nil
}
Loading

0 comments on commit 32b96fd

Please sign in to comment.