extralite 2.5 → 2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +34 -13
  4. data/Gemfile +4 -0
  5. data/Gemfile-bundle +1 -1
  6. data/LICENSE +1 -1
  7. data/README.md +1059 -247
  8. data/Rakefile +18 -0
  9. data/TODO.md +0 -7
  10. data/examples/kv_store.rb +49 -0
  11. data/examples/multi_fiber.rb +16 -0
  12. data/examples/on_progress.rb +9 -0
  13. data/examples/pubsub_store_polyphony.rb +194 -0
  14. data/examples/pubsub_store_threads.rb +204 -0
  15. data/ext/extralite/changeset.c +463 -0
  16. data/ext/extralite/common.c +177 -91
  17. data/ext/extralite/database.c +745 -276
  18. data/ext/extralite/extconf-bundle.rb +10 -4
  19. data/ext/extralite/extconf.rb +34 -34
  20. data/ext/extralite/extralite.h +104 -47
  21. data/ext/extralite/extralite_ext.c +6 -0
  22. data/ext/extralite/iterator.c +14 -86
  23. data/ext/extralite/query.c +171 -264
  24. data/extralite-bundle.gemspec +1 -1
  25. data/extralite.gemspec +1 -1
  26. data/gemspec.rb +10 -11
  27. data/lib/extralite/version.rb +1 -1
  28. data/lib/extralite.rb +69 -10
  29. data/lib/sequel/adapters/extralite.rb +1 -1
  30. data/test/helper.rb +9 -1
  31. data/test/perf_argv_transform.rb +74 -0
  32. data/test/perf_ary.rb +14 -12
  33. data/test/perf_hash.rb +17 -15
  34. data/test/perf_hash_prepared.rb +58 -0
  35. data/test/perf_hash_transform.rb +66 -0
  36. data/test/perf_polyphony.rb +74 -0
  37. data/test/test_changeset.rb +161 -0
  38. data/test/test_database.rb +720 -104
  39. data/test/test_extralite.rb +2 -2
  40. data/test/test_iterator.rb +28 -13
  41. data/test/test_query.rb +352 -110
  42. data/test/test_sequel.rb +4 -4
  43. metadata +24 -16
  44. data/Gemfile.lock +0 -37
  45. data/test/perf_prepared.rb +0 -64
data/test/test_query.rb CHANGED
@@ -2,8 +2,9 @@
2
2
 
3
3
  require_relative 'helper'
4
4
  require 'date'
5
+ require 'json'
5
6
 
6
- class QueryTest < MiniTest::Test
7
+ class QueryTest < Minitest::Test
7
8
  def setup
8
9
  @db = Extralite::Database.new(':memory:')
9
10
  @db.query('create table if not exists t (x,y,z)')
@@ -17,10 +18,47 @@ class QueryTest < MiniTest::Test
17
18
 
18
19
  def test_prepare
19
20
  query = @db.prepare('select 1')
20
- assert_equal 1, query.next_single_column
21
+ assert_equal({ '1': 1 }, query.next)
21
22
 
22
23
  query = @db.prepare('select x from t where y = ?', 5)
23
- assert_equal 4, query.next_single_column
24
+ assert_equal({ x: 4 }, query.next)
25
+ end
26
+
27
+ def test_mode
28
+ query = @db.prepare('select 1')
29
+ assert_equal :hash, query.mode
30
+
31
+ query.mode = :argv
32
+ assert_equal :argv, query.mode
33
+
34
+ query.mode = :ary
35
+ assert_equal :ary, query.mode
36
+
37
+ assert_raises(Extralite::Error) { query.mode = :foo }
38
+ assert_equal :ary, query.mode
39
+
40
+ query.mode = :hash
41
+ assert_equal :hash, query.mode
42
+ end
43
+
44
+ def test_prepare_argv
45
+ query = @db.prepare_argv('select 1')
46
+ assert_equal :argv, query.mode
47
+
48
+ assert_equal 1, query.next
49
+ end
50
+
51
+ def test_prepare_argv_with_too_many_columns
52
+ q = @db.prepare_argv('select 1, 2, 3, 4, 5, 6, 7, 8, 9')
53
+
54
+ assert_raises(Extralite::Error) { q.next }
55
+ end
56
+
57
+ def test_prepare_ary
58
+ query = @db.prepare_ary('select 1')
59
+ assert_equal :ary, query.mode
60
+
61
+ assert_equal [1], query.next
24
62
  end
