activerecord-copy 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rubocop.yml +40 -0
  4. data/.travis.yml +9 -0
  5. data/CHANGELOG.md +5 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +49 -0
  8. data/README.md +40 -0
  9. data/Rakefile +1 -0
  10. data/activerecord-copy.gemspec +25 -0
  11. data/lib/activerecord-copy.rb +92 -0
  12. data/lib/activerecord-copy/constants.rb +18 -0
  13. data/lib/activerecord-copy/decoder.rb +176 -0
  14. data/lib/activerecord-copy/encode_for_copy.rb +253 -0
  15. data/lib/activerecord-copy/exception.rb +4 -0
  16. data/lib/activerecord-copy/temp_buffer.rb +38 -0
  17. data/lib/activerecord-copy/version.rb +3 -0
  18. data/spec/big_write_spec.rb +17 -0
  19. data/spec/errors_spec.rb +8 -0
  20. data/spec/fixtures/3_col_array.txt +1 -0
  21. data/spec/fixtures/3_col_hstore.dat +0 -0
  22. data/spec/fixtures/3_col_hstore.txt +1 -0
  23. data/spec/fixtures/3_column_array.dat +0 -0
  24. data/spec/fixtures/array_with_two.dat +0 -0
  25. data/spec/fixtures/array_with_two2.dat +0 -0
  26. data/spec/fixtures/big_str_array.dat +0 -0
  27. data/spec/fixtures/big_str_array2.dat +0 -0
  28. data/spec/fixtures/bigint.dat +0 -0
  29. data/spec/fixtures/date.dat +0 -0
  30. data/spec/fixtures/date2.dat +0 -0
  31. data/spec/fixtures/date2000.dat +0 -0
  32. data/spec/fixtures/dates.dat +0 -0
  33. data/spec/fixtures/dates_p924.dat +0 -0
  34. data/spec/fixtures/dates_pg935.dat +0 -0
  35. data/spec/fixtures/empty_uuid.dat +0 -0
  36. data/spec/fixtures/falseclass.dat +0 -0
  37. data/spec/fixtures/float.dat +0 -0
  38. data/spec/fixtures/hstore_utf8.dat +0 -0
  39. data/spec/fixtures/intarray.dat +0 -0
  40. data/spec/fixtures/json.dat +0 -0
  41. data/spec/fixtures/json_array.dat +0 -0
  42. data/spec/fixtures/just_an_array.dat +0 -0
  43. data/spec/fixtures/just_an_array2.dat +0 -0
  44. data/spec/fixtures/multiline_hstore.dat +0 -0
  45. data/spec/fixtures/output.dat +0 -0
  46. data/spec/fixtures/timestamp.dat +0 -0
  47. data/spec/fixtures/timestamp_9.3.dat +0 -0
  48. data/spec/fixtures/timestamp_big.dat +0 -0
  49. data/spec/fixtures/timestamp_rounding.dat +0 -0
  50. data/spec/fixtures/trueclass.dat +0 -0
  51. data/spec/fixtures/utf8.dat +0 -0
  52. data/spec/fixtures/uuid.dat +0 -0
  53. data/spec/fixtures/uuid_array.dat +0 -0
  54. data/spec/multiline_spec.rb +17 -0
  55. data/spec/spec_helper.rb +22 -0
  56. data/spec/verify_data_formats_spec.rb +415 -0
  57. data/spec/verify_decoder_spec.rb +263 -0
  58. metadata +182 -0
