func (o *Orm) save(m *model, obj interface{}) (Result, error) { if profile.On && profile.Profiling() { defer profile.Start(orm).Note("save", m.name).End() } var res Result var err error if m.fields.PrimaryKey >= 0 { pkName, pkVal := o.primaryKey(m.fields, obj) if driver.IsZero(pkVal) { return o.insert(m, obj) } res, err = o.update(m, Eq(pkName, pkVal.Interface()), obj) } else if len(m.fields.CompositePrimaryKey) > 0 { // Composite primary key names, values := o.compositePrimaryKey(m.fields, obj) for _, v := range values { if !driver.IsZero(v) { // We have a non-zero value, try to update qs := make([]query.Q, len(names)) for ii := range names { qs[ii] = Eq(names[ii], values[ii].Interface()) } res, err = o.update(m, And(qs...), obj) break } } if res == nil && err == nil { // Not updated. All the fields in the PK are zero return o.insert(m, obj) } } else { // No pk return o.insert(m, obj) } if err != nil { return nil, err } up, err := res.RowsAffected() if err != nil { return nil, err } if up == 0 { return o.insert(m, obj) } return res, nil }
func (d *Driver) saveParameters(m driver.Model, data interface{}) (reflect.Value, []string, []interface{}, error) { // data is guaranteed to be of m.Type() val := driver.Direct(reflect.ValueOf(data)) fields := m.Fields() max := len(fields.MNames) names := make([]string, 0, max) values := make([]interface{}, 0, max) var err error if d.transforms != nil { for ii, v := range fields.Indexes { f := d.fieldByIndex(val, v, false) if !f.IsValid() { continue } if fields.OmitEmpty[ii] && driver.IsZero(f) { continue } ft := f.Type() var fval interface{} if _, ok := d.transforms[ft]; ok { fval, err = d.backend.TransformOutValue(f) if err != nil { return val, nil, nil, err } if fields.NullEmpty[ii] && driver.IsZero(reflect.ValueOf(fval)) { fval = nil } } else if !fields.NullEmpty[ii] || !driver.IsZero(f) { if c := codec.FromTag(fields.Tags[ii]); c != nil { fval, err = c.Encode(f.Interface()) if err != nil { return val, nil, nil, err } if p := pipe.FromTag(fields.Tags[ii]); p != nil { data, err := p.Encode(fval.([]byte)) if err != nil { return val, nil, nil, err } fval = data } } else { // Most sql drivers won't accept aliases for string type if ft.Kind() == reflect.String && ft != stringType { f = f.Convert(stringType) } fval = f.Interface() } } names = append(names, fields.MNames[ii]) values = append(values, fval) } } else { for ii, v := range fields.Indexes { f := d.fieldByIndex(val, v, false) if !f.IsValid() { continue } if fields.OmitEmpty[ii] && driver.IsZero(f) { continue } var fval interface{} if !fields.NullEmpty[ii] || !driver.IsZero(f) { if c := codec.FromTag(fields.Tags[ii]); c != nil { fval, err = c.Encode(&f) if err != nil { return val, nil, nil, err } } else { ft := f.Type() // Most sql drivers won't accept aliases for string type if ft.Kind() == reflect.String && ft != stringType { f = f.Convert(stringType) } fval = f.Interface() } } names = append(names, fields.MNames[ii]) values = append(values, fval) } } return val, names, values, nil }