From 3b5f65188b79258c880d2ccab7b83c645719fdd8 Mon Sep 17 00:00:00 2001 From: nixx Date: Wed, 10 Jan 2024 13:31:49 +0300 Subject: [PATCH] support update & delete for clickhouse from version 23.3 and newer #93 --- .../clickhouse/schema_creation.rb | 6 +----- .../clickhouse/schema_statements.rb | 14 ++++++------- .../connection_adapters/clickhouse_adapter.rb | 21 +++---------------- lib/arel/visitors/clickhouse.rb | 11 ++++++++++ lib/clickhouse-activerecord/version.rb | 2 +- lib/tasks/clickhouse.rake | 4 ++-- 6 files changed, 25 insertions(+), 33 deletions(-) diff --git a/lib/active_record/connection_adapters/clickhouse/schema_creation.rb b/lib/active_record/connection_adapters/clickhouse/schema_creation.rb index 1ac577bf..aa20d7c9 100644 --- a/lib/active_record/connection_adapters/clickhouse/schema_creation.rb +++ b/lib/active_record/connection_adapters/clickhouse/schema_creation.rb @@ -125,11 +125,7 @@ def visit_ChangeColumnDefinition(o) end def current_database - if ActiveRecord::version >= Gem::Version.new('6.1') - ActiveRecord::Base.connection_db_config.database - else - ActiveRecord::Base.connection_config[:database] - end + ActiveRecord::Base.connection_db_config.database end end end diff --git a/lib/active_record/connection_adapters/clickhouse/schema_statements.rb b/lib/active_record/connection_adapters/clickhouse/schema_statements.rb index 0d649362..8027e8b9 100644 --- a/lib/active_record/connection_adapters/clickhouse/schema_statements.rb +++ b/lib/active_record/connection_adapters/clickhouse/schema_statements.rb @@ -30,12 +30,16 @@ def exec_insert_all(sql, name) true end + # @link https://clickhouse.com/docs/en/sql-reference/statements/alter/update def exec_update(_sql, _name = nil, _binds = []) - raise ActiveRecord::ActiveRecordError, 'Clickhouse update is not supported' + do_execute(_sql, _name, format: nil) + true end + # @link https://clickhouse.com/docs/en/sql-reference/statements/delete def exec_delete(_sql, _name = nil, _binds = []) - raise ActiveRecord::ActiveRecordError, 'Clickhouse delete is not supported' + do_execute(_sql, _name, format: nil) + true end def tables(name = nil) @@ -143,11 +147,7 @@ def new_column_from_field(table_name, field, _definitions) default = field[3] default_value = extract_value_from_default(default) default_function = extract_default_function(default_value, default) - if ActiveRecord::version >= Gem::Version.new('6') - ClickhouseColumn.new(field[0], default_value, type_metadata, field[1].include?('Nullable'), default_function) - else - ClickhouseColumn.new(field[0], default_value, type_metadata, field[1].include?('Nullable'), table_name, default_function) - end + ClickhouseColumn.new(field[0], default_value, type_metadata, field[1].include?('Nullable'), default_function) end protected diff --git a/lib/active_record/connection_adapters/clickhouse_adapter.rb b/lib/active_record/connection_adapters/clickhouse_adapter.rb index 607c87f2..99ecc952 100644 --- a/lib/active_record/connection_adapters/clickhouse_adapter.rb +++ b/lib/active_record/connection_adapters/clickhouse_adapter.rb @@ -127,9 +127,6 @@ def initialize(logger, connection_parameters, config, full_config) @full_config = full_config @prepared_statements = false - if ActiveRecord::version == Gem::Version.new('6.0.0') - @prepared_statement_status = Concurrent::ThreadLocalVar.new(false) - end connect end @@ -238,30 +235,18 @@ def quote(value) # Quoting time without microseconds def quoted_date(value) if value.acts_like?(:time) - if ActiveRecord::version >= Gem::Version.new('7') - zone_conversion_method = ActiveRecord.default_timezone == :utc ? :getutc : :getlocal - else - zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal - end + zone_conversion_method = ActiveRecord.default_timezone == :utc ? :getutc : :getlocal if value.respond_to?(zone_conversion_method) value = value.send(zone_conversion_method) end end - if ActiveRecord::version >= Gem::Version.new('7') - value.to_fs(:db) - else - value.to_s(:db) - end + value.to_fs(:db) end def column_name_for_operation(operation, node) # :nodoc: - if ActiveRecord::version >= Gem::Version.new('6') - visitor.compile(node) - else - column_name_from_arel_node(node) - end + visitor.compile(node) end # Executes insert +sql+ statement in the context of this connection using diff --git a/lib/arel/visitors/clickhouse.rb b/lib/arel/visitors/clickhouse.rb index a63471a9..8b6a1d62 100644 --- a/lib/arel/visitors/clickhouse.rb +++ b/lib/arel/visitors/clickhouse.rb @@ -23,6 +23,17 @@ def visit_Arel_Nodes_SelectOptions(o, collector) maybe_visit o.settings, super end + def visit_Arel_Nodes_UpdateStatement(o, collector) + o = prepare_update_statement(o) + + collector << 'ALTER TABLE ' + collector = visit o.relation, collector + collect_nodes_for o.values, collector, ' UPDATE ' + collect_nodes_for o.wheres, collector, ' WHERE ', ' AND ' + collect_nodes_for o.orders, collector, ' ORDER BY ' + maybe_visit o.limit, collector + end + def visit_Arel_Nodes_Settings(o, collector) return collector if o.expr.empty? diff --git a/lib/clickhouse-activerecord/version.rb b/lib/clickhouse-activerecord/version.rb index fd3b523d..c24924bc 100644 --- a/lib/clickhouse-activerecord/version.rb +++ b/lib/clickhouse-activerecord/version.rb @@ -1,3 +1,3 @@ module ClickhouseActiverecord - VERSION = '1.0.0' + VERSION = '1.0.1' end diff --git a/lib/tasks/clickhouse.rake b/lib/tasks/clickhouse.rake index 181ac42c..eca458a0 100644 --- a/lib/tasks/clickhouse.rake +++ b/lib/tasks/clickhouse.rake @@ -72,7 +72,7 @@ namespace :clickhouse do desc 'Migrate the clickhouse database' task migrate: %i[prepare_schema_migration_table prepare_internal_metadata_table] do Rake::Task['db:migrate:clickhouse'].execute - if File.exists? "#{Rails.root}/db/clickhouse_schema_simple.rb" + if File.exist? "#{Rails.root}/db/clickhouse_schema_simple.rb" Rake::Task['clickhouse:schema:dump'].execute(simple: true) end end @@ -80,7 +80,7 @@ namespace :clickhouse do desc 'Rollback the clickhouse database' task rollback: %i[prepare_schema_migration_table prepare_internal_metadata_table] do Rake::Task['db:rollback:clickhouse'].execute - if File.exists? "#{Rails.root}/db/clickhouse_schema_simple.rb" + if File.exist? "#{Rails.root}/db/clickhouse_schema_simple.rb" Rake::Task['clickhouse:schema:dump'].execute(simple: true) end end