ar_cache 1.1.0 → 2.0.0

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.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ArCache
4
- VERSION = '1.1.0'
4
+ VERSION = '2.0.0'
5
5
  end
@@ -8,7 +8,14 @@ module ArCache
8
8
  @klass = klass
9
9
  @table = klass.ar_cache_table
10
10
  @predicates = predicates
11
- @missed_values = []
11
+ end
12
+
13
+ def missed_values
14
+ @missed_values ||= []
15
+ end
16
+
17
+ def invalid_keys
18
+ @invalid_keys ||= []
12
19
  end
13
20
 
14
21
  def cacheable?
@@ -24,8 +31,8 @@ module ArCache
24
31
  count = 0
25
32
 
26
33
  bool = index.all? do |column|
27
- where_values_hash[column].tap do |value|
28
- if value.is_a?(Array)
34
+ (Thread.current[:ar_cache_reflection] ? where_values_hash.key?(column) : where_values_hash[column]).tap do
35
+ if where_values_hash[column].is_a?(Array)
29
36
  @multi_values_key = column
30
37
  count += 1
31
38
  end
@@ -52,15 +59,15 @@ module ArCache
52
59
  @cache_hash = {}
53
60
  multi_values_key = @multi_values_key || @index.first
54
61
 
55
- Array(where_values_hash[multi_values_key]).each do |v|
62
+ Array.wrap(where_values_hash[multi_values_key]).each do |v|
56
63
  @cache_hash[table.cache_key(where_values_hash, @index, multi_values_key, v)] = v
57
64
  end
58
65
 
59
66
  return @cache_hash if primary_key_index?
60
67
 
61
68
  @original_cache_hash = @cache_hash
62
- @cache_hash = ArCache::Store.read_multi(@cache_hash.keys)
63
- @original_cache_hash.each { |k, v| @missed_values << v unless @cache_hash.key?(k) }
69
+ @cache_hash = ArCache.read_multi(*@cache_hash.keys, raw: true)
70
+ @original_cache_hash.each { |k, v| missed_values << v unless @cache_hash.key?(k) }
64
71
  @cache_hash = @cache_hash.invert
65
72
 
66
73
  @cache_hash
@@ -73,26 +80,28 @@ module ArCache
73
80
  end
74
81
 
75
82
  def missed_hash
76
- @missed_hash ||= @missed_values.empty? ? {} : { (@multi_values_key || @index.first) => @missed_values }
83
+ @missed_hash ||= missed_values.empty? ? {} : { (@multi_values_key || @index.first) => missed_values }
77
84
  end
78
85
 
79
86
  def add_missed_values(key)
80
87
  if primary_key_index?
81
- @missed_values << cache_hash[key]
88
+ missed_values << cache_hash[key]
82
89
  else
83
- @missed_values << @original_cache_hash[cache_hash[key]]
90
+ missed_values << @original_cache_hash[cache_hash[key]]
84
91
  end
85
92
  end
86
93
 
87
- def add_invalid_keys(key)
88
- @invalid_keys ||= []
89
- @invalid_keys << key
90
- @invalid_keys << cache_hash[key] unless primary_key_index?
91
- @invalid_keys
94
+ def add_blank_primary_cache_key(key)
95
+ invalid_keys << key
96
+ end
97
+
98
+ def add_invalid_second_cache_key(key)
99
+ # invalid_keys << key # The primary key index is reliable.
100
+ invalid_keys << cache_hash[key] unless primary_key_index?
92
101
  end
93
102
 
94
103
  def delete_invalid_keys
95
- ArCache::Store.delete_multi(@invalid_keys) if @invalid_keys
104
+ ArCache.delete_multi(invalid_keys) if invalid_keys.any?
96
105
  end
97
106
 
98
107
  # This module is based on ActiveRecord::Relation::WhereClause modified
@@ -100,13 +109,10 @@ module ArCache
100
109
  def where_values_hash
101
110
  @where_values_hash ||= equalities(predicates).each_with_object({}) do |node, hash|
102
111
  # Don't support Arel::Nodes::NamedFunction.
103
- # But we don't judge it, because it will raise exception if it is Arel::Nodes::NamedFunction object.
104
112
  next if table.name != node.left.relation.name
105
113
 
106
114
  name = node.left.name.to_s
107
115
  value = extract_node_value(node.right)
108
- next if value.respond_to?(:size) && value.size > ArCache::Configuration.index_column_max_size
109
-
110
116
  hash[name] = value
