inventory_refresh 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/Gemfile +4 -0
  4. data/bundler.d/.gitkeep +0 -0
  5. data/inventory_refresh.gemspec +4 -4
  6. data/lib/inventory_refresh/inventory_collection/builder.rb +249 -0
  7. data/lib/inventory_refresh/inventory_collection/graph.rb +0 -15
  8. data/lib/inventory_refresh/inventory_collection/helpers/associations_helper.rb +80 -0
  9. data/lib/inventory_refresh/inventory_collection/helpers/initialize_helper.rb +456 -0
  10. data/lib/inventory_refresh/inventory_collection/helpers/questions_helper.rb +132 -0
  11. data/lib/inventory_refresh/inventory_collection/helpers.rb +6 -0
  12. data/lib/inventory_refresh/inventory_collection/index/type/skeletal.rb +5 -5
  13. data/lib/inventory_refresh/inventory_collection/reference.rb +4 -0
  14. data/lib/inventory_refresh/inventory_collection/scanner.rb +111 -18
  15. data/lib/inventory_refresh/inventory_collection/serialization.rb +7 -7
  16. data/lib/inventory_refresh/inventory_collection/unconnected_edge.rb +19 -0
  17. data/lib/inventory_refresh/inventory_collection.rb +114 -649
  18. data/lib/inventory_refresh/inventory_object.rb +17 -11
  19. data/lib/inventory_refresh/inventory_object_lazy.rb +20 -10
  20. data/lib/inventory_refresh/persister.rb +212 -0
  21. data/lib/inventory_refresh/save_collection/base.rb +18 -3
  22. data/lib/inventory_refresh/save_collection/saver/base.rb +25 -62
  23. data/lib/inventory_refresh/save_collection/saver/concurrent_safe_batch.rb +73 -225
  24. data/lib/inventory_refresh/save_collection/saver/partial_upsert_helper.rb +226 -0
  25. data/lib/inventory_refresh/save_collection/saver/retention_helper.rb +115 -0
  26. data/lib/inventory_refresh/save_collection/saver/sql_helper.rb +122 -0
  27. data/lib/inventory_refresh/save_collection/saver/sql_helper_update.rb +24 -5
  28. data/lib/inventory_refresh/save_collection/saver/sql_helper_upsert.rb +6 -6
  29. data/lib/inventory_refresh/save_collection/sweeper.rb +69 -0
  30. data/lib/inventory_refresh/save_inventory.rb +18 -8
  31. data/lib/inventory_refresh/target_collection.rb +12 -0
  32. data/lib/inventory_refresh/version.rb +1 -1
  33. data/lib/inventory_refresh.rb +1 -0
  34. metadata +24 -15
  35. data/lib/inventory_refresh/save_collection/recursive.rb +0 -52
  36. data/lib/inventory_refresh/save_collection/saver/concurrent_safe.rb +0 -71
@@ -25,8 +25,13 @@ module InventoryRefresh
25
25
  reference.stringified_reference
26
26
  end
27
27
 
28
+ # @return [Hash] hash reference having :manager_ref keys, which can uniquely identity entity under a manager
29
+ def uuid
30
+ reference.full_reference.slice(*reference.keys).stringify_keys!
31
+ end
32
+
28
33
  # @return [InventoryRefresh::InventoryObject] returns self
29
- def load
34
+ def load(*_args)
30
35
  self
31
36
  end
32
37
 
@@ -92,8 +97,9 @@ module InventoryRefresh
92
97
  #
93
98
  # @param inventory_collection_scope [InventoryRefresh::InventoryCollection] parent InventoryCollection object
94
99
  # @param all_attribute_keys [Array<Symbol>] Attribute keys we will modify based on object's data
100
+ # @param inventory_object [InventoryRefresh::InventoryObject] InventoryObject object owning these attributes
95
101
  # @return [Hash] Data in DB format
96
- def attributes_with_keys(inventory_collection_scope = nil, all_attribute_keys = [])
102
+ def attributes_with_keys(inventory_collection_scope = nil, all_attribute_keys = [], inventory_object = nil)
97
103
  # We should explicitly pass a scope, since the inventory_object can be mapped to more InventoryCollections with
