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.
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