inventory_refresh 0.1.1 → 0.2.2
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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +1 -0
- data/.gitignore +6 -0
- data/.travis.yml +3 -3
- data/Gemfile +4 -0
- data/inventory_refresh.gemspec +7 -5
- data/lib/inventory_refresh.rb +1 -0
- data/lib/inventory_refresh/inventory_collection.rb +115 -646
- 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.rb +6 -0
- 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/index/proxy.rb +1 -1
- 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_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 +27 -64
- 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
- metadata +61 -19
- data/lib/inventory_refresh/save_collection/recursive.rb +0 -52
- data/lib/inventory_refresh/save_collection/saver/concurrent_safe.rb +0 -71
@@ -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
|
@@ -247,7 +234,7 @@ module InventoryRefresh::SaveCollection
|
|
247
234
|
# Change the InventoryCollection's :association or :arel parameter to return distinct results. The :through
|
248
235
|
# relations can return the same record multiple times. We don't want to do SELECT DISTINCT by default, since
|
249
236
|
# it can be very slow.
|
250
|
-
|
237
|
+
unless inventory_collection.assert_graph_integrity
|
251
238
|
logger.warn("Please update :association or :arel for #{inventory_collection} to return a DISTINCT result. "\
|
252
239
|
" The duplicate value is being ignored.")
|
253
240
|
return false
|
@@ -273,7 +260,7 @@ module InventoryRefresh::SaveCollection
|
|
273
260
|
subject = "#{hash} of #{inventory_collection} because of missing foreign key #{x} for "\
|
274
261
|
"#{inventory_collection.parent.class.name}:"\
|
275
262
|
"#{inventory_collection.parent.try(:id)}"
|
276
|
-
|
263
|
+
unless inventory_collection.assert_graph_integrity
|
277
264
|
logger.warn("Referential integrity check violated, ignoring #{subject}")
|
278
265
|
return false
|
279
266
|
else
|
@@ -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
|