gitlab-ce/lib/gitlab/database/triggers/assign_desired_sharding_key.rb

75 lines
2.5 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module Database
module Triggers
class AssignDesiredShardingKey
include Gitlab::Database::SchemaHelpers
attr_reader :name
delegate :execute, :quote_table_name, :quote_column_name, to: :connection, private: true
def initialize(
table:, sharding_key:, parent_table:, parent_sharding_key:,
foreign_key:, connection:, parent_table_primary_key: nil, trigger_name: nil
)
@table = table
@sharding_key = sharding_key
@parent_table = parent_table
@parent_table_primary_key = parent_table_primary_key
@parent_sharding_key = parent_sharding_key
@foreign_key = foreign_key
@name = trigger_name || generated_name
@connection = connection
end
def create
quoted_table_name = quote_table_name(table)
quoted_parent_table = quote_table_name(parent_table)
quoted_sharding_key = quote_column_name(sharding_key)
quoted_parent_sharding_key = quote_column_name(parent_sharding_key)
quoted_primary_key = quote_column_name(parent_table_primary_key || 'id')
quoted_foreign_key = quote_column_name(foreign_key)
create_trigger_function(name) do
<<~SQL
IF NEW.#{quoted_sharding_key} IS NULL THEN
SELECT #{quoted_parent_sharding_key}
INTO NEW.#{quoted_sharding_key}
FROM #{quoted_parent_table}
WHERE #{quoted_parent_table}.#{quoted_primary_key} = NEW.#{quoted_foreign_key};
END IF;
RETURN NEW;
SQL
end
# Postgres 14 adds the `OR REPLACE` option to trigger creation, so
# this line can be removed and `OR REPLACE` added to `#create_trigger`
# when the minimum supported version is updated to 14 (milestone 17.0).
drop_trigger(quoted_table_name, name)
create_trigger(quoted_table_name, name, name, fires: 'BEFORE INSERT OR UPDATE')
end
def drop
drop_trigger(quote_table_name(table), name)
drop_function(name)
end
private
attr_reader :table, :sharding_key, :parent_table, :parent_table_primary_key, :parent_sharding_key,
:foreign_key, :connection
def generated_name
identifier = "#{table}_assign_#{sharding_key}"
"trigger_#{Digest::SHA256.hexdigest(identifier).first(12)}"
end
end
end
end
end