Compare commits

...

2 commits

Author SHA1 Message Date
Brian J. Cardiff
1f2a1cd3cb
Release 0.20.0 (#92) 2023-06-23 16:29:58 -03:00
Brian J. Cardiff
c08fc2befc
Update to crystal-db 0.12.0 (refactor connection factory) (#91)
* Refactor connection builder

* Update for ConnectionBuilder

* Update to crystal-db ~> 0.12.0

* run crystal tool format
2023-06-23 15:36:08 -03:00
7 changed files with 74 additions and 54 deletions

View file

@ -1,3 +1,9 @@
## v0.20.0 (2023-06-23)
* Update to crystal-db ~> 0.12.0. ([#91](https://github.com/crystal-lang/crystal-sqlite3/pull/91))
* Fix result set & connection release lifecycle. ([#90](https://github.com/crystal-lang/crystal-sqlite3/pull/90))
* Automatically set PRAGMAs using connection query params. ([#85](https://github.com/crystal-lang/crystal-sqlite3/pull/85), thanks @luislavena)
## v0.19.0 (2022-01-28) ## v0.19.0 (2022-01-28)
* Update to crystal-db ~> 0.11.0. ([#77](https://github.com/crystal-lang/crystal-sqlite3/pull/77)) * Update to crystal-db ~> 0.11.0. ([#77](https://github.com/crystal-lang/crystal-sqlite3/pull/77))

View file

@ -1,14 +1,14 @@
name: sqlite3 name: sqlite3
version: 0.19.0 version: 0.20.0
dependencies: dependencies:
db: db:
github: crystal-lang/crystal-db github: crystal-lang/crystal-db
version: ~> 0.11.0 version: ~> 0.12.0
authors: authors:
- Ary Borenszweig <aborenszweig@manas.tech> - Ary Borenszweig <aborenszweig@manas.tech>
- Brian J. Cardiff <bcardiff@manas.tech> - Brian J. Cardiff <bcardiff@gmail.com>
crystal: ">= 1.0.0, < 2.0.0" crystal: ">= 1.0.0, < 2.0.0"

View file

@ -13,7 +13,7 @@ private def cast_if_blob(expr, sql_type)
end end
end end
DB::DriverSpecs(DB::Any).run do DB::DriverSpecs(DB::Any).run do |ctx|
support_unprepared false support_unprepared false
before do before do
@ -104,7 +104,7 @@ DB::DriverSpecs(DB::Any).run do
db.exec %(insert into a (i, str) values (23, "bai bai");) db.exec %(insert into a (i, str) values (23, "bai bai");)
2.times do |i| 2.times do |i|
DB.open db.uri do |db| DB.open ctx.connection_string do |db|
begin begin
db.query("SELECT i, str FROM a WHERE i = ?", 23) do |rs| db.query("SELECT i, str FROM a WHERE i = ?", 23) do |rs|
rs.move_next rs.move_next

View file

@ -27,7 +27,7 @@ describe Driver do
it "should use database option as file to open" do it "should use database option as file to open" do
with_db do |db| with_db do |db|
db.driver.should be_a(SQLite3::Driver) db.checkout.should be_a(SQLite3::Connection)
File.exists?(DB_FILENAME).should be_true File.exists?(DB_FILENAME).should be_true
end end
end end

View file

@ -1,12 +1,56 @@
class SQLite3::Connection < DB::Connection class SQLite3::Connection < DB::Connection
def initialize(database) record Options,
super filename : String = ":memory:",
filename = self.class.filename(database.uri) # pragmas
check LibSQLite3.open_v2(filename, out @db, (Flag::READWRITE | Flag::CREATE), nil) busy_timeout : String? = nil,
cache_size : String? = nil,
foreign_keys : String? = nil,
journal_mode : String? = nil,
synchronous : String? = nil,
wal_autocheckpoint : String? = nil do
def self.from_uri(uri : URI, default = Options.new)
params = HTTP::Params.parse(uri.query || "")
Options.new(
filename: URI.decode_www_form((uri.host || "") + uri.path),
# pragmas
busy_timeout: params.fetch("busy_timeout", default.busy_timeout),
cache_size: params.fetch("cache_size", default.cache_size),
foreign_keys: params.fetch("foreign_keys", default.foreign_keys),
journal_mode: params.fetch("journal_mode", default.journal_mode),
synchronous: params.fetch("synchronous", default.synchronous),
wal_autocheckpoint: params.fetch("wal_autocheckpoint", default.wal_autocheckpoint),
)
end
def pragma_statement
res = String.build do |str|
pragma_append(str, "busy_timeout", busy_timeout)
pragma_append(str, "cache_size", cache_size)
pragma_append(str, "foreign_keys", foreign_keys)
pragma_append(str, "journal_mode", journal_mode)
pragma_append(str, "synchronous", synchronous)
pragma_append(str, "wal_autocheckpoint", wal_autocheckpoint)
end
res.empty? ? nil : res
end
private def pragma_append(io, key, value)
return unless value
io << "PRAGMA #{key}=#{value};"
end
end
def initialize(options : ::DB::Connection::Options, sqlite3_options : Options)
super(options)
check LibSQLite3.open_v2(sqlite3_options.filename, out @db, (Flag::READWRITE | Flag::CREATE), nil)
# 2 means 2 arguments; 1 is the code for UTF-8 # 2 means 2 arguments; 1 is the code for UTF-8
check LibSQLite3.create_function(@db, "regexp", 2, 1, nil, SQLite3::REGEXP_FN, nil, nil) check LibSQLite3.create_function(@db, "regexp", 2, 1, nil, SQLite3::REGEXP_FN, nil, nil)
process_query_params(database.uri) if pragma_statement = sqlite3_options.pragma_statement
check LibSQLite3.exec(@db, pragma_statement, nil, nil, nil)
end
rescue rescue
raise DB::ConnectionRefused.new raise DB::ConnectionRefused.new
end end
@ -89,44 +133,4 @@ class SQLite3::Connection < DB::Connection
private def check(code) private def check(code)
raise Exception.new(self) unless code == 0 raise Exception.new(self) unless code == 0
end end
private def process_query_params(uri : URI)
return unless query = uri.query
detected_pragmas = extract_params(query,
busy_timeout: nil,
cache_size: nil,
foreign_keys: nil,
journal_mode: nil,
synchronous: nil,
wal_autocheckpoint: nil,
)
# concatenate all into a single SQL string
sql = String.build do |str|
detected_pragmas.each do |key, value|
next unless value
str << "PRAGMA #{key}=#{value};"
end
end
check LibSQLite3.exec(@db, sql, nil, nil, nil)
end
private def extract_params(query : String, **default : **T) forall T
res = default
URI::Params.parse(query) do |key, value|
{% begin %}
case key
{% for key in T %}
when {{ key.stringify }}
res = res.merge({{key.id}}: value)
{% end %}
end
{% end %}
end
res
end
end end

View file

@ -1,6 +1,16 @@
class SQLite3::Driver < DB::Driver class SQLite3::Driver < DB::Driver
def build_connection(context : DB::ConnectionContext) : SQLite3::Connection class ConnectionBuilder < ::DB::ConnectionBuilder
SQLite3::Connection.new(context) def initialize(@options : ::DB::Connection::Options, @sqlite3_options : SQLite3::Connection::Options)
end
def build : ::DB::Connection
SQLite3::Connection.new(@options, @sqlite3_options)
end
end
def connection_builder(uri : URI) : ::DB::ConnectionBuilder
params = HTTP::Params.parse(uri.query || "")
ConnectionBuilder.new(connection_options(params), SQLite3::Connection::Options.from_uri(uri))
end end
end end

View file

@ -1,3 +1,3 @@
module SQLite3 module SQLite3
VERSION = "0.19.0" VERSION = "0.20.0"
end end