コード例 #1
0
ファイル: driver.go プロジェクト: rainycape/gondola
func (d *Driver) makeTable(m driver.Model) (*Table, error) {
	fields := m.Fields()
	names := fields.MNames
	qnames := fields.QNames
	ftypes := fields.Types
	tags := fields.Tags
	dbFields := make([]*Field, len(names))
	for ii, v := range names {
		typ := ftypes[ii]
		tag := tags[ii]
		ft, err := d.backend.FieldType(typ, tag)
		if err != nil {
			return nil, err
		}
		def := tag.Value("default")
		if fields.HasDefault(ii) {
			// Handled by the ORM
			def = ""
		}
		if def != "" {
			if driver.IsFunc(def) {
				fname, _ := driver.SplitFuncArgs(def)
				fn, err := d.backend.Func(fname, ftypes[ii])
				if err != nil {
					if err == ErrFuncNotSupported {
						err = fmt.Errorf("backend %s does not support function %s", d.backend.Name(), tag.Value("default"))
					}
					return nil, err
				}
				def = fn
			} else {
				def = driver.UnescapeDefault(def)
				if typ.Kind() == reflect.String {
					def = d.db.QuoteString(def)
				}
			}
		}
		field := &Field{
			Name:    v,
			Type:    ft,
			Default: def,
		}
		if tag.Has("notnull") {
			field.AddConstraint(ConstraintNotNull)
		}
		if d.isPrimaryKey(fields, ii, tag) {
			field.AddConstraint(ConstraintPrimaryKey)
		} else if tag.Has("unique") {
			field.AddConstraint(ConstraintUnique)
		}
		if tag.Has("auto_increment") {
			field.AddOption(OptionAutoIncrement)
		}
		if ref := fields.References[qnames[ii]]; ref != nil {
			fk, _, err := ref.Model.Fields().Map(ref.Field)
			if err != nil {
				return nil, err
			}
			field.Constraints = append(field.Constraints, &Constraint{
				Type:       ConstraintForeignKey,
				References: MakeReference(ref.Model.Table(), fk),
			})
		}
		dbFields[ii] = field
	}
	return &Table{Fields: dbFields}, nil
}
コード例 #2
0
ファイル: registry.go プロジェクト: rainycape/gondola
func (o *Orm) setFieldsDefaults(f *driver.Fields) error {
	defaults := make(map[int]reflect.Value)
	for ii, v := range f.Tags {
		def := v.Value("default")
		if def == "" {
			continue
		}
		if driver.IsFunc(def) {
			// Currently we only support two hardcoded functions, now() and today()
			fname, _ := driver.SplitFuncArgs(def)
			fn, ok := ormFuncs[fname]
			if !ok {
				return fmt.Errorf("unknown orm function %s()", fname)
			}
			retType := fn.Type().Out(0)
			if retType != f.Types[ii] {
				return fmt.Errorf("type mismatch: orm function %s() returns %s, but field %s in %s is of type %s", fname, retType, f.QNames[ii], f.Type, f.Types[ii])
			}
			if o.driver.Capabilities()&driver.CAP_DEFAULTS == 0 || !o.driver.HasFunc(fname, retType) {
				defaults[ii] = fn
			}
		} else {
			// Raw value, only to be stored in defaults if the driver
			// does not support CAP_DEFAULTS or it's a TEXT value and
			// the driver lacks CAP_DEFAULTS_TEXT
			caps := o.driver.Capabilities()
			if caps&driver.CAP_DEFAULTS != 0 && (caps&driver.CAP_DEFAULTS_TEXT != 0 || !isText(f, ii)) {
				continue
			}
			// Try to parse it
			ftyp := f.Types[ii]
			indirs := 0
			for ftyp.Kind() == reflect.Ptr {
				indirs++
				ftyp = ftyp.Elem()
			}
			val := reflect.New(ftyp)
			if err := input.Parse(def, val.Interface()); err != nil {
				return fmt.Errorf("invalid default value %q for field %s of type %s in %s: %s", def, f.QNames[ii], f.Types[ii], f.Type, err)
			}
			if indirs == 0 {
				defaults[ii] = val.Elem()
			} else {
				// Pointer, need to allocate a new value each time
				typ := f.Types[ii].Elem()
				defVal := val.Elem()
				f := func() reflect.Value {
					v := reflect.New(typ).Elem()
					for v.Kind() == reflect.Ptr {
						v.Set(reflect.New(v.Type().Elem()))
						v = v.Elem()
					}
					v.Set(defVal)
					return v
				}
				defaults[ii] = reflect.ValueOf(f)
			}
		}
	}
	if len(defaults) > 0 {
		f.Defaults = defaults
	}
	return nil
}