extralite 1.14 → 1.15

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32105cda1ba5871c89609e42828a095d76d4cd2da29bd6d47beefc6a3ae93bd6
4
- data.tar.gz: 4ff38c0e6144b22792e2a57792f295fc85a6b3d4b9eb09820e4f3b3e4c78bec1
3
+ metadata.gz: 0275df0298c578e4b166e392a43e7edcc4566d08eccdfe8c76ef0fd4e2a0c244
4
+ data.tar.gz: 312f5218786eaeaa879703c403ace437b351f76fe1fd5660d3d64fe6592f1c8a
5
5
  SHA512:
6
- metadata.gz: c0e94553b7ca02732fe93729844ef16ce58bce7582be1e9c1684f215999b7a4a84414265c6a6932fbc379887940bd70d8ff913c782b0ce6b1ee0eebd9f4438a0
7
- data.tar.gz: 14db1538d2aafb781375d636cdcb9a42e92a74ce11304a953930f7456c76895051f8a37e61cf5dfff7b8dc3c4e02694187fd0ad6a8204ca0d948ec1fe3b26479
6
+ metadata.gz: 8b2052fc2ca18c5d1e61c5ada2a094a1ef5e56053ab8434b8fbb55da35bd2633dcae0131b383caf0b7a9f2990a05205d8788a72ae98ce79b69854f8b517e4c6e
7
+ data.tar.gz: cff930e31e7f6d0050f2467c2661fa8369ba259bdaf9359154da1ba9ba5dc67ca3c6f327a34dbac73f0edf3d145962c2e973e12bee9c2f323a07612c5b984c03
@@ -7,8 +7,8 @@ jobs:
7
7
  strategy:
8
8
  fail-fast: false
9
9
  matrix:
10
- os: [ubuntu-latest, macos-10.15]
11
- ruby: [2.7, 3.0, 3.1, truffleruby]
10
+ os: [ubuntu-latest, macos-latest]
11
+ ruby: ['2.7', '3.0', '3.1', truffleruby]
12
12
 
13
13
  name: >-
14
14
  ${{matrix.os}}, ${{matrix.ruby}}
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 1.15 2022-10-01
2
+
3
+ - Add `Database#pragma` method
4
+ - Add `Database#tables` method
5
+
1
6
  ## 1.14 2022-02-28
2
7
 
3
8
  - Introduce `extralite-bundle` gem for bundling SQLite, use system lib by
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- extralite (1.14)
4
+ extralite (1.15)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -38,6 +38,8 @@ latest features and enhancements.
38
38
  - A variety of methods for different data access patterns: rows as hashes, rows
39
39
  as arrays, single row, single column, single value.
40
40
  - Prepared statements.
