Class: Upkeep::Subscriptions::ReverseIndex

Inherits:
Object
  • Object
show all
Defined in:
lib/upkeep/subscriptions/reverse_index.rb

Defined Under Namespace

Classes: Entry

Constant Summary collapse

COHORT_IDENTITY_SOURCES =
%w[Current.user cookie current_attribute session warden_user].freeze

Instance Method Summary collapse

Constructor Details

#initializeReverseIndex

Returns a new instance of ReverseIndex.



18
19
20
21
22
23
24
25
# File 'lib/upkeep/subscriptions/reverse_index.rb', line 18

def initialize
  @entries_by_lookup_key = Hash.new { |hash, key| hash[key] = [] }
  @entry_keys_by_lookup_key = Hash.new { |hash, key| hash[key] = {} }
  @lookup_keys_by_subscription_id = Hash.new { |hash, key| hash[key] = {} }
  @cohort_entries_by_index_key = {}
  @cohort_members_by_index_key = Hash.new { |hash, key| hash[key] = {} }
  @cohort_index_keys_by_subscription_id = Hash.new { |hash, key| hash[key] = {} }
end

Instance Method Details

#delete_subscription(subscription_id) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/upkeep/subscriptions/reverse_index.rb', line 45

def delete_subscription(subscription_id)
  lookup_keys = @lookup_keys_by_subscription_id.delete(subscription_id)&.keys || []
  lookup_keys.each do |lookup_key|
    entries = @entries_by_lookup_key.fetch(lookup_key, nil)
    next unless entries

    entries.reject! { |entry| entry.subscription_id == subscription_id }
    @entry_keys_by_lookup_key[lookup_key].delete_if { |entry_key, _present| entry_key.fetch(0) == subscription_id }

    next unless entries.empty?

    @entries_by_lookup_key.delete(lookup_key)
    @entry_keys_by_lookup_key.delete(lookup_key)
  end

  cohort_index_keys = @cohort_index_keys_by_subscription_id.delete(subscription_id)&.keys || []
  cohort_index_keys.each { |index_key| delete_cohort_subscription(index_key, subscription_id) }
end

#entries_for(changes) ⇒ Object



64
65
66
67
68
69
70
71
# File 'lib/upkeep/subscriptions/reverse_index.rb', line 64

def entries_for(changes)
  raw_entries = changes
    .flat_map { |change| lookup_keys_for_change(change) }
    .flat_map { |lookup_key| @entries_by_lookup_key.fetch(lookup_key, []) }
    .uniq { |entry| [entry.subscription_id, entry.owner_id, entry.dependency_cache_key] }

  collapse_cohort_entries(raw_entries)
end

#entries_for_subscription(subscription) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/upkeep/subscriptions/reverse_index.rb', line 80

def entries_for_subscription(subscription)
  subscription.recorder.flush_pending_dependencies if subscription.recorder.respond_to?(:flush_pending_dependencies)
  cohort_key = cohort_key_for(subscription)
  subscription.graph.dependency_nodes.flat_map do |node|
    subscription.graph.dependency_owner_ids(node.id).map do |owner_id|
      Entry.new(
        subscription.id,
        owner_id,
        node.payload.cache_key,
        node.payload,
        [subscription.subscriber_id],
        cohort_key
      )
    end
  end
end

#entries_for_subscription_instance(entries, subscription) ⇒ Object



97
98
99
# File 'lib/upkeep/subscriptions/reverse_index.rb', line 97

def entries_for_subscription_instance(entries, subscription)
  entries.map { |entry| entry_for_subscription(entry, subscription) }
end

#index(subscription) ⇒ Object



27
28
29
# File 'lib/upkeep/subscriptions/reverse_index.rb', line 27

def index(subscription)
  index_entries(entries_for_subscription(subscription))
end

#index_entries(entries, subscription: nil) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/upkeep/subscriptions/reverse_index.rb', line 31

def index_entries(entries, subscription: nil)
  entries = entries_for_subscription_instance(entries, subscription) if subscription

  entries.each do |entry|
    lookup_keys_for_dependency(entry.dependency).each do |lookup_key|
      if entry.cohort?
        index_cohort_entry(lookup_key, entry)
      else
        index_direct_entry(lookup_key, entry)
      end
    end
  end
end

#lookup_keys_for_change(change) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/upkeep/subscriptions/reverse_index.rb', line 112

def lookup_keys_for_change(change)
  table = change.fetch(:table)
  attributes = change.fetch(:changed_attributes, [])

  keys = attributes.map do |attribute|
    if change[:id]
      [:active_record_attribute, table, change.fetch(:id), attribute]
    else
      [:active_record_attribute_any_id, table, attribute]
    end
  end

  keys.concat(attributes.map { |attribute| [:active_record_collection_column, table, attribute] })
  keys.uniq
end

#lookup_keys_for_dependency(dependency) ⇒ Object



101
102
103
104
105
106
107
108
109
110
# File 'lib/upkeep/subscriptions/reverse_index.rb', line 101

def lookup_keys_for_dependency(dependency)
  case dependency.source
  when :active_record_attribute
    active_record_attribute_lookup_keys(dependency.key)
  when :active_record_collection, :active_record_query
    active_record_collection_lookup_keys(dependency)
  else
    []
  end
end

#summaryObject



73
74
75
76
77
78
# File 'lib/upkeep/subscriptions/reverse_index.rb', line 73

def summary
  {
    lookup_keys: @entries_by_lookup_key.size,
    entries: @entries_by_lookup_key.values.sum(&:size)
  }
end