From 6a73d4f64da9952cdfd662346c5cbfa55903e339 Mon Sep 17 00:00:00 2001 From: Luis Lavena Date: Sat, 11 Feb 2023 19:01:52 +0100 Subject: [PATCH] Simplify PRAGMA mapping and detection No longer prefix PRAGMAS with `_`, so the mapping between the real SQLite3 pragmas and the usage in the URI is more direct. Use macros instead of case to detect pragmas from URI params and return those as NamedTuple. --- README.md | 12 +++++----- spec/connection_spec.cr | 42 +++++++++++++++++------------------ src/sqlite3/connection.cr | 46 +++++++++++++++++++++++---------------- 3 files changed, 54 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 6086f06..99c9b41 100644 --- a/README.md +++ b/README.md @@ -67,12 +67,12 @@ The following is the list of supported options: | Name | Connection key | |---------------------------|-----------------| -| [Busy Timeout][pragma-to] | `_busy_timeout` | -| [Cache Size][pragma-cs] | `_cache_size` | -| [Foreign Keys][pragma-fk] | `_foreign_keys` | -| [Journal Mode][pragma-jm] | `_journal_mode` | -| [Synchronous][pragma-sync] | `_synchronous` | -| [WAL autocheckoint][pragma-walck] | `_wal_autocheckpoint` | +| [Busy Timeout][pragma-to] | `busy_timeout` | +| [Cache Size][pragma-cs] | `cache_size` | +| [Foreign Keys][pragma-fk] | `foreign_keys` | +| [Journal Mode][pragma-jm] | `journal_mode` | +| [Synchronous][pragma-sync] | `synchronous` | +| [WAL autocheckoint][pragma-walck] | `wal_autocheckpoint` | Please note there values passed using these connection keys are passed directly to SQLite3 without check or evaluation. Using incorrect values result diff --git a/spec/connection_spec.cr b/spec/connection_spec.cr index 0eabc13..84e9759 100644 --- a/spec/connection_spec.cr +++ b/spec/connection_spec.cr @@ -10,9 +10,9 @@ private def dump(source, target) end end -private def it_sets_pragma_on_connection(pragma : String, option : String, value : String, expected, file = __FILE__, line = __LINE__) - it "sets pragma '#{pragma}' to #{expected} using '#{option}'", file, line do - with_db("#{DB_FILENAME}?#{option}=#{value}") do |db| +private def it_sets_pragma_on_connection(pragma : String, value : String, expected, file = __FILE__, line = __LINE__) + it "sets pragma '#{pragma}' to #{expected}", file, line do + with_db("#{DB_FILENAME}?#{pragma}=#{value}") do |db| db.scalar("PRAGMA #{pragma}").should eq(expected) end end @@ -78,32 +78,32 @@ describe Connection do end # adjust busy_timeout pragma (default is 0) - it_sets_pragma_on_connection "busy_timeout", "_busy_timeout", "1000", 1000 + it_sets_pragma_on_connection "busy_timeout", "1000", 1000 # adjust cache_size pragma (default is -2000, 2MB) - it_sets_pragma_on_connection "cache_size", "_cache_size", "-4000", -4000 + it_sets_pragma_on_connection "cache_size", "-4000", -4000 # enable foreign_keys, no need to test off (is the default) - it_sets_pragma_on_connection "foreign_keys", "_foreign_keys", "1", 1 - it_sets_pragma_on_connection "foreign_keys", "_foreign_keys", "yes", 1 - it_sets_pragma_on_connection "foreign_keys", "_foreign_keys", "true", 1 - it_sets_pragma_on_connection "foreign_keys", "_foreign_keys", "on", 1 + it_sets_pragma_on_connection "foreign_keys", "1", 1 + it_sets_pragma_on_connection "foreign_keys", "yes", 1 + it_sets_pragma_on_connection "foreign_keys", "true", 1 + it_sets_pragma_on_connection "foreign_keys", "on", 1 # change journal_mode (default is delete) - it_sets_pragma_on_connection "journal_mode", "_journal_mode", "delete", "delete" - it_sets_pragma_on_connection "journal_mode", "_journal_mode", "truncate", "truncate" - it_sets_pragma_on_connection "journal_mode", "_journal_mode", "persist", "persist" + it_sets_pragma_on_connection "journal_mode", "delete", "delete" + it_sets_pragma_on_connection "journal_mode", "truncate", "truncate" + it_sets_pragma_on_connection "journal_mode", "persist", "persist" # change synchronous mode (default is 2, FULL) - it_sets_pragma_on_connection "synchronous", "_synchronous", "0", 0 - it_sets_pragma_on_connection "synchronous", "_synchronous", "off", 0 - it_sets_pragma_on_connection "synchronous", "_synchronous", "1", 1 - it_sets_pragma_on_connection "synchronous", "_synchronous", "normal", 1 - it_sets_pragma_on_connection "synchronous", "_synchronous", "2", 2 - it_sets_pragma_on_connection "synchronous", "_synchronous", "full", 2 - it_sets_pragma_on_connection "synchronous", "_synchronous", "3", 3 - it_sets_pragma_on_connection "synchronous", "_synchronous", "extra", 3 + it_sets_pragma_on_connection "synchronous", "0", 0 + it_sets_pragma_on_connection "synchronous", "off", 0 + it_sets_pragma_on_connection "synchronous", "1", 1 + it_sets_pragma_on_connection "synchronous", "normal", 1 + it_sets_pragma_on_connection "synchronous", "2", 2 + it_sets_pragma_on_connection "synchronous", "full", 2 + it_sets_pragma_on_connection "synchronous", "3", 3 + it_sets_pragma_on_connection "synchronous", "extra", 3 # change wal_autocheckpoint (default is 1000) - it_sets_pragma_on_connection "wal_autocheckpoint", "_wal_autocheckpoint", "0", 0 + it_sets_pragma_on_connection "wal_autocheckpoint", "0", 0 end diff --git a/src/sqlite3/connection.cr b/src/sqlite3/connection.cr index ec07224..3979120 100644 --- a/src/sqlite3/connection.cr +++ b/src/sqlite3/connection.cr @@ -93,32 +93,40 @@ class SQLite3::Connection < DB::Connection private def process_query_params(uri : URI) return unless query = uri.query - pragmas = Hash(String, String).new - - URI::Params.parse(query) do |key, value| - case key - when "_busy_timeout" - pragmas["busy_timeout"] = value - when "_cache_size" - pragmas["cache_size"] = value - when "_foreign_keys" - pragmas["foreign_keys"] = value - when "_journal_mode" - pragmas["journal_mode"] = value - when "_synchronous" - pragmas["synchronous"] = value - when "_wal_autocheckpoint" - pragmas["wal_autocheckpoint"] = value - end - end + 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| - pragmas.each do |key, value| + 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