inventory_refresh 0.3.6 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +25 -30
  3. data/.github/workflows/ci.yaml +47 -0
  4. data/.rubocop.yml +3 -3
  5. data/.rubocop_cc.yml +3 -4
  6. data/.rubocop_local.yml +5 -2
  7. data/.whitesource +3 -0
  8. data/CHANGELOG.md +19 -0
  9. data/Gemfile +10 -4
  10. data/README.md +1 -2
  11. data/Rakefile +2 -2
  12. data/inventory_refresh.gemspec +8 -9
  13. data/lib/inventory_refresh/application_record_iterator.rb +25 -12
  14. data/lib/inventory_refresh/graph/topological_sort.rb +24 -26
  15. data/lib/inventory_refresh/graph.rb +2 -2
  16. data/lib/inventory_refresh/inventory_collection/builder.rb +37 -15
  17. data/lib/inventory_refresh/inventory_collection/data_storage.rb +9 -0
  18. data/lib/inventory_refresh/inventory_collection/helpers/initialize_helper.rb +147 -38
  19. data/lib/inventory_refresh/inventory_collection/helpers/questions_helper.rb +48 -4
  20. data/lib/inventory_refresh/inventory_collection/index/proxy.rb +35 -3
  21. data/lib/inventory_refresh/inventory_collection/index/type/base.rb +8 -0
  22. data/lib/inventory_refresh/inventory_collection/index/type/local_db.rb +2 -0
  23. data/lib/inventory_refresh/inventory_collection/index/type/skeletal.rb +1 -0
  24. data/lib/inventory_refresh/inventory_collection/reference.rb +1 -0
  25. data/lib/inventory_refresh/inventory_collection/references_storage.rb +17 -0
  26. data/lib/inventory_refresh/inventory_collection/scanner.rb +91 -3
  27. data/lib/inventory_refresh/inventory_collection/serialization.rb +16 -10
  28. data/lib/inventory_refresh/inventory_collection.rb +122 -64
  29. data/lib/inventory_refresh/inventory_object.rb +74 -40
  30. data/lib/inventory_refresh/inventory_object_lazy.rb +17 -10
  31. data/lib/inventory_refresh/null_logger.rb +2 -2
  32. data/lib/inventory_refresh/persister.rb +43 -93
  33. data/lib/inventory_refresh/save_collection/base.rb +4 -2
  34. data/lib/inventory_refresh/save_collection/saver/base.rb +114 -15
  35. data/lib/inventory_refresh/save_collection/saver/batch.rb +17 -0
  36. data/lib/inventory_refresh/save_collection/saver/concurrent_safe_batch.rb +129 -51
  37. data/lib/inventory_refresh/save_collection/saver/default.rb +57 -0
  38. data/lib/inventory_refresh/save_collection/saver/partial_upsert_helper.rb +2 -19
  39. data/lib/inventory_refresh/save_collection/saver/retention_helper.rb +68 -3
  40. data/lib/inventory_refresh/save_collection/saver/sql_helper.rb +125 -0
  41. data/lib/inventory_refresh/save_collection/saver/sql_helper_update.rb +10 -6
  42. data/lib/inventory_refresh/save_collection/saver/sql_helper_upsert.rb +28 -16
  43. data/lib/inventory_refresh/save_collection/sweeper.rb +17 -93
  44. data/lib/inventory_refresh/save_collection/topological_sort.rb +5 -5
  45. data/lib/inventory_refresh/save_inventory.rb +5 -12
  46. data/lib/inventory_refresh/target.rb +73 -0
  47. data/lib/inventory_refresh/target_collection.rb +92 -0
  48. data/lib/inventory_refresh/version.rb +1 -1
  49. data/lib/inventory_refresh.rb +2 -0
  50. metadata +34 -37
  51. data/.travis.yml +0 -23
  52. data/lib/inventory_refresh/exception.rb +0 -8