25
63
 
26
64
  def test_query_props
@@ -33,8 +71,13 @@ class QueryTest < MiniTest::Test
33
71
  def test_bind
34
72
  @db.query("insert into t values ('a', 'b', 'c')")
35
73
 
36
- q = @db.prepare('select * from t where `z` = :foo')
37
- results = q.bind(foo: 'c').to_a_ary
74
+ q = @db.prepare_ary('select * from t where `z` = :foo')
75
+ results = q.bind(foo: 'c').to_a
76
+
77
+ assert_equal [['a', 'b', 'c']], results
78
+
79
+ # try again with the same parameters
80
+ results = q.to_a
38
81
 
39
82
  assert_equal [['a', 'b', 'c']], results
40
83
  end
@@ -56,19 +99,6 @@ class QueryTest < MiniTest::Test
56
99
  # EOF should repeat
57
100
  v = query.next
58
101
  assert_nil v
59
-
60
- query = @db.prepare('select * from t')
61
- v = query.next_hash
62
- assert_equal({ x: 1, y: 2, z: 3}, v)
63
-
64
- v = query.next_hash
65
- assert_equal({ x: 4, y: 5, z: 6}, v)
66
-
67
- v = query.next_hash
68
- assert_equal({ x: 7, y: 8, z: 9}, v)
69
-
70
- v = query.next_hash
71
- assert_nil v
72
102
  end
73
103
 
74
104
  def test_query_next_with_row_count
@@ -129,97 +159,112 @@ class QueryTest < MiniTest::Test
129
159
  end
130
160
 
131
161
  def test_query_next_ary
132
- query = @db.prepare('select * from t')
133
- v = query.next_ary
162
+ query = @db.prepare_ary('select * from t')
163
+ v = query.next
134
164
  assert_equal([1, 2, 3], v)
135
165
 
136
- v = query.next_ary
166
+ v = query.next
137
167
  assert_equal([4, 5, 6], v)
138
168
 
139
- v = query.next_ary
169
+ v = query.next
140
170
  assert_equal([7, 8, 9], v)
141
171
 
142
- v = query.next_ary
172
+ v = query.next
143
173
  assert_nil v
144
174
 
145
- v = query.next_ary
175
+ v = query.next
146
176
  assert_nil v
147
177
  end
148
178
 
149
179
  def test_query_next_ary_with_row_count
150
- query = @db.prepare('select * from t')
151
- v = query.next_ary(1)
180
+ query = @db.prepare_ary('select * from t')
181
+ v = query.next(1)
152
182
  assert_equal([[1, 2, 3]], v)
153
183
 
154
- v = query.next_ary(2)
184
+ v = query.next(2)
155
185
  assert_equal([[4, 5, 6], [7, 8, 9]], v)
156
186
 
157
- v = query.next_ary(2)
187
+ v = query.next(2)
158
188
  assert_equal([], v)
159
189
 
160
- v = query.next_ary(2)
190
+ v = query.next(2)
161
191
  assert_nil v
162
192
  end
163
193
 
164
194
  def test_query_next_ary_with_block
165
- query = @db.prepare('select * from t')
195
+ query = @db.prepare_ary('select * from t')
166
196
  buf = []
167
- v = query.next_ary { |r| buf << r }
197
+ v = query.next { |r| buf << r }
168
198
  assert_equal query, v
169
199
  assert_equal [[1, 2, 3]], buf
170
200
 
171
201
  buf = []
172
- v = query.next_ary(2) { |r| buf << r }
202
+ v = query.next(2) { |r| buf << r }
173
203
  assert_equal query, v
174
204
  assert_equal [[4, 5, 6], [7, 8, 9]], buf
175
205
 
176
206
  buf = []
177
- v = query.next_ary(2) { |r| buf << r }
207
+ v = query.next(2) { |r| buf << r }
178
208
  assert_equal query, v
179
209
  assert_equal [], buf
180
210
  end
181
211
 
182
- def test_query_next_single_column
183
- query = @db.prepare('select x from t')
184
- v = query.next_single_column
212
+ def test_query_next_argv_single_column
213
+ query = @db.prepare_argv('select x from t')
214
+ v = query.next
185
215
  assert_equal(1, v)
