extralite-bundle 1.25 → 1.27
Sign up to get free protection for your applications and to get access to all the features.
- 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/ext/sqlite3/sqlite3.c +7506 -3493
- data/ext/sqlite3/sqlite3.h +304 -130
- 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
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-bundle
|
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
|