Example #1
0
// InputNamed takes a (generally) user-provided input string and parses it into the out
// parameter, which must be settable (this usually means you'll have to pass a pointer
// to this function). See the documentation on Parse() for a list of the supported types.
// If name is provided, it will be included in any error returned by this function.
// Additional constraints might be specified with the tag parameter, the ones currently
// supported are:
//  - required: Marks the field as required, will return an error if it's empty.
//  - optional: Marks the field as optional, will accept empty values.
//  - max_length: Sets the maximum length for the input.
//  - min_length: Sets the minimum length for the input.
//  - alphanumeric: Requires the input to be only letters and numbers
//
// Finally, the required parameter indicates if the value should be considered required
// or optional in absence of the "required" and "optional" tag fields.
func InputNamed(name string, input string, out interface{}, tag *structs.Tag, required bool) error {
	v, err := types.SettableValue(out)
	if err != nil {
		return err
	}
	if err := parse(input, v); err != nil {
		return err
	}
	if v.Type().Kind() != reflect.Bool && tag != nil {
		if ((required && !tag.Optional()) || tag.Required()) && input == "" {
			return RequiredInputError(name)
		}
		if maxlen, ok := tag.MaxLength(); ok && len(input) > maxlen {
			if name != "" {
				return i18n.Errorfc("form", "%s is too long (maximum length is %d)", name, maxlen)
			}
			return i18n.Errorfc("form", "too long (maximum length is %d)", maxlen)
		}
		if minlen, ok := tag.MinLength(); ok && len(input) < minlen {
			if name != "" {
				return i18n.Errorfc("form", "%s is too short (minimum length is %d)", name, minlen)
			}
			return i18n.Errorfc("form", "too short (minimum length is %d)", minlen)
		}
		if tag.Alphanumeric() && len(input) > 0 && !alphanumericRe.MatchString(input) {
			if name != "" {
				return i18n.Errorfc("form", "%s must be alphanumeric", name)
			}
			return i18n.Errorfc("form", "must be alphanumeric")
		}
	}
	return nil
}
Example #2
0
func (b *Backend) FieldType(typ reflect.Type, t *structs.Tag) (string, error) {
	if c := codec.FromTag(t); c != nil {
		if c.Binary || t.PipeName() != "" {
			return "BLOB", nil
		}
		return "TEXT", nil
	}
	var ft string
	switch typ.Kind() {
	case reflect.Bool:
		ft = "BOOL"
	case reflect.Int8:
		ft = "TINYINT"
	case reflect.Uint8:
		ft = "TINYINT UNSIGNED"
	case reflect.Int16:
		ft = "SMALLINT"
	case reflect.Uint16:
		ft = "SMALLINT UNSIGNED"
	case reflect.Int32:
		ft = "INT"
	case reflect.Uint32:
		ft = "INT UNSIGNED"
	case reflect.Int, reflect.Int64:
		ft = "BIGINT"
	case reflect.Uint, reflect.Uint64:
		ft = "BIGINT UNSIGNED"
	case reflect.Float32:
		ft = "FLOAT"
	case reflect.Float64:
		ft = "DOUBLE"
	case reflect.String:
		if ml, ok := t.MaxLength(); ok {
			ft = fmt.Sprintf("VARCHAR (%d)", ml)
		} else if fl, ok := t.Length(); ok {
			ft = fmt.Sprintf("CHAR (%d)", fl)
		} else {
			ft = "TEXT"
		}
	case reflect.Slice:
		etyp := typ.Elem()
		if etyp.Kind() == reflect.Uint8 {
			// []byte
			ft = "BLOB"
		}
	case reflect.Struct:
		if typ.Name() == "Time" && typ.PkgPath() == "time" {
			ft = "DATETIME"
		}
	}
	if ft != "" {
		return ft, nil
	}
	return "", fmt.Errorf("can't map field type %v to a database type", typ)
}
Example #3
0
func (b *Backend) FieldType(typ reflect.Type, t *structs.Tag) (string, error) {
	if c := codec.FromTag(t); c != nil {
		// TODO: Use type JSON on Postgresql >= 9.2 for JSON encoded fields
		if c.Binary || t.PipeName() != "" {
			return "BYTEA", nil
		}
		return "TEXT", nil
	}
	var ft string
	switch typ.Kind() {
	case reflect.Bool:
		ft = "BOOL"
	case reflect.Int8, reflect.Uint8, reflect.Int16:
		ft = "INT2"
	case reflect.Uint16, reflect.Int32:
		ft = "INT4"
	case reflect.Int, reflect.Uint, reflect.Uint32, reflect.Int64, reflect.Uint64:
		ft = "INT8"
	case reflect.Float32:
		ft = "FLOAT4"
	case reflect.Float64:
		ft = "FLOAT8"
	case reflect.String:
		if t.Has("macaddr") {
			ft = "MACADDR"
		} else if t.Has("inet") {
			ft = "INET"
		} else {
			if ml, ok := t.MaxLength(); ok {
				ft = fmt.Sprintf("VARCHAR (%d)", ml)
			} else if fl, ok := t.Length(); ok {
				ft = fmt.Sprintf("CHAR (%d)", fl)
			} else {
				ft = "TEXT"
			}
		}
	case reflect.Slice:
		etyp := typ.Elem()
		if etyp.Kind() == reflect.Uint8 {
			// []byte
			ft = "BYTEA"
			// TODO: database/sql does not support array types. Enable this code
			// if that changes in the future
			//		} else if typ.Elem().Kind() != reflect.Struct {
			//			et, err := b.FieldType(typ.Elem(), tag)
			//			if err != nil {
			//				return "", err
			//			}
			//			t = et + "[]"
		}
	case reflect.Struct:
		if typ.Name() == "Time" && typ.PkgPath() == "time" {
			ft = "TIMESTAMP WITHOUT TIME ZONE"
		}
	}
	if t.Has("auto_increment") {
		if strings.HasPrefix(ft, "INT") {
			ft = strings.Replace(ft, "INT", "SERIAL", -1)
		} else {
			return "", fmt.Errorf("postgres does not support auto incrementing %v", typ)
		}
	}
	if ft != "" {
		return ft, nil
	}
	return "", fmt.Errorf("can't map field type %v to a database type", typ)
}