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.
- checksums.yaml +4 -4
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/bundler.d/.gitkeep +0 -0
- data/inventory_refresh.gemspec +4 -4
- data/lib/inventory_refresh/inventory_collection/builder.rb +249 -0
- data/lib/inventory_refresh/inventory_collection/graph.rb +0 -15
- data/lib/inventory_refresh/inventory_collection/helpers/associations_helper.rb +80 -0
- data/lib/inventory_refresh/inventory_collection/helpers/initialize_helper.rb +456 -0
- data/lib/inventory_refresh/inventory_collection/helpers/questions_helper.rb +132 -0
- data/lib/inventory_refresh/inventory_collection/helpers.rb +6 -0
- data/lib/inventory_refresh/inventory_collection/index/type/skeletal.rb +5 -5
- data/lib/inventory_refresh/inventory_collection/reference.rb +4 -0
- data/lib/inventory_refresh/inventory_collection/scanner.rb +111 -18
- data/lib/inventory_refresh/inventory_collection/serialization.rb +7 -7
- data/lib/inventory_refresh/inventory_collection/unconnected_edge.rb +19 -0
- data/lib/inventory_refresh/inventory_collection.rb +114 -649
- data/lib/inventory_refresh/inventory_object.rb +17 -11
- data/lib/inventory_refresh/inventory_object_lazy.rb +20 -10
- data/lib/inventory_refresh/persister.rb +212 -0
- data/lib/inventory_refresh/save_collection/base.rb +18 -3
- data/lib/inventory_refresh/save_collection/saver/base.rb +25 -62
- data/lib/inventory_refresh/save_collection/saver/concurrent_safe_batch.rb +73 -225
- data/lib/inventory_refresh/save_collection/saver/partial_upsert_helper.rb +226 -0
- data/lib/inventory_refresh/save_collection/saver/retention_helper.rb +115 -0
- data/lib/inventory_refresh/save_collection/saver/sql_helper.rb +122 -0
- data/lib/inventory_refresh/save_collection/saver/sql_helper_update.rb +24 -5
- data/lib/inventory_refresh/save_collection/saver/sql_helper_upsert.rb +6 -6
- data/lib/inventory_refresh/save_collection/sweeper.rb +69 -0
- data/lib/inventory_refresh/save_inventory.rb +18 -8
- data/lib/inventory_refresh/target_collection.rb +12 -0
- data/lib/inventory_refresh/version.rb +1 -1
- data/lib/inventory_refresh.rb +1 -0
- metadata +24 -15
- data/lib/inventory_refresh/save_collection/recursive.rb +0 -52
- 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(
|
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[:
|
151
|
-
assign_only_newest(:
|
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[:
|
160
|
-
assign_full_row_version_attr(:
|
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, :
|
215
|
+
# [:resource_timestamp, :resource_counter]
|
210
216
|
# @param partial_row_version_attr [Symbol] Attr name for partial rows, allowed values are
|
211
|
-
# [:resource_timestamps, :
|
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, :
|
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
|
-
|
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
|
-
|
135
|
-
|
136
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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,
|
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
|
-
|
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
|
303
|
-
hash[:updated_at] = update_time if
|
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
|
312
|
-
hash[:created_at] = create_time if
|
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
|
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
|
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?(:
|
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
|
387
|
-
|
388
|
-
|
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
|