db_memoize
library to cache (memoize) method return values in database
Note: when updating from version 0.1 to 0.2 you need to run a migration on the existing table, see below.
Usage in ActiveRecord models:
Example Class:
class Letter < ActiveRecord::Base
include DbMemoize::Model
def hello(name = 'John')
"Hello #{name}!"
end
db_memoize :hello
def bye
'Best regards'
end
db_memoize :bye
end
Get Values
record = Letter.first
record.hello
=> 'Hello John!'
record.hello
=> 'Hello John!'
will call the original method only once. Consecutive calls will return a cached value.
If the method takes arguments..
record.hello('Maria')
record.hello('John')
a cached value will be created for every set of arguments.
Clear Values
To clear cached values for a single method
record.unmemoize(:hello)
To clear all cached values of one record
record.unmemoize
To clear cached values of given records for a single method
Letter.unmemoize([letter1, letter2], :hello)
To clear all cached values of given records
Letter.unmemoize([letter1, letter2])
Instead of ActiveRecord instances it's sufficient to pass in the ids of the records, too
Letter.unmemoize([23,24])
Gotchas
As the cached values themselves are writtten to the database, are ActiveRecord records (of type DbMemoize::Value) and are reqistered as an association you can access all of the cached values of an object like this:
record.memoized_values
This means you can also very easily perform eager loading on them:
Letter.includes(:memoized_values).all
DbMemoize by default will write log output to STDOUT. You can change this by setting another logger like so:
DbMemoize.logger = your_logger
Rake Tasks
To warmup your cache you can pre-generate cached values via a rake task like this (only works for methods not depending on arguments)
bundle exec rake db_memoize:warmup class=Letter methods=hello,bye
Similarly you can wipe all cached values for a given class
bundle exec rake db_memoize:clear class=Letter
Setup
To create the required DB tables add a migration like this:
class CreateMemoizedValues < ActiveRecord::Migration
def up
require 'db_memoize/migrations'
DbMemoize::Migrations.create_tables(self)
end
def down
drop_table :memoized_values
end
end
Testing
Note that db_memoize needs Postgres. To set up the database needed to run tests, this is what you can do:
# sudo su postgresql
# createuser >>yourusername<< # createdb -O >>yourusername<< db_memoize_test
Updating from 0.1 -> 0.2
You need to run a migration, like the following:
class FixDbMemoizeTable < ActiveRecord::Migration
def up
# After updating db_memoize to 0.2 we need to update some structures, depending
# on whether or not db_memoize 0.1 or 0.2 was creating the database tables.
execute " ALTER TABLE memoized_values\n ALTER COLUMN entity_table_name SET NOT NULL,\n ALTER COLUMN entity_id SET NOT NULL,\n ALTER COLUMN method_name SET NOT NULL,\n ALTER COLUMN created_at SET NOT NULL;\n DROP INDEX IF EXISTS index_memoized_values_on_entity_table_name_and_entity_id;\n CREATE INDEX IF NOT EXISTS index_memoized_values_on_entity_id_and_entity_table_name \n ON memoized_values(entity_id, entity_table_name);\n CREATE INDEX IF NOT EXISTS memoized_attributes_idx \n ON memoized_values (((arguments_hash IS NULL)))\n SQL\n end\n\n def down\n execute <<-SQL\n DROP INDEX memoized_attributes_idx;\n DROP INDEX index_memoized_values_on_entity_id_and_entity_table_name;\n SQL\n end\nend\n"
Have fun!