Class: InventoryRefresh::SaveCollection::Sweeper

Inherits:
Base
  • Object
show all
Includes:
InventoryRefresh::SaveCollection::Saver::RetentionHelper
Defined in:
lib/inventory_refresh/save_collection/sweeper.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

save_inventory_object_inventory

Methods included from Logging

#logger

Constructor Details

#initialize(inventory_collection, refresh_state, sweep_scope) ⇒ Sweeper

Returns a new instance of Sweeper.



56
57
58
59
60
61
62
63
64
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 56

def initialize(inventory_collection, refresh_state, sweep_scope)
  @inventory_collection = inventory_collection

  @refresh_state = refresh_state
  @sweep_scope   = sweep_scope

  @model_class = inventory_collection.model_class
  @primary_key = @model_class.primary_key
end

Instance Attribute Details

#inventory_collectionObject (readonly)

Returns the value of attribute inventory_collection.



50
51
52
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 50

def inventory_collection
  @inventory_collection
end

#model_classObject (readonly)

Returns the value of attribute model_class.



50
51
52
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 50

def model_class
  @model_class
end

#primary_keyObject (readonly)

Returns the value of attribute primary_key.



50
51
52
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 50

def primary_key
  @primary_key
end

#refresh_stateObject (readonly)

Returns the value of attribute refresh_state.



50
51
52
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 50

def refresh_state
  @refresh_state
end

#sweep_scopeObject (readonly)

Returns the value of attribute sweep_scope.



50
51
52
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 50

def sweep_scope
  @sweep_scope
end

Class Method Details

.build_scope_set(sweep_scope) ⇒ Object



37
38
39
40
41
42
43
44
45
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 37

def build_scope_set(sweep_scope)
  return [] unless sweep_scope

  if sweep_scope.kind_of?(Array)
    sweep_scope.map(&:to_sym).to_set
  elsif sweep_scope.kind_of?(Hash)
    sweep_scope.keys.map(&:to_sym).to_set
  end
end

.in_scope?(inventory_collection, scope_set) ⇒ Boolean

Returns:

  • (Boolean)


33
34
35
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 33

def in_scope?(inventory_collection, scope_set)
  scope_set.include?(inventory_collection&.name)
end

.sweep(_ems, inventory_collections, sweep_scope, refresh_state) ⇒ Object

Sweeps inactive records based on :last_seen_on and :refresh_start timestamps. All records having :last_seen_on lower than :refresh_start or nil will be archived/deleted.

Parameters:

  • _ems (ActiveRecord)

    Manager owning the inventory_collections

  • inventory_collections (Array<InventoryRefresh::InventoryCollection>)

    Array of InventoryCollection objects for sweeping

  • sweep_scope (Array<String, Symbol, Hash>)

    Array of inventory collection names marking sweep. Or for targeted sweeping it’s array of hashes, where key is inventory collection name pointing to an array of identifiers of inventory objects we want to target for sweeping.

  • refresh_state (ActiveRecord)

    Record of :refresh_states



19
20
21
22
23
24
25
26
27
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 19

def sweep(_ems, inventory_collections, sweep_scope, refresh_state)
  scope_set = build_scope_set(sweep_scope)

  inventory_collections.each do |inventory_collection|
    next unless sweep_possible?(inventory_collection, scope_set)

    new(inventory_collection, refresh_state, sweep_scope).sweep
  end
end

.sweep_possible?(inventory_collection, scope_set) ⇒ Boolean

Returns:

  • (Boolean)


29
30
31
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 29

def sweep_possible?(inventory_collection, scope_set)
  inventory_collection.supports_column?(:last_seen_at) && in_scope?(inventory_collection, scope_set)
end

Instance Method Details

#apply_targeted_sweep_scope(all_entities_query) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 66

def apply_targeted_sweep_scope(all_entities_query)
  if sweep_scope.kind_of?(Hash)
    scope = sweep_scope[inventory_collection.name]
    return all_entities_query if scope.nil? || scope.empty?

    # Scan the scope to find all references, so we can load them from DB in batches
    scan_sweep_scope!(scope)

    scope_keys = Set.new
    conditions = scope.map { |x| InventoryRefresh::InventoryObject.attributes_with_keys(x, inventory_collection, scope_keys) }
    assert_conditions!(conditions, scope_keys)

    all_entities_query.where(inventory_collection.build_multi_selection_condition(conditions, scope_keys))
  else
    all_entities_query
  end
end

#assert_conditions!(conditions, scope_keys) ⇒ Object



99
100
101
102
103
104
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 99

def assert_conditions!(conditions, scope_keys)
  conditions.each do |cond|
    assert_uniform_keys!(cond, scope_keys)
    assert_non_existent_keys!(cond)
  end
end

#assert_non_existent_keys!(cond) ⇒ Object



115
116
117
118
119
120
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 115

def assert_non_existent_keys!(cond)
  return if (diff = (cond.keys.to_set - inventory_collection.all_column_names)).empty?

  raise(InventoryRefresh::Exception::SweeperNonExistentScopeKeyFoundError,
        "Sweeping scope for #{inventory_collection} contained keys that are not columns: #{diff.to_a}")
end

#assert_uniform_keys!(cond, scope_keys) ⇒ Object



106
107
108
109
110
111
112
113
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 106

def assert_uniform_keys!(cond, scope_keys)
  return if (diff = (scope_keys - cond.keys.to_set)).empty?

  raise(InventoryRefresh::Exception::SweeperNonUniformScopeKeyFoundError,
        "Sweeping scope for #{inventory_collection} contained non uniform keys. All keys for the"\
        "scope must be the same, it's possible to send multiple sweeps with different key set. Missing keys"\
        " for a scope were: #{diff.to_a}")
end

#loadable?(value) ⇒ Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 84

def loadable?(value)
  inventory_object_lazy?(value) || inventory_object?(value)
end

#scan_sweep_scope!(scope) ⇒ Object



88
89
90
91
92
93
94
95
96
97
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 88

def scan_sweep_scope!(scope)
  scope.each do |sc|
    sc.each_value do |value|
      next unless loadable?(value)

      value_inventory_collection = value.inventory_collection
      value_inventory_collection.add_reference(value.reference, :key => value.key)
    end
  end
end

#sweepObject



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/inventory_refresh/save_collection/sweeper.rb', line 122

def sweep
  refresh_start = refresh_state.created_at
  raise "Couldn't load :created_at out of RefreshState record: #{refresh_state}" unless refresh_start

  table       = model_class.arel_table
  date_field  = table[:last_seen_at]
  all_entities_query = inventory_collection.full_collection_for_comparison
  all_entities_query = all_entities_query.active if inventory_collection.retention_strategy == :archive && inventory_collection.supports_column?(:archived_at)

  all_entities_query = apply_targeted_sweep_scope(all_entities_query)

  query = all_entities_query
          .where(date_field.lt(refresh_start)).or(all_entities_query.where(:last_seen_at => nil))
          .select(table[:id])

  query.find_in_batches do |batch|
    destroy_records!(batch)
  end
end