active_model_cachers 2.1.7 → 2.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/workflows/ruby.yml +59 -0
- data/.gitignore +9 -9
- data/CHANGELOG.md +71 -67
- data/CODE_OF_CONDUCT.md +48 -48
- data/LICENSE.txt +21 -21
- data/README.md +399 -390
- data/Rakefile +10 -10
- data/active_model_cachers.gemspec +45 -45
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/gemfiles/3.2.gemfile +11 -11
- data/gemfiles/4.2.gemfile +11 -11
- data/gemfiles/5.0.gemfile +11 -11
- data/gemfiles/5.1.gemfile +11 -11
- data/gemfiles/5.2.gemfile +11 -11
- data/gemfiles/6.0.gemfile +11 -11
- data/lib/active_model_cachers/active_record/attr_model.rb +124 -124
- data/lib/active_model_cachers/active_record/cacher.rb +97 -97
- data/lib/active_model_cachers/active_record/extension.rb +119 -119
- data/lib/active_model_cachers/active_record/global_callbacks.rb +67 -67
- data/lib/active_model_cachers/cache_service.rb +151 -151
- data/lib/active_model_cachers/cache_service_factory.rb +55 -55
- data/lib/active_model_cachers/column_value_cache.rb +47 -47
- data/lib/active_model_cachers/config.rb +6 -6
- data/lib/active_model_cachers/false_object.rb +5 -5
- data/lib/active_model_cachers/hook/associations.rb +43 -43
- data/lib/active_model_cachers/hook/dependencies.rb +38 -38
- data/lib/active_model_cachers/hook/on_model_delete.rb +29 -29
- data/lib/active_model_cachers/nil_object.rb +5 -5
- data/lib/active_model_cachers/patches/patch_rails_3.rb +49 -49
- data/lib/active_model_cachers/patches/uninitialized_attribute.rb +9 -9
- data/lib/active_model_cachers/version.rb +4 -4
- metadata +12 -7
- data/.travis.yml +0 -33
@@ -1,151 +1,151 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'active_model_cachers/nil_object'
|
3
|
-
require 'active_model_cachers/false_object'
|
4
|
-
require 'active_model_cachers/column_value_cache'
|
5
|
-
|
6
|
-
module ActiveModelCachers
|
7
|
-
class CacheService
|
8
|
-
class << self
|
9
|
-
attr_accessor :cache_key
|
10
|
-
attr_accessor :query_mapping
|
11
|
-
|
12
|
-
def instance(id)
|
13
|
-
hash = (RequestStore.store[self] ||= {})
|
14
|
-
return hash[id] ||= new(id)
|
15
|
-
end
|
16
|
-
|
17
|
-
def clean_at(id)
|
18
|
-
instance(id).clean_cache
|
19
|
-
end
|
20
|
-
|
21
|
-
@@column_value_cache = ActiveModelCachers::ColumnValueCache.new
|
22
|
-
def define_callback_for_cleaning_cache(class_name, column, foreign_key, with_id, on: nil)
|
23
|
-
return if @callbacks_defined
|
24
|
-
@callbacks_defined = true
|
25
|
-
|
26
|
-
clean = ->(id){ clean_at(with_id ? id : nil) }
|
27
|
-
clean_ids = []
|
28
|
-
fire_on = Array(on) if on
|
29
|
-
|
30
|
-
ActiveRecord::Extension.global_callbacks.instance_exec do
|
31
|
-
on_nullify(class_name) do |nullified_column, get_ids|
|
32
|
-
get_ids.call.each{|s| clean.call(s) } if nullified_column == column
|
33
|
-
end
|
34
|
-
|
35
|
-
after_touch1(class_name) do
|
36
|
-
clean.call(@@column_value_cache.add(self.class, class_name, id, foreign_key, self).call)
|
37
|
-
end
|
38
|
-
|
39
|
-
after_touch2(class_name) do
|
40
|
-
@@column_value_cache.clean_cache
|
41
|
-
end
|
42
|
-
|
43
|
-
after_commit1(class_name) do
|
44
|
-
next if fire_on and not transaction_include_any_action?(fire_on)
|
45
|
-
changed = column ? previous_changes.key?(column) : previous_changes.present?
|
46
|
-
if changed || destroyed?
|
47
|
-
clean.call(@@column_value_cache.add(self.class, class_name, id, foreign_key, self).call)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
after_commit2(class_name) do
|
52
|
-
@@column_value_cache.clean_cache
|
53
|
-
end
|
54
|
-
|
55
|
-
before_delete1(class_name) do |id, model|
|
56
|
-
clean_ids << @@column_value_cache.add(self, class_name, id, foreign_key, model)
|
57
|
-
end
|
58
|
-
|
59
|
-
before_delete2(class_name) do |_, model|
|
60
|
-
clean_ids.each{|s| clean.call(s.call) }
|
61
|
-
clean_ids = []
|
62
|
-
end
|
63
|
-
|
64
|
-
after_delete(class_name) do
|
65
|
-
@@column_value_cache.clean_cache
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
# ----------------------------------------------------------------
|
72
|
-
# ● instance methods
|
73
|
-
# ----------------------------------------------------------------
|
74
|
-
def initialize(id)
|
75
|
-
@id = id
|
76
|
-
end
|
77
|
-
|
78
|
-
def get(binding: nil, reflect: nil)
|
79
|
-
@cached_data ||= fetch_from_cache(binding: binding, reflect: reflect)
|
80
|
-
return cache_to_raw_data(@cached_data)
|
81
|
-
end
|
82
|
-
|
83
|
-
def peek(binding: nil, reflect: nil)
|
84
|
-
@cached_data ||= get_from_cache
|
85
|
-
return cache_to_raw_data(@cached_data)
|
86
|
-
end
|
87
|
-
|
88
|
-
def clean_cache(binding: nil, reflect: nil)
|
89
|
-
@cached_data = nil
|
90
|
-
Rails.cache.delete(cache_key)
|
91
|
-
return nil
|
92
|
-
end
|
93
|
-
|
94
|
-
private
|
95
|
-
|
96
|
-
def cache_key
|
97
|
-
key = self.class.cache_key
|
98
|
-
return @id ? "#{key}_#{@id}" : key
|
99
|
-
end
|
100
|
-
|
101
|
-
def get_query(binding, reflect)
|
102
|
-
self.class.query_mapping[reflect] || begin
|
103
|
-
puts "Warning: cannot find query. possible reflects: #{self.class.query_mapping.keys}, reflect: #{reflect}"
|
104
|
-
self.class.query_mapping.values.first
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def get_without_cache(binding, attr)
|
109
|
-
query = get_query(binding, attr)
|
110
|
-
return binding ? binding.instance_exec(@id, &query) : query.call(@id) if @id and query.parameters.size == 1
|
111
|
-
return binding ? binding.instance_exec(&query) : query.call
|
112
|
-
end
|
113
|
-
|
114
|
-
def raw_to_cache_data(raw)
|
115
|
-
return NilObject if raw == nil
|
116
|
-
return FalseObject if raw == false
|
117
|
-
clean_ar_cache(raw.is_a?(Array) ? raw : [raw])
|
118
|
-
return raw_without_singleton_methods(raw)
|
119
|
-
end
|
120
|
-
|
121
|
-
def cache_to_raw_data(cached_data)
|
122
|
-
return nil if cached_data == NilObject
|
123
|
-
return false if cached_data == FalseObject
|
124
|
-
return cached_data
|
125
|
-
end
|
126
|
-
|
127
|
-
def get_from_cache
|
128
|
-
ActiveModelCachers.config.store.read(cache_key)
|
129
|
-
end
|
130
|
-
|
131
|
-
def fetch_from_cache(binding: nil, reflect: nil)
|
132
|
-
ActiveModelCachers.config.store.fetch(cache_key, expires_in: 30.minutes) do
|
133
|
-
raw_to_cache_data(get_without_cache(binding, reflect))
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def clean_ar_cache(models)
|
138
|
-
return if not models.first.is_a?(::ActiveRecord::Base)
|
139
|
-
models.each do |model|
|
140
|
-
model.send(:clear_aggregation_cache) if model.respond_to?(:clear_aggregation_cache, true)
|
141
|
-
model.send(:clear_association_cache)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def raw_without_singleton_methods(raw)
|
146
|
-
return raw if raw.singleton_methods.empty?
|
147
|
-
return raw.class.find_by(id: raw.id) if raw.is_a?(::ActiveRecord::Base) # cannot marshal singleton, so load a new record instead.
|
148
|
-
return raw # not sure what to do with other cases
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_model_cachers/nil_object'
|
3
|
+
require 'active_model_cachers/false_object'
|
4
|
+
require 'active_model_cachers/column_value_cache'
|
5
|
+
|
6
|
+
module ActiveModelCachers
|
7
|
+
class CacheService
|
8
|
+
class << self
|
9
|
+
attr_accessor :cache_key
|
10
|
+
attr_accessor :query_mapping
|
11
|
+
|
12
|
+
def instance(id)
|
13
|
+
hash = (RequestStore.store[self] ||= {})
|
14
|
+
return hash[id] ||= new(id)
|
15
|
+
end
|
16
|
+
|
17
|
+
def clean_at(id)
|
18
|
+
instance(id).clean_cache
|
19
|
+
end
|
20
|
+
|
21
|
+
@@column_value_cache = ActiveModelCachers::ColumnValueCache.new
|
22
|
+
def define_callback_for_cleaning_cache(class_name, column, foreign_key, with_id, on: nil)
|
23
|
+
return if @callbacks_defined
|
24
|
+
@callbacks_defined = true
|
25
|
+
|
26
|
+
clean = ->(id){ clean_at(with_id ? id : nil) }
|
27
|
+
clean_ids = []
|
28
|
+
fire_on = Array(on) if on
|
29
|
+
|
30
|
+
ActiveRecord::Extension.global_callbacks.instance_exec do
|
31
|
+
on_nullify(class_name) do |nullified_column, get_ids|
|
32
|
+
get_ids.call.each{|s| clean.call(s) } if nullified_column == column
|
33
|
+
end
|
34
|
+
|
35
|
+
after_touch1(class_name) do
|
36
|
+
clean.call(@@column_value_cache.add(self.class, class_name, id, foreign_key, self).call)
|
37
|
+
end
|
38
|
+
|
39
|
+
after_touch2(class_name) do
|
40
|
+
@@column_value_cache.clean_cache
|
41
|
+
end
|
42
|
+
|
43
|
+
after_commit1(class_name) do
|
44
|
+
next if fire_on and not transaction_include_any_action?(fire_on)
|
45
|
+
changed = column ? previous_changes.key?(column) : previous_changes.present?
|
46
|
+
if changed || destroyed?
|
47
|
+
clean.call(@@column_value_cache.add(self.class, class_name, id, foreign_key, self).call)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
after_commit2(class_name) do
|
52
|
+
@@column_value_cache.clean_cache
|
53
|
+
end
|
54
|
+
|
55
|
+
before_delete1(class_name) do |id, model|
|
56
|
+
clean_ids << @@column_value_cache.add(self, class_name, id, foreign_key, model)
|
57
|
+
end
|
58
|
+
|
59
|
+
before_delete2(class_name) do |_, model|
|
60
|
+
clean_ids.each{|s| clean.call(s.call) }
|
61
|
+
clean_ids = []
|
62
|
+
end
|
63
|
+
|
64
|
+
after_delete(class_name) do
|
65
|
+
@@column_value_cache.clean_cache
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# ----------------------------------------------------------------
|
72
|
+
# ● instance methods
|
73
|
+
# ----------------------------------------------------------------
|
74
|
+
def initialize(id)
|
75
|
+
@id = id
|
76
|
+
end
|
77
|
+
|
78
|
+
def get(binding: nil, reflect: nil)
|
79
|
+
@cached_data ||= fetch_from_cache(binding: binding, reflect: reflect)
|
80
|
+
return cache_to_raw_data(@cached_data)
|
81
|
+
end
|
82
|
+
|
83
|
+
def peek(binding: nil, reflect: nil)
|
84
|
+
@cached_data ||= get_from_cache
|
85
|
+
return cache_to_raw_data(@cached_data)
|
86
|
+
end
|
87
|
+
|
88
|
+
def clean_cache(binding: nil, reflect: nil)
|
89
|
+
@cached_data = nil
|
90
|
+
Rails.cache.delete(cache_key)
|
91
|
+
return nil
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def cache_key
|
97
|
+
key = self.class.cache_key
|
98
|
+
return @id ? "#{key}_#{@id}" : key
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_query(binding, reflect)
|
102
|
+
self.class.query_mapping[reflect] || begin
|
103
|
+
puts "Warning: cannot find query. possible reflects: #{self.class.query_mapping.keys}, reflect: #{reflect}"
|
104
|
+
self.class.query_mapping.values.first
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def get_without_cache(binding, attr)
|
109
|
+
query = get_query(binding, attr)
|
110
|
+
return binding ? binding.instance_exec(@id, &query) : query.call(@id) if @id and query.parameters.size == 1
|
111
|
+
return binding ? binding.instance_exec(&query) : query.call
|
112
|
+
end
|
113
|
+
|
114
|
+
def raw_to_cache_data(raw)
|
115
|
+
return NilObject if raw == nil
|
116
|
+
return FalseObject if raw == false
|
117
|
+
clean_ar_cache(raw.is_a?(Array) ? raw : [raw])
|
118
|
+
return raw_without_singleton_methods(raw)
|
119
|
+
end
|
120
|
+
|
121
|
+
def cache_to_raw_data(cached_data)
|
122
|
+
return nil if cached_data == NilObject
|
123
|
+
return false if cached_data == FalseObject
|
124
|
+
return cached_data
|
125
|
+
end
|
126
|
+
|
127
|
+
def get_from_cache
|
128
|
+
ActiveModelCachers.config.store.read(cache_key)
|
129
|
+
end
|
130
|
+
|
131
|
+
def fetch_from_cache(binding: nil, reflect: nil)
|
132
|
+
ActiveModelCachers.config.store.fetch(cache_key, expires_in: 30.minutes) do
|
133
|
+
raw_to_cache_data(get_without_cache(binding, reflect))
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def clean_ar_cache(models)
|
138
|
+
return if not models.first.is_a?(::ActiveRecord::Base)
|
139
|
+
models.each do |model|
|
140
|
+
model.send(:clear_aggregation_cache) if model.respond_to?(:clear_aggregation_cache, true)
|
141
|
+
model.send(:clear_association_cache)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def raw_without_singleton_methods(raw)
|
146
|
+
return raw if raw.singleton_methods.empty?
|
147
|
+
return raw.class.find_by(id: raw.id) if raw.is_a?(::ActiveRecord::Base) # cannot marshal singleton, so load a new record instead.
|
148
|
+
return raw # not sure what to do with other cases
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -1,55 +1,55 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'request_store'
|
3
|
-
require 'active_model_cachers/cache_service'
|
4
|
-
|
5
|
-
module ActiveModelCachers
|
6
|
-
class CacheServiceFactory
|
7
|
-
@key_class_mapping = {}
|
8
|
-
@cache_key_klass_mapping = {}
|
9
|
-
|
10
|
-
class << self
|
11
|
-
def has_cacher?(attr)
|
12
|
-
return (@key_class_mapping[get_cache_key(attr)] != nil)
|
13
|
-
end
|
14
|
-
|
15
|
-
def create_for_active_model(attr, query)
|
16
|
-
cache_key = get_cache_key(attr)
|
17
|
-
|
18
|
-
klass = @key_class_mapping[cache_key] ||= ->{
|
19
|
-
klass = Class.new(CacheService)
|
20
|
-
klass.cache_key = cache_key
|
21
|
-
klass.query_mapping = {}
|
22
|
-
klass.instance_variable_set(:@callbacks_defined, false) # to remove warning: instance variable @callbacks_defined not initialized
|
23
|
-
next klass
|
24
|
-
}[]
|
25
|
-
|
26
|
-
klass.query_mapping[attr.reflect] = query
|
27
|
-
return klass
|
28
|
-
end
|
29
|
-
|
30
|
-
def set_klass_to_mapping(attr, current_klass)
|
31
|
-
cache_key = get_cache_key(attr)
|
32
|
-
changed = clean_klass_cache_if_reloaded!(cache_key, current_klass, attr)
|
33
|
-
@cache_key_klass_mapping[cache_key] = current_klass
|
34
|
-
return changed
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
def get_cache_key(attr)
|
40
|
-
class_name, column = attr.extract_class_and_column
|
41
|
-
return "active_model_cachers_#{class_name}_at_#{column}" if column
|
42
|
-
foreign_key = attr.foreign_key(reverse: true)
|
43
|
-
return "active_model_cachers_#{class_name}_by_#{foreign_key}" if foreign_key and foreign_key.to_s != 'id'
|
44
|
-
return "active_model_cachers_#{class_name}"
|
45
|
-
end
|
46
|
-
|
47
|
-
def clean_klass_cache_if_reloaded!(cache_key, current_klass, attr)
|
48
|
-
origin_klass, @cache_key_klass_mapping[cache_key] = @cache_key_klass_mapping[cache_key], current_klass
|
49
|
-
return false if origin_klass == nil or origin_klass == current_klass # when code reloaded in development.
|
50
|
-
@key_class_mapping[cache_key] = nil
|
51
|
-
return true
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'request_store'
|
3
|
+
require 'active_model_cachers/cache_service'
|
4
|
+
|
5
|
+
module ActiveModelCachers
|
6
|
+
class CacheServiceFactory
|
7
|
+
@key_class_mapping = {}
|
8
|
+
@cache_key_klass_mapping = {}
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def has_cacher?(attr)
|
12
|
+
return (@key_class_mapping[get_cache_key(attr)] != nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_for_active_model(attr, query)
|
16
|
+
cache_key = get_cache_key(attr)
|
17
|
+
|
18
|
+
klass = @key_class_mapping[cache_key] ||= ->{
|
19
|
+
klass = Class.new(CacheService)
|
20
|
+
klass.cache_key = cache_key
|
21
|
+
klass.query_mapping = {}
|
22
|
+
klass.instance_variable_set(:@callbacks_defined, false) # to remove warning: instance variable @callbacks_defined not initialized
|
23
|
+
next klass
|
24
|
+
}[]
|
25
|
+
|
26
|
+
klass.query_mapping[attr.reflect] = query
|
27
|
+
return klass
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_klass_to_mapping(attr, current_klass)
|
31
|
+
cache_key = get_cache_key(attr)
|
32
|
+
changed = clean_klass_cache_if_reloaded!(cache_key, current_klass, attr)
|
33
|
+
@cache_key_klass_mapping[cache_key] = current_klass
|
34
|
+
return changed
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def get_cache_key(attr)
|
40
|
+
class_name, column = attr.extract_class_and_column
|
41
|
+
return "active_model_cachers_#{class_name}_at_#{column}" if column
|
42
|
+
foreign_key = attr.foreign_key(reverse: true)
|
43
|
+
return "active_model_cachers_#{class_name}_by_#{foreign_key}" if foreign_key and foreign_key.to_s != 'id'
|
44
|
+
return "active_model_cachers_#{class_name}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def clean_klass_cache_if_reloaded!(cache_key, current_klass, attr)
|
48
|
+
origin_klass, @cache_key_klass_mapping[cache_key] = @cache_key_klass_mapping[cache_key], current_klass
|
49
|
+
return false if origin_klass == nil or origin_klass == current_klass # when code reloaded in development.
|
50
|
+
@key_class_mapping[cache_key] = nil
|
51
|
+
return true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -1,47 +1,47 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class ActiveModelCachers::ColumnValueCache
|
4
|
-
def initialize
|
5
|
-
@cache1 = Hash.new{|h, k| h[k] = {} }
|
6
|
-
@cache2 = Hash.new{|h, k| h[k] = {} }
|
7
|
-
end
|
8
|
-
|
9
|
-
def add(object, class_name, id, foreign_key, model)
|
10
|
-
value = (@cache1[class_name][[id, foreign_key]] ||= get_id_from(object, id, foreign_key, model))
|
11
|
-
return ->{ (value == :not_set ? query_value(object, class_name, id, foreign_key) : value)}
|
12
|
-
end
|
13
|
-
|
14
|
-
def query_value(object, class_name, id, foreign_key)
|
15
|
-
cache = @cache2[class_name]
|
16
|
-
if cache.empty?
|
17
|
-
no_data_keys = @cache1[class_name].select{|k, v| v == :not_set }.keys
|
18
|
-
ids = no_data_keys.map(&:first).uniq
|
19
|
-
columns = ['id', *no_data_keys.map(&:second)].uniq
|
20
|
-
pluck_columns(object, object.where(id: ids).limit(ids.size), columns).each do |columns_data|
|
21
|
-
model_id = columns_data.first
|
22
|
-
columns.each_with_index do |column, index|
|
23
|
-
cache[[model_id, column]] = columns_data[index]
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
return cache[[id, foreign_key]]
|
28
|
-
end
|
29
|
-
|
30
|
-
def clean_cache
|
31
|
-
@cache1.clear
|
32
|
-
@cache2.clear
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def pluck_columns(_, relation, columns)
|
38
|
-
relation.pluck(*columns)
|
39
|
-
end
|
40
|
-
|
41
|
-
def get_id_from(object, id, column, model)
|
42
|
-
return id if column == 'id'
|
43
|
-
model ||= object.cacher.peek_by(id: id) if object.has_cacher?
|
44
|
-
return model.send(column) if model and model.has_attribute?(column)
|
45
|
-
return :not_set
|
46
|
-
end
|
47
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ActiveModelCachers::ColumnValueCache
|
4
|
+
def initialize
|
5
|
+
@cache1 = Hash.new{|h, k| h[k] = {} }
|
6
|
+
@cache2 = Hash.new{|h, k| h[k] = {} }
|
7
|
+
end
|
8
|
+
|
9
|
+
def add(object, class_name, id, foreign_key, model)
|
10
|
+
value = (@cache1[class_name][[id, foreign_key]] ||= get_id_from(object, id, foreign_key, model))
|
11
|
+
return ->{ (value == :not_set ? query_value(object, class_name, id, foreign_key) : value)}
|
12
|
+
end
|
13
|
+
|
14
|
+
def query_value(object, class_name, id, foreign_key)
|
15
|
+
cache = @cache2[class_name]
|
16
|
+
if cache.empty?
|
17
|
+
no_data_keys = @cache1[class_name].select{|k, v| v == :not_set }.keys
|
18
|
+
ids = no_data_keys.map(&:first).uniq
|
19
|
+
columns = ['id', *no_data_keys.map(&:second)].uniq
|
20
|
+
pluck_columns(object, object.where(id: ids).limit(ids.size), columns).each do |columns_data|
|
21
|
+
model_id = columns_data.first
|
22
|
+
columns.each_with_index do |column, index|
|
23
|
+
cache[[model_id, column]] = columns_data[index]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return cache[[id, foreign_key]]
|
28
|
+
end
|
29
|
+
|
30
|
+
def clean_cache
|
31
|
+
@cache1.clear
|
32
|
+
@cache2.clear
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def pluck_columns(_, relation, columns)
|
38
|
+
relation.pluck(*columns)
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_id_from(object, id, column, model)
|
42
|
+
return id if column == 'id'
|
43
|
+
model ||= object.cacher.peek_by(id: id) if object.has_cacher?
|
44
|
+
return model.send(column) if model and model.has_attribute?(column)
|
45
|
+
return :not_set
|
46
|
+
end
|
47
|
+
end
|