@@ -42,12 +42,64 @@ module InventoryRefresh
42
42
  # Transforms InventoryObject object data into hash format with keys that are column names and resolves correct
43
43
  # values of the foreign keys (even the polymorphic ones)
44
44
  #
45
- # @param data [Array<Object>] Array of objects that we want to map to DB table columns
45
+ # @param inventory_collection_scope [InventoryRefresh::InventoryCollection] parent InventoryCollection object
46
+ # @return [Hash] Data in DB format
47
+ def attributes(inventory_collection_scope = nil)
48
+ # We should explicitly pass a scope, since the inventory_object can be mapped to more InventoryCollections with
49
+ # different blacklist and whitelist. The generic code always passes a scope.
50
+ inventory_collection_scope ||= inventory_collection
51
+
52
+ attributes_for_saving = {}
53
+ # First transform the values
54
+ data.each do |key, value|
55
+ if !allowed?(inventory_collection_scope, key)
56
+ next
57
+ elsif value.kind_of?(Array) && value.any? { |x| loadable?(x) }
58
+ # Lets fill also the original data, so other InventoryObject referring to this attribute gets the right
59
+ # result
60
+ data[key] = value.compact.map(&:load).compact
61
+ # We can use built in _ids methods to assign array of ids into has_many relations. So e.g. the :key_pairs=
62
+ # relation setter will become :key_pair_ids=
63
+ attributes_for_saving["#{key.to_s.singularize}_ids".to_sym] = data[key].map(&:id).compact.uniq
64
+ elsif loadable?(value) || inventory_collection_scope.association_to_foreign_key_mapping[key]
65
+ # Lets fill also the original data, so other InventoryObject referring to this attribute gets the right
66
+ # result
67
+ data[key] = value.load if value.respond_to?(:load)
68
+ if (foreign_key = inventory_collection_scope.association_to_foreign_key_mapping[key])
69
+ # We have an association to fill, lets fill also the :key, cause some other InventoryObject can refer to it
70
+ record_id = data[key].try(:id)
71
+ attributes_for_saving[foreign_key.to_sym] = record_id
72
+
73
+ if (foreign_type = inventory_collection_scope.association_to_foreign_type_mapping[key])
74
+ # If we have a polymorphic association, we need to also fill a base class name, but we want to nullify it
75
+ # if record_id is missing
76
+ base_class = data[key].try(:base_class_name) || data[key].class.try(:base_class).try(:name)
77
+ attributes_for_saving[foreign_type.to_sym] = record_id ? base_class : nil
78
+ end
79
+ elsif data[key].kind_of?(::InventoryRefresh::InventoryObject)
80
+ # We have an association to fill but not an Activerecord association, so e.g. Ancestry, lets just load
81
+ # it here. This way of storing ancestry is ineffective in DB call count, but RAM friendly
82
+ attributes_for_saving[key.to_sym] = data[key].base_class_name.constantize.find_by(:id => data[key].id)
83
+ else
84
+ # We have a normal attribute to fill
85
+ attributes_for_saving[key.to_sym] = data[key]
86
+ end
87
+ else
88
+ attributes_for_saving[key.to_sym] = value
89
+ end
90
+ end
91
+
92
+ attributes_for_saving
93
+ end
94
+
95
+ # Transforms InventoryObject object data into hash format with keys that are column names and resolves correct
96
+ # values of the foreign keys (even the polymorphic ones)
97
+ #
46
98
  # @param inventory_collection_scope [InventoryRefresh::InventoryCollection] parent InventoryCollection object
47
99
  # @param all_attribute_keys [Array<Symbol>] Attribute keys we will modify based on object's data
48
100
  # @param inventory_object [InventoryRefresh::InventoryObject] InventoryObject object owning these attributes
49
101
  # @return [Hash] Data in DB format
50
- def self.attributes_with_keys(data, inventory_collection_scope = nil, all_attribute_keys = [], inventory_object = nil)
102
+ def attributes_with_keys(inventory_collection_scope = nil, all_attribute_keys = [], inventory_object = nil)
51
103
  # We should explicitly pass a scope, since the inventory_object can be mapped to more InventoryCollections with
52
104
  # different blacklist and whitelist. The generic code always passes a scope.
53
105
  inventory_collection_scope ||= inventory_collection
@@ -96,8 +148,8 @@ module InventoryRefresh
96
148
  def assign_attributes(attributes)
97
149
  attributes.each do |k, v|
98
150
  # We don't want timestamps or resource versions to be overwritten here, since those are driving the conditions
99
- next if %i(resource_timestamps resource_timestamps_max resource_timestamp).include?(k)
100
- next if %i(resource_counters resource_counters_max resource_counter).include?(k)
151
+ next if %i[resource_timestamps resource_timestamps_max resource_timestamp].include?(k)
152
+ next if %i[resource_counters resource_counters_max resource_counter].include?(k)
101
153
 
102
154
  if data[:resource_timestamp] && attributes[:resource_timestamp]
103
155
  assign_only_newest(:resource_timestamp, :resource_timestamps, attributes, data, k, v)
@@ -146,44 +198,14 @@ module InventoryRefresh
146
198
  end
147
199
  end
148
200
 
149
- unless defined_methods.include?(attr.to_sym)
150
- define_method(attr) do
151
- data[attr]
152
- end
201
+ next if defined_methods.include?(attr.to_sym)
202
+
203
+ define_method(attr) do
204
+ data[attr]
153
205
  end
154
206
  end
155
207
  end
156
208
 
157
- # Return true if the attribute is allowed to be saved into the DB
158
- #
159
- # @param inventory_collection_scope [InventoryRefresh::InventoryCollection] InventoryCollection object owning the
160
- # attribute
161
- # @param key [Symbol] attribute name
162
- # @return true if the attribute is allowed to be saved into the DB
163
- def self.allowed?(inventory_collection_scope, key)
164
- foreign_to_association = (inventory_collection_scope.foreign_key_to_association_mapping[key] ||
165
- inventory_collection_scope.foreign_type_to_association_mapping[key])
166
-
167
- return false if inventory_collection_scope.attributes_blacklist.present? &&
168
- (inventory_collection_scope.attributes_blacklist.include?(key) ||
169
- (foreign_to_association && inventory_collection_scope.attributes_blacklist.include?(foreign_to_association)))
170
-
171
- return false if inventory_collection_scope.attributes_whitelist.present? &&
172
- (!inventory_collection_scope.attributes_whitelist.include?(key) &&
173
- (!foreign_to_association || (foreign_to_association && inventory_collection_scope.attributes_whitelist.include?(foreign_to_association))))
174
-
175
- true
176
- end
177
-
178
- # Return true if the object is loadable, which we determine by a list of loadable classes.
179
- #
180
- # @param value [Object] object we test
181
- # @return true if the object is loadable
182
- def self.loadable?(value)
183
- value.kind_of?(::InventoryRefresh::InventoryObjectLazy) || value.kind_of?(::InventoryRefresh::InventoryObject) ||
184
- value.kind_of?(::InventoryRefresh::ApplicationRecordReference)
185
- end
186
-
187
209
  private
188
210
 
189
211
  # Assigns value based on the version attributes. If versions are specified, it asigns attribute only if it's
@@ -261,7 +283,18 @@ module InventoryRefresh
261
283
  # @param key [Symbol] attribute name
262
284
  # @return true if the attribute is allowed to be saved into the DB
263
285
  def allowed?(inventory_collection_scope, key)
264
- self.class.allowed?(inventory_collection_scope, key)
286
+ foreign_to_association = inventory_collection_scope.foreign_key_to_association_mapping[key] ||
287
+ inventory_collection_scope.foreign_type_to_association_mapping[key]
288
+
289
+ return false if inventory_collection_scope.attributes_blacklist.present? &&
290
+ (inventory_collection_scope.attributes_blacklist.include?(key) ||
291
+ (foreign_to_association && inventory_collection_scope.attributes_blacklist.include?(foreign_to_association)))
292
+
293
+ return false if inventory_collection_scope.attributes_whitelist.present? &&
294
+ (!inventory_collection_scope.attributes_whitelist.include?(key) &&
295
+ (!foreign_to_association || (foreign_to_association && inventory_collection_scope.attributes_whitelist.include?(foreign_to_association))))
296
+
297
+ true
265
298
  end
266
299
 
267
300
  # Return true if the object is loadable, which we determine by a list of loadable classes.
@@ -269,7 +302,8 @@ module InventoryRefresh
269
302
  # @param value [Object] object we test
270
303
  # @return true if the object is loadable
271
304
  def loadable?(value)
272
- self.class.loadable?(value)
305
+ value.kind_of?(::InventoryRefresh::InventoryObjectLazy) || value.kind_of?(::InventoryRefresh::InventoryObject) ||
306
+ value.kind_of?(::InventoryRefresh::ApplicationRecordReference)
273
307
  end
274
308
  end
275
309
  end
@@ -30,6 +30,7 @@ module InventoryRefresh
30
30
 
31
31
  # @return [String] stringified reference
32
32
  def to_s
33
+ # TODO(lsmola) do we need this method?
33
34
  stringified_reference
34
35
  end
35
36
 
@@ -70,6 +71,10 @@ module InventoryRefresh
70
71
 
71
72
  # @return [Boolean] true if the key is an association on inventory_collection_scope model class
72
73
  def association?(key)
74
+ # TODO(lsmola) remove this if there will be better dependency scan, probably with transitive dependencies filled
75
+ # in a second pass, then we can get rid of this hardcoded symbols. Right now we are not able to introspect these.
76
+ return true if [:parent, :genealogy_parent].include?(key)
77
+
73
78
  inventory_collection.dependency_attributes.key?(key) ||
74
79
  !inventory_collection.association_to_foreign_key_mapping[key].nil?
75
80
  end
@@ -95,7 +100,7 @@ module InventoryRefresh
95
100
 
96
101
  private
97
102
 
98
- delegate :saved?, :saver_strategy, :skeletal_primary_index, :to => :inventory_collection
103
+ delegate :parallel_safe?, :saved?, :saver_strategy, :skeletal_primary_index, :targeted?, :to => :inventory_collection
99
104
  delegate :nested_secondary_index?, :primary?, :full_reference, :keys, :primary?, :to => :reference
100
105
 
101
106
  attr_writer :reference
@@ -107,18 +112,20 @@ module InventoryRefresh
107
112
  #
108
113
  # @return [InventoryRefresh::InventoryObject, NilClass] Returns pre-created InventoryObject or nil
109
114
  def skeletal_precreate!
115
+ # We can do skeletal pre-create only for strategies using unique indexes. Since this can build records out of
116
+ # the given :arel scope, we will always attempt to create the recod, so we need unique index to avoid duplication
117
+ # of records.
118
+ return unless parallel_safe?
110
119
  # Pre-create only for strategies that will be persisting data, i.e. are not saved already
111
120
  return if saved?
112
121
  # We can only do skeletal pre-create for primary index reference, since that is needed to create DB unique index
113
- # and full reference must be present
114
- return if !primary? || full_reference.blank?
115
-
116
- # To avoid pre-creating invalid records all fields of a primary key must have non null value
117
- # TODO(lsmola) for composite keys, it's still valid to have one of the keys nil, figure out how to allow this. We
118
- # will need to scan the DB for NOT NULL constraint and allow it based on that. So we would move this check to
119
- # saving code, but this will require bigger change, since having the column nil means we will have to batch it
120
- # smartly, since having nil means we will need to use different unique index for the upsert/update query.
121
- return if keys.any? { |x| full_reference[x].nil? }
122
+ return unless primary?
123
+ # Full reference must be present
124
+ return if full_reference.blank?
125
+
126
+ # To avoid pre-creating invalid records all fields of a primary key must have value
127
+ # TODO(lsmola) for composite keys, it's still valid to have one of the keys nil, figure out how to allow this
128
+ return if keys.any? { |x| full_reference[x].blank? }
122
129
 
123
130
  skeletal_primary_index.build(full_reference)
124
131
  end
@@ -3,10 +3,10 @@ require "logger"
3
3
  module InventoryRefresh
4
4
  class NullLogger < Logger
5
5
  def initialize(*_args)
6
- end
6
+ end
7
7
 
8
8
  def add(*_args, &_block)
9
- end
9
+ end
10
10
 
11
11
  def debug?
12
12
  false
@@ -3,21 +3,18 @@ module InventoryRefresh
3
3
  require 'json'
4
4
  require 'yaml'
5
5
 
6
- attr_reader :manager, :collections
6
+ attr_reader :manager, :target, :collections
7
7
 
8
- attr_accessor :refresh_state_uuid, :refresh_state_part_uuid, :refresh_time_tracking, :total_parts, :sweep_scope, :retry_count, :retry_max
9
- attr_accessor :persister_started_at, :persister_finished_at,
10
- :refresh_state_part_collected_at, :refresh_state_part_sent_at,
11
- :refresh_state_started_at, :refresh_state_sent_at, :ingress_api_sent_at
8
+ attr_accessor :refresh_state_uuid, :refresh_state_part_uuid, :total_parts, :sweep_scope, :retry_count, :retry_max
12
9
 
13
10
  # @param manager [ManageIQ::Providers::BaseManager] A manager object
14
- def initialize(manager)
11
+ # @param target [Object] A refresh Target object
12
+ def initialize(manager, target = nil)
15
13
  @manager = manager
14
+ @target = target
16
15
 
17
16
  @collections = {}
18
17
 
19
- self.persister_started_at = Time.now.utc.to_datetime.to_s
20
-
21
18
  initialize_inventory_collections
22
19
  end
23
20
 
@@ -48,6 +45,9 @@ module InventoryRefresh
48
45
  &block)
49
46
 
50
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
51
  builder.evaluate_lambdas!(self)
52
52
 
53
53
  collections[collection_name] = builder.to_inventory_collection
@@ -66,7 +66,7 @@ module InventoryRefresh
66
66
  # @return [InventoryRefresh::InventoryCollection] returns a defined InventoryCollection or undefined method
67
67
  def method_missing(method_name, *arguments, &block)
68
68
  if inventory_collections_names.include?(method_name)
69
- self.define_collections_reader(method_name)
69
+ define_collections_reader(method_name)
70
70
  send(method_name)
71
71
  else
72
72
  super
@@ -96,7 +96,7 @@ module InventoryRefresh
96
96
 
97
97
  # Returns serialized Persisted object to JSON
98
98
  # @return [String] serialized Persisted object to JSON
99
- def to_json
99
+ def to_json(*_args)
100
100
  JSON.dump(to_hash)
101
101
  end
102
102
 
@@ -104,25 +104,21 @@ module InventoryRefresh
104
104
  def to_hash
105
105
  collections_data = collections.map do |_, collection|
106
106
  next if collection.data.blank? &&
107
+ collection.targeted_scope.primary_references.blank? &&
108
+ collection.all_manager_uuids.nil? &&
107
109
  collection.skeletal_primary_index.index_data.blank?
108
110
 
109
111
  collection.to_hash
110
112
  end.compact
111
113
 
