value_test.go 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214
  1. // Copyright 2015 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package bigquery
  15. import (
  16. "encoding/base64"
  17. "fmt"
  18. "math"
  19. "math/big"
  20. "testing"
  21. "time"
  22. "cloud.google.com/go/civil"
  23. "cloud.google.com/go/internal/testutil"
  24. "github.com/google/go-cmp/cmp"
  25. bq "google.golang.org/api/bigquery/v2"
  26. )
  27. func TestConvertBasicValues(t *testing.T) {
  28. schema := Schema{
  29. {Type: StringFieldType},
  30. {Type: IntegerFieldType},
  31. {Type: FloatFieldType},
  32. {Type: BooleanFieldType},
  33. {Type: BytesFieldType},
  34. {Type: NumericFieldType},
  35. }
  36. row := &bq.TableRow{
  37. F: []*bq.TableCell{
  38. {V: "a"},
  39. {V: "1"},
  40. {V: "1.2"},
  41. {V: "true"},
  42. {V: base64.StdEncoding.EncodeToString([]byte("foo"))},
  43. {V: "123.123456789"},
  44. },
  45. }
  46. got, err := convertRow(row, schema)
  47. if err != nil {
  48. t.Fatalf("error converting: %v", err)
  49. }
  50. want := []Value{"a", int64(1), 1.2, true, []byte("foo"), big.NewRat(123123456789, 1e9)}
  51. if !testutil.Equal(got, want) {
  52. t.Errorf("converting basic values: got:\n%v\nwant:\n%v", got, want)
  53. }
  54. }
  55. func TestConvertTime(t *testing.T) {
  56. schema := Schema{
  57. {Type: TimestampFieldType},
  58. {Type: DateFieldType},
  59. {Type: TimeFieldType},
  60. {Type: DateTimeFieldType},
  61. }
  62. ts := testTimestamp.Round(time.Millisecond)
  63. row := &bq.TableRow{
  64. F: []*bq.TableCell{
  65. {V: fmt.Sprintf("%.10f", float64(ts.UnixNano())/1e9)},
  66. {V: testDate.String()},
  67. {V: testTime.String()},
  68. {V: testDateTime.String()},
  69. },
  70. }
  71. got, err := convertRow(row, schema)
  72. if err != nil {
  73. t.Fatalf("error converting: %v", err)
  74. }
  75. want := []Value{ts, testDate, testTime, testDateTime}
  76. for i, g := range got {
  77. w := want[i]
  78. if !testutil.Equal(g, w) {
  79. t.Errorf("#%d: got:\n%v\nwant:\n%v", i, g, w)
  80. }
  81. }
  82. if got[0].(time.Time).Location() != time.UTC {
  83. t.Errorf("expected time zone UTC: got:\n%v", got)
  84. }
  85. }
  86. func TestConvertSmallTimes(t *testing.T) {
  87. for _, year := range []int{1600, 1066, 1} {
  88. want := time.Date(year, time.January, 1, 0, 0, 0, 0, time.UTC)
  89. s := fmt.Sprintf("%.10f", float64(want.Unix()))
  90. got, err := convertBasicType(s, TimestampFieldType)
  91. if err != nil {
  92. t.Fatal(err)
  93. }
  94. if !got.(time.Time).Equal(want) {
  95. t.Errorf("got %v, want %v", got, want)
  96. }
  97. }
  98. }
  99. func TestConvertNullValues(t *testing.T) {
  100. schema := Schema{{Type: StringFieldType}}
  101. row := &bq.TableRow{
  102. F: []*bq.TableCell{
  103. {V: nil},
  104. },
  105. }
  106. got, err := convertRow(row, schema)
  107. if err != nil {
  108. t.Fatalf("error converting: %v", err)
  109. }
  110. want := []Value{nil}
  111. if !testutil.Equal(got, want) {
  112. t.Errorf("converting null values: got:\n%v\nwant:\n%v", got, want)
  113. }
  114. }
  115. func TestBasicRepetition(t *testing.T) {
  116. schema := Schema{
  117. {Type: IntegerFieldType, Repeated: true},
  118. }
  119. row := &bq.TableRow{
  120. F: []*bq.TableCell{
  121. {
  122. V: []interface{}{
  123. map[string]interface{}{
  124. "v": "1",
  125. },
  126. map[string]interface{}{
  127. "v": "2",
  128. },
  129. map[string]interface{}{
  130. "v": "3",
  131. },
  132. },
  133. },
  134. },
  135. }
  136. got, err := convertRow(row, schema)
  137. if err != nil {
  138. t.Fatalf("error converting: %v", err)
  139. }
  140. want := []Value{[]Value{int64(1), int64(2), int64(3)}}
  141. if !testutil.Equal(got, want) {
  142. t.Errorf("converting basic repeated values: got:\n%v\nwant:\n%v", got, want)
  143. }
  144. }
  145. func TestNestedRecordContainingRepetition(t *testing.T) {
  146. schema := Schema{
  147. {
  148. Type: RecordFieldType,
  149. Schema: Schema{
  150. {Type: IntegerFieldType, Repeated: true},
  151. },
  152. },
  153. }
  154. row := &bq.TableRow{
  155. F: []*bq.TableCell{
  156. {
  157. V: map[string]interface{}{
  158. "f": []interface{}{
  159. map[string]interface{}{
  160. "v": []interface{}{
  161. map[string]interface{}{"v": "1"},
  162. map[string]interface{}{"v": "2"},
  163. map[string]interface{}{"v": "3"},
  164. },
  165. },
  166. },
  167. },
  168. },
  169. },
  170. }
  171. got, err := convertRow(row, schema)
  172. if err != nil {
  173. t.Fatalf("error converting: %v", err)
  174. }
  175. want := []Value{[]Value{[]Value{int64(1), int64(2), int64(3)}}}
  176. if !testutil.Equal(got, want) {
  177. t.Errorf("converting basic repeated values: got:\n%v\nwant:\n%v", got, want)
  178. }
  179. }
  180. func TestRepeatedRecordContainingRepetition(t *testing.T) {
  181. schema := Schema{
  182. {
  183. Type: RecordFieldType,
  184. Repeated: true,
  185. Schema: Schema{
  186. {Type: IntegerFieldType, Repeated: true},
  187. },
  188. },
  189. }
  190. row := &bq.TableRow{F: []*bq.TableCell{
  191. {
  192. V: []interface{}{ // repeated records.
  193. map[string]interface{}{ // first record.
  194. "v": map[string]interface{}{ // pointless single-key-map wrapper.
  195. "f": []interface{}{ // list of record fields.
  196. map[string]interface{}{ // only record (repeated ints)
  197. "v": []interface{}{ // pointless wrapper.
  198. map[string]interface{}{
  199. "v": "1",
  200. },
  201. map[string]interface{}{
  202. "v": "2",
  203. },
  204. map[string]interface{}{
  205. "v": "3",
  206. },
  207. },
  208. },
  209. },
  210. },
  211. },
  212. map[string]interface{}{ // second record.
  213. "v": map[string]interface{}{
  214. "f": []interface{}{
  215. map[string]interface{}{
  216. "v": []interface{}{
  217. map[string]interface{}{
  218. "v": "4",
  219. },
  220. map[string]interface{}{
  221. "v": "5",
  222. },
  223. map[string]interface{}{
  224. "v": "6",
  225. },
  226. },
  227. },
  228. },
  229. },
  230. },
  231. },
  232. },
  233. }}
  234. got, err := convertRow(row, schema)
  235. if err != nil {
  236. t.Fatalf("error converting: %v", err)
  237. }
  238. want := []Value{ // the row is a list of length 1, containing an entry for the repeated record.
  239. []Value{ // the repeated record is a list of length 2, containing an entry for each repetition.
  240. []Value{ // the record is a list of length 1, containing an entry for the repeated integer field.
  241. []Value{int64(1), int64(2), int64(3)}, // the repeated integer field is a list of length 3.
  242. },
  243. []Value{ // second record
  244. []Value{int64(4), int64(5), int64(6)},
  245. },
  246. },
  247. }
  248. if !testutil.Equal(got, want) {
  249. t.Errorf("converting repeated records with repeated values: got:\n%v\nwant:\n%v", got, want)
  250. }
  251. }
  252. func TestRepeatedRecordContainingRecord(t *testing.T) {
  253. schema := Schema{
  254. {
  255. Type: RecordFieldType,
  256. Repeated: true,
  257. Schema: Schema{
  258. {
  259. Type: StringFieldType,
  260. },
  261. {
  262. Type: RecordFieldType,
  263. Schema: Schema{
  264. {Type: IntegerFieldType},
  265. {Type: StringFieldType},
  266. },
  267. },
  268. },
  269. },
  270. }
  271. row := &bq.TableRow{F: []*bq.TableCell{
  272. {
  273. V: []interface{}{ // repeated records.
  274. map[string]interface{}{ // first record.
  275. "v": map[string]interface{}{ // pointless single-key-map wrapper.
  276. "f": []interface{}{ // list of record fields.
  277. map[string]interface{}{ // first record field (name)
  278. "v": "first repeated record",
  279. },
  280. map[string]interface{}{ // second record field (nested record).
  281. "v": map[string]interface{}{ // pointless single-key-map wrapper.
  282. "f": []interface{}{ // nested record fields
  283. map[string]interface{}{
  284. "v": "1",
  285. },
  286. map[string]interface{}{
  287. "v": "two",
  288. },
  289. },
  290. },
  291. },
  292. },
  293. },
  294. },
  295. map[string]interface{}{ // second record.
  296. "v": map[string]interface{}{
  297. "f": []interface{}{
  298. map[string]interface{}{
  299. "v": "second repeated record",
  300. },
  301. map[string]interface{}{
  302. "v": map[string]interface{}{
  303. "f": []interface{}{
  304. map[string]interface{}{
  305. "v": "3",
  306. },
  307. map[string]interface{}{
  308. "v": "four",
  309. },
  310. },
  311. },
  312. },
  313. },
  314. },
  315. },
  316. },
  317. },
  318. }}
  319. got, err := convertRow(row, schema)
  320. if err != nil {
  321. t.Fatalf("error converting: %v", err)
  322. }
  323. // TODO: test with flattenresults.
  324. want := []Value{ // the row is a list of length 1, containing an entry for the repeated record.
  325. []Value{ // the repeated record is a list of length 2, containing an entry for each repetition.
  326. []Value{ // record contains a string followed by a nested record.
  327. "first repeated record",
  328. []Value{
  329. int64(1),
  330. "two",
  331. },
  332. },
  333. []Value{ // second record.
  334. "second repeated record",
  335. []Value{
  336. int64(3),
  337. "four",
  338. },
  339. },
  340. },
  341. }
  342. if !testutil.Equal(got, want) {
  343. t.Errorf("converting repeated records containing record : got:\n%v\nwant:\n%v", got, want)
  344. }
  345. }
  346. func TestConvertRowErrors(t *testing.T) {
  347. // mismatched lengths
  348. if _, err := convertRow(&bq.TableRow{F: []*bq.TableCell{{V: ""}}}, Schema{}); err == nil {
  349. t.Error("got nil, want error")
  350. }
  351. v3 := map[string]interface{}{"v": 3}
  352. for _, test := range []struct {
  353. value interface{}
  354. fs FieldSchema
  355. }{
  356. {3, FieldSchema{Type: IntegerFieldType}}, // not a string
  357. {[]interface{}{v3}, // not a string, repeated
  358. FieldSchema{Type: IntegerFieldType, Repeated: true}},
  359. {map[string]interface{}{"f": []interface{}{v3}}, // not a string, nested
  360. FieldSchema{Type: RecordFieldType, Schema: Schema{{Type: IntegerFieldType}}}},
  361. {map[string]interface{}{"f": []interface{}{v3}}, // wrong length, nested
  362. FieldSchema{Type: RecordFieldType, Schema: Schema{}}},
  363. } {
  364. _, err := convertRow(
  365. &bq.TableRow{F: []*bq.TableCell{{V: test.value}}},
  366. Schema{&test.fs})
  367. if err == nil {
  368. t.Errorf("value %v, fs %v: got nil, want error", test.value, test.fs)
  369. }
  370. }
  371. // bad field type
  372. if _, err := convertBasicType("", FieldType("BAD")); err == nil {
  373. t.Error("got nil, want error")
  374. }
  375. }
  376. func TestValuesSaverConvertsToMap(t *testing.T) {
  377. testCases := []struct {
  378. vs ValuesSaver
  379. wantInsertID string
  380. wantRow map[string]Value
  381. }{
  382. {
  383. vs: ValuesSaver{
  384. Schema: Schema{
  385. {Name: "intField", Type: IntegerFieldType},
  386. {Name: "strField", Type: StringFieldType},
  387. {Name: "dtField", Type: DateTimeFieldType},
  388. {Name: "nField", Type: NumericFieldType},
  389. },
  390. InsertID: "iid",
  391. Row: []Value{1, "a",
  392. civil.DateTime{
  393. Date: civil.Date{Year: 1, Month: 2, Day: 3},
  394. Time: civil.Time{Hour: 4, Minute: 5, Second: 6, Nanosecond: 7000}},
  395. big.NewRat(123456789000, 1e9),
  396. },
  397. },
  398. wantInsertID: "iid",
  399. wantRow: map[string]Value{
  400. "intField": 1,
  401. "strField": "a",
  402. "dtField": "0001-02-03 04:05:06.000007",
  403. "nField": "123.456789000",
  404. },
  405. },
  406. {
  407. vs: ValuesSaver{
  408. Schema: Schema{
  409. {Name: "intField", Type: IntegerFieldType},
  410. {
  411. Name: "recordField",
  412. Type: RecordFieldType,
  413. Schema: Schema{
  414. {Name: "nestedInt", Type: IntegerFieldType, Repeated: true},
  415. },
  416. },
  417. },
  418. InsertID: "iid",
  419. Row: []Value{1, []Value{[]Value{2, 3}}},
  420. },
  421. wantInsertID: "iid",
  422. wantRow: map[string]Value{
  423. "intField": 1,
  424. "recordField": map[string]Value{
  425. "nestedInt": []Value{2, 3},
  426. },
  427. },
  428. },
  429. { // repeated nested field
  430. vs: ValuesSaver{
  431. Schema: Schema{
  432. {
  433. Name: "records",
  434. Type: RecordFieldType,
  435. Schema: Schema{
  436. {Name: "x", Type: IntegerFieldType},
  437. {Name: "y", Type: IntegerFieldType},
  438. },
  439. Repeated: true,
  440. },
  441. },
  442. InsertID: "iid",
  443. Row: []Value{ // a row is a []Value
  444. []Value{ // repeated field's value is a []Value
  445. []Value{1, 2}, // first record of the repeated field
  446. []Value{3, 4}, // second record
  447. },
  448. },
  449. },
  450. wantInsertID: "iid",
  451. wantRow: map[string]Value{
  452. "records": []Value{
  453. map[string]Value{"x": 1, "y": 2},
  454. map[string]Value{"x": 3, "y": 4},
  455. },
  456. },
  457. },
  458. }
  459. for _, tc := range testCases {
  460. gotRow, gotInsertID, err := tc.vs.Save()
  461. if err != nil {
  462. t.Errorf("Expected successful save; got: %v", err)
  463. continue
  464. }
  465. if !testutil.Equal(gotRow, tc.wantRow) {
  466. t.Errorf("%v row:\ngot:\n%+v\nwant:\n%+v", tc.vs, gotRow, tc.wantRow)
  467. }
  468. if !testutil.Equal(gotInsertID, tc.wantInsertID) {
  469. t.Errorf("%v ID:\ngot:\n%+v\nwant:\n%+v", tc.vs, gotInsertID, tc.wantInsertID)
  470. }
  471. }
  472. }
  473. func TestValuesToMapErrors(t *testing.T) {
  474. for _, test := range []struct {
  475. values []Value
  476. schema Schema
  477. }{
  478. { // mismatched length
  479. []Value{1},
  480. Schema{},
  481. },
  482. { // nested record not a slice
  483. []Value{1},
  484. Schema{{Type: RecordFieldType}},
  485. },
  486. { // nested record mismatched length
  487. []Value{[]Value{1}},
  488. Schema{{Type: RecordFieldType}},
  489. },
  490. { // nested repeated record not a slice
  491. []Value{[]Value{1}},
  492. Schema{{Type: RecordFieldType, Repeated: true}},
  493. },
  494. { // nested repeated record mismatched length
  495. []Value{[]Value{[]Value{1}}},
  496. Schema{{Type: RecordFieldType, Repeated: true}},
  497. },
  498. } {
  499. _, err := valuesToMap(test.values, test.schema)
  500. if err == nil {
  501. t.Errorf("%v, %v: got nil, want error", test.values, test.schema)
  502. }
  503. }
  504. }
  505. func TestStructSaver(t *testing.T) {
  506. schema := Schema{
  507. {Name: "s", Type: StringFieldType},
  508. {Name: "r", Type: IntegerFieldType, Repeated: true},
  509. {Name: "t", Type: TimeFieldType},
  510. {Name: "tr", Type: TimeFieldType, Repeated: true},
  511. {Name: "nested", Type: RecordFieldType, Schema: Schema{
  512. {Name: "b", Type: BooleanFieldType},
  513. }},
  514. {Name: "rnested", Type: RecordFieldType, Repeated: true, Schema: Schema{
  515. {Name: "b", Type: BooleanFieldType},
  516. }},
  517. {Name: "p", Type: IntegerFieldType, Required: false},
  518. {Name: "n", Type: NumericFieldType, Required: false},
  519. {Name: "nr", Type: NumericFieldType, Repeated: true},
  520. }
  521. type (
  522. N struct{ B bool }
  523. T struct {
  524. S string
  525. R []int
  526. T civil.Time
  527. TR []civil.Time
  528. Nested *N
  529. Rnested []*N
  530. P NullInt64
  531. N *big.Rat
  532. NR []*big.Rat
  533. }
  534. )
  535. check := func(msg string, in interface{}, want map[string]Value) {
  536. ss := StructSaver{
  537. Schema: schema,
  538. InsertID: "iid",
  539. Struct: in,
  540. }
  541. got, gotIID, err := ss.Save()
  542. if err != nil {
  543. t.Fatalf("%s: %v", msg, err)
  544. }
  545. if wantIID := "iid"; gotIID != wantIID {
  546. t.Errorf("%s: InsertID: got %q, want %q", msg, gotIID, wantIID)
  547. }
  548. if diff := testutil.Diff(got, want); diff != "" {
  549. t.Errorf("%s: %s", msg, diff)
  550. }
  551. }
  552. ct1 := civil.Time{Hour: 1, Minute: 2, Second: 3, Nanosecond: 4000}
  553. ct2 := civil.Time{Hour: 5, Minute: 6, Second: 7, Nanosecond: 8000}
  554. in := T{
  555. S: "x",
  556. R: []int{1, 2},
  557. T: ct1,
  558. TR: []civil.Time{ct1, ct2},
  559. Nested: &N{B: true},
  560. Rnested: []*N{{true}, {false}},
  561. P: NullInt64{Valid: true, Int64: 17},
  562. N: big.NewRat(123456, 1000),
  563. NR: []*big.Rat{big.NewRat(3, 1), big.NewRat(56789, 1e5)},
  564. }
  565. want := map[string]Value{
  566. "s": "x",
  567. "r": []int{1, 2},
  568. "t": "01:02:03.000004",
  569. "tr": []string{"01:02:03.000004", "05:06:07.000008"},
  570. "nested": map[string]Value{"b": true},
  571. "rnested": []Value{map[string]Value{"b": true}, map[string]Value{"b": false}},
  572. "p": NullInt64{Valid: true, Int64: 17},
  573. "n": "123.456000000",
  574. "nr": []string{"3.000000000", "0.567890000"},
  575. }
  576. check("all values", in, want)
  577. check("all values, ptr", &in, want)
  578. check("empty struct", T{}, map[string]Value{"s": "", "t": "00:00:00", "p": NullInt64{}})
  579. // Missing and extra fields ignored.
  580. type T2 struct {
  581. S string
  582. // missing R, Nested, RNested
  583. Extra int
  584. }
  585. check("missing and extra", T2{S: "x"}, map[string]Value{"s": "x"})
  586. check("nils in slice", T{Rnested: []*N{{true}, nil, {false}}},
  587. map[string]Value{
  588. "s": "",
  589. "t": "00:00:00",
  590. "p": NullInt64{},
  591. "rnested": []Value{map[string]Value{"b": true}, map[string]Value(nil), map[string]Value{"b": false}},
  592. })
  593. check("zero-length repeated", T{Rnested: []*N{}},
  594. map[string]Value{
  595. "rnested": []Value{},
  596. "s": "",
  597. "t": "00:00:00",
  598. "p": NullInt64{},
  599. })
  600. }
  601. func TestStructSaverErrors(t *testing.T) {
  602. type (
  603. badField struct {
  604. I int `bigquery:"@"`
  605. }
  606. badR struct{ R int }
  607. badRN struct{ R []int }
  608. )
  609. for i, test := range []struct {
  610. inputStruct interface{}
  611. schema Schema
  612. }{
  613. {0, nil}, // not a struct
  614. {&badField{}, nil}, // bad field name
  615. {&badR{}, Schema{{Name: "r", Repeated: true}}}, // repeated field has bad type
  616. {&badR{}, Schema{{Name: "r", Type: RecordFieldType}}}, // nested field has bad type
  617. {&badRN{[]int{0}}, // nested repeated field has bad type
  618. Schema{{Name: "r", Type: RecordFieldType, Repeated: true}}},
  619. } {
  620. ss := &StructSaver{Struct: test.inputStruct, Schema: test.schema}
  621. _, _, err := ss.Save()
  622. if err == nil {
  623. t.Errorf("#%d, %v, %v: got nil, want error", i, test.inputStruct, test.schema)
  624. }
  625. }
  626. }
  627. func TestNumericString(t *testing.T) {
  628. for _, test := range []struct {
  629. in *big.Rat
  630. want string
  631. }{
  632. {big.NewRat(2, 3), "0.666666667"}, // round to 9 places
  633. {big.NewRat(1, 2), "0.500000000"},
  634. {big.NewRat(1, 2*1e8), "0.000000005"},
  635. {big.NewRat(5, 1e10), "0.000000001"}, // round up the 5 in the 10th decimal place
  636. {big.NewRat(-5, 1e10), "-0.000000001"}, // round half away from zero
  637. } {
  638. got := NumericString(test.in)
  639. if got != test.want {
  640. t.Errorf("%v: got %q, want %q", test.in, got, test.want)
  641. }
  642. }
  643. }
  644. func TestConvertRows(t *testing.T) {
  645. schema := Schema{
  646. {Type: StringFieldType},
  647. {Type: IntegerFieldType},
  648. {Type: FloatFieldType},
  649. {Type: BooleanFieldType},
  650. }
  651. rows := []*bq.TableRow{
  652. {F: []*bq.TableCell{
  653. {V: "a"},
  654. {V: "1"},
  655. {V: "1.2"},
  656. {V: "true"},
  657. }},
  658. {F: []*bq.TableCell{
  659. {V: "b"},
  660. {V: "2"},
  661. {V: "2.2"},
  662. {V: "false"},
  663. }},
  664. }
  665. want := [][]Value{
  666. {"a", int64(1), 1.2, true},
  667. {"b", int64(2), 2.2, false},
  668. }
  669. got, err := convertRows(rows, schema)
  670. if err != nil {
  671. t.Fatalf("got %v, want nil", err)
  672. }
  673. if !testutil.Equal(got, want) {
  674. t.Errorf("\ngot %v\nwant %v", got, want)
  675. }
  676. rows[0].F[0].V = 1
  677. _, err = convertRows(rows, schema)
  678. if err == nil {
  679. t.Error("got nil, want error")
  680. }
  681. }
  682. func TestValueList(t *testing.T) {
  683. schema := Schema{
  684. {Name: "s", Type: StringFieldType},
  685. {Name: "i", Type: IntegerFieldType},
  686. {Name: "f", Type: FloatFieldType},
  687. {Name: "b", Type: BooleanFieldType},
  688. }
  689. want := []Value{"x", 7, 3.14, true}
  690. var got []Value
  691. vl := (*valueList)(&got)
  692. if err := vl.Load(want, schema); err != nil {
  693. t.Fatal(err)
  694. }
  695. if !testutil.Equal(got, want) {
  696. t.Errorf("got %+v, want %+v", got, want)
  697. }
  698. // Load truncates, not appends.
  699. // https://github.com/googleapis/google-cloud-go/issues/437
  700. if err := vl.Load(want, schema); err != nil {
  701. t.Fatal(err)
  702. }
  703. if !testutil.Equal(got, want) {
  704. t.Errorf("got %+v, want %+v", got, want)
  705. }
  706. }
  707. func TestValueMap(t *testing.T) {
  708. ns := Schema{
  709. {Name: "x", Type: IntegerFieldType},
  710. {Name: "y", Type: IntegerFieldType},
  711. }
  712. schema := Schema{
  713. {Name: "s", Type: StringFieldType},
  714. {Name: "i", Type: IntegerFieldType},
  715. {Name: "f", Type: FloatFieldType},
  716. {Name: "b", Type: BooleanFieldType},
  717. {Name: "n", Type: RecordFieldType, Schema: ns},
  718. {Name: "rn", Type: RecordFieldType, Schema: ns, Repeated: true},
  719. }
  720. in := []Value{"x", 7, 3.14, true,
  721. []Value{1, 2},
  722. []Value{[]Value{3, 4}, []Value{5, 6}},
  723. }
  724. var vm valueMap
  725. if err := vm.Load(in, schema); err != nil {
  726. t.Fatal(err)
  727. }
  728. want := map[string]Value{
  729. "s": "x",
  730. "i": 7,
  731. "f": 3.14,
  732. "b": true,
  733. "n": map[string]Value{"x": 1, "y": 2},
  734. "rn": []Value{
  735. map[string]Value{"x": 3, "y": 4},
  736. map[string]Value{"x": 5, "y": 6},
  737. },
  738. }
  739. if !testutil.Equal(vm, valueMap(want)) {
  740. t.Errorf("got\n%+v\nwant\n%+v", vm, want)
  741. }
  742. in = make([]Value, len(schema))
  743. want = map[string]Value{
  744. "s": nil,
  745. "i": nil,
  746. "f": nil,
  747. "b": nil,
  748. "n": nil,
  749. "rn": nil,
  750. }
  751. var vm2 valueMap
  752. if err := vm2.Load(in, schema); err != nil {
  753. t.Fatal(err)
  754. }
  755. if !testutil.Equal(vm2, valueMap(want)) {
  756. t.Errorf("got\n%+v\nwant\n%+v", vm2, want)
  757. }
  758. }
  759. var (
  760. // For testing StructLoader
  761. schema2 = Schema{
  762. {Name: "s", Type: StringFieldType},
  763. {Name: "s2", Type: StringFieldType},
  764. {Name: "by", Type: BytesFieldType},
  765. {Name: "I", Type: IntegerFieldType},
  766. {Name: "U", Type: IntegerFieldType},
  767. {Name: "F", Type: FloatFieldType},
  768. {Name: "B", Type: BooleanFieldType},
  769. {Name: "TS", Type: TimestampFieldType},
  770. {Name: "D", Type: DateFieldType},
  771. {Name: "T", Type: TimeFieldType},
  772. {Name: "DT", Type: DateTimeFieldType},
  773. {Name: "N", Type: NumericFieldType},
  774. {Name: "nested", Type: RecordFieldType, Schema: Schema{
  775. {Name: "nestS", Type: StringFieldType},
  776. {Name: "nestI", Type: IntegerFieldType},
  777. }},
  778. {Name: "t", Type: StringFieldType},
  779. }
  780. testTimestamp = time.Date(2016, 11, 5, 7, 50, 22, 8, time.UTC)
  781. testDate = civil.Date{Year: 2016, Month: 11, Day: 5}
  782. testTime = civil.Time{Hour: 7, Minute: 50, Second: 22, Nanosecond: 8}
  783. testDateTime = civil.DateTime{Date: testDate, Time: testTime}
  784. testNumeric = big.NewRat(123, 456)
  785. testValues = []Value{"x", "y", []byte{1, 2, 3}, int64(7), int64(8), 3.14, true,
  786. testTimestamp, testDate, testTime, testDateTime, testNumeric,
  787. []Value{"nested", int64(17)}, "z"}
  788. )
  789. type testStruct1 struct {
  790. B bool
  791. I int
  792. U uint16
  793. times
  794. S string
  795. S2 String
  796. By []byte
  797. F float64
  798. N *big.Rat
  799. Nested nested
  800. Tagged string `bigquery:"t"`
  801. }
  802. type String string
  803. type nested struct {
  804. NestS string
  805. NestI int
  806. }
  807. type times struct {
  808. TS time.Time
  809. T civil.Time
  810. D civil.Date
  811. DT civil.DateTime
  812. }
  813. func TestStructLoader(t *testing.T) {
  814. var ts1 testStruct1
  815. mustLoad(t, &ts1, schema2, testValues)
  816. // Note: the schema field named "s" gets matched to the exported struct
  817. // field "S", not the unexported "s".
  818. want := &testStruct1{
  819. B: true,
  820. I: 7,
  821. U: 8,
  822. F: 3.14,
  823. times: times{TS: testTimestamp, T: testTime, D: testDate, DT: testDateTime},
  824. S: "x",
  825. S2: "y",
  826. By: []byte{1, 2, 3},
  827. N: big.NewRat(123, 456),
  828. Nested: nested{NestS: "nested", NestI: 17},
  829. Tagged: "z",
  830. }
  831. if diff := testutil.Diff(&ts1, want, cmp.AllowUnexported(testStruct1{})); diff != "" {
  832. t.Error(diff)
  833. }
  834. // Test pointers to nested structs.
  835. type nestedPtr struct{ Nested *nested }
  836. var np nestedPtr
  837. mustLoad(t, &np, schema2, testValues)
  838. want2 := &nestedPtr{Nested: &nested{NestS: "nested", NestI: 17}}
  839. if diff := testutil.Diff(&np, want2); diff != "" {
  840. t.Error(diff)
  841. }
  842. // Existing values should be reused.
  843. nst := &nested{NestS: "x", NestI: -10}
  844. np = nestedPtr{Nested: nst}
  845. mustLoad(t, &np, schema2, testValues)
  846. if diff := testutil.Diff(&np, want2); diff != "" {
  847. t.Error(diff)
  848. }
  849. if np.Nested != nst {
  850. t.Error("nested struct pointers not equal")
  851. }
  852. }
  853. type repStruct struct {
  854. Nums []int
  855. ShortNums [2]int // to test truncation
  856. LongNums [5]int // to test padding with zeroes
  857. Nested []*nested
  858. }
  859. var (
  860. repSchema = Schema{
  861. {Name: "nums", Type: IntegerFieldType, Repeated: true},
  862. {Name: "shortNums", Type: IntegerFieldType, Repeated: true},
  863. {Name: "longNums", Type: IntegerFieldType, Repeated: true},
  864. {Name: "nested", Type: RecordFieldType, Repeated: true, Schema: Schema{
  865. {Name: "nestS", Type: StringFieldType},
  866. {Name: "nestI", Type: IntegerFieldType},
  867. }},
  868. }
  869. v123 = []Value{int64(1), int64(2), int64(3)}
  870. repValues = []Value{v123, v123, v123,
  871. []Value{
  872. []Value{"x", int64(1)},
  873. []Value{"y", int64(2)},
  874. },
  875. }
  876. )
  877. func TestStructLoaderRepeated(t *testing.T) {
  878. var r1 repStruct
  879. mustLoad(t, &r1, repSchema, repValues)
  880. want := repStruct{
  881. Nums: []int{1, 2, 3},
  882. ShortNums: [...]int{1, 2}, // extra values discarded
  883. LongNums: [...]int{1, 2, 3, 0, 0},
  884. Nested: []*nested{{"x", 1}, {"y", 2}},
  885. }
  886. if diff := testutil.Diff(r1, want); diff != "" {
  887. t.Error(diff)
  888. }
  889. r2 := repStruct{
  890. Nums: []int{-1, -2, -3, -4, -5}, // truncated to zero and appended to
  891. LongNums: [...]int{-1, -2, -3, -4, -5}, // unset elements are zeroed
  892. }
  893. mustLoad(t, &r2, repSchema, repValues)
  894. if diff := testutil.Diff(r2, want); diff != "" {
  895. t.Error(diff)
  896. }
  897. if got, want := cap(r2.Nums), 5; got != want {
  898. t.Errorf("cap(r2.Nums) = %d, want %d", got, want)
  899. }
  900. // Short slice case.
  901. r3 := repStruct{Nums: []int{-1}}
  902. mustLoad(t, &r3, repSchema, repValues)
  903. if diff := testutil.Diff(r3, want); diff != "" {
  904. t.Error(diff)
  905. }
  906. if got, want := cap(r3.Nums), 3; got != want {
  907. t.Errorf("cap(r3.Nums) = %d, want %d", got, want)
  908. }
  909. }
  910. type testStructNullable struct {
  911. String NullString
  912. Bytes []byte
  913. Integer NullInt64
  914. Float NullFloat64
  915. Boolean NullBool
  916. Timestamp NullTimestamp
  917. Date NullDate
  918. Time NullTime
  919. DateTime NullDateTime
  920. Numeric *big.Rat
  921. Record *subNullable
  922. }
  923. type subNullable struct {
  924. X NullInt64
  925. }
  926. var testStructNullableSchema = Schema{
  927. {Name: "String", Type: StringFieldType, Required: false},
  928. {Name: "Bytes", Type: BytesFieldType, Required: false},
  929. {Name: "Integer", Type: IntegerFieldType, Required: false},
  930. {Name: "Float", Type: FloatFieldType, Required: false},
  931. {Name: "Boolean", Type: BooleanFieldType, Required: false},
  932. {Name: "Timestamp", Type: TimestampFieldType, Required: false},
  933. {Name: "Date", Type: DateFieldType, Required: false},
  934. {Name: "Time", Type: TimeFieldType, Required: false},
  935. {Name: "DateTime", Type: DateTimeFieldType, Required: false},
  936. {Name: "Numeric", Type: NumericFieldType, Required: false},
  937. {Name: "Record", Type: RecordFieldType, Required: false, Schema: Schema{
  938. {Name: "X", Type: IntegerFieldType, Required: false},
  939. }},
  940. }
  941. func TestStructLoaderNullable(t *testing.T) {
  942. var ts testStructNullable
  943. nilVals := make([]Value, len(testStructNullableSchema))
  944. mustLoad(t, &ts, testStructNullableSchema, nilVals)
  945. want := testStructNullable{}
  946. if diff := testutil.Diff(ts, want); diff != "" {
  947. t.Error(diff)
  948. }
  949. nonnilVals := []Value{"x", []byte{1, 2, 3}, int64(1), 2.3, true, testTimestamp, testDate, testTime,
  950. testDateTime, big.NewRat(1, 2), []Value{int64(4)}}
  951. // All ts fields are nil. Loading non-nil values will cause them all to
  952. // be allocated.
  953. mustLoad(t, &ts, testStructNullableSchema, nonnilVals)
  954. want = testStructNullable{
  955. String: NullString{StringVal: "x", Valid: true},
  956. Bytes: []byte{1, 2, 3},
  957. Integer: NullInt64{Int64: 1, Valid: true},
  958. Float: NullFloat64{Float64: 2.3, Valid: true},
  959. Boolean: NullBool{Bool: true, Valid: true},
  960. Timestamp: NullTimestamp{Timestamp: testTimestamp, Valid: true},
  961. Date: NullDate{Date: testDate, Valid: true},
  962. Time: NullTime{Time: testTime, Valid: true},
  963. DateTime: NullDateTime{DateTime: testDateTime, Valid: true},
  964. Numeric: big.NewRat(1, 2),
  965. Record: &subNullable{X: NullInt64{Int64: 4, Valid: true}},
  966. }
  967. if diff := testutil.Diff(ts, want); diff != "" {
  968. t.Error(diff)
  969. }
  970. // Struct pointers are reused, byte slices are not.
  971. want = ts
  972. want.Bytes = []byte{17}
  973. vals2 := []Value{nil, []byte{17}, nil, nil, nil, nil, nil, nil, nil, nil, []Value{int64(7)}}
  974. mustLoad(t, &ts, testStructNullableSchema, vals2)
  975. if ts.Record != want.Record {
  976. t.Error("record pointers not identical")
  977. }
  978. }
  979. func TestStructLoaderOverflow(t *testing.T) {
  980. type S struct {
  981. I int16
  982. U uint16
  983. F float32
  984. }
  985. schema := Schema{
  986. {Name: "I", Type: IntegerFieldType},
  987. {Name: "U", Type: IntegerFieldType},
  988. {Name: "F", Type: FloatFieldType},
  989. }
  990. var s S
  991. z64 := int64(0)
  992. for _, vals := range [][]Value{
  993. {int64(math.MaxInt16 + 1), z64, 0},
  994. {z64, int64(math.MaxInt32), 0},
  995. {z64, int64(-1), 0},
  996. {z64, z64, math.MaxFloat32 * 2},
  997. } {
  998. if err := load(&s, schema, vals); err == nil {
  999. t.Errorf("%+v: got nil, want error", vals)
  1000. }
  1001. }
  1002. }
  1003. func TestStructLoaderFieldOverlap(t *testing.T) {
  1004. // It's OK if the struct has fields that the schema does not, and vice versa.
  1005. type S1 struct {
  1006. I int
  1007. X [][]int // not in the schema; does not even correspond to a valid BigQuery type
  1008. // many schema fields missing
  1009. }
  1010. var s1 S1
  1011. if err := load(&s1, schema2, testValues); err != nil {
  1012. t.Fatal(err)
  1013. }
  1014. want1 := S1{I: 7}
  1015. if diff := testutil.Diff(s1, want1); diff != "" {
  1016. t.Error(diff)
  1017. }
  1018. // It's even valid to have no overlapping fields at all.
  1019. type S2 struct{ Z int }
  1020. var s2 S2
  1021. mustLoad(t, &s2, schema2, testValues)
  1022. want2 := S2{}
  1023. if diff := testutil.Diff(s2, want2); diff != "" {
  1024. t.Error(diff)
  1025. }
  1026. }
  1027. func TestStructLoaderErrors(t *testing.T) {
  1028. check := func(sp interface{}) {
  1029. var sl structLoader
  1030. err := sl.set(sp, schema2)
  1031. if err == nil {
  1032. t.Errorf("%T: got nil, want error", sp)
  1033. }
  1034. }
  1035. type bad1 struct{ F int32 } // wrong type for FLOAT column
  1036. check(&bad1{})
  1037. type bad2 struct{ I uint } // unsupported integer type
  1038. check(&bad2{})
  1039. type bad3 struct {
  1040. I int `bigquery:"@"`
  1041. } // bad field name
  1042. check(&bad3{})
  1043. type bad4 struct{ Nested int } // non-struct for nested field
  1044. check(&bad4{})
  1045. type bad5 struct{ Nested struct{ NestS int } } // bad nested struct
  1046. check(&bad5{})
  1047. bad6 := &struct{ Nums int }{} // non-slice for repeated field
  1048. sl := structLoader{}
  1049. err := sl.set(bad6, repSchema)
  1050. if err == nil {
  1051. t.Errorf("%T: got nil, want error", bad6)
  1052. }
  1053. // sl.set's error is sticky, even with good input.
  1054. err2 := sl.set(&repStruct{}, repSchema)
  1055. if err2 != err {
  1056. t.Errorf("%v != %v, expected equal", err2, err)
  1057. }
  1058. // sl.Load is similarly sticky
  1059. err2 = sl.Load(nil, nil)
  1060. if err2 != err {
  1061. t.Errorf("%v != %v, expected equal", err2, err)
  1062. }
  1063. // Null values.
  1064. schema := Schema{
  1065. {Name: "i", Type: IntegerFieldType},
  1066. {Name: "f", Type: FloatFieldType},
  1067. {Name: "b", Type: BooleanFieldType},
  1068. {Name: "s", Type: StringFieldType},
  1069. {Name: "d", Type: DateFieldType},
  1070. {Name: "r", Type: RecordFieldType, Schema: Schema{{Name: "X", Type: IntegerFieldType}}},
  1071. }
  1072. type s struct {
  1073. I int
  1074. F float64
  1075. B bool
  1076. S string
  1077. D civil.Date
  1078. }
  1079. vals := []Value{int64(0), 0.0, false, "", testDate}
  1080. mustLoad(t, &s{}, schema, vals)
  1081. for i, e := range vals {
  1082. vals[i] = nil
  1083. got := load(&s{}, schema, vals)
  1084. if got != errNoNulls {
  1085. t.Errorf("#%d: got %v, want %v", i, got, errNoNulls)
  1086. }
  1087. vals[i] = e
  1088. }
  1089. // Using more than one struct type with the same structLoader.
  1090. type different struct {
  1091. B bool
  1092. I int
  1093. times
  1094. S string
  1095. Nums []int
  1096. }
  1097. sl = structLoader{}
  1098. if err := sl.set(&testStruct1{}, schema2); err != nil {
  1099. t.Fatal(err)
  1100. }
  1101. err = sl.set(&different{}, schema2)
  1102. if err == nil {
  1103. t.Error("different struct types: got nil, want error")
  1104. }
  1105. }
  1106. func mustLoad(t *testing.T, pval interface{}, schema Schema, vals []Value) {
  1107. if err := load(pval, schema, vals); err != nil {
  1108. t.Fatalf("loading: %v", err)
  1109. }
  1110. }
  1111. func load(pval interface{}, schema Schema, vals []Value) error {
  1112. var sl structLoader
  1113. if err := sl.set(pval, schema); err != nil {
  1114. return err
  1115. }
  1116. return sl.Load(vals, nil)
  1117. }
  1118. func BenchmarkStructLoader_NoCompile(b *testing.B) {
  1119. benchmarkStructLoader(b, false)
  1120. }
  1121. func BenchmarkStructLoader_Compile(b *testing.B) {
  1122. benchmarkStructLoader(b, true)
  1123. }
  1124. func benchmarkStructLoader(b *testing.B, compile bool) {
  1125. var ts1 testStruct1
  1126. for i := 0; i < b.N; i++ {
  1127. var sl structLoader
  1128. for j := 0; j < 10; j++ {
  1129. if err := load(&ts1, schema2, testValues); err != nil {
  1130. b.Fatal(err)
  1131. }
  1132. if !compile {
  1133. sl.typ = nil
  1134. }
  1135. }
  1136. }
  1137. }