98
104
  # different blacklist and whitelist. The generic code always passes a scope.
99
105
  inventory_collection_scope ||= inventory_collection
@@ -106,7 +112,7 @@ module InventoryRefresh
106
112
  elsif loadable?(value) || inventory_collection_scope.association_to_foreign_key_mapping[key]
107
113
  # Lets fill also the original data, so other InventoryObject referring to this attribute gets the right
108
114
  # result
109
- data[key] = value.load if value.respond_to?(:load)
115
+ data[key] = value.load(inventory_object, key) if value.respond_to?(:load)
110
116
  if (foreign_key = inventory_collection_scope.association_to_foreign_key_mapping[key])
111
117
  # We have an association to fill, lets fill also the :key, cause some other InventoryObject can refer to it
112
118
  record_id = data[key].try(:id)
@@ -143,12 +149,12 @@ module InventoryRefresh
143
149
  attributes.each do |k, v|
144
150
  # We don't want timestamps or resource versions to be overwritten here, since those are driving the conditions
145
151
  next if %i(resource_timestamps resource_timestamps_max resource_timestamp).include?(k)
146
- next if %i(resource_versions resource_versions_max resource_version).include?(k)
152
+ next if %i(resource_counters resource_counters_max resource_counter).include?(k)
147
153
 
148
154
  if data[:resource_timestamp] && attributes[:resource_timestamp]
149
155
  assign_only_newest(:resource_timestamp, :resource_timestamps, attributes, data, k, v)
150
- elsif data[:resource_version] && attributes[:resource_version]
151
- assign_only_newest(:resource_version, :resource_versions, attributes, data, k, v)
156
+ elsif data[:resource_counter] && attributes[:resource_counter]
157
+ assign_only_newest(:resource_counter, :resource_counters, attributes, data, k, v)
152
158
  else
153
159
  public_send("#{k}=", v)
154
160
  end
@@ -156,8 +162,8 @@ module InventoryRefresh
156
162
 
157
163
  if attributes[:resource_timestamp]
158
164
  assign_full_row_version_attr(:resource_timestamp, attributes, data)
159
- elsif attributes[:resource_version]
160
- assign_full_row_version_attr(:resource_version, attributes, data)
165
+ elsif attributes[:resource_counter]
166
+ assign_full_row_version_attr(:resource_counter, attributes, data)
161
167
  end
162
168
 
163
169
  self
@@ -206,9 +212,9 @@ module InventoryRefresh
206
212
  # newer than existing attribute.
207
213
  #
208
214
  # @param full_row_version_attr [Symbol] Attr name for full rows, allowed values are
209
- # [:resource_timestamp, :resource_version]
215
+ # [:resource_timestamp, :resource_counter]
210
216
  # @param partial_row_version_attr [Symbol] Attr name for partial rows, allowed values are
211
- # [:resource_timestamps, :resource_versions]
217
+ # [:resource_timestamps, :resource_counters]
212
218
  # @param attributes [Hash] New attributes we are assigning
213
219
  # @param data [Hash] Existing attributes of the InventoryObject
214
220
  # @param k [Symbol] Name of the attribute we are assigning
@@ -247,7 +253,7 @@ module InventoryRefresh
247
253
  # Assigns attribute representing version of the whole row
248
254
  #
249
255
  # @param full_row_version_attr [Symbol] Attr name for full rows, allowed values are
250
- # [:resource_timestamp, :resource_version]
256
+ # [:resource_timestamp, :resource_counter]
251
257
  # @param attributes [Hash] New attributes we are assigning
252
258
  # @param data [Hash] Existing attributes of the InventoryObject
253
259
  def assign_full_row_version_attr(full_row_version_attr, attributes, data)
@@ -42,12 +42,14 @@ module InventoryRefresh
42
42
  "InventoryObjectLazy:('#{self}', #{inventory_collection}#{suffix})"
43
43
  end
44
44
 
45
+ # @param inventory_object [InventoryRefresh::InventoryObject] InventoryObject object owning this relation
46
+ # @param inventory_object_key [Symbol] InventoryObject object's attribute pointing to this relation
45
47
  # @return [InventoryRefresh::InventoryObject, Object] InventoryRefresh::InventoryObject instance or an attribute
