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
@@ -13,7 +13,7 @@ module InventoryRefresh
|
|
13
13
|
indexed_inventory_collections = inventory_collections.index_by(&:name)
|
14
14
|
|
15
15
|
inventory_collections.each do |inventory_collection|
|
16
|
-
new(inventory_collection, indexed_inventory_collections).scan!
|
16
|
+
new(inventory_collection, indexed_inventory_collections, build_association_hash(inventory_collections)).scan!
|
17
17
|
end
|
18
18
|
|
19
19
|
inventory_collections.each do |inventory_collection|
|
@@ -22,9 +22,21 @@ module InventoryRefresh
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
25
|
+
|
26
|
+
def build_association_hash(inventory_collections)
|
27
|
+
associations_hash = {}
|
28
|
+
parents = inventory_collections.map(&:parent).compact.uniq
|
29
|
+
parents.each do |parent|
|
30
|
+
parent.class.reflect_on_all_associations(:has_many).each do |association|
|
31
|
+
through_assoc = association.options.try(:[], :through)
|
32
|
+
associations_hash[association.name] = through_assoc if association.options.try(:[], :through)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
associations_hash
|
36
|
+
end
|
25
37
|
end
|
26
38
|
|
27
|
-
attr_reader :inventory_collection, :indexed_inventory_collections
|
39
|
+
attr_reader :associations_hash, :inventory_collection, :indexed_inventory_collections
|
28
40
|
|
29
41
|
# Boolean helpers the scanner uses from the :inventory_collection
|
30
42
|
delegate :inventory_object_lazy?,
|
@@ -40,19 +52,26 @@ module InventoryRefresh
|
|
40
52
|
:to => :inventory_collection
|
41
53
|
|
42
54
|
# The data scanner modifies inside of the :inventory_collection
|
43
|
-
delegate :
|
55
|
+
delegate :all_manager_uuids_scope,
|
56
|
+
:association,
|
57
|
+
:arel,
|
58
|
+
:attribute_references,
|
59
|
+
:custom_save_block,
|
44
60
|
:data_collection_finalized=,
|
45
61
|
:dependency_attributes,
|
62
|
+
:targeted?,
|
46
63
|
:targeted_scope,
|
64
|
+
:parent,
|
47
65
|
:parent_inventory_collections,
|
48
66
|
:parent_inventory_collections=,
|
49
67
|
:references,
|
50
68
|
:transitive_dependency_attributes,
|
51
69
|
:to => :inventory_collection
|
52
70
|
|
53
|
-
def initialize(inventory_collection, indexed_inventory_collections)
|
71
|
+
def initialize(inventory_collection, indexed_inventory_collections, associations_hash)
|
54
72
|
@inventory_collection = inventory_collection
|
55
73
|
@indexed_inventory_collections = indexed_inventory_collections
|
74
|
+
@associations_hash = associations_hash
|
56
75
|
end
|
57
76
|
|
58
77
|
def scan!
|
@@ -66,26 +85,85 @@ module InventoryRefresh
|
|
66
85
|
end
|
67
86
|
end
|
68
87
|
|
69
|
-
#
|
70
|
-
|
71
|
-
|
72
|
-
ic = indexed_inventory_collections[inventory_collection_index]
|
73
|
-
if ic.nil?
|
74
|
-
raise "Can't find InventoryCollection #{inventory_collection_index} from #{inventory_collection}" if targeted?
|
75
|
-
else
|
76
|
-
# Add parent_inventory_collection as a dependency, so e.g. disconnect is done in a right order
|
77
|
-
(dependency_attributes[:__parent_inventory_collections] ||= Set.new) << ic
|
78
|
-
ic
|
79
|
-
end
|
80
|
-
end.compact
|
88
|
+
# Scan InventoryCollection skeletal data
|
89
|
+
inventory_collection.skeletal_primary_index.each_value do |inventory_object|
|
90
|
+
scan_inventory_object!(inventory_object)
|
81
91
|
end
|
82
92
|
|
93
|
+
build_parent_inventory_collections!
|
94
|
+
scan_all_manager_uuids_scope!
|
95
|
+
|
83
96
|
# Mark InventoryCollection as finalized aka. scanned
|
84
97
|
self.data_collection_finalized = true
|
85
98
|
end
|
86
99
|
|
87
100
|
private
|
88
101
|
|
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
|
+
|
89
167
|
def scan_inventory_object!(inventory_object)
|
90
168
|
inventory_object.data.each do |key, value|
|
91
169
|
if value.kind_of?(Array)
|
@@ -96,8 +174,23 @@ module InventoryRefresh
|
|
96
174
|
end
|
97
175
|
end
|
98
176
|
|
177
|
+
def loadable?(value)
|
178
|
+
inventory_object_lazy?(value) || inventory_object?(value)
|
179
|
+
end
|
180
|
+
|
181
|
+
def add_reference(value_inventory_collection, value)
|
182
|
+
value_inventory_collection.add_reference(value.reference, :key => value.key)
|
183
|
+
end
|
184
|
+
|
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
|
+
|
99
192
|
def scan_inventory_object_attribute!(key, value)
|
100
|
-
return
|
193
|
+
return unless loadable?(value)
|
101
194
|
value_inventory_collection = value.inventory_collection
|
102
195
|
|
103
196
|
# Storing attributes and their dependencies
|
@@ -105,7 +198,7 @@ module InventoryRefresh
|
|
105
198
|
|
106
199
|
# Storing a reference in the target inventory_collection, then each IC knows about all the references and can
|
107
200
|
# e.g. load all the referenced uuids from a DB
|
108
|
-
|
201
|
+
add_reference(value_inventory_collection, value)
|
109
202
|
|
110
203
|
if inventory_object_lazy?(value)
|
111
204
|
# Storing if attribute is a transitive dependency, so a lazy_find :key results in dependency
|
@@ -4,6 +4,7 @@ module InventoryRefresh
|
|
4
4
|
class InventoryCollection
|
5
5
|
class Serialization
|
6
6
|
delegate :all_manager_uuids,
|
7
|
+
:all_manager_uuids=,
|
7
8
|
:build,
|
8
9
|
:targeted_scope,
|
9
10
|
:data,
|
@@ -27,18 +28,17 @@ module InventoryRefresh
|
|
27
28
|
# @param available_inventory_collections [Array<InventoryRefresh::InventoryCollection>] List of available
|
28
29
|
# InventoryCollection objects
|
29
30
|
def from_hash(inventory_objects_data, available_inventory_collections)
|
30
|
-
targeted_scope.merge!(inventory_objects_data["manager_uuids"].map(&:symbolize_keys!))
|
31
|
+
targeted_scope.merge!(inventory_objects_data["manager_uuids"].map(&:symbolize_keys!)) if inventory_objects_data["manager_uuids"]
|
31
32
|
|
32
|
-
inventory_objects_data['data'].each do |inventory_object_data|
|
33
|
+
(inventory_objects_data['data'] || []).each do |inventory_object_data|
|
33
34
|
build(hash_to_data(inventory_object_data, available_inventory_collections).symbolize_keys!)
|
34
35
|
end
|
35
36
|
|
36
|
-
inventory_objects_data['partial_data'].each do |inventory_object_data|
|
37
|
+
(inventory_objects_data['partial_data'] || []).each do |inventory_object_data|
|
37
38
|
skeletal_primary_index.build(hash_to_data(inventory_object_data, available_inventory_collections).symbolize_keys!)
|
38
39
|
end
|
39
40
|
|
40
|
-
|
41
|
-
# self.all_manager_uuids = inventory_objects_data['all_manager_uuids']
|
41
|
+
self.all_manager_uuids = inventory_objects_data['all_manager_uuids']
|
42
42
|
end
|
43
43
|
|
44
44
|
# Serializes InventoryCollection's data storage into Array of Hashes
|
@@ -105,9 +105,9 @@ module InventoryRefresh
|
|
105
105
|
raise "Nested lazy_relation of #{inventory_collection} is too deep, left processing: #{hash}" if depth > 20
|
106
106
|
|
107
107
|
hash.transform_values do |value|
|
108
|
-
if value.kind_of?(Hash) && value['
|
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['
|
110
|
+
elsif value.kind_of?(Array) && value.first.kind_of?(Hash) && value.first['inventory_collection_name']
|
111
111
|
# TODO(lsmola) do we need to compact it sooner? What if first element is nil? On the other hand, we want to
|
112
112
|
# deprecate this Vm HABTM assignment because it's not effective
|
113
113
|
value.compact.map { |x| hash_to_lazy_relation(x, available_inventory_collections, depth) }
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "active_support/core_ext/module/delegation"
|
2
|
+
|
3
|
+
module InventoryRefresh
|
4
|
+
class InventoryCollection
|
5
|
+
class UnconnectedEdge
|
6
|
+
attr_reader :inventory_object, :inventory_object_key, :inventory_object_lazy
|
7
|
+
|
8
|
+
# @param inventory_object [InventoryRefresh::InventoryObject] InventoryObject that couldn't connect the relation
|
9
|
+
# @param inventory_object_key [String] Relation name that couldn't be connected
|
10
|
+
# @param inventory_object_lazy [InventoryRefresh::InventoryObjectLazy] The lazy relation that failed to load
|
11
|
+
# this can happen only for relations with key, or pointing to DB only relations
|
12
|
+
def initialize(inventory_object, inventory_object_key, inventory_object_lazy)
|
13
|
+
@inventory_object = inventory_object
|
14
|
+
@inventory_object_key = inventory_object_key
|
15
|
+
@inventory_object_lazy = inventory_object_lazy
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|