186
216
 
187
- v = query.next_single_column
217
+ v = query.next
188
218
  assert_equal(4, v)
189
219
 
190
- v = query.next_single_column
220
+ v = query.next
191
221
  assert_equal(7, v)
192
222
 
193
- v = query.next_single_column
223
+ v = query.next
224
+ assert_nil v
225
+ end
226
+
227
+ def test_query_next_argv_multi_column
228
+ query = @db.prepare_argv('select x, y from t')
229
+ v = query.next
230
+ assert_equal([1, 2], v)
231
+
232
+ v = query.next
233
+ assert_equal([4, 5], v)
234
+
235
+ v = query.next
236
+ assert_equal([7, 8], v)
237
+
238
+ v = query.next
194
239
  assert_nil v
195
240
  end
196
241
 
197
- def test_query_next_single_column_with_row_count
198
- query = @db.prepare('select x from t')
199
- v = query.next_single_column(1)
242
+ def test_query_next_argv_with_row_count
243
+ query = @db.prepare_argv('select x from t')
244
+ v = query.next(1)
200
245
  assert_equal([1], v)
201
246
 
202
- v = query.next_single_column(3)
247
+ v = query.next(3)
203
248
  assert_equal([4, 7], v)
204
249
 
205
- v = query.next_single_column(2)
250
+ v = query.next(2)
206
251
  assert_nil v
207
252
  end
208
253
 
209
- def test_query_next_single_column_with_block
210
- query = @db.prepare('select x from t')
254
+ def test_query_next_argv_with_block
255
+ query = @db.prepare_argv('select x, y from t')
211
256
  buf = []
212
- v = query.next_single_column { |r| buf << r }
257
+ v = query.next { |x, y| buf << [x, y] }
213
258
  assert_equal query, v
214
- assert_equal [1], buf
259
+ assert_equal [[1, 2]], buf
215
260
 
216
261
  buf = []
217
- v = query.next_single_column(2) { |r| buf << r }
262
+ v = query.next(2) { |x, y| buf << [x, y] }
218
263
  assert_equal query, v
219
- assert_equal [4, 7], buf
264
+ assert_equal [[4, 5], [7, 8]], buf
220
265
 
221
266
  buf = []
222
- v = query.next_single_column(2) { |r| buf << r }
267
+ v = query.next(2) { |x, y| buf << [x, y] }
223
268
  assert_equal query, v
224
269
  assert_equal [], buf
225
270
  end
@@ -228,14 +273,13 @@ class QueryTest < MiniTest::Test
228
273
  assert_equal [{ x: 1, y: 2, z: 3 }], @query.bind(1).to_a
229
274
  assert_equal [{ x: 4, y: 5, z: 6 }], @query.bind(4).to_a
230
275
 
231
- assert_equal [{ x: 1, y: 2, z: 3 }], @query.bind(1).to_a_hash
232
- assert_equal [{ x: 4, y: 5, z: 6 }], @query.bind(4).to_a_hash
276
+ @query.mode = :ary
233
277
 
234
- assert_equal [[1, 2, 3]], @query.bind(1).to_a_ary
235
- assert_equal [[4, 5, 6]], @query.bind(4).to_a_ary
278
+ assert_equal [[1, 2, 3]], @query.bind(1).to_a
279
+ assert_equal [[4, 5, 6]], @query.bind(4).to_a
236
280
 
237
- query = @db.prepare('select y from t')
238
- assert_equal [2, 5, 8], query.to_a_single_column
281
+ query = @db.prepare_argv('select y from t')
282
+ assert_equal [2, 5, 8], query.to_a
239
283
  end
240
284
 
241
285
  def test_query_each
@@ -280,23 +324,24 @@ class QueryTest < MiniTest::Test
280
324
 
281
325
  def test_query_each_ary
282
326
  buf = []
283
- @query.bind(1).each_ary { |r| buf << r }
327
+ @query.mode = :ary
328
+ @query.bind(1).each { |r| buf << r }
284
329
  assert_equal [[1, 2, 3]], buf
285
330
 
286
331
  # each should reset the stmt
287
332
  buf = []
288
- @query.each_ary { |r| buf << r }
333
+ @query.each { |r| buf << r }
289
334
  assert_equal [[1, 2, 3]], buf