46
48
  # on key
47
- def load
49
+ def load(inventory_object = nil, inventory_object_key = nil)
48
50
  transform_nested_secondary_indexes! if transform_nested_lazy_finds && nested_secondary_index?
49
51
 
50
- key ? load_object_with_key : load_object
52
+ load_object(inventory_object, inventory_object_key)
51
53
  end
52
54
 
53
55
  # return [Boolean] true if the Lazy object is causing a dependency, Lazy link is always a dependency if no :key
@@ -128,15 +130,15 @@ module InventoryRefresh
128
130
  skeletal_primary_index.build(full_reference)
129
131
  end
130
132
 
133
+ # @param loaded_object [InventoryRefresh::InventoryObject, NilClass] Loaded object or nil if object wasn't found
131
134
  # @return [Object] value found or :key or default value if the value is nil
132
- def load_object_with_key
135
+ def load_object_with_key(loaded_object)
133
136
  # TODO(lsmola) Log error if we are accessing path that is present in blacklist or not present in whitelist
134
- found = inventory_collection.find(reference)
135
- if found.present?
136
- if found.try(:data).present?
137
- found.data[key] || default
137
+ if loaded_object.present?
138
+ if loaded_object.try(:data).present?
139
+ loaded_object.data[key] || default
138
140
  else
139
- found.public_send(key) || default
141
+ loaded_object.public_send(key) || default
140
142
  end
141
143
  else
142
144
  default
@@ -144,8 +146,16 @@ module InventoryRefresh
144
146
  end
145
147
 
146
148
  # @return [InventoryRefresh::InventoryObject, NilClass] InventoryRefresh::InventoryObject instance or nil if not found
147
- def load_object
148
- inventory_collection.find(reference)
149
+ def load_object(inventory_object = nil, inventory_object_key = nil)
150
+ loaded_object = inventory_collection.find(reference)
151
+
152
+ if inventory_object && inventory_object_key && !loaded_object && reference.loadable?
153
+ # Object was not loaded, but the reference is pointing to something, lets return it as edge that should've
154
+ # been loaded.
155
+ inventory_object.inventory_collection.store_unconnected_edges(inventory_object, inventory_object_key, self)
156
+ end
157
+
158
+ key ? load_object_with_key(loaded_object) : loaded_object
149
159
  end
150
160
  end
151
161
  end
