From 4b2174d67428384a95c1fc908989d2b40487428e Mon Sep 17 00:00:00 2001 From: Trevor Vallender Date: Wed, 21 Aug 2024 10:54:09 +0100 Subject: [PATCH] Allow use of alternative database interfaces The CLI tool used as a database interface is now specified and customisable via ActiveRecord.database_cli. This specifies the current defaults but allows them to be overridden by users. It continues to accept array values to allow fallback options. --- activerecord/CHANGELOG.md | 10 ++++++++++ activerecord/lib/active_record.rb | 3 +++ .../connection_adapters/abstract_mysql_adapter.rb | 2 +- .../connection_adapters/postgresql_adapter.rb | 2 +- .../connection_adapters/sqlite3_adapter.rb | 2 +- .../test/cases/adapters/mysql2/dbconsole_test.rb | 11 +++++++++++ .../cases/adapters/postgresql/dbconsole_test.rb | 11 +++++++++++ .../test/cases/adapters/sqlite3/dbconsole_test.rb | 11 +++++++++++ guides/source/configuring.md | 13 +++++++++++++ 9 files changed, 62 insertions(+), 3 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 725af31fea8..6bae0ce49cd 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,13 @@ +* Support use of alternative database interfaces via the `database_cli` ActiveRecord configuration option. + + ```ruby + Rails.application.configure do + config.active_record.database_cli = { postgresql: "pgcli" } + end + ``` + + *T S Vallender* + * Add support for dumping table inheritance and native partitioning table definitions for PostgeSQL adapter *Justin Talbott* diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index 6518859b398..288514f54e7 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -207,6 +207,9 @@ module ActiveRecord end end + singleton_class.attr_accessor :database_cli + self.database_cli = { postgresql: "psql", mysql: %w[mysql mysql5], sqlite: "sqlite3" } + singleton_class.attr_reader :default_timezone # Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 525ee338080..eafbbaaad60 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -79,7 +79,7 @@ module ActiveRecord args << config.database - find_cmd_and_exec(["mysql", "mysql5"], *args) + find_cmd_and_exec(ActiveRecord.database_cli[:mysql], *args) end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index f2274c181f8..619a39f22bb 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -86,7 +86,7 @@ module ActiveRecord "-c #{name}=#{value.to_s.gsub(/[ \\]/, '\\\\\0')}" unless value == ":default" || value == :default end.join(" ") end - find_cmd_and_exec("psql", config.database) + find_cmd_and_exec(ActiveRecord.database_cli[:postgresql], config.database) end end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 34189c03bd7..634043d6b69 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -45,7 +45,7 @@ module ActiveRecord args << "-header" if options[:header] args << File.expand_path(config.database, Rails.respond_to?(:root) ? Rails.root : nil) - find_cmd_and_exec("sqlite3", *args) + find_cmd_and_exec(ActiveRecord.database_cli[:sqlite], *args) end end diff --git a/activerecord/test/cases/adapters/mysql2/dbconsole_test.rb b/activerecord/test/cases/adapters/mysql2/dbconsole_test.rb index e939ba4f743..ed1df018590 100644 --- a/activerecord/test/cases/adapters/mysql2/dbconsole_test.rb +++ b/activerecord/test/cases/adapters/mysql2/dbconsole_test.rb @@ -63,6 +63,17 @@ module ActiveRecord end end + def test_mysql_can_use_alternative_cli + ActiveRecord.database_cli[:mysql] = "mycli" + config = make_db_config(adapter: "mysql2", database: "db", database_cli: "mycli") + + assert_find_cmd_and_exec_called_with(["mycli", "db"]) do + Mysql2Adapter.dbconsole(config) + end + ensure + ActiveRecord.database_cli[:mysql] = %w[mysql mysql5] + end + private def make_db_config(config) ActiveRecord::DatabaseConfigurations::HashConfig.new("test", "primary", config) diff --git a/activerecord/test/cases/adapters/postgresql/dbconsole_test.rb b/activerecord/test/cases/adapters/postgresql/dbconsole_test.rb index 086b48229f3..9e6af8f9009 100644 --- a/activerecord/test/cases/adapters/postgresql/dbconsole_test.rb +++ b/activerecord/test/cases/adapters/postgresql/dbconsole_test.rb @@ -78,6 +78,17 @@ module ActiveRecord assert_equal "-c search_path=my_schema,\\ default,\\ \\\\my_schema -c statement_timeout=5000", ENV["PGOPTIONS"] end + def test_postgresql_can_use_alternative_cli + ActiveRecord.database_cli[:postgresql] = "pgcli" + config = make_db_config(adapter: "postgresql", database: "db") + + assert_find_cmd_and_exec_called_with(["pgcli", "db"]) do + PostgreSQLAdapter.dbconsole(config) + end + ensure + ActiveRecord.database_cli[:postgresql] = "psql" + end + private def preserve_pg_env old_values = ENV_VARS.map { |var| ENV[var] } diff --git a/activerecord/test/cases/adapters/sqlite3/dbconsole_test.rb b/activerecord/test/cases/adapters/sqlite3/dbconsole_test.rb index c69598237b2..6702cf14db5 100644 --- a/activerecord/test/cases/adapters/sqlite3/dbconsole_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/dbconsole_test.rb @@ -52,6 +52,17 @@ module ActiveRecord Rails.singleton_class.remove_method(:root) end + def test_sqlite3_can_use_alternative_cli + ActiveRecord.database_cli[:sqlite] = "sqlitecli" + config = make_db_config(adapter: "sqlite3", database: "config/db.sqlite3", database_cli: "sqlitecli") + + assert_find_cmd_and_exec_called_with(["sqlitecli", root.join("config/db.sqlite3").to_s]) do + SQLite3Adapter.dbconsole(config) + end + ensure + ActiveRecord.database_cli[:sqlite] = "sqlite3" + end + private def root Pathname(__dir__).join("../../../..") diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 077c02382a0..8586bbeb338 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -1633,6 +1633,19 @@ warning, or neither. | --------------------- | -------------------- | | (original) | `true` | +#### config.active_record.database_cli + +Controls which CLI tool will be used for accessing the database when running `rails dbconsole`. By default +the standard tool for the database will be used (e.g. `psql` for PostgreSQL and `mysql` for MySQL). The option +takes a hash which specifies the tool per-database system, and an array can be used where fallback options are +required: + +```ruby +# config/application.rb + +config.active_record.database_cli = { postgresql: "pgcli", mysql: %w[ mycli mysql ] } +``` + #### `ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans` and `ActiveRecord::ConnectionAdapters::TrilogyAdapter.emulate_booleans` Controls whether the Active Record MySQL adapter will consider all `tinyint(1)` columns as booleans. Defaults to `true`.