extralite 2.6 → 2.7.1
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.yardopts +1 -1
- data/CHANGELOG.md +32 -17
- data/Gemfile +4 -0
- data/Gemfile-bundle +1 -1
- data/README.md +262 -75
- data/Rakefile +18 -0
- data/TODO.md +0 -9
- data/examples/kv_store.rb +49 -0
- data/examples/multi_fiber.rb +16 -0
- data/examples/on_progress.rb +9 -0
- data/examples/pubsub_store_polyphony.rb +194 -0
- data/examples/pubsub_store_threads.rb +204 -0
- data/ext/extralite/changeset.c +3 -3
- data/ext/extralite/common.c +173 -87
- data/ext/extralite/database.c +650 -315
- data/ext/extralite/extconf.rb +7 -11
- data/ext/extralite/extralite.h +89 -48
- data/ext/extralite/iterator.c +6 -84
- data/ext/extralite/query.c +165 -256
- data/extralite-bundle.gemspec +1 -1
- data/extralite.gemspec +1 -1
- data/gemspec.rb +10 -11
- data/lib/extralite/version.rb +1 -1
- data/lib/extralite.rb +27 -17
- data/lib/sequel/adapters/extralite.rb +1 -1
- data/test/helper.rb +2 -1
- data/test/perf_argv_transform.rb +74 -0
- data/test/perf_hash_transform.rb +66 -0
- data/test/perf_polyphony.rb +74 -0
- data/test/test_changeset.rb +2 -2
- data/test/test_database.rb +531 -115
- data/test/test_extralite.rb +2 -2
- data/test/test_iterator.rb +28 -13
- data/test/test_query.rb +348 -111
- data/test/test_sequel.rb +4 -4
- metadata +20 -14
- data/Gemfile.lock +0 -37
data/test/test_database.rb
CHANGED
@@ -4,8 +4,9 @@ require_relative 'helper'
|
|
4
4
|
|
5
5
|
require 'date'
|
6
6
|
require 'tempfile'
|
7
|
+
require 'json'
|
7
8
|
|
8
|
-
class DatabaseTest <
|
9
|
+
class DatabaseTest < Minitest::Test
|
9
10
|
def setup
|
10
11
|
@db = Extralite::Database.new(':memory:')
|
11
12
|
@db.query('create table if not exists t (x,y,z)')
|
@@ -47,27 +48,38 @@ class DatabaseTest < MiniTest::Test
|
|
47
48
|
assert_equal [], r
|
48
49
|
end
|
49
50
|
|
50
|
-
def
|
51
|
-
r = @db.
|
52
|
-
assert_equal
|
51
|
+
def test_query_argv
|
52
|
+
r = @db.query_argv('select * from t')
|
53
|
+
assert_equal [[1, 2, 3], [4, 5, 6]], r
|
53
54
|
|
54
|
-
r = @db.
|
55
|
-
|
55
|
+
r = @db.query_argv('select * from t where x = 2')
|
56
|
+
assert_equal [], r
|
57
|
+
|
58
|
+
# with block
|
59
|
+
r = []
|
60
|
+
@db.query_argv('select * from t') { |a, b, c| r << [a, b, c] }
|
61
|
+
assert_equal [[1, 2, 3], [4, 5, 6]], r
|
56
62
|
end
|
57
63
|
|
58
|
-
def
|
59
|
-
|
60
|
-
|
64
|
+
def test_query_argv_with_too_many_columns
|
65
|
+
assert_raises(Extralite::Error) {
|
66
|
+
@db.query_argv('select 1, 2, 3, 4, 5, 6, 7, 8, 9');
|
67
|
+
}
|
68
|
+
end
|
61
69
|
|
62
|
-
|
63
|
-
|
70
|
+
def test_query_single
|
71
|
+
r = @db.query_single('select * from t order by x desc limit 1')
|
72
|
+
assert_equal({ x: 4, y: 5, z: 6 }, r)
|
73
|
+
|
74
|
+
r = @db.query_single('select * from t where x = 2')
|
75
|
+
assert_nil r
|
64
76
|
end
|
65
77
|
|
66
|
-
def
|
67
|
-
r = @db.
|
78
|
+
def test_query_single_argv
|
79
|
+
r = @db.query_single_argv('select z from t order by Z desc limit 1')
|
68
80
|
assert_equal 6, r
|
69
81
|
|
70
|
-
r = @db.
|
82
|
+
r = @db.query_single_argv('select z from t where x = 2')
|
71
83
|
assert_nil r
|
72
84
|
end
|
73
85
|
|
@@ -87,7 +99,7 @@ class DatabaseTest < MiniTest::Test
|
|
87
99
|
def test_multiple_statements
|
88
100
|
@db.query("insert into t values ('a', 'b', 'c'); insert into t values ('d', 'e', 'f');")
|
89
101
|
|
90
|
-
assert_equal [1, 4, 'a', 'd'], @db.
|
102
|
+
assert_equal [1, 4, 'a', 'd'], @db.query_argv('select x from t order by x')
|
91
103
|
end
|
92
104
|
|
93
105
|
def test_multiple_statements_with_error
|
@@ -111,13 +123,13 @@ class DatabaseTest < MiniTest::Test
|
|
111
123
|
|
112
124
|
def test_close
|
113
125
|
assert_equal false, @db.closed?
|
114
|
-
r = @db.
|
126
|
+
r = @db.query_single_argv('select 42')
|
115
127
|
assert_equal 42, r
|
116
128
|
|
117
129
|
assert_equal @db, @db.close
|
118
130
|
assert_equal true, @db.closed?
|
119
131
|
|
120
|
-
assert_raises(Extralite::Error) { @db.
|
132
|
+
assert_raises(Extralite::Error) { @db.query_single_argv('select 42') }
|
121
133
|
end
|
122
134
|
|
123
135
|
def test_parameter_binding_simple
|
@@ -127,7 +139,7 @@ class DatabaseTest < MiniTest::Test
|
|
127
139
|
r = @db.query('select x, y, z from t where z = ?', 6)
|
128
140
|
assert_equal [{ x: 4, y: 5, z: 6 }], r
|
129
141
|
|
130
|
-
error = assert_raises(Extralite::ParameterError) { @db.
|
142
|
+
error = assert_raises(Extralite::ParameterError) { @db.query_single_argv('select ?', Date.today) }
|
131
143
|
assert_equal error.message, 'Cannot bind parameter at position 1 of type Date'
|
132
144
|
end
|
133
145
|
|
@@ -161,33 +173,33 @@ class DatabaseTest < MiniTest::Test
|
|
161
173
|
class Foo; end
|
162
174
|
|
163
175
|
def test_parameter_binding_from_hash
|
164
|
-
assert_equal 42, @db.
|
165
|
-
assert_equal 42, @db.
|
166
|
-
assert_equal 42, @db.
|
167
|
-
assert_nil @db.
|
176
|
+
assert_equal 42, @db.query_single_argv('select :bar', foo: 41, bar: 42)
|
177
|
+
assert_equal 42, @db.query_single_argv('select :bar', 'foo' => 41, 'bar' => 42)
|
178
|
+
assert_equal 42, @db.query_single_argv('select ?8', 7 => 41, 8 => 42)
|
179
|
+
assert_nil @db.query_single_argv('select :bar', foo: 41)
|
168
180
|
|
169
|
-
error = assert_raises(Extralite::ParameterError) { @db.
|
181
|
+
error = assert_raises(Extralite::ParameterError) { @db.query_single_argv('select ?', Foo.new => 42) }
|
170
182
|
assert_equal error.message, 'Cannot bind parameter with a key of type DatabaseTest::Foo'
|
171
183
|
|
172
|
-
error = assert_raises(Extralite::ParameterError) { @db.
|
184
|
+
error = assert_raises(Extralite::ParameterError) { @db.query_single_argv('select ?', %w[a b] => 42) }
|
173
185
|
assert_equal error.message, 'Cannot bind parameter with a key of type Array'
|
174
186
|
end
|
175
187
|
|
176
188
|
def test_parameter_binding_from_struct
|
177
|
-
foo_bar = Struct.new(:
|
189
|
+
foo_bar = Struct.new(:':foo', :bar)
|
178
190
|
value = foo_bar.new(41, 42)
|
179
|
-
assert_equal 41, @db.
|
180
|
-
assert_equal 42, @db.
|
181
|
-
assert_nil @db.
|
191
|
+
assert_equal 41, @db.query_single_argv('select :foo', value)
|
192
|
+
assert_equal 42, @db.query_single_argv('select :bar', value)
|
193
|
+
assert_nil @db.query_single_argv('select :baz', value)
|
182
194
|
end
|
183
195
|
|
184
196
|
def test_parameter_binding_from_data_class
|
185
197
|
skip "Data isn't supported in Ruby < 3.2" if RUBY_VERSION < '3.2'
|
186
198
|
|
187
|
-
foo_bar = Data.define(:
|
188
|
-
value = foo_bar.new(
|
189
|
-
assert_equal 42, @db.
|
190
|
-
assert_nil @db.
|
199
|
+
foo_bar = Data.define(:':foo', :bar)
|
200
|
+
value = foo_bar.new(':foo': 41, bar: 42)
|
201
|
+
assert_equal 42, @db.query_single_argv('select :bar', value)
|
202
|
+
assert_nil @db.query_single_argv('select :baz', value)
|
191
203
|
end
|
192
204
|
|
193
205
|
def test_parameter_binding_for_blobs
|
@@ -197,69 +209,69 @@ class DatabaseTest < MiniTest::Test
|
|
197
209
|
|
198
210
|
# it's a string, not a blob
|
199
211
|
@db.execute('INSERT INTO blobs VALUES (?)', 'Hello, 世界!')
|
200
|
-
result = @db.
|
212
|
+
result = @db.query_single(sql, @db.last_insert_rowid)
|
201
213
|
assert_equal 'text', result[:type]
|
202
214
|
assert_equal Encoding::UTF_8, result[:data].encoding
|
203
215
|
|
204
216
|
data = File.binread(blob_path)
|
205
217
|
@db.execute('INSERT INTO blobs VALUES (?)', data)
|
206
|
-
result = @db.
|
218
|
+
result = @db.query_single(sql, @db.last_insert_rowid)
|
207
219
|
assert_equal 'blob', result[:type]
|
208
220
|
assert_equal data, result[:data]
|
209
221
|
|
210
222
|
data = (+'Hello, 世界!').force_encoding(Encoding::ASCII_8BIT)
|
211
223
|
@db.execute('INSERT INTO blobs VALUES (?)', data)
|
212
|
-
result = @db.
|
224
|
+
result = @db.query_single(sql, @db.last_insert_rowid)
|
213
225
|
assert_equal 'blob', result[:type]
|
214
226
|
assert_equal Encoding::ASCII_8BIT, result[:data].encoding
|
215
227
|
assert_equal 'Hello, 世界!', result[:data].force_encoding(Encoding::UTF_8)
|
216
228
|
|
217
229
|
data = Extralite::Blob.new('Hello, 世界!')
|
218
230
|
@db.execute('INSERT INTO blobs VALUES (?)', data)
|
219
|
-
result = @db.
|
231
|
+
result = @db.query_single(sql, @db.last_insert_rowid)
|
220
232
|
assert_equal 'blob', result[:type]
|
221
233
|
assert_equal Encoding::ASCII_8BIT, result[:data].encoding
|
222
234
|
assert_equal 'Hello, 世界!', result[:data].force_encoding(Encoding::UTF_8)
|
223
235
|
end
|
224
236
|
|
225
237
|
def test_parameter_binding_for_simple_types
|
226
|
-
assert_nil @db.
|
238
|
+
assert_nil @db.query_single_argv('select ?', nil)
|
227
239
|
|
228
240
|
# 32-bit integers
|
229
|
-
assert_equal
|
230
|
-
assert_equal
|
241
|
+
assert_equal(-2** 31, @db.query_single_argv('select ?', -2**31))
|
242
|
+
assert_equal(2**31 - 1, @db.query_single_argv('select ?', 2**31 - 1))
|
231
243
|
|
232
244
|
# 64-bit integers
|
233
|
-
assert_equal
|
234
|
-
assert_equal
|
245
|
+
assert_equal(-2 ** 63, @db.query_single_argv('select ?', -2 ** 63))
|
246
|
+
assert_equal(2**63 - 1, @db.query_single_argv('select ?', 2**63 - 1))
|
235
247
|
|
236
248
|
# floats
|
237
|
-
assert_equal Float::MIN, @db.
|
238
|
-
assert_equal Float::MAX, @db.
|
249
|
+
assert_equal Float::MIN, @db.query_single_argv('select ?', Float::MIN)
|
250
|
+
assert_equal Float::MAX, @db.query_single_argv('select ?', Float::MAX)
|
239
251
|
|
240
252
|
# boolean
|
241
|
-
assert_equal 1, @db.
|
242
|
-
assert_equal 0, @db.
|
253
|
+
assert_equal 1, @db.query_single_argv('select ?', true)
|
254
|
+
assert_equal 0, @db.query_single_argv('select ?', false)
|
243
255
|
|
244
256
|
# strings and symbols
|
245
|
-
assert_equal 'foo', @db.
|
246
|
-
assert_equal 'foo', @db.
|
257
|
+
assert_equal 'foo', @db.query_single_argv('select ?', 'foo')
|
258
|
+
assert_equal 'foo', @db.query_single_argv('select ?', :foo)
|
247
259
|
end
|
248
260
|
|
249
261
|
def test_value_casting
|
250
|
-
r = @db.
|
262
|
+
r = @db.query_single_argv("select 'abc'")
|
251
263
|
assert_equal 'abc', r
|
252
264
|
|
253
|
-
r = @db.
|
265
|
+
r = @db.query_single_argv('select 123')
|
254
266
|
assert_equal 123, r
|
255
267
|
|
256
|
-
r = @db.
|
268
|
+
r = @db.query_single_argv('select 12.34')
|
257
269
|
assert_equal 12.34, r
|
258
270
|
|
259
|
-
r = @db.
|
271
|
+
r = @db.query_single_argv('select zeroblob(4)')
|
260
272
|
assert_equal "\x00\x00\x00\x00", r
|
261
273
|
|
262
|
-
r = @db.
|
274
|
+
r = @db.query_single_argv('select null')
|
263
275
|
assert_nil r
|
264
276
|
end
|
265
277
|
|
@@ -271,7 +283,7 @@ class DatabaseTest < MiniTest::Test
|
|
271
283
|
@db.load_extension(File.join(__dir__, 'extensions/text.dylib'))
|
272
284
|
end
|
273
285
|
|
274
|
-
r = @db.
|
286
|
+
r = @db.query_single_argv("select reverse('abcd')")
|
275
287
|
assert_equal 'dcba', r
|
276
288
|
end
|
277
289
|
|
@@ -592,7 +604,7 @@ class DatabaseTest < MiniTest::Test
|
|
592
604
|
], array
|
593
605
|
end
|
594
606
|
|
595
|
-
def
|
607
|
+
def test_batch_query_argv_with_array
|
596
608
|
@db.query('create table foo (a, b, c)')
|
597
609
|
assert_equal [], @db.query('select * from foo')
|
598
610
|
|
@@ -600,20 +612,20 @@ class DatabaseTest < MiniTest::Test
|
|
600
612
|
[1, '2', 3],
|
601
613
|
['4', 5, 6]
|
602
614
|
]
|
603
|
-
results = @db.
|
615
|
+
results = @db.batch_query_argv('insert into foo values (?, ?, ?) returning c', data)
|
604
616
|
assert_equal [
|
605
617
|
[3],
|
606
618
|
[6]
|
607
619
|
], results
|
608
620
|
|
609
|
-
results = @db.
|
621
|
+
results = @db.batch_query_argv('update foo set c = ? returning c * 10 + cast(b as integer)', [42, 43])
|
610
622
|
assert_equal [
|
611
623
|
[422, 425],
|
612
624
|
[432, 435]
|
613
625
|
], results
|
614
626
|
|
615
627
|
array = []
|
616
|
-
changes = @db.
|
628
|
+
changes = @db.batch_query_argv('update foo set c = ? returning c * 10 + cast(b as integer)', [44, 45]) do |rows|
|
617
629
|
array << rows
|
618
630
|
end
|
619
631
|
assert_equal 4, changes
|
@@ -623,25 +635,25 @@ class DatabaseTest < MiniTest::Test
|
|
623
635
|
], array
|
624
636
|
end
|
625
637
|
|
626
|
-
def
|
638
|
+
def test_batch_query_argv_with_enumerable
|
627
639
|
@db.query('create table foo (a integer primary key, b)')
|
628
640
|
assert_equal [], @db.query('select * from foo')
|
629
641
|
|
630
|
-
results = @db.
|
642
|
+
results = @db.batch_query_argv('insert into foo (b) values (?) returning b * 10 + a', 11..13)
|
631
643
|
assert_equal [
|
632
644
|
[111],
|
633
645
|
[122],
|
634
646
|
[133]
|
635
647
|
], results
|
636
648
|
|
637
|
-
results = @db.
|
649
|
+
results = @db.batch_query_argv('update foo set b = ? returning b * 10 + a', 42..43)
|
638
650
|
assert_equal [
|
639
651
|
[421, 422, 423],
|
640
652
|
[431, 432, 433]
|
641
653
|
], results
|
642
654
|
|
643
655
|
array = []
|
644
|
-
changes = @db.
|
656
|
+
changes = @db.batch_query_argv('update foo set b = ? returning b * 10 + a', 44..45) do |rows|
|
645
657
|
array << rows
|
646
658
|
end
|
647
659
|
assert_equal 6, changes
|
@@ -651,13 +663,13 @@ class DatabaseTest < MiniTest::Test
|
|
651
663
|
], array
|
652
664
|
end
|
653
665
|
|
654
|
-
def
|
666
|
+
def test_batch_query_argv_with_proc
|
655
667
|
@db.query('create table foo (a integer primary key, b)')
|
656
668
|
assert_equal [], @db.query('select * from foo')
|
657
669
|
|
658
670
|
pr = parameter_source_proc([5, 4, 3])
|
659
671
|
assert_kind_of Proc, pr
|
660
|
-
results = @db.
|
672
|
+
results = @db.batch_query_argv('insert into foo (b) values (?) returning b', pr)
|
661
673
|
assert_equal [
|
662
674
|
[5],
|
663
675
|
[4],
|
@@ -665,7 +677,7 @@ class DatabaseTest < MiniTest::Test
|
|
665
677
|
], results
|
666
678
|
|
667
679
|
pr = parameter_source_proc([42, 43])
|
668
|
-
results = @db.
|
680
|
+
results = @db.batch_query_argv('update foo set b = ? returning b * 10 + a', pr)
|
669
681
|
assert_equal [
|
670
682
|
[421, 422, 423],
|
671
683
|
[431, 432, 433]
|
@@ -673,7 +685,7 @@ class DatabaseTest < MiniTest::Test
|
|
673
685
|
|
674
686
|
array = []
|
675
687
|
pr = parameter_source_proc([44, 45])
|
676
|
-
changes = @db.
|
688
|
+
changes = @db.batch_query_argv('update foo set b = ? returning b * 10 + a', pr) do |rows|
|
677
689
|
array << rows
|
678
690
|
end
|
679
691
|
assert_equal 6, changes
|
@@ -703,6 +715,8 @@ class DatabaseTest < MiniTest::Test
|
|
703
715
|
SQL
|
704
716
|
}
|
705
717
|
t.join
|
718
|
+
ensure
|
719
|
+
t&.kill
|
706
720
|
end
|
707
721
|
|
708
722
|
def test_database_status
|
@@ -766,6 +780,8 @@ class DatabaseTest < MiniTest::Test
|
|
766
780
|
|
767
781
|
db2.busy_timeout = nil
|
768
782
|
assert_raises(Extralite::BusyError) { db2.query('begin exclusive') }
|
783
|
+
ensure
|
784
|
+
t&.kill
|
769
785
|
end
|
770
786
|
|
771
787
|
def test_database_total_changes
|
@@ -817,30 +833,31 @@ class DatabaseTest < MiniTest::Test
|
|
817
833
|
db = Extralite::Database.new(':memory:', gvl_release_threshold: 23)
|
818
834
|
assert_equal 23, db.gvl_release_threshold
|
819
835
|
|
820
|
-
fn = Tempfile.new('
|
821
|
-
db = Extralite::Database.new(fn,
|
836
|
+
fn = Tempfile.new('extralite_test_database_initialize_options_wal').path
|
837
|
+
db = Extralite::Database.new(fn, wal: true)
|
822
838
|
assert_equal 'wal', db.pragma(:journal_mode)
|
823
|
-
|
824
|
-
fn = Tempfile.new('extralite_test_database_initialize_options_2').path
|
825
|
-
db = Extralite::Database.new(fn, synchronous: true)
|
826
839
|
assert_equal 1, db.pragma(:synchronous)
|
840
|
+
|
841
|
+
fn = Tempfile.new('extralite_test_database_initialize_options_pragma').path
|
842
|
+
db = Extralite::Database.new(fn, pragma: { application_id: 42 })
|
843
|
+
assert_equal 42, db.pragma(:application_id)
|
827
844
|
end
|
828
845
|
|
829
846
|
def test_database_inspect
|
830
847
|
db = Extralite::Database.new(':memory:')
|
831
|
-
assert_match
|
848
|
+
assert_match(/^\#\<Extralite::Database:0x[0-9a-f]+ :memory:\>$/, db.inspect)
|
832
849
|
end
|
833
850
|
|
834
851
|
def test_database_inspect_on_closed_database
|
835
852
|
db = Extralite::Database.new(':memory:')
|
836
|
-
assert_match
|
853
|
+
assert_match(/^\#\<Extralite::Database:0x[0-9a-f]+ :memory:\>$/, db.inspect)
|
837
854
|
db.close
|
838
|
-
assert_match
|
855
|
+
assert_match(/^\#\<Extralite::Database:0x[0-9a-f]+ \(closed\)\>$/, db.inspect)
|
839
856
|
end
|
840
857
|
|
841
858
|
def test_string_encoding
|
842
859
|
db = Extralite::Database.new(':memory:')
|
843
|
-
v = db.
|
860
|
+
v = db.query_single_argv("select 'foo'")
|
844
861
|
assert_equal 'foo', v
|
845
862
|
assert_equal 'UTF-8', v.encoding.name
|
846
863
|
end
|
@@ -856,7 +873,7 @@ class DatabaseTest < MiniTest::Test
|
|
856
873
|
|
857
874
|
q1 = Queue.new
|
858
875
|
q2 = Queue.new
|
859
|
-
|
876
|
+
t = Thread.new do
|
860
877
|
db1.transaction do
|
861
878
|
assert_equal true, db1.transaction_active?
|
862
879
|
db1.execute('insert into foo values (42)')
|
@@ -871,9 +888,11 @@ class DatabaseTest < MiniTest::Test
|
|
871
888
|
assert_equal [], db2.query('select * from foo')
|
872
889
|
|
873
890
|
q2 << true
|
874
|
-
|
891
|
+
t.join
|
875
892
|
# transaction now committed
|
876
893
|
assert_equal [{ x: 42 }], db2.query('select * from foo')
|
894
|
+
ensure
|
895
|
+
t&.kill
|
877
896
|
end
|
878
897
|
|
879
898
|
def test_database_transaction_rollback
|
@@ -923,29 +942,82 @@ class DatabaseTest < MiniTest::Test
|
|
923
942
|
assert_equal [], db.query('select * from foo')
|
924
943
|
|
925
944
|
db.execute('insert into foo values (42)')
|
926
|
-
assert_equal [42], db.
|
945
|
+
assert_equal [42], db.query_argv('select x from foo')
|
927
946
|
|
928
947
|
db.savepoint(:a)
|
929
948
|
|
930
949
|
db.execute('insert into foo values (43)')
|
931
|
-
assert_equal [42, 43], db.
|
950
|
+
assert_equal [42, 43], db.query_argv('select x from foo')
|
932
951
|
|
933
952
|
db.savepoint(:b)
|
934
953
|
|
935
954
|
db.execute('insert into foo values (44)')
|
936
|
-
assert_equal [42, 43, 44], db.
|
955
|
+
assert_equal [42, 43, 44], db.query_argv('select x from foo')
|
937
956
|
|
938
957
|
db.rollback_to(:b)
|
939
|
-
assert_equal [42, 43], db.
|
958
|
+
assert_equal [42, 43], db.query_argv('select x from foo')
|
940
959
|
|
941
960
|
db.release(:a)
|
942
961
|
|
943
|
-
assert_equal [42, 43], db.
|
962
|
+
assert_equal [42, 43], db.query_argv('select x from foo')
|
944
963
|
end
|
945
964
|
end
|
965
|
+
|
966
|
+
def test_prepare
|
967
|
+
q = @db.prepare('select * from t order by x')
|
968
|
+
assert_kind_of Extralite::Query, q
|
969
|
+
|
970
|
+
assert_equal [
|
971
|
+
{ x: 1, y: 2, z: 3},
|
972
|
+
{ x: 4, y: 5, z: 6}
|
973
|
+
], q.to_a
|
974
|
+
end
|
975
|
+
|
976
|
+
def test_prepare_argv
|
977
|
+
q = @db.prepare_argv('select * from t order by x')
|
978
|
+
assert_kind_of Extralite::Query, q
|
979
|
+
|
980
|
+
buf = []
|
981
|
+
q.each { |x, y, z| buf << z }
|
982
|
+
assert_equal [3, 6], buf
|
983
|
+
end
|
984
|
+
|
985
|
+
def test_prepare_ary
|
986
|
+
q = @db.prepare_ary('select * from t order by x')
|
987
|
+
assert_kind_of Extralite::Query, q
|
988
|
+
|
989
|
+
assert_equal [
|
990
|
+
[1, 2, 3],
|
991
|
+
[4, 5, 6]
|
992
|
+
], q.to_a
|
993
|
+
end
|
994
|
+
|
995
|
+
def test_prepare_with_transform
|
996
|
+
q = @db.prepare('select * from t order by x') { |h| h[:x] * 100 + h[:y] * 10 + h[:z] }
|
997
|
+
assert_equal [
|
998
|
+
123,
|
999
|
+
456
|
1000
|
+
], q.to_a
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
def test_prepare_argv_with_transform
|
1004
|
+
q = @db.prepare_argv('select * from t order by x') { |x, y, z| x * 100 + y * 10 + z }
|
1005
|
+
assert_equal [
|
1006
|
+
123,
|
1007
|
+
456
|
1008
|
+
], q.to_a
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
def test_prepare_ary_with_transform
|
1012
|
+
q = @db.prepare_ary('select * from t order by x') { |r| r * 2 }
|
1013
|
+
assert_equal [
|
1014
|
+
[1, 2, 3, 1, 2, 3],
|
1015
|
+
[4, 5, 6, 4, 5, 6]
|
1016
|
+
], q.to_a
|
1017
|
+
end
|
946
1018
|
end
|
947
1019
|
|
948
|
-
class ScenarioTest <
|
1020
|
+
class ScenarioTest < Minitest::Test
|
949
1021
|
def setup
|
950
1022
|
@fn = Tempfile.new('extralite_scenario_test').path
|
951
1023
|
@db = Extralite::Database.new(@fn)
|
@@ -974,7 +1046,7 @@ class ScenarioTest < MiniTest::Test
|
|
974
1046
|
|
975
1047
|
sleep 0.1
|
976
1048
|
@db.query 'begin deferred'
|
977
|
-
result = @db.
|
1049
|
+
result = @db.query_argv('select x from t')
|
978
1050
|
assert_equal [1, 4], result
|
979
1051
|
|
980
1052
|
assert_raises(Extralite::BusyError) do
|
@@ -1008,8 +1080,10 @@ class ScenarioTest < MiniTest::Test
|
|
1008
1080
|
@db.query('insert into t values (7, 8, 9)')
|
1009
1081
|
@db.query('commit')
|
1010
1082
|
|
1011
|
-
result = @db.
|
1083
|
+
result = @db.query_argv('select x from t')
|
1012
1084
|
assert_equal [1, 4, 7], result
|
1085
|
+
ensure
|
1086
|
+
t&.kill
|
1013
1087
|
end
|
1014
1088
|
|
1015
1089
|
def test_concurrent_queries
|
@@ -1035,7 +1109,10 @@ class ScenarioTest < MiniTest::Test
|
|
1035
1109
|
t1.join
|
1036
1110
|
t2.join
|
1037
1111
|
|
1038
|
-
assert_equal (1..100).to_a, @db.
|
1112
|
+
assert_equal (1..100).to_a, @db.query_argv('select x from t order by x')
|
1113
|
+
ensure
|
1114
|
+
t1&.kill
|
1115
|
+
t2&.kill
|
1039
1116
|
end
|
1040
1117
|
|
1041
1118
|
def test_database_trace
|
@@ -1064,7 +1141,7 @@ class ScenarioTest < MiniTest::Test
|
|
1064
1141
|
end
|
1065
1142
|
end
|
1066
1143
|
|
1067
|
-
class BackupTest <
|
1144
|
+
class BackupTest < Minitest::Test
|
1068
1145
|
def setup
|
1069
1146
|
@src = Extralite::Database.new(':memory:')
|
1070
1147
|
@dst = Extralite::Database.new(':memory:')
|
@@ -1144,6 +1221,9 @@ class ConcurrencyTest < Minitest::Test
|
|
1144
1221
|
|
1145
1222
|
assert delays.size > 4
|
1146
1223
|
assert_equal 0, delays.select { |d| d > 0.15 }.size
|
1224
|
+
ensure
|
1225
|
+
t1&.kill
|
1226
|
+
t2&.kill
|
1147
1227
|
end
|
1148
1228
|
|
1149
1229
|
def test_gvl_always_hold
|
@@ -1178,6 +1258,9 @@ class ConcurrencyTest < Minitest::Test
|
|
1178
1258
|
|
1179
1259
|
assert delays.size >= 1
|
1180
1260
|
assert delays.first > 0.2
|
1261
|
+
ensure
|
1262
|
+
t1&.kill
|
1263
|
+
t2&.kill
|
1181
1264
|
end
|
1182
1265
|
|
1183
1266
|
def test_gvl_mode_get_set
|
@@ -1200,20 +1283,165 @@ class ConcurrencyTest < Minitest::Test
|
|
1200
1283
|
db = Extralite::Database.new(':memory:')
|
1201
1284
|
|
1202
1285
|
buf = []
|
1203
|
-
db.on_progress(1) { buf << :progress }
|
1286
|
+
db.on_progress(period: 1) { buf << :progress }
|
1204
1287
|
|
1205
|
-
result = db.
|
1288
|
+
result = db.query_single('select 1 as a, 2 as b, 3 as c')
|
1206
1289
|
assert_equal({ a: 1, b: 2, c: 3 }, result)
|
1207
1290
|
assert_in_range 5..7, buf.size
|
1208
1291
|
|
1209
1292
|
buf = []
|
1210
|
-
db.on_progress(2) { buf << :progress }
|
1293
|
+
db.on_progress(period: 2) { buf << :progress }
|
1211
1294
|
|
1212
|
-
result = db.
|
1295
|
+
result = db.query_single('select 1 as a, 2 as b, 3 as c')
|
1213
1296
|
assert_equal({ a: 1, b: 2, c: 3 }, result)
|
1214
1297
|
assert_in_range 2..4, buf.size
|
1215
1298
|
end
|
1216
1299
|
|
1300
|
+
def test_progress_handler_normal_mode
|
1301
|
+
db = Extralite::Database.new(':memory:')
|
1302
|
+
|
1303
|
+
count = 0
|
1304
|
+
db.on_progress(period: 1) { count += 1 }
|
1305
|
+
db.query('select 1 as a')
|
1306
|
+
assert count > 0
|
1307
|
+
base_count = count
|
1308
|
+
|
1309
|
+
count = 0
|
1310
|
+
db.on_progress(period: 1) { count += 1 }
|
1311
|
+
10.times { db.query('select 1 as a') }
|
1312
|
+
assert_equal base_count * 10, count
|
1313
|
+
|
1314
|
+
count = 0
|
1315
|
+
db.on_progress(period: 10, tick: 1) { count += 1 }
|
1316
|
+
10.times { db.query('select 1 as a') }
|
1317
|
+
assert_equal base_count, count
|
1318
|
+
end
|
1319
|
+
|
1320
|
+
def test_progress_handler_at_least_once_mode
|
1321
|
+
db = Extralite::Database.new(':memory:')
|
1322
|
+
|
1323
|
+
count = 0
|
1324
|
+
db.on_progress(period: 1) { count += 1 }
|
1325
|
+
db.query('select 1 as a')
|
1326
|
+
assert count > 0
|
1327
|
+
base_count = count
|
1328
|
+
|
1329
|
+
count = 0
|
1330
|
+
db.on_progress(period: 1, mode: :at_least_once) { count += 1 }
|
1331
|
+
10.times { db.query('select 1 as a') }
|
1332
|
+
assert_equal base_count * 10 + 10, count
|
1333
|
+
|
1334
|
+
count = 0
|
1335
|
+
db.on_progress(period: 10, tick: 1, mode: :at_least_once) { count += 1 }
|
1336
|
+
10.times { db.query('select 1 as a') }
|
1337
|
+
assert_equal base_count + 10, count
|
1338
|
+
end
|
1339
|
+
|
1340
|
+
def test_progress_handler_once_mode
|
1341
|
+
db = Extralite::Database.new(':memory:')
|
1342
|
+
|
1343
|
+
count = 0
|
1344
|
+
db.on_progress(mode: :once) { count += 1 }
|
1345
|
+
10.times { db.query('select 1 as a') }
|
1346
|
+
assert_equal 10, count
|
1347
|
+
|
1348
|
+
count = 0
|
1349
|
+
db.on_progress(period: 1, mode: :once) { count += 1 }
|
1350
|
+
10.times { db.query('select 1 as a') }
|
1351
|
+
assert_equal 10, count
|
1352
|
+
|
1353
|
+
count = 0
|
1354
|
+
db.on_progress(period: 10, tick: 1, mode: :once) { count += 1 }
|
1355
|
+
10.times { db.query('select 1 as a') }
|
1356
|
+
assert_equal 10, count
|
1357
|
+
end
|
1358
|
+
|
1359
|
+
def test_progress_handler_once_mode_with_batch_query
|
1360
|
+
db = Extralite::Database.new(':memory:')
|
1361
|
+
|
1362
|
+
count = 0
|
1363
|
+
db.on_progress(period: 1, mode: :once) { count += 1 }
|
1364
|
+
db.batch_query('select ?', 1..10)
|
1365
|
+
assert_equal 10, count
|
1366
|
+
|
1367
|
+
db.batch_query('select ?', 1..3)
|
1368
|
+
assert_equal 13, count
|
1369
|
+
end
|
1370
|
+
|
1371
|
+
def test_progress_handler_reset
|
1372
|
+
db = Extralite::Database.new(':memory:')
|
1373
|
+
|
1374
|
+
count = 0
|
1375
|
+
set_progress = -> {
|
1376
|
+
count = 0
|
1377
|
+
db.on_progress(mode: :once) { count += 1 }
|
1378
|
+
}
|
1379
|
+
|
1380
|
+
set_progress.()
|
1381
|
+
10.times { db.query('select 1 as a') }
|
1382
|
+
assert_equal 10, count
|
1383
|
+
|
1384
|
+
count = 0
|
1385
|
+
db.on_progress(mode: :none)
|
1386
|
+
10.times { db.query('select 1 as a') }
|
1387
|
+
assert_equal 0, count
|
1388
|
+
|
1389
|
+
set_progress.()
|
1390
|
+
10.times { db.query('select 1 as a') }
|
1391
|
+
assert_equal 10, count
|
1392
|
+
|
1393
|
+
count = 0
|
1394
|
+
db.on_progress(period: 0) { foo }
|
1395
|
+
10.times { db.query('select 1 as a') }
|
1396
|
+
assert_equal 0, count
|
1397
|
+
|
1398
|
+
set_progress.()
|
1399
|
+
10.times { db.query('select 1 as a') }
|
1400
|
+
assert_equal 10, count
|
1401
|
+
|
1402
|
+
count = 0
|
1403
|
+
db.on_progress
|
1404
|
+
10.times { db.query('select 1 as a') }
|
1405
|
+
assert_equal 0, count
|
1406
|
+
end
|
1407
|
+
|
1408
|
+
def test_progress_handler_invalid_arg
|
1409
|
+
db = Extralite::Database.new(':memory:')
|
1410
|
+
|
1411
|
+
assert_raises(TypeError) { db.on_progress(period: :foo) }
|
1412
|
+
assert_raises(TypeError) { db.on_progress(tick: :foo) }
|
1413
|
+
assert_raises(ArgumentError) { db.on_progress(mode: :foo) }
|
1414
|
+
end
|
1415
|
+
|
1416
|
+
def test_progress_handler_once_mode_with_prepared_query
|
1417
|
+
db = Extralite::Database.new(':memory:')
|
1418
|
+
db.execute 'create table foo (x)'
|
1419
|
+
db.batch_query('insert into foo values (?)', 1..10)
|
1420
|
+
q = db.prepare('select x from foo')
|
1421
|
+
|
1422
|
+
count = 0
|
1423
|
+
db.on_progress(period: 1, mode: :once) { count += 1 }
|
1424
|
+
|
1425
|
+
q.to_a
|
1426
|
+
assert_equal 1, count
|
1427
|
+
|
1428
|
+
q.reset
|
1429
|
+
record_count = 0
|
1430
|
+
assert_equal 2, count
|
1431
|
+
while q.next
|
1432
|
+
record_count += 1
|
1433
|
+
end
|
1434
|
+
assert_equal 10, record_count
|
1435
|
+
assert_equal 2, count
|
1436
|
+
|
1437
|
+
q.reset
|
1438
|
+
assert_equal 3, count
|
1439
|
+
while q.next
|
1440
|
+
record_count += 1
|
1441
|
+
end
|
1442
|
+
assert_equal 3, count
|
1443
|
+
end
|
1444
|
+
|
1217
1445
|
LONG_QUERY = <<~SQL
|
1218
1446
|
WITH RECURSIVE
|
1219
1447
|
fibo (curr, next)
|
@@ -1228,7 +1456,7 @@ class ConcurrencyTest < Minitest::Test
|
|
1228
1456
|
def test_progress_handler_timeout_interrupt
|
1229
1457
|
db = Extralite::Database.new(':memory:')
|
1230
1458
|
t0 = Time.now
|
1231
|
-
db.on_progress
|
1459
|
+
db.on_progress do
|
1232
1460
|
Thread.pass
|
1233
1461
|
db.interrupt if Time.now - t0 >= 0.2
|
1234
1462
|
end
|
@@ -1270,7 +1498,7 @@ class ConcurrencyTest < Minitest::Test
|
|
1270
1498
|
def test_progress_handler_timeout_raise
|
1271
1499
|
db = Extralite::Database.new(':memory:')
|
1272
1500
|
t0 = Time.now
|
1273
|
-
db.on_progress
|
1501
|
+
db.on_progress do
|
1274
1502
|
Thread.pass
|
1275
1503
|
raise CustomTimeoutError if Time.now - t0 >= 0.2
|
1276
1504
|
end
|
@@ -1315,7 +1543,7 @@ class ConcurrencyTest < Minitest::Test
|
|
1315
1543
|
assert_raises(Extralite::BusyError) { db2.query('begin exclusive') }
|
1316
1544
|
|
1317
1545
|
t0 = Time.now
|
1318
|
-
db2.on_progress
|
1546
|
+
db2.on_progress do
|
1319
1547
|
Thread.pass
|
1320
1548
|
raise CustomTimeoutError if Time.now - t0 >= 0.2
|
1321
1549
|
end
|
@@ -1348,6 +1576,29 @@ class ConcurrencyTest < Minitest::Test
|
|
1348
1576
|
assert_equal 1, ((t1 - t0) * 5).round.to_i
|
1349
1577
|
assert_kind_of CustomTimeoutError, err
|
1350
1578
|
end
|
1579
|
+
|
1580
|
+
def test_global_progress_handler
|
1581
|
+
count = 0
|
1582
|
+
Extralite.on_progress(tick: 1, period: 1) { count += 1 }
|
1583
|
+
|
1584
|
+
db = Extralite::Database.new(':memory:')
|
1585
|
+
10.times { db.query('select 1') }
|
1586
|
+
refute_equal 0, count
|
1587
|
+
|
1588
|
+
old_count = count
|
1589
|
+
Extralite.on_progress # remove global progress handler
|
1590
|
+
|
1591
|
+
# already opened db should preserve progress handler behaviour
|
1592
|
+
10.times { db.query('select 1') }
|
1593
|
+
refute_equal old_count, count
|
1594
|
+
|
1595
|
+
old_count = count
|
1596
|
+
db2 = Extralite::Database.new(':memory:')
|
1597
|
+
10.times { db2.query('select 1') }
|
1598
|
+
assert_equal old_count, count
|
1599
|
+
ensure
|
1600
|
+
Extralite.on_progress(mode: :none)
|
1601
|
+
end
|
1351
1602
|
end
|
1352
1603
|
|
1353
1604
|
class RactorTest < Minitest::Test
|
@@ -1369,67 +1620,232 @@ class RactorTest < Minitest::Test
|
|
1369
1620
|
r << 42
|
1370
1621
|
r.take # wait for ractor to terminate
|
1371
1622
|
|
1372
|
-
assert_equal 42, db.
|
1623
|
+
assert_equal 42, db.query_single_argv('select x from foo')
|
1373
1624
|
end
|
1374
1625
|
|
1375
1626
|
# Adapted from here: https://github.com/sparklemotion/sqlite3-ruby/pull/365/files
|
1376
1627
|
def test_ractor_share_database
|
1377
|
-
skip
|
1628
|
+
skip "skipped for now as ractors seem kinda flakey (failing sporadically)"
|
1378
1629
|
|
1379
1630
|
db_receiver = Ractor.new do
|
1380
1631
|
db = Ractor.receive
|
1381
1632
|
Ractor.yield db.object_id
|
1382
1633
|
begin
|
1383
|
-
db.execute(
|
1384
|
-
raise
|
1634
|
+
db.execute('create table foo (b)')
|
1635
|
+
raise 'Should have raised an exception in db.execute()'
|
1385
1636
|
rescue => e
|
1386
1637
|
Ractor.yield e
|
1387
1638
|
end
|
1388
1639
|
end
|
1389
1640
|
sleep 0.1
|
1390
1641
|
db_creator = Ractor.new(db_receiver) do |db_receiver|
|
1391
|
-
db = Extralite::Database.new(
|
1642
|
+
db = Extralite::Database.new(':memory:')
|
1392
1643
|
Ractor.yield db.object_id
|
1393
1644
|
db_receiver.send(db)
|
1394
1645
|
sleep 0.1
|
1395
|
-
db.execute(
|
1646
|
+
db.execute('create table foo (a)')
|
1396
1647
|
end
|
1397
1648
|
first_oid = db_creator.take
|
1398
1649
|
second_oid = db_receiver.take
|
1399
1650
|
refute_equal first_oid, second_oid
|
1400
1651
|
ex = db_receiver.take
|
1401
1652
|
assert_kind_of Extralite::Error, ex
|
1402
|
-
assert_equal
|
1653
|
+
assert_equal 'Database is closed', ex.message
|
1403
1654
|
end
|
1404
1655
|
|
1405
|
-
STRESS_DB_NAME = Tempfile.new('extralite_test_ractor_stress').path
|
1406
|
-
|
1407
1656
|
# Adapted from here: https://github.com/sparklemotion/sqlite3-ruby/pull/365/files
|
1408
1657
|
def test_ractor_stress
|
1409
1658
|
skip if SKIP_RACTOR_TESTS
|
1410
|
-
|
1411
|
-
Ractor.make_shareable(STRESS_DB_NAME)
|
1412
1659
|
|
1413
|
-
|
1414
|
-
db.execute("PRAGMA journal_mode=WAL") # A little slow without this
|
1415
|
-
db.execute("create table stress_test (a integer primary_key, b text)")
|
1660
|
+
fn = Tempfile.new('extralite_test_ractor_stress').path
|
1416
1661
|
random = Random.new.freeze
|
1662
|
+
|
1417
1663
|
ractors = (0..9).map do |ractor_number|
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1664
|
+
sleep 0.05
|
1665
|
+
Ractor.new(fn, random, ractor_number) do |rfn, r, n|
|
1666
|
+
rdb = Extralite::Database.new(rfn)
|
1667
|
+
rdb.busy_timeout = 3
|
1668
|
+
rdb.pragma(journal_mode: 'wal', synchronous: 1)
|
1669
|
+
rdb.execute('create table if not exists stress_test (a integer primary_key, b text)')
|
1670
|
+
changes = 0
|
1421
1671
|
10.times do |i|
|
1422
|
-
|
1672
|
+
changes += rdb.execute('insert into stress_test(a, b) values (?, ?)', n * 100 + i, r.rand)
|
1423
1673
|
end
|
1674
|
+
Ractor.yield changes
|
1424
1675
|
end
|
1425
1676
|
end
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1677
|
+
|
1678
|
+
buf = []
|
1679
|
+
ractors.each { |r| buf << r.take }
|
1680
|
+
assert_equal [10] * 10, buf
|
1681
|
+
|
1682
|
+
final_check = Ractor.new(fn) do |rfn|
|
1683
|
+
rdb = Extralite::Database.new(rfn, wal: true)
|
1684
|
+
count = rdb.query_single_argv('select count(*) from stress_test')
|
1430
1685
|
Ractor.yield count
|
1431
1686
|
end
|
1432
1687
|
count = final_check.take
|
1433
1688
|
assert_equal 100, count
|
1434
1689
|
end
|
1435
1690
|
end
|
1691
|
+
|
1692
|
+
class DatabaseTransformTest < Minitest::Test
|
1693
|
+
def setup
|
1694
|
+
@db = Extralite::Database.new(':memory:')
|
1695
|
+
@db.query('create table t (a, b, c)')
|
1696
|
+
|
1697
|
+
@q3 = @db.prepare('select * from t where a = ?')
|
1698
|
+
@q4 = @db.prepare('select * from t order by a')
|
1699
|
+
|
1700
|
+
@db.batch_execute('insert into t (a, b, c) values (?, ?, ?)', [
|
1701
|
+
[1, 2, { foo: 42, bar: 43 }.to_json],
|
1702
|
+
[4, 5, { foo: 45, bar: 46 }.to_json]
|
1703
|
+
])
|
1704
|
+
end
|
1705
|
+
|
1706
|
+
class MyModel
|
1707
|
+
def initialize(h)
|
1708
|
+
@h = h
|
1709
|
+
end
|
1710
|
+
|
1711
|
+
def values
|
1712
|
+
@h
|
1713
|
+
end
|
1714
|
+
end
|
1715
|
+
|
1716
|
+
def test_query_hash_transform
|
1717
|
+
transform = ->(h) { MyModel.new(h) }
|
1718
|
+
|
1719
|
+
sql = 'select a, b from t where a = ?'
|
1720
|
+
o = @db.query(transform, sql, 1).first
|
1721
|
+
assert_kind_of MyModel, o
|
1722
|
+
assert_equal({ a: 1, b: 2 }, o.values)
|
1723
|
+
|
1724
|
+
o = @db.query(transform, sql, 4).first
|
1725
|
+
assert_kind_of MyModel, o
|
1726
|
+
assert_equal({ a: 4, b: 5 }, o.values)
|
1727
|
+
|
1728
|
+
sql = 'select a, b from t order by a'
|
1729
|
+
assert_equal [
|
1730
|
+
{ a: 1, b: 2 },
|
1731
|
+
{ a: 4, b: 5 }
|
1732
|
+
], @db.query(transform, sql).map(&:values)
|
1733
|
+
|
1734
|
+
buf = []
|
1735
|
+
@db.query(transform, sql) { |r| buf << r.values }
|
1736
|
+
assert_equal [
|
1737
|
+
{ a: 1, b: 2 },
|
1738
|
+
{ a: 4, b: 5 }
|
1739
|
+
], buf
|
1740
|
+
end
|
1741
|
+
|
1742
|
+
def test_query_ary_transform
|
1743
|
+
transform = ->(h) { MyModel.new(h) }
|
1744
|
+
|
1745
|
+
sql = 'select a, b from t where a = ?'
|
1746
|
+
o = @db.query_ary(transform, sql, 1).first
|
1747
|
+
assert_kind_of MyModel, o
|
1748
|
+
assert_equal([1, 2], o.values)
|
1749
|
+
|
1750
|
+
o = @db.query_ary(transform, sql, 4).first
|
1751
|
+
assert_kind_of MyModel, o
|
1752
|
+
assert_equal([4, 5], o.values)
|
1753
|
+
|
1754
|
+
sql = 'select a, b from t order by a'
|
1755
|
+
assert_equal [
|
1756
|
+
[1, 2],
|
1757
|
+
[4, 5]
|
1758
|
+
], @db.query_ary(transform, sql).map(&:values)
|
1759
|
+
|
1760
|
+
buf = []
|
1761
|
+
@db.query_ary(transform, sql) { |r| buf << r.values }
|
1762
|
+
assert_equal [
|
1763
|
+
[1, 2],
|
1764
|
+
[4, 5]
|
1765
|
+
], buf
|
1766
|
+
end
|
1767
|
+
|
1768
|
+
def test_query_hash_single_row_transform
|
1769
|
+
transform = ->(h) { MyModel.new(h) }
|
1770
|
+
|
1771
|
+
sql = 'select a, b from t where a = ?'
|
1772
|
+
o = @db.query_single(transform, sql, 1)
|
1773
|
+
assert_kind_of MyModel, o
|
1774
|
+
assert_equal({ a: 1, b: 2 }, o.values)
|
1775
|
+
|
1776
|
+
o = @db.query_single(transform, sql, 4)
|
1777
|
+
assert_kind_of MyModel, o
|
1778
|
+
assert_equal({ a: 4, b: 5 }, o.values)
|
1779
|
+
end
|
1780
|
+
|
1781
|
+
def test_query_ary_single_row_transform
|
1782
|
+
transform = ->(h) { MyModel.new(h) }
|
1783
|
+
|
1784
|
+
sql = 'select a, b from t where a = ?'
|
1785
|
+
o = @db.query_single_ary(transform, sql, 1)
|
1786
|
+
assert_kind_of MyModel, o
|
1787
|
+
assert_equal([1, 2], o.values)
|
1788
|
+
|
1789
|
+
o = @db.query_single_ary(transform, sql, 4)
|
1790
|
+
assert_kind_of MyModel, o
|
1791
|
+
assert_equal([4, 5], o.values)
|
1792
|
+
end
|
1793
|
+
|
1794
|
+
def test_query_argv_single_column_transform
|
1795
|
+
transform = ->(c) { JSON.parse(c, symbolize_names: true) }
|
1796
|
+
sql = 'select c from t where a = ?'
|
1797
|
+
|
1798
|
+
assert_equal([{ foo: 42, bar: 43 }], @db.query_argv(transform, sql, 1))
|
1799
|
+
assert_equal([{ foo: 45, bar: 46 }], @db.query_argv(transform, sql, 4))
|
1800
|
+
|
1801
|
+
sql = 'select c from t order by a'
|
1802
|
+
assert_equal [
|
1803
|
+
{ foo: 42, bar: 43 },
|
1804
|
+
{ foo: 45, bar: 46 }
|
1805
|
+
], @db.query_argv(transform, sql)
|
1806
|
+
|
1807
|
+
buf = []
|
1808
|
+
@db.query_argv(transform, sql) { |r| buf << r }
|
1809
|
+
assert_equal [
|
1810
|
+
{ foo: 42, bar: 43 },
|
1811
|
+
{ foo: 45, bar: 46 }
|
1812
|
+
], buf
|
1813
|
+
end
|
1814
|
+
|
1815
|
+
def test_query_argv_single_row_single_column
|
1816
|
+
transform = ->(c) { JSON.parse(c, symbolize_names: true) }
|
1817
|
+
sql = 'select c from t where a = ?'
|
1818
|
+
|
1819
|
+
assert_equal({ foo: 42, bar: 43 }, @db.query_single_argv(transform, sql, 1))
|
1820
|
+
assert_equal({ foo: 45, bar: 46 }, @db.query_single_argv(transform, sql, 4))
|
1821
|
+
end
|
1822
|
+
|
1823
|
+
def test_query_argv_multi_column
|
1824
|
+
transform = ->(a, b, c) { { a: a, b: b, c: JSON.parse(c, symbolize_names: true) } }
|
1825
|
+
sql = 'select * from t where a = ?'
|
1826
|
+
|
1827
|
+
assert_equal([{ a: 1, b: 2, c: { foo: 42, bar: 43 }}], @db.query_argv(transform, sql, 1))
|
1828
|
+
assert_equal([{ a: 4, b: 5, c: { foo: 45, bar: 46 }}], @db.query_argv(transform, sql, 4))
|
1829
|
+
|
1830
|
+
sql = 'select * from t order by a'
|
1831
|
+
assert_equal [
|
1832
|
+
{ a: 1, b: 2, c: { foo: 42, bar: 43 }},
|
1833
|
+
{ a: 4, b: 5, c: { foo: 45, bar: 46 }}
|
1834
|
+
], @db.query_argv(transform, sql)
|
1835
|
+
|
1836
|
+
buf = []
|
1837
|
+
@db.query_argv(transform, sql) { |r| buf << r }
|
1838
|
+
assert_equal [
|
1839
|
+
{ a: 1, b: 2, c: { foo: 42, bar: 43 }},
|
1840
|
+
{ a: 4, b: 5, c: { foo: 45, bar: 46 }}
|
1841
|
+
], buf
|
1842
|
+
end
|
1843
|
+
|
1844
|
+
def test_query_argv_single_row_multi_column
|
1845
|
+
transform = ->(a, b, c) { { a: a, b: b, c: JSON.parse(c, symbolize_names: true) } }
|
1846
|
+
sql = 'select * from t where a = ?'
|
1847
|
+
|
1848
|
+
assert_equal({ a: 1, b: 2, c: { foo: 42, bar: 43 }}, @db.query_single_argv(transform, sql, 1))
|
1849
|
+
assert_equal({ a: 4, b: 5, c: { foo: 45, bar: 46 }}, @db.query_single_argv(transform, sql, 4))
|
1850
|
+
end
|
1851
|
+
end
|