290
335
 
291
- query = @db.prepare('select * from t')
336
+ query = @db.prepare_ary('select * from t')
292
337
  buf = []
293
- query.each_ary { |r| buf << r }
338
+ query.each { |r| buf << r }
294
339
  assert_equal [[1, 2, 3], [4, 5, 6], [7, 8, 9]], buf
295
340
  end
296
341
 
297
342
  def test_query_each_ary_without_block
298
- query = @db.prepare('select * from t')
299
- iter = query.each_ary
343
+ query = @db.prepare_ary('select * from t')
344
+ iter = query.each
300
345
  assert_kind_of Extralite::Iterator, iter
301
346
 
302
347
  buf = []
@@ -305,26 +350,54 @@ class QueryTest < MiniTest::Test
305
350
  assert_equal [[1, 2, 3], [4, 5, 6], [7, 8, 9]], buf
306
351
  end
307
352
 
308
- def test_query_each_single_column
309
- query = @db.prepare('select x from t where x = ?')
353
+ def test_query_each_argv
354
+ buf = []
355
+ @query.mode = :argv
356
+ @query.bind(1).each { |a, b, c| buf << [a, b, c] }
357
+ assert_equal [[1, 2, 3]], buf
358
+
359
+ # each should reset the stmt
310
360
  buf = []
311
- query.bind(1).each_single_column { |r| buf << r }
361
+ @query.each { |a, b, c| buf << [a, b, c] }
362
+ assert_equal [[1, 2, 3]], buf
363
+
364
+ query = @db.prepare_argv('select * from t')
365
+ buf = []
366
+ query.each { |a, b, c| buf << [a, b, c] }
367
+ assert_equal [[1, 2, 3], [4, 5, 6], [7, 8, 9]], buf
368
+ end
369
+
370
+ def test_query_each_argv_without_block
371
+ query = @db.prepare_argv('select * from t')
372
+ iter = query.each
373
+ assert_kind_of Extralite::Iterator, iter
374
+
375
+ buf = []
376
+ v = iter.each { |a, b, c| buf << [a, b, c] }
377
+ assert_equal iter, v
378
+ assert_equal [[1, 2, 3], [4, 5, 6], [7, 8, 9]], buf
379
+ end
380
+
381
+ def test_query_each_argv_single_column
382
+ query = @db.prepare_argv('select x from t where x = ?')
383
+ buf = []
384
+ query.bind(1).each { |r| buf << r }
312
385
  assert_equal [1], buf
313
386
 
314
387
  # each should reset the stmt
315
388
  buf = []
316
- query.each_single_column { |r| buf << r }
389
+ query.each { |r| buf << r }
317
390
  assert_equal [1], buf
318
391
 
319
- query = @db.prepare('select x from t')
392
+ query = @db.prepare_argv('select x from t')
320
393
  buf = []
321
- query.each_single_column { |r| buf << r }
394
+ query.each { |r| buf << r }
322
395
  assert_equal [1, 4, 7], buf
323
396
  end
324
397
 
325
- def test_query_each_single_column_without_block
326
- query = @db.prepare('select x from t')
327
- iter = query.each_single_column
398
+ def test_query_each_argv_single_column_without_block
399
+ query = @db.prepare_argv('select x from t')
400
+ iter = query.each
328
401
  assert_kind_of Extralite::Iterator, iter
329
402
 
330
403
  buf = []
@@ -411,33 +484,33 @@ class QueryTest < MiniTest::Test
411
484
  class Foo; end
412
485
 
413
486
  def test_parameter_binding_from_hash
414
- assert_equal 42, @db.prepare('select :bar').bind(foo: 41, bar: 42).next_single_column
415
- assert_equal 42, @db.prepare('select :bar').bind('foo' => 41, 'bar' => 42).next_single_column
416
- assert_equal 42, @db.prepare('select ?8').bind(7 => 41, 8 => 42).next_single_column
417
- assert_nil @db.prepare('select :bar').bind(foo: 41).next_single_column
487
+ assert_equal 42, @db.prepare_argv('select :bar').bind(foo: 41, bar: 42).next
488
+ assert_equal 42, @db.prepare_argv('select :bar').bind('foo' => 41, 'bar' => 42).next
489
+ assert_equal 42, @db.prepare_argv('select ?8').bind(7 => 41, 8 => 42).next
490
+ assert_nil @db.prepare_argv('select :bar').bind(foo: 41).next
418
491
 
