func (s *scanner) codecAndPipe() (*codec.Codec, *pipe.Pipe) { if c := codec.FromTag(s.Tag); c != nil { return c, pipe.FromTag(s.Tag) } return nil, 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 }
func (o *Orm) fields(table string, s *structs.Struct) (*driver.Fields, map[string]*reference, error) { methods, err := driver.MakeMethods(s.Type) if err != nil { return nil, nil, err } fields := &driver.Fields{ Struct: s, PrimaryKey: -1, Methods: methods, } var references map[string]*reference for ii, v := range s.QNames { // XXX: Check if this quoting is enough fields.QuotedNames = append(fields.QuotedNames, fmt.Sprintf("\"%s\".\"%s\"", table, s.MNames[ii])) t := s.Types[ii] ftag := s.Tags[ii] // Check encoded types if cn := ftag.CodecName(); cn != "" { if codec.Get(cn) == nil { if imp := codec.RequiredImport(cn); imp != "" { return nil, nil, fmt.Errorf("please import %q to use the codec %q", imp, cn) } return nil, nil, fmt.Errorf("can't find codec %q. Perhaps you missed an import?", cn) } } else { switch t.Kind() { case reflect.Array, reflect.Chan, reflect.Func, reflect.Interface, reflect.Map: return nil, nil, fmt.Errorf("field %q in struct %s has invalid type %s", v, s.Type, t) } } if pn := ftag.PipeName(); pn != "" { // Check if the field has a codec and the pipe exists if ftag.CodecName() == "" { return nil, nil, fmt.Errorf("field %q has pipe %s but no codec - only encoded types can use pipes", v, pn) } if pipe.FromTag(ftag) == nil { return nil, nil, fmt.Errorf("can't find ORM pipe %q. Perhaps you missed an import?", pn) } } // Struct has flattened types, but we need to original type // to determine if it should be nullempty or omitempty by default field := s.Type.FieldByIndex(s.Indexes[ii]) fields.OmitEmpty = append(fields.OmitEmpty, ftag.Has("omitempty") || (defaultsToOmitEmpty(field.Type, ftag) && !ftag.Has("notomitempty"))) fields.NullEmpty = append(fields.NullEmpty, ftag.Has("nullempty") || (defaultsToNullEmpty(field.Type, ftag) && !ftag.Has("notnullempty"))) if ftag.Has("primary_key") { if fields.PrimaryKey >= 0 { return nil, nil, fmt.Errorf("duplicate primary_key in struct %v (%s and %s)", s.Type, s.QNames[fields.PrimaryKey], v) } fields.PrimaryKey = ii } if ftag.Has("auto_increment") { if k := types.Kind(t.Kind()); k != types.Int && k != types.Uint { return nil, nil, fmt.Errorf("auto_increment field %q in struct %s must be of integer type (signed or unsigned", v, s.Type) } fields.AutoincrementPk = fields.PrimaryKey == ii } if ref := ftag.Value("references"); ref != "" { m := referencesRe.FindStringSubmatch(ref) if len(m) != 4 { return nil, nil, fmt.Errorf("field %q has invalid references %q. Must be in the form references=Model or references=Model(Field)", v, ref) } if references == nil { references = make(map[string]*reference) } references[v] = &reference{model: m[1], field: m[3]} } } if err := o.setFieldsDefaults(fields); err != nil { return nil, nil, err } return fields, references, nil }