extralite 2.5 → 2.7

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 (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