Skip to content

Commit

Permalink
Merge pull request ManageIQ#17029 from Ladas/automatically_pick_the_r…
Browse files Browse the repository at this point in the history
…ight_unique_index

Automatically fetch the right unique index
  • Loading branch information
agrare authored Feb 28, 2018
2 parents ac0e949 + 501a90b commit 8102655
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 20 deletions.
43 changes: 28 additions & 15 deletions app/models/manager_refresh/save_collection/saver/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -250,26 +250,39 @@ def assign_attributes_for_create!(hash, create_time)
assign_attributes_for_update!(hash, create_time)
end

def unique_index_columns
return @unique_index_columns if @unique_index_columns
def unique_indexes
@unique_indexes_cache if @unique_indexes_cache

if model_class.respond_to?(:manager_refresh_unique_index_columns)
return @unique_index_columns = model_class.manager_refresh_unique_index_columns
end

unique_indexes = model_class.connection.indexes(model_class.table_name).select(&:unique)
if unique_indexes.count > 1
raise "Cannot infer unique index automatically, since the table #{model_class.table_name}"\
" of the #{inventory_collection} contains more than 1 unique index: '#{unique_indexes.collect(&:name)}'."\
" Please define the unique index columns explicitly on a model as a class method"\
" self.manager_refresh_unique_index_columns returning [:column1, :column2, etc.]"
end
@unique_indexes_cache = model_class.connection.indexes(model_class.table_name).select(&:unique)

if unique_indexes.blank?
if @unique_indexes_cache.blank?
raise "#{inventory_collection} and its table #{model_class.table_name} must have a unique index defined, to"\
" be able to use saver_strategy :concurrent_safe or :concurrent_safe_batch."
end
@unique_index_columns = unique_indexes.first.columns.map(&:to_sym)

@unique_indexes_cache
end

def unique_index_for(keys)
@unique_index_for_keys_cache ||= {}
@unique_index_for_keys_cache[keys] if @unique_index_for_keys_cache[keys]

# Find all uniq indexes that that are covering our keys
uniq_key_candidates = unique_indexes.each_with_object([]) { |i, obj| obj << i if (keys - i.columns.map(&:to_sym)).empty? }

if @unique_indexes_cache.blank?
raise "#{inventory_collection} and its table #{model_class.table_name} must have a unique index defined "\
"covering columns #{keys} to be able to use saver_strategy :concurrent_safe or :concurrent_safe_batch."
end

# Take the uniq key having the least number of columns
@unique_index_for_keys_cache[keys] = uniq_key_candidates.min_by { |x| x.columns.count }
end

def unique_index_columns
return @unique_index_columns if @unique_index_columns

@unique_index_columns = unique_index_for(unique_index_keys).columns.map(&:to_sym)
end

def supports_sti?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ def build_insert_query(all_attribute_keys, hashes, on_conflict: nil)
ON CONFLICT DO NOTHING
}
elsif on_conflict_update
index_where_condition = unique_index_for(unique_index_keys).where
where_to_sql = index_where_condition ? "WHERE #{index_where_condition}" : ""

insert_query += %{
ON CONFLICT (#{unique_index_columns.map { |x| quote_column_name(x) }.join(",")})
ON CONFLICT (#{unique_index_columns.map { |x| quote_column_name(x) }.join(",")}) #{where_to_sql}
DO
UPDATE
SET #{all_attribute_keys_array.map { |key| build_insert_set_cols(key) }.join(", ")}
Expand Down
4 changes: 0 additions & 4 deletions app/models/vm_or_template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -294,10 +294,6 @@ def self.model_suffix
manager_class.short_token
end

def self.manager_refresh_unique_index_columns
[:ems_id, :ems_ref]
end

def to_s
name
end
Expand Down

0 comments on commit 8102655

Please sign in to comment.