Adapter should raise more specific exceptions, esp in Rake tasks
bjeanes opened this issue · comments
Currently, when a database does not exist and a query is executed, a generic ActiveRecord::ActiveRecordError
is raised.
Other adapters use ActiveRecord::NoDatabaseError
and the db:prepare
Rake task depends on this fact to do the right thing (and has done since at least Rails 6, though I suspect earlier).
Here is what is raised with postgres
adapter on main DB, when trying to migrate or query against a non-existent DB:
#<ActiveRecord::NoDatabaseError:"connection to server at \"172.31.0.5\", port 5432 failed: FATAL: database \"db\" does not exist\n">
And clickhouse with current version of this adapter:
#<ActiveRecord::ActiveRecordError:"Response code: 404:\nCode: 81. DB::Exception: Database analytics_db doesn't exist. (UNKNOWN_DATABASE) (version 22.3.7.28 (official build))\n">
Similarly, ActiveRecord::DatabaseAlreadyExists
should be raised when the database already exists and it Rails is attempting to create it. This exception is caught to make the Rake task seem idempotent.
My workaround in the meantime:
# lib/tasks/db.rake
namespace :db do
# Clickhouse adapter does not raise the right exception when there is no DB, which breaks
# `db:prepare` task. I don't want to monkeypatch broadly in our app on this driver, so
# this task is a workaround that only applies in this db setup context.
#
# https://github.com/PNixx/clickhouse-activerecord/issues/91
task :fix_clickhouse do
module ClickhouseAdapterNoDbFix
def process_response(res)
super(res)
rescue ActiveRecord::ActiveRecordError
case res.body
when /DB::Exception:.*\(UNKNOWN_DATABASE\)/
raise ActiveRecord::NoDatabaseError
when /DB::Exception:.*\(DATABASE_ALREADY_EXISTS\)/
raise ActiveRecord::DatabaseAlreadyExists
else
raise
end
end
end
ActiveRecord::ConnectionAdapters::Clickhouse::SchemaStatements.prepend(ClickhouseAdapterNoDbFix)
end
end
Rake::Task['db:load_config'].enhance ['db:fix_clickhouse']