inventory_refresh 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/Gemfile +4 -0
  4. data/bundler.d/.gitkeep +0 -0
  5. data/inventory_refresh.gemspec +4 -4
  6. data/lib/inventory_refresh/inventory_collection/builder.rb +249 -0
  7. data/lib/inventory_refresh/inventory_collection/graph.rb +0 -15
  8. data/lib/inventory_refresh/inventory_collection/helpers/associations_helper.rb +80 -0
  9. data/lib/inventory_refresh/inventory_collection/helpers/initialize_helper.rb +456 -0
  10. data/lib/inventory_refresh/inventory_collection/helpers/questions_helper.rb +132 -0
  11. data/lib/inventory_refresh/inventory_collection/helpers.rb +6 -0
  12. data/lib/inventory_refresh/inventory_collection/index/type/skeletal.rb +5 -5
  13. data/lib/inventory_refresh/inventory_collection/reference.rb +4 -0
  14. data/lib/inventory_refresh/inventory_collection/scanner.rb +111 -18
  15. data/lib/inventory_refresh/inventory_collection/serialization.rb +7 -7
  16. data/lib/inventory_refresh/inventory_collection/unconnected_edge.rb +19 -0
  17. data/lib/inventory_refresh/inventory_collection.rb +114 -649
  18. data/lib/inventory_refresh/inventory_object.rb +17 -11
  19. data/lib/inventory_refresh/inventory_object_lazy.rb +20 -10
  20. data/lib/inventory_refresh/persister.rb +212 -0
  21. data/lib/inventory_refresh/save_collection/base.rb +18 -3
  22. data/lib/inventory_refresh/save_collection/saver/base.rb +25 -62
  23. data/lib/inventory_refresh/save_collection/saver/concurrent_safe_batch.rb +73 -225
  24. data/lib/inventory_refresh/save_collection/saver/partial_upsert_helper.rb +226 -0
  25. data/lib/inventory_refresh/save_collection/saver/retention_helper.rb +115 -0
  26. data/lib/inventory_refresh/save_collection/saver/sql_helper.rb +122 -0
  27. data/lib/inventory_refresh/save_collection/saver/sql_helper_update.rb +24 -5
  28. data/lib/inventory_refresh/save_collection/saver/sql_helper_upsert.rb +6 -6
  29. data/lib/inventory_refresh/save_collection/sweeper.rb +69 -0
  30. data/lib/inventory_refresh/save_inventory.rb +18 -8
  31. data/lib/inventory_refresh/target_collection.rb +12 -0
  32. data/lib/inventory_refresh/version.rb +1 -1
  33. data/lib/inventory_refresh.rb +1 -0
  34. metadata +24 -15
  35. data/lib/inventory_refresh/save_collection/recursive.rb +0 -52
  36. 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 :attribute_references,
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
- # Transform :parent_inventory_collections symbols to InventoryCollection objects
70
- if parent_inventory_collections.present?
71
- self.parent_inventory_collections = parent_inventory_collections.map do |inventory_collection_index|
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 if !inventory_object_lazy?(value) && !inventory_object?(value)
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
- value_inventory_collection.add_reference(value.reference, :key => value.key)
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
- # TODO(lsmola) add support for all_manager_uuids serialization
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['type'] == "InventoryRefresh::InventoryObjectLazy"
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['type'] == "InventoryRefresh::InventoryObjectLazy"
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