orm 1. complete QueryRow/QueryRows api 2. QuerySeter.All support *[]Type and *[]*Type
This commit is contained in:
		
							parent
							
								
									22d2de9fc7
								
							
						
					
					
						commit
						41dd6e580d
					
				
							
								
								
									
										20
									
								
								orm/db.go
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								orm/db.go
									
									
									
									
									
								
							| @ -479,15 +479,19 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi | ||||
| 	ind := reflect.Indirect(val) | ||||
| 
 | ||||
| 	errTyp := true | ||||
| 
 | ||||
| 	one := true | ||||
| 	isPtr := true | ||||
| 
 | ||||
| 	if val.Kind() == reflect.Ptr { | ||||
| 		fn := "" | ||||
| 		if ind.Kind() == reflect.Slice { | ||||
| 			one = false | ||||
| 			if ind.Type().Elem().Kind() == reflect.Ptr { | ||||
| 				typ := ind.Type().Elem().Elem() | ||||
| 			typ := ind.Type().Elem() | ||||
| 			switch typ.Kind() { | ||||
| 			case reflect.Ptr: | ||||
| 				fn = getFullName(typ.Elem()) | ||||
| 			case reflect.Struct: | ||||
| 				isPtr = false | ||||
| 				fn = getFullName(typ) | ||||
| 			} | ||||
| 		} else { | ||||
| @ -601,13 +605,21 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi | ||||
| 			if one { | ||||
| 				ind.Set(mind) | ||||
| 			} else { | ||||
| 				if cnt == 0 { | ||||
| 					slice = reflect.New(ind.Type()).Elem() | ||||
| 				} | ||||
| 
 | ||||
| 				if isPtr { | ||||
| 					slice = reflect.Append(slice, mind.Addr()) | ||||
| 				} else { | ||||
| 					slice = reflect.Append(slice, mind) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		cnt++ | ||||
| 	} | ||||
| 
 | ||||
| 	if one == false { | ||||
| 	if one == false && cnt > 0 { | ||||
| 		ind.Set(slice) | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -10,6 +10,7 @@ const ( | ||||
| 	od_SET_DEFAULT        = "set_default" | ||||
| 	od_DO_NOTHING         = "do_nothing" | ||||
| 	defaultStructTagName  = "orm" | ||||
| 	defaultStructTagDelim = ";" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
|  | ||||
| @ -16,7 +16,7 @@ type Data struct { | ||||
| 	Char     string    `orm:"size(50)"` | ||||
| 	Text     string    `orm:"type(text)"` | ||||
| 	Date     time.Time `orm:"type(date)"` | ||||
| 	DateTime time.Time | ||||
| 	DateTime time.Time `orm:"column(datetime)"` | ||||
| 	Byte     byte | ||||
| 	Rune     rune | ||||
| 	Int      int | ||||
| @ -37,10 +37,10 @@ type Data struct { | ||||
| type DataNull struct { | ||||
| 	Id       int | ||||
| 	Boolean  bool      `orm:"null"` | ||||
| 	Char     string    `orm:"size(50);null"` | ||||
| 	Text     string    `orm:"type(text);null"` | ||||
| 	Date     time.Time `orm:"type(date);null"` | ||||
| 	DateTime time.Time `orm:"null"` | ||||
| 	Char     string    `orm:"null;size(50)"` | ||||
| 	Text     string    `orm:"null;type(text)"` | ||||
| 	Date     time.Time `orm:"null;type(date)"` | ||||
| 	DateTime time.Time `orm:"null;column(datetime)""` | ||||
| 	Byte     byte      `orm:"null"` | ||||
| 	Rune     rune      `orm:"null"` | ||||
| 	Int      int       `orm:"null"` | ||||
| @ -174,7 +174,10 @@ var ( | ||||
| 	IsPostgres = DBARGS.Driver == "postgres" | ||||
| ) | ||||
| 
 | ||||
| var dORM Ormer | ||||
| var ( | ||||
| 	dORM     Ormer | ||||
| 	dDbBaser dbBaser | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| 	Debug, _ = StrTo(DBARGS.Debug).Bool() | ||||
|  | ||||
| @ -114,7 +114,7 @@ func getFieldType(val reflect.Value) (ft int, err error) { | ||||
| func parseStructTag(data string, attrs *map[string]bool, tags *map[string]string) { | ||||
| 	attr := make(map[string]bool) | ||||
| 	tag := make(map[string]string) | ||||
| 	for _, v := range strings.Split(data, ";") { | ||||
| 	for _, v := range strings.Split(data, defaultStructTagDelim) { | ||||
| 		v = strings.TrimSpace(v) | ||||
| 		if supportTag[v] == 1 { | ||||
| 			attr[v] = true | ||||
|  | ||||
							
								
								
									
										360
									
								
								orm/orm_raw.go
									
									
									
									
									
								
							
							
						
						
									
										360
									
								
								orm/orm_raw.go
									
									
									
									
									
								
							| @ -4,6 +4,8 @@ import ( | ||||
| 	"database/sql" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| type rawPrepare struct { | ||||
| @ -64,14 +66,362 @@ func (o *rawSet) Exec() (sql.Result, error) { | ||||
| 	return o.orm.db.Exec(query, args...) | ||||
| } | ||||
| 
 | ||||
| func (o *rawSet) QueryRow(...interface{}) error { | ||||
| 	//TODO | ||||
| func (o *rawSet) setFieldValue(ind reflect.Value, value interface{}) { | ||||
| 	switch ind.Kind() { | ||||
| 	case reflect.Bool: | ||||
| 		if value == nil { | ||||
| 			ind.SetBool(false) | ||||
| 		} else if v, ok := value.(bool); ok { | ||||
| 			ind.SetBool(v) | ||||
| 		} else { | ||||
| 			v, _ := StrTo(ToStr(value)).Bool() | ||||
| 			ind.SetBool(v) | ||||
| 		} | ||||
| 
 | ||||
| 	case reflect.String: | ||||
| 		if value == nil { | ||||
| 			ind.SetString("") | ||||
| 		} else { | ||||
| 			ind.SetString(ToStr(value)) | ||||
| 		} | ||||
| 
 | ||||
| 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||
| 		if value == nil { | ||||
| 			ind.SetInt(0) | ||||
| 		} else { | ||||
| 			val := reflect.ValueOf(value) | ||||
| 			switch val.Kind() { | ||||
| 			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||
| 				ind.SetInt(val.Int()) | ||||
| 			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||||
| 				ind.SetInt(int64(val.Uint())) | ||||
| 			default: | ||||
| 				v, _ := StrTo(ToStr(value)).Int64() | ||||
| 				ind.SetInt(v) | ||||
| 			} | ||||
| 		} | ||||
| 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||||
| 		if value == nil { | ||||
| 			ind.SetUint(0) | ||||
| 		} else { | ||||
| 			val := reflect.ValueOf(value) | ||||
| 			switch val.Kind() { | ||||
| 			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||
| 				ind.SetUint(uint64(val.Int())) | ||||
| 			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||||
| 				ind.SetUint(val.Uint()) | ||||
| 			default: | ||||
| 				v, _ := StrTo(ToStr(value)).Uint64() | ||||
| 				ind.SetUint(v) | ||||
| 			} | ||||
| 		} | ||||
| 	case reflect.Float64, reflect.Float32: | ||||
| 		if value == nil { | ||||
| 			ind.SetFloat(0) | ||||
| 		} else { | ||||
| 			val := reflect.ValueOf(value) | ||||
| 			switch val.Kind() { | ||||
| 			case reflect.Float64: | ||||
| 				ind.SetFloat(val.Float()) | ||||
| 			default: | ||||
| 				v, _ := StrTo(ToStr(value)).Float64() | ||||
| 				ind.SetFloat(v) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 	case reflect.Struct: | ||||
| 		if value == nil { | ||||
| 			ind.Set(reflect.Zero(ind.Type())) | ||||
| 
 | ||||
| 		} else if _, ok := ind.Interface().(time.Time); ok { | ||||
| 			var str string | ||||
| 			switch d := value.(type) { | ||||
| 			case time.Time: | ||||
| 				o.orm.alias.DbBaser.TimeFromDB(&d, o.orm.alias.TZ) | ||||
| 				ind.Set(reflect.ValueOf(d)) | ||||
| 			case []byte: | ||||
| 				str = string(d) | ||||
| 			case string: | ||||
| 				str = d | ||||
| 			} | ||||
| 			if str != "" { | ||||
| 				if len(str) >= 19 { | ||||
| 					str = str[:19] | ||||
| 					t, err := time.ParseInLocation(format_DateTime, str, o.orm.alias.TZ) | ||||
| 					if err == nil { | ||||
| 						t = t.In(DefaultTimeLoc) | ||||
| 						ind.Set(reflect.ValueOf(t)) | ||||
| 					} | ||||
| 				} else if len(str) >= 10 { | ||||
| 					str = str[:10] | ||||
| 					t, err := time.ParseInLocation(format_Date, str, DefaultTimeLoc) | ||||
| 					if err == nil { | ||||
| 						ind.Set(reflect.ValueOf(t)) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (o *rawSet) loopInitRefs(typ reflect.Type, refsPtr *[]interface{}, sIdxesPtr *[][]int) { | ||||
| 	sIdxes := *sIdxesPtr | ||||
| 	refs := *refsPtr | ||||
| 
 | ||||
| 	if typ.Kind() == reflect.Struct { | ||||
| 		if typ.String() == "time.Time" { | ||||
| 			var ref interface{} | ||||
| 			refs = append(refs, &ref) | ||||
| 			sIdxes = append(sIdxes, []int{0}) | ||||
| 		} else { | ||||
| 			idxs := []int{} | ||||
| 		outFor: | ||||
| 			for idx := 0; idx < typ.NumField(); idx++ { | ||||
| 				ctyp := typ.Field(idx) | ||||
| 
 | ||||
| 				tag := ctyp.Tag.Get(defaultStructTagName) | ||||
| 				for _, v := range strings.Split(tag, defaultStructTagDelim) { | ||||
| 					if v == "-" { | ||||
| 						continue outFor | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				tp := ctyp.Type | ||||
| 				if tp.Kind() == reflect.Ptr { | ||||
| 					tp = tp.Elem() | ||||
| 				} | ||||
| 
 | ||||
| 				if tp.String() == "time.Time" { | ||||
| 					var ref interface{} | ||||
| 					refs = append(refs, &ref) | ||||
| 
 | ||||
| 				} else if tp.Kind() != reflect.Struct { | ||||
| 					var ref interface{} | ||||
| 					refs = append(refs, &ref) | ||||
| 
 | ||||
| 				} else { | ||||
| 					// skip other type | ||||
| 					continue | ||||
| 				} | ||||
| 
 | ||||
| 				idxs = append(idxs, idx) | ||||
| 			} | ||||
| 			sIdxes = append(sIdxes, idxs) | ||||
| 		} | ||||
| 	} else { | ||||
| 		var ref interface{} | ||||
| 		refs = append(refs, &ref) | ||||
| 		sIdxes = append(sIdxes, []int{0}) | ||||
| 	} | ||||
| 
 | ||||
| 	*sIdxesPtr = sIdxes | ||||
| 	*refsPtr = refs | ||||
| } | ||||
| 
 | ||||
| func (o *rawSet) loopSetRefs(refs []interface{}, sIdxes [][]int, sInds []reflect.Value, nIndsPtr *[]reflect.Value, eTyps []reflect.Type, init bool) { | ||||
| 	nInds := *nIndsPtr | ||||
| 
 | ||||
| 	cur := 0 | ||||
| 	for i, idxs := range sIdxes { | ||||
| 		sInd := sInds[i] | ||||
| 		eTyp := eTyps[i] | ||||
| 
 | ||||
| 		typ := eTyp | ||||
| 		isPtr := false | ||||
| 		if typ.Kind() == reflect.Ptr { | ||||
| 			isPtr = true | ||||
| 			typ = typ.Elem() | ||||
| 		} | ||||
| 		if typ.Kind() == reflect.Ptr { | ||||
| 			isPtr = true | ||||
| 			typ = typ.Elem() | ||||
| 		} | ||||
| 
 | ||||
| 		var nInd reflect.Value | ||||
| 		if init { | ||||
| 			nInd = reflect.New(sInd.Type()).Elem() | ||||
| 		} else { | ||||
| 			nInd = nInds[i] | ||||
| 		} | ||||
| 
 | ||||
| 		val := reflect.New(typ) | ||||
| 		ind := val.Elem() | ||||
| 
 | ||||
| 		tpName := ind.Type().String() | ||||
| 
 | ||||
| 		if ind.Kind() == reflect.Struct { | ||||
| 			if tpName == "time.Time" { | ||||
| 				value := reflect.ValueOf(refs[cur]).Elem().Interface() | ||||
| 				if isPtr && value == nil { | ||||
| 					val = reflect.New(val.Type()).Elem() | ||||
| 				} else { | ||||
| 					o.setFieldValue(ind, value) | ||||
| 				} | ||||
| 				cur++ | ||||
| 			} else { | ||||
| 				hasValue := false | ||||
| 				for _, idx := range idxs { | ||||
| 					tind := ind.Field(idx) | ||||
| 					value := reflect.ValueOf(refs[cur]).Elem().Interface() | ||||
| 					if value != nil { | ||||
| 						hasValue = true | ||||
| 					} | ||||
| 					if tind.Kind() == reflect.Ptr { | ||||
| 						if value == nil { | ||||
| 							tindV := reflect.New(tind.Type()).Elem() | ||||
| 							tind.Set(tindV) | ||||
| 						} else { | ||||
| 							tindV := reflect.New(tind.Type().Elem()) | ||||
| 							o.setFieldValue(tindV.Elem(), value) | ||||
| 							tind.Set(tindV) | ||||
| 						} | ||||
| 					} else { | ||||
| 						o.setFieldValue(tind, value) | ||||
| 					} | ||||
| 					cur++ | ||||
| 				} | ||||
| 				if hasValue == false && isPtr { | ||||
| 					val = reflect.New(val.Type()).Elem() | ||||
| 				} | ||||
| 			} | ||||
| 		} else { | ||||
| 			value := reflect.ValueOf(refs[cur]).Elem().Interface() | ||||
| 			if isPtr && value == nil { | ||||
| 				val = reflect.New(val.Type()).Elem() | ||||
| 			} else { | ||||
| 				o.setFieldValue(ind, value) | ||||
| 			} | ||||
| 			cur++ | ||||
| 		} | ||||
| 
 | ||||
| 		if nInd.Kind() == reflect.Slice { | ||||
| 			if isPtr { | ||||
| 				nInd = reflect.Append(nInd, val) | ||||
| 			} else { | ||||
| 				nInd = reflect.Append(nInd, ind) | ||||
| 			} | ||||
| 		} else { | ||||
| 			if isPtr { | ||||
| 				nInd.Set(val) | ||||
| 			} else { | ||||
| 				nInd.Set(ind) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		nInds[i] = nInd | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (o *rawSet) QueryRow(containers ...interface{}) error { | ||||
| 	if len(containers) == 0 { | ||||
| 		panic("<RawSeter.QueryRow> need at least one arg") | ||||
| 	} | ||||
| 
 | ||||
| 	refs := make([]interface{}, 0, len(containers)) | ||||
| 	sIdxes := make([][]int, 0) | ||||
| 	sInds := make([]reflect.Value, 0) | ||||
| 	eTyps := make([]reflect.Type, 0) | ||||
| 
 | ||||
| 	for _, container := range containers { | ||||
| 		val := reflect.ValueOf(container) | ||||
| 		ind := reflect.Indirect(val) | ||||
| 
 | ||||
| 		if val.Kind() != reflect.Ptr { | ||||
| 			panic("<RawSeter.QueryRow> all args must be use ptr") | ||||
| 		} | ||||
| 
 | ||||
| 		etyp := ind.Type() | ||||
| 		typ := etyp | ||||
| 		if typ.Kind() == reflect.Ptr { | ||||
| 			typ = typ.Elem() | ||||
| 		} | ||||
| 		if typ.Kind() == reflect.Ptr { | ||||
| 			typ = typ.Elem() | ||||
| 		} | ||||
| 
 | ||||
| 		sInds = append(sInds, ind) | ||||
| 		eTyps = append(eTyps, etyp) | ||||
| 
 | ||||
| 		o.loopInitRefs(typ, &refs, &sIdxes) | ||||
| 	} | ||||
| 
 | ||||
| 	query := o.query | ||||
| 	o.orm.alias.DbBaser.ReplaceMarks(&query) | ||||
| 
 | ||||
| 	args := getFlatParams(nil, o.args, o.orm.alias.TZ) | ||||
| 	row := o.orm.db.QueryRow(query, args...) | ||||
| 
 | ||||
| 	if err := row.Scan(refs...); err == sql.ErrNoRows { | ||||
| 		return ErrNoRows | ||||
| 	} else if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	nInds := make([]reflect.Value, len(sInds)) | ||||
| 	o.loopSetRefs(refs, sIdxes, sInds, &nInds, eTyps, true) | ||||
| 	for i, sInd := range sInds { | ||||
| 		nInd := nInds[i] | ||||
| 		sInd.Set(nInd) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (o *rawSet) QueryRows(...interface{}) (int64, error) { | ||||
| 	//TODO | ||||
| 	return 0, nil | ||||
| func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) { | ||||
| 	refs := make([]interface{}, 0) | ||||
| 	sIdxes := make([][]int, 0) | ||||
| 	sInds := make([]reflect.Value, 0) | ||||
| 	eTyps := make([]reflect.Type, 0) | ||||
| 
 | ||||
| 	for _, container := range containers { | ||||
| 		val := reflect.ValueOf(container) | ||||
| 		sInd := reflect.Indirect(val) | ||||
| 		if val.Kind() != reflect.Ptr || sInd.Kind() != reflect.Slice { | ||||
| 			panic("<RawSeter.QueryRows> all args must be use ptr slice") | ||||
| 		} | ||||
| 
 | ||||
| 		etyp := sInd.Type().Elem() | ||||
| 		typ := etyp | ||||
| 		if typ.Kind() == reflect.Ptr { | ||||
| 			typ = typ.Elem() | ||||
| 		} | ||||
| 
 | ||||
| 		sInds = append(sInds, sInd) | ||||
| 		eTyps = append(eTyps, etyp) | ||||
| 
 | ||||
| 		o.loopInitRefs(typ, &refs, &sIdxes) | ||||
| 	} | ||||
| 
 | ||||
| 	query := o.query | ||||
| 	o.orm.alias.DbBaser.ReplaceMarks(&query) | ||||
| 
 | ||||
| 	args := getFlatParams(nil, o.args, o.orm.alias.TZ) | ||||
| 	rows, err := o.orm.db.Query(query, args...) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 
 | ||||
| 	nInds := make([]reflect.Value, len(sInds)) | ||||
| 
 | ||||
| 	var cnt int64 | ||||
| 	for rows.Next() { | ||||
| 		if err := rows.Scan(refs...); err != nil { | ||||
| 			return 0, err | ||||
| 		} | ||||
| 
 | ||||
| 		o.loopSetRefs(refs, sIdxes, sInds, &nInds, eTyps, cnt == 0) | ||||
| 
 | ||||
| 		cnt++ | ||||
| 	} | ||||
| 
 | ||||
| 	if cnt > 0 { | ||||
| 		for i, sInd := range sInds { | ||||
| 			nInd := nInds[i] | ||||
| 			sInd.Set(nInd) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return cnt, nil | ||||
| } | ||||
| 
 | ||||
| func (o *rawSet) readValues(container interface{}) (int64, error) { | ||||
|  | ||||
							
								
								
									
										351
									
								
								orm/orm_test.go
									
									
									
									
									
								
							
							
						
						
									
										351
									
								
								orm/orm_test.go
									
									
									
									
									
								
							| @ -216,6 +216,7 @@ func TestRegisterModels(t *testing.T) { | ||||
| 	BootStrap() | ||||
| 
 | ||||
| 	dORM = NewOrm() | ||||
| 	dDbBaser = getDbAlias("default").DbBaser | ||||
| } | ||||
| 
 | ||||
| func TestModelSyntax(t *testing.T) { | ||||
| @ -629,9 +630,23 @@ func TestOperators(t *testing.T) { | ||||
| func TestAll(t *testing.T) { | ||||
| 	var users []*User | ||||
| 	qs := dORM.QueryTable("user") | ||||
| 	num, err := qs.All(&users) | ||||
| 	num, err := qs.OrderBy("Id").All(&users) | ||||
| 	throwFail(t, err) | ||||
| 	throwFail(t, AssertIs(num, T_Equal, 3)) | ||||
| 	throwFailNow(t, AssertIs(num, T_Equal, 3)) | ||||
| 
 | ||||
| 	throwFail(t, AssertIs(users[0].UserName, T_Equal, "slene")) | ||||
| 	throwFail(t, AssertIs(users[1].UserName, T_Equal, "astaxie")) | ||||
| 	throwFail(t, AssertIs(users[2].UserName, T_Equal, "nobody")) | ||||
| 
 | ||||
| 	var users2 []User | ||||
| 	qs = dORM.QueryTable("user") | ||||
| 	num, err = qs.OrderBy("Id").All(&users2) | ||||
| 	throwFail(t, err) | ||||
| 	throwFailNow(t, AssertIs(num, T_Equal, 3)) | ||||
| 
 | ||||
| 	throwFailNow(t, AssertIs(users2[0].UserName, T_Equal, "slene")) | ||||
| 	throwFailNow(t, AssertIs(users2[1].UserName, T_Equal, "astaxie")) | ||||
| 	throwFailNow(t, AssertIs(users2[2].UserName, T_Equal, "nobody")) | ||||
| 
 | ||||
| 	qs = dORM.QueryTable("user") | ||||
| 	num, err = qs.Filter("user_name", "nothing").All(&users) | ||||
| @ -645,8 +660,14 @@ func TestOne(t *testing.T) { | ||||
| 	err := qs.One(&user) | ||||
| 	throwFail(t, AssertIs(err, T_Equal, ErrMultiRows)) | ||||
| 
 | ||||
| 	user = User{} | ||||
| 	err = qs.OrderBy("Id").Limit(1).One(&user) | ||||
| 	throwFailNow(t, err) | ||||
| 	throwFail(t, AssertIs(user.UserName, T_Equal, "slene")) | ||||
| 
 | ||||
| 	err = qs.Filter("user_name", "nothing").One(&user) | ||||
| 	throwFail(t, AssertIs(err, T_Equal, ErrNoRows)) | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func TestValues(t *testing.T) { | ||||
| @ -836,30 +857,282 @@ func TestPrepareInsert(t *testing.T) { | ||||
| 	throwFail(t, AssertIs(err, T_Equal, ErrStmtClosed)) | ||||
| } | ||||
| 
 | ||||
| func TestRawQueryRow(t *testing.T) { | ||||
| func TestRawExec(t *testing.T) { | ||||
| 	Q := dDbBaser.TableQuote() | ||||
| 
 | ||||
| 	query := fmt.Sprintf("UPDATE %suser%s SET %suser_name%s = ? WHERE %suser_name%s = ?", Q, Q, Q, Q, Q, Q) | ||||
| 	res, err := dORM.Raw(query, "testing", "slene").Exec() | ||||
| 	throwFail(t, err) | ||||
| 	num, err := res.RowsAffected() | ||||
| 	throwFail(t, AssertIs(num, T_Equal, 1), err) | ||||
| 
 | ||||
| 	res, err = dORM.Raw(query, "slene", "testing").Exec() | ||||
| 	throwFail(t, err) | ||||
| 	num, err = res.RowsAffected() | ||||
| 	throwFail(t, AssertIs(num, T_Equal, 1), err) | ||||
| } | ||||
| 
 | ||||
| func TestRawQueryRows(t *testing.T) { | ||||
| func TestRawQueryRow(t *testing.T) { | ||||
| 	var ( | ||||
| 		Boolean  bool | ||||
| 		Char     string | ||||
| 		Text     string | ||||
| 		Date     time.Time | ||||
| 		DateTime time.Time | ||||
| 		Byte     byte | ||||
| 		Rune     rune | ||||
| 		Int      int | ||||
| 		Int8     int | ||||
| 		Int16    int16 | ||||
| 		Int32    int32 | ||||
| 		Int64    int64 | ||||
| 		Uint     uint | ||||
| 		Uint8    uint8 | ||||
| 		Uint16   uint16 | ||||
| 		Uint32   uint32 | ||||
| 		Uint64   uint64 | ||||
| 		Float32  float32 | ||||
| 		Float64  float64 | ||||
| 		Decimal  float64 | ||||
| 	) | ||||
| 
 | ||||
| 	data_values := make(map[string]interface{}, len(Data_Values)) | ||||
| 
 | ||||
| 	for k, v := range Data_Values { | ||||
| 		data_values[strings.ToLower(k)] = v | ||||
| 	} | ||||
| 
 | ||||
| 	Q := dDbBaser.TableQuote() | ||||
| 
 | ||||
| 	cols := []string{ | ||||
| 		"id", "boolean", "char", "text", "date", "datetime", "byte", "rune", "int", "int8", "int16", "int32", | ||||
| 		"int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64", "decimal", | ||||
| 	} | ||||
| 	sep := fmt.Sprintf("%s, %s", Q, Q) | ||||
| 	query := fmt.Sprintf("SELECT %s%s%s FROM data WHERE id = ?", Q, strings.Join(cols, sep), Q) | ||||
| 	var id int | ||||
| 	values := []interface{}{ | ||||
| 		&id, &Boolean, &Char, &Text, &Date, &DateTime, &Byte, &Rune, &Int, &Int8, &Int16, &Int32, | ||||
| 		&Int64, &Uint, &Uint8, &Uint16, &Uint32, &Uint64, &Float32, &Float64, &Decimal, | ||||
| 	} | ||||
| 	err := dORM.Raw(query, 1).QueryRow(values...) | ||||
| 	throwFailNow(t, err) | ||||
| 	for i, col := range cols { | ||||
| 		vu := values[i] | ||||
| 		v := reflect.ValueOf(vu).Elem().Interface() | ||||
| 		switch col { | ||||
| 		case "id": | ||||
| 			throwFail(t, AssertIs(id, T_Equal, 1)) | ||||
| 		case "date": | ||||
| 			v = v.(time.Time).In(DefaultTimeLoc) | ||||
| 			value := data_values[col].(time.Time).In(DefaultTimeLoc) | ||||
| 			throwFail(t, AssertIs(v, T_Equal, value, test_Date)) | ||||
| 		case "datetime": | ||||
| 			v = v.(time.Time).In(DefaultTimeLoc) | ||||
| 			value := data_values[col].(time.Time).In(DefaultTimeLoc) | ||||
| 			throwFail(t, AssertIs(v, T_Equal, value, test_DateTime)) | ||||
| 		default: | ||||
| 			throwFail(t, AssertIs(v, T_Equal, data_values[col])) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	type Tmp struct { | ||||
| 		Skip0    string | ||||
| 		Id       int | ||||
| 		Char     *string | ||||
| 		Skip1    int `orm:"-"` | ||||
| 		Date     time.Time | ||||
| 		DateTime time.Time | ||||
| 	} | ||||
| 
 | ||||
| 	Boolean = false | ||||
| 	Text = "" | ||||
| 	Int64 = 0 | ||||
| 	Uint = 0 | ||||
| 
 | ||||
| 	tmp := new(Tmp) | ||||
| 
 | ||||
| 	cols = []string{ | ||||
| 		"int", "char", "date", "datetime", "boolean", "text", "int64", "uint", | ||||
| 	} | ||||
| 	query = fmt.Sprintf("SELECT NULL, %s%s%s FROM data WHERE id = ?", Q, strings.Join(cols, sep), Q) | ||||
| 	values = []interface{}{ | ||||
| 		tmp, &Boolean, &Text, &Int64, &Uint, | ||||
| 	} | ||||
| 	err = dORM.Raw(query, 1).QueryRow(values...) | ||||
| 	throwFailNow(t, err) | ||||
| 
 | ||||
| 	for _, col := range cols { | ||||
| 		switch col { | ||||
| 		case "id": | ||||
| 			throwFail(t, AssertIs(tmp.Id, T_Equal, data_values[col])) | ||||
| 		case "char": | ||||
| 			c := tmp.Char | ||||
| 			throwFail(t, AssertIs(*c, T_Equal, data_values[col])) | ||||
| 		case "date": | ||||
| 			v := tmp.Date.In(DefaultTimeLoc) | ||||
| 			value := data_values[col].(time.Time).In(DefaultTimeLoc) | ||||
| 			throwFail(t, AssertIs(v, T_Equal, value, test_Date)) | ||||
| 		case "datetime": | ||||
| 			v := tmp.DateTime.In(DefaultTimeLoc) | ||||
| 			value := data_values[col].(time.Time).In(DefaultTimeLoc) | ||||
| 			throwFail(t, AssertIs(v, T_Equal, value, test_DateTime)) | ||||
| 		case "boolean": | ||||
| 			throwFail(t, AssertIs(Boolean, T_Equal, data_values[col])) | ||||
| 		case "text": | ||||
| 			throwFail(t, AssertIs(Text, T_Equal, data_values[col])) | ||||
| 		case "int64": | ||||
| 			throwFail(t, AssertIs(Int64, T_Equal, data_values[col])) | ||||
| 		case "uint": | ||||
| 			throwFail(t, AssertIs(Uint, T_Equal, data_values[col])) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var ( | ||||
| 		uid    int | ||||
| 		status *int | ||||
| 		pid    *int | ||||
| 	) | ||||
| 
 | ||||
| 	cols = []string{ | ||||
| 		"id", "status", "profile_id", | ||||
| 	} | ||||
| 	query = fmt.Sprintf("SELECT %s%s%s FROM %suser%s WHERE id = ?", Q, strings.Join(cols, sep), Q, Q, Q) | ||||
| 	err = dORM.Raw(query, 4).QueryRow(&uid, &status, &pid) | ||||
| 	throwFail(t, err) | ||||
| 	throwFail(t, AssertIs(uid, T_Equal, 4)) | ||||
| 	throwFail(t, AssertIs(*status, T_Equal, 3)) | ||||
| 	throwFail(t, AssertIs(pid, T_Equal, nil)) | ||||
| } | ||||
| 
 | ||||
| func TestQueryRows(t *testing.T) { | ||||
| 	Q := dDbBaser.TableQuote() | ||||
| 
 | ||||
| 	cols := []string{ | ||||
| 		"id", "boolean", "char", "text", "date", "datetime", "byte", "rune", "int", "int8", "int16", "int32", | ||||
| 		"int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64", "decimal", | ||||
| 	} | ||||
| 
 | ||||
| 	var datas []*Data | ||||
| 	var dids []int | ||||
| 
 | ||||
| 	sep := fmt.Sprintf("%s, %s", Q, Q) | ||||
| 	query := fmt.Sprintf("SELECT %s%s%s, id FROM %sdata%s", Q, strings.Join(cols, sep), Q, Q, Q) | ||||
| 	num, err := dORM.Raw(query).QueryRows(&datas, &dids) | ||||
| 	throwFailNow(t, err) | ||||
| 	throwFailNow(t, AssertIs(num, T_Equal, 1)) | ||||
| 	throwFailNow(t, AssertIs(len(datas), T_Equal, 1)) | ||||
| 	throwFailNow(t, AssertIs(len(dids), T_Equal, 1)) | ||||
| 	throwFailNow(t, AssertIs(dids[0], T_Equal, 1)) | ||||
| 
 | ||||
| 	ind := reflect.Indirect(reflect.ValueOf(datas[0])) | ||||
| 
 | ||||
| 	for name, value := range Data_Values { | ||||
| 		e := ind.FieldByName(name) | ||||
| 		vu := e.Interface() | ||||
| 		switch name { | ||||
| 		case "Date": | ||||
| 			vu = vu.(time.Time).In(DefaultTimeLoc).Format(test_Date) | ||||
| 			value = value.(time.Time).In(DefaultTimeLoc).Format(test_Date) | ||||
| 		case "DateTime": | ||||
| 			vu = vu.(time.Time).In(DefaultTimeLoc).Format(test_DateTime) | ||||
| 			value = value.(time.Time).In(DefaultTimeLoc).Format(test_DateTime) | ||||
| 		} | ||||
| 		throwFail(t, AssertIs(vu == value, T_Equal, true), value, vu) | ||||
| 	} | ||||
| 
 | ||||
| 	type Tmp struct { | ||||
| 		Id      int | ||||
| 		Name    string | ||||
| 		Skiped0 string `orm:"-"` | ||||
| 		Pid     *int | ||||
| 		Skiped1 Data | ||||
| 		Skiped2 *Data | ||||
| 	} | ||||
| 
 | ||||
| 	var ( | ||||
| 		ids         []int | ||||
| 		userNames   []string | ||||
| 		profileIds1 []int | ||||
| 		profileIds2 []*int | ||||
| 		createds    []time.Time | ||||
| 		updateds    []time.Time | ||||
| 		tmps1       []*Tmp | ||||
| 		tmps2       []Tmp | ||||
| 	) | ||||
| 	cols = []string{ | ||||
| 		"id", "user_name", "profile_id", "profile_id", "id", "user_name", "profile_id", "id", "user_name", "profile_id", "created", "updated", | ||||
| 	} | ||||
| 	query = fmt.Sprintf("SELECT %s%s%s FROM %suser%s ORDER BY id", Q, strings.Join(cols, sep), Q, Q, Q) | ||||
| 	num, err = dORM.Raw(query).QueryRows(&ids, &userNames, &profileIds1, &profileIds2, &tmps1, &tmps2, &createds, &updateds) | ||||
| 	throwFailNow(t, err) | ||||
| 	throwFailNow(t, AssertIs(num, T_Equal, 3)) | ||||
| 
 | ||||
| 	var users []User | ||||
| 	dORM.QueryTable("user").OrderBy("Id").All(&users) | ||||
| 
 | ||||
| 	for i := 0; i < 3; i++ { | ||||
| 		id := ids[i] | ||||
| 		name := userNames[i] | ||||
| 		pid1 := profileIds1[i] | ||||
| 		pid2 := profileIds2[i] | ||||
| 		created := createds[i] | ||||
| 		updated := updateds[i] | ||||
| 
 | ||||
| 		user := users[i] | ||||
| 		throwFailNow(t, AssertIs(id, T_Equal, user.Id)) | ||||
| 		throwFailNow(t, AssertIs(name, T_Equal, user.UserName)) | ||||
| 		if user.Profile != nil { | ||||
| 			throwFailNow(t, AssertIs(pid1, T_Equal, user.Profile.Id)) | ||||
| 			throwFailNow(t, AssertIs(*pid2, T_Equal, user.Profile.Id)) | ||||
| 		} else { | ||||
| 			throwFailNow(t, AssertIs(pid1, T_Equal, 0)) | ||||
| 			throwFailNow(t, AssertIs(pid2, T_Equal, nil)) | ||||
| 		} | ||||
| 		throwFailNow(t, AssertIs(created, T_Equal, user.Created, test_Date)) | ||||
| 		throwFailNow(t, AssertIs(updated, T_Equal, user.Updated, test_DateTime)) | ||||
| 
 | ||||
| 		tmp := tmps1[i] | ||||
| 		tmp1 := *tmp | ||||
| 		throwFailNow(t, AssertIs(tmp1.Id, T_Equal, user.Id)) | ||||
| 		throwFailNow(t, AssertIs(tmp1.Name, T_Equal, user.UserName)) | ||||
| 		if user.Profile != nil { | ||||
| 			pid := tmp1.Pid | ||||
| 			throwFailNow(t, AssertIs(*pid, T_Equal, user.Profile.Id)) | ||||
| 		} else { | ||||
| 			throwFailNow(t, AssertIs(tmp1.Pid, T_Equal, nil)) | ||||
| 		} | ||||
| 
 | ||||
| 		tmp2 := tmps2[i] | ||||
| 		throwFailNow(t, AssertIs(tmp2.Id, T_Equal, user.Id)) | ||||
| 		throwFailNow(t, AssertIs(tmp2.Name, T_Equal, user.UserName)) | ||||
| 		if user.Profile != nil { | ||||
| 			pid := tmp2.Pid | ||||
| 			throwFailNow(t, AssertIs(*pid, T_Equal, user.Profile.Id)) | ||||
| 		} else { | ||||
| 			throwFailNow(t, AssertIs(tmp2.Pid, T_Equal, nil)) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	type Sec struct { | ||||
| 		Id   int | ||||
| 		Name string | ||||
| 	} | ||||
| 
 | ||||
| 	var tmp []*Sec | ||||
| 	query = fmt.Sprintf("SELECT NULL, NULL FROM %suser%s LIMIT 1", Q, Q) | ||||
| 	num, err = dORM.Raw(query).QueryRows(&tmp) | ||||
| 	throwFail(t, err) | ||||
| 	throwFail(t, AssertIs(num, T_Equal, 1)) | ||||
| 	throwFail(t, AssertIs(tmp[0], T_Equal, nil)) | ||||
| } | ||||
| 
 | ||||
| func TestRawValues(t *testing.T) { | ||||
| 	switch { | ||||
| 	case IsMysql || IsSqlite: | ||||
| 
 | ||||
| 		res, err := dORM.Raw("UPDATE user SET user_name = ? WHERE user_name = ?", "testing", "slene").Exec() | ||||
| 		throwFail(t, err) | ||||
| 		num, err := res.RowsAffected() | ||||
| 		throwFail(t, AssertIs(num, T_Equal, 1), err) | ||||
| 
 | ||||
| 		res, err = dORM.Raw("UPDATE user SET user_name = ? WHERE user_name = ?", "slene", "testing").Exec() | ||||
| 		throwFail(t, err) | ||||
| 		num, err = res.RowsAffected() | ||||
| 		throwFail(t, AssertIs(num, T_Equal, 1), err) | ||||
| 	Q := dDbBaser.TableQuote() | ||||
| 
 | ||||
| 	var maps []Params | ||||
| 		num, err = dORM.Raw("SELECT user_name FROM user WHERE status = ?", 1).Values(&maps) | ||||
| 	query := fmt.Sprintf("SELECT %suser_name%s FROM %suser%s WHERE %sstatus%s = ?", Q, Q, Q, Q, Q, Q) | ||||
| 	num, err := dORM.Raw(query, 1).Values(&maps) | ||||
| 	throwFail(t, err) | ||||
| 	throwFail(t, AssertIs(num, T_Equal, 1)) | ||||
| 	if num == 1 { | ||||
| @ -867,15 +1140,16 @@ func TestRawValues(t *testing.T) { | ||||
| 	} | ||||
| 
 | ||||
| 	var lists []ParamsList | ||||
| 		num, err = dORM.Raw("SELECT user_name FROM user WHERE status = ?", 1).ValuesList(&lists) | ||||
| 	num, err = dORM.Raw(query, 1).ValuesList(&lists) | ||||
| 	throwFail(t, err) | ||||
| 	throwFail(t, AssertIs(num, T_Equal, 1)) | ||||
| 	if num == 1 { | ||||
| 		throwFail(t, AssertIs(lists[0][0], T_Equal, "slene")) | ||||
| 	} | ||||
| 
 | ||||
| 	query = fmt.Sprintf("SELECT %sprofile_id%s FROM %suser%s ORDER BY %sid%s ASC", Q, Q, Q, Q, Q, Q) | ||||
| 	var list ParamsList | ||||
| 		num, err = dORM.Raw("SELECT profile_id FROM user ORDER BY id ASC").ValuesFlat(&list) | ||||
| 	num, err = dORM.Raw(query).ValuesFlat(&list) | ||||
| 	throwFail(t, err) | ||||
| 	throwFail(t, AssertIs(num, T_Equal, 3)) | ||||
| 	if num == 3 { | ||||
| @ -883,45 +1157,6 @@ func TestRawValues(t *testing.T) { | ||||
| 		throwFail(t, AssertIs(list[1], T_Equal, "3")) | ||||
| 		throwFail(t, AssertIs(list[2], T_Equal, nil)) | ||||
| 	} | ||||
| 
 | ||||
| 	case IsPostgres: | ||||
| 
 | ||||
| 		res, err := dORM.Raw(`UPDATE "user" SET "user_name" = ? WHERE "user_name" = ?`, "testing", "slene").Exec() | ||||
| 		throwFail(t, err) | ||||
| 		num, err := res.RowsAffected() | ||||
| 		throwFail(t, AssertIs(num, T_Equal, 1), err) | ||||
| 
 | ||||
| 		res, err = dORM.Raw(`UPDATE "user" SET "user_name" = ? WHERE "user_name" = ?`, "slene", "testing").Exec() | ||||
| 		throwFail(t, err) | ||||
| 		num, err = res.RowsAffected() | ||||
| 		throwFail(t, AssertIs(num, T_Equal, 1), err) | ||||
| 
 | ||||
| 		var maps []Params | ||||
| 		num, err = dORM.Raw(`SELECT "user_name" FROM "user" WHERE "status" = ?`, 1).Values(&maps) | ||||
| 		throwFail(t, err) | ||||
| 		throwFail(t, AssertIs(num, T_Equal, 1)) | ||||
| 		if num == 1 { | ||||
| 			throwFail(t, AssertIs(maps[0]["user_name"], T_Equal, "slene")) | ||||
| 		} | ||||
| 
 | ||||
| 		var lists []ParamsList | ||||
| 		num, err = dORM.Raw(`SELECT "user_name" FROM "user" WHERE "status" = ?`, 1).ValuesList(&lists) | ||||
| 		throwFail(t, err) | ||||
| 		throwFail(t, AssertIs(num, T_Equal, 1)) | ||||
| 		if num == 1 { | ||||
| 			throwFail(t, AssertIs(lists[0][0], T_Equal, "slene")) | ||||
| 		} | ||||
| 
 | ||||
| 		var list ParamsList | ||||
| 		num, err = dORM.Raw(`SELECT "profile_id" FROM "user" ORDER BY id ASC`).ValuesFlat(&list) | ||||
| 		throwFail(t, err) | ||||
| 		throwFail(t, AssertIs(num, T_Equal, 3)) | ||||
| 		if num == 3 { | ||||
| 			throwFail(t, AssertIs(list[0], T_Equal, "2")) | ||||
| 			throwFail(t, AssertIs(list[1], T_Equal, "3")) | ||||
| 			throwFail(t, AssertIs(list[2], T_Equal, nil)) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestRawPrepare(t *testing.T) { | ||||
|  | ||||
| @ -115,6 +115,8 @@ func ToStr(value interface{}, args ...int) (s string) { | ||||
| 		s = strconv.FormatUint(v, argInt(args).Get(0, 10)) | ||||
| 	case string: | ||||
| 		s = v | ||||
| 	case []byte: | ||||
| 		s = string(v) | ||||
| 	default: | ||||
| 		s = fmt.Sprintf("%v", v) | ||||
| 	} | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user