@@ -0,0 +1,212 @@
1
+ module InventoryRefresh
2
+ class Persister
3
+ require 'json'
4
+ require 'yaml'
5
+
6
+ attr_reader :manager, :target, :collections
7
+
8
+ attr_accessor :refresh_state_uuid, :refresh_state_part_uuid, :total_parts, :sweep_scope, :retry_count, :retry_max
9
+
10
+ # @param manager [ManageIQ::Providers::BaseManager] A manager object
11
+ # @param target [Object] A refresh Target object
12
+ def initialize(manager, target = nil)
13
+ @manager = manager
14
+ @target = target
15
+
16
+ @collections = {}
17
+
18
+ initialize_inventory_collections
19
+ end
20
+
21
+ # Interface for creating InventoryCollection under @collections
22
+ #
23
+ # @param builder_class [ManageIQ::Providers::Inventory::Persister::Builder] or subclasses
24
+ # @param collection_name [Symbol || Array] used as InventoryCollection:association
25
+ # @param extra_properties [Hash] props from InventoryCollection.initialize list
26
+ # - adds/overwrites properties added by builder
27
+ #
28
+ # @param settings [Hash] builder settings
29
+ # - @see ManageIQ::Providers::Inventory::Persister::Builder.default_options
30
+ # - @see make_builder_settings()
31
+ #
32
+ # @example
33
+ # add_collection(:vms, ManageIQ::Providers::Inventory::Persister::Builder::CloudManager) do |builder|
34
+ # builder.add_properties(
35
+ # :strategy => :local_db_cache_all,
36
+ # )
37
+ # )
38
+ #
39
+ # @see documentation https://github.com/ManageIQ/guides/tree/master/providers/persister/inventory_collections.md
40
+ #
41
+ def add_collection(collection_name, builder_class = inventory_collection_builder, extra_properties = {}, settings = {}, &block)
42
+ builder = builder_class.prepare_data(collection_name,
43
+ self.class,
44
+ builder_settings(settings),
45
+ &block)
46
+
47
+ builder.add_properties(extra_properties) if extra_properties.present?
48
+
49
+ builder.add_properties({:manager_uuids => target.try(:references, collection_name) || []}, :if_missing) if targeted?
50
+
51
+ builder.evaluate_lambdas!(self)
52
+
53
+ collections[collection_name] = builder.to_inventory_collection
54
+ end
55
+
56
+ # @return [Array<InventoryRefresh::InventoryCollection>] array of InventoryCollection objects of the persister
57
+ def inventory_collections
58
+ collections.values
59
+ end
60
+
61
+ # @return [Array<Symbol>] array of InventoryCollection object names of the persister
62
+ def inventory_collections_names
63
+ collections.keys
64
+ end
65
+
66
+ # @return [InventoryRefresh::InventoryCollection] returns a defined InventoryCollection or undefined method
67
+ def method_missing(method_name, *arguments, &block)
68
+ if inventory_collections_names.include?(method_name)
69
+ self.define_collections_reader(method_name)
70
+ send(method_name)
71
+ else
72
+ super
73
+ end
74
+ end
75
+
76
+ # @return [Boolean] true if InventoryCollection with passed method_name name is defined
77
+ def respond_to_missing?(method_name, _include_private = false)
78
+ inventory_collections_names.include?(method_name) || super
79
+ end
80
+
81
+ # Defines a new attr reader returning InventoryCollection object
82
+ def define_collections_reader(collection_key)
83
+ define_singleton_method(collection_key) do
84
+ collections[collection_key]
85
+ end
86
+ end
87
+
88
+ def inventory_collection_builder
89
+ ::InventoryRefresh::InventoryCollection::Builder
90
+ end
91
+
92
+ # Persists InventoryCollection objects into the DB
93
+ def persist!
94
+ InventoryRefresh::SaveInventory.save_inventory(manager, inventory_collections)
95
+ end
96
+
97
+ # Returns serialized Persisted object to JSON
98
+ # @return [String] serialized Persisted object to JSON
99
+ def to_json
100
+ JSON.dump(to_hash)
101
+ end
102
+
103
+ # @return [Hash] entire Persister object serialized to hash
104
+ def to_hash
105
+ collections_data = collections.map do |_, collection|
106
+ next if collection.data.blank? &&
107
+ collection.targeted_scope.primary_references.blank? &&
108
+ collection.all_manager_uuids.nil? &&
109
+ collection.skeletal_primary_index.index_data.blank?
110
+
111
+ collection.to_hash
112
+ end.compact
113
+
114
+ {
115
+ :refresh_state_uuid => refresh_state_uuid,
116
+ :refresh_state_part_uuid => refresh_state_part_uuid,
117
+ :retry_count => retry_count,
118
+ :retry_max => retry_max,
119
+ :total_parts => total_parts,
120
+ :sweep_scope => sweep_scope,
121
+ :collections => collections_data,
122
+ }
123
+ end
124
+
125
+ class << self
126
+ # Returns Persister object loaded from a passed JSON
127
+ #
128
+ # @param json_data [String] input JSON data
129
+ # @return [ManageIQ::Providers::Inventory::Persister] Persister object loaded from a passed JSON
130
+ def from_json(json_data, manager, target = nil)
131
+ from_hash(JSON.parse(json_data), manager, target)
132
+ end
133
+
134
+ # Returns Persister object built from serialized data
135
+ #
136
+ # @param persister_data [Hash] serialized Persister object in hash
137
+ # @return [ManageIQ::Providers::Inventory::Persister] Persister object built from serialized data
138
+ def from_hash(persister_data, manager, target = nil)
139
+ # TODO(lsmola) we need to pass serialized targeted scope here
140
+ target ||= InventoryRefresh::TargetCollection.new(:manager => manager)
141
+
142
+ new(manager, target).tap do |persister|
143
+ persister_data['collections'].each do |collection|
144
+ inventory_collection = persister.collections[collection['name'].try(:to_sym)]
145
+ raise "Unrecognized InventoryCollection name: #{inventory_collection}" if inventory_collection.blank?
146
+
147
+ inventory_collection.from_hash(collection, persister.collections)
148
+ end
149
+
150
+ persister.refresh_state_uuid = persister_data['refresh_state_uuid']
151
+ persister.refresh_state_part_uuid = persister_data['refresh_state_part_uuid']
152
+ persister.retry_count = persister_data['retry_count']
153
+ persister.retry_max = persister_data['retry_max']
154
+ persister.total_parts = persister_data['total_parts']
155
+ persister.sweep_scope = persister_data['sweep_scope']
156
+ end
157
+ end
158
+ end
159
+
160
+ protected
161
+
162
+ def initialize_inventory_collections
163
+ # can be implemented in a subclass
164
+ end
165
+
166
+ # @param extra_settings [Hash]
167
+ # :auto_inventory_attributes
168
+ # - auto creates inventory_object_attributes from target model_class setters
169
+ # - attributes used in InventoryObject.add_attributes
170
+ # :without_model_class
171
+ # - if false and no model_class derived or specified, throws exception
172
+ # - doesn't try to derive model class automatically
173
+ # - @see method ManageIQ::Providers::Inventory::Persister::Builder.auto_model_class
174
+ def builder_settings(extra_settings = {})
175
+ opts = inventory_collection_builder.default_options
176
+
177
+ opts[:shared_properties] = shared_options
178
+ opts[:auto_inventory_attributes] = true
179
+ opts[:without_model_class] = false
180
+
181
+ opts.merge(extra_settings)
182
+ end
183
+
184
+ def strategy
185
+ nil
186
+ end
187
+
188
+ def saver_strategy
189
+ :default
190
+ end
191
+
192
+ # Persisters for targeted refresh can override to true
193
+ def targeted?
194
+ false
195
+ end
196
+
197
+ def assert_graph_integrity?
198
+ false
199
+ end
200
+
201
+ # @return [Hash] kwargs shared for all InventoryCollection objects
202
+ def shared_options
203
+ {
204
+ :saver_strategy => saver_strategy,
205
+ :strategy => strategy,
206
+ :targeted => targeted?,
207
+ :parent => manager.presence,
208
+ :assert_graph_integrity => assert_graph_integrity?,
209
+ }
210
+ end
211
+ end
212
+ end
@@ -1,6 +1,5 @@
1
1
  require "inventory_refresh/logging"