419
- error = assert_raises(Extralite::ParameterError) { @db.prepare('select ?').bind(Foo.new => 42).next_single_column }
492
+ error = assert_raises(Extralite::ParameterError) { @db.prepare_argv('select ?').bind(Foo.new => 42).next }
420
493
  assert_equal error.message, 'Cannot bind parameter with a key of type QueryTest::Foo'
421
494
 
422
- error = assert_raises(Extralite::ParameterError) { @db.prepare('select ?').bind(%w[a b] => 42).next_single_column }
495
+ error = assert_raises(Extralite::ParameterError) { @db.prepare_argv('select ?').bind(%w[a b] => 42).next }
423
496
  assert_equal error.message, 'Cannot bind parameter with a key of type Array'
424
497
  end
425
498
 
426
499
  def test_parameter_binding_from_struct
427
- foo_bar = Struct.new(:":foo", :bar)
500
+ foo_bar = Struct.new(:':foo', :bar)
428
501
  value = foo_bar.new(41, 42)
429
- assert_equal 41, @db.prepare('select :foo').bind(value).next_single_column
430
- assert_equal 42, @db.prepare('select :bar').bind(value).next_single_column
431
- assert_nil @db.prepare('select :baz').bind(value).next_single_column
502
+ assert_equal 41, @db.prepare_argv('select :foo').bind(value).next
503
+ assert_equal 42, @db.prepare_argv('select :bar').bind(value).next
504
+ assert_nil @db.prepare_argv('select :baz').bind(value).next
432
505
  end
433
506
 
434
507
  def test_parameter_binding_from_data_class
435
508
  skip "Data isn't supported in Ruby < 3.2" if RUBY_VERSION < '3.2'
436
509
 
437
- foo_bar = Data.define(:":foo", :bar)
438
- value = foo_bar.new(":foo": 41, bar: 42)
439
- assert_equal 42, @db.prepare('select :bar').bind(value).next_single_column
440
- assert_nil @db.prepare('select :baz').bind(value).next_single_column
510
+ foo_bar = Data.define(:':foo', :bar)
511
+ value = foo_bar.new(':foo': 41, bar: 42)
512
+ assert_equal 42, @db.prepare_argv('select :bar').bind(value).next
513
+ assert_nil @db.prepare_argv('select :baz').bind(value).next
441
514
  end
442
515
 
443
516
  def test_query_columns
@@ -446,10 +519,10 @@ class QueryTest < MiniTest::Test
446
519
  end
447
520
 
448
521
  def test_query_columns_with_parameterized_sql
449
- q = @db.prepare('select * from t where z = :z')
522
+ q = @db.prepare_ary('select * from t where z = :z')
450
523
  q.bind(z: 9)
451
524
  assert_equal [:x, :y, :z], q.columns
452
- assert_equal [[7, 8, 9]], q.to_a_ary
525
+ assert_equal [[7, 8, 9]], q.to_a
453
526
  end
454
527
 
455
528
  def test_query_close
@@ -659,16 +732,16 @@ class QueryTest < MiniTest::Test
659
732
  [[3, 3]]
660
733
  ], results
661
734
 
662
- q = @db.prepare('update foo set b = ? returning *')
735
+ q = @db.prepare_ary('update foo set b = ? returning *')
663
736
 
664
- results = q.batch_query_ary([42, 43])
737
+ results = q.batch_query([42, 43])
665
738
  assert_equal [
666
739
  [[1, 42], [2, 42], [3, 42]],
667
740
  [[1, 43], [2, 43], [3, 43]]
668
741
  ], results
669
742
 
670
743
  array = []
671
- changes = q.batch_query_ary([44, 45]) do |rows|
744
+ changes = q.batch_query([44, 45]) do |rows|
672
745
  array << rows
673
746
  end
674
747
  assert_equal 6, changes
@@ -690,16 +763,16 @@ class QueryTest < MiniTest::Test
690
763
  [[3, 3]]
691
764
  ], results
692
765
 
693
- q = @db.prepare('update foo set b = ? returning *')
766
+ q = @db.prepare_ary('update foo set b = ? returning *')
694
767
 
