extralite 1.27 → 2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,502 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+
5
+ class QueryTest < MiniTest::Test
6
+ def setup
7
+ @db = Extralite::Database.new(':memory:')
8
+ @db.query('create table if not exists t (x,y,z)')
9
+ @db.query('delete from t')
10
+ @db.query('insert into t values (1, 2, 3)')
11
+ @db.query('insert into t values (4, 5, 6)')
12
+ @db.query('insert into t values (7, 8, 9)')
13
+
14
+ @query = @db.prepare('select * from t where x = ?')
15
+ end
16
+
17
+ def test_prepare
18
+ query = @db.prepare('select 1')
19
+ assert_equal 1, query.next_single_column
20
+
21
+ query = @db.prepare('select x from t where y = ?', 5)
22
+ assert_equal 4, query.next_single_column
23
+ end
24
+
25
+ def test_query_props
26
+ assert_kind_of Extralite::Query, @query
27
+ assert_equal @db, @query.database
28
+ assert_equal @db, @query.db
29
+ assert_equal 'select * from t where x = ?', @query.sql
30
+ end
31
+
32
+ def test_bind
33
+ @db.query("insert into t values ('a', 'b', 'c')")
34
+
35
+ q = @db.prepare('select * from t where `z` = :foo')
36
+ results = q.bind(foo: 'c').to_a_ary
37
+
38
+ assert_equal [['a', 'b', 'c']], results
39
+ end
40
+
41
+ def test_query_next
42
+ query = @db.prepare('select * from t')
43
+ v = query.next
44
+ assert_equal({ x: 1, y: 2, z: 3}, v)
45
+
46
+ v = query.next
47
+ assert_equal({ x: 4, y: 5, z: 6}, v)
48
+
49
+ v = query.next
50
+ assert_equal({ x: 7, y: 8, z: 9}, v)
51
+
52
+ v = query.next
53
+ assert_nil v
54
+
55
+ # EOF should repeat
56
+ v = query.next
57
+ assert_nil v
58
+
59
+ query = @db.prepare('select * from t')
60
+ v = query.next_hash
61
+ assert_equal({ x: 1, y: 2, z: 3}, v)
62
+
63
+ v = query.next_hash
64
+ assert_equal({ x: 4, y: 5, z: 6}, v)
65
+
66
+ v = query.next_hash
67
+ assert_equal({ x: 7, y: 8, z: 9}, v)
68
+
69
+ v = query.next_hash
70
+ assert_nil v
71
+ end
72
+
73
+ def test_query_next_with_row_count
74
+ query = @db.prepare('select * from t')
75
+ v = query.next(1)
76
+ assert_equal([{ x: 1, y: 2, z: 3}], v)
77
+
78
+ v = query.next(2)
79
+ assert_equal([{ x: 4, y: 5, z: 6}, { x: 7, y: 8, z: 9}], v)
80
+
81
+ v = query.next
82
+ assert_nil v
83
+
84
+ query = @db.prepare('select * from t')
85
+ v = query.next(-1)
86
+ assert_equal([{ x: 1, y: 2, z: 3}, { x: 4, y: 5, z: 6}, { x: 7, y: 8, z: 9}], v)
87
+ end
88
+
89
+ def test_query_next_with_block
90
+ query = @db.prepare('select * from t')
91
+ buf = []
92
+ v = query.next { |r| buf << r }
93
+ assert_equal query, v
94
+ assert_equal [{x: 1, y: 2, z: 3}], buf
95
+
96
+ buf = []
97
+ v = query.next(2) { |r| buf << r }
98
+ assert_equal query, v
99
+ assert_equal [{ x: 4, y: 5, z: 6}, { x: 7, y: 8, z: 9}], buf
100
+
101
+ buf = []
102
+ v = query.next(2) { |r| buf << r }
103
+ assert_equal query, v
104
+ assert_equal [], buf
105
+
106
+ buf = []
107
+ v = query.next(2) { |r| buf << r }
108
+ assert_equal query, v
109
+ assert_equal [], buf
110
+ end
111
+
112
+ def test_query_next_with_block_with_break
113
+ query = @db.prepare('select * from t')
114
+ buf = []
115
+ v = query.next(-1) { |r| buf << r; break }
116
+ assert_nil v
117
+ assert_equal [{x: 1, y: 2, z: 3}], buf
118
+
119
+ buf = []
120
+ v = query.next(-1) { |r| buf << r }
121
+ assert_equal query, v
122
+ assert_equal [{x: 4, y: 5, z: 6}, {x: 7, y: 8, z: 9}], buf
123
+
124
+ buf = []
125
+ v = query.next(2) { |r| buf << r }
126
+ assert_equal query, v
127
+ assert_equal [], buf
128
+ end
129
+
130
+ def test_query_next_ary
131
+ query = @db.prepare('select * from t')
132
+ v = query.next_ary
133
+ assert_equal([1, 2, 3], v)
134
+
135
+ v = query.next_ary
136
+ assert_equal([4, 5, 6], v)
137
+
138
+ v = query.next_ary
139
+ assert_equal([7, 8, 9], v)
140
+
141
+ v = query.next_ary
142
+ assert_nil v
143
+
144
+ v = query.next_ary
145
+ assert_nil v
146
+ end
147
+
148
+ def test_query_next_ary_with_row_count
149
+ query = @db.prepare('select * from t')
150
+ v = query.next_ary(1)
151
+ assert_equal([[1, 2, 3]], v)
152
+
153
+ v = query.next_ary(2)
154
+ assert_equal([[4, 5, 6], [7, 8, 9]], v)
155
+
156
+ v = query.next_ary(2)
157
+ assert_equal([], v)
158
+
159
+ v = query.next_ary(2)
160
+ assert_nil v
161
+ end
162
+
163
+ def test_query_next_ary_with_block
164
+ query = @db.prepare('select * from t')
165
+ buf = []
166
+ v = query.next_ary { |r| buf << r }
167
+ assert_equal query, v
168
+ assert_equal [[1, 2, 3]], buf
169
+
170
+ buf = []
171
+ v = query.next_ary(2) { |r| buf << r }
172
+ assert_equal query, v
173
+ assert_equal [[4, 5, 6], [7, 8, 9]], buf
174
+
175
+ buf = []
176
+ v = query.next_ary(2) { |r| buf << r }
177
+ assert_equal query, v
178
+ assert_equal [], buf
179
+ end
180
+
181
+ def test_query_next_single_column
182
+ query = @db.prepare('select x from t')
183
+ v = query.next_single_column
184
+ assert_equal(1, v)
185
+
186
+ v = query.next_single_column
187
+ assert_equal(4, v)
188
+
189
+ v = query.next_single_column
190
+ assert_equal(7, v)
191
+
192
+ v = query.next_single_column
193
+ assert_nil v
194
+ end
195
+
196
+ def test_query_next_single_column_with_row_count
197
+ query = @db.prepare('select x from t')
198
+ v = query.next_single_column(1)
199
+ assert_equal([1], v)
200
+
201
+ v = query.next_single_column(3)
202
+ assert_equal([4, 7], v)
203
+
204
+ v = query.next_single_column(2)
205
+ assert_nil v
206
+ end
207
+
208
+ def test_query_next_single_column_with_block
209
+ query = @db.prepare('select x from t')
210
+ buf = []
211
+ v = query.next_single_column { |r| buf << r }
212
+ assert_equal query, v
213
+ assert_equal [1], buf
214
+
215
+ buf = []
216
+ v = query.next_single_column(2) { |r| buf << r }
217
+ assert_equal query, v
218
+ assert_equal [4, 7], buf
219
+
220
+ buf = []
221
+ v = query.next_single_column(2) { |r| buf << r }
222
+ assert_equal query, v
223
+ assert_equal [], buf
224
+ end
225
+
226
+ def test_query_to_a
227
+ assert_equal [{ x: 1, y: 2, z: 3 }], @query.bind(1).to_a
228
+ assert_equal [{ x: 4, y: 5, z: 6 }], @query.bind(4).to_a
229
+
230
+ assert_equal [{ x: 1, y: 2, z: 3 }], @query.bind(1).to_a_hash
231
+ assert_equal [{ x: 4, y: 5, z: 6 }], @query.bind(4).to_a_hash
232
+
233
+ assert_equal [[1, 2, 3]], @query.bind(1).to_a_ary
234
+ assert_equal [[4, 5, 6]], @query.bind(4).to_a_ary
235
+
236
+ query = @db.prepare('select y from t')
237
+ assert_equal [2, 5, 8], query.to_a_single_column
238
+ end
239
+
240
+ def test_query_each
241
+ buf = []
242
+ @query.bind(1).each { |r| buf << r }
243
+ assert_equal [{x: 1, y: 2, z: 3}], buf
244
+
245
+ # each should reset the stmt
246
+ buf = []
247
+ @query.each { |r| buf << r }
248
+ assert_equal [{x: 1, y: 2, z: 3}], buf
249
+
250
+ query = @db.prepare('select * from t')
251
+ buf = []
252
+ query.each { |r| buf << r }
253
+ assert_equal [{x: 1, y: 2, z: 3},{ x: 4, y: 5, z: 6 }, { x: 7, y: 8, z: 9 }], buf
254
+ end
255
+
256
+ def test_query_each_with_break
257
+ query = @db.prepare('select * from t')
258
+
259
+ buf = []
260
+ query.each { |r| buf << r; break }
261
+ assert_equal [{x: 1, y: 2, z: 3}], buf
262
+
263
+ # each should reset the stmt
264
+ buf = []
265
+ query.each { |r| buf << r }
266
+ assert_equal [{x: 1, y: 2, z: 3},{ x: 4, y: 5, z: 6 }, { x: 7, y: 8, z: 9 }], buf
267
+ end
268
+
269
+ def test_query_each_without_block
270
+ query = @db.prepare('select * from t')
271
+ iter = query.each
272
+ assert_kind_of Extralite::Iterator, iter
273
+
274
+ buf = []
275
+ v = iter.each { |r| buf << r }
276
+ assert_equal iter, v
277
+ assert_equal [{x: 1, y: 2, z: 3},{ x: 4, y: 5, z: 6 }, { x: 7, y: 8, z: 9 }], buf
278
+ end
279
+
280
+ def test_query_each_ary
281
+ buf = []
282
+ @query.bind(1).each_ary { |r| buf << r }
283
+ assert_equal [[1, 2, 3]], buf
284
+
285
+ # each should reset the stmt
286
+ buf = []
287
+ @query.each_ary { |r| buf << r }
288
+ assert_equal [[1, 2, 3]], buf
289
+
290
+ query = @db.prepare('select * from t')
291
+ buf = []
292
+ query.each_ary { |r| buf << r }
293
+ assert_equal [[1, 2, 3], [4, 5, 6], [7, 8, 9]], buf
294
+ end
295
+
296
+ def test_query_each_ary_without_block
297
+ query = @db.prepare('select * from t')
298
+ iter = query.each_ary
299
+ assert_kind_of Extralite::Iterator, iter
300
+
301
+ buf = []
302
+ v = iter.each { |r| buf << r }
303
+ assert_equal iter, v
304
+ assert_equal [[1, 2, 3], [4, 5, 6], [7, 8, 9]], buf
305
+ end
306
+
307
+ def test_query_each_single_column
308
+ query = @db.prepare('select x from t where x = ?')
309
+ buf = []
310
+ query.bind(1).each_single_column { |r| buf << r }
311
+ assert_equal [1], buf
312
+
313
+ # each should reset the stmt
314
+ buf = []
315
+ query.each_single_column { |r| buf << r }
316
+ assert_equal [1], buf
317
+
318
+ query = @db.prepare('select x from t')
319
+ buf = []
320
+ query.each_single_column { |r| buf << r }
321
+ assert_equal [1, 4, 7], buf
322
+ end
323
+
324
+ def test_query_each_single_column_without_block
325
+ query = @db.prepare('select x from t')
326
+ iter = query.each_single_column
327
+ assert_kind_of Extralite::Iterator, iter
328
+
329
+ buf = []
330
+ v = iter.each { |r| buf << r }
331
+ assert_equal iter, v
332
+ assert_equal [1, 4, 7], buf
333
+ end
334
+
335
+ def test_query_with_invalid_sql
336
+ assert_raises(Extralite::SQLError) { @db.prepare('blah').to_a }
337
+ end
338
+
339
+ def test_query_with_multiple_queries
340
+ assert_raises(Extralite::Error) { @db.prepare('select 1; select 2').to_a }
341
+ end
342
+
343
+ def test_query_multiple_statements
344
+ assert_raises(Extralite::Error) {
345
+ @db.prepare("insert into t values ('a', 'b', 'c'); insert into t values ('d', 'e', 'f');").to_a
346
+ }
347
+ end
348
+
349
+ def test_query_multiple_statements_with_bad_sql
350
+ error = nil
351
+ begin
352
+ query =@db.prepare("insert into t values foo; insert into t values ('d', 'e', 'f');")
353
+ query.next
354
+ rescue => error
355
+ end
356
+
357
+ assert_kind_of Extralite::SQLError, error
358
+ assert_equal 'near "foo": syntax error', error.message
359
+ end
360
+
361
+ def test_query_repeated_execution_missing_param
362
+ assert_nil @query.next
363
+
364
+ @query.bind(4)
365
+ assert_equal({x: 4, y: 5, z: 6}, @query.next)
366
+ end
367
+
368
+ def test_query_empty_sql
369
+ assert_raises(Extralite::Error) { @db.prepare(' ') }
370
+
371
+ r = @db.prepare('select 1 as foo; ').next
372
+ assert_equal({ foo: 1 }, r)
373
+ end
374
+
375
+ def test_query_parameter_binding_simple
376
+ r = @db.prepare('select x, y, z from t where x = ?').bind(1).next
377
+ assert_equal({ x: 1, y: 2, z: 3 }, r)
378
+ end
379
+
380
+ def test_query_parameter_binding_with_index
381
+ r = @db.prepare('select x, y, z from t where x = ?2').bind(0, 1).next
382
+ assert_equal({ x: 1, y: 2, z: 3 }, r)
383
+
384
+ r = @db.prepare('select x, y, z from t where z = ?3').bind(3, 4, 6).next
385
+ assert_equal({ x: 4, y: 5, z: 6 }, r)
386
+ end
387
+
388
+ def test_query_parameter_binding_with_name
389
+ r = @db.prepare('select x, y, z from t where x = :x').bind(x: 1, y: 2).next
390
+ assert_equal({ x: 1, y: 2, z: 3 }, r)
391
+
392
+ r = @db.prepare('select x, y, z from t where z = :zzz').bind('zzz' => 6).next
393
+ assert_equal({ x: 4, y: 5, z: 6 }, r)
394
+
395
+ r = @db.prepare('select x, y, z from t where z = :bazzz').bind(':bazzz' => 6).next
396
+ assert_equal({ x: 4, y: 5, z: 6 }, r)
397
+ end
398
+
399
+ def test_query_parameter_binding_with_index_key
400
+ r = @db.prepare('select x, y, z from t where z = ?').bind(1 => 3).next
401
+ assert_equal({ x: 1, y: 2, z: 3 }, r)
402
+
403
+ r = @db.prepare('select x, y, z from t where x = ?2').bind(1 => 42, 2 => 4).next
404
+ assert_equal({ x: 4, y: 5, z: 6 }, r)
405
+ end
406
+
407
+ def test_query_columns
408
+ r = @db.prepare("select 'abc' as a, 'def' as b").columns
409
+ assert_equal [:a, :b], r
410
+ end
411
+
412
+ def test_query_columns_with_parameterized_sql
413
+ q = @db.prepare('select * from t where z = :z')
414
+ q.bind(z: 9)
415
+ assert_equal [:x, :y, :z], q.columns
416
+ assert_equal [[7, 8, 9]], q.to_a_ary
417
+ end
418
+
419
+ def test_query_close
420
+ p = @db.prepare("select 'abc'")
421
+
422
+ assert_equal false, p.closed?
423
+
424
+ p.close
425
+ assert_equal true, p.closed?
426
+
427
+ p.close
428
+ assert_equal true, p.closed?
429
+
430
+ assert_raises(Extralite::Error) { p.next }
431
+ end
432
+
433
+ def test_query_execute_multi
434
+ @db.query('create table foo (a, b, c)')
435
+ assert_equal [], @db.query('select * from foo')
436
+
437
+ records = [
438
+ [1, '2', 3],
439
+ ['4', 5, 6]
440
+ ]
441
+
442
+ p = @db.prepare('insert into foo values (?, ?, ?)')
443
+ changes = p.execute_multi(records)
444
+
445
+ assert_equal 2, changes
446
+ assert_equal [
447
+ { a: 1, b: '2', c: 3 },
448
+ { a: '4', b: 5, c: 6 }
449
+ ], @db.query('select * from foo')
450
+ end
451
+
452
+ def test_query_status
453
+ assert_equal 0, @query.status(Extralite::SQLITE_STMTSTATUS_RUN)
454
+ @query.to_a
455
+ assert_equal 1, @query.status(Extralite::SQLITE_STMTSTATUS_RUN)
456
+ @query.to_a
457
+ assert_equal 2, @query.status(Extralite::SQLITE_STMTSTATUS_RUN)
458
+ @query.to_a
459
+ assert_equal 3, @query.status(Extralite::SQLITE_STMTSTATUS_RUN, true)
460
+ assert_equal 0, @query.status(Extralite::SQLITE_STMTSTATUS_RUN)
461
+ end
462
+
463
+ def test_query_status_after_close
464
+ assert_equal 0, @query.status(Extralite::SQLITE_STMTSTATUS_RUN)
465
+ @query.to_a
466
+ assert_equal 1, @query.status(Extralite::SQLITE_STMTSTATUS_RUN)
467
+ @query.close
468
+ assert_raises(Extralite::Error) { @query.status(Extralite::SQLITE_STMTSTATUS_RUN) }
469
+ end
470
+
471
+ def test_query_after_db_close
472
+ assert_equal [{ x: 4, y: 5, z: 6}], @query.bind(4).to_a
473
+ @db.close
474
+ assert_equal [{ x: 4, y: 5, z: 6}], @query.bind(4).to_a
475
+ end
476
+
477
+ def test_query_eof
478
+ query = @db.prepare('select x from t')
479
+ assert_equal false, query.eof?
480
+
481
+ query.next
482
+ assert_equal false, query.eof?
483
+
484
+ query.next(2)
485
+ assert_equal false, query.eof?
486
+
487
+ query.next
488
+ assert_equal true, query.eof?
489
+
490
+ query.next
491
+ assert_equal true, query.eof?
492
+
493
+ query.reset
494
+ assert_equal false, query.eof?
495
+
496
+ query.next
497
+ assert_equal false, query.eof?
498
+
499
+ assert_equal [1, 4, 7], query.to_a_single_column
500
+ assert_equal true, query.eof?
501
+ end
502
+ end
data/test/test_sequel.rb CHANGED
@@ -34,13 +34,32 @@ class SequelExtraliteTest < MiniTest::Test
34
34
  prepared_query = items.where(name: :$name).prepare(:select, :select_by_name)
