extralite 1.4 → 1.8.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,380 @@
1
+ # frozen-string-literal: true
2
+
3
+ # This file was adapted from the SQLite adapter included in Sequel:
4
+ # https://github.com/jeremyevans/sequel
5
+ # (distributed under the MIT license)
6
+
7
+ require 'extralite'
8
+ require 'sequel/adapters/shared/sqlite'
9
+
10
+ module Sequel
11
+ module Extralite
12
+ FALSE_VALUES = (%w'0 false f no n'.each(&:freeze) + [0]).freeze
13
+
14
+ blob = Object.new
15
+ def blob.call(s)
16
+ Sequel::SQL::Blob.new(s.to_s)
17
+ end
18
+
19
+ boolean = Object.new
20
+ def boolean.call(s)
21
+ s = s.downcase if s.is_a?(String)
22
+ !FALSE_VALUES.include?(s)
23
+ end
24
+
25
+ date = Object.new
26
+ def date.call(s)
27
+ case s
28
+ when String
29
+ Sequel.string_to_date(s)
30
+ when Integer
31
+ Date.jd(s)
32
+ when Float
33
+ Date.jd(s.to_i)
34
+ else
35
+ raise Sequel::Error, "unhandled type when converting to date: #{s.inspect} (#{s.class.inspect})"
36
+ end
37
+ end
38
+
39
+ integer = Object.new
40
+ def integer.call(s)
41
+ s.to_i
42
+ end
43
+
44
+ float = Object.new
45
+ def float.call(s)
46
+ s.to_f
47
+ end
48
+
49
+ numeric = Object.new
50
+ def numeric.call(s)
51
+ s = s.to_s unless s.is_a?(String)
52
+ BigDecimal(s) rescue s
53
+ end
54
+
55
+ time = Object.new
56
+ def time.call(s)
57
+ case s
58
+ when String
59
+ Sequel.string_to_time(s)
60
+ when Integer
61
+ Sequel::SQLTime.create(s/3600, (s % 3600)/60, s % 60)
62
+ when Float
63
+ s, f = s.divmod(1)
64
+ Sequel::SQLTime.create(s/3600, (s % 3600)/60, s % 60, (f*1000000).round)
65
+ else
66
+ raise Sequel::Error, "unhandled type when converting to date: #{s.inspect} (#{s.class.inspect})"
67
+ end
68
+ end
69
+
70
+ # Hash with string keys and callable values for converting SQLite types.
71
+ SQLITE_TYPES = {}
72
+ {
73
+ %w'date' => date,
74
+ %w'time' => time,
75
+ %w'bit bool boolean' => boolean,
76
+ %w'integer smallint mediumint int bigint' => integer,
77
+ %w'numeric decimal money' => numeric,
78
+ %w'float double real dec fixed' + ['double precision'] => float,
79
+ %w'blob' => blob
80
+ }.each do |k,v|
81
+ k.each{|n| SQLITE_TYPES[n] = v}
82
+ end
83
+ SQLITE_TYPES.freeze
84
+
85
+ USE_EXTENDED_RESULT_CODES = false
86
+
87
+ class Database < Sequel::Database
88
+ include ::Sequel::SQLite::DatabaseMethods
89
+
90
+ set_adapter_scheme :extralite
91
+
92
+ # Mimic the file:// uri, by having 2 preceding slashes specify a relative
93
+ # path, and 3 preceding slashes specify an absolute path.
94
+ def self.uri_to_options(uri) # :nodoc:
95
+ { :database => (uri.host.nil? && uri.path == '/') ? nil : "#{uri.host}#{uri.path}" }
96
+ end
97
+
98
+ private_class_method :uri_to_options
99
+
100
+ # The conversion procs to use for this database
101
+ attr_reader :conversion_procs
102
+
103
+ # Connect to the database. Since SQLite is a file based database,
104
+ # available options are limited:
105
+ #
106
+ # :database :: database name (filename or ':memory:' or file: URI)
107
+ # :readonly :: open database in read-only mode; useful for reading
108
+ # static data that you do not want to modify
109
+ # :timeout :: how long to wait for the database to be available if it
110
+ # is locked, given in milliseconds (default is 5000)
111
+ def connect(server)
112
+ opts = server_opts(server)
113
+ opts[:database] = ':memory:' if blank_object?(opts[:database])
114
+ # sqlite3_opts = {}
115
+ # sqlite3_opts[:readonly] = typecast_value_boolean(opts[:readonly]) if opts.has_key?(:readonly)
116
+ db = ::Extralite::Database.new(opts[:database].to_s)#, sqlite3_opts)
117
+ # db.busy_timeout(typecast_value_integer(opts.fetch(:timeout, 5000)))
118
+
119
+ # if USE_EXTENDED_RESULT_CODES
120
+ # db.extended_result_codes = true
121
+ # end
122
+
123
+ connection_pragmas.each{|s| log_connection_yield(s, db){db.query(s)}}
124
+
125
+ # class << db
126
+ # attr_reader :prepared_statements
127
+ # end
128
+ # db.instance_variable_set(:@prepared_statements, {})
129
+
130
+ db
131
+ end
132
+
133
+ # Disconnect given connections from the database.
134
+ def disconnect_connection(c)
135
+ # c.prepared_statements.each_value{|v| v.first.close}
136
+ c.close
137
+ end
138
+
139
+ # Run the given SQL with the given arguments and yield each row.
140
+ def execute(sql, opts=OPTS, &block)
141
+ _execute(:select, sql, opts, &block)
142
+ end
143
+
144
+ # Run the given SQL with the given arguments and return the number of changed rows.
145
+ def execute_dui(sql, opts=OPTS)
146
+ _execute(:update, sql, opts)
147
+ end
148
+
149
+ # Drop any prepared statements on the connection when executing DDL. This is because
150
+ # prepared statements lock the table in such a way that you can't drop or alter the
151
+ # table while a prepared statement that references it still exists.
152
+ # def execute_ddl(sql, opts=OPTS)
153
+ # synchronize(opts[:server]) do |conn|
154
+ # conn.prepared_statements.values.each{|cps, s| cps.close}
155
+ # conn.prepared_statements.clear
156
+ # super
157
+ # end
158
+ # end
159
+
160
+ def execute_insert(sql, opts=OPTS)
161
+ _execute(:insert, sql, opts)
162
+ end
163
+
164
+ def freeze
165
+ @conversion_procs.freeze
166
+ super
167
+ end
168
+
169
+ # Handle Integer and Float arguments, since SQLite can store timestamps as integers and floats.
170
+ def to_application_timestamp(s)
171
+ case s
172
+ when String
173
+ super
174
+ when Integer
175
+ super(Time.at(s).to_s)
176
+ when Float
177
+ super(DateTime.jd(s).to_s)
178
+ else
179
+ raise Sequel::Error, "unhandled type when converting to : #{s.inspect} (#{s.class.inspect})"
180
+ end
181
+ end
182
+
183
+ private
184
+
185
+ def adapter_initialize
186
+ @conversion_procs = SQLITE_TYPES.dup
187
+ @conversion_procs['datetime'] = @conversion_procs['timestamp'] = method(:to_application_timestamp)
188
+ set_integer_booleans
189
+ end
190
+
191
+ # Yield an available connection. Rescue any Extralite::Error and turn
192
+ # them into DatabaseErrors.
193
+ def _execute(type, sql, opts, &block)
194
+ begin
195
+ synchronize(opts[:server]) do |conn|
196
+ # return execute_prepared_statement(conn, type, sql, opts, &block) if sql.is_a?(Symbol)
197
+ log_args = opts[:arguments]
198
+ args = {}
199
+ opts.fetch(:arguments, OPTS).each{|k, v| args[k] = prepared_statement_argument(v) }
200
+ case type
201
+ when :select
202
+ log_connection_yield(sql, conn, log_args){conn.query(sql, args, &block)}
203
+ when :insert
204
+ log_connection_yield(sql, conn, log_args){conn.query(sql, args)}
205
+ conn.last_insert_rowid
206
+ when :update
207
+ log_connection_yield(sql, conn, log_args){conn.query(sql, args)}
208
+ conn.changes
209
+ end
210
+ end
211
+ rescue ::Extralite::Error => e
212
+ raise_error(e)
213
+ end
214
+ end
215
+
216
+ # The SQLite adapter does not need the pool to convert exceptions.
217
+ # Also, force the max connections to 1 if a memory database is being
218
+ # used, as otherwise each connection gets a separate database.
219
+ def connection_pool_default_options
220
+ o = super.dup
221
+ # Default to only a single connection if a memory database is used,
222
+ # because otherwise each connection will get a separate database
223
+ o[:max_connections] = 1 if @opts[:database] == ':memory:' || blank_object?(@opts[:database])
224
+ o
225
+ end
226
+
227
+ def prepared_statement_argument(arg)
228
+ case arg
229
+ when Date, DateTime, Time
230
+ literal(arg)[1...-1]
231
+ when SQL::Blob
232
+ arg.to_blob
233
+ when true, false
234
+ if integer_booleans
235
+ arg ? 1 : 0
236
+ else
237
+ literal(arg)[1...-1]
238
+ end
239
+ else
240
+ arg
241
+ end
242
+ end
243
+
244
+ # Execute a prepared statement on the database using the given name.
245
+ def execute_prepared_statement(conn, type, name, opts, &block)
246
+ ps = prepared_statement(name)
247
+ sql = ps.prepared_sql
248
+ args = opts[:arguments]
249
+ ps_args = {}
250
+ args.each{|k, v| ps_args[k] = prepared_statement_argument(v)}
251
+ if cpsa = conn.prepared_statements[name]
252
+ cps, cps_sql = cpsa
253
+ if cps_sql != sql
254
+ cps.close
255
+ cps = nil
256
+ end
257
+ end
258
+ unless cps
259
+ cps = log_connection_yield("PREPARE #{name}: #{sql}", conn){conn.prepare(sql)}
260
+ conn.prepared_statements[name] = [cps, sql]
261
+ end
262
+ log_sql = String.new
263
+ log_sql << "EXECUTE #{name}"
264
+ if ps.log_sql
265
+ log_sql << " ("
266
+ log_sql << sql
267
+ log_sql << ")"
268
+ end
269
+ if block
270
+ log_connection_yield(log_sql, conn, args){cps.execute(ps_args, &block)}
271
+ else
272
+ log_connection_yield(log_sql, conn, args){cps.execute!(ps_args){|r|}}
273
+ case type
274
+ when :insert
275
+ conn.last_insert_rowid
276
+ when :update
277
+ conn.changes
278
+ end
279
+ end
280
+ end
281
+
282
+ # # SQLite3 raises ArgumentError in addition to SQLite3::Exception in
283
+ # # some cases, such as operations on a closed database.
284
+ def database_error_classes
285
+ #[Extralite::Error, ArgumentError]
286
+ [::Extralite::Error]
287
+ end
288
+
289
+ def dataset_class_default
290
+ Dataset
291
+ end
292
+
293
+ if USE_EXTENDED_RESULT_CODES
294
+ # Support SQLite exception codes if ruby-sqlite3 supports them.
295
+ def sqlite_error_code(exception)
296
+ exception.code if exception.respond_to?(:code)
297
+ end
298
+ end
299
+ end
300
+
301
+ class Dataset < Sequel::Dataset
302
+ include ::Sequel::SQLite::DatasetMethods
303
+
304
+ module ArgumentMapper
305
+ include Sequel::Dataset::ArgumentMapper
306
+
307
+ protected
308
+
309
+ # Return a hash with the same values as the given hash,
310
+ # but with the keys converted to strings.
311
+ def map_to_prepared_args(hash)
312
+ args = {}
313
+ hash.each{|k,v| args[k.to_s.gsub('.', '__')] = v}
314
+ args
315
+ end
316
+
317
+ private
318
+
319
+ # SQLite uses a : before the name of the argument for named
320
+ # arguments.
321
+ def prepared_arg(k)
322
+ LiteralString.new("#{prepared_arg_placeholder}#{k.to_s.gsub('.', '__')}")
323
+ end
324
+ end
325
+
326
+ BindArgumentMethods = prepared_statements_module(:bind, ArgumentMapper)
327
+ PreparedStatementMethods = prepared_statements_module(:prepare, BindArgumentMethods)
328
+
329
+ def fetch_rows(sql, &block)
330
+ execute(sql, &block)
331
+ # execute(sql) do |result|
332
+ # cps = db.conversion_procs
333
+ # type_procs = result.types.map{|t| cps[base_type_name(t)]}
334
+ # j = -1
335
+ # cols = result.columns.map{|c| [output_identifier(c), type_procs[(j+=1)]]}
336
+ # self.columns = cols.map(&:first)
337
+ # max = cols.length
338
+ # result.each do |values|
339
+ # row = {}
340
+ # i = -1
341
+ # while (i += 1) < max
342
+ # name, type_proc = cols[i]
343
+ # v = values[i]
344
+ # if type_proc && v
345
+ # v = type_proc.call(v)
346
+ # end
347
+ # row[name] = v
348
+ # end
349
+ # yield row
350
+ # end
351
+ # end
352
+ end
353
+
354
+ private
355
+
356
+ # The base type name for a given type, without any parenthetical part.
357
+ def base_type_name(t)
358
+ (t =~ /^(.*?)\(/ ? $1 : t).downcase if t
359
+ end
360
+
361
+ # Quote the string using the adapter class method.
362
+ def literal_string_append(sql, v)
363
+ sql << "'" << v.gsub(/'/, "''") << "'"
364
+ end
365
+
366
+ def bound_variable_modules
367
+ [BindArgumentMethods]
368
+ end
369
+
370
+ def prepared_statement_modules
371
+ [PreparedStatementMethods]
372
+ end
373
+
374
+ # SQLite uses a : before the name of the argument as a placeholder.
375
+ def prepared_arg_placeholder
376
+ ':'
377
+ end
378
+ end
379
+ end
380
+ end
data/test/perf.rb ADDED
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+ gem 'sqlite3'
8
+ gem 'extralite', path: '..'
9
+ gem 'benchmark-ips'
10
+ end
11
+
12
+ require 'benchmark/ips'
13
+ require 'fileutils'
14
+
15
+ DB_PATH = '/tmp/extralite_sqlite3_perf.db'
16
+
17
+ def prepare_database(count)
18
+ FileUtils.rm(DB_PATH) rescue nil
19
+ db = Extralite::Database.new(DB_PATH)
20
+ db.query('create table foo ( a integer primary key, b text )')
21
+ db.query('begin')
22
+ count.times { db.query('insert into foo (b) values (?)', "hello#{rand(1000)}" )}
23
+ db.query('commit')
24
+ end
25
+
26
+ def sqlite3_run(count)
27
+ db = SQLite3::Database.new(DB_PATH, :results_as_hash => true)
28
+ results = db.execute('select * from foo')
29
+ raise unless results.size == count
30
+ end
31
+
32
+ def extralite_run(count)
33
+ db = Extralite::Database.new(DB_PATH)
34
+ results = db.query('select * from foo')
35
+ raise unless results.size == count
36
+ end
37
+
38
+ [10, 1000, 100000].each do |c|
39
+ puts; puts; puts "Record count: #{c}"
40
+
41
+ prepare_database(c)
42
+
43
+ Benchmark.ips do |x|
44
+ x.config(:time => 3, :warmup => 1)
45
+
46
+ x.report("sqlite3") { sqlite3_run(c) }
47
+ x.report("extralite") { extralite_run(c) }
48
+
49
+ x.compare!
50
+ end
51
+ end
data/test/run.rb ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir.glob("#{__dir__}/test_*.rb").each do |path|
4
+ require(path)
5
+ end
@@ -4,7 +4,7 @@ require_relative 'helper'
4
4
 
5
5
  class DatabaseTest < MiniTest::Test
6
6
  def setup
7
- @db = Extralite::Database.new('/tmp/extralite.db')
7
+ @db = Extralite::Database.new(':memory:')
8
8
  @db.query('create table if not exists t (x,y,z)')
9
9
  @db.query('delete from t')
10
10
  @db.query('insert into t values (1, 2, 3)')
@@ -55,7 +55,7 @@ class DatabaseTest < MiniTest::Test
55
55
  def test_query_single_column
56
56
  r = @db.query_single_column('select y from t')
57
57
  assert_equal [2, 5], r
58
-
58
+
59
59
  r = @db.query_single_column('select y from t where x = 2')
60
60
  assert_equal [], r
61
61
  end
@@ -82,6 +82,17 @@ end
82
82
  assert_equal [1, 4, 'a', 'd'], @db.query_single_column('select x from t order by x')
83
83
  end
84
84
 
85
+ def test_multiple_statements_with_error
86
+ error = nil
87
+ begin
88
+ @db.query("insert into t values foo; insert into t values ('d', 'e', 'f');")
89
+ rescue => error
90
+ end
91
+
92
+ assert_kind_of Extralite::SQLError, error
93
+ assert_equal 'near "foo": syntax error', error.message
94
+ end
95
+
85
96
  def test_empty_sql
86
97
  r = @db.query(' ')
87
98
  assert_nil r
@@ -97,7 +108,101 @@ end
97
108
 
98
109
  assert_equal @db, @db.close
99
110
  assert_equal true, @db.closed?
100
-
111
+
101
112
  assert_raises(Extralite::Error) { @db.query_single_value('select 42') }
102
113
  end
114
+
115
+ def test_parameter_binding_simple
116
+ r = @db.query('select x, y, z from t where x = ?', 1)
117
+ assert_equal [{ x: 1, y: 2, z: 3 }], r
118
+
119
+ r = @db.query('select x, y, z from t where z = ?', 6)
120
+ assert_equal [{ x: 4, y: 5, z: 6 }], r
121
+ end
122
+
123
+ def test_parameter_binding_with_index
124
+ r = @db.query('select x, y, z from t where x = ?2', 0, 1)
125
+ assert_equal [{ x: 1, y: 2, z: 3 }], r
126
+
127
+ r = @db.query('select x, y, z from t where z = ?3', 3, 4, 6)
128
+ assert_equal [{ x: 4, y: 5, z: 6 }], r
129
+ end
130
+
131
+ def test_parameter_binding_with_name
132
+ r = @db.query('select x, y, z from t where x = :x', x: 1, y: 2)
133
+ assert_equal [{ x: 1, y: 2, z: 3 }], r
134
+
135
+ r = @db.query('select x, y, z from t where z = :zzz', 'zzz' => 6)
136
+ assert_equal [{ x: 4, y: 5, z: 6 }], r
137
+
138
+ r = @db.query('select x, y, z from t where z = :bazzz', ':bazzz' => 6)
139
+ assert_equal [{ x: 4, y: 5, z: 6 }], r
140
+ end
141
+ end
142
+
143
+ class ScenarioTest < MiniTest::Test
144
+ def setup
145
+ @db = Extralite::Database.new('/tmp/extralite.db')
146
+ @db.query('create table if not exists t (x,y,z)')
147
+ @db.query('delete from t')
148
+ @db.query('insert into t values (1, 2, 3)')
149
+ @db.query('insert into t values (4, 5, 6)')
150
+ end
151
+
152
+ def test_concurrent_transactions
153
+ done = false
154
+ t = Thread.new do
155
+ db = Extralite::Database.new('/tmp/extralite.db')
156
+ db.query 'begin immediate'
157
+ sleep 0.01 until done
158
+
159
+ while true
160
+ begin
161
+ db.query 'commit'
162
+ break
163
+ rescue Extralite::BusyError
164
+ sleep 0.01
165
+ end
166
+ end
167
+ end
168
+
169
+ sleep 0.1
170
+ @db.query 'begin deferred'
171
+ result = @db.query_single_column('select x from t')
172
+ assert_equal [1, 4], result
173
+
174
+ assert_raises(Extralite::BusyError) do
175
+ @db.query('insert into t values (7, 8, 9)')
176
+ end
177
+
178
+ done = true
179
+ sleep 0.1
180
+
181
+ assert_raises(Extralite::BusyError) do
182
+ @db.query('insert into t values (7, 8, 9)')
183
+ end
184
+
185
+ assert_equal true, @db.transaction_active?
186
+
187
+ # the thing to do in this case is to commit the read transaction, allowing
188
+ # the other thread to commit its write transaction, and then we can
189
+ # "upgrade" to a write transaction
190
+
191
+ @db.query('commit')
192
+
193
+ while true
194
+ begin
195
+ @db.query('begin immediate')
196
+ break
197
+ rescue Extralite::BusyError
198
+ sleep 0.1
199
+ end
200
+ end
201
+
202
+ @db.query('insert into t values (7, 8, 9)')
203
+ @db.query('commit')
204
+
205
+ result = @db.query_single_column('select x from t')
206
+ assert_equal [1, 4, 7], result
207
+ end
103
208
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+ require 'sequel'
5
+
6
+ class SequelExtraliteTest < MiniTest::Test
7
+ def test_sequel
8
+ db = Sequel.connect('extralite::memory:')
9
+ db.create_table :items do
10
+ primary_key :id
11
+ String :name, unique: true, null: false
12
+ Float :price, null: false
13
+ end
14
+
15
+ items = db[:items]
16
+
17
+ items.insert(name: 'abc', price: 123)
18
+ items.insert(name: 'def', price: 456)
19
+ items.insert(name: 'ghi', price: 789)
20
+
21
+ assert_equal 3, items.count
22
+ assert_equal (123+456+789) / 3, items.avg(:price)
23
+ end
24
+ 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'
4
+ version: 1.8.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-08-25 00:00:00.000000000 Z
11
+ date: 2021-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 1.1.1
19
+ version: 1.1.6
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 1.1.1
26
+ version: 1.1.6
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: minitest
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 5.14.4
33
+ version: 5.15.0
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 5.14.4
40
+ version: 5.15.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: simplecov
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -53,33 +53,33 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: 0.17.1
55
55
  - !ruby/object:Gem::Dependency
56
- name: rubocop
56
+ name: yard
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: 0.85.1
61
+ version: 0.9.27
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: 0.85.1
68
+ version: 0.9.27
69
69
  - !ruby/object:Gem::Dependency
70
- name: pry
70
+ name: sequel
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 0.13.1
75
+ version: 5.51.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 0.13.1
82
+ version: 5.51.0
83
83
  description:
84
84
  email: sharon@noteflakes.com
85
85
  executables: []
@@ -103,14 +103,17 @@ files:
103
103
  - extralite.gemspec
104
104
  - lib/extralite.rb
105
105
  - lib/extralite/version.rb
106
+ - lib/sequel/adapters/extralite.rb
106
107
  - test/helper.rb
108
+ - test/perf.rb
109
+ - test/run.rb
107
110
  - test/test_database.rb
111
+ - test/test_sequel.rb
108
112
  homepage: https://github.com/digital-fabric/extralite
109
113
  licenses:
110
114
  - MIT
111
115
  metadata:
112
116
  source_code_uri: https://github.com/digital-fabric/extralite
113
- documentation_uri: https://github.com/digital-fabric/extralite
114
117
  homepage_uri: https://github.com/digital-fabric/extralite
115
118
  changelog_uri: https://github.com/digital-fabric/extralite/blob/master/CHANGELOG.md
116
119
  post_install_message: