extralite 1.4 → 1.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +3 -8
- data/CHANGELOG.md +18 -0
- data/Gemfile.lock +12 -33
- data/README.md +83 -20
- data/Rakefile +17 -8
- data/ext/extralite/extralite.c +239 -26
- data/extralite.gemspec +5 -5
- data/lib/extralite/version.rb +1 -1
- data/lib/extralite.rb +20 -0
- data/lib/sequel/adapters/extralite.rb +380 -0
- data/test/perf.rb +51 -0
- data/test/run.rb +5 -0
- data/test/test_database.rb +108 -3
- data/test/test_sequel.rb +24 -0
- metadata +16 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 149ddf21bc7feaf4d7c3a19011ac9a515fe83d5f57b88c507783bee8c6d5e096
|
4
|
+
data.tar.gz: 55507a0acbd8efeb89d5dfcf652441081285a670a5968a96f2696d3073844975
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7cdc5d0179c26c3deddc8439e4aaa5f91429ed3839cffc2224fefd8e90c78f0db9c4768f9534b693638572ec5e99ab0317a948f037c654262eca6d801a438f9
|
7
|
+
data.tar.gz: 4ae156e6850e5485b31b1f701597c0692608b59facd1473ca064d0b23ca8b5d2d84995f4fe4c99800b3e01815fb32e21481290e369506e5d2c4e9794af8fe853
|
data/.github/workflows/test.yml
CHANGED
@@ -8,7 +8,7 @@ jobs:
|
|
8
8
|
fail-fast: false
|
9
9
|
matrix:
|
10
10
|
os: [ubuntu-latest]
|
11
|
-
ruby: [2.6, 2.7, 3.0]
|
11
|
+
ruby: [2.6, 2.7, '3.0']
|
12
12
|
|
13
13
|
name: >-
|
14
14
|
${{matrix.os}}, ${{matrix.ruby}}
|
@@ -16,15 +16,10 @@ jobs:
|
|
16
16
|
runs-on: ${{matrix.os}}
|
17
17
|
steps:
|
18
18
|
- uses: actions/checkout@v1
|
19
|
-
- uses:
|
19
|
+
- uses: ruby/setup-ruby@v1
|
20
20
|
with:
|
21
21
|
ruby-version: ${{matrix.ruby}}
|
22
|
-
|
23
|
-
run: |
|
24
|
-
gem install bundler
|
25
|
-
bundle install
|
26
|
-
- name: Show Linux kernel version
|
27
|
-
run: uname -r
|
22
|
+
bundler-cache: true # 'bundle install' and cache
|
28
23
|
- name: Compile C-extension
|
29
24
|
run: bundle exec rake compile
|
30
25
|
- name: Run tests
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
## 1.8 2021-12-15
|
2
|
+
|
3
|
+
- Add documentation
|
4
|
+
|
5
|
+
## 1.7 2021-12-13
|
6
|
+
|
7
|
+
- Add extralite Sequel adapter
|
8
|
+
- Add support for binding hash parameters
|
9
|
+
|
10
|
+
## 1.6 2021-12-13
|
11
|
+
|
12
|
+
- Release GVL while fetching rows
|
13
|
+
|
14
|
+
## 1.5 2021-12-13
|
15
|
+
|
16
|
+
- Release GVL while preparing statements
|
17
|
+
- Use `sqlite3_prepare_v2` instead of deprecated `sqlite_prepare`
|
18
|
+
|
1
19
|
## 1.4 2021-08-25
|
2
20
|
|
3
21
|
- Fix possible segfault in cleanup_stmt
|
data/Gemfile.lock
CHANGED
@@ -1,58 +1,37 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
extralite (1.
|
4
|
+
extralite (1.8)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
ast (2.4.2)
|
10
|
-
coderay (1.1.3)
|
11
9
|
docile (1.4.0)
|
12
10
|
json (2.5.1)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
parser (3.0.1.1)
|
17
|
-
ast (~> 2.4.1)
|
18
|
-
pry (0.13.1)
|
19
|
-
coderay (~> 1.1)
|
20
|
-
method_source (~> 1.0)
|
21
|
-
rainbow (3.0.0)
|
22
|
-
rake (13.0.3)
|
23
|
-
rake-compiler (1.1.1)
|
11
|
+
minitest (5.15.0)
|
12
|
+
rake (13.0.6)
|
13
|
+
rake-compiler (1.1.6)
|
24
14
|
rake
|
25
|
-
|
26
|
-
rexml (3.2.5)
|
27
|
-
rubocop (0.85.1)
|
28
|
-
parallel (~> 1.10)
|
29
|
-
parser (>= 2.7.0.1)
|
30
|
-
rainbow (>= 2.2.2, < 4.0)
|
31
|
-
regexp_parser (>= 1.7)
|
32
|
-
rexml
|
33
|
-
rubocop-ast (>= 0.0.3)
|
34
|
-
ruby-progressbar (~> 1.7)
|
35
|
-
unicode-display_width (>= 1.4.0, < 2.0)
|
36
|
-
rubocop-ast (1.5.0)
|
37
|
-
parser (>= 3.0.1.1)
|
38
|
-
ruby-progressbar (1.11.0)
|
15
|
+
sequel (5.51.0)
|
39
16
|
simplecov (0.17.1)
|
40
17
|
docile (~> 1.1)
|
41
18
|
json (>= 1.8, < 3)
|
42
19
|
simplecov-html (~> 0.10.0)
|
43
20
|
simplecov-html (0.10.2)
|
44
|
-
|
21
|
+
webrick (1.7.0)
|
22
|
+
yard (0.9.27)
|
23
|
+
webrick (~> 1.7.0)
|
45
24
|
|
46
25
|
PLATFORMS
|
47
26
|
ruby
|
48
27
|
|
49
28
|
DEPENDENCIES
|
50
29
|
extralite!
|
51
|
-
minitest (= 5.
|
52
|
-
|
53
|
-
|
54
|
-
rubocop (= 0.85.1)
|
30
|
+
minitest (= 5.15.0)
|
31
|
+
rake-compiler (= 1.1.6)
|
32
|
+
sequel (= 5.51.0)
|
55
33
|
simplecov (= 0.17.1)
|
34
|
+
yard (= 0.9.27)
|
56
35
|
|
57
36
|
BUNDLED WITH
|
58
37
|
2.1.4
|
data/README.md
CHANGED
@@ -6,22 +6,29 @@
|
|
6
6
|
|
7
7
|
## What is Extralite?
|
8
8
|
|
9
|
-
Extralite is an extra-lightweight (less than
|
10
|
-
Ruby. It provides a single class with a minimal set of methods to
|
11
|
-
an SQLite3 database.
|
9
|
+
Extralite is an extra-lightweight (less than 430 lines of C-code) SQLite3
|
10
|
+
wrapper for Ruby. It provides a single class with a minimal set of methods to
|
11
|
+
interact with an SQLite3 database.
|
12
12
|
|
13
13
|
## Features
|
14
14
|
|
15
|
-
- A variety of methods for different data access patterns:
|
16
|
-
|
15
|
+
- A variety of methods for different data access patterns: rows as hashes, rows
|
16
|
+
as arrays, single row, single column, single value.
|
17
|
+
- Super fast - [up to 12.5x faster](#performance) than the
|
18
|
+
[sqlite3](https://github.com/sparklemotion/sqlite3-ruby) gem (see also
|
19
|
+
[comparison](#why-not-just-use-the-sqlite3-gem).)
|
20
|
+
- Improved [concurrency](#what-about-concurrency) for multithreaded apps: the
|
21
|
+
Ruby GVL is released while preparing SQL statements and while iterating over
|
22
|
+
results.
|
17
23
|
- Iterate over records with a block, or collect records into an array.
|
18
24
|
- Parameter binding.
|
19
|
-
-
|
20
|
-
creating/modifying schemas).
|
25
|
+
- Automatically execute SQL strings containing multiple semicolon-separated
|
26
|
+
queries (handy for creating/modifying schemas).
|
21
27
|
- Get last insert rowid.
|
22
28
|
- Get number of rows changed by last query.
|
23
29
|
- Load extensions (loading of extensions is autmatically enabled. You can find
|
24
30
|
some useful extensions here: https://github.com/nalgeon/sqlean.)
|
31
|
+
- Includes a [Sequel adapter](#usage-with-sequel) (an ActiveRecord)
|
25
32
|
|
26
33
|
## Usage
|
27
34
|
|
@@ -60,8 +67,13 @@ db.query_single_value("select 'foo'") #=> "foo"
|
|
60
67
|
# parameter binding (works for all query_xxx methods)
|
61
68
|
db.query_hash('select ? as foo, ? as bar', 1, 2) #=> [{ :foo => 1, :bar => 2 }]
|
62
69
|
|
70
|
+
# parameter binding of named parameters
|
71
|
+
db.query('select * from foo where bar = :bar', bar: 42)
|
72
|
+
db.query('select * from foo where bar = :bar', 'bar' => 42)
|
73
|
+
db.query('select * from foo where bar = :bar', ':bar' => 42)
|
74
|
+
|
63
75
|
# get last insert rowid
|
64
|
-
rowid = db.
|
76
|
+
rowid = db.last_insert_rowid
|
65
77
|
|
66
78
|
# get number of rows changed in last query
|
67
79
|
number_of_rows_affected = db.changes
|
@@ -77,23 +89,74 @@ db.close
|
|
77
89
|
db.closed? #=> true
|
78
90
|
```
|
79
91
|
|
92
|
+
## Usage with Sequel
|
93
|
+
|
94
|
+
Extralite includes an adapter for
|
95
|
+
[Sequel](https://github.com/jeremyevans/sequel). To use the Extralite adapter,
|
96
|
+
just use the `extralite` scheme instead of `sqlite`:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
DB = Sequel.connect('extralite:blog.db')
|
100
|
+
articles = DB[:articles]
|
101
|
+
p articles.to_a
|
102
|
+
```
|
103
|
+
|
104
|
+
(Make sure you include `extralite` as a dependency in your `Gemfile`.)
|
105
|
+
|
80
106
|
## Why not just use the sqlite3 gem?
|
81
107
|
|
82
|
-
The sqlite3-ruby gem is a
|
83
|
-
thousands of developers. I've
|
84
|
-
|
85
|
-
Thus extralite was
|
108
|
+
The [sqlite3-ruby](https://github.com/sparklemotion/sqlite3-ruby) gem is a
|
109
|
+
popular, solid, well-maintained project, used by thousands of developers. I've
|
110
|
+
been doing a lot of work with SQLite3 databases lately, and wanted to have a
|
111
|
+
simpler API that gives me query results in a variety of ways. Thus extralite was
|
112
|
+
born.
|
113
|
+
|
114
|
+
Extralite is quite a bit [faster](#performance) than sqlite3-ruby and is also
|
115
|
+
[thread-friendly](#what-about-concurrency). On the other hand, Extralite does
|
116
|
+
not have support for defining custom functions, aggregates and collations. If
|
117
|
+
you're using those features, you'll need to stick with sqlite3-ruby.
|
118
|
+
|
119
|
+
Here's a table summarizing the differences between the two gems:
|
120
|
+
|
121
|
+
| |sqlite3-ruby|Extralite|
|
122
|
+
|-|-|-|
|
123
|
+
|API design|multiple classes|single class|
|
124
|
+
|Query results|row as hash, row as array, single row, single value|row as hash, row as array, __single column__, single row, single value|
|
125
|
+
|execute multiple statements|separate API (#execute_batch)|integrated|
|
126
|
+
|custom functions in Ruby|yes|no|
|
127
|
+
|custom collations|yes|no|
|
128
|
+
|custom aggregate functions|yes|no|
|
129
|
+
|Multithread friendly|no|[yes](#what-about-concurrency)|
|
130
|
+
|Code size|~2650LoC|~500LoC|
|
131
|
+
|Performance|1x|1.5x to 12.5x (see [below](#performance))|
|
86
132
|
|
87
133
|
## What about concurrency?
|
88
134
|
|
89
|
-
Extralite
|
90
|
-
|
91
|
-
|
135
|
+
Extralite releases the GVL while making blocking calls to the sqlite3 library,
|
136
|
+
that is while preparing SQL statements and fetching rows. Releasing the GVL
|
137
|
+
allows other threads to run while the sqlite3 library is busy compiling SQL into
|
138
|
+
bytecode, or fetching the next row. This does not seem to hurt Extralite's
|
139
|
+
performance:
|
140
|
+
|
141
|
+
## Performance
|
142
|
+
|
143
|
+
A benchmark script is
|
144
|
+
[included](https://github.com/digital-fabric/extralite/blob/main/test/perf.rb),
|
145
|
+
creating a table of various row counts, then fetching the entire table using
|
146
|
+
either `sqlite3` or `extralite`. This benchmark shows Extralite to be up to 12.5
|
147
|
+
times faster than `sqlite3` when fetching a large number of rows. Here are the
|
148
|
+
results (using the `sqlite3` gem performance as baseline):
|
149
|
+
|
150
|
+
|Row count|sqlite3-ruby (baseline)|Extralite (relative - rounded)|
|
151
|
+
|-:|-:|-:|
|
152
|
+
|10|1x|1.5x|
|
153
|
+
|1K|1x|7x|
|
154
|
+
|100K|1x|12.5x|
|
92
155
|
|
93
|
-
|
94
|
-
|
156
|
+
(If you're interested in checking this yourself, just run the script and let me
|
157
|
+
know if your results are different.)
|
95
158
|
|
96
|
-
##
|
159
|
+
## Contributing
|
97
160
|
|
98
|
-
|
99
|
-
|
161
|
+
Contributions in the form of issues, PRs or comments will be greatly
|
162
|
+
appreciated!
|
data/Rakefile
CHANGED
@@ -1,18 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/clean'
|
5
5
|
|
6
|
-
require
|
7
|
-
Rake::ExtensionTask.new(
|
8
|
-
ext.ext_dir =
|
6
|
+
require 'rake/extensiontask'
|
7
|
+
Rake::ExtensionTask.new('extralite_ext') do |ext|
|
8
|
+
ext.ext_dir = 'ext/extralite'
|
9
9
|
end
|
10
10
|
|
11
11
|
task :recompile => [:clean, :compile]
|
12
12
|
|
13
|
-
task :default => [:compile, :test]
|
13
|
+
task :default => [:compile, :doc, :test]
|
14
|
+
task :doc => :yard
|
14
15
|
task :test do
|
15
|
-
exec 'ruby test/
|
16
|
+
exec 'ruby test/run.rb'
|
16
17
|
end
|
17
18
|
|
18
|
-
CLEAN.include
|
19
|
+
CLEAN.include '**/*.o', '**/*.so', '**/*.so.*', '**/*.a', '**/*.bundle', '**/*.jar', 'pkg', 'tmp'
|
20
|
+
|
21
|
+
require 'yard'
|
22
|
+
YARD_FILES = FileList['ext/extralite/extralite.c', 'lib/extralite.rb', 'lib/sequel/adapters/extralite.rb']
|
23
|
+
|
24
|
+
YARD::Rake::YardocTask.new do |t|
|
25
|
+
t.files = YARD_FILES
|
26
|
+
t.options = %w(-o doc --readme README.md)
|
27
|
+
end
|