Class: RedisMemo::MemoizeQuery::Invalidation

Inherits:
Object
  • Object
show all
Defined in:
lib/redis_memo/memoize_query/invalidation.rb

Overview

Automatically invalidate memoizable when modifying ActiveRecords objects. You still need to invalidate memos when you are using SQL queries to perform update / delete (does not trigger record callbacks)

Class Method Summary collapse

Class Method Details

.install(model_class) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/redis_memo/memoize_query/invalidation.rb', line 9

def self.install(model_class)
  var_name = :@@__redis_memo_memoize_query_invalidation_installed__
  return if model_class.class_variable_defined?(var_name)

  model_class.class_eval do
    # A memory-persistent memoizable used for invalidating all queries of a
    # particular model
    def self.redis_memo_class_memoizable
      @redis_memo_class_memoizable ||= RedisMemo::MemoizeQuery.create_memo(self)
    end

    %i(delete decrement! increment!).each do |method_name|
      alias_method :"without_redis_memo_invalidation_#{method_name}", method_name

      define_method method_name do |*args|
        result = send(:"without_redis_memo_invalidation_#{method_name}", *args)

        RedisMemo::MemoizeQuery.invalidate(self)

        result
      end
    end
  end

  # Methods that won't trigger model callbacks
  # https://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks
  %i(
    decrement_counter
    delete_all delete_by
    increment_counter
    touch_all
    update_column update_columns update_all update_counters
  ).each do |method_name|
    # Example: Model.update_all
    rewrite_default_method(
      model_class,
      model_class,
      method_name,
      class_method: true,
    )

    # Example: Model.where(...).update_all
    rewrite_default_method(
      model_class,
      model_class.const_get(:ActiveRecord_Relation),
      method_name,
      class_method: false,
    )
  end

  %i(
    insert insert! insert_all insert_all!
  ).each do |method_name|
    rewrite_insert_method(
      model_class,
      method_name,
    )
  end

  %i(
    upsert upsert_all
  ).each do |method_name|
    rewrite_upsert_method(
      model_class,
      method_name,
    )
  end

  %i(
    import import!
  ).each do |method_name|
    rewrite_import_method(
      model_class,
      method_name,
    )
  end

  model_class.class_variable_set(var_name, true)
end

.invalidate_new_records(model_class, &blk) ⇒ Object



89
90
91
92
93
94
95
# File 'lib/redis_memo/memoize_query/invalidation.rb', line 89

def self.invalidate_new_records(model_class, &blk)
  current_id = model_class.maximum(model_class.primary_key)
  result = blk.call
  records = select_by_new_ids(model_class, current_id)
  RedisMemo::MemoizeQuery.invalidate(*records) unless records.empty?
  result
end

.invalidate_records_by_conflict_target(model_class, records:, conflict_target: nil, &blk) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/redis_memo/memoize_query/invalidation.rb', line 97

def self.invalidate_records_by_conflict_target(model_class, records:, conflict_target: nil, &blk)
  if conflict_target.nil?
    # When the conflict_target is not set, we are basically inserting new
    # records since duplicate rows are simply skipped
    return invalidate_new_records(model_class, &blk)
  end

  relation = build_relation_by_conflict_target(model_class, records, conflict_target)
  # Invalidate records before updating
  records = select_by_conflict_target_relation(model_class, relation)
  RedisMemo::MemoizeQuery.invalidate(*records) unless records.empty?

  # Perform updating
  result = blk.call

  # Invalidate records after updating
  records = select_by_conflict_target_relation(model_class, relation)
  RedisMemo::MemoizeQuery.invalidate(*records) unless records.empty?

  result
end