Added statement cache
This commit is contained in:
parent
45321a69b3
commit
af1a4bdc56
@ -1,5 +1,22 @@
|
|||||||
## Rails 4.0.0 (unreleased) ##
|
## Rails 4.0.0 (unreleased) ##
|
||||||
|
|
||||||
|
* Added Statement Cache to allow the caching of a single statement. The cache works by
|
||||||
|
duping the relation returned from yielding a statement which allows skipping the AST
|
||||||
|
building phase.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
cache = ActiveRecord::StatementCache.new do
|
||||||
|
Book.where(:name => "my book").limit(100)
|
||||||
|
end
|
||||||
|
|
||||||
|
books = cache.execute
|
||||||
|
|
||||||
|
The solution attempts to get closer to the speed of `find_by_sql` but still maintaining
|
||||||
|
the expressiveness of the AR queries.
|
||||||
|
|
||||||
|
*Olli Rissanen*
|
||||||
|
|
||||||
* Fixing issue #8345. Now throwing an error when one attempts to touch a
|
* Fixing issue #8345. Now throwing an error when one attempts to touch a
|
||||||
new object that has not yet been persisted. For instance:
|
new object that has not yet been persisted. For instance:
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ module ActiveRecord
|
|||||||
autoload :SchemaMigration
|
autoload :SchemaMigration
|
||||||
autoload :Scoping
|
autoload :Scoping
|
||||||
autoload :Serialization
|
autoload :Serialization
|
||||||
|
autoload :StatementCache
|
||||||
autoload :Store
|
autoload :Store
|
||||||
autoload :Timestamp
|
autoload :Timestamp
|
||||||
autoload :Transactions
|
autoload :Transactions
|
||||||
|
26
activerecord/lib/active_record/statement_cache.rb
Normal file
26
activerecord/lib/active_record/statement_cache.rb
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
module ActiveRecord
|
||||||
|
|
||||||
|
# Statement cache is used to cache a single statement in order to avoid creating the AST again.
|
||||||
|
# Initializing the cache is done by passing the statement in the initialization block:
|
||||||
|
#
|
||||||
|
# cache = ActiveRecord::StatementCache.new do
|
||||||
|
# Book.where(:name => "my book").limit(100)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# The cached statement is executed by using the +execute+ method:
|
||||||
|
#
|
||||||
|
# cache.execute
|
||||||
|
#
|
||||||
|
# The relation returned by yield is cached, and for each +execute+ call the cached relation gets duped.
|
||||||
|
# Database is queried when +to_a+ is called on the relation.
|
||||||
|
class StatementCache
|
||||||
|
def initialize
|
||||||
|
@relation = yield
|
||||||
|
raise ArgumentError.new("Statement cannot be nil") if @relation.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
@relation.dup.to_a
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
64
activerecord/test/cases/statement_cache_test.rb
Normal file
64
activerecord/test/cases/statement_cache_test.rb
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
require 'cases/helper'
|
||||||
|
require 'models/book'
|
||||||
|
require 'models/liquid'
|
||||||
|
require 'models/molecule'
|
||||||
|
require 'models/electron'
|
||||||
|
|
||||||
|
module ActiveRecord
|
||||||
|
class StatementCacheTest < ActiveRecord::TestCase
|
||||||
|
def setup
|
||||||
|
@connection = ActiveRecord::Base.connection
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_statement_cache_with_simple_statement
|
||||||
|
cache = ActiveRecord::StatementCache.new do
|
||||||
|
Book.where(name: "my book").where("author_id > 3")
|
||||||
|
end
|
||||||
|
|
||||||
|
Book.create(name: "my book", author_id: 4)
|
||||||
|
|
||||||
|
books = cache.execute
|
||||||
|
assert_equal "my book", books[0].name
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_statement_cache_with_nil_statement_raises_error
|
||||||
|
assert_raise(ArgumentError) do
|
||||||
|
cache = ActiveRecord::StatementCache.new do
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_statement_cache_with_complex_statement
|
||||||
|
cache = ActiveRecord::StatementCache.new do
|
||||||
|
Liquid.joins(:molecules => :electrons).where('molecules.name' => 'dioxane', 'electrons.name' => 'lepton')
|
||||||
|
end
|
||||||
|
|
||||||
|
salty = Liquid.create(name: 'salty')
|
||||||
|
molecule = salty.molecules.create(name: 'dioxane')
|
||||||
|
electron = molecule.electrons.create(name: 'lepton')
|
||||||
|
|
||||||
|
liquids = cache.execute
|
||||||
|
assert_equal "salty", liquids[0].name
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_statement_cache_values_differ
|
||||||
|
cache = ActiveRecord::StatementCache.new do
|
||||||
|
Book.where(name: "my book")
|
||||||
|
end
|
||||||
|
|
||||||
|
for i in 0..2 do
|
||||||
|
Book.create(name: "my book")
|
||||||
|
end
|
||||||
|
|
||||||
|
first_books = cache.execute
|
||||||
|
|
||||||
|
for i in 0..2 do
|
||||||
|
Book.create(name: "my book")
|
||||||
|
end
|
||||||
|
|
||||||
|
additional_books = cache.execute
|
||||||
|
assert first_books != additional_books
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user