35
35
  prepared_insert = items.prepare(:insert, :insert_with_name_and_price, name: :$name, price: :$price)
36
36
 
37
- assert_equal prepared_query.call(name: 'def'), [{ id: 2, name: 'def', price: 456 }]
38
- assert_equal @db.call(:select_by_name, name: 'def'), [{ id: 2, name: 'def', price: 456 }]
37
+ assert_equal [{ id: 2, name: 'def', price: 456 }], prepared_query.call(name: 'def')
38
+ assert_equal [{ id: 2, name: 'def', price: 456 }], @db.call(:select_by_name, name: 'def')
39
39
 
40
40
  id = prepared_insert.call(name: 'jkl', price: 444)
41
- assert_equal items[id: id], { id: id, name: 'jkl', price: 444 }
41
+ assert_equal({ id: id, name: 'jkl', price: 444 }, items[id: id])
42
42
 
43
43
  id = @db.call(:insert_with_name_and_price, name: 'mno', price: 555)
44
- assert_equal items[id: id], { id: id, name: 'mno', price: 555 }
44
+ assert_equal({ id: id, name: 'mno', price: 555 }, items[id: id])
45
+ end
46
+
47
+ def test_migration
48
+ # Adapted from https://github.com/digital-fabric/extralite/issues/8
49
+ Dir.mktmpdir("extralite-migration") do |dir|
50
+ File.write(dir + "/001_migrate.rb", <<~RUBY)
51
+ Sequel.migration do
52
+ change do
53
+ create_table(:foobars) { primary_key :id }
54
+ end
55
+ end
56
+ RUBY
57
+
58
+ Sequel.extension :migration
59
+ db = Sequel.connect("extralite://")
60
+ Sequel::Migrator.run(db, dir)
61
+
62
+ assert_equal [:id], db[:foobars].columns
63
+ end
45
64
  end
46
65
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: extralite
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.27'
4
+ version: '2.0'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-12 00:00:00.000000000 Z
11
+ date: 2023-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -107,7 +107,8 @@ files:
107
107
  - ext/extralite/extralite.h
108
108
  - ext/extralite/extralite_ext.c
109
109
  - ext/extralite/extralite_sqlite3.c
110
- - ext/extralite/prepared_statement.c
110
+ - ext/extralite/iterator.c
111
+ - ext/extralite/query.c
111
112
  - extralite-bundle.gemspec
112
113
  - extralite.gemspec
113
114
  - gemspec.rb
@@ -124,7 +125,8 @@ files:
124
125
  - test/run.rb
125
126
  - test/test_database.rb
126
127
  - test/test_extralite.rb
127
- - test/test_prepared_statement.rb
128
+ - test/test_iterator.rb
129
+ - test/test_query.rb
128
130
  - test/test_sequel.rb
129
131
  homepage: https://github.com/digital-fabric/extralite
130
132
  licenses: