PNixx / clickhouse-activerecord

A Ruby database ActiveRecord driver for ClickHouse

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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']