Module: Ensql
- Defined in:
- lib/ensql.rb,
lib/ensql/sql.rb,
lib/ensql/error.rb,
lib/ensql/adapter.rb,
lib/ensql/version.rb,
lib/ensql/load_sql.rb,
lib/ensql/transaction.rb,
lib/ensql/pool_wrapper.rb,
lib/ensql/sequel_adapter.rb,
lib/ensql/postgres_adapter.rb,
lib/ensql/active_record_adapter.rb
Overview
Primary interface for loading, interpolating and executing SQL statements using your preferred database connection. See Ensql.sql for interpolation details.
Defined Under Namespace
Modules: Adapter Classes: ActiveRecordAdapter, Error, PoolWrapper, PostgresAdapter, SQL, SequelAdapter
Constant Summary collapse
- VERSION =
Gem version
"0.6.5"
- SUPPORTED_ACTIVERECORD_VERSIONS =
Versions of activerecord compatible with the ActiveRecordAdapter
[">= 5.0", "< 6.2"].freeze
- SUPPORTED_SEQUEL_VERSIONS =
Versions of sequel compatible with the SequelAdapter
"~> 5.9"
- SUPPORTED_PG_VERSIONS =
Versions of pg compatibile with the PostgresAdapter
[">= 0.19", "< 2"].freeze
Class Attribute Summary collapse
-
.sql_path ⇒ Object
Path to search for *.sql queries in, defaults to "sql/".
Class Method Summary collapse
-
.adapter ⇒ Object
Get the current connection adapter.
-
.adapter=(adapter) ⇒ Object
Set the connection adapter to use.
-
.load_sql(name, params = {}) ⇒ Ensql::SQL
Load SQL from a file within Ensql.sql_path.
-
.rollback! ⇒ Object
Immediately rollback and exit the current transaction block.
-
.run(sql, params = {}) ⇒ void
Convenience method to interpolate and run the supplied SQL on the current adapter.
-
.sql(sql, params = {}) ⇒ Ensql::SQL
Encapsulates a plain-text SQL statement and optional parameters to interpolate.
-
.transaction(start: "START TRANSACTION", commit: "COMMIT", rollback: "ROLLBACK", &block) ⇒ Object
Wrap a block with a transaction.
Class Attribute Details
.sql_path ⇒ Object
Path to search for *.sql queries in, defaults to "sql/". For example, if
sql_path is set to 'app/queries', load_sql('users/active')
will read
'app/queries/users/active.sql'.
16 17 18 |
# File 'lib/ensql/load_sql.rb', line 16 def sql_path @sql_path ||= "sql" end |
Class Method Details
.adapter ⇒ Object
Get the current connection adapter. If not specified, it will try to autoload an adapter based on the availability of Sequel or ActiveRecord, in that order.
17 18 19 |
# File 'lib/ensql/adapter.rb', line 17 def adapter Thread.current[:ensql_adapter] || Thread.main[:ensql_adapter] ||= autoload_adapter end |
.adapter=(adapter) ⇒ Object
Set the connection adapter to use. Must implement the interface defined in Adapter. This uses a thread-local variable so adapters can be switched safely in a multi-threaded web server.
24 25 26 27 28 29 30 |
# File 'lib/ensql/adapter.rb', line 24 def adapter=(adapter) if adapter.is_a?(Module) && (adapter.name == "Ensql::SequelAdapter" || adapter.name == "Ensql::ActiveRecordAdapter") warn "Using `#{adapter}` as an adapter is deprecated, use `#{adapter}.new`.", uplevel: 1 end Thread.current[:ensql_adapter] = adapter end |
.load_sql(name, params = {}) ⇒ Ensql::SQL
32 33 34 35 36 37 |
# File 'lib/ensql/load_sql.rb', line 32 def load_sql(name, params = {}) path = File.join(sql_path, "#{name}.sql") SQL.new(File.read(path), params, name) rescue Errno::ENOENT raise Error, "couldn't load SQL from file '#{path}' (sql_path: '#{sql_path}')" end |
.rollback! ⇒ Object
Immediately rollback and exit the current transaction block. See transaction.
51 52 53 54 55 |
# File 'lib/ensql/transaction.rb', line 51 def rollback! throw :rollback, :rollback rescue UncaughtThrowError raise Error, "not in a transaction block, can't rollback" end |
.run(sql, params = {}) ⇒ void
This method returns an undefined value.
Convenience method to interpolate and run the supplied SQL on the current adapter.
45 46 47 |
# File 'lib/ensql.rb', line 45 def run(sql, params = {}) SQL.new(sql, params).run end |
.sql(sql, params = {}) ⇒ Ensql::SQL
Encapsulates a plain-text SQL statement and optional parameters to interpolate. Interpolation is indicated by one of the four placeholder formats:
Literal:
%{param}
- Interpolates
param
as a quoted string or a numeric literal depending on the class. nil
is interpolated as'NULL'
.- Other objects depend on the database and the adapter, but most (like
Time
) are serialised as a quoted SQL string.
- Interpolates
List Expansion:
%{(param)}
- Expands an array to a list of quoted literals.
- Mostly useful for
column IN (1,2)
or postgres row literals. - Empty arrays are interpolated as
(NULL)
for SQL conformance. - The parameter will be converted to an Array.
Nested List:
%{param(nested sql)}
- Takes an array of parameter hashes and interpolates the nested SQL for each Hash in the Array.
- Raises an error if param is nil or a non-hash array.
- Primary useful for SQL
VALUES ()
clauses.
SQL Fragment:
%{!sql_param}
- Interpolates the parameter without quoting, as a SQL fragment.
- The parameter must be an SQL object or this will raise an error.
nil
will not be interpolated.- Allows composition of SQL via subqueries.
Any placeholders in the SQL must be present in the params hash or a KeyError will be raised during interpolation. Interpolation occurs just before the SQL is executed.
33 34 35 |
# File 'lib/ensql.rb', line 33 def sql(sql, params = {}) SQL.new(sql, params) end |
.transaction(start: "START TRANSACTION", commit: "COMMIT", rollback: "ROLLBACK", &block) ⇒ Object
Wrap a block with a transaction. Uses the well supported
SQL-standard commands for controlling a transaction by default, however database
specific statements can be supplied. Any exceptions inside the block will
trigger a rollback and be reraised. Alternatively, you can call
rollback! to immediately exit the block and rollback the transaction.
Returns the result of the block. If the block returns :rollback
, the
transaction will also be rolled back.
# If `do_thing1` or `do_thing2` raise an error, no statements are committed.
Ensql.transaction { do_thing1; do_thing2 }
# If `do_thing2` is falsey, `do_thing1` is rolled back and `do_thing3` is skipped.
Ensql.transaction { do_thing1; do_thing2 or Ensql.rollback!; do_thing3 }
# Nest transactions with savepoints.
Ensql.transaction do
do_thing1
Ensql.transaction(start: 'SAVEPOINT my_savepoint', commit: 'RELEASE SAVEPOINT my_savepoint', rollback: 'ROLLBACK TO SAVEPOINT my_savepoint') do
do_thing2
do_thing3
end
end
# Use database-specific transaction semantics.
Ensql.transaction(start: 'BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY DEFERRABLE') { }
38 39 40 41 42 43 44 45 46 47 |
# File 'lib/ensql/transaction.rb', line 38 def transaction(start: "START TRANSACTION", commit: "COMMIT", rollback: "ROLLBACK", &block) adapter.run(start) result = catch(:rollback, &block) adapter.run(result == :rollback ? rollback : commit) result # # We need to try rollback on _any_ exception. Since we reraise, rescuing this is safe. rescue Exception # rubocop:disable Lint/RescueException adapter.run(rollback) raise end |