111
117
  end
112
118
  rescue NoMethodError, ActiveModel::RangeError
@@ -133,15 +139,18 @@ module ArCache
133
139
  end
134
140
 
135
141
  private def extract_node_value(node)
136
- value = case node
137
- when Array
138
- node.map { |v| extract_node_value(v) }
139
- when Arel::Nodes::BindParam
140
- node.value.value_for_database # Maybe raise ActiveModel::RangeError
141
- when Arel::Nodes::Casted, Arel::Nodes::Quoted
142
- node.value_for_database # Maybe raise ActiveModel::RangeError
143
- end
142
+ case node
143
+ when Array
144
+ node.map { |v| extract_node_value(v) }
145
+ when Arel::Nodes::BindParam
146
+ value_for_database(node.value)
147
+ when Arel::Nodes::Casted, Arel::Nodes::Quoted
148
+ value_for_database(node)
149
+ end
150
+ end
144
151
 
152
+ private def value_for_database(node)
153
+ value = node.value_for_database # Maybe raise ActiveModel::RangeError
145
154
  value.is_a?(Date) ? value.to_s : value
146
155
  end
147
156
  end
@@ -1,21 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rails/generators'
4
- require 'rails/generators/migration'
5
- require 'rails/generators/active_record/migration'
6
4
 
7
5
  module ArCache
8
6
  module Generators
9
7
  class InstallGenerator < Rails::Generators::Base
10
- include Rails::Generators::Migration
11
- include ::ActiveRecord::Generators::Migration
12
-
13
8
  source_root File.expand_path('templates', __dir__)
14
9
 
15
10
  def copy_initializer_file
16
11
  copy_file 'configuration.rb', 'config/initializers/ar_cache.rb'
17
-
18
- migration_template 'migrate/create_ar_cache_records.rb', 'db/migrate/create_ar_cache_records.rb'
19
12
  end
20
13
  end
21
14
  end
@@ -2,33 +2,28 @@
2
2
 
3
3
  # For more information, please see: https://github.com/OuYangJinTing/ar_cache/README.md
4
4
  ArCache.configure do |config|
5
- # WARNING: The should uncomment only when your database default isolation level is "READ UNCOMMITTED"!
6
- # config.read_uncommitted = true # defaul false
5
+ # NOTE: Please change true if database happened some problems
6
+ # Arcache default use database share lock to ensure that the cache is correct.
7
+ config.cache_lock = false # Boolean
7
8
 
8
- # config.cache_store = ActiveSupport::Cache::Store # default Rails.cache || ActiveSupport::Cache::MemoryStore.new
9
+ # The cache tool.
10
+ config.cache_store = defined?(Rails) ? Rails.cache : ActiveSupport::Cache::MemoryStore.new
9
11
 
10
- # Cache key automatic expiration time.
11
- # config.expires_in = Numeric # default 1 week
12
-
13
- # Serialize and deserialize cached data.
14
- # config.coder = [YAML|JSON] # default YAML
15
-
16
- # Support the maximum length of index column value.
17
- # config.index_column_max_size = Integer # default 64
12
+ # The cache key valid time.
13
+ config.expires_in = 1.week # Integer
18
14
 
19
15
  # ArCache switch.
20
- # config.disabled = Boolean # default false
21
-
22
- # Whether to support selecct columns query
23
- # config.select_disabled = Boolean # default true
24
-
25
- # config.tables_options = {
26
- # table_name: {
27
- # disabled: Boolean,
28
- # select_disabled: Boolean,
29
- # unique_indexes: Array # eg: [:id, [:name, :statue]], The default is the unique index column of the table.
30
- # ignored_columns: Array # eg: [:created_at, :updated_at], defaule [].
31
- # },
32
- # ...
33
- # }
16
+ config.disabled = false # Boolean
17
+
18
+ # Whether to support select column sql.
19
+ config.select_disabled = true # Boolean
20
+
21
+ config.tables_options = {
22
+ # table_name: {
23
+ # disabled: Boolean,
24
+ # select_disabled: Boolean,
25
+ # unique_indexes: Array # eg: [:id, [:name, :statue]], The default is the unique index column of the table.
26
+ # },
27
+ # ...
28
+ }
34
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ar_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OuYangJinTing
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-10 00:00:00.000000000 Z
11
+ date: 2021-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -30,6 +30,26 @@ dependencies:
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '7'
33
+ - !ruby/object:Gem::Dependency
34
+ name: oj
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '3'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '4'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '3'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '4'
33
53
  description: An modern cacheing library for ActiveRecord inspired by cache-money and
34
54
  second_level_cache.
35
55
  email:
@@ -48,6 +68,7 @@ files:
48
68
  - Gemfile.lock
49
69
  - LICENSE.txt
50
70
  - README.md
71
+ - README.zh-CN.md
51
72
  - Rakefile
52
73
  - ar_cache.gemspec
53
74
  - bin/activerecord-test
@@ -72,14 +93,11 @@ files:
72
93
  - lib/ar_cache/marshal.rb
73
94
  - lib/ar_cache/mock_table.rb
74
95
  - lib/ar_cache/query.rb
75
- - lib/ar_cache/record.rb
76
- - lib/ar_cache/store.rb
77
96
  - lib/ar_cache/table.rb
78
97
  - lib/ar_cache/version.rb
79
98
  - lib/ar_cache/where_clause.rb
80
99
  - lib/generators/ar_cache/install_generator.rb
81
100
  - lib/generators/ar_cache/templates/configuration.rb
82
- - lib/generators/ar_cache/templates/migrate/create_ar_cache_records.rb.tt
83
101
  homepage: https://github.com/OuYangJinTing/ar_cache
84
102
  licenses:
85
103
  - MIT
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ArCache
4
- class Record < ActiveRecord::Base # rubocop:disable Rails/ApplicationRecord
5
- self.table_name = 'ar_cache_records'
6
-
7
- default_scope { skip_ar_cache }
8
-
9
- def self.get(table_name)
10
- find_by(table_name: table_name)
11
- end
12
-
13
- def self.version(table)
14
- (get(table.name) || store(table)).version
15
- end
16
-
17
- def self.update_version(table)
18
- record = get(table.name)
19
- return store(table).version unless record
20
-
21
- record.update_version
22
- record.version
23
- end
24
-
25
- def self.store(table)
26
- record = get(table.name) || new(table_name: table.name)
27
- record.store(table)
28
- record
29
- end
30
-
31
- def store(table)
32
- with_optimistic_retry do
33
- self.version += 1 unless table_md5 == table.md5
34
- self.table_md5 = table.md5
35
-
36
- save! if changed?
37
- end
38
- end
39
-
40
- def update_version
41
- with_optimistic_retry do
42
- self.version += 1
43
- save!
44
- end
45
- end
46
-
47
- private def with_optimistic_retry
48
- yield
49
- rescue ::ActiveRecord::StaleObjectError
50
- reload
51
- retry
52
- end
53
- end
54
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ArCache
4
- class Store
5
- @options = { raw: true, expires_in: ArCache::Configuration.expires_in }.freeze
6
-
7
- class << self
8
- delegate :delete, :delete_multi, :clear, :exist?, to: 'ArCache::Configuration.cache_store'
9
-
10
- def write(name, value)
11
- ArCache::Configuration.cache_store.write(name, dump(value), @options)
12
- end
13
-
14
- def write_multi(hash)
15
- hash.each { |k, v| hash[k] = dump(v) }
16
- ArCache::Configuration.cache_store.write_multi(hash, @options)
17
- end
18
-
19
- def read(name)
20
- load(ArCache::Configuration.cache_store.read(name, @options))
21
- end
22
-
23
- def read_multi(names)
24
- entries = ArCache::Configuration.cache_store.read_multi(*names, @options)
25
- entries.each { |k, v| entries[k] = load(v) }
26
- entries
27
- end
28
-
29
- private def dump(value)
30
- ArCache::Configuration.coder.dump(value)
31
- end
32
-
33
- private def load(value)
34
- ArCache::Configuration.coder.load(value) if value
35
- end
36
- end
37
- end
38
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateArCacheMonitors < ActiveRecord::Migration[<%= ActiveRecord::VERSION::MAJOR %>.<%= ActiveRecord::VERSION::MINOR %>]
4
- def change
5
- create_table :ar_cache_records do |t|
6
- t.string :table_name, null: false
7
- t.string :table_md5, null: false, limit: 32, default: '0' * 32
8
- t.integer :version, null: false, default: 0
9
- t.integer :lock_version, null: false, default: 0
10
-
11
- t.timestamps null: false
12
-
13
- t.index :table_name, unique: true
14
- end
15
- end
16
- end