112
114
  {
113
- :refresh_state_uuid => refresh_state_uuid,
114
- :refresh_state_part_uuid => refresh_state_part_uuid,
115
- :refresh_state_part_collected_at => refresh_state_part_collected_at,
116
- :refresh_state_part_sent_at => refresh_state_part_sent_at,
117
- :refresh_state_started_at => refresh_state_started_at,
118
- :refresh_state_sent_at => refresh_state_sent_at,
119
- :ingress_api_sent_at => ingress_api_sent_at,
120
- :refresh_time_tracking => refresh_time_tracking,
121
- :retry_count => retry_count,
122
- :retry_max => retry_max,
123
- :total_parts => total_parts,
124
- :sweep_scope => sweep_scope_to_hash(sweep_scope),
125
- :collections => collections_data,
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,
126
122
  }
127
123
  end
128
124
 
@@ -131,70 +127,33 @@ module InventoryRefresh
131
127
  #
132
128
  # @param json_data [String] input JSON data
133
129
  # @return [ManageIQ::Providers::Inventory::Persister] Persister object loaded from a passed JSON
134
- def from_json(json_data, manager)
135
- from_hash(JSON.parse(json_data), manager)
130
+ def from_json(json_data, manager, target = nil)
131
+ from_hash(JSON.parse(json_data), manager, target)
136
132
  end
137
133
 
138
134
  # Returns Persister object built from serialized data
139
135
  #
140
136
  # @param persister_data [Hash] serialized Persister object in hash
141
137
  # @return [ManageIQ::Providers::Inventory::Persister] Persister object built from serialized data
142
- def from_hash(persister_data, manager)
143
- new(manager).tap do |persister|
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|
144
143
  persister_data['collections'].each do |collection|
145
144
  inventory_collection = persister.collections[collection['name'].try(:to_sym)]
146
- raise "Unrecognized InventoryCollection name: #{collection['name']}" if inventory_collection.blank?
145
+ raise "Unrecognized InventoryCollection name: #{inventory_collection}" if inventory_collection.blank?
147
146
 
148
147
  inventory_collection.from_hash(collection, persister.collections)
149
148
  end
150
149
 
151
- persister.refresh_state_uuid = persister_data['refresh_state_uuid']
152
- persister.refresh_state_part_uuid = persister_data['refresh_state_part_uuid']
153
- persister.refresh_state_part_collected_at = persister_data['refresh_state_part_collected_at']
154
- persister.refresh_state_part_sent_at = persister_data['refresh_state_part_sent_at']
155
- persister.refresh_state_started_at = persister_data['refresh_state_started_at']
156
- persister.refresh_state_sent_at = persister_data['refresh_state_sent_at']
157
- persister.ingress_api_sent_at = persister_data['ingress_api_sent_at']
158
- persister.retry_count = persister_data['retry_count']
159
- persister.retry_max = persister_data['retry_max']
160
- persister.total_parts = persister_data['total_parts']
161
- persister.sweep_scope = sweep_scope_from_hash(persister_data['sweep_scope'], persister.collections)
162
- end
163
- end
164
-
165
- private
166
-
167
- def assert_sweep_scope!(sweep_scope)
168
- return unless sweep_scope
169
-
170
- allowed_format_message = "Allowed format of sweep scope is Array<String> or Hash{String => Hash}, got #{sweep_scope}"
171
-
172
- if sweep_scope.kind_of?(Array)
173
- return if sweep_scope.all? { |x| x.kind_of?(String) || x.kind_of?(Symbol) }
174
-
175
- raise InventoryRefresh::Exception::SweeperScopeBadFormat, allowed_format_message
176
- elsif sweep_scope.kind_of?(Hash)
177
- return if sweep_scope.values.all? { |x| x.kind_of?(Array) }
178
-
179
- raise InventoryRefresh::Exception::SweeperScopeBadFormat, allowed_format_message
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']
180
156
  end
181
-
182
- raise InventoryRefresh::Exception::SweeperScopeBadFormat, allowed_format_message
183
- end
184
-
185
- def sweep_scope_from_hash(sweep_scope, available_inventory_collections)
186
- assert_sweep_scope!(sweep_scope)
187
-
188
- return sweep_scope unless sweep_scope.kind_of?(Hash)
189
-
190
- sweep_scope.each_with_object({}) do |(k, v), obj|
191
- inventory_collection = available_inventory_collections[k.try(:to_sym)]
192
- raise "Unrecognized InventoryCollection name: #{k}" if inventory_collection.blank?
193
-
194
- serializer = InventoryRefresh::InventoryCollection::Serialization.new(inventory_collection)
195
-
196
- obj[k] = serializer.sweep_scope_from_hash(v, available_inventory_collections)
197
- end.symbolize_keys!
198
157
  end
199
158
  end
200
159
 
@@ -226,37 +185,28 @@ module InventoryRefresh
226
185
  nil
227
186
  end
228
187
 
229
- def assert_graph_integrity?
188
+ def saver_strategy
189
+ :default
190
+ end
191
+
192
+ # Persisters for targeted refresh can override to true
193
+ def targeted?
230
194
  false
231
195
  end
232
196
 
233
- def use_ar_object?
234
- true
197
+ def assert_graph_integrity?
198
+ false
235
199
  end
236
200
 
237
201
  # @return [Hash] kwargs shared for all InventoryCollection objects
238
202
  def shared_options
239
203
  {
204
+ :saver_strategy => saver_strategy,
240
205
  :strategy => strategy,
206
+ :targeted => targeted?,
241
207
  :parent => manager.presence,
242
208
  :assert_graph_integrity => assert_graph_integrity?,
243
- :use_ar_object => use_ar_object?,
244
209
  }
245
210
  end
246
-
247
- private
248
-
249
- def sweep_scope_to_hash(sweep_scope)
250
- return sweep_scope unless sweep_scope.kind_of?(Hash)
251
-
252
- sweep_scope.each_with_object({}) do |(k, v), obj|
253
- inventory_collection = collections[k.try(:to_sym)]
254
- raise "Unrecognized InventoryCollection name: #{k}" if inventory_collection.blank?
255
-
256
- serializer = InventoryRefresh::InventoryCollection::Serialization.new(inventory_collection)
257
-
258
- obj[k] = serializer.sweep_scope_to_hash(v)
259
- end
260
- end
261
211
  end
262
212
  end
@@ -1,5 +1,7 @@
1
1
  require "inventory_refresh/logging"
2
+ require "inventory_refresh/save_collection/saver/batch"
2
3
  require "inventory_refresh/save_collection/saver/concurrent_safe_batch"
4
+ require "inventory_refresh/save_collection/saver/default"
3
5
 
4
6
  module InventoryRefresh::SaveCollection
5
7
  class Base
@@ -14,7 +16,7 @@ module InventoryRefresh::SaveCollection
14
16
  return if skip?(inventory_collection)
15
17
 
16
18
  logger.debug("----- BEGIN ----- Saving collection #{inventory_collection} of size #{inventory_collection.size} to"\
17
- " the database, for the manager: '#{ems.id}'...")
19
+ " the database, for the manager: '#{ems.name}'...")
18
20
 
19
21
  if inventory_collection.custom_save_block.present?
20
22
  logger.debug("Saving collection #{inventory_collection} using a custom save block")
@@ -22,7 +24,7 @@ module InventoryRefresh::SaveCollection
22
24
  else
23
25
  save_inventory(inventory_collection)
24
26
  end
25
- logger.debug("----- END ----- Saving collection #{inventory_collection}, for the manager: '#{ems.id}'...Complete")
27
+ logger.debug("----- END ----- Saving collection #{inventory_collection}, for the manager: '#{ems.name}'...Complete")
26
28
  inventory_collection.saved = true
27
29
  end
28
30