Class: Flipper::Adapters::Memoizable

Inherits:
Object
  • Object
show all
Includes:
Flipper::Adapter
Defined in:
lib/flipper/adapters/memoizable.rb

Overview

Internal: Adapter that wraps another adapter with the ability to memoize adapter calls in memory. Used by flipper dsl and the memoizer middleware to make it possible to memoize adapter calls for the duration of a request.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Flipper::Adapter

#default_config, included, #name

Constructor Details

#initialize(adapter, cache = nil) ⇒ Memoizable

Public



18
19
20
21
22
23
24
# File 'lib/flipper/adapters/memoizable.rb', line 18

def initialize(adapter, cache = nil)
  @adapter = adapter
  @cache = cache || {}
  @memoize = false
  @features_key = :flipper_features
  @get_all_key = :all_memoized
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object



142
143
144
# File 'lib/flipper/adapters/memoizable.rb', line 142

def method_missing(name, *args, **kwargs, &block)
  @adapter.send name, *args, **kwargs, &block
end

Instance Attribute Details

#adapterObject (readonly)

Internal: The adapter this adapter is wrapping.



15
16
17
# File 'lib/flipper/adapters/memoizable.rb', line 15

def adapter
  @adapter
end

#cacheObject (readonly)

Internal



12
13
14
# File 'lib/flipper/adapters/memoizable.rb', line 12

def cache
  @cache
end

Instance Method Details

#add(feature) ⇒ Object

Public



36
37
38
# File 'lib/flipper/adapters/memoizable.rb', line 36

def add(feature)
  @adapter.add(feature).tap { expire_features_set }
end

#clear(feature) ⇒ Object

Public



49
50
51
# File 'lib/flipper/adapters/memoizable.rb', line 49

def clear(feature)
  @adapter.clear(feature).tap { expire_feature(feature) }
end

#disable(feature, gate, thing) ⇒ Object

Public



116
117
118
# File 'lib/flipper/adapters/memoizable.rb', line 116

def disable(feature, gate, thing)
  @adapter.disable(feature, gate, thing).tap { expire_feature(feature) }
end

#enable(feature, gate, thing) ⇒ Object

Public



111
112
113
# File 'lib/flipper/adapters/memoizable.rb', line 111

def enable(feature, gate, thing)
  @adapter.enable(feature, gate, thing).tap { expire_feature(feature) }
end

#export(format: :json, version: 1) ⇒ Object



124
125
126
# File 'lib/flipper/adapters/memoizable.rb', line 124

def export(format: :json, version: 1)
  @adapter.export(format: format, version: version)
end

#featuresObject

Public



27
28
29
30
31
32
33
# File 'lib/flipper/adapters/memoizable.rb', line 27

def features
  if memoizing?
    cache.fetch(@features_key) { cache[@features_key] = @adapter.features }
  else
    @adapter.features
  end
end

#get(feature) ⇒ Object

Public



54
55
56
57
58
59
60
# File 'lib/flipper/adapters/memoizable.rb', line 54

def get(feature)
  if memoizing?
    cache.fetch(key_for(feature.key)) { cache[key_for(feature.key)] = @adapter.get(feature) }
  else
    @adapter.get(feature)
  end
end

#get_allObject



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/flipper/adapters/memoizable.rb', line 84

def get_all
  if memoizing?
    response = nil
    if cache[@get_all_key]
      response = {}
      cache[@features_key].each do |key|
        response[key] = cache[key_for(key)]
      end
    else
      response = @adapter.get_all
      response.each do |key, value|
        cache[key_for(key)] = value
      end
      cache[@features_key] = response.keys.to_set
      cache[@get_all_key] = true
    end

    # Ensures that looking up other features that do not exist doesn't
    # result in N+1 adapter calls.
    response.default_proc = ->(memo, key) { memo[key] = default_config }
    response
  else
    @adapter.get_all
  end
end

#get_multi(features) ⇒ Object

Public



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/flipper/adapters/memoizable.rb', line 63

def get_multi(features)
  if memoizing?
    uncached_features = features.reject { |feature| cache[key_for(feature.key)] }

    if uncached_features.any?
      response = @adapter.get_multi(uncached_features)
      response.each do |key, hash|
        cache[key_for(key)] = hash
      end
    end

    result = {}
    features.each do |feature|
      result[feature.key] = cache[key_for(feature.key)]
    end
    result
  else
    @adapter.get_multi(features)
  end
end

#import(source) ⇒ Object



120
121
122
# File 'lib/flipper/adapters/memoizable.rb', line 120

def import(source)
  @adapter.import(source).tap { cache.clear if memoizing? }
end

#memoize=(value) ⇒ Object

Internal: Turns local caching on/off.

value - The Boolean that decides if local caching is on.



131
132
133
134
# File 'lib/flipper/adapters/memoizable.rb', line 131

def memoize=(value)
  cache.clear
  @memoize = value
end

#memoizing?Boolean

Internal: Returns true for using local cache, false for not.

Returns:

  • (Boolean)


137
138
139
# File 'lib/flipper/adapters/memoizable.rb', line 137

def memoizing?
  !!@memoize
end

#remove(feature) ⇒ Object

Public



41
42
43
44
45
46
# File 'lib/flipper/adapters/memoizable.rb', line 41

def remove(feature)
  @adapter.remove(feature).tap do
    expire_features_set
    expire_feature(feature)
  end
end