2
2
  require "inventory_refresh/save_collection/saver/batch"
3
- require "inventory_refresh/save_collection/saver/concurrent_safe"
4
3
  require "inventory_refresh/save_collection/saver/concurrent_safe_batch"
5
4
  require "inventory_refresh/save_collection/saver/default"
6
5
 
@@ -14,7 +13,9 @@ module InventoryRefresh::SaveCollection
14
13
  # @param ems [ExtManagementSystem] manger owning the InventoryCollection object
15
14
  # @param inventory_collection [InventoryRefresh::InventoryCollection] InventoryCollection object we want to save
16
15
  def save_inventory_object_inventory(ems, inventory_collection)
17
- logger.debug("Saving collection #{inventory_collection} of size #{inventory_collection.size} to"\
16
+ return if skip?(inventory_collection)
17
+
18
+ logger.debug("----- BEGIN ----- Saving collection #{inventory_collection} of size #{inventory_collection.size} to"\
18
19
  " the database, for the manager: '#{ems.name}'...")
19
20
 
20
21
  if inventory_collection.custom_save_block.present?
@@ -23,12 +24,26 @@ module InventoryRefresh::SaveCollection
23
24
  else
24
25
  save_inventory(inventory_collection)
25
26
  end
26
- logger.debug("Saving collection #{inventory_collection}, for the manager: '#{ems.name}'...Complete")
27
+ logger.debug("----- END ----- Saving collection #{inventory_collection}, for the manager: '#{ems.name}'...Complete")
27
28
  inventory_collection.saved = true
28
29
  end
29
30
 
30
31
  private
31
32
 
33
+ # Returns true and sets collection as saved, if the collection should be skipped.
34
+ #
35
+ # @param inventory_collection [InventoryRefresh::InventoryCollection] InventoryCollection object we want to save
36
+ # @return [Boolean] True if processing of the collection should be skipped
37
+ def skip?(inventory_collection)
38
+ if inventory_collection.noop?
39
+ logger.debug("Skipping #{inventory_collection} processing because it will do no operation.")
40
+ inventory_collection.saved = true
41
+ return true
42
+ end
43
+
44
+ false
45
+ end
46
+
32
47
  # Saves one InventoryCollection object into the DB using a configured saver_strategy class.
33
48
  #
34
49
  # @param inventory_collection [InventoryRefresh::InventoryCollection] InventoryCollection object we want to save
@@ -24,7 +24,7 @@ module InventoryRefresh::SaveCollection
24
24
  @arel_primary_key = @model_class.arel_attribute(@primary_key)
25
25
  @unique_index_keys = inventory_collection.unique_index_keys
26
26
  @unique_index_keys_to_s = inventory_collection.manager_ref_to_cols.map(&:to_s)
27
- @select_keys = [@primary_key] + @unique_index_keys_to_s
27
+ @select_keys = [@primary_key] + @unique_index_keys_to_s + internal_columns.map(&:to_s)
28
28
  @unique_db_primary_keys = Set.new
29
29
  @unique_db_indexes = Set.new
30
30
 
@@ -77,18 +77,23 @@ module InventoryRefresh::SaveCollection
77
77
  def save_inventory_collection!
78
78
  # If we have a targeted InventoryCollection that wouldn't do anything, quickly skip it
79
79
  return if inventory_collection.noop?
80
- # If we want to use delete_complement strategy using :all_manager_uuids attribute, we are skipping any other
81
- # job. We want to do 1 :delete_complement job at 1 time, to keep to memory down.
82
- return delete_complement if inventory_collection.all_manager_uuids.present?
83
80
 
84
- save!(association)
81
+ # Delete_complement strategy using :all_manager_uuids attribute
82
+ delete_complement unless inventory_collection.delete_complement_noop?
83
+
84
+ # Create/Update/Archive/Delete records based on InventoryCollection data and scope
85
+ save!(association) unless inventory_collection.saving_noop?
85
86
  end
86
87
 
87
88
  protected
88
89
 
89
90
  attr_reader :inventory_collection, :association
90
91
 
91
- delegate :build_stringified_reference, :build_stringified_reference_for_record, :to => :inventory_collection
92
+ delegate :build_stringified_reference,
93
+ :build_stringified_reference_for_record,
94
+ :resource_version_column,
95
+ :internal_columns,
96
+ :to => :inventory_collection
92
97
 
93
98
  # Applies serialize method for each relevant attribute, which will cast the value to the right type.
94
99
  #
@@ -126,6 +131,8 @@ module InventoryRefresh::SaveCollection
126
131
  :batch_size, :batch_size_for_persisting, :model_class, :serializable_keys, :deserializable_keys, :pg_types, :table_name,
127
132
  :q_table_name
128
133
 
134
+ delegate :supports_column?, :to => :inventory_collection
135
+
129
136
  # Saves the InventoryCollection
130
137
  #
131
138
  # @param association [Symbol] An existing association on manager
@@ -200,27 +207,7 @@ module InventoryRefresh::SaveCollection
200
207
 
201
208
  # Deletes a complement of referenced data
202
209
  def delete_complement
203
- return unless inventory_collection.delete_allowed?
204
-
205
- all_manager_uuids_size = inventory_collection.all_manager_uuids.size
206
-
207
- logger.debug("Processing :delete_complement of #{inventory_collection} of size "\
208
- "#{all_manager_uuids_size}...")
209
- deleted_counter = 0
210
-
211
- inventory_collection.db_collection_for_comparison_for_complement_of(
212
- inventory_collection.all_manager_uuids
213
- ).find_in_batches do |batch|
214
- ActiveRecord::Base.transaction do
215
- batch.each do |record|
216
- record.public_send(inventory_collection.delete_method)
217
- deleted_counter += 1
218
- end
219
- end
220
- end
221
-
222
- logger.debug("Processing :delete_complement of #{inventory_collection} of size "\
223
- "#{all_manager_uuids_size}, deleted=#{deleted_counter}...Complete")
210
+ raise(":delete_complement method is supported only for :saver_strategy => [:batch, :concurrent_safe_batch]")
224
211
  end
225
212
 
226
213
  # Deletes/soft-deletes a given record
@@ -299,8 +286,8 @@ module InventoryRefresh::SaveCollection
299
286
  # @param update_time [Time] data hash
300
287
  def assign_attributes_for_update!(hash, update_time)
301
288
  hash[:type] = model_class.name if supports_sti? && hash[:type].nil?
302
- hash[:updated_on] = update_time if supports_updated_on?
303
- hash[:updated_at] = update_time if supports_updated_at?
289
+ hash[:updated_on] = update_time if supports_column?(:updated_on)
290
+ hash[:updated_at] = update_time if supports_column?(:updated_at)
304
291
  end
305
292
 
306
293
  # Enriches data hash with timestamp and type columns
@@ -308,8 +295,8 @@ module InventoryRefresh::SaveCollection
308
295
  # @param hash [Hash] data hash
309
296
  # @param create_time [Time] data hash
310
297
  def assign_attributes_for_create!(hash, create_time)
311
- hash[:created_on] = create_time if supports_created_on?
312
- hash[:created_at] = create_time if supports_created_at?
298
+ hash[:created_on] = create_time if supports_column?(:created_on)
299
+ hash[:created_at] = create_time if supports_column?(:created_at)
313
300
  assign_attributes_for_update!(hash, create_time)
314
301
  end
315
302
 
@@ -343,49 +330,25 @@ module InventoryRefresh::SaveCollection
343
330
  @supports_sti_cache ||= inventory_collection.supports_sti?
344
331
  end
345
332
 
346
- # @return [Boolean] true if the model_class has created_on column
347
- def supports_created_on?
348
- @supports_created_on_cache ||= inventory_collection.supports_created_on?
349
- end
350
-
351
- # @return [Boolean] true if the model_class has updated_on column
352
- def supports_updated_on?
353
- @supports_updated_on_cache ||= inventory_collection.supports_updated_on?
354
- end
355
-
356
- # @return [Boolean] true if the model_class has created_at column
357
- def supports_created_at?
358
- @supports_created_at_cache ||= inventory_collection.supports_created_at?
359
- end
360
-
361
- # @return [Boolean] true if the model_class has updated_at column
362
- def supports_updated_at?
363
- @supports_updated_at_cache ||= inventory_collection.supports_updated_at?
364
- end
365
-
366
333
  # @return [Boolean] true if any serializable keys are present
367
334
  def serializable_keys?
368
335
  @serializable_keys_bool_cache ||= serializable_keys.present?
369
336
  end
370
337
 
371
- # @return [Boolean] true if the model_class has resource_timestamp column
338
+ # @return [Boolean] true if the keys we are saving have resource_timestamp column
372
339
  def supports_remote_data_timestamp?(all_attribute_keys)
373
340
  all_attribute_keys.include?(:resource_timestamp) # include? on Set is O(1)
374
341
  end
375
342
 
376
- # @return [Boolean] true if the model_class has resource_version column
343
+ # @return [Boolean] true if the keys we are saving have resource_counter column
377
344
  def supports_remote_data_version?(all_attribute_keys)
378
- all_attribute_keys.include?(:resource_version) # include? on Set is O(1)
379
- end
380
-
381
- # @return [Boolean] true if the model_class has resource_timestamps column
382
- def supports_resource_timestamps_max?
383
- @supports_resource_timestamps_max_cache ||= inventory_collection.supports_resource_timestamps_max?
345
+ all_attribute_keys.include?(:resource_counter) # include? on Set is O(1)
384
346
  end
385
347
 
386
- # @return [Boolean] true if the model_class has resource_versions column
387
- def supports_resource_versions_max?
388
- @supports_resource_versions_max_cache ||= inventory_collection.supports_resource_versions_max?
348
+ # @return [Boolean] true if the keys we are saving have resource_version column, which solves for a quick check
349
+ # if the record was modified
350
+ def supports_resource_version?(all_attribute_keys)
351
+ all_attribute_keys.include?(resource_version_column) # include? on Set is O(1)
389
352
  end
390
353
  end
391
354
  end