extralite 1.27 → 2.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.
@@ -0,0 +1,519 @@
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
434
+ q = @db.prepare('update t set x = 42')
435
+ assert_equal 3, q.execute
436
+ assert_equal [[42, 2, 3], [42, 5, 6], [42, 8, 9]], @db.query_ary('select * from t order by z')
437
+ end
438
+
439
+ def test_query_execute_with_params
440
+ q = @db.prepare('update t set x = ? where z = ?')
441
+ assert_equal 1, q.execute(42, 9)
442
+ assert_equal [[1, 2, 3], [4, 5, 6], [42, 8, 9]], @db.query_ary('select * from t order by z')
443
+ end
444
+
445
+ def test_query_execute_multi
446
+ @db.query('create table foo (a, b, c)')
447
+ assert_equal [], @db.query('select * from foo')
448
+
449
+ records = [
450
+ [1, '2', 3],
451
+ ['4', 5, 6]
452
+ ]
453
+
454
+ p = @db.prepare('insert into foo values (?, ?, ?)')
455
+ changes = p.execute_multi(records)
456
+
457
+ assert_equal 2, changes
458
+ assert_equal [
459
+ { a: 1, b: '2', c: 3 },
460
+ { a: '4', b: 5, c: 6 }
461
+ ], @db.query('select * from foo')
462
+ end
463
+
464
+ def test_query_status
465
+ assert_equal 0, @query.status(Extralite::SQLITE_STMTSTATUS_RUN)
466
+ @query.to_a
467
+ assert_equal 1, @query.status(Extralite::SQLITE_STMTSTATUS_RUN)
468
+ @query.to_a
469
+ assert_equal 2, @query.status(Extralite::SQLITE_STMTSTATUS_RUN)
470
+ @query.to_a
471
+ assert_equal 3, @query.status(Extralite::SQLITE_STMTSTATUS_RUN, true)
472
+ assert_equal 0, @query.status(Extralite::SQLITE_STMTSTATUS_RUN)
473
+ end
474
+
475
+ def test_query_status_after_close
476
+ assert_equal 0, @query.status(Extralite::SQLITE_STMTSTATUS_RUN)
477
+ @query.to_a
478
+ assert_equal 1, @query.status(Extralite::SQLITE_STMTSTATUS_RUN)
479
+ @query.close
480
+ assert_raises(Extralite::Error) { @query.status(Extralite::SQLITE_STMTSTATUS_RUN) }
481
+ end
482
+
483
+ def test_query_after_db_close
484
+ assert_equal [{ x: 4, y: 5, z: 6}], @query.bind(4).to_a
485
+ @db.close
486
+ assert_equal [{ x: 4, y: 5, z: 6}], @query.bind(4).to_a
487
+ end
488
+
489
+ def test_query_eof
490
+ query = @db.prepare('select x from t')
491
+ assert_equal false, query.eof?
492
+
493
+ query.next
494
+ assert_equal false, query.eof?
495
+
496
+ query.next(2)
497
+ assert_equal false, query.eof?
498
+
499
+ query.next
500
+ assert_equal true, query.eof?
501
+
502
+ query.next
503
+ assert_equal true, query.eof?
504
+
505
+ query.reset
506
+ assert_equal false, query.eof?
507
+
508
+ query.next
509
+ assert_equal false, query.eof?
510
+
511
+ assert_equal [1, 4, 7], query.to_a_single_column
512
+ assert_equal true, query.eof?
513
+ end
514
+
515
+ def test_query_inspect
516
+ q = @db.prepare('select x from t')
517
+ assert_match /^\#\<Extralite::Query:0x[0-9a-f]+ #{q.sql.inspect}\>$/, q.inspect
518
+ end
519
+ 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.1'
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-11 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: