Пример #1
0
func (ø *Row) SelectByStruct(structPtr interface{}, tagVal string, opts ...interface{}) error {
	str, err := meta.StructByValue(meta.FinalValue(structPtr))
	if err != nil {
		return err
	}
	tags, err2 := str.Tags()
	if err2 != nil {
		return err2
	}
	options := []interface{}{}
	order := []string{}

	for k, v := range tags {
		if t := v.Get("db.select"); t != "" && strings.Contains(t, tagVal) {
			fi := ø.queryField(k, opts...)
			if fi == nil {
				panic("can't find field " + k + " : no Queryfield property of given fields or aliases")
			}
			options = append(options, fi)
			order = append(order, k)
		}
	}

	options = append(options, opts...)
	row, err := ø.Any(options...)
	if err != nil {
		return err
	}
	err = row.GetStruct(tagVal, structPtr)
	if err != nil {
		return err
	}
	return nil
}
Пример #2
0
/*
  only the fields that are *fat.Field and not nil are chosen to be set
	from the row. fields that are not set in the row, are set to nil
*/
func (r *Registry) FromRow(row *Row, øptrToFatStruct interface{}) (err error) {
	fn := func(field *meta.Field) {
		if err != nil {
			return
		}

		if field.Value.IsNil() {
			return
		}

		ff, isFat := field.Value.Interface().(*fat.Field)

		if !isFat {
			return
		}

		dbField := r.FieldOf(ff)

		if row.Values()[dbField] != nil {
			fatField := field.Value.Interface().(*fat.Field)
			err = scanFieldToStruct(row, fatField, dbField)
			return
		}

		field.Value.Set(fatFieldNil)
		//		ff.Set(fatFieldNil)
		/*
			if dbField.Is(NullAllowed) {
				ff.Set(fatFieldNil)
			}
		*/
	}

	var stru *meta.Struct
	stru, err = meta.StructByValue(reflect.ValueOf(øptrToFatStruct))

	if err == nil {
		stru.Each(fn)
	}
	return
}
Пример #3
0
func setFieldInStruct(vl reflect.Value, fieldName string, tagVal string, v *TypedValue, s interface{}) error {

	str, err := meta.StructByValue(meta.FinalValue(s))

	if err != nil {
		return err
	}

	tag, err2 := str.Tag(fieldName)
	if err2 != nil {
		return err2
	}

	// tag does match the given
	if tag != nil && strings.Contains(tag.Get("db.select"), tagVal) {
		err := Convert(v, vl.Addr().Interface())
		if err != nil {
			return fmt.Errorf("error in field %s: %s", fieldName, err.Error())
		}
	}
	return nil
}
Пример #4
0
func (r *Registry) RegisterTable(name string, ptrToFatStru interface{}) (*Table, error) {
	val := reflect.ValueOf(ptrToFatStru)
	if val.Kind() != reflect.Ptr {
		return nil, fmt.Errorf("%T is no pointer to a struct", ptrToFatStru)
	}

	if val.Elem().Kind() != reflect.Struct {
		return nil, fmt.Errorf("%T is no pointer to a struct", ptrToFatStru)
	}

	valType := TypeString(ptrToFatStru)

	stru, err := mt.StructByValue(val)
	if err != nil {
		return nil, err
	}

	table := NewTable(name)

	fn := func(fld *mt.Field) {
		dbFlag := splitSpace(fld.Type.Tag.Get("db"))

		if len(dbFlag) < 1 {
			return
		}

		//fname := fld.Type.Tag.Get("db")
		fname := dbFlag[0] // fld.Type.Tag.Get("db")

		if fname == "-" {
			return
		}

		//if fname != "" && fname != "-" {
		ff := fld.Value.Interface().(*fat.Field)
		var typ Type
		ftype := findType(fld.Type.Tag.Get("type"))
		if ftype != "" {
			switch ftype {
			case "[string]string", "[string]int", "[string]time", "[string]float", "[string]bool":
				typ = JsonType
			case "int":
				typ = IntType
			case "text":
				typ = TextType
			case "bool":
				typ = BoolType
			case "date":
				typ = DateType
				/*	case "time":
					typ = TimeType */
			case "xml":
				typ = XmlType
			case "float":
				typ = FloatType
			case "[]float":
				typ = FloatsType
			case "timestamptz":
				typ = TimeStampTZType
			case "timestamp":
				typ = TimeStampType
			case "json":
				typ = JsonType
			case "[]int":
				typ = IntsType
			case "[]string":
				typ = StringsType
			case "[]bool":
				typ = BoolsType
			case "html":
				typ = HtmlType
			case "[]time":
				typ = TimeStampsTZType
			case "uuid":
				typ = UuidType
				/*
					case "ltree":
						typ = LtreeType
					case "trigger":
						typ = TriggerType
				*/
			default:
				if varcharReg.MatchString(fld.Type.Tag.Get("type")) {
					a := varcharReg.FindStringSubmatch(fld.Type.Tag.Get("type"))
					i, err := strconv.Atoi(a[1])
					if err != nil {
						panic(fmt.Sprintf("can't parse varchar value: %#v: %s of field %s", ftype, err.Error(), fld.Type.Name))
					}
					if i > 255 {
						panic(fmt.Sprintf("max number for varchar is 255, not %v in field %s", i, fld.Type.Name))
					}
					typ = VarChar(i)
				} else {
					panic(fmt.Sprintf("unknown type %#v of field %s", ftype, fld.Type.Name))
				}
			}
		} else {
			/*
				switch ff.Typ() {
				case "string":
					typ = VarChar(255)
				case "bool":
					typ = BoolType
				case "int":
					typ = IntType
				case "time":
					typ = TimeType
				case "[]string":
					typ = StringsType
				case "[]int":
					typ = IntsType
				default:
			*/
			panic(fmt.Sprintf("type: %#v has no corresponding pgsql.Type in field %s", ff.Typ(), fld.Type.Name))
			/*
				}
			*/
		}

		f := table.NewField(fname, typ)
		var isPkey bool
		//fflags := fld.Type.Tag.Get("pgsql.flags")
		//if fflags != "" {
		//	flgs := strings.Split(fflags, ",")
		if len(dbFlag) > 1 {

			//for _, fl := range flgs {
			for _, fl := range dbFlag[1:] {
				fl = strings.TrimSpace(fl)
				var fffl Flag
				switch fl {
				case "NULL":
					fffl = NullAllowed
				case "PKEY":
					isPkey = true
					fffl = PrimaryKey
				case "SERIAL":
					fffl = Serial
				case "UUIDGEN":
					fffl = UuidGenerate
				case "DELETE_CASCADE":
					fffl = OnDeleteCascade
				default:
					panic(fmt.Sprintf("unsupported flag: %#v in field %s", fl, fld.Type.Name))
				}
				f.Add(fffl)
			}
		}
		//}
		/*
			if ff.Default() != nil {
				f.Default = Sql(ff.Default().String())
			}
		*/
		if isPkey {
			table.PrimaryKey = append(table.PrimaryKey, f)
		}

		//fmt.Printf("adding field %#v, %#v, %s, %s\n", val.Type().String(), val.Type().Name(), fld.Type.Name, f.Name)
		//FieldRegistry.AddField(val.Type().String(), fld.Type.Name, f)
		r.AddField(valType, fld.Type.Name, f)
		//}
	}
	//	TableRegistry.AddTable(val.Type().String(), table)
	r.AddTable(valType, table)
	stru.Each(fn)
	return table, nil
}
Пример #5
0
func TableDefinition(strPtr interface{}) (td *tableDefinition, err error) {
	td = &tableDefinition{}
	td.Fields = map[string]*Field{}
	td.Uniques = map[string][]string{}
	// maps fieldname to field
	st, err := meta.StructByValue(reflect.ValueOf(strPtr))
	if err != nil {
		return
	}
	st.Each(func(f *meta.Field) {

		field := f.Type
		val := f.Value

		switch field.Type {
		case tableType:
			tName := field.Name
			if name := field.Tag.Get("name"); name != "" {
				tName = name
			}
			td.Table = NewTable(tName)

			val.Set(reflect.ValueOf(td.Table))
			if un := field.Tag.Get("unique"); un != "" {
				for _, uniq := range strings.Split(un, ",") {
					td.Uniques[uniq] = strings.Split(uniq, "#")
				}
			}
		case fieldType:
			fName := field.Name
			if name := field.Tag.Get("name"); name != "" {
				fName = name
			}
			options := []interface{}{}

			type_ := field.Tag.Get("type")
			if type_ == "" {
				err = fmt.Errorf("no type tag set for field %s in table definition %T", field.Name, strPtr)
				return
			}

			var ty Type
			switch type_ {
			case "int":
				ty = IntType
			case "float":
				ty = FloatType
			case "text":
				ty = TextType
			case "bool":
				ty = BoolType
			case "timestamptz":
				ty = TimeStampTZType
			case "timestamp":
				ty = TimeType
			case "date":
				ty = DateType
			case "time":
				ty = TimeType
			case "xml":
				ty = XmlType
			case "integer[]":
				ty = IntsType
			case "character varying[]":
				ty = StringsType
			case "uuid":
				ty = UuidType
			case "ltree":
				ty = LtreeType
			case "trigger":
				ty = TriggerType
			default:
				md := varcharRegexp.FindStringSubmatch(type_)
				if len(md) == 2 {
					i, e := strconv.Atoi(md[1])
					if e != nil {
						err = fmt.Errorf("error in varchar type tag for field %s in table definition %T, can't parse integer", field.Name, strPtr)
						return
					}
					ty = VarChar(i)
				} else {
					err = fmt.Errorf("error in type tag for field %s in table definition %T, unknown type: %s", field.Name, strPtr, type_)
					return
				}
			}

			options = append(options, ty)

			if flags := field.Tag.Get("flag"); flags != "" {
				for _, fl := range strings.Split(flags, ",") {
					switch fl {
					case "null":
						options = append(options, NullAllowed)
					case "pkey":
						options = append(options, PrimaryKey)
					case "unique":
						options = append(options, Unique)
					case "index":
						options = append(options, Indexed)
					case "serial":
						options = append(options, Serial)
					case "uuidgenerate":
						options = append(options, UuidGenerate)
					default:
						err = fmt.Errorf("error in flags tag for field %s in table definition %T, unknown flag: %s", field.Name, strPtr, fl)
						return
					}
				}
			}

			if enum := field.Tag.Get("enum"); enum != "" {
				enums := strings.Split(enum, ",")
				sel := make([]interface{}, len(enums))
				for i, en := range enums {
					sel[i] = en
				}
				options = append(options, SelectionArray(sel))
			}

			f := NewField(fName, options...).SetQueryField(field.Name)
			td.Fields[fName] = f
			val.Set(reflect.ValueOf(f))
		}
	})
	// meta.Struct.EachRaw(strPtr, func(field reflect.StructField, val reflect.Value) {

	return
}
Пример #6
0
// TODO make a compilable version that saves the infos about
// fieldnumbers etc and allows faster queriing
func (ø *Row) SelectByStructs(result interface{}, tagVal string, opts ...interface{}) (int, error) {
	/*
		if !meta.Slice.Check(result) {
			return 0, fmt.Errorf("result is no slice")
		}
	*/
	slic := reflect.ValueOf(result)
	l := slic.Len()
	if l == 0 {
		return 0, fmt.Errorf("result slice has length 0")
	}

	stru, err := meta.StructByValue(slic.Index(0))
	if err != nil {
		return 0, err
	}

	tags, err2 := stru.Tags()

	if err2 != nil {
		return 0, err2
	}

	// tags := meta.Struct.Tags(slic.Index(0).Interface())
	options := []interface{}{Limit(l)}
	order := []string{}

	for k, v := range tags {
		if t := v.Get("db.select"); t != "" && strings.Contains(t, tagVal) {
			fi := ø.queryField(k, opts...)
			if fi == nil {
				panic("can't find field " + k + " : no Queryfield property of given fields or aliases")
			}
			options = append(options, fi)
			order = append(order, k)
		}
	}

	options = append(options, opts...)
	rows, err := ø.Find(options...)
	if err != nil {
		return 0, fmt.Errorf("error in find: %s", err.Error())
	}
	i := 0
	errs := []string{}
	for rows.Next() {
		ro, e := rows.ScanRow()
		if e != nil {
			errs = append(errs, e.Error())
			continue
		}
		e = ro.GetStruct(tagVal, slic.Index(i).Addr().Interface())
		if e != nil {
			errs = append(errs, fmt.Sprintf("error while scanning row %v: %s", i, e.Error()))
		}
		i++
	}
	if len(errs) > 0 {
		return i, fmt.Errorf(strings.Join(errs, "\n"))
	}
	return i, nil
}
Пример #7
0
func (r *CRUD) scanFields() (err error) {
	var hasDeleteField bool
	//fn := func(fld reflect.StructField, vl reflect.Value, tag string) {
	fn := func(fld *meta.Field) {
		if err != nil {
			return
		}
		tag := fld.Type.Tag.Get("rest")
		if tag == "" {
			return
		}

		methods := map[string]bool{}

		if strings.Contains(tag, "C") {
			methods["C"] = true
		}

		if strings.Contains(tag, "D") {
			if hasDeleteField {
				err = fmt.Errorf("more than one delete field (key) is not supported")
				return
			}
			methods["D"] = true
			hasDeleteField = true
		}

		if strings.Contains(tag, "L") {
			methods["L"] = true
		}

		if strings.Contains(tag, "U") {
			methods["U"] = true
		}

		if strings.Contains(tag, "R") {
			methods["R"] = true
		}

		if len(methods) == 0 {
			return
		}

		//ff := r.field(fld.Name)
		ff := r.field(fld.Type.Name)
		if ff == nil {
			err = fmt.Errorf("can't find field for table %s field %s\n", r.typeString(), fld.Type.Name)
			return
		}

		// pgsql.flags
		if strings.Contains(fld.Type.Tag.Get("db"), "PKEY") {
			if r.primaryKey != nil {
				err = fmt.Errorf("can't have more than one primary key %s and %s\n", r.primaryKey, fld.Type.Name)
				return
			}
			r.primaryKey = r.field(fld.Type.Name)
		}

		r.fields[fld.Type.Name] = methods
	}

	var stru *meta.Struct
	stru, err = meta.StructByValue(reflect.ValueOf(r.prototype))
	stru.Each(fn)
	//meta.Struct.EachTag(r.prototype, "rest", fn)

	if r.primaryKey == nil {
		err = fmt.Errorf("has not primary key, add db:\"PKEY\"")
	}

	pkType := r.primaryKey.Type
	if !pkType.IsCompatible(IntType) {
		if pkType.IsCompatible(TextType) {
			r.pKeyIsString = true
			return
		}
		err = fmt.Errorf("primary key %s (%s) is not compatible to int or string", r.primaryKey.Name, pkType.String())
	}

	return
}
Пример #8
0
/*
	only the fields that are *fat.Field and not nil are chosen to set
	the row. øptrToFatStruct must be registered with RegisterTable
	before using this function
*/
func (r *Registry) ToRow(øptrToFatStruct interface{}, row *Row) (err error) {
	var stru *meta.Struct
	stru, err = meta.StructByValue(reflect.ValueOf(øptrToFatStruct))

	if err != nil {
		return
	}

	t := r.TableOf(øptrToFatStruct)

	if t == nil {
		err = fmt.Errorf("%T is not registered, use RegisterTable", øptrToFatStruct)
		return
	}

	if row.Table != t {
		err = fmt.Errorf("table of the given fatstruct (%s) is not the same as table of the given row (%s)",
			t.Sql().String(),
			row.Table.Sql().String(),
		)
	}

	if err != nil {
		return
	}

	fn := func(field *meta.Field) {
		// stop on first error
		if err != nil {
			return
		}

		if field.Value.IsNil() {
			return
		}

		ff, isFat := field.Value.Interface().(*fat.Field)

		if !isFat {
			return
		}

		rowField := r.FieldOf(ff)
		v := ff.Get()

		switch v.(type) {
		case []fat.Type:
			vl := ff.String()
			vl = strings.Replace(vl, "[", "{", -1)
			vl = strings.Replace(vl, "]", "}", -1)
			err = row.Set(rowField, vl)
		case map[string]fat.Type:
			err = row.Set(rowField, ff.String())
		default:
			err = row.Set(rowField, v)
		}
	}

	stru.Each(fn)
	return
}