@@ -0,0 +1,415 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+ require 'date'
4
+
5
+ describe 'generating data' do
6
+ it 'encodes hstore data correctly' do
7
+ encoder = ActiveRecordCopy::EncodeForCopy.new
8
+ encoder.add [1, 'text', { a: 1, b: 'asdf' }]
9
+ encoder.close
10
+ io = encoder.get_io
11
+ existing_data = filedata('3_col_hstore.dat')
12
+ str = io.read
13
+ expect(io.class.name).to eq 'StringIO'
14
+ str.force_encoding('ASCII-8BIT')
15
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
16
+ expect(str).to eq existing_data
17
+ end
18
+
19
+ it 'encodes hstore data correctly from tempfile' do
20
+ encoder = ActiveRecordCopy::EncodeForCopy.new(use_tempfile: true)
21
+ encoder.add [1, 'text', { a: 1, b: 'asdf' }]
22
+ encoder.close
23
+ io = encoder.get_io
24
+ existing_data = filedata('3_col_hstore.dat')
25
+ str = io.read
26
+ expect(io.class.name).to eq 'Tempfile'
27
+ str.force_encoding('ASCII-8BIT')
28
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
29
+ expect(str).to eq existing_data
30
+ end
31
+
32
+ it 'encodes hstore with utf8 data correctly from tempfile' do
33
+ encoder = ActiveRecordCopy::EncodeForCopy.new(use_tempfile: true)
34
+ encoder.add [{ test: 'Ekström' }]
35
+ encoder.add [{ test: 'Dueñas' }]
36
+ encoder.add [{ 'account_first_name' => 'asdfasdf asñas', 'testtesttesttesttesttestest' => '', 'aasdfasdfasdfasdfasdfasdfasdfasdfasfasfasdfs' => '' }] # needed to verify encoding issue
37
+ encoder.close
38
+ io = encoder.get_io
39
+ existing_data = filedata('hstore_utf8.dat')
40
+ str = io.read
41
+ expect(io.class.name).to eq 'Tempfile'
42
+ str.force_encoding('ASCII-8BIT')
43
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
44
+ expect(str).to eq existing_data
45
+ end
46
+
47
+ it 'encodes TrueClass data correctly' do
48
+ encoder = ActiveRecordCopy::EncodeForCopy.new
49
+ encoder.add [true]
50
+ encoder.close
51
+ io = encoder.get_io
52
+ existing_data = filedata('trueclass.dat')
53
+ str = io.read
54
+ expect(io.class.name).to eq 'StringIO'
55
+ str.force_encoding('ASCII-8BIT')
56
+ expect(str).to eq existing_data
57
+ end
58
+
59
+ it 'encodes FalseClass data correctly' do
60
+ encoder = ActiveRecordCopy::EncodeForCopy.new
61
+ encoder.add [false]
62
+ encoder.close
63
+ io = encoder.get_io
64
+ existing_data = filedata('falseclass.dat')
65
+ str = io.read
66
+ expect(io.class.name).to eq 'StringIO'
67
+ str.force_encoding('ASCII-8BIT')
68
+ expect(str).to eq existing_data
69
+ end
70
+
71
+ it 'encodes array data correctly' do
72
+ encoder = ActiveRecordCopy::EncodeForCopy.new
73
+ encoder.add [%w(hi jim)]
74
+ encoder.close
75
+ io = encoder.get_io
76
+ existing_data = filedata('array_with_two2.dat')
77
+ str = io.read
78
+ expect(io.class.name).to eq 'StringIO'
79
+ str.force_encoding('ASCII-8BIT')
80
+ expect(str).to eq existing_data
81
+ end
82
+
83
+ it 'encodes string array data correctly' do
84
+ encoder = ActiveRecordCopy::EncodeForCopy.new
85
+ encoder.add [%w(asdfasdfasdfasdf asdfasdfasdfasdfadsfadf 1123423423423)]
86
+ encoder.close
87
+ io = encoder.get_io
88
+ existing_data = filedata('big_str_array.dat')
89
+ str = io.read
90
+ expect(io.class.name).to eq 'StringIO'
91
+ str.force_encoding('ASCII-8BIT')
92
+ expect(str).to eq existing_data
93
+ end
94
+
95
+ it 'encodes string array with big string int' do
96
+ encoder = ActiveRecordCopy::EncodeForCopy.new
97
+ encoder.add [['182749082739172']]
98
+ encoder.close
99
+ io = encoder.get_io
100
+ existing_data = filedata('just_an_array2.dat')
101
+ str = io.read
102
+ expect(io.class.name).to eq 'StringIO'
103
+ str.force_encoding('ASCII-8BIT')
104
+ expect(str).to eq existing_data
105
+ end
106
+
107
+ it 'encodes string array data correctly' do
108
+ encoder = ActiveRecordCopy::EncodeForCopy.new
109
+ encoder.add [%w(asdfasdfasdfasdf asdfasdfasdfasdfadsfadf)]
110
+ encoder.close
111
+ io = encoder.get_io
112
+ existing_data = filedata('big_str_array2.dat')
113
+ str = io.read
114
+ expect(io.class.name).to eq 'StringIO'
115
+ str.force_encoding('ASCII-8BIT')
116
+ expect(str).to eq existing_data
117
+ end
118
+
119
+ it 'encodes array data from tempfile correctly', pending: 'broken right now' do
120
+ encoder = ActiveRecordCopy::EncodeForCopy.new(use_tempfile: true)
121
+ encoder.add [1, 'hi', ['hi', 'there', 'rubyist']]
122
+ encoder.close
123
+ io = encoder.get_io
124
+ existing_data = filedata('3_column_array.dat')
125
+ str = io.read
126
+ expect(io.class.name).to eq 'Tempfile'
127
+ str.force_encoding('ASCII-8BIT')
128
+ expect(str).to eq existing_data
129
+ end
130
+
131
+ it 'encodes integer array data from tempfile correctly' do
132
+ encoder = ActiveRecordCopy::EncodeForCopy.new(use_tempfile: true)
133
+ encoder.add [[1, 2, 3]]
134
+ encoder.close
135
+ io = encoder.get_io
136
+ existing_data = filedata('intarray.dat')
137
+ str = io.read
138
+ expect(io.class.name).to eq 'Tempfile'
139
+ str.force_encoding('ASCII-8BIT')
140
+ expect(str).to eq existing_data
141
+ end
142
+
143
+ it 'encodes date data correctly' do
144
+ encoder = ActiveRecordCopy::EncodeForCopy.new
145
+ encoder.add [Date.parse('1900-12-03')]
146
+ encoder.close
147
+ io = encoder.get_io
148
+ existing_data = filedata('date.dat')
149
+ str = io.read
150
+ expect(io.class.name).to eq 'StringIO'
151
+ str.force_encoding('ASCII-8BIT')
152
+ expect(str).to eq existing_data
153
+ end
154
+
155
+ it 'encodes date data correctly for years > 2000' do
156
+ encoder = ActiveRecordCopy::EncodeForCopy.new
157
+ encoder.add [Date.parse('2033-01-12')]
158
+ encoder.close
159
+ io = encoder.get_io
160
+ existing_data = filedata('date2000.dat')
161
+ str = io.read
162
+ expect(io.class.name).to eq 'StringIO'
163
+ str.force_encoding('ASCII-8BIT')
164
+ expect(str).to eq existing_data
165
+ end
166
+
167
+ it 'encodes date data correctly in the 70s' do
168
+ encoder = ActiveRecordCopy::EncodeForCopy.new
169
+ encoder.add [Date.parse('1971-12-11')]
170
+ encoder.close
171
+ io = encoder.get_io
172
+ existing_data = filedata('date2.dat')
173
+ str = io.read
174
+ expect(io.class.name).to eq 'StringIO'
175
+ str.force_encoding('ASCII-8BIT')
176
+ expect(str).to eq existing_data
177
+ end
178
+
179
+ it 'encodes multiple 2015 dates' do
180
+ encoder = ActiveRecordCopy::EncodeForCopy.new
181
+ encoder.add [Date.parse('2015-04-08'), nil, Date.parse('2015-04-13')]
182
+ encoder.close
183
+ io = encoder.get_io
184
+ existing_data = filedata('dates.dat')
185
+ str = io.read
186
+ expect(io.class.name).to eq 'StringIO'
187
+ str.force_encoding('ASCII-8BIT')
188
+ expect(str).to eq existing_data
189
+ end
190
+
191
+ it 'encodes timestamp data correctly' do
192
+ encoder = ActiveRecordCopy::EncodeForCopy.new
193
+ encoder.add [Time.parse('2013-06-11 15:03:54.62605 UTC')]
194
+ encoder.close
195
+ io = encoder.get_io
196
+ existing_data = filedata('timestamp.dat')
197
+ str = io.read
198
+ expect(io.class.name).to eq 'StringIO'
199
+ str.force_encoding('ASCII-8BIT')
200
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
201
+ expect(str).to eq existing_data
202
+ end
203
+
204
+ require 'time'
205
+
206
+ # When this timestamp is converted to float it will incorrectly change the
207
+ # last digit of usecs to and therefore insert the wrong data into the database
208
+ it 'encodes timestamp data correctly without rounding' do
209
+ encoder = ActiveRecordCopy::EncodeForCopy.new
210
+ encoder.add [Time.parse('2017-07-23 00:02:57.121215 UTC')]
211
+ encoder.close
212
+ io = encoder.get_io
213
+ existing_data = filedata('timestamp_rounding.dat')
214
+ str = io.read
215
+ expect(io.class.name).to eq 'StringIO'
216
+ str.force_encoding('ASCII-8BIT')
217
+ # File.open('spec/fixtures/timestamp_rounding.dat', 'w:ASCII-8BIT') { |out| out.write(str) }
218
+ expect(str).to eq existing_data
219
+ end
220
+
221
+ it 'encodes dates and times in pg 9.2.4' do
222
+ encoder = ActiveRecordCopy::EncodeForCopy.new
223
+ encoder.add [Date.parse('2015-04-08'), nil, Time.parse('2015-02-13 16:13:57.732772 UTC')]
224
+ encoder.close
225
+ io = encoder.get_io
226
+ existing_data = filedata('dates_p924.dat')
227
+ str = io.read
228
+ expect(io.class.name).to eq 'StringIO'
229
+ str.force_encoding('ASCII-8BIT')
230
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
231
+ expect(str).to eq existing_data
232
+ end
233
+
234
+ it 'encodes dates and times in pg 9.3.5' do
235
+ encoder = ActiveRecordCopy::EncodeForCopy.new
236
+ encoder.add [Date.parse('2015-04-08'), nil, Time.parse('2015-02-13 16:13:57.732772 UTC')]
237
+ encoder.close
238
+ io = encoder.get_io
239
+ existing_data = filedata('dates_pg935.dat')
240
+ str = io.read
241
+ expect(io.class.name).to eq 'StringIO'
242
+ str.force_encoding('ASCII-8BIT')
243
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
244
+ expect(str).to eq existing_data
245
+ end
246
+
247
+ it 'encodes timestamp data correctly' do
248
+ encoder = ActiveRecordCopy::EncodeForCopy.new
249
+ encoder.add [Time.parse('2013-06-11 15:03:54.62605 UTC')]
250
+ encoder.close
251
+ io = encoder.get_io
252
+ existing_data = filedata('timestamp.dat')
253
+ str = io.read
254
+ expect(io.class.name).to eq 'StringIO'
255
+ str.force_encoding('ASCII-8BIT')
256
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
257
+ expect(str).to eq existing_data
258
+ end
259
+
260
+ it 'encodes big timestamp data correctly' do
261
+ encoder = ActiveRecordCopy::EncodeForCopy.new
262
+ encoder.add [Time.parse('2014-12-02 16:01:22.437311 UTC')]
263
+ encoder.close
264
+ io = encoder.get_io
265
+ existing_data = filedata('timestamp_9.3.dat')
266
+ str = io.read
267
+ expect(io.class.name).to eq 'StringIO'
268
+ str.force_encoding('ASCII-8BIT')
269
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
270
+ expect(str).to eq existing_data
271
+ end
272
+
273
+ it 'encodes json hash correctly' do
274
+ encoder = ActiveRecordCopy::EncodeForCopy.new(column_types: { 0 => :json })
275
+ encoder.add [{}]
276
+ encoder.close
277
+ io = encoder.get_io
278
+ existing_data = filedata('json.dat')
279
+ str = io.read
280
+ expect(io.class.name).to eq 'StringIO'
281
+ str.force_encoding('ASCII-8BIT')
282
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
283
+ expect(str).to eq existing_data
284
+ end
285
+
286
+ it 'encodes json array correctly' do
287
+ encoder = ActiveRecordCopy::EncodeForCopy.new(column_types: { 0 => :json })
288
+ encoder.add [[]]
289
+ encoder.close
290
+ io = encoder.get_io
291
+ existing_data = filedata('json_array.dat')
292
+ str = io.read
293
+ expect(io.class.name).to eq 'StringIO'
294
+ str.force_encoding('ASCII-8BIT')
295
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
296
+ expect(str).to eq existing_data
297
+ end
298
+
299
+ it 'encodes float correctly from tempfile' do
300
+ encoder = ActiveRecordCopy::EncodeForCopy.new(use_tempfile: true)
301
+ encoder.add [Time.parse('2013-06-11 15:03:54.62605 UTC')]
302
+ encoder.close
303
+ io = encoder.get_io
304
+ existing_data = filedata('timestamp.dat')
305
+ str = io.read
306
+ expect(io.class.name).to eq 'Tempfile'
307
+ str.force_encoding('ASCII-8BIT')
308
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
309
+ expect(str).to eq existing_data
310
+ end
311
+
312
+ it 'encodes float data correctly' do
313
+ encoder = ActiveRecordCopy::EncodeForCopy.new
314
+ encoder.add [1_234_567.1234567]
315
+ encoder.close
316
+ io = encoder.get_io
317
+ existing_data = filedata('float.dat')
318
+ str = io.read
319
+ expect(io.class.name).to eq 'StringIO'
320
+ str.force_encoding('ASCII-8BIT')
321
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
322
+ expect(str).to eq existing_data
323
+ end
324
+
325
+ it 'encode float correctly from tempfile' do
326
+ encoder = ActiveRecordCopy::EncodeForCopy.new(use_tempfile: true)
327
+ encoder.add [1_234_567.1234567]
328
+ encoder.close
329
+ io = encoder.get_io
330
+ existing_data = filedata('float.dat')
331
+ str = io.read
332
+ expect(io.class.name).to eq 'Tempfile'
333
+ str.force_encoding('ASCII-8BIT')
334
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
335
+ expect(str).to eq existing_data
336
+ end
337
+
338
+ it 'encodes uuid correctly from tempfile' do
339
+ encoder = ActiveRecordCopy::EncodeForCopy.new(use_tempfile: true, column_types: { 0 => :uuid })
340
+ encoder.add ['e876eef5-a116-4a27-b71f-bac4a1dcd20e']
341
+ encoder.close
342
+ io = encoder.get_io
343
+ existing_data = filedata('uuid.dat')
344
+ str = io.read
345
+ expect(io.class.name).to eq 'Tempfile'
346
+ str.force_encoding('ASCII-8BIT')
347
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
348
+ expect(str).to eq existing_data
349
+ end
350
+
351
+ it 'encodes null uuid correctly from tempfile' do
352
+ encoder = ActiveRecordCopy::EncodeForCopy.new(use_tempfile: true, column_types: { 1 => :uuid })
353
+ encoder.add ['before2', nil, nil, 123_423_423]
354
+ encoder.close
355
+ io = encoder.get_io
356
+ existing_data = filedata('empty_uuid.dat')
357
+ str = io.read
358
+ expect(io.class.name).to eq 'Tempfile'
359
+ str.force_encoding('ASCII-8BIT')
360
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
361
+ expect(str).to eq existing_data
362
+ end
363
+
364
+ it 'encodes uuid correctly from tempfile' do
365
+ encoder = ActiveRecordCopy::EncodeForCopy.new(use_tempfile: true, column_types: { 0 => :uuid })
366
+ encoder.add [['6272bd7d-adae-44b7-bba1-dca871c2a6fd', '7dc8431f-fcce-4d4d-86f3-6857cba47d38']]
367
+ encoder.close
368
+ io = encoder.get_io
369
+ existing_data = filedata('uuid_array.dat')
370
+ str = io.read
371
+ expect(io.class.name).to eq 'Tempfile'
372
+ str.force_encoding('ASCII-8BIT')
373
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
374
+ expect(str).to eq existing_data
375
+ end
376
+
377
+ it 'encodes utf8 string correctly' do
378
+ encoder = ActiveRecordCopy::EncodeForCopy.new
379
+ ekstrom = 'Ekström'
380
+ encoder.add [ekstrom]
381
+ encoder.close
382
+ io = encoder.get_io
383
+ existing_data = filedata('utf8.dat')
384
+ str = io.read
385
+ expect(io.class.name).to eq 'StringIO'
386
+ str.force_encoding('ASCII-8BIT')
387
+ expect(str).to eq existing_data
388
+ end
389
+
390
+ it 'encodes bigint as int correctly from tempfile' do
391
+ encoder = ActiveRecordCopy::EncodeForCopy.new(use_tempfile: true, column_types: { 0 => :bigint })
392
+ encoder.add [23_372_036_854_775_808, 'test']
393
+ encoder.close
394
+ io = encoder.get_io
395
+ existing_data = filedata('bigint.dat')
396
+ str = io.read
397
+ expect(io.class.name).to eq 'Tempfile'
398
+ str.force_encoding('ASCII-8BIT')
399
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
400
+ expect(str).to eq existing_data
401
+ end
402
+
403
+ it 'encodes bigint correctly from tempfile' do
404
+ encoder = ActiveRecordCopy::EncodeForCopy.new(use_tempfile: true, column_types: { 0 => :bigint })
405
+ encoder.add %w(23372036854775808 test)
406
+ encoder.close
407
+ io = encoder.get_io
408
+ existing_data = filedata('bigint.dat')
409
+ str = io.read
410
+ expect(io.class.name).to eq 'Tempfile'
411
+ str.force_encoding('ASCII-8BIT')
412
+ # File.open('spec/fixtures/output.dat', 'w:ASCII-8BIT') {|out| out.write(str) }
413
+ expect(str).to eq existing_data
414
+ end
415
+ end
@@ -0,0 +1,263 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+ require 'time'
4
+
5
+ describe 'parsing data' do
6
+ it 'walks through each line and stop' do
7
+ decoder = ActiveRecordCopy::Decoder.new(
8
+ io: fileio('hstore_utf8.dat'),
9
+ column_types: { 0 => :hstore }
10
+ )
11
+ lines = []
12
+ decoder.each do |l|
13
+ lines << l
14
+ end
15
+ expect(lines).to eq [
16
+ [{ 'test' => 'Ekström' }],
17
+ [{ 'test' => 'Dueñas' }],
18
+ [{ 'account_first_name' => 'asdfasdf asñas', 'testtesttesttesttesttestest' => '', 'aasdfasdfasdfasdfasdfasdfasdfasdfasfasfasdfs' => '' }]
19
+ ]
20
+ end
21
+
22
+ it 'handles getting called after running out of data' do
23
+ decoder = ActiveRecordCopy::Decoder.new(
24
+ io: fileio('3_col_hstore.dat'),
25
+ column_types: { 0 => :int, 1 => :string, 2 => :hstore }
26
+ )
27
+ r = decoder.read_line
28
+ expect(r).to eq [1, 'text', { 'a' => '1', 'b' => 'asdf' }]
29
+ expect(decoder.read_line).to be_nil
30
+ expect(decoder.read_line).to be_nil
31
+ end
32
+
33
+ it 'encodes hstore data correctly' do
34
+ decoder = ActiveRecordCopy::Decoder.new(
35
+ io: fileio('3_col_hstore.dat'),
36
+ column_types: { 0 => :int, 1 => :string, 2 => :hstore }
37
+ )
38
+ r = decoder.read_line
39
+ expect(r).to eq [1, 'text', { 'a' => '1', 'b' => 'asdf' }]
40
+ end
41
+
42
+ it 'returns nil if past data' do
43
+ decoder = ActiveRecordCopy::Decoder.new(
44
+ io: fileio('3_col_hstore.dat'),
45
+ column_types: { 0 => :int, 1 => :string, 2 => :hstore }
46
+ )
47
+ r = decoder.read_line
48
+ expect(r).to eq [1, 'text', { 'a' => '1', 'b' => 'asdf' }]
49
+ r = decoder.read_line
50
+ expect(r).to eq nil
51
+ end
52
+
53
+ it 'encodes hstore with utf8 data correctly from tempfile' do
54
+ decoder = ActiveRecordCopy::Decoder.new(
55
+ io: fileio('hstore_utf8.dat'),
56
+ column_types: { 0 => :hstore }
57
+ )
58
+ r = decoder.read_line
59
+ expect(r).to eq [{ 'test' => 'Ekström' }]
60
+ r = decoder.read_line
61
+ expect(r).to eq [{ 'test' => 'Dueñas' }]
62
+ r = decoder.read_line
63
+ expect(r).to eq [{ 'account_first_name' => 'asdfasdf asñas', 'testtesttesttesttesttestest' => '', 'aasdfasdfasdfasdfasdfasdfasdfasdfasfasfasdfs' => '' }]
64
+ end
65
+
66
+ it 'encodes TrueClass data correctly' do
67
+ decoder = ActiveRecordCopy::Decoder.new(
68
+ io: fileio('trueclass.dat'),
69
+ column_types: { 0 => :boolean }
70
+ )
71
+ r = decoder.read_line
72
+ expect(r).to eq [true]
73
+ end
74
+
75
+ it 'encodes FalseClass data correctly' do
76
+ decoder = ActiveRecordCopy::Decoder.new(
77
+ io: fileio('falseclass.dat'),
78
+ column_types: { 0 => :boolean }
79
+ )
80
+ r = decoder.read_line
81
+ expect(r).to eq [false]
82
+ end
83
+
84
+ it 'encodes array data correctly' do
85
+ decoder = ActiveRecordCopy::Decoder.new(
86
+ io: fileio('array_with_two2.dat'),
87
+ column_types: { 0 => :array }
88
+ )
89
+ r = decoder.read_line
90
+ expect(r).to eq [%w(hi jim)]
91
+ end
92
+
93
+ it 'encodes string array data correctly' do
94
+ decoder = ActiveRecordCopy::Decoder.new(
95
+ io: fileio('big_str_array.dat'),
96
+ column_types: { 0 => :array }
97
+ )
98
+ r = decoder.read_line
99
+ expect(r).to eq [%w(asdfasdfasdfasdf asdfasdfasdfasdfadsfadf 1123423423423)]
100
+ end
101
+
102
+ it 'encodes string array with big string int' do
103
+ decoder = ActiveRecordCopy::Decoder.new(
104
+ io: fileio('just_an_array2.dat'),
105
+ column_types: { 0 => :array }
106
+ )
107
+ r = decoder.read_line
108
+ expect(r).to eq [['182749082739172']]
109
+ end
110
+
111
+ it 'encodes string array data correctly' do
112
+ decoder = ActiveRecordCopy::Decoder.new(
113
+ io: fileio('big_str_array2.dat'),
114
+ column_types: { 0 => :array }
115
+ )
116
+ r = decoder.read_line
117
+ expect(r).to eq [%w(asdfasdfasdfasdf asdfasdfasdfasdfadsfadf)]
118
+ end
119
+
120
+ it 'encodes array data from tempfile correctly', pending: 'broken right now' do
121
+ decoder = ActiveRecordCopy::Decoder.new(
122
+ io: fileio('3_column_array.dat'),
123
+ column_types: { 0 => :array }
124
+ )
125
+ r = decoder.read_line
126
+ expect(r).to eq [1, 'hi', ['hi', 'there', 'rubyist']]
127
+ end
128
+
129
+ it 'encodes integer array data from tempfile correctly' do
130
+ decoder = ActiveRecordCopy::Decoder.new(
131
+ io: fileio('intarray.dat'),
132
+ column_types: { 0 => :array }
133
+ )
134
+ r = decoder.read_line
135
+ expect(r).to eq [[1, 2, 3]]
136
+ end
137
+
138
+ it 'encodes old date data correctly' do
139
+ decoder = ActiveRecordCopy::Decoder.new(
140
+ io: fileio('date.dat'),
141
+ column_types: { 0 => :date }
142
+ )
143
+ r = decoder.read_line
144
+ expect(r).to eq [Date.parse('1900-12-03')]
145
+ end
146
+
147
+ it 'encodes date data correctly for years > 2000' do
148
+ decoder = ActiveRecordCopy::Decoder.new(
149
+ io: fileio('date2000.dat'),
150
+ column_types: { 0 => :date }
151
+ )
152
+ r = decoder.read_line
153
+ expect(r).to eq [Date.parse('2033-01-12')]
154
+ end
155
+
156
+ it 'encodes date data correctly in the 70s' do
157
+ decoder = ActiveRecordCopy::Decoder.new(
158
+ io: fileio('date2.dat'),
159
+ column_types: { 0 => :date }
160
+ )
161
+ r = decoder.read_line
162
+ expect(r).to eq [Date.parse('1971-12-11')]
163
+ end
164
+
165
+ it 'encodes multiple 2015 dates' do
166
+ decoder = ActiveRecordCopy::Decoder.new(
167
+ io: fileio('dates.dat'),
168
+ column_types: { 0 => :date, 1 => :date, 2 => :date }
169
+ )
170
+ r = decoder.read_line
171
+ expect(r).to eq [Date.parse('2015-04-08'), nil, Date.parse('2015-04-13')]
172
+ end
173
+
174
+ it 'encodes timestamp data correctly' do
175
+ decoder = ActiveRecordCopy::Decoder.new(
176
+ io: fileio('timestamp.dat'),
177
+ column_types: { 0 => :time }
178
+ )
179
+ r = decoder.read_line
180
+ expect(r.map(&:to_f)).to eq [Time.parse('2013-06-11 15:03:54.62605 UTC')].map(&:to_f)
181
+ end
182
+
183
+ it 'encodes dates and times in pg 9.2.4' do
184
+ decoder = ActiveRecordCopy::Decoder.new(
185
+ io: fileio('dates_p924.dat'),
186
+ column_types: { 0 => :date, 2 => :time }
187
+ )
188
+ r = decoder.read_line
189
+ expect(r.map { |f| f.is_a?(Time) ? f.to_f : f }).to eq [Date.parse('2015-04-08'), nil, Time.parse('2015-02-13 16:13:57.732772 UTC')].map { |f| f.is_a?(Time) ? f.to_f : f }
190
+ end
191
+
192
+ it 'encodes dates and times in pg 9.3.5' do
193
+ decoder = ActiveRecordCopy::Decoder.new(
194
+ io: fileio('dates_pg935.dat'),
195
+ column_types: { 0 => :date, 2 => :time }
196
+ )
197
+ r = decoder.read_line
198
+ expect(r.map { |f| f.is_a?(Time) ? f.to_f : f }).to eq [Date.parse('2015-04-08'), nil, Time.parse('2015-02-13 16:13:57.732772 UTC')].map { |f| f.is_a?(Time) ? f.to_f : f }
199
+ end
200
+
201
+ it 'encodes big timestamp data correctly' do
202
+ decoder = ActiveRecordCopy::Decoder.new(
203
+ io: fileio('timestamp_9.3.dat'),
204
+ column_types: { 0 => :time }
205
+ )
206
+ r = decoder.read_line
207
+ expect(r.map { |f| f.is_a?(Time) ? f.to_f : f }).to eq [Time.parse('2014-12-02 16:01:22.437311 UTC')].map { |f| f.is_a?(Time) ? f.to_f : f }
208
+ end
209
+
210
+ it 'encodes float data correctly' do
211
+ decoder = ActiveRecordCopy::Decoder.new(
212
+ io: fileio('float.dat'),
213
+ column_types: { 0 => :float }
214
+ )
215
+ r = decoder.read_line
216
+ expect(r).to eq [1_234_567.1234567]
217
+ end
218
+
219
+ it 'encodes uuid correctly from tempfile' do
220
+ decoder = ActiveRecordCopy::Decoder.new(
221
+ io: fileio('uuid.dat'),
222
+ column_types: { 0 => :uuid }
223
+ )
224
+ r = decoder.read_line
225
+ expect(r).to eq ['e876eef5-a116-4a27-b71f-bac4a1dcd20e']
226
+ end
227
+
228
+ it 'encodes null uuid correctly from tempfile' do
229
+ decoder = ActiveRecordCopy::Decoder.new(
230
+ io: fileio('empty_uuid.dat'),
231
+ column_types: { 0 => :string, 1 => :uuid, 2 => :uuid, 3 => :integer }
232
+ )
233
+ r = decoder.read_line
234
+ expect(r).to eq ['before2', nil, nil, 123_423_423]
235
+ end
236
+
237
+ it 'encodes uuid correctly from tempfile' do
238
+ decoder = ActiveRecordCopy::Decoder.new(
239
+ io: fileio('uuid_array.dat'),
240
+ column_types: { 0 => :array }
241
+ )
242
+ r = decoder.read_line
243
+ expect(r).to eq [['6272bd7d-adae-44b7-bba1-dca871c2a6fd', '7dc8431f-fcce-4d4d-86f3-6857cba47d38']]
244
+ end
245
+
246
+ it 'encodes utf8 string correctly' do
247
+ decoder = ActiveRecordCopy::Decoder.new(
248
+ io: fileio('utf8.dat'),
249
+ column_types: { 0 => :string }
250
+ )
251
+ r = decoder.read_line
252
+ expect(r).to eq ['Ekström']
253
+ end
254
+
255
+ it 'encodes bigint as int correctly from tempfile' do
256
+ decoder = ActiveRecordCopy::Decoder.new(
257
+ io: fileio('bigint.dat'),
258
+ column_types: { 0 => :bigint, 1 => :string }
259
+ )
260
+ r = decoder.read_line
261
+ expect(r).to eq [23_372_036_854_775_808, 'test']
262
+ end
263
+ end