41
+ - Use system-installed sqlite3, or the [bundled latest version of
42
+ SQLite3](#installing-the-extralite-sqlite3-bundle).
41
43
  - Super fast - [up to 12.5x faster](#performance) than the
42
44
  [sqlite3](https://github.com/sparklemotion/sqlite3-ruby) gem (see also
43
45
  [comparison](#why-not-just-use-the-sqlite3-gem).)
@@ -63,7 +65,7 @@ gem 'extralite'
63
65
 
64
66
  You can also run `gem install extralite` if you just want to check it out.
65
67
 
66
- ## Installing the Extralite-SQLite3 bundle
68
+ ### Installing the Extralite-SQLite3 bundle
67
69
 
68
70
  If you don't have sqlite3 installed on your system, do not want to use the
69
71
  system-installed version of SQLite3, or would like to use the latest version of
@@ -136,6 +138,14 @@ number_of_rows_affected = db.changes
136
138
  # get db filename
137
139
  db.filename #=> "/tmp/my.db"
138
140
 
141
+ # get list of tables
142
+ db.tables #=> ['foo', 'bar']
143
+
144
+ # get and set pragmas
145
+ db.pragma(:journal_mode) #=> 'delete'
146
+ db.pragma(journal_mode: 'wal')
147
+ db.pragma(:journal_mode) #=> 'wal'
148
+
139
149
  # load an extension
140
150
  db.load_extension('/path/to/extension.so')
141
151
 
@@ -175,7 +185,7 @@ Here's a table summarizing the differences between the two gems:
175
185
 
176
186
  | |sqlite3-ruby|Extralite|
177
187
  |-|-|-|
178
- |SQLite3 dependency|depends on OS-installed libsqlite3|bundles latest version of SQLite3|
188
+ |SQLite3 dependency|depends on OS-installed libsqlite3|Use either system sqlite3 or [bundled latest version of SQLite3](#installing-the-extralite-sqlite3-bundle)|
179
189
  |API design|multiple classes|single class|
180
190
  |Query results|row as hash, row as array, single row, single value|row as hash, row as array, __single column__, single row, single value|
181
191
  |Execute multiple statements|separate API (#execute_batch)|integrated|
data/Rakefile CHANGED
@@ -24,3 +24,23 @@ YARD::Rake::YardocTask.new do |t|
24
24
  t.files = YARD_FILES
25
25
  t.options = %w(-o doc --readme README.md)
26
26
  end
27
+
28
+ task :release do
29
+ require_relative './lib/extralite/version'
30
+ version = Extralite::VERSION
31
+
32
+ puts 'Building extralite...'
33
+ `gem build extralite.gemspec`
34
+
35
+ puts 'Building extralite-bundle...'
36
+ `gem build extralite-bundle.gemspec`
37
+
38
+ puts "Pushing extralite #{version}..."
39
+ `gem push extralite-#{version}.gem`
40
+
41
+ puts "Pushing extralite-bundle #{version}..."
42
+ `gem push extralite-bundle-#{version}.gem`
43
+
44
+ puts "Cleaning up..."
45
+ `rm *.gem`
46
+ end
@@ -31,7 +31,7 @@ void bind_hash_parameter_values(sqlite3_stmt *stmt, VALUE hash) {
31
31
 
32
32
  switch (TYPE(k)) {
33
33
  case T_FIXNUM:
34
- bind_parameter_value(stmt, NUM2INT(k), v);
34
+ bind_parameter_value(stmt, FIX2INT(k), v);
35
35
  break;
36
36
  case T_SYMBOL:
37
37
  k = rb_funcall(k, ID_TO_S, 0);
@@ -345,3 +345,7 @@ VALUE safe_query_single_value(query_ctx *ctx) {
345
345
  RB_GC_GUARD(value);
346
346
  return value;
347
347
  }
348
+
349
+ VALUE safe_query_columns(query_ctx *ctx) {
350
+ return get_column_names(ctx->stmt, sqlite3_column_count(ctx->stmt));
351
+ }
@@ -263,6 +263,15 @@ VALUE Database_query_single_value(int argc, VALUE *argv, VALUE self) {
263
263
  return Database_perform_query(argc, argv, self, safe_query_single_value);
264
264
  }
265
265
 
266
+ /* call-seq:
267
+ * db.columns(sql) -> columns
268
+ *
269
+ * Returns the column names for the given query, without running it.
270
+ */
271
+ VALUE Database_columns(VALUE self, VALUE sql) {
272
+ return Database_perform_query(1, &sql, self, safe_query_columns);
273
+ }
274
+
266
275
  /* call-seq:
267
276
  * db.last_insert_rowid -> int
268
277
  *
@@ -272,7 +281,7 @@ VALUE Database_last_insert_rowid(VALUE self) {
272
281
  Database_t *db;
273
282
  GetOpenDatabase(self, db);
274
283
 
275
- return INT2NUM(sqlite3_last_insert_rowid(db->sqlite3_db));
284
+ return INT2FIX(sqlite3_last_insert_rowid(db->sqlite3_db));
276
285
  }
277
286
 
278
287
  /* call-seq:
@@ -284,7 +293,7 @@ VALUE Database_changes(VALUE self) {
284
293
  Database_t *db;
285
294
  GetOpenDatabase(self, db);
286
295
 
287
- return INT2NUM(sqlite3_changes(db->sqlite3_db));
296
+ return INT2FIX(sqlite3_changes(db->sqlite3_db));
288
297
  }
289
298
 
290
299
  /* call-seq:
@@ -362,6 +371,7 @@ void Init_ExtraliteDatabase() {
362
371
  rb_define_method(cDatabase, "query_single_row", Database_query_single_row, -1);
363
372
  rb_define_method(cDatabase, "query_single_column", Database_query_single_column, -1);
364
373
  rb_define_method(cDatabase, "query_single_value", Database_query_single_value, -1);
374
+ rb_define_method(cDatabase, "columns", Database_columns, 1);
365
375
 
366
376
  rb_define_method(cDatabase, "last_insert_rowid", Database_last_insert_rowid, 0);
367
377
  rb_define_method(cDatabase, "changes", Database_changes, 0);
@@ -53,6 +53,7 @@ VALUE safe_query_hash(query_ctx *ctx);
53
53
  VALUE safe_query_single_column(query_ctx *ctx);
54
54
  VALUE safe_query_single_row(query_ctx *ctx);
55
55
  VALUE safe_query_single_value(query_ctx *ctx);
56
+ VALUE safe_query_columns(query_ctx *ctx);
56
57
 
57
58
  void prepare_single_stmt(sqlite3 *db, sqlite3_stmt **stmt, VALUE sql);
58
59
  void prepare_multi_stmt(sqlite3 *db, sqlite3_stmt **stmt, VALUE sql);
@@ -63,6 +63,9 @@ static inline VALUE PreparedStatement_perform_query(int argc, VALUE *argv, VALUE
63
63
  PreparedStatement_t *stmt;
64
64
  GetPreparedStatement(self, stmt);
65
65
 
66
+ if (!stmt->stmt)
67
+ rb_raise(cError, "Prepared statement is closed");
68
+
66
69
  sqlite3_reset(stmt->stmt);
67
70
  sqlite3_clear_bindings(stmt->stmt);
68
71
  bind_all_parameters(stmt->stmt, argc, argv);
@@ -218,6 +221,43 @@ VALUE PreparedStatement_sql(VALUE self) {
218
221
  return stmt->sql;
219
222
  }
220
223
 
224
+ /* call-seq:
225
+ * stmt.columns -> columns
226
+ *
227
+ * Returns the column names for the prepared statement without running it.
228
+ */
229
+ VALUE PreparedStatement_columns(VALUE self) {
230
+ return PreparedStatement_perform_query(0, NULL, self, safe_query_columns);
231
+ }
232
+
233
+ /* call-seq:
234
+ * stmt.close -> stmt
235
+ *
236
+ * Closes the prepared statement. Running a closed prepared statement will raise
237
+ * an error.
238
+ */
239
+ VALUE PreparedStatement_close(VALUE self) {
240
+ PreparedStatement_t *stmt;
241
+ GetPreparedStatement(self, stmt);
242
+ if (stmt->stmt) {
243
+ sqlite3_finalize(stmt->stmt);
244
+ stmt->stmt = NULL;
245
+ }
246
+ return self;
247
+ }
248
+
249
+ /* call-seq:
250
+ * stmt.closed? -> closed
251
+ *
252
+ * Returns true if the prepared statement is closed.
253
+ */
254
+ VALUE PreparedStatement_closed_p(VALUE self) {
255
+ PreparedStatement_t *stmt;
256
+ GetPreparedStatement(self, stmt);
257
+
258
+ return stmt->stmt ? Qfalse : Qtrue;
259
+ }
260
+
221
261
  void Init_ExtralitePreparedStatement() {
222
262
  VALUE mExtralite = rb_define_module("Extralite");
223
263
 
@@ -235,4 +275,9 @@ void Init_ExtralitePreparedStatement() {
235
275
  rb_define_method(cPreparedStatement, "query_single_row", PreparedStatement_query_single_row, -1);
236
276
  rb_define_method(cPreparedStatement, "query_single_column", PreparedStatement_query_single_column, -1);
237
277
  rb_define_method(cPreparedStatement, "query_single_value", PreparedStatement_query_single_value, -1);
278
+
279
+ rb_define_method(cPreparedStatement, "columns", PreparedStatement_columns, 0);
280
+
281
+ rb_define_method(cPreparedStatement, "close", PreparedStatement_close, 0);
282
+ rb_define_method(cPreparedStatement, "closed?", PreparedStatement_closed_p, 0);
238
283
  }
@@ -1,3 +1,3 @@
1
1
  module Extralite
2
- VERSION = '1.14'
2
+ VERSION = '1.15'
3
3
  end
data/lib/extralite.rb CHANGED
@@ -17,5 +17,29 @@ module Extralite
17
17
 
18
18
  # An SQLite database
19
19
  class Database
20
+ alias_method :execute, :query
21
+
22
+ TABLES_SQL = <<~SQL
23
+ SELECT name FROM sqlite_schema
24
+ WHERE type ='table'
25
+ AND name NOT LIKE 'sqlite_%';
26
+ SQL
27
+
28
+ def tables
29
+ query_single_column(TABLES_SQL)
30
+ end
31
+
32
+ def pragma(value)
33
+ value.is_a?(Hash) ? pragma_set(value) : pragma_get(value)
34
+ end
35
+
36
+ def pragma_set(values)
37
+ sql = values.inject(+'') { |s, (k, v)| s += "pragma #{k}=#{v}; " }
38
+ query(sql)
39
+ end
40
+
41
+ def pragma_get(key)
42
+ query_single_value("pragma #{key}")
43
+ end
20
44
  end
21
- end
45
+ end
@@ -122,17 +122,17 @@ module Sequel
122
122
 
123
123
  connection_pragmas.each{|s| log_connection_yield(s, db){db.query(s)}}
124
124
 
125
- # class << db
126
- # attr_reader :prepared_statements
127
- # end
128
- # db.instance_variable_set(:@prepared_statements, {})
125
+ class << db
126
+ attr_reader :prepared_statements
127
+ end
128
+ db.instance_variable_set(:@prepared_statements, {})
129
129
 
130
130
  db
131
131
  end
132
132
 
133
133
  # Disconnect given connections from the database.
134
134
  def disconnect_connection(c)
135
- # c.prepared_statements.each_value{|v| v.first.close}
135
+ c.prepared_statements.each_value{|v| v.first.close }
136
136
  c.close
137
137
  end
138
138
 
@@ -149,13 +149,13 @@ module Sequel
149
149
  # Drop any prepared statements on the connection when executing DDL. This is because
150
150
  # prepared statements lock the table in such a way that you can't drop or alter the
151
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
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
159
 
160
160
  def execute_insert(sql, opts=OPTS)
161
161
  _execute(:insert, sql, opts)
@@ -193,7 +193,7 @@ module Sequel
193
193
  def _execute(type, sql, opts, &block)
194
194
  begin
195
195
  synchronize(opts[:server]) do |conn|
196
- # return execute_prepared_statement(conn, type, sql, opts, &block) if sql.is_a?(Symbol)
196
+ return execute_prepared_statement(conn, type, sql, opts, &block) if sql.is_a?(Symbol)
197
197
  log_args = opts[:arguments]
198
198
  args = {}
199
199
  opts.fetch(:arguments, OPTS).each{|k, v| args[k] = prepared_statement_argument(v) }
@@ -68,6 +68,11 @@ end
68
68
  assert_nil r
69
69
  end
70
70
 
71
+ def test_columns
72
+ r = @db.columns('select x, z from t')
73
+ assert_equal [:x, :z], r
74
+ end
75
+
71
76
  def test_transaction_active?
72
77
  assert_equal false, @db.transaction_active?
73
78
  @db.query('begin')
@@ -177,6 +182,31 @@ end
177
182
  r = @db.query_single_value("select reverse('abcd')")
178
183
  assert_equal 'dcba', r
179
184
  end
185
+
186
+ def test_tables
187
+ assert_equal ['t'], @db.tables
188
+
189
+ @db.query('create table foo (bar text)')
190
+ assert_equal ['t', 'foo'], @db.tables
191
+
192
+ @db.query('drop table t')
193
+ assert_equal ['foo'], @db.tables
194
+
195
+ @db.query('drop table foo')
196
+ assert_equal [], @db.tables
197
+ end
198
+
199
+ def test_pragma
200
+ assert_equal 'memory', @db.pragma('journal_mode')
201
+ assert_equal 2, @db.pragma('synchronous')
202
+
203
+ assert_equal 1, @db.pragma(:schema_version)
204
+ assert_equal 0, @db.pragma(:recursive_triggers)
205
+
206
+ assert_equal [], @db.pragma(schema_version: 33, recursive_triggers: 1)
207
+ assert_equal 33, @db.pragma(:schema_version)
208
+ assert_equal 1, @db.pragma(:recursive_triggers)
209
+ end
180
210
  end
181
211
 
182
212
  class ScenarioTest < MiniTest::Test
@@ -4,10 +4,6 @@ require_relative 'helper'
4
4
 
5
5
  class ExtraliteTest < MiniTest::Test
6
6
  def test_sqlite3_version
7
- reported = `sqlite3 --version` rescue ''
8
- match = reported.match(/^([\d\.]+)/)
9
- if match
10
- assert_equal match[1], Extralite.sqlite3_version
11
- end
7
+ assert_match /^3\.\d+\.\d+$/, Extralite.sqlite3_version
12
8
  end
13
9
  end
@@ -162,4 +162,23 @@ end
162
162
  r = @db.prepare('select null').query_single_value
163
163
  assert_nil r
164
164
  end
165
+
166
+ def test_prepared_statement_columns
167
+ r = @db.prepare("select 'abc' as a, 'def' as b").columns
168
+ assert_equal [:a, :b], r
169
+ end
170
+
171
+ def test_prepared_statement_close
172
+ p = @db.prepare("select 'abc'")
173
+
174
+ assert_equal false, p.closed?
175
+
176
+ p.close
177
+ assert_equal true, p.closed?
178
+
179
+ p.close
180
+ assert_equal true, p.closed?
181
+
182
+ assert_raises { p.query_single_value }
183
+ end
165
184
  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.14'
4
+ version: '1.15'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-28 00:00:00.000000000 Z
11
+ date: 2022-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -80,7 +80,7 @@ dependencies:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
82
  version: 5.51.0
83
- description:
83
+ description:
84
84
  email: sharon@noteflakes.com
85
85
  executables: []
86
86
  extensions:
@@ -134,7 +134,7 @@ metadata:
134
134
  documentation_uri: https://www.rubydoc.info/gems/extralite
135
135
  homepage_uri: https://github.com/digital-fabric/extralite
136
136
  changelog_uri: https://github.com/digital-fabric/extralite/blob/master/CHANGELOG.md
137
- post_install_message:
137
+ post_install_message:
138
138
  rdoc_options:
139
139
  - "--title"
140
140
  - extralite
@@ -153,8 +153,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
153
  - !ruby/object:Gem::Version
154
154
  version: '0'
155
155
  requirements: []
156
- rubygems_version: 3.3.3
157
- signing_key:
156
+ rubygems_version: 3.3.7
157
+ signing_key:
158
158
  specification_version: 4
159
159
  summary: Extra-lightweight SQLite3 wrapper for Ruby
160
160
  test_files: []