695
- results = q.batch_query_ary(42..43)
768
+ results = q.batch_query(42..43)
696
769
  assert_equal [
697
770
  [[1, 42], [2, 42], [3, 42]],
698
771
  [[1, 43], [2, 43], [3, 43]]
699
772
  ], results
700
773
 
701
774
  array = []
702
- changes = q.batch_query_ary(44..45) do |rows|
775
+ changes = q.batch_query(44..45) do |rows|
703
776
  array << rows
704
777
  end
705
778
  assert_equal 6, changes
@@ -721,10 +794,10 @@ class QueryTest < MiniTest::Test
721
794
  [[3, 3]]
722
795
  ], results
723
796
 
724
- q = @db.prepare('update foo set b = ? returning *')
797
+ q = @db.prepare_ary('update foo set b = ? returning *')
725
798
 
726
799
  pr = parameter_source_proc([42, 43])
727
- results = q.batch_query_ary(pr)
800
+ results = q.batch_query(pr)
728
801
  assert_equal [
729
802
  [[1, 42], [2, 42], [3, 42]],
730
803
  [[1, 43], [2, 43], [3, 43]]
@@ -732,7 +805,7 @@ class QueryTest < MiniTest::Test
732
805
 
733
806
  array = []
734
807
  pr = parameter_source_proc([44, 45])
735
- changes = q.batch_query_ary(pr) do |rows|
808
+ changes = q.batch_query(pr) do |rows|
736
809
  array << rows
737
810
  end
738
811
  assert_equal 6, changes
@@ -754,16 +827,16 @@ class QueryTest < MiniTest::Test
754
827
  [[3, 3]]
755
828
  ], results
756
829
 
757
- q = @db.prepare('update foo set b = ? returning b * 10 + a')
830
+ q = @db.prepare_argv('update foo set b = ? returning b * 10 + a')
758
831
 
759
- results = q.batch_query_single_column([42, 43])
832
+ results = q.batch_query([42, 43])
760
833
  assert_equal [
761
834
  [421, 422, 423],
762
835
  [431, 432, 433]
763
836
  ], results
764
837
 
765
838
  array = []
766
- changes = q.batch_query_single_column([44, 45]) do |rows|
839
+ changes = q.batch_query([44, 45]) do |rows|
767
840
  array << rows
768
841
  end
769
842
  assert_equal 6, changes
@@ -785,16 +858,16 @@ class QueryTest < MiniTest::Test
785
858
  [[3, 3]]
786
859
  ], results
787
860
 
788
- q = @db.prepare('update foo set b = ? returning b * 10 + a')
861
+ q = @db.prepare_argv('update foo set b = ? returning b * 10 + a')
789
862
 
790
- results = q.batch_query_single_column(42..43)
863
+ results = q.batch_query(42..43)
791
864
  assert_equal [
792
865
  [421, 422, 423],
793
866
  [431, 432, 433]
794
867
  ], results
795
868
 
796
869
  array = []
797
- changes = q.batch_query_single_column(44..45) do |rows|
870
+ changes = q.batch_query(44..45) do |rows|
798
871
  array << rows
799
872
  end
800
873
  assert_equal 6, changes
@@ -816,10 +889,10 @@ class QueryTest < MiniTest::Test
816
889
  [[3, 3]]
817
890
  ], results
818
891
 
819
- q = @db.prepare('update foo set b = ? returning b * 10 + a')
892
+ q = @db.prepare_argv('update foo set b = ? returning b * 10 + a')
820
893
 
821
894
  pr = parameter_source_proc([42, 43])
