extralite 2.6 → 2.7.1
Sign up to get free protection for your applications and to get access to all the features.
- 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/ext/extralite/query.c
CHANGED
@@ -14,6 +14,10 @@ VALUE cQuery;
|
|
14
14
|
ID ID_inspect;
|
15
15
|
ID ID_slice;
|
16
16
|
|
17
|
+
VALUE SYM_hash;
|
18
|
+
VALUE SYM_argv;
|
19
|
+
VALUE SYM_ary;
|
20
|
+
|
17
21
|
#define DB_GVL_MODE(query) Database_prepare_gvl_mode(query->db_struct)
|
18
22
|
|
19
23
|
static size_t Query_size(const void *ptr) {
|
@@ -24,12 +28,14 @@ static void Query_mark(void *ptr) {
|
|
24
28
|
Query_t *query = ptr;
|
25
29
|
rb_gc_mark_movable(query->db);
|
26
30
|
rb_gc_mark_movable(query->sql);
|
31
|
+
rb_gc_mark_movable(query->transform_proc);
|
27
32
|
}
|
28
33
|
|
29
34
|
static void Query_compact(void *ptr) {
|
30
35
|
Query_t *query = ptr;
|
31
36
|
query->db = rb_gc_location(query->db);
|
32
37
|
query->sql = rb_gc_location(query->sql);
|
38
|
+
query->transform_proc = rb_gc_location(query->transform_proc);
|
33
39
|
}
|
34
40
|
|
35
41
|
static void Query_free(void *ptr) {
|
@@ -48,6 +54,7 @@ static VALUE Query_allocate(VALUE klass) {
|
|
48
54
|
Query_t *query = ALLOC(Query_t);
|
49
55
|
query->db = Qnil;
|
50
56
|
query->sql = Qnil;
|
57
|
+
query->transform_proc = Qnil;
|
51
58
|
query->sqlite3_db = NULL;
|
52
59
|
query->stmt = NULL;
|
53
60
|
return TypedData_Wrap_Struct(klass, &Query_type, query);
|
@@ -59,6 +66,27 @@ static inline Query_t *self_to_query(VALUE obj) {
|
|
59
66
|
return query;
|
60
67
|
}
|
61
68
|
|
69
|
+
static inline enum query_mode symbol_to_query_mode(VALUE sym) {
|
70
|
+
if (sym == SYM_hash) return QUERY_HASH;
|
71
|
+
if (sym == SYM_argv) return QUERY_ARGV;
|
72
|
+
if (sym == SYM_ary) return QUERY_ARY;
|
73
|
+
|
74
|
+
rb_raise(cError, "Invalid query mode");
|
75
|
+
}
|
76
|
+
|
77
|
+
static inline VALUE query_mode_to_symbol(enum query_mode query_mode) {
|
78
|
+
switch (query_mode) {
|
79
|
+
case QUERY_HASH:
|
80
|
+
return SYM_hash;
|
81
|
+
case QUERY_ARGV:
|
82
|
+
return SYM_argv;
|
83
|
+
case QUERY_ARY:
|
84
|
+
return SYM_ary;
|
85
|
+
default:
|
86
|
+
rb_raise(cError, "Invalid mode");
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
62
90
|
/* Initializes a new prepared query with the given database and SQL string. A
|
63
91
|
* `Query` is normally instantiated by calling `Database#prepare`:
|
64
92
|
*
|
@@ -66,9 +94,10 @@ static inline Query_t *self_to_query(VALUE obj) {
|
|
66
94
|
*
|
67
95
|
* @param db [Extralite::Database] associated database
|
68
96
|
* @param sql [String] SQL string
|
97
|
+
* @param mode [Symbol] query mode
|
69
98
|
* @return [void]
|
70
99
|
*/
|
71
|
-
VALUE Query_initialize(VALUE self, VALUE db, VALUE sql) {
|
100
|
+
VALUE Query_initialize(VALUE self, VALUE db, VALUE sql, VALUE mode) {
|
72
101
|
Query_t *query = self_to_query(self);
|
73
102
|
|
74
103
|
sql = rb_funcall(sql, ID_strip, 0);
|
@@ -77,6 +106,8 @@ VALUE Query_initialize(VALUE self, VALUE db, VALUE sql) {
|
|
77
106
|
|
78
107
|
RB_OBJ_WRITE(self, &query->db, db);
|
79
108
|
RB_OBJ_WRITE(self, &query->sql, sql);
|
109
|
+
if (rb_block_given_p())
|
110
|
+
RB_OBJ_WRITE(self, &query->transform_proc, rb_block_proc());
|
80
111
|
|
81
112
|
query->db = db;
|
82
113
|
query->db_struct = self_to_database(db);
|
@@ -84,6 +115,7 @@ VALUE Query_initialize(VALUE self, VALUE db, VALUE sql) {
|
|
84
115
|
query->stmt = NULL;
|
85
116
|
query->closed = 0;
|
86
117
|
query->eof = 0;
|
118
|
+
query->query_mode = symbol_to_query_mode(mode);
|
87
119
|
|
88
120
|
return Qnil;
|
89
121
|
}
|
@@ -91,7 +123,7 @@ VALUE Query_initialize(VALUE self, VALUE db, VALUE sql) {
|
|
91
123
|
static inline void query_reset(Query_t *query) {
|
92
124
|
if (!query->stmt)
|
93
125
|
prepare_single_stmt(DB_GVL_MODE(query), query->sqlite3_db, &query->stmt, query->sql);
|
94
|
-
|
126
|
+
Database_issue_query(query->db_struct, query->sql);
|
95
127
|
sqlite3_reset(query->stmt);
|
96
128
|
query->eof = 0;
|
97
129
|
}
|
@@ -99,9 +131,7 @@ static inline void query_reset(Query_t *query) {
|
|
99
131
|
static inline void query_reset_and_bind(Query_t *query, int argc, VALUE * argv) {
|
100
132
|
if (!query->stmt)
|
101
133
|
prepare_single_stmt(DB_GVL_MODE(query), query->sqlite3_db, &query->stmt, query->sql);
|
102
|
-
|
103
|
-
TRACE_SQL(query->db_struct, query->sql);
|
104
|
-
|
134
|
+
Database_issue_query(query->db_struct, query->sql);
|
105
135
|
sqlite3_reset(query->stmt);
|
106
136
|
query->eof = 0;
|
107
137
|
if (argc > 0) {
|
@@ -128,8 +158,6 @@ VALUE Query_reset(VALUE self) {
|
|
128
158
|
if (query->closed) rb_raise(cError, "Query is closed");
|
129
159
|
|
130
160
|
query_reset(query);
|
131
|
-
TRACE_SQL(query->db_struct, query->sql);
|
132
|
-
|
133
161
|
return self;
|
134
162
|
}
|
135
163
|
|
@@ -175,7 +203,7 @@ VALUE Query_eof_p(VALUE self) {
|
|
175
203
|
|
176
204
|
#define MAX_ROWS(max_rows) (max_rows == SINGLE_ROW ? 1 : max_rows)
|
177
205
|
|
178
|
-
static inline VALUE Query_perform_next(VALUE self, int max_rows,
|
206
|
+
static inline VALUE Query_perform_next(VALUE self, int max_rows, safe_query_impl call) {
|
179
207
|
Query_t *query = self_to_query(self);
|
180
208
|
if (query->closed) rb_raise(cError, "Query is closed");
|
181
209
|
|
@@ -184,69 +212,37 @@ static inline VALUE Query_perform_next(VALUE self, int max_rows, VALUE (*call)(q
|
|
184
212
|
|
185
213
|
query_ctx ctx = QUERY_CTX(
|
186
214
|
self,
|
215
|
+
query->sql,
|
187
216
|
query->db_struct,
|
188
217
|
query->stmt,
|
189
218
|
Qnil,
|
190
|
-
|
219
|
+
query->transform_proc,
|
220
|
+
query->query_mode,
|
221
|
+
ROW_YIELD_OR_MODE(max_rows == SINGLE_ROW ? ROW_SINGLE : ROW_MULTI),
|
191
222
|
MAX_ROWS(max_rows)
|
192
223
|
);
|
193
224
|
VALUE result = call(&ctx);
|
194
225
|
query->eof = ctx.eof;
|
195
|
-
return (ctx.
|
226
|
+
return (ctx.row_mode == ROW_YIELD) ? self : result;
|
196
227
|
}
|
197
228
|
|
198
229
|
#define MAX_ROWS_FROM_ARGV(argc, argv) (argc == 1 ? FIX2INT(argv[0]) : SINGLE_ROW)
|
199
230
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
* @return [Hash, Extralite::Query] next row or self if block is given
|
212
|
-
* @overload next_hash()
|
213
|
-
* @return [Hash, Extralite::Query] next row or self if block is given
|
214
|
-
* @overload next(row_count)
|
215
|
-
* @param row_count [Integer] maximum row count or -1 for all rows
|
216
|
-
* @return [Array<Hash>, Extralite::Query] next rows or self if block is given
|
217
|
-
* @overload next_hash(row_count)
|
218
|
-
* @param row_count [Integer] maximum row count or -1 for all rows
|
219
|
-
* @return [Array<Hash>, Extralite::Query] next rows or self if block is given
|
220
|
-
*/
|
221
|
-
VALUE Query_next_hash(int argc, VALUE *argv, VALUE self) {
|
222
|
-
rb_check_arity(argc, 0, 1);
|
223
|
-
return Query_perform_next(self, MAX_ROWS_FROM_ARGV(argc, argv), safe_query_hash);
|
224
|
-
}
|
225
|
-
|
226
|
-
/* Returns the next 1 or more rows from the associated query's result set as an
|
227
|
-
* array.
|
228
|
-
*
|
229
|
-
* If no row count is given, a single row is returned. If a row count is given,
|
230
|
-
* an array containing up to the `row_count` rows is returned. If `row_count` is
|
231
|
-
* -1, all rows are returned. If the end of the result set has been reached,
|
232
|
-
* `nil` is returned.
|
233
|
-
*
|
234
|
-
* If a block is given, rows are passed to the block and self is returned.
|
235
|
-
*
|
236
|
-
* @overload next_ary()
|
237
|
-
* @return [Array, Extralite::Query] next row or self if block is given
|
238
|
-
* @overload next_ary(row_count)
|
239
|
-
* @param row_count [Integer] maximum row count or -1 for all rows
|
240
|
-
* @return [Array<Array>, Extralite::Query] next rows or self if block is given
|
241
|
-
*/
|
242
|
-
VALUE Query_next_ary(int argc, VALUE *argv, VALUE self) {
|
243
|
-
rb_check_arity(argc, 0, 1);
|
244
|
-
return Query_perform_next(self, MAX_ROWS_FROM_ARGV(argc, argv), safe_query_ary);
|
231
|
+
inline safe_query_impl query_impl(enum query_mode query_mode) {
|
232
|
+
switch (query_mode) {
|
233
|
+
case QUERY_HASH:
|
234
|
+
return safe_query_hash;
|
235
|
+
case QUERY_ARGV:
|
236
|
+
return safe_query_argv;
|
237
|
+
case QUERY_ARY:
|
238
|
+
return safe_query_ary;
|
239
|
+
default:
|
240
|
+
rb_raise(cError, "Invalid query mode (query_impl)");
|
241
|
+
}
|
245
242
|
}
|
246
243
|
|
247
|
-
/* Returns the next 1 or more rows from the associated query's result set
|
248
|
-
*
|
249
|
-
* raised.
|
244
|
+
/* Returns the next 1 or more rows from the associated query's result set. The
|
245
|
+
* row value is returned according to the query mode and the query transform.
|
250
246
|
*
|
251
247
|
* If no row count is given, a single row is returned. If a row count is given,
|
252
248
|
* an array containing up to the `row_count` rows is returned. If `row_count` is
|
@@ -255,92 +251,41 @@ VALUE Query_next_ary(int argc, VALUE *argv, VALUE self) {
|
|
255
251
|
*
|
256
252
|
* If a block is given, rows are passed to the block and self is returned.
|
257
253
|
*
|
258
|
-
* @overload
|
259
|
-
* @return [
|
260
|
-
* @overload
|
254
|
+
* @overload next()
|
255
|
+
* @return [any, Extralite::Query] next row or self if block is given
|
256
|
+
* @overload next(row_count)
|
261
257
|
* @param row_count [Integer] maximum row count or -1 for all rows
|
262
|
-
* @return [Array<
|
258
|
+
* @return [Array<any>, Extralite::Query] next rows or self if block is given
|
263
259
|
*/
|
264
|
-
VALUE
|
265
|
-
rb_check_arity(argc, 0, 1);
|
266
|
-
return Query_perform_next(self, MAX_ROWS_FROM_ARGV(argc, argv), safe_query_single_column);
|
267
|
-
}
|
268
|
-
|
269
|
-
/* Returns all rows in the associated query's result set as hashes.
|
270
|
-
*
|
271
|
-
* @overload to_a()
|
272
|
-
* @return [Array<Hash>] all rows
|
273
|
-
* @overload to_a_hash
|
274
|
-
* @return [Array<Hash>] all rows
|
275
|
-
*/
|
276
|
-
VALUE Query_to_a_hash(VALUE self) {
|
277
|
-
Query_t *query = self_to_query(self);
|
278
|
-
query_reset(query);
|
279
|
-
return Query_perform_next(self, ALL_ROWS, safe_query_hash);
|
280
|
-
}
|
281
|
-
|
282
|
-
/* Returns all rows in the associated query's result set as arrays.
|
283
|
-
*
|
284
|
-
* @return [Array<Array>] all rows
|
285
|
-
*/
|
286
|
-
VALUE Query_to_a_ary(VALUE self) {
|
287
|
-
Query_t *query = self_to_query(self);
|
288
|
-
query_reset(query);
|
289
|
-
return Query_perform_next(self, ALL_ROWS, safe_query_ary);
|
290
|
-
}
|
291
|
-
|
292
|
-
/* Returns all rows in the associated query's result set as single values. If
|
293
|
-
* the result set contains more than one column an error is raised.
|
294
|
-
*
|
295
|
-
* @return [Array<Object>] all rows
|
296
|
-
*/
|
297
|
-
VALUE Query_to_a_single_column(VALUE self) {
|
260
|
+
VALUE Query_next(int argc, VALUE *argv, VALUE self) {
|
298
261
|
Query_t *query = self_to_query(self);
|
299
|
-
|
300
|
-
return Query_perform_next(self,
|
301
|
-
}
|
302
|
-
|
303
|
-
/* Iterates through the result set, passing each row to the given block as a
|
304
|
-
* hash. If no block is given, returns a `Extralite::Iterator` instance in hash
|
305
|
-
* mode.
|
306
|
-
*
|
307
|
-
* @return [Extralite::Query, Extralite::Iterator] self or an iterator if no block is given
|
308
|
-
*/
|
309
|
-
VALUE Query_each_hash(VALUE self) {
|
310
|
-
if (!rb_block_given_p()) return rb_funcall(cIterator, ID_new, 2, self, SYM_hash);
|
311
|
-
|
312
|
-
Query_t *query = self_to_query(self);
|
313
|
-
query_reset(query);
|
314
|
-
return Query_perform_next(self, ALL_ROWS, safe_query_hash);
|
262
|
+
rb_check_arity(argc, 0, 1);
|
263
|
+
return Query_perform_next(self, MAX_ROWS_FROM_ARGV(argc, argv), query_impl(query->query_mode));
|
315
264
|
}
|
316
265
|
|
317
|
-
/*
|
318
|
-
*
|
319
|
-
* array mode.
|
266
|
+
/* Returns all rows in the associated query's result set. Rows are returned
|
267
|
+
* according to the query mode and the query transform.
|
320
268
|
*
|
321
|
-
* @return [
|
269
|
+
* @return [Array<any>] all rows
|
322
270
|
*/
|
323
|
-
VALUE
|
324
|
-
if (!rb_block_given_p()) return rb_funcall(cIterator, ID_new, 2, self, SYM_ary);
|
325
|
-
|
271
|
+
VALUE Query_to_a(VALUE self) {
|
326
272
|
Query_t *query = self_to_query(self);
|
327
273
|
query_reset(query);
|
328
|
-
return Query_perform_next(self, ALL_ROWS,
|
274
|
+
return Query_perform_next(self, ALL_ROWS, query_impl(query->query_mode));
|
329
275
|
}
|
330
276
|
|
331
|
-
/* Iterates through the result set, passing each row to the given block
|
332
|
-
*
|
333
|
-
*
|
334
|
-
* single column mode.
|
277
|
+
/* Iterates through the result set, passing each row to the given block. If no
|
278
|
+
* block is given, returns a `Extralite::Iterator` instance. Rows are given to
|
279
|
+
* the block according to the query mode and the query transform.
|
335
280
|
*
|
336
281
|
* @return [Extralite::Query, Extralite::Iterator] self or an iterator if no block is given
|
337
282
|
*/
|
338
|
-
VALUE
|
339
|
-
if (!rb_block_given_p()) return rb_funcall(cIterator, ID_new,
|
283
|
+
VALUE Query_each(VALUE self) {
|
284
|
+
if (!rb_block_given_p()) return rb_funcall(cIterator, ID_new, 1, self);
|
340
285
|
|
341
286
|
Query_t *query = self_to_query(self);
|
342
287
|
query_reset(query);
|
343
|
-
return Query_perform_next(self, ALL_ROWS,
|
288
|
+
return Query_perform_next(self, ALL_ROWS, query_impl(query->query_mode));
|
344
289
|
}
|
345
290
|
|
346
291
|
/* call-seq:
|
@@ -440,10 +385,13 @@ VALUE Query_batch_execute(VALUE self, VALUE parameters) {
|
|
440
385
|
|
441
386
|
query_ctx ctx = QUERY_CTX(
|
442
387
|
self,
|
388
|
+
query->sql,
|
443
389
|
query->db_struct,
|
444
390
|
query->stmt,
|
445
391
|
parameters,
|
446
|
-
|
392
|
+
Qnil,
|
393
|
+
QUERY_HASH,
|
394
|
+
ROW_YIELD_OR_MODE(ROW_MULTI),
|
447
395
|
ALL_ROWS
|
448
396
|
);
|
449
397
|
return safe_batch_execute(&ctx);
|
@@ -462,6 +410,8 @@ VALUE Query_batch_execute(VALUE self, VALUE parameters) {
|
|
462
410
|
* invocation of the query, and the total number of changes is returned.
|
463
411
|
* Otherwise, an array containing the resulting rows for each invocation is
|
464
412
|
* returned.
|
413
|
+
*
|
414
|
+
* Rows are returned according to the query mode and transform.
|
465
415
|
*
|
466
416
|
* q = db.prepare('insert into foo values (?, ?) returning bar, baz')
|
467
417
|
* records = [
|
@@ -473,7 +423,7 @@ VALUE Query_batch_execute(VALUE self, VALUE parameters) {
|
|
473
423
|
* *
|
474
424
|
* @param sql [String] query SQL
|
475
425
|
* @param parameters [Array<Array, Hash>, Enumerable, Enumerator, Callable] parameters to run query with
|
476
|
-
* @return [Array<
|
426
|
+
* @return [Array<Array>, Integer] Returned rows or total number of changes effected
|
477
427
|
*/
|
478
428
|
VALUE Query_batch_query(VALUE self, VALUE parameters) {
|
479
429
|
Query_t *query = self_to_query(self);
|
@@ -484,103 +434,18 @@ VALUE Query_batch_query(VALUE self, VALUE parameters) {
|
|
484
434
|
|
485
435
|
query_ctx ctx = QUERY_CTX(
|
486
436
|
self,
|
437
|
+
query->sql,
|
487
438
|
query->db_struct,
|
488
439
|
query->stmt,
|
489
440
|
parameters,
|
490
|
-
|
441
|
+
query->transform_proc,
|
442
|
+
query->query_mode,
|
443
|
+
ROW_YIELD_OR_MODE(ROW_MULTI),
|
491
444
|
ALL_ROWS
|
492
445
|
);
|
493
446
|
return safe_batch_query(&ctx);
|
494
447
|
}
|
495
448
|
|
496
|
-
/* call-seq:
|
497
|
-
* query.batch_query_ary(sql, params_array) -> rows
|
498
|
-
* query.batch_query_ary(sql, enumerable) -> rows
|
499
|
-
* query.batch_query_ary(sql, callable) -> rows
|
500
|
-
* query.batch_query_ary(sql, params_array) { |rows| ... } -> changes
|
501
|
-
* query.batch_query_ary(sql, enumerable) { |rows| ... } -> changes
|
502
|
-
* query.batch_query_ary(sql, callable) { |rows| ... } -> changes
|
503
|
-
*
|
504
|
-
* Executes the prepared query for each list of parameters in the given paramter
|
505
|
-
* source. If a block is given, it is called with the resulting rows for each
|
506
|
-
* invocation of the query, and the total number of changes is returned.
|
507
|
-
* Otherwise, an array containing the resulting rows for each invocation is
|
508
|
-
* returned. Rows are represented as arrays.
|
509
|
-
*
|
510
|
-
* q = db.prepare('insert into foo values (?, ?) returning bar, baz')
|
511
|
-
* records = [
|
512
|
-
* [1, 2],
|
513
|
-
* [3, 4]
|
514
|
-
* ]
|
515
|
-
* q.batch_query_ary(records)
|
516
|
-
* #=> [{ bar: 1, baz: 2 }, { bar: 3, baz: 4}]
|
517
|
-
* *
|
518
|
-
* @param sql [String] query SQL
|
519
|
-
* @param parameters [Array<Array, Hash>, Enumerable, Enumerator, Callable] parameters to run query with
|
520
|
-
* @return [Array<Hash>, Integer] Total number of changes effected
|
521
|
-
*/
|
522
|
-
VALUE Query_batch_query_ary(VALUE self, VALUE parameters) {
|
523
|
-
Query_t *query = self_to_query(self);
|
524
|
-
if (query->closed) rb_raise(cError, "Query is closed");
|
525
|
-
|
526
|
-
if (!query->stmt)
|
527
|
-
prepare_single_stmt(DB_GVL_MODE(query), query->sqlite3_db, &query->stmt, query->sql);
|
528
|
-
|
529
|
-
query_ctx ctx = QUERY_CTX(
|
530
|
-
self,
|
531
|
-
query->db_struct,
|
532
|
-
query->stmt,
|
533
|
-
parameters,
|
534
|
-
QUERY_MODE(QUERY_MULTI_ROW),
|
535
|
-
ALL_ROWS
|
536
|
-
);
|
537
|
-
return safe_batch_query_ary(&ctx);
|
538
|
-
}
|
539
|
-
|
540
|
-
/* call-seq:
|
541
|
-
* query.batch_query_single_column(sql, params_array) -> rows
|
542
|
-
* query.batch_query_single_column(sql, enumerable) -> rows
|
543
|
-
* query.batch_query_single_column(sql, callable) -> rows
|
544
|
-
* query.batch_query_single_column(sql, params_array) { |rows| ... } -> changes
|
545
|
-
* query.batch_query_single_column(sql, enumerable) { |rows| ... } -> changes
|
546
|
-
* query.batch_query_single_column(sql, callable) { |rows| ... } -> changes
|
547
|
-
*
|
548
|
-
* Executes the prepared query for each list of parameters in the given paramter
|
549
|
-
* source. If a block is given, it is called with the resulting rows for each
|
550
|
-
* invocation of the query, and the total number of changes is returned.
|
551
|
-
* Otherwise, an array containing the resulting rows for each invocation is
|
552
|
-
* returned. Rows are represented as single values.
|
553
|
-
*
|
554
|
-
* q = db.prepare('insert into foo values (?, ?) returning bar, baz')
|
555
|
-
* records = [
|
556
|
-
* [1, 2],
|
557
|
-
* [3, 4]
|
558
|
-
* ]
|
559
|
-
* q.batch_query_single_column(records)
|
560
|
-
* #=> [{ bar: 1, baz: 2 }, { bar: 3, baz: 4}]
|
561
|
-
* *
|
562
|
-
* @param sql [String] query SQL
|
563
|
-
* @param parameters [Array<Array, Hash>, Enumerable, Enumerator, Callable] parameters to run query with
|
564
|
-
* @return [Array<Hash>, Integer] Total number of changes effected
|
565
|
-
*/
|
566
|
-
VALUE Query_batch_query_single_column(VALUE self, VALUE parameters) {
|
567
|
-
Query_t *query = self_to_query(self);
|
568
|
-
if (query->closed) rb_raise(cError, "Query is closed");
|
569
|
-
|
570
|
-
if (!query->stmt)
|
571
|
-
prepare_single_stmt(DB_GVL_MODE(query), query->sqlite3_db, &query->stmt, query->sql);
|
572
|
-
|
573
|
-
query_ctx ctx = QUERY_CTX(
|
574
|
-
self,
|
575
|
-
query->db_struct,
|
576
|
-
query->stmt,
|
577
|
-
parameters,
|
578
|
-
QUERY_MODE(QUERY_MULTI_ROW),
|
579
|
-
ALL_ROWS
|
580
|
-
);
|
581
|
-
return safe_batch_query_single_column(&ctx);
|
582
|
-
}
|
583
|
-
|
584
449
|
/* Returns the database associated with the query.
|
585
450
|
*
|
586
451
|
* @overload database()
|
@@ -622,7 +487,12 @@ VALUE Query_columns(VALUE self) {
|
|
622
487
|
*/
|
623
488
|
VALUE Query_clone(VALUE self) {
|
624
489
|
Query_t *query = self_to_query(self);
|
625
|
-
|
490
|
+
VALUE args[] = {
|
491
|
+
query->db,
|
492
|
+
query->sql,
|
493
|
+
query_mode_to_symbol(query->query_mode)
|
494
|
+
};
|
495
|
+
return rb_funcall_with_block(cQuery, ID_new, 3, args, query->transform_proc);
|
626
496
|
}
|
627
497
|
|
628
498
|
/* Closes the query. Attempting to run a closed query will raise an error.
|
@@ -675,6 +545,27 @@ VALUE Query_status(int argc, VALUE* argv, VALUE self) {
|
|
675
545
|
return INT2NUM(value);
|
676
546
|
}
|
677
547
|
|
548
|
+
/* Sets the transform block to the given block. If a transform block is set,
|
549
|
+
* calls to #to_a, #next, #each and #batch_query will transform values fetched
|
550
|
+
* from the database using the transform block before passing them to the
|
551
|
+
* application code. To remove the transform block, call `#transform`
|
552
|
+
* without a block. The transform for each row is done by passing the row hash
|
553
|
+
* to the block.
|
554
|
+
*
|
555
|
+
* # fetch column c as an ORM object
|
556
|
+
* q = db.prepare('select * from foo order by a').transform do |h|
|
557
|
+
* MyModel.new(h)
|
558
|
+
* end
|
559
|
+
*
|
560
|
+
* @return [Extralite::Query] query
|
561
|
+
*/
|
562
|
+
VALUE Query_transform(VALUE self) {
|
563
|
+
Query_t *query = self_to_query(self);
|
564
|
+
|
565
|
+
RB_OBJ_WRITE(self, &query->transform_proc, rb_block_given_p() ? rb_block_proc() : Qnil);
|
566
|
+
return self;
|
567
|
+
}
|
568
|
+
|
678
569
|
/* Returns a short string representation of the query instance, including the
|
679
570
|
* SQL string.
|
680
571
|
*
|
@@ -693,50 +584,68 @@ VALUE Query_inspect(VALUE self) {
|
|
693
584
|
return rb_sprintf("#<%"PRIsVALUE":%p %"PRIsVALUE">", cname, (void*)self, sql);
|
694
585
|
}
|
695
586
|
|
587
|
+
/* Returns the query mode.
|
588
|
+
*
|
589
|
+
* @return [Symbol] query mode
|
590
|
+
*/
|
591
|
+
VALUE Query_mode_get(VALUE self) {
|
592
|
+
Query_t *query = self_to_query(self);
|
593
|
+
return query_mode_to_symbol(query->query_mode);
|
594
|
+
}
|
595
|
+
|
596
|
+
/* call-seq:
|
597
|
+
* query.mode = mode
|
598
|
+
*
|
599
|
+
* Sets the query mode. This can be one of `:hash`, `:argv`, `:ary`.
|
600
|
+
*
|
601
|
+
* @param mode [Symbol] query mode
|
602
|
+
* @return [Symbol] query mode
|
603
|
+
*/
|
604
|
+
VALUE Query_mode_set(VALUE self, VALUE mode) {
|
605
|
+
Query_t *query = self_to_query(self);
|
606
|
+
query->query_mode = symbol_to_query_mode(mode);
|
607
|
+
return mode;
|
608
|
+
}
|
609
|
+
|
696
610
|
void Init_ExtraliteQuery(void) {
|
697
611
|
VALUE mExtralite = rb_define_module("Extralite");
|
698
612
|
|
699
613
|
cQuery = rb_define_class_under(mExtralite, "Query", rb_cObject);
|
700
614
|
rb_define_alloc_func(cQuery, Query_allocate);
|
701
615
|
|
702
|
-
rb_define_method(cQuery, "bind",
|
703
|
-
rb_define_method(cQuery, "close",
|
704
|
-
rb_define_method(cQuery, "closed?",
|
705
|
-
rb_define_method(cQuery, "columns",
|
706
|
-
rb_define_method(cQuery, "clone",
|
707
|
-
rb_define_method(cQuery, "database",
|
708
|
-
rb_define_method(cQuery, "db",
|
709
|
-
rb_define_method(cQuery, "dup",
|
710
|
-
|
711
|
-
rb_define_method(cQuery, "
|
712
|
-
rb_define_method(cQuery, "
|
713
|
-
rb_define_method(cQuery, "
|
714
|
-
rb_define_method(cQuery, "
|
715
|
-
|
716
|
-
rb_define_method(cQuery, "
|
717
|
-
rb_define_method(cQuery, "
|
718
|
-
rb_define_method(cQuery, "
|
719
|
-
rb_define_method(cQuery, "
|
720
|
-
rb_define_method(cQuery, "
|
721
|
-
rb_define_method(cQuery, "
|
722
|
-
rb_define_method(cQuery, "
|
723
|
-
rb_define_method(cQuery, "
|
724
|
-
rb_define_method(cQuery, "
|
725
|
-
|
726
|
-
rb_define_method(cQuery, "next", Query_next_hash, -1);
|
727
|
-
rb_define_method(cQuery, "next_ary", Query_next_ary, -1);
|
728
|
-
rb_define_method(cQuery, "next_hash", Query_next_hash, -1);
|
729
|
-
rb_define_method(cQuery, "next_single_column", Query_next_single_column, -1);
|
730
|
-
|
731
|
-
rb_define_method(cQuery, "reset", Query_reset, 0);
|
732
|
-
rb_define_method(cQuery, "sql", Query_sql, 0);
|
733
|
-
rb_define_method(cQuery, "status", Query_status, -1);
|
734
|
-
|
735
|
-
rb_define_method(cQuery, "to_a", Query_to_a_hash, 0);
|
736
|
-
rb_define_method(cQuery, "to_a_ary", Query_to_a_ary, 0);
|
737
|
-
rb_define_method(cQuery, "to_a_hash", Query_to_a_hash, 0);
|
738
|
-
rb_define_method(cQuery, "to_a_single_column", Query_to_a_single_column, 0);
|
616
|
+
rb_define_method(cQuery, "bind", Query_bind, -1);
|
617
|
+
rb_define_method(cQuery, "close", Query_close, 0);
|
618
|
+
rb_define_method(cQuery, "closed?", Query_closed_p, 0);
|
619
|
+
rb_define_method(cQuery, "columns", Query_columns, 0);
|
620
|
+
rb_define_method(cQuery, "clone", Query_clone, 0);
|
621
|
+
rb_define_method(cQuery, "database", Query_database, 0);
|
622
|
+
rb_define_method(cQuery, "db", Query_database, 0);
|
623
|
+
rb_define_method(cQuery, "dup", Query_clone, 0);
|
624
|
+
rb_define_method(cQuery, "each", Query_each, 0);
|
625
|
+
rb_define_method(cQuery, "eof?", Query_eof_p, 0);
|
626
|
+
rb_define_method(cQuery, "execute", Query_execute, -1);
|
627
|
+
rb_define_method(cQuery, "<<", Query_execute_chevrons, 1);
|
628
|
+
rb_define_method(cQuery, "batch_execute", Query_batch_execute, 1);
|
629
|
+
rb_define_method(cQuery, "batch_query", Query_batch_query, 1);
|
630
|
+
rb_define_method(cQuery, "initialize", Query_initialize, 3);
|
631
|
+
rb_define_method(cQuery, "inspect", Query_inspect, 0);
|
632
|
+
rb_define_method(cQuery, "mode", Query_mode_get, 0);
|
633
|
+
rb_define_method(cQuery, "mode=", Query_mode_set, 1);
|
634
|
+
rb_define_method(cQuery, "next", Query_next, -1);
|
635
|
+
rb_define_method(cQuery, "reset", Query_reset, 0);
|
636
|
+
rb_define_method(cQuery, "sql", Query_sql, 0);
|
637
|
+
rb_define_method(cQuery, "status", Query_status, -1);
|
638
|
+
rb_define_method(cQuery, "to_a", Query_to_a, 0);
|
639
|
+
rb_define_method(cQuery, "transform", Query_transform, 0);
|
739
640
|
|
740
641
|
ID_inspect = rb_intern("inspect");
|
741
642
|
ID_slice = rb_intern("slice");
|
643
|
+
|
644
|
+
SYM_hash = ID2SYM(rb_intern("hash"));
|
645
|
+
SYM_argv = ID2SYM(rb_intern("argv"));
|
646
|
+
SYM_ary = ID2SYM(rb_intern("ary"));
|
647
|
+
|
648
|
+
rb_gc_register_mark_object(SYM_hash);
|
649
|
+
rb_gc_register_mark_object(SYM_argv);
|
650
|
+
rb_gc_register_mark_object(SYM_ary);
|
742
651
|
}
|
data/extralite-bundle.gemspec
CHANGED
data/extralite.gemspec
CHANGED
data/gemspec.rb
CHANGED
@@ -8,19 +8,18 @@ def common_spec(s)
|
|
8
8
|
s.files = `git ls-files`.split
|
9
9
|
s.homepage = 'https://github.com/digital-fabric/extralite'
|
10
10
|
s.metadata = {
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
"changelog_uri" => "https://github.com/digital-fabric/extralite/blob/master/CHANGELOG.md"
|
11
|
+
'homepage_uri' => 'https://github.com/digital-fabric/extralite',
|
12
|
+
'documentation_uri' => 'https://www.rubydoc.info/gems/extralite',
|
13
|
+
'changelog_uri' => 'https://github.com/digital-fabric/extralite/blob/master/CHANGELOG.md'
|
15
14
|
}
|
16
|
-
s.rdoc_options = [
|
17
|
-
s.extra_rdoc_files = [
|
18
|
-
s.require_paths = [
|
15
|
+
s.rdoc_options = ['--title', 'Extralite', '--main', 'README.md']
|
16
|
+
s.extra_rdoc_files = ['README.md']
|
17
|
+
s.require_paths = ['lib']
|
19
18
|
s.required_ruby_version = '>= 3.0'
|
20
19
|
|
21
|
-
s.add_development_dependency 'rake-compiler', '1.
|
22
|
-
s.add_development_dependency 'minitest', '5.
|
20
|
+
s.add_development_dependency 'rake-compiler', '1.2.7'
|
21
|
+
s.add_development_dependency 'minitest', '5.21.2'
|
23
22
|
s.add_development_dependency 'simplecov', '0.17.1'
|
24
|
-
s.add_development_dependency 'yard', '0.9.
|
25
|
-
s.add_development_dependency 'sequel', '5.
|
23
|
+
s.add_development_dependency 'yard', '0.9.34'
|
24
|
+
s.add_development_dependency 'sequel', '5.77.0'
|
26
25
|
end
|
data/lib/extralite/version.rb
CHANGED