inventory_refresh 0.2.2 → 0.3.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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +0 -1
- data/.travis.yml +6 -8
- data/inventory_refresh.gemspec +2 -4
- data/lib/inventory_refresh.rb +0 -2
- data/lib/inventory_refresh/application_record_iterator.rb +9 -26
- data/lib/inventory_refresh/exception.rb +8 -0
- data/lib/inventory_refresh/inventory_collection.rb +36 -110
- data/lib/inventory_refresh/inventory_collection/builder.rb +6 -6
- data/lib/inventory_refresh/inventory_collection/data_storage.rb +0 -9
- data/lib/inventory_refresh/inventory_collection/helpers/initialize_helper.rb +34 -143
- data/lib/inventory_refresh/inventory_collection/helpers/questions_helper.rb +1 -44
- data/lib/inventory_refresh/inventory_collection/index/proxy.rb +6 -34
- data/lib/inventory_refresh/inventory_collection/index/type/base.rb +0 -8
- data/lib/inventory_refresh/inventory_collection/references_storage.rb +0 -17
- data/lib/inventory_refresh/inventory_collection/scanner.rb +1 -87
- data/lib/inventory_refresh/inventory_collection/serialization.rb +10 -16
- data/lib/inventory_refresh/inventory_object.rb +34 -68
- data/lib/inventory_refresh/inventory_object_lazy.rb +10 -17
- data/lib/inventory_refresh/persister.rb +63 -29
- data/lib/inventory_refresh/save_collection/base.rb +2 -4
- data/lib/inventory_refresh/save_collection/saver/base.rb +8 -108
- data/lib/inventory_refresh/save_collection/saver/concurrent_safe_batch.rb +48 -126
- data/lib/inventory_refresh/save_collection/saver/partial_upsert_helper.rb +19 -1
- data/lib/inventory_refresh/save_collection/saver/retention_helper.rb +3 -68
- data/lib/inventory_refresh/save_collection/saver/sql_helper.rb +0 -125
- data/lib/inventory_refresh/save_collection/saver/sql_helper_update.rb +5 -9
- data/lib/inventory_refresh/save_collection/saver/sql_helper_upsert.rb +9 -17
- data/lib/inventory_refresh/save_collection/sweeper.rb +91 -18
- data/lib/inventory_refresh/save_collection/topological_sort.rb +5 -5
- data/lib/inventory_refresh/save_inventory.rb +12 -5
- data/lib/inventory_refresh/version.rb +1 -1
- metadata +9 -45
- data/lib/inventory_refresh/save_collection/saver/batch.rb +0 -17
- data/lib/inventory_refresh/save_collection/saver/default.rb +0 -57
- data/lib/inventory_refresh/target.rb +0 -73
- data/lib/inventory_refresh/target_collection.rb +0 -92
@@ -50,11 +50,6 @@ module InventoryRefresh
|
|
50
50
|
dependencies.all?(&:saved?)
|
51
51
|
end
|
52
52
|
|
53
|
-
# @return [Boolean] true if we are using a saver strategy that allows saving in parallel processes
|
54
|
-
def parallel_safe?
|
55
|
-
@parallel_safe_cache ||= %i(concurrent_safe concurrent_safe_batch).include?(saver_strategy)
|
56
|
-
end
|
57
|
-
|
58
53
|
# @return [Boolean] true if the model_class supports STI
|
59
54
|
def supports_sti?
|
60
55
|
@supports_sti_cache = model_class.column_names.include?("type") if @supports_sti_cache.nil?
|
@@ -81,50 +76,12 @@ module InventoryRefresh
|
|
81
76
|
data_collection_finalized
|
82
77
|
end
|
83
78
|
|
84
|
-
# @return [Boolean] true is processing of this InventoryCollection will be in targeted mode
|
85
|
-
def targeted?
|
86
|
-
targeted
|
87
|
-
end
|
88
|
-
|
89
79
|
# True if processing of this InventoryCollection object would lead to no operations. Then we use this marker to
|
90
80
|
# stop processing of the InventoryCollector object very soon, to avoid a lot of unnecessary Db queries, etc.
|
91
81
|
#
|
92
82
|
# @return [Boolean] true if processing of this InventoryCollection object would lead to no operations.
|
93
83
|
def noop?
|
94
|
-
|
95
|
-
saving_noop? && delete_complement_noop?
|
96
|
-
end
|
97
|
-
|
98
|
-
# @return [Boolean] true if processing InventoryCollection will not lead to any created/updated/deleted record
|
99
|
-
def saving_noop?
|
100
|
-
saving_targeted_parent_collection_noop? || saving_targeted_child_collection_noop? || saving_full_collection_noop?
|
101
|
-
end
|
102
|
-
|
103
|
-
# @return true if processing InventoryCollection will not lead to deleting the complement of passed ids
|
104
|
-
def delete_complement_noop?
|
105
|
-
all_manager_uuids.nil?
|
106
|
-
end
|
107
|
-
|
108
|
-
private
|
109
|
-
|
110
|
-
# @return true if it's a noop parent targeted InventoryCollection
|
111
|
-
def saving_targeted_parent_collection_noop?
|
112
|
-
targeted_noop_condition && parent_inventory_collections.blank? && targeted_scope.primary_references.blank?
|
113
|
-
end
|
114
|
-
|
115
|
-
# @return true if it's a noop child targeted InventoryCollection
|
116
|
-
def saving_targeted_child_collection_noop?
|
117
|
-
targeted_noop_condition && parent_inventory_collections.present? &&
|
118
|
-
parent_inventory_collections.all? { |x| x.targeted_scope.primary_references.blank? }
|
119
|
-
end
|
120
|
-
|
121
|
-
# @return true if it's a noop full InventoryCollection refresh
|
122
|
-
def saving_full_collection_noop?
|
123
|
-
!targeted? && data.blank? && !delete_allowed? && skeletal_primary_index.blank?
|
124
|
-
end
|
125
|
-
|
126
|
-
def targeted_noop_condition
|
127
|
-
targeted? && custom_save_block.nil? && skeletal_primary_index.blank?
|
84
|
+
data.blank? && custom_save_block.nil? && skeletal_primary_index.blank?
|
128
85
|
end
|
129
86
|
end
|
130
87
|
end
|
@@ -64,14 +64,6 @@ module InventoryRefresh
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
-
def reindex_secondary_indexes!
|
68
|
-
data_indexes.each do |ref, index|
|
69
|
-
next if ref == primary_index_ref
|
70
|
-
|
71
|
-
index.reindex!
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
67
|
def primary_index
|
76
68
|
data_index(primary_index_ref)
|
77
69
|
end
|
@@ -94,30 +86,16 @@ module InventoryRefresh
|
|
94
86
|
end
|
95
87
|
end
|
96
88
|
|
97
|
-
def find_by(manager_uuid_hash, ref: primary_index_ref)
|
98
|
-
# TODO(lsmola) deprecate this, it's enough to have find method
|
99
|
-
find(manager_uuid_hash, :ref => ref)
|
100
|
-
end
|
101
|
-
|
102
|
-
def lazy_find_by(manager_uuid_hash, ref: primary_index_ref, key: nil, default: nil)
|
103
|
-
# TODO(lsmola) deprecate this, it's enough to have lazy_find method
|
104
|
-
|
105
|
-
lazy_find(manager_uuid_hash, :ref => ref, :key => key, :default => default)
|
106
|
-
end
|
107
|
-
|
108
89
|
def lazy_find(manager_uuid, ref: primary_index_ref, key: nil, default: nil, transform_nested_lazy_finds: false)
|
109
|
-
# TODO(lsmola) also, it should be enough to have only 1 find method, everything can be lazy, until we try to
|
110
|
-
# access the data
|
111
|
-
# TODO(lsmola) lazy_find will support only hash, then we can remove the _by variant
|
112
90
|
return if manager_uuid.nil?
|
113
91
|
assert_index(manager_uuid, ref)
|
114
92
|
|
115
93
|
::InventoryRefresh::InventoryObjectLazy.new(inventory_collection,
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
94
|
+
manager_uuid,
|
95
|
+
:ref => ref,
|
96
|
+
:key => key,
|
97
|
+
:default => default,
|
98
|
+
:transform_nested_lazy_finds => transform_nested_lazy_finds)
|
121
99
|
end
|
122
100
|
|
123
101
|
def named_ref(ref = primary_index_ref)
|
@@ -132,19 +110,13 @@ module InventoryRefresh
|
|
132
110
|
|
133
111
|
delegate :association_to_foreign_key_mapping,
|
134
112
|
:build_stringified_reference,
|
135
|
-
:parallel_safe?,
|
136
113
|
:strategy,
|
137
114
|
:to => :inventory_collection
|
138
115
|
|
139
116
|
attr_reader :all_refs, :data_indexes, :inventory_collection, :primary_ref, :local_db_indexes, :secondary_refs
|
140
117
|
|
141
118
|
def find_in_data_or_skeletal_index(reference)
|
142
|
-
|
143
|
-
# With parallel safe strategies, we create skeletal nodes that we can look for
|
144
|
-
data_index_find(reference) || skeletal_index_find(reference)
|
145
|
-
else
|
146
|
-
data_index_find(reference)
|
147
|
-
end
|
119
|
+
data_index_find(reference) || skeletal_index_find(reference)
|
148
120
|
end
|
149
121
|
|
150
122
|
def skeletal_index_find(reference)
|
@@ -27,14 +27,6 @@ module InventoryRefresh
|
|
27
27
|
index[build_stringified_reference(inventory_object.data, attribute_names)] = inventory_object
|
28
28
|
end
|
29
29
|
|
30
|
-
# Rebuilds the indexes for all InventoryObject objects
|
31
|
-
def reindex!
|
32
|
-
self.index = {}
|
33
|
-
data.each do |inventory_object|
|
34
|
-
store_index_for(inventory_object)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
30
|
# @return [Array] Returns index data
|
39
31
|
def index_data
|
40
32
|
index.values
|
@@ -45,23 +45,6 @@ module InventoryRefresh
|
|
45
45
|
add_reference(reference_data)
|
46
46
|
end
|
47
47
|
|
48
|
-
# Adds array of references to the storage. The reference can be already existing, otherwise we attempt to build
|
49
|
-
# it.
|
50
|
-
#
|
51
|
-
# @param references_array [Array] Array of reference objects acceptable by add_reference method.
|
52
|
-
# @param ref [Symbol] A key to specific reference, if it's a reference pointing to something else than primary
|
53
|
-
# index.
|
54
|
-
# @return [InventoryRefresh::InventoryCollection::ReferencesStorage] Returns self
|
55
|
-
def merge!(references_array, ref: nil)
|
56
|
-
references_array.each { |reference_data| add_reference(reference_data, :ref => ref) }
|
57
|
-
self
|
58
|
-
end
|
59
|
-
|
60
|
-
# @return [Hash{String => InventoryRefresh::InventoryCollection::Reference}] Hash of indexed Reference objects
|
61
|
-
def primary_references
|
62
|
-
references[primary_index_ref]
|
63
|
-
end
|
64
|
-
|
65
48
|
# Builds a Reference object
|
66
49
|
#
|
67
50
|
# @param reference_data [InventoryRefresh::InventoryCollection::References, Hash, Object] Either existing Reference
|
@@ -41,7 +41,6 @@ module InventoryRefresh
|
|
41
41
|
# Boolean helpers the scanner uses from the :inventory_collection
|
42
42
|
delegate :inventory_object_lazy?,
|
43
43
|
:inventory_object?,
|
44
|
-
:targeted?,
|
45
44
|
:to => :inventory_collection
|
46
45
|
|
47
46
|
# Methods the scanner uses from the :inventory_collection
|
@@ -52,18 +51,13 @@ module InventoryRefresh
|
|
52
51
|
:to => :inventory_collection
|
53
52
|
|
54
53
|
# The data scanner modifies inside of the :inventory_collection
|
55
|
-
delegate :
|
56
|
-
:association,
|
54
|
+
delegate :association,
|
57
55
|
:arel,
|
58
56
|
:attribute_references,
|
59
57
|
:custom_save_block,
|
60
58
|
:data_collection_finalized=,
|
61
59
|
:dependency_attributes,
|
62
|
-
:targeted?,
|
63
|
-
:targeted_scope,
|
64
60
|
:parent,
|
65
|
-
:parent_inventory_collections,
|
66
|
-
:parent_inventory_collections=,
|
67
61
|
:references,
|
68
62
|
:transitive_dependency_attributes,
|
69
63
|
:to => :inventory_collection
|
@@ -78,11 +72,6 @@ module InventoryRefresh
|
|
78
72
|
# Scan InventoryCollection InventoryObjects and store the results inside of the InventoryCollection
|
79
73
|
data.each do |inventory_object|
|
80
74
|
scan_inventory_object!(inventory_object)
|
81
|
-
|
82
|
-
if targeted? && parent_inventory_collections.blank?
|
83
|
-
# We want to track what manager_uuids we should query from a db, for the targeted refresh
|
84
|
-
targeted_scope << inventory_object.reference
|
85
|
-
end
|
86
75
|
end
|
87
76
|
|
88
77
|
# Scan InventoryCollection skeletal data
|
@@ -90,80 +79,12 @@ module InventoryRefresh
|
|
90
79
|
scan_inventory_object!(inventory_object)
|
91
80
|
end
|
92
81
|
|
93
|
-
build_parent_inventory_collections!
|
94
|
-
scan_all_manager_uuids_scope!
|
95
|
-
|
96
82
|
# Mark InventoryCollection as finalized aka. scanned
|
97
83
|
self.data_collection_finalized = true
|
98
84
|
end
|
99
85
|
|
100
86
|
private
|
101
87
|
|
102
|
-
def scan_all_manager_uuids_scope!
|
103
|
-
return if all_manager_uuids_scope.nil?
|
104
|
-
|
105
|
-
all_manager_uuids_scope.each do |scope|
|
106
|
-
scope.each_value do |value|
|
107
|
-
scan_all_manager_uuids_scope_attribute!(value)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def build_parent_inventory_collections!
|
113
|
-
if parent_inventory_collections.nil?
|
114
|
-
build_parent_inventory_collection!
|
115
|
-
else
|
116
|
-
# We can't figure out what immediate parent is, we'll add parent_inventory_collections as dependencies
|
117
|
-
parent_inventory_collections.each { |ic_name| add_parent_inventory_collection_dependency!(ic_name) }
|
118
|
-
end
|
119
|
-
|
120
|
-
return if parent_inventory_collections.blank?
|
121
|
-
|
122
|
-
# Transform InventoryCollection object names to actual objects
|
123
|
-
self.parent_inventory_collections = parent_inventory_collections.map { |x| load_inventory_collection_by_name(x) }
|
124
|
-
end
|
125
|
-
|
126
|
-
def build_parent_inventory_collection!
|
127
|
-
return unless supports_building_inventory_collection?
|
128
|
-
|
129
|
-
if association.present? && parent.present? && associations_hash[association].present?
|
130
|
-
# Add immediate parent IC as dependency
|
131
|
-
add_parent_inventory_collection_dependency!(associations_hash[association])
|
132
|
-
# Add root IC in parent_inventory_collections
|
133
|
-
self.parent_inventory_collections = [find_parent_inventory_collection(associations_hash, inventory_collection.association)]
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def supports_building_inventory_collection?
|
138
|
-
# Don't try to introspect ICs with custom query or saving code
|
139
|
-
return if arel.present? || custom_save_block.present?
|
140
|
-
# We support :parent_inventory_collections only for targeted mode, where all ICs are present
|
141
|
-
return unless targeted?
|
142
|
-
|
143
|
-
true
|
144
|
-
end
|
145
|
-
|
146
|
-
def add_parent_inventory_collection_dependency!(ic_name)
|
147
|
-
ic = load_inventory_collection_by_name(ic_name)
|
148
|
-
(dependency_attributes[:__parent_inventory_collections] ||= Set.new) << ic if ic
|
149
|
-
end
|
150
|
-
|
151
|
-
def find_parent_inventory_collection(hash, name)
|
152
|
-
if hash[name]
|
153
|
-
find_parent_inventory_collection(hash, hash[name])
|
154
|
-
else
|
155
|
-
name
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
def load_inventory_collection_by_name(name)
|
160
|
-
ic = indexed_inventory_collections[name]
|
161
|
-
if ic.nil?
|
162
|
-
raise "Can't find InventoryCollection :#{name} referenced from #{inventory_collection}" if targeted?
|
163
|
-
end
|
164
|
-
ic
|
165
|
-
end
|
166
|
-
|
167
88
|
def scan_inventory_object!(inventory_object)
|
168
89
|
inventory_object.data.each do |key, value|
|
169
90
|
if value.kind_of?(Array)
|
@@ -182,13 +103,6 @@ module InventoryRefresh
|
|
182
103
|
value_inventory_collection.add_reference(value.reference, :key => value.key)
|
183
104
|
end
|
184
105
|
|
185
|
-
def scan_all_manager_uuids_scope_attribute!(value)
|
186
|
-
return unless loadable?(value)
|
187
|
-
|
188
|
-
add_reference(value.inventory_collection, value)
|
189
|
-
(dependency_attributes[:__all_manager_uuids_scope] ||= Set.new) << value.inventory_collection
|
190
|
-
end
|
191
|
-
|
192
106
|
def scan_inventory_object_attribute!(key, value)
|
193
107
|
return unless loadable?(value)
|
194
108
|
value_inventory_collection = value.inventory_collection
|
@@ -3,10 +3,7 @@ require "active_support/core_ext/module/delegation"
|
|
3
3
|
module InventoryRefresh
|
4
4
|
class InventoryCollection
|
5
5
|
class Serialization
|
6
|
-
delegate :
|
7
|
-
:all_manager_uuids=,
|
8
|
-
:build,
|
9
|
-
:targeted_scope,
|
6
|
+
delegate :build,
|
10
7
|
:data,
|
11
8
|
:inventory_object_lazy?,
|
12
9
|
:inventory_object?,
|
@@ -28,8 +25,6 @@ module InventoryRefresh
|
|
28
25
|
# @param available_inventory_collections [Array<InventoryRefresh::InventoryCollection>] List of available
|
29
26
|
# InventoryCollection objects
|
30
27
|
def from_hash(inventory_objects_data, available_inventory_collections)
|
31
|
-
targeted_scope.merge!(inventory_objects_data["manager_uuids"].map(&:symbolize_keys!)) if inventory_objects_data["manager_uuids"]
|
32
|
-
|
33
28
|
(inventory_objects_data['data'] || []).each do |inventory_object_data|
|
34
29
|
build(hash_to_data(inventory_object_data, available_inventory_collections).symbolize_keys!)
|
35
30
|
end
|
@@ -37,8 +32,12 @@ module InventoryRefresh
|
|
37
32
|
(inventory_objects_data['partial_data'] || []).each do |inventory_object_data|
|
38
33
|
skeletal_primary_index.build(hash_to_data(inventory_object_data, available_inventory_collections).symbolize_keys!)
|
39
34
|
end
|
35
|
+
end
|
40
36
|
|
41
|
-
|
37
|
+
def sweep_scope_from_hash(sweep_scope, available_inventory_collections)
|
38
|
+
sweep_scope.map do |s|
|
39
|
+
hash_to_data(s, available_inventory_collections).symbolize_keys!
|
40
|
+
end
|
42
41
|
end
|
43
42
|
|
44
43
|
# Serializes InventoryCollection's data storage into Array of Hashes
|
@@ -47,14 +46,15 @@ module InventoryRefresh
|
|
47
46
|
def to_hash
|
48
47
|
{
|
49
48
|
:name => name,
|
50
|
-
# TODO(lsmola) we do not support nested references here, should we?
|
51
|
-
:manager_uuids => targeted_scope.primary_references.values.map(&:full_reference),
|
52
|
-
:all_manager_uuids => all_manager_uuids,
|
53
49
|
:data => data.map { |x| data_to_hash(x.data) },
|
54
50
|
:partial_data => skeletal_primary_index.index_data.map { |x| data_to_hash(x.data) },
|
55
51
|
}
|
56
52
|
end
|
57
53
|
|
54
|
+
def sweep_scope_to_hash(sweep_scope)
|
55
|
+
sweep_scope.map { |x| data_to_hash(x) }
|
56
|
+
end
|
57
|
+
|
58
58
|
private
|
59
59
|
|
60
60
|
# Converts InventoryRefresh::InventoryObject or InventoryRefresh::InventoryObjectLazy into Hash
|
@@ -107,10 +107,6 @@ module InventoryRefresh
|
|
107
107
|
hash.transform_values do |value|
|
108
108
|
if value.kind_of?(Hash) && value['inventory_collection_name']
|
109
109
|
hash_to_lazy_relation(value, available_inventory_collections, depth)
|
110
|
-
elsif value.kind_of?(Array) && value.first.kind_of?(Hash) && value.first['inventory_collection_name']
|
111
|
-
# TODO(lsmola) do we need to compact it sooner? What if first element is nil? On the other hand, we want to
|
112
|
-
# deprecate this Vm HABTM assignment because it's not effective
|
113
|
-
value.compact.map { |x| hash_to_lazy_relation(x, available_inventory_collections, depth) }
|
114
110
|
else
|
115
111
|
value
|
116
112
|
end
|
@@ -128,8 +124,6 @@ module InventoryRefresh
|
|
128
124
|
data.transform_values do |value|
|
129
125
|
if inventory_object_lazy?(value) || inventory_object?(value)
|
130
126
|
lazy_relation_to_hash(value, depth)
|
131
|
-
elsif value.kind_of?(Array) && (inventory_object_lazy?(value.compact.first) || inventory_object?(value.compact.first))
|
132
|
-
value.compact.map { |x| lazy_relation_to_hash(x, depth) }
|
133
127
|
else
|
134
128
|
value
|
135
129
|
end
|
@@ -42,64 +42,12 @@ 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
|
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
|
-
#
|
45
|
+
# @param data [Array<Object>] Array of objects that we want to map to DB table columns
|
98
46
|
# @param inventory_collection_scope [InventoryRefresh::InventoryCollection] parent InventoryCollection object
|
99
47
|
# @param all_attribute_keys [Array<Symbol>] Attribute keys we will modify based on object's data
|
100
48
|
# @param inventory_object [InventoryRefresh::InventoryObject] InventoryObject object owning these attributes
|
101
49
|
# @return [Hash] Data in DB format
|
102
|
-
def attributes_with_keys(inventory_collection_scope = nil, all_attribute_keys = [], inventory_object = nil)
|
50
|
+
def self.attributes_with_keys(data, inventory_collection_scope = nil, all_attribute_keys = [], inventory_object = nil)
|
103
51
|
# We should explicitly pass a scope, since the inventory_object can be mapped to more InventoryCollections with
|
104
52
|
# different blacklist and whitelist. The generic code always passes a scope.
|
105
53
|
inventory_collection_scope ||= inventory_collection
|
@@ -206,6 +154,36 @@ module InventoryRefresh
|
|
206
154
|
end
|
207
155
|
end
|
208
156
|
|
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
|
+
|
209
187
|
private
|
210
188
|
|
211
189
|
# Assigns value based on the version attributes. If versions are specified, it asigns attribute only if it's
|
@@ -283,18 +261,7 @@ module InventoryRefresh
|
|
283
261
|
# @param key [Symbol] attribute name
|
284
262
|
# @return true if the attribute is allowed to be saved into the DB
|
285
263
|
def allowed?(inventory_collection_scope, key)
|
286
|
-
|
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
|
264
|
+
self.class.allowed?(inventory_collection_scope, key)
|
298
265
|
end
|
299
266
|
|
300
267
|
# Return true if the object is loadable, which we determine by a list of loadable classes.
|
@@ -302,8 +269,7 @@ module InventoryRefresh
|
|
302
269
|
# @param value [Object] object we test
|
303
270
|
# @return true if the object is loadable
|
304
271
|
def loadable?(value)
|
305
|
-
|
306
|
-
value.kind_of?(::InventoryRefresh::ApplicationRecordReference)
|
272
|
+
self.class.loadable?(value)
|
307
273
|
end
|
308
274
|
end
|
309
275
|
end
|