Class: InventoryRefresh::SaveCollection::Saver::Base

Inherits:
Object
  • Object
show all
Includes:
Logging, SqlHelper
Defined in:
lib/inventory_refresh/save_collection/saver/base.rb

Direct Known Subclasses

ConcurrentSafeBatch, Default

Instance Method Summary collapse

Methods included from SqlHelper

#build_multi_selection_query, #complement_of!, #get_connection, #pg_type_cast, #quote, #quote_and_pg_type_cast, #quote_column_name

Methods included from Logging

#logger

Constructor Details

#initialize(inventory_collection) ⇒ Base

Returns a new instance of Base.

Parameters:



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/inventory_refresh/save_collection/saver/base.rb', line 13

def initialize(inventory_collection)
  @inventory_collection = inventory_collection
  # TODO(lsmola) do I need to reload every time? Also it should be enough to clear the associations.
  inventory_collection.parent.reload if inventory_collection.parent
  @association = inventory_collection.db_collection_for_comparison

  # Private attrs
  @model_class            = inventory_collection.model_class
  @table_name             = @model_class.table_name
  @q_table_name           = get_connection.quote_table_name(@table_name)
  @primary_key            = @model_class.primary_key
  @arel_primary_key       = @model_class.arel_attribute(@primary_key)
  @unique_index_keys      = inventory_collection.unique_index_keys
  @unique_index_keys_to_s = inventory_collection.manager_ref_to_cols.map(&:to_s)
  @select_keys            = [@primary_key] + @unique_index_keys_to_s + internal_columns.map(&:to_s)
  @unique_db_primary_keys = Set.new
  @unique_db_indexes      = Set.new

  # Right now ApplicationRecordIterator in association is used for targeted refresh. Given the small amount of
  # records flowing through there, we probably don't need to optimize that association to fetch a pure SQL.
  @pure_sql_records_fetching = !inventory_collection.use_ar_object? && !@association.kind_of?(InventoryRefresh::ApplicationRecordIterator)

  @batch_size_for_persisting = inventory_collection.batch_size_pure_sql

  @batch_size          = @pure_sql_records_fetching ? @batch_size_for_persisting : inventory_collection.batch_size
  @record_key_method   = @pure_sql_records_fetching ? :pure_sql_record_key : :ar_record_key
  @select_keys_indexes = @select_keys.each_with_object({}).with_index { |(key, obj), index| obj[key.to_s] = index }
  @pg_types            = @model_class.attribute_names.each_with_object({}) do |key, obj|
    obj[key.to_sym] = inventory_collection.model_class.columns_hash[key]
                                          .try(:sql_type_metadata)
                                          .try(:instance_values)
                                          .try(:[], "sql_type")
  end

  @serializable_keys = {}
  @deserializable_keys = {}
  @model_class.attribute_names.each do |key|
    attribute_type = @model_class.type_for_attribute(key.to_s)
    pg_type        = @pg_types[key.to_sym]

    if inventory_collection.use_ar_object?
      # When using AR object, lets make sure we type.serialize(value) every value, so we have a slow but always
      # working way driven by a configuration
      @serializable_keys[key.to_sym] = attribute_type
      @deserializable_keys[key.to_sym] = attribute_type
    elsif attribute_type.respond_to?(:coder) ||
          attribute_type.type == :int4range ||
          attribute_type.type == :jsonb ||
          pg_type == "text[]" ||
          pg_type == "character varying[]"
      # Identify columns that needs to be encoded by type.serialize(value), it's a costy operations so lets do
      # do it only for columns we need it for.
      # TODO: should these set @deserializable_keys too?
      @serializable_keys[key.to_sym] = attribute_type
    elsif attribute_type.type == :decimal
      # Postgres formats decimal columns with fixed number of digits e.g. '0.100'
      # Need to parse and let Ruby format the value to have a comparable string.
      @serializable_keys[key.to_sym] = attribute_type
      @deserializable_keys[key.to_sym] = attribute_type
    end
  end
end

Instance Method Details

#save_inventory_collection!Object

Saves the InventoryCollection



77
78
79
80
81
82
83
84
85
86
# File 'lib/inventory_refresh/save_collection/saver/base.rb', line 77

def save_inventory_collection!
  # If we have a targeted InventoryCollection that wouldn't do anything, quickly skip it
  return if inventory_collection.noop?

  # Delete_complement strategy using :all_manager_uuids attribute
  delete_complement unless inventory_collection.delete_complement_noop?

  # Create/Update/Archive/Delete records based on InventoryCollection data and scope
  save!(association) unless inventory_collection.saving_noop?
end