412a4a04 by slene

#384

1 parent e0e8fa6e
...@@ -4,7 +4,6 @@ import ( ...@@ -4,7 +4,6 @@ import (
4 "database/sql" 4 "database/sql"
5 "fmt" 5 "fmt"
6 "reflect" 6 "reflect"
7 "strings"
8 "time" 7 "time"
9 ) 8 )
10 9
...@@ -164,65 +163,11 @@ func (o *rawSet) setFieldValue(ind reflect.Value, value interface{}) { ...@@ -164,65 +163,11 @@ func (o *rawSet) setFieldValue(ind reflect.Value, value interface{}) {
164 } 163 }
165 } 164 }
166 165
167 func (o *rawSet) loopInitRefs(typ reflect.Type, refsPtr *[]interface{}, sIdxesPtr *[][]int) { 166 func (o *rawSet) loopSetRefs(refs []interface{}, sInds []reflect.Value, nIndsPtr *[]reflect.Value, eTyps []reflect.Type, init bool) {
168 sIdxes := *sIdxesPtr
169 refs := *refsPtr
170
171 if typ.Kind() == reflect.Struct {
172 if typ.String() == "time.Time" {
173 var ref interface{}
174 refs = append(refs, &ref)
175 sIdxes = append(sIdxes, []int{0})
176 } else {
177 idxs := []int{}
178 outFor:
179 for idx := 0; idx < typ.NumField(); idx++ {
180 ctyp := typ.Field(idx)
181
182 tag := ctyp.Tag.Get(defaultStructTagName)
183 for _, v := range strings.Split(tag, defaultStructTagDelim) {
184 if v == "-" {
185 continue outFor
186 }
187 }
188
189 tp := ctyp.Type
190 if tp.Kind() == reflect.Ptr {
191 tp = tp.Elem()
192 }
193
194 if tp.String() == "time.Time" {
195 var ref interface{}
196 refs = append(refs, &ref)
197
198 } else if tp.Kind() != reflect.Struct {
199 var ref interface{}
200 refs = append(refs, &ref)
201
202 } else {
203 // skip other type
204 continue
205 }
206
207 idxs = append(idxs, idx)
208 }
209 sIdxes = append(sIdxes, idxs)
210 }
211 } else {
212 var ref interface{}
213 refs = append(refs, &ref)
214 sIdxes = append(sIdxes, []int{0})
215 }
216
217 *sIdxesPtr = sIdxes
218 *refsPtr = refs
219 }
220
221 func (o *rawSet) loopSetRefs(refs []interface{}, sIdxes [][]int, sInds []reflect.Value, nIndsPtr *[]reflect.Value, eTyps []reflect.Type, init bool) {
222 nInds := *nIndsPtr 167 nInds := *nIndsPtr
223 168
224 cur := 0 169 cur := 0
225 for i, idxs := range sIdxes { 170 for i := 0; i < len(sInds); i++ {
226 sInd := sInds[i] 171 sInd := sInds[i]
227 eTyp := eTyps[i] 172 eTyp := eTyps[i]
228 173
...@@ -258,32 +203,8 @@ func (o *rawSet) loopSetRefs(refs []interface{}, sIdxes [][]int, sInds []reflect ...@@ -258,32 +203,8 @@ func (o *rawSet) loopSetRefs(refs []interface{}, sIdxes [][]int, sInds []reflect
258 o.setFieldValue(ind, value) 203 o.setFieldValue(ind, value)
259 } 204 }
260 cur++ 205 cur++
261 } else {
262 hasValue := false
263 for _, idx := range idxs {
264 tind := ind.Field(idx)
265 value := reflect.ValueOf(refs[cur]).Elem().Interface()
266 if value != nil {
267 hasValue = true
268 }
269 if tind.Kind() == reflect.Ptr {
270 if value == nil {
271 tindV := reflect.New(tind.Type()).Elem()
272 tind.Set(tindV)
273 } else {
274 tindV := reflect.New(tind.Type().Elem())
275 o.setFieldValue(tindV.Elem(), value)
276 tind.Set(tindV)
277 }
278 } else {
279 o.setFieldValue(tind, value)
280 }
281 cur++
282 }
283 if hasValue == false && isPtr {
284 val = reflect.New(val.Type()).Elem()
285 }
286 } 206 }
207
287 } else { 208 } else {
288 value := reflect.ValueOf(refs[cur]).Elem().Interface() 209 value := reflect.ValueOf(refs[cur]).Elem().Interface()
289 if isPtr && value == nil { 210 if isPtr && value == nil {
...@@ -313,15 +234,12 @@ func (o *rawSet) loopSetRefs(refs []interface{}, sIdxes [][]int, sInds []reflect ...@@ -313,15 +234,12 @@ func (o *rawSet) loopSetRefs(refs []interface{}, sIdxes [][]int, sInds []reflect
313 } 234 }
314 235
315 func (o *rawSet) QueryRow(containers ...interface{}) error { 236 func (o *rawSet) QueryRow(containers ...interface{}) error {
316 if len(containers) == 0 {
317 panic(fmt.Errorf("<RawSeter.QueryRow> need at least one arg"))
318 }
319
320 refs := make([]interface{}, 0, len(containers)) 237 refs := make([]interface{}, 0, len(containers))
321 sIdxes := make([][]int, 0)
322 sInds := make([]reflect.Value, 0) 238 sInds := make([]reflect.Value, 0)
323 eTyps := make([]reflect.Type, 0) 239 eTyps := make([]reflect.Type, 0)
324 240
241 structMode := false
242 var sMi *modelInfo
325 for _, container := range containers { 243 for _, container := range containers {
326 val := reflect.ValueOf(container) 244 val := reflect.ValueOf(container)
327 ind := reflect.Indirect(val) 245 ind := reflect.Indirect(val)
...@@ -335,44 +253,120 @@ func (o *rawSet) QueryRow(containers ...interface{}) error { ...@@ -335,44 +253,120 @@ func (o *rawSet) QueryRow(containers ...interface{}) error {
335 if typ.Kind() == reflect.Ptr { 253 if typ.Kind() == reflect.Ptr {
336 typ = typ.Elem() 254 typ = typ.Elem()
337 } 255 }
338 if typ.Kind() == reflect.Ptr {
339 typ = typ.Elem()
340 }
341 256
342 sInds = append(sInds, ind) 257 sInds = append(sInds, ind)
343 eTyps = append(eTyps, etyp) 258 eTyps = append(eTyps, etyp)
344 259
345 o.loopInitRefs(typ, &refs, &sIdxes) 260 if typ.Kind() == reflect.Struct && typ.String() != "time.Time" {
261 if len(containers) > 1 {
262 panic(fmt.Errorf("<RawSeter.QueryRow> now support one struct only. see #384"))
263 }
264
265 structMode = true
266 fn := getFullName(typ)
267 if mi, ok := modelCache.getByFN(fn); ok {
268 sMi = mi
269 }
270 } else {
271 var ref interface{}
272 refs = append(refs, &ref)
273 }
346 } 274 }
347 275
348 query := o.query 276 query := o.query
349 o.orm.alias.DbBaser.ReplaceMarks(&query) 277 o.orm.alias.DbBaser.ReplaceMarks(&query)
350 278
351 args := getFlatParams(nil, o.args, o.orm.alias.TZ) 279 args := getFlatParams(nil, o.args, o.orm.alias.TZ)
352 row := o.orm.db.QueryRow(query, args...) 280 rows, err := o.orm.db.Query(query, args...)
353 281 if err != nil {
354 if err := row.Scan(refs...); err == sql.ErrNoRows { 282 if err == sql.ErrNoRows {
355 return ErrNoRows 283 return ErrNoRows
356 } else if err != nil { 284 }
357 return err 285 return err
358 } 286 }
359 287
360 nInds := make([]reflect.Value, len(sInds)) 288 if rows.Next() {
361 o.loopSetRefs(refs, sIdxes, sInds, &nInds, eTyps, true) 289 if structMode {
362 for i, sInd := range sInds { 290 columns, err := rows.Columns()
363 nInd := nInds[i] 291 if err != nil {
364 sInd.Set(nInd) 292 return err
293 }
294
295 columnsMp := make(map[string]interface{}, len(columns))
296
297 refs = make([]interface{}, 0, len(columns))
298 for _, col := range columns {
299 var ref interface{}
300 columnsMp[col] = &ref
301 refs = append(refs, &ref)
302 }
303
304 if err := rows.Scan(refs...); err != nil {
305 return err
306 }
307
308 ind := sInds[0]
309
310 if ind.Kind() == reflect.Ptr {
311 if ind.IsNil() || !ind.IsValid() {
312 ind.Set(reflect.New(eTyps[0].Elem()))
313 }
314 ind = ind.Elem()
315 }
316
317 if sMi != nil {
318 for _, col := range columns {
319 if fi := sMi.fields.GetByColumn(col); fi != nil {
320 value := reflect.ValueOf(columnsMp[col]).Elem().Interface()
321 o.setFieldValue(ind.FieldByIndex([]int{fi.fieldIndex}), value)
322 }
323 }
324 } else {
325 for i := 0; i < ind.NumField(); i++ {
326 f := ind.Field(i)
327 fe := ind.Type().Field(i)
328
329 var attrs map[string]bool
330 var tags map[string]string
331 parseStructTag(fe.Tag.Get("orm"), &attrs, &tags)
332 var col string
333 if col = tags["column"]; len(col) == 0 {
334 col = snakeString(fe.Name)
335 }
336 if v, ok := columnsMp[col]; ok {
337 value := reflect.ValueOf(v).Elem().Interface()
338 o.setFieldValue(f, value)
339 }
340 }
341 }
342
343 } else {
344 if err := rows.Scan(refs...); err != nil {
345 return err
346 }
347
348 nInds := make([]reflect.Value, len(sInds))
349 o.loopSetRefs(refs, sInds, &nInds, eTyps, true)
350 for i, sInd := range sInds {
351 nInd := nInds[i]
352 sInd.Set(nInd)
353 }
354 }
355
356 } else {
357 return ErrNoRows
365 } 358 }
366 359
367 return nil 360 return nil
368 } 361 }
369 362
370 func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) { 363 func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) {
371 refs := make([]interface{}, 0) 364 refs := make([]interface{}, 0, len(containers))
372 sIdxes := make([][]int, 0)
373 sInds := make([]reflect.Value, 0) 365 sInds := make([]reflect.Value, 0)
374 eTyps := make([]reflect.Type, 0) 366 eTyps := make([]reflect.Type, 0)
375 367
368 structMode := false
369 var sMi *modelInfo
376 for _, container := range containers { 370 for _, container := range containers {
377 val := reflect.ValueOf(container) 371 val := reflect.ValueOf(container)
378 sInd := reflect.Indirect(val) 372 sInd := reflect.Indirect(val)
...@@ -389,7 +383,20 @@ func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) { ...@@ -389,7 +383,20 @@ func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) {
389 sInds = append(sInds, sInd) 383 sInds = append(sInds, sInd)
390 eTyps = append(eTyps, etyp) 384 eTyps = append(eTyps, etyp)
391 385
392 o.loopInitRefs(typ, &refs, &sIdxes) 386 if typ.Kind() == reflect.Struct && typ.String() != "time.Time" {
387 if len(containers) > 1 {
388 panic(fmt.Errorf("<RawSeter.QueryRow> now support one struct only. see #384"))
389 }
390
391 structMode = true
392 fn := getFullName(typ)
393 if mi, ok := modelCache.getByFN(fn); ok {
394 sMi = mi
395 }
396 } else {
397 var ref interface{}
398 refs = append(refs, &ref)
399 }
393 } 400 }
394 401
395 query := o.query 402 query := o.query
...@@ -403,21 +410,97 @@ func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) { ...@@ -403,21 +410,97 @@ func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) {
403 410
404 nInds := make([]reflect.Value, len(sInds)) 411 nInds := make([]reflect.Value, len(sInds))
405 412
413 sInd := sInds[0]
414
406 var cnt int64 415 var cnt int64
407 for rows.Next() { 416 for rows.Next() {
408 if err := rows.Scan(refs...); err != nil {
409 return 0, err
410 }
411 417
412 o.loopSetRefs(refs, sIdxes, sInds, &nInds, eTyps, cnt == 0) 418 if structMode {
419 columns, err := rows.Columns()
420 if err != nil {
421 return 0, err
422 }
423
424 columnsMp := make(map[string]interface{}, len(columns))
425
426 refs = make([]interface{}, 0, len(columns))
427 for _, col := range columns {
428 var ref interface{}
429 columnsMp[col] = &ref
430 refs = append(refs, &ref)
431 }
432
433 if err := rows.Scan(refs...); err != nil {
434 return 0, err
435 }
436
437 if cnt == 0 && !sInd.IsNil() {
438 sInd.Set(reflect.New(sInd.Type()).Elem())
439 }
440
441 var ind reflect.Value
442 if eTyps[0].Kind() == reflect.Ptr {
443 ind = reflect.New(eTyps[0].Elem())
444 } else {
445 ind = reflect.New(eTyps[0])
446 }
447
448 if ind.Kind() == reflect.Ptr {
449 ind = ind.Elem()
450 }
451
452 if sMi != nil {
453 for _, col := range columns {
454 if fi := sMi.fields.GetByColumn(col); fi != nil {
455 value := reflect.ValueOf(columnsMp[col]).Elem().Interface()
456 o.setFieldValue(ind.FieldByIndex([]int{fi.fieldIndex}), value)
457 }
458 }
459 } else {
460 for i := 0; i < ind.NumField(); i++ {
461 f := ind.Field(i)
462 fe := ind.Type().Field(i)
463
464 var attrs map[string]bool
465 var tags map[string]string
466 parseStructTag(fe.Tag.Get("orm"), &attrs, &tags)
467 var col string
468 if col = tags["column"]; len(col) == 0 {
469 col = snakeString(fe.Name)
470 }
471 if v, ok := columnsMp[col]; ok {
472 value := reflect.ValueOf(v).Elem().Interface()
473 o.setFieldValue(f, value)
474 }
475 }
476 }
477
478 if eTyps[0].Kind() == reflect.Ptr {
479 ind = ind.Addr()
480 }
481
482 sInd = reflect.Append(sInd, ind)
483
484 } else {
485 if err := rows.Scan(refs...); err != nil {
486 return 0, err
487 }
488
489 o.loopSetRefs(refs, sInds, &nInds, eTyps, cnt == 0)
490 }
413 491
414 cnt++ 492 cnt++
415 } 493 }
416 494
417 if cnt > 0 { 495 if cnt > 0 {
418 for i, sInd := range sInds { 496
419 nInd := nInds[i] 497 if structMode {
420 sInd.Set(nInd) 498 sInds[0].Set(sInd)
499 } else {
500 for i, sInd := range sInds {
501 nInd := nInds[i]
502 sInd.Set(nInd)
503 }
421 } 504 }
422 } 505 }
423 506
......
...@@ -1322,58 +1322,6 @@ func TestRawQueryRow(t *testing.T) { ...@@ -1322,58 +1322,6 @@ func TestRawQueryRow(t *testing.T) {
1322 } 1322 }
1323 } 1323 }
1324 1324
1325 type Tmp struct {
1326 Skip0 string
1327 Id int
1328 Char *string
1329 Skip1 int `orm:"-"`
1330 Date time.Time
1331 DateTime time.Time
1332 }
1333
1334 Boolean = false
1335 Text = ""
1336 Int64 = 0
1337 Uint = 0
1338
1339 tmp := new(Tmp)
1340
1341 cols = []string{
1342 "int", "char", "date", "datetime", "boolean", "text", "int64", "uint",
1343 }
1344 query = fmt.Sprintf("SELECT NULL, %s%s%s FROM data WHERE id = ?", Q, strings.Join(cols, sep), Q)
1345 values = []interface{}{
1346 tmp, &Boolean, &Text, &Int64, &Uint,
1347 }
1348 err = dORM.Raw(query, 1).QueryRow(values...)
1349 throwFailNow(t, err)
1350
1351 for _, col := range cols {
1352 switch col {
1353 case "id":
1354 throwFail(t, AssertIs(tmp.Id, data_values[col]))
1355 case "char":
1356 c := tmp.Char
1357 throwFail(t, AssertIs(*c, data_values[col]))
1358 case "date":
1359 v := tmp.Date.In(DefaultTimeLoc)
1360 value := data_values[col].(time.Time).In(DefaultTimeLoc)
1361 throwFail(t, AssertIs(v, value, test_Date))
1362 case "datetime":
1363 v := tmp.DateTime.In(DefaultTimeLoc)
1364 value := data_values[col].(time.Time).In(DefaultTimeLoc)
1365 throwFail(t, AssertIs(v, value, test_DateTime))
1366 case "boolean":
1367 throwFail(t, AssertIs(Boolean, data_values[col]))
1368 case "text":
1369 throwFail(t, AssertIs(Text, data_values[col]))
1370 case "int64":
1371 throwFail(t, AssertIs(Int64, data_values[col]))
1372 case "uint":
1373 throwFail(t, AssertIs(Uint, data_values[col]))
1374 }
1375 }
1376
1377 var ( 1325 var (
1378 uid int 1326 uid int
1379 status *int 1327 status *int
...@@ -1394,22 +1342,13 @@ func TestRawQueryRow(t *testing.T) { ...@@ -1394,22 +1342,13 @@ func TestRawQueryRow(t *testing.T) {
1394 func TestQueryRows(t *testing.T) { 1342 func TestQueryRows(t *testing.T) {
1395 Q := dDbBaser.TableQuote() 1343 Q := dDbBaser.TableQuote()
1396 1344
1397 cols := []string{
1398 "id", "boolean", "char", "text", "date", "datetime", "byte", "rune", "int", "int8", "int16", "int32",
1399 "int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64", "decimal",
1400 }
1401
1402 var datas []*Data 1345 var datas []*Data
1403 var dids []int
1404 1346
1405 sep := fmt.Sprintf("%s, %s", Q, Q) 1347 query := fmt.Sprintf("SELECT * FROM %sdata%s", Q, Q)
1406 query := fmt.Sprintf("SELECT %s%s%s, id FROM %sdata%s", Q, strings.Join(cols, sep), Q, Q, Q) 1348 num, err := dORM.Raw(query).QueryRows(&datas)
1407 num, err := dORM.Raw(query).QueryRows(&datas, &dids)
1408 throwFailNow(t, err) 1349 throwFailNow(t, err)
1409 throwFailNow(t, AssertIs(num, 1)) 1350 throwFailNow(t, AssertIs(num, 1))
1410 throwFailNow(t, AssertIs(len(datas), 1)) 1351 throwFailNow(t, AssertIs(len(datas), 1))
1411 throwFailNow(t, AssertIs(len(dids), 1))
1412 throwFailNow(t, AssertIs(dids[0], 1))
1413 1352
1414 ind := reflect.Indirect(reflect.ValueOf(datas[0])) 1353 ind := reflect.Indirect(reflect.ValueOf(datas[0]))
1415 1354
...@@ -1427,90 +1366,42 @@ func TestQueryRows(t *testing.T) { ...@@ -1427,90 +1366,42 @@ func TestQueryRows(t *testing.T) {
1427 throwFail(t, AssertIs(vu == value, true), value, vu) 1366 throwFail(t, AssertIs(vu == value, true), value, vu)
1428 } 1367 }
1429 1368
1430 type Tmp struct { 1369 var datas2 []Data
1431 Id int
1432 Name string
1433 Skiped0 string `orm:"-"`
1434 Pid *int
1435 Skiped1 Data
1436 Skiped2 *Data
1437 }
1438 1370
1439 var ( 1371 query = fmt.Sprintf("SELECT * FROM %sdata%s", Q, Q)
1440 ids []int 1372 num, err = dORM.Raw(query).QueryRows(&datas2)
1441 userNames []string
1442 profileIds1 []int
1443 profileIds2 []*int
1444 createds []time.Time
1445 updateds []time.Time
1446 tmps1 []*Tmp
1447 tmps2 []Tmp
1448 )
1449 cols = []string{
1450 "id", "user_name", "profile_id", "profile_id", "id", "user_name", "profile_id", "id", "user_name", "profile_id", "created", "updated",
1451 }
1452 query = fmt.Sprintf("SELECT %s%s%s FROM %suser%s ORDER BY id", Q, strings.Join(cols, sep), Q, Q, Q)
1453 num, err = dORM.Raw(query).QueryRows(&ids, &userNames, &profileIds1, &profileIds2, &tmps1, &tmps2, &createds, &updateds)
1454 throwFailNow(t, err) 1373 throwFailNow(t, err)
1455 throwFailNow(t, AssertIs(num, 3)) 1374 throwFailNow(t, AssertIs(num, 1))
1375 throwFailNow(t, AssertIs(len(datas2), 1))
1456 1376
1457 var users []User 1377 ind = reflect.Indirect(reflect.ValueOf(datas2[0]))
1458 dORM.QueryTable("user").OrderBy("Id").All(&users)
1459
1460 for i := 0; i < 3; i++ {
1461 id := ids[i]
1462 name := userNames[i]
1463 pid1 := profileIds1[i]
1464 pid2 := profileIds2[i]
1465 created := createds[i]
1466 updated := updateds[i]
1467
1468 user := users[i]
1469 throwFailNow(t, AssertIs(id, user.Id))
1470 throwFailNow(t, AssertIs(name, user.UserName))
1471 if user.Profile != nil {
1472 throwFailNow(t, AssertIs(pid1, user.Profile.Id))
1473 throwFailNow(t, AssertIs(*pid2, user.Profile.Id))
1474 } else {
1475 throwFailNow(t, AssertIs(pid1, 0))
1476 throwFailNow(t, AssertIs(pid2, nil))
1477 }
1478 throwFailNow(t, AssertIs(created, user.Created, test_Date))
1479 throwFailNow(t, AssertIs(updated, user.Updated, test_DateTime))
1480
1481 tmp := tmps1[i]
1482 tmp1 := *tmp
1483 throwFailNow(t, AssertIs(tmp1.Id, user.Id))
1484 throwFailNow(t, AssertIs(tmp1.Name, user.UserName))
1485 if user.Profile != nil {
1486 pid := tmp1.Pid
1487 throwFailNow(t, AssertIs(*pid, user.Profile.Id))
1488 } else {
1489 throwFailNow(t, AssertIs(tmp1.Pid, nil))
1490 }
1491 1378
1492 tmp2 := tmps2[i] 1379 for name, value := range Data_Values {
1493 throwFailNow(t, AssertIs(tmp2.Id, user.Id)) 1380 e := ind.FieldByName(name)
1494 throwFailNow(t, AssertIs(tmp2.Name, user.UserName)) 1381 vu := e.Interface()
1495 if user.Profile != nil { 1382 switch name {
1496 pid := tmp2.Pid 1383 case "Date":
1497 throwFailNow(t, AssertIs(*pid, user.Profile.Id)) 1384 vu = vu.(time.Time).In(DefaultTimeLoc).Format(test_Date)
1498 } else { 1385 value = value.(time.Time).In(DefaultTimeLoc).Format(test_Date)
1499 throwFailNow(t, AssertIs(tmp2.Pid, nil)) 1386 case "DateTime":
1387 vu = vu.(time.Time).In(DefaultTimeLoc).Format(test_DateTime)
1388 value = value.(time.Time).In(DefaultTimeLoc).Format(test_DateTime)
1500 } 1389 }
1390 throwFail(t, AssertIs(vu == value, true), value, vu)
1501 } 1391 }
1502 1392
1503 type Sec struct { 1393 var ids []int
1504 Id int 1394 var usernames []string
1505 Name string 1395 num, err = dORM.Raw("SELECT id, user_name FROM user ORDER BY id asc").QueryRows(&ids, &usernames)
1506 } 1396 throwFailNow(t, err)
1507 1397 throwFailNow(t, AssertIs(num, 3))
1508 var tmp []*Sec 1398 throwFailNow(t, AssertIs(len(ids), 3))
1509 query = fmt.Sprintf("SELECT NULL, NULL FROM %suser%s LIMIT 1", Q, Q) 1399 throwFailNow(t, AssertIs(ids[0], 2))
1510 num, err = dORM.Raw(query).QueryRows(&tmp) 1400 throwFailNow(t, AssertIs(usernames[0], "slene"))
1511 throwFail(t, err) 1401 throwFailNow(t, AssertIs(ids[1], 3))
1512 throwFail(t, AssertIs(num, 1)) 1402 throwFailNow(t, AssertIs(usernames[1], "astaxie"))
1513 throwFail(t, AssertIs(tmp[0], nil)) 1403 throwFailNow(t, AssertIs(ids[2], 4))
1404 throwFailNow(t, AssertIs(usernames[2], "nobody"))
1514 } 1405 }
1515 1406
1516 func TestRawValues(t *testing.T) { 1407 func TestRawValues(t *testing.T) {
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!