extralite 1.0 → 1.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/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +12 -6
- data/ext/extralite/extralite.c +41 -10
- data/lib/extralite/version.rb +1 -1
- data/test/test_database.rb +11 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bcad0681ac1ee598acef1989d7320f4215242dcfb3dad8857e791e313b2e673b
|
4
|
+
data.tar.gz: c26b4ed323da3ccd965a026b7d1c738723293412d226bda3c7c6795881b73239
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1d5ab7ba821785f24a75cfe2e0d9d9fac0dbf6f2504321e24a89a89fc783fc3a30bc10f9ee4a97340202db04a8351e730c701d11e53643b065dee5fc009014b
|
7
|
+
data.tar.gz: 31a6ad671bb88f74ae2ba02d0da1e8c23275816ce41f630e82bcb7003b7e3f06a5cd9a53abeeb215bbedee54aeac763445809d4add0906cfbce087ce2acbc5b9
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,16 @@
|
|
1
|
-
|
1
|
+
# Extralite - a Ruby gem for working with SQLite3 databases
|
2
|
+
|
3
|
+
[](http://rubygems.org/gems/extralite)
|
4
|
+
[](https://github.com/digital-fabric/extralite/actions?query=workflow%3ATests)
|
5
|
+
[](https://github.com/digital-fabric/extralite/blob/master/LICENSE)
|
6
|
+
|
7
|
+
## What is Extralite?
|
2
8
|
|
3
9
|
Extralite is an extra-lightweight (~365 lines of C-code) SQLite3 wrapper for
|
4
10
|
Ruby. It provides a single class with a minimal set of methods to interact with
|
5
11
|
an SQLite3 database.
|
6
12
|
|
7
|
-
|
13
|
+
## Features
|
8
14
|
|
9
15
|
- A variety of methods for different data access patterns: row as hash, row as
|
10
16
|
array, single single row, single column, single value.
|
@@ -17,7 +23,7 @@ an SQLite3 database.
|
|
17
23
|
- Load extensions (loading of extensions is autmatically enabled. You can find
|
18
24
|
some useful extensions here: https://github.com/nalgeon/sqlean.)
|
19
25
|
|
20
|
-
|
26
|
+
## Usage
|
21
27
|
|
22
28
|
```ruby
|
23
29
|
require 'extralite'
|
@@ -67,14 +73,14 @@ db.filename #=> "/tmp/my.db"
|
|
67
73
|
db.load_extension('/path/to/extension.so')
|
68
74
|
```
|
69
75
|
|
70
|
-
|
76
|
+
## Why not just use the sqlite3 gem?
|
71
77
|
|
72
78
|
The sqlite3-ruby gem is a popular, solid, well-maintained project, used by
|
73
79
|
thousands of developers. I've been doing a lot of work with SQLite3 lately, and
|
74
80
|
wanted to have a simpler API that gives me query results in a variety of ways.
|
75
81
|
Thus extralite was born.
|
76
82
|
|
77
|
-
|
83
|
+
## What about concurrency?
|
78
84
|
|
79
85
|
Extralite currently does not release the GVL. This means that even if queries
|
80
86
|
are executed on a separate thread, no other Ruby threads will be scheduled while
|
@@ -83,7 +89,7 @@ SQLite3 is busy fetching the next record.
|
|
83
89
|
In the future Extralite might be changed to release the GVL each time
|
84
90
|
`sqlite3_step` is called.
|
85
91
|
|
86
|
-
|
92
|
+
## Can I use it with an ORM like ActiveRecord or Sequel?
|
87
93
|
|
88
94
|
Not yet, but you are welcome to contribute adapters for those projects. I will
|
89
95
|
be releasing my own not-an-ORM tool in the near future.
|
data/ext/extralite/extralite.c
CHANGED
@@ -39,6 +39,14 @@ static VALUE Database_allocate(VALUE klass) {
|
|
39
39
|
#define GetDatabase(obj, database) \
|
40
40
|
TypedData_Get_Struct((obj), Database_t, &Database_type, (database))
|
41
41
|
|
42
|
+
// make sure the database is open
|
43
|
+
#define GetOpenDatabase(obj, database) { \
|
44
|
+
TypedData_Get_Struct((obj), Database_t, &Database_type, (database)); \
|
45
|
+
if (!(database)->sqlite3_db) { \
|
46
|
+
rb_raise(cError, "Database is closed"); \
|
47
|
+
} \
|
48
|
+
}
|
49
|
+
|
42
50
|
|
43
51
|
VALUE Database_initialize(VALUE self, VALUE path) {
|
44
52
|
int rc;
|
@@ -60,6 +68,27 @@ VALUE Database_initialize(VALUE self, VALUE path) {
|
|
60
68
|
return Qnil;
|
61
69
|
}
|
62
70
|
|
71
|
+
VALUE Database_close(VALUE self) {
|
72
|
+
int rc;
|
73
|
+
Database_t *db;
|
74
|
+
GetDatabase(self, db);
|
75
|
+
|
76
|
+
rc = sqlite3_close(db->sqlite3_db);
|
77
|
+
if (rc) {
|
78
|
+
rb_raise(cError, "%s", sqlite3_errmsg(db->sqlite3_db));
|
79
|
+
}
|
80
|
+
|
81
|
+
db->sqlite3_db = 0;
|
82
|
+
return self;
|
83
|
+
}
|
84
|
+
|
85
|
+
VALUE Database_closed_p(VALUE self) {
|
86
|
+
Database_t *db;
|
87
|
+
GetDatabase(self, db);
|
88
|
+
|
89
|
+
return db->sqlite3_db ? Qfalse : Qtrue;
|
90
|
+
}
|
91
|
+
|
63
92
|
inline VALUE get_column_value(sqlite3_stmt *stmt, int col, int type) {
|
64
93
|
switch (type) {
|
65
94
|
case SQLITE_NULL:
|
@@ -214,7 +243,7 @@ VALUE safe_query_hash(VALUE arg) {
|
|
214
243
|
VALUE column_names;
|
215
244
|
|
216
245
|
check_arity_and_prepare_sql(ctx->argc, ctx->argv, sql);
|
217
|
-
|
246
|
+
GetOpenDatabase(ctx->self, db);
|
218
247
|
|
219
248
|
prepare_multi_stmt(db->sqlite3_db, &ctx->stmt, sql);
|
220
249
|
bind_all_parameters(ctx->stmt, ctx->argc, ctx->argv);
|
@@ -250,7 +279,7 @@ VALUE safe_query_ary(VALUE arg) {
|
|
250
279
|
VALUE sql;
|
251
280
|
|
252
281
|
check_arity_and_prepare_sql(ctx->argc, ctx->argv, sql);
|
253
|
-
|
282
|
+
GetOpenDatabase(ctx->self, db);
|
254
283
|
|
255
284
|
prepare_multi_stmt(db->sqlite3_db, &ctx->stmt, sql);
|
256
285
|
bind_all_parameters(ctx->stmt, ctx->argc, ctx->argv);
|
@@ -283,7 +312,7 @@ VALUE safe_query_single_row(VALUE arg) {
|
|
283
312
|
VALUE column_names;
|
284
313
|
|
285
314
|
check_arity_and_prepare_sql(ctx->argc, ctx->argv, sql);
|
286
|
-
|
315
|
+
GetOpenDatabase(ctx->self, db);
|
287
316
|
|
288
317
|
prepare_multi_stmt(db->sqlite3_db, &ctx->stmt, sql);
|
289
318
|
bind_all_parameters(ctx->stmt, ctx->argc, ctx->argv);
|
@@ -314,7 +343,7 @@ VALUE safe_query_single_column(VALUE arg) {
|
|
314
343
|
VALUE value;
|
315
344
|
|
316
345
|
check_arity_and_prepare_sql(ctx->argc, ctx->argv, sql);
|
317
|
-
|
346
|
+
GetOpenDatabase(ctx->self, db);
|
318
347
|
|
319
348
|
prepare_multi_stmt(db->sqlite3_db, &ctx->stmt, sql);
|
320
349
|
bind_all_parameters(ctx->stmt, ctx->argc, ctx->argv);
|
@@ -348,7 +377,7 @@ VALUE safe_query_single_value(VALUE arg) {
|
|
348
377
|
VALUE value = Qnil;
|
349
378
|
|
350
379
|
check_arity_and_prepare_sql(ctx->argc, ctx->argv, sql);
|
351
|
-
|
380
|
+
GetOpenDatabase(ctx->self, db);
|
352
381
|
|
353
382
|
prepare_multi_stmt(db->sqlite3_db, &ctx->stmt, sql);
|
354
383
|
bind_all_parameters(ctx->stmt, ctx->argc, ctx->argv);
|
@@ -370,14 +399,14 @@ VALUE Database_query_single_value(int argc, VALUE *argv, VALUE self) {
|
|
370
399
|
|
371
400
|
VALUE Database_last_insert_rowid(VALUE self) {
|
372
401
|
Database_t *db;
|
373
|
-
|
402
|
+
GetOpenDatabase(self, db);
|
374
403
|
|
375
404
|
return INT2NUM(sqlite3_last_insert_rowid(db->sqlite3_db));
|
376
405
|
}
|
377
406
|
|
378
407
|
VALUE Database_changes(VALUE self) {
|
379
408
|
Database_t *db;
|
380
|
-
|
409
|
+
GetOpenDatabase(self, db);
|
381
410
|
|
382
411
|
return INT2NUM(sqlite3_changes(db->sqlite3_db));
|
383
412
|
}
|
@@ -386,7 +415,7 @@ VALUE Database_filename(int argc, VALUE *argv, VALUE self) {
|
|
386
415
|
const char *db_name;
|
387
416
|
const char *filename;
|
388
417
|
Database_t *db;
|
389
|
-
|
418
|
+
GetOpenDatabase(self, db);
|
390
419
|
|
391
420
|
rb_check_arity(argc, 0, 1);
|
392
421
|
db_name = (argc == 1) ? StringValueCStr(argv[0]) : "main";
|
@@ -396,14 +425,14 @@ VALUE Database_filename(int argc, VALUE *argv, VALUE self) {
|
|
396
425
|
|
397
426
|
VALUE Database_transaction_active_p(VALUE self) {
|
398
427
|
Database_t *db;
|
399
|
-
|
428
|
+
GetOpenDatabase(self, db);
|
400
429
|
|
401
430
|
return sqlite3_get_autocommit(db->sqlite3_db) ? Qfalse : Qtrue;
|
402
431
|
}
|
403
432
|
|
404
433
|
VALUE Database_load_extension(VALUE self, VALUE path) {
|
405
434
|
Database_t *db;
|
406
|
-
|
435
|
+
GetOpenDatabase(self, db);
|
407
436
|
char *err_msg;
|
408
437
|
|
409
438
|
int rc = sqlite3_load_extension(db->sqlite3_db, RSTRING_PTR(path), 0, &err_msg);
|
@@ -422,6 +451,8 @@ void Init_Extralite() {
|
|
422
451
|
rb_define_alloc_func(cDatabase, Database_allocate);
|
423
452
|
|
424
453
|
rb_define_method(cDatabase, "initialize", Database_initialize, 1);
|
454
|
+
rb_define_method(cDatabase, "close", Database_close, 0);
|
455
|
+
rb_define_method(cDatabase, "closed?", Database_closed_p, 0);
|
425
456
|
|
426
457
|
rb_define_method(cDatabase, "query", Database_query_hash, -1);
|
427
458
|
rb_define_method(cDatabase, "query_hash", Database_query_hash, -1);
|
data/lib/extralite/version.rb
CHANGED
data/test/test_database.rb
CHANGED
@@ -89,4 +89,15 @@ end
|
|
89
89
|
r = @db.query('select 1 as foo; ')
|
90
90
|
assert_equal [{ foo: 1 }], r
|
91
91
|
end
|
92
|
+
|
93
|
+
def test_close
|
94
|
+
assert_equal false, @db.closed?
|
95
|
+
r = @db.query_single_value('select 42')
|
96
|
+
assert_equal 42, r
|
97
|
+
|
98
|
+
assert_equal @db, @db.close
|
99
|
+
assert_equal true, @db.closed?
|
100
|
+
|
101
|
+
assert_raises(Extralite::Error) { @db.query_single_value('select 42') }
|
102
|
+
end
|
92
103
|
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.
|
4
|
+
version: '1.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: 2021-
|
11
|
+
date: 2021-06-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|