822
- results = q.batch_query_single_column(pr)
895
+ results = q.batch_query(pr)
823
896
  assert_equal [
824
897
  [421, 422, 423],
825
898
  [431, 432, 433]
@@ -827,7 +900,7 @@ class QueryTest < MiniTest::Test
827
900
 
828
901
  array = []
829
902
  pr = parameter_source_proc([44, 45])
830
- changes = q.batch_query_single_column(pr) do |rows|
903
+ changes = q.batch_query(pr) do |rows|
831
904
  array << rows
832
905
  end
833
906
  assert_equal 6, changes
@@ -863,7 +936,7 @@ class QueryTest < MiniTest::Test
863
936
  end
864
937
 
865
938
  def test_query_eof
866
- query = @db.prepare('select x from t')
939
+ query = @db.prepare_argv('select x from t')
867
940
  assert_equal false, query.eof?
868
941
 
869
942
  query.next
@@ -884,13 +957,13 @@ class QueryTest < MiniTest::Test
884
957
  query.next
885
958
  assert_equal false, query.eof?
886
959
 
887
- assert_equal [1, 4, 7], query.to_a_single_column
960
+ assert_equal [1, 4, 7], query.to_a
888
961
  assert_equal true, query.eof?
889
962
  end
890
963
 
891
964
  def test_query_inspect
892
965
  q = @db.prepare('select x from t')
893
- assert_match /^\#\<Extralite::Query:0x[0-9a-f]+ #{q.sql.inspect}\>$/, q.inspect
966
+ assert_match(/^\#\<Extralite::Query:0x[0-9a-f]+ #{q.sql.inspect}\>$/, q.inspect)
894
967
  end
895
968
 
896
969
  def test_query_clone
@@ -910,6 +983,175 @@ class QueryTest < MiniTest::Test
910
983
  assert_kind_of Extralite::Query, q2
911
984
  assert_equal @db, q2.database
912
985
  assert_equal q1.sql, q2.sql
913
- refute_equal q1, q2
986
+ refute_same q1, q2
987
+
988
+ q1 = @db.prepare_argv('select x from t')
989
+ q2 = q1.dup
990
+
991
+ assert_kind_of Extralite::Query, q2
992
+ assert_equal @db, q2.database
993
+ assert_equal q1.sql, q2.sql
994
+ refute_same q1, q2
995
+ assert_equal :argv, q2.mode
996
+ end
997
+
998
+ def test_query_dup_with_transform
999
+ q1 = @db.prepare_ary('select x, y from t') { |a| a * 2 }
1000
+ q2 = q1.dup
1001
+
1002
+ assert_equal [
1003
+ [1, 2, 1, 2],
1004
+ [4, 5, 4, 5],
1005
+ [7, 8, 7, 8],
1006
+ ], q2.to_a
1007
+ end
1008
+ end
1009
+
1010
+ class QueryTransformTest < Minitest::Test
1011
+ def setup
1012
+ @db = Extralite::Database.new(':memory:')
1013
+ @db.query('create table t (a, b, c)')
1014
+
1015
+ @q1 = @db.prepare_argv('select c from t where a = ?')
1016
+ @q2 = @db.prepare_argv('select c from t order by a')
1017
+
1018
+ @q3 = @db.prepare('select * from t where a = ?')
1019
+ @q4 = @db.prepare('select * from t order by a')
1020
+
1021
+ @q5 = @db.prepare('select a, b from t where a = ?')
1022
+ @q6 = @db.prepare('select a, b from t order by a')
1023
+
1024
+ @db.batch_execute('insert into t (a, b, c) values (?, ?, ?)', [
1025
+ [1, 2, { foo: 42, bar: 43 }.to_json],
1026
+ [4, 5, { foo: 45, bar: 46 }.to_json]
1027
+ ])
1028
+ end
1029
+
1030
+ class MyModel
1031
+ def initialize(h)
1032
+ @h = h
1033
+ end
1034
+
1035
+ def values
1036
+ @h
1037
+ end
1038
+ end
1039
+
1040
+ def test_transform_hash
1041
+ q = @q5.transform { |h| MyModel.new(h) }
1042
+ assert_equal @q5, q
1043
+
1044
+ o = @q5.bind(1).next
1045
+ assert_kind_of MyModel, o
1046
+ assert_equal({ a: 1, b: 2 }, o.values)
1047
+
1048
+ o = @q5.bind(4).next
1049
+ assert_kind_of MyModel, o
1050
+ assert_equal({ a: 4, b: 5 }, o.values)
1051
+
1052
+ assert_equal [
1053
+ [{ a: 1, b: 2 }],
1054
+ [{ a: 4, b: 5 }]
1055
+ ], @q5.batch_query([[1], [4]]).map { |a| a.map(&:values) }
1056
+
1057
+ @q6.transform { |h| MyModel.new(h) }
1058
+ assert_equal [
1059
+ { a: 1, b: 2 },
1060
+ { a: 4, b: 5 }
1061
+ ], @q6.to_a.map(&:values)
1062
+
1063
+ buf = []
1064
+ @q6.each { |r| buf << r.values }
1065
+ assert_equal [
1066
+ { a: 1, b: 2 },
1067
+ { a: 4, b: 5 }
1068
+ ], buf
1069
+ end
1070
+
1071
+ def test_transform_ary
1072
+ @q5.mode = :ary
1073
+ q = @q5.transform { |h| MyModel.new(h) }
1074
+ assert_equal @q5, q
1075
+
1076
+ o = @q5.bind(1).next
1077
+ assert_kind_of MyModel, o
1078
+ assert_equal([1, 2], o.values)
1079
+
1080
+ o = @q5.bind(4).next
1081
+ assert_kind_of MyModel, o
1082
+ assert_equal([4, 5], o.values)
1083
+
1084
+ assert_equal [
1085
+ [[1, 2]],
1086
+ [[4, 5]]
1087
+ ], @q5.batch_query([[1], [4]]).map { |a| a.map(&:values) }
1088
+
1089
+ @q6.mode = :ary
1090
+ @q6.transform { |h| MyModel.new(h) }
1091
+ assert_equal [
1092
+ [1, 2],
1093
+ [4, 5]
1094
+ ], @q6.to_a.map(&:values)
1095
+
1096
+ buf = []
1097
+ @q6.each { |r| buf << r.values }
1098
+ assert_equal [
1099
+ [1, 2],
1100
+ [4, 5]
1101
+ ], buf
1102
+ end
1103
+
1104
+ def test_transform_argv_single_column
1105
+ q = @q1.transform { |c| JSON.parse(c, symbolize_names: true) }
1106
+ assert_equal @q1, q
1107
+
1108
+ assert_equal({ foo: 42, bar: 43 }, @q1.bind(1).next)
1109
+ assert_equal({ foo: 45, bar: 46 }, @q1.bind(4).next)
1110
+
1111
+ assert_equal [
1112
+ [{ foo: 42, bar: 43 }],
1113
+ [{ foo: 45, bar: 46 }]
1114
+ ], @q1.batch_query([[1], [4]])
1115
+
1116
+ @q2.transform { |c| JSON.parse(c, symbolize_names: true) }
1117
+ assert_equal [
1118
+ { foo: 42, bar: 43 },
1119
+ { foo: 45, bar: 46 }
1120
+ ], @q2.to_a
1121
+
1122
+ buf = []
1123
+ @q2.each { |r| buf << r }
1124
+ assert_equal [
1125
+ { foo: 42, bar: 43 },
1126
+ { foo: 45, bar: 46 }
1127
+ ], buf
1128
+ end
1129
+
1130
+ def test_transform_argv_multi_column
1131
+ @q3.mode = :argv
1132
+ q = @q3.transform { |a, b, c| { a: a, b: b, c: JSON.parse(c, symbolize_names: true) } }
1133
+ assert_equal @q3, q
1134
+
1135
+ assert_equal({ a: 1, b: 2, c: { foo: 42, bar: 43 }}, @q3.bind(1).next)
1136
+ assert_equal({ a: 4, b: 5, c: { foo: 45, bar: 46 }}, @q3.bind(4).next)
1137
+
1138
+ assert_equal [
1139
+ [{ a: 1, b: 2, c: { foo: 42, bar: 43 }}],
1140
+ [{ a: 4, b: 5, c: { foo: 45, bar: 46 }}]
1141
+ ], @q3.batch_query([[1], [4]])
1142
+
1143
+ @q4.mode = :argv
1144
+ @q4.transform { |a, b, c| { a: a, b: b, c: JSON.parse(c, symbolize_names: true) } }
1145
+ assert_equal [
1146
+ { a: 1, b: 2, c: { foo: 42, bar: 43 }},
1147
+ { a: 4, b: 5, c: { foo: 45, bar: 46 }}
1148
+ ], @q4.to_a
1149
+
1150
+ buf = []
1151
+ @q4.each { |r| buf << r }
1152
+ assert_equal [
1153
+ { a: 1, b: 2, c: { foo: 42, bar: 43 }},
1154
+ { a: 4, b: 5, c: { foo: 45, bar: 46 }}
1155
+ ], buf
914
1156
  end
915
1157
  end