active_model_cachers 2.1.6 → 2.1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +9 -9
- data/.travis.yml +8 -1
- data/CHANGELOG.md +67 -62
- data/CODE_OF_CONDUCT.md +48 -48
- data/LICENSE.txt +21 -21
- data/README.md +1 -1
- data/Rakefile +10 -10
- data/active_model_cachers.gemspec +7 -0
- 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 -0
- data/lib/active_model_cachers.rb +0 -0
- 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 +10 -4
@@ -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
|
@@ -1,6 +1,6 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module ActiveModelCachers
|
3
|
-
class Config
|
4
|
-
attr_accessor :store
|
5
|
-
end
|
6
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ActiveModelCachers
|
3
|
+
class Config
|
4
|
+
attr_accessor :store
|
5
|
+
end
|
6
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module ActiveModelCachers
|
3
|
-
class FalseObject
|
4
|
-
end
|
5
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ActiveModelCachers
|
3
|
+
class FalseObject
|
4
|
+
end
|
5
|
+
end
|
@@ -1,43 +1,43 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'active_record'
|
3
|
-
require 'active_record/associations/has_many_association'
|
4
|
-
require 'active_model_cachers/hook/on_model_delete'
|
5
|
-
|
6
|
-
module ActiveModelCachers::Hook
|
7
|
-
module Associations
|
8
|
-
def delete_count(method, scope)
|
9
|
-
if method == :delete_all
|
10
|
-
# TODO:
|
11
|
-
else # nullify
|
12
|
-
call_hooks{ scope.pluck(:id) }
|
13
|
-
end
|
14
|
-
super
|
15
|
-
end
|
16
|
-
|
17
|
-
def delete_records(records, method)
|
18
|
-
case method
|
19
|
-
when :destroy
|
20
|
-
when :delete_all
|
21
|
-
# TODO:
|
22
|
-
else
|
23
|
-
call_hooks{ records.map(&:id) }
|
24
|
-
end
|
25
|
-
super
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def call_hooks(&get_ids)
|
31
|
-
ids = nil
|
32
|
-
get_ids_with_cache = ->{ ids ||= get_ids.call }
|
33
|
-
ActiveModelCachers::ActiveRecord::Extension.global_callbacks.on_nullify.exec(
|
34
|
-
self,
|
35
|
-
reflection.klass,
|
36
|
-
reflection.foreign_key,
|
37
|
-
get_ids_with_cache,
|
38
|
-
)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
ActiveRecord::Associations::HasManyAssociation.send(:prepend, ActiveModelCachers::Hook::Associations)
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_record'
|
3
|
+
require 'active_record/associations/has_many_association'
|
4
|
+
require 'active_model_cachers/hook/on_model_delete'
|
5
|
+
|
6
|
+
module ActiveModelCachers::Hook
|
7
|
+
module Associations
|
8
|
+
def delete_count(method, scope)
|
9
|
+
if method == :delete_all
|
10
|
+
# TODO:
|
11
|
+
else # nullify
|
12
|
+
call_hooks{ scope.pluck(:id) }
|
13
|
+
end
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def delete_records(records, method)
|
18
|
+
case method
|
19
|
+
when :destroy
|
20
|
+
when :delete_all
|
21
|
+
# TODO:
|
22
|
+
else
|
23
|
+
call_hooks{ records.map(&:id) }
|
24
|
+
end
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def call_hooks(&get_ids)
|
31
|
+
ids = nil
|
32
|
+
get_ids_with_cache = ->{ ids ||= get_ids.call }
|
33
|
+
ActiveModelCachers::ActiveRecord::Extension.global_callbacks.on_nullify.exec(
|
34
|
+
self,
|
35
|
+
reflection.klass,
|
36
|
+
reflection.foreign_key,
|
37
|
+
get_ids_with_cache,
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
ActiveRecord::Associations::HasManyAssociation.send(:prepend, ActiveModelCachers::Hook::Associations)
|
@@ -1,38 +1,38 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'active_support/dependencies'
|
3
|
-
|
4
|
-
module ActiveModelCachers::Hook
|
5
|
-
module Depdenencies
|
6
|
-
def onload(const_name, times: 1, &block)
|
7
|
-
const = const_name if not const_name.is_a?(String)
|
8
|
-
if const or Module.const_defined?(const_name)
|
9
|
-
(const || const_name.constantize).instance_exec(&block)
|
10
|
-
else
|
11
|
-
load_hooks[const_name].push(block: block, times: times)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def load_hooks
|
16
|
-
@load_hooks ||= Hash.new{|h, k| h[k] = [] }
|
17
|
-
end
|
18
|
-
|
19
|
-
def new_constants_in(*)
|
20
|
-
new_constants = super.each do |const_name|
|
21
|
-
hooks = load_hooks[const_name]
|
22
|
-
need_compact = false
|
23
|
-
hooks.each_with_index do |hook, idx|
|
24
|
-
if (hook[:times] -= 1) < 0
|
25
|
-
hooks[idx] = nil
|
26
|
-
need_compact = true
|
27
|
-
next
|
28
|
-
end
|
29
|
-
const_name.constantize.instance_exec(&hook[:block])
|
30
|
-
end
|
31
|
-
hooks.compact! if need_compact
|
32
|
-
end
|
33
|
-
return new_constants
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
ActiveSupport::Dependencies.send(:extend, ActiveModelCachers::Hook::Depdenencies)
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/dependencies'
|
3
|
+
|
4
|
+
module ActiveModelCachers::Hook
|
5
|
+
module Depdenencies
|
6
|
+
def onload(const_name, times: 1, &block)
|
7
|
+
const = const_name if not const_name.is_a?(String)
|
8
|
+
if const or Module.const_defined?(const_name)
|
9
|
+
(const || const_name.constantize).instance_exec(&block)
|
10
|
+
else
|
11
|
+
load_hooks[const_name].push(block: block, times: times)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def load_hooks
|
16
|
+
@load_hooks ||= Hash.new{|h, k| h[k] = [] }
|
17
|
+
end
|
18
|
+
|
19
|
+
def new_constants_in(*)
|
20
|
+
new_constants = super.each do |const_name|
|
21
|
+
hooks = load_hooks[const_name]
|
22
|
+
need_compact = false
|
23
|
+
hooks.each_with_index do |hook, idx|
|
24
|
+
if (hook[:times] -= 1) < 0
|
25
|
+
hooks[idx] = nil
|
26
|
+
need_compact = true
|
27
|
+
next
|
28
|
+
end
|
29
|
+
const_name.constantize.instance_exec(&hook[:block])
|
30
|
+
end
|
31
|
+
hooks.compact! if need_compact
|
32
|
+
end
|
33
|
+
return new_constants
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
ActiveSupport::Dependencies.send(:extend, ActiveModelCachers::Hook::Depdenencies)
|
@@ -1,29 +1,29 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'active_record'
|
3
|
-
|
4
|
-
module ActiveModelCachers::Hook
|
5
|
-
module OnModelDelete
|
6
|
-
module InstanceMethods
|
7
|
-
def delete
|
8
|
-
self.class.delete(id, self) if persisted?
|
9
|
-
@destroyed = true
|
10
|
-
freeze
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
module ClassMethods
|
15
|
-
def delete(id, model = nil)
|
16
|
-
ActiveModelCachers::ActiveRecord::Extension.global_callbacks.before_delete1.exec(self, self, id, model)
|
17
|
-
ActiveModelCachers::ActiveRecord::Extension.global_callbacks.before_delete2.exec(self, self, id, model)
|
18
|
-
|
19
|
-
result = super(id)
|
20
|
-
|
21
|
-
ActiveModelCachers::ActiveRecord::Extension.global_callbacks.after_delete.exec(self, self, id, model)
|
22
|
-
return result
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
ActiveRecord::Base.send(:include, ActiveModelCachers::Hook::OnModelDelete::InstanceMethods)
|
29
|
-
ActiveRecord::Base.send(:extend, ActiveModelCachers::Hook::OnModelDelete::ClassMethods)
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
module ActiveModelCachers::Hook
|
5
|
+
module OnModelDelete
|
6
|
+
module InstanceMethods
|
7
|
+
def delete
|
8
|
+
self.class.delete(id, self) if persisted?
|
9
|
+
@destroyed = true
|
10
|
+
freeze
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def delete(id, model = nil)
|
16
|
+
ActiveModelCachers::ActiveRecord::Extension.global_callbacks.before_delete1.exec(self, self, id, model)
|
17
|
+
ActiveModelCachers::ActiveRecord::Extension.global_callbacks.before_delete2.exec(self, self, id, model)
|
18
|
+
|
19
|
+
result = super(id)
|
20
|
+
|
21
|
+
ActiveModelCachers::ActiveRecord::Extension.global_callbacks.after_delete.exec(self, self, id, model)
|
22
|
+
return result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
ActiveRecord::Base.send(:include, ActiveModelCachers::Hook::OnModelDelete::InstanceMethods)
|
29
|
+
ActiveRecord::Base.send(:extend, ActiveModelCachers::Hook::OnModelDelete::ClassMethods)
|