extralite 1.25 → 1.27
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/.github/FUNDING.yml +1 -1
- data/.yardopts +8 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +2 -2
- data/README.md +1 -1
- data/ext/extralite/extconf.rb +1 -0
- data/ext/extralite/prepared_statement.c +6 -0
- data/lib/extralite/sqlite3_constants.rb +0 -1
- data/lib/extralite/version.rb +2 -1
- data/lib/extralite.rb +1 -0
- data/lib/sequel/adapters/extralite.rb +45 -26
- data/test/test_sequel.rb +27 -5
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a027328ec4af0d01bc81706f4f8e1ea08770a1341d8a36953882244b2d20ed88
|
4
|
+
data.tar.gz: 916fabb4a5328e93bcdcb8121b54aa3e958b87915e9b1c9027cccb44941837b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc4cd60e38d6e229d5d28ab6e28db3a16f7ddf1ffde53e3f5a97cacebe607158604421016bab34fa5bf96659ab4d0074fffb0f51712e4429d5529f59bbcdec0d
|
7
|
+
data.tar.gz: db9905c1c839a4135fe4c1156b3991f8cad5ac438b5c70091be34e8afee7563371e19afe45cd835cec2f83dd26fc92e5855bf7c53c6ee473728b80caabb3e5e1
|
data/.github/FUNDING.yml
CHANGED
@@ -1 +1 @@
|
|
1
|
-
github:
|
1
|
+
github: noteflakes
|
data/.yardopts
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
# 1.27 2023-06-12
|
2
|
+
|
3
|
+
- Fix execution of prepared statements in Sequel adapter (#23 @gschlager)
|
4
|
+
- Update bundled sqlite code to version 3.42.0 (#22 @gschlager)
|
5
|
+
|
6
|
+
# 1.26 2023-05-17
|
7
|
+
|
8
|
+
- Improve documentation
|
9
|
+
|
1
10
|
# 1.25 2023-03-10
|
2
11
|
|
3
12
|
- Remove bundled sqlite3 source files from extralite.gemspec
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -14,7 +14,7 @@ with an SQLite3 database, as well as prepared statements.
|
|
14
14
|
Extralite comes in two flavors: the `extralite` gem which uses the
|
15
15
|
system-installed sqlite3 library, and the `extralite-bundle` gem which bundles
|
16
16
|
the latest version of SQLite
|
17
|
-
([3.
|
17
|
+
([3.42.0](https://sqlite.org/releaselog/3_42_0.html)), offering access to the
|
18
18
|
latest features and enhancements.
|
19
19
|
|
20
20
|
## Features
|
data/ext/extralite/extconf.rb
CHANGED
data/lib/extralite/version.rb
CHANGED
data/lib/extralite.rb
CHANGED
@@ -7,22 +7,28 @@
|
|
7
7
|
require 'extralite'
|
8
8
|
require 'sequel/adapters/shared/sqlite'
|
9
9
|
|
10
|
+
# @!visibility private
|
10
11
|
module Sequel
|
12
|
+
# Extralite Sequel adapter
|
11
13
|
module Extralite
|
14
|
+
# @!visibility private
|
12
15
|
FALSE_VALUES = (%w'0 false f no n'.each(&:freeze) + [0]).freeze
|
13
16
|
|
14
17
|
blob = Object.new
|
18
|
+
# @!visibility private
|
15
19
|
def blob.call(s)
|
16
20
|
Sequel::SQL::Blob.new(s.to_s)
|
17
21
|
end
|
18
22
|
|
19
23
|
boolean = Object.new
|
24
|
+
# @!visibility private
|
20
25
|
def boolean.call(s)
|
21
26
|
s = s.downcase if s.is_a?(String)
|
22
27
|
!FALSE_VALUES.include?(s)
|
23
28
|
end
|
24
29
|
|
25
30
|
date = Object.new
|
31
|
+
# @!visibility private
|
26
32
|
def date.call(s)
|
27
33
|
case s
|
28
34
|
when String
|
@@ -37,22 +43,26 @@ module Sequel
|
|
37
43
|
end
|
38
44
|
|
39
45
|
integer = Object.new
|
46
|
+
# @!visibility private
|
40
47
|
def integer.call(s)
|
41
48
|
s.to_i
|
42
49
|
end
|
43
50
|
|
44
51
|
float = Object.new
|
52
|
+
# @!visibility private
|
45
53
|
def float.call(s)
|
46
54
|
s.to_f
|
47
55
|
end
|
48
56
|
|
49
57
|
numeric = Object.new
|
58
|
+
# @!visibility private
|
50
59
|
def numeric.call(s)
|
51
60
|
s = s.to_s unless s.is_a?(String)
|
52
61
|
BigDecimal(s) rescue s
|
53
62
|
end
|
54
63
|
|
55
64
|
time = Object.new
|
65
|
+
# @!visibility private
|
56
66
|
def time.call(s)
|
57
67
|
case s
|
58
68
|
when String
|
@@ -82,19 +92,21 @@ module Sequel
|
|
82
92
|
end
|
83
93
|
SQLITE_TYPES.freeze
|
84
94
|
|
95
|
+
# @!visibility private
|
85
96
|
USE_EXTENDED_RESULT_CODES = false
|
86
|
-
|
97
|
+
|
98
|
+
# Database adapter for Sequel
|
87
99
|
class Database < Sequel::Database
|
88
100
|
include ::Sequel::SQLite::DatabaseMethods
|
89
|
-
|
101
|
+
|
90
102
|
set_adapter_scheme :extralite
|
91
|
-
|
103
|
+
|
92
104
|
# Mimic the file:// uri, by having 2 preceding slashes specify a relative
|
93
105
|
# path, and 3 preceding slashes specify an absolute path.
|
94
106
|
def self.uri_to_options(uri) # :nodoc:
|
95
107
|
{ :database => (uri.host.nil? && uri.path == '/') ? nil : "#{uri.host}#{uri.path}" }
|
96
108
|
end
|
97
|
-
|
109
|
+
|
98
110
|
private_class_method :uri_to_options
|
99
111
|
|
100
112
|
# The conversion procs to use for this database
|
@@ -119,14 +131,14 @@ module Sequel
|
|
119
131
|
# if USE_EXTENDED_RESULT_CODES
|
120
132
|
# db.extended_result_codes = true
|
121
133
|
# end
|
122
|
-
|
134
|
+
|
123
135
|
connection_pragmas.each{|s| log_connection_yield(s, db){db.query(s)}}
|
124
|
-
|
136
|
+
|
125
137
|
class << db
|
126
138
|
attr_reader :prepared_statements
|
127
139
|
end
|
128
140
|
db.instance_variable_set(:@prepared_statements, {})
|
129
|
-
|
141
|
+
|
130
142
|
db
|
131
143
|
end
|
132
144
|
|
@@ -135,7 +147,7 @@ module Sequel
|
|
135
147
|
c.prepared_statements.each_value{|v| v.first.close }
|
136
148
|
c.close
|
137
149
|
end
|
138
|
-
|
150
|
+
|
139
151
|
# Run the given SQL with the given arguments and yield each row.
|
140
152
|
def execute(sql, opts=OPTS, &block)
|
141
153
|
_execute(:select, sql, opts, &block)
|
@@ -145,7 +157,7 @@ module Sequel
|
|
145
157
|
def execute_dui(sql, opts=OPTS)
|
146
158
|
_execute(:update, sql, opts)
|
147
159
|
end
|
148
|
-
|
160
|
+
|
149
161
|
# Drop any prepared statements on the connection when executing DDL. This is because
|
150
162
|
# prepared statements lock the table in such a way that you can't drop or alter the
|
151
163
|
# table while a prepared statement that references it still exists.
|
@@ -156,11 +168,13 @@ module Sequel
|
|
156
168
|
super
|
157
169
|
end
|
158
170
|
end
|
159
|
-
|
171
|
+
|
172
|
+
# @!visibility private
|
160
173
|
def execute_insert(sql, opts=OPTS)
|
161
174
|
_execute(:insert, sql, opts)
|
162
175
|
end
|
163
|
-
|
176
|
+
|
177
|
+
# @!visibility private
|
164
178
|
def freeze
|
165
179
|
@conversion_procs.freeze
|
166
180
|
super
|
@@ -181,13 +195,13 @@ module Sequel
|
|
181
195
|
end
|
182
196
|
|
183
197
|
private
|
184
|
-
|
198
|
+
|
185
199
|
def adapter_initialize
|
186
200
|
@conversion_procs = SQLITE_TYPES.dup
|
187
201
|
@conversion_procs['datetime'] = @conversion_procs['timestamp'] = method(:to_application_timestamp)
|
188
202
|
set_integer_booleans
|
189
203
|
end
|
190
|
-
|
204
|
+
|
191
205
|
# Yield an available connection. Rescue any Extralite::Error and turn
|
192
206
|
# them into DatabaseErrors.
|
193
207
|
def _execute(type, sql, opts, &block)
|
@@ -212,7 +226,7 @@ module Sequel
|
|
212
226
|
raise_error(e)
|
213
227
|
end
|
214
228
|
end
|
215
|
-
|
229
|
+
|
216
230
|
# The SQLite adapter does not need the pool to convert exceptions.
|
217
231
|
# Also, force the max connections to 1 if a memory database is being
|
218
232
|
# used, as otherwise each connection gets a separate database.
|
@@ -223,7 +237,7 @@ module Sequel
|
|
223
237
|
o[:max_connections] = 1 if @opts[:database] == ':memory:' || blank_object?(@opts[:database])
|
224
238
|
o
|
225
239
|
end
|
226
|
-
|
240
|
+
|
227
241
|
def prepared_statement_argument(arg)
|
228
242
|
case arg
|
229
243
|
when Date, DateTime, Time
|
@@ -267,9 +281,9 @@ module Sequel
|
|
267
281
|
log_sql << ")"
|
268
282
|
end
|
269
283
|
if block
|
270
|
-
log_connection_yield(log_sql, conn, args){cps.
|
284
|
+
log_connection_yield(log_sql, conn, args){cps.query(ps_args, &block)}
|
271
285
|
else
|
272
|
-
log_connection_yield(log_sql, conn, args){cps.
|
286
|
+
log_connection_yield(log_sql, conn, args){cps.query(ps_args){|r|}}
|
273
287
|
case type
|
274
288
|
when :insert
|
275
289
|
conn.last_insert_rowid
|
@@ -278,7 +292,7 @@ module Sequel
|
|
278
292
|
end
|
279
293
|
end
|
280
294
|
end
|
281
|
-
|
295
|
+
|
282
296
|
# # SQLite3 raises ArgumentError in addition to SQLite3::Exception in
|
283
297
|
# # some cases, such as operations on a closed database.
|
284
298
|
def database_error_classes
|
@@ -297,15 +311,17 @@ module Sequel
|
|
297
311
|
end
|
298
312
|
end
|
299
313
|
end
|
300
|
-
|
314
|
+
|
315
|
+
# Dataset adapter for Sequel
|
301
316
|
class Dataset < Sequel::Dataset
|
302
317
|
include ::Sequel::SQLite::DatasetMethods
|
303
318
|
|
319
|
+
# @!visibility private
|
304
320
|
module ArgumentMapper
|
305
321
|
include Sequel::Dataset::ArgumentMapper
|
306
|
-
|
322
|
+
|
307
323
|
protected
|
308
|
-
|
324
|
+
|
309
325
|
# Return a hash with the same values as the given hash,
|
310
326
|
# but with the keys converted to strings.
|
311
327
|
def map_to_prepared_args(hash)
|
@@ -313,19 +329,22 @@ module Sequel
|
|
313
329
|
hash.each{|k,v| args[k.to_s.gsub('.', '__')] = v}
|
314
330
|
args
|
315
331
|
end
|
316
|
-
|
332
|
+
|
317
333
|
private
|
318
|
-
|
334
|
+
|
319
335
|
# SQLite uses a : before the name of the argument for named
|
320
336
|
# arguments.
|
321
337
|
def prepared_arg(k)
|
322
338
|
LiteralString.new("#{prepared_arg_placeholder}#{k.to_s.gsub('.', '__')}")
|
323
339
|
end
|
324
340
|
end
|
325
|
-
|
341
|
+
|
342
|
+
# @!visibility private
|
326
343
|
BindArgumentMethods = prepared_statements_module(:bind, ArgumentMapper)
|
344
|
+
# @!visibility private
|
327
345
|
PreparedStatementMethods = prepared_statements_module(:prepare, BindArgumentMethods)
|
328
346
|
|
347
|
+
# @!visibility private
|
329
348
|
def fetch_rows(sql, &block)
|
330
349
|
execute(sql, &block)
|
331
350
|
# execute(sql) do |result|
|
@@ -350,9 +369,9 @@ module Sequel
|
|
350
369
|
# end
|
351
370
|
# end
|
352
371
|
end
|
353
|
-
|
372
|
+
|
354
373
|
private
|
355
|
-
|
374
|
+
|
356
375
|
# The base type name for a given type, without any parenthetical part.
|
357
376
|
def base_type_name(t)
|
358
377
|
(t =~ /^(.*?)\(/ ? $1 : t).downcase if t
|
data/test/test_sequel.rb
CHANGED
@@ -4,21 +4,43 @@ require_relative 'helper'
|
|
4
4
|
require 'sequel'
|
5
5
|
|
6
6
|
class SequelExtraliteTest < MiniTest::Test
|
7
|
-
def
|
8
|
-
db = Sequel.connect('extralite::memory:')
|
9
|
-
db.create_table :items do
|
7
|
+
def setup
|
8
|
+
@db = Sequel.connect('extralite::memory:')
|
9
|
+
@db.create_table :items do
|
10
10
|
primary_key :id
|
11
11
|
String :name, unique: true, null: false
|
12
12
|
Float :price, null: false
|
13
13
|
end
|
14
14
|
|
15
|
-
items = db[:items]
|
16
|
-
|
15
|
+
items = @db[:items]
|
17
16
|
items.insert(name: 'abc', price: 123)
|
18
17
|
items.insert(name: 'def', price: 456)
|
19
18
|
items.insert(name: 'ghi', price: 789)
|
19
|
+
end
|
20
|
+
|
21
|
+
def teardown
|
22
|
+
@db.disconnect
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_sequel
|
26
|
+
items = @db[:items]
|
20
27
|
|
21
28
|
assert_equal 3, items.count
|
22
29
|
assert_equal (123+456+789) / 3, items.avg(:price)
|
23
30
|
end
|
31
|
+
|
32
|
+
def test_prepared_statement
|
33
|
+
items = @db[:items]
|
34
|
+
prepared_query = items.where(name: :$name).prepare(:select, :select_by_name)
|
35
|
+
prepared_insert = items.prepare(:insert, :insert_with_name_and_price, name: :$name, price: :$price)
|
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 }]
|
39
|
+
|
40
|
+
id = prepared_insert.call(name: 'jkl', price: 444)
|
41
|
+
assert_equal items[id: id], { id: id, name: 'jkl', price: 444 }
|
42
|
+
|
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 }
|
45
|
+
end
|
24
46
|
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.27'
|
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-
|
11
|
+
date: 2023-06-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -91,6 +91,7 @@ files:
|
|
91
91
|
- ".github/FUNDING.yml"
|
92
92
|
- ".github/workflows/test.yml"
|
93
93
|
- ".gitignore"
|
94
|
+
- ".yardopts"
|
94
95
|
- CHANGELOG.md
|
95
96
|
- Gemfile
|
96
97
|
- Gemfile.lock
|