Module: RedisMemo::MemoizeQuery
- Defined in:
- lib/redis_memo/memoize_query.rb,
lib/redis_memo/memoize_query/memoize_table_column.rb
Overview
Hook into ActiveRecord to cache SQL queries and perform auto cache invalidation
Defined Under Namespace
Classes: CachedSelect, Invalidation, ModelCallback
Constant Summary collapse
- @@memoized_columns =
Class variable containing all memoized columns on all ActiveRecord models
Hash.new { |h, k| h[k] = [Set.new, Set.new] }
Class Method Summary collapse
-
.create_memo(model_class, **extra_props) ⇒ Object
Creates a
RedisMemo::Memoizable
from the given ActiveRecord model class and column values. -
.invalidate(*records) ⇒ Object
Invalidates all memoized SQL queries which would contain the given records.
-
.invalidate_all(model_class) ⇒ Object
Invalidates all memoized SQL queries on the given model.
-
.memoized_columns(model_or_table, editable_only: false) ⇒ Object
Returns the list of columns currently memoized on the model or table.
Instance Method Summary collapse
-
#memoize_table_column(*raw_columns, editable: true) ⇒ Object
Core entry method for using RedisMemo to cache SQL select queries on the given column names.
Class Method Details
.create_memo(model_class, **extra_props) ⇒ Object
Creates a RedisMemo::Memoizable
from the given ActiveRecord model class and column values.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/redis_memo/memoize_query.rb', line 112 def self.create_memo(model_class, **extra_props) using_active_record!(model_class) keys = extra_props.keys.sort if !keys.empty? && !memoized_columns(model_class).include?(keys) raise RedisMemo::ArgumentError.new("'#{model_class.name}' has not memoized columns: #{keys}") end extra_props.each do |key, value| # The data type is ensured by the database, thus we don't need to cast # types here for better performance column_name = key.to_s extra_props[key] = if model_class.defined_enums.include?(column_name) enum_mapping = model_class.defined_enums[column_name] # Assume a value is a converted enum if it does not exist in the # enum mapping (enum_mapping[value.to_s] || value).to_s else value.to_s end end RedisMemo::Memoizable.new( __redis_memo_memoize_query_table_name__: model_class.table_name, **extra_props, ) end |
.invalidate(*records) ⇒ Object
Invalidates all memoized SQL queries which would contain the given records.
89 90 91 92 93 |
# File 'lib/redis_memo/memoize_query.rb', line 89 def self.invalidate(*records) RedisMemo::Memoizable.invalidate( records.map { |record| to_memos(record) }.flatten, ) end |
.invalidate_all(model_class) ⇒ Object
Invalidates all memoized SQL queries on the given model.
77 78 79 80 81 82 83 84 |
# File 'lib/redis_memo/memoize_query.rb', line 77 def self.invalidate_all(model_class) RedisMemo::Tracer.trace( 'redis_memo.memoizable.invalidate_all', model_class.name, ) do RedisMemo::Memoizable.invalidate([model_class.redis_memo_class_memoizable]) end end |
.memoized_columns(model_or_table, editable_only: false) ⇒ Object
Returns the list of columns currently memoized on the model or table
102 103 104 105 |
# File 'lib/redis_memo/memoize_query.rb', line 102 def self.memoized_columns(model_or_table, editable_only: false) table = model_or_table.is_a?(Class) ? model_or_table.table_name : model_or_table @@memoized_columns[table.to_sym][editable_only ? 1 : 0] end |
Instance Method Details
#memoize_table_column(*raw_columns, editable: true) ⇒ Object
Core entry method for using RedisMemo to cache SQL select queries on the given column names. We intercept any ActiveRecord select queries and extract the column dependencies from SQL query parameters. From the extracted dependencies and the memoized columns on the table, we determine whether or not the query should be cached on RedisMemo. Learn more in RedisMemo::MemoizeQuery::CachedSelect
.
class User < ApplicationRecord
extend RedisMemo::MemoizeQuery
memoize_table_column :id
memoize_table_column :first_name
memoize_table_column :first_name, last_name
end
On the User model, queries such as
- record.user
- User.find(user_id)
- User.where(id: user_id).first
- User.where(first_name: first_name).first
- User.where(first_name: first_name, last_name: last_name).first
- User.find_by_first_name(first_name)
will first check the Redis cache for the data before hitting the SQL database; the cache results are invalidated automatically when user records are changed.
Note that memoize_table_column :first_name, last_name specifies that only AND queries that contain both columns will be memoized. The query User.where(last_name: last_name) will NOT be memoized with the given configuration.
will be used to create memos that are invalidatable after each record save.
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 |
# File 'lib/redis_memo/memoize_query.rb', line 42 def memoize_table_column(*raw_columns, editable: true) RedisMemo::MemoizeQuery.__send__(:using_active_record!, self) return if RedisMemo::DefaultOptions.disable_all return if RedisMemo::DefaultOptions.model_disabled_for_caching?(self) columns = raw_columns.map(&:to_sym).sort RedisMemo::MemoizeQuery.memoized_columns(self, editable_only: true) << columns if editable RedisMemo::MemoizeQuery.memoized_columns(self, editable_only: false) << columns RedisMemo::MemoizeQuery::ModelCallback.install(self) RedisMemo::MemoizeQuery::Invalidation.install(self) unless RedisMemo::DefaultOptions.disable_cached_select RedisMemo::MemoizeQuery::CachedSelect.install(ActiveRecord::Base.connection) end # The code below might fail due to missing DB/table errors columns.each do |column| next if columns_hash.include?(column.to_s) raise RedisMemo::ArgumentError.new("'#{name}' does not contain column '#{column}'") end unless RedisMemo::DefaultOptions.model_disabled_for_caching?(self) RedisMemo::MemoizeQuery::CachedSelect.enabled_models[table_name] = self end rescue ActiveRecord::NoDatabaseError, ActiveRecord::StatementInvalid # no-opts: models with memoize_table_column decleared might be loaded in # rake tasks that are used to create databases end |