kasket 3.1.5 → 3.2.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.
- checksums.yaml +4 -4
- data/lib/kasket.rb +0 -6
- data/lib/kasket/configuration_mixin.rb +0 -1
- data/lib/kasket/dirty_mixin.rb +0 -1
- data/lib/kasket/query_parser.rb +1 -14
- data/lib/kasket/read_mixin.rb +1 -2
- data/lib/kasket/reload_association_mixin.rb +1 -3
- data/lib/kasket/version.rb +2 -3
- data/lib/kasket/visitor.rb +15 -15
- data/lib/kasket/write_mixin.rb +0 -1
- metadata +49 -73
- data/test/cache_expiry_test.rb +0 -49
- data/test/cacheable_test.rb +0 -58
- data/test/configuration_mixin_test.rb +0 -44
- data/test/database.yml +0 -7
- data/test/dirty_test.rb +0 -16
- data/test/find_one_test.rb +0 -61
- data/test/find_some_test.rb +0 -55
- data/test/fixtures/authors.yml +0 -7
- data/test/fixtures/blogs.yml +0 -5
- data/test/fixtures/comments.yml +0 -16
- data/test/fixtures/posts.yml +0 -24
- data/test/helper.rb +0 -84
- data/test/parser_test.rb +0 -153
- data/test/read_mixin_test.rb +0 -89
- data/test/reload_test.rb +0 -17
- data/test/schema.rb +0 -31
- data/test/test_models.rb +0 -44
- data/test/transaction_test.rb +0 -27
- data/test/visitor_test.rb +0 -39
data/test/cache_expiry_test.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
require File.expand_path("helper", File.dirname(__FILE__))
|
2
|
-
|
3
|
-
class CacheExpiryTest < ActiveSupport::TestCase
|
4
|
-
fixtures :blogs, :posts
|
5
|
-
|
6
|
-
context "a cached object" do
|
7
|
-
setup do
|
8
|
-
post = Post.first
|
9
|
-
@post = Post.find(post.id)
|
10
|
-
|
11
|
-
assert(Kasket.cache.read(@post.kasket_key))
|
12
|
-
end
|
13
|
-
|
14
|
-
should "be removed from cache when deleted" do
|
15
|
-
@post.destroy
|
16
|
-
assert_nil(Kasket.cache.read(@post.kasket_key))
|
17
|
-
end
|
18
|
-
|
19
|
-
should "clear all indices for instance when deleted" do
|
20
|
-
Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "id=#{@post.id}")
|
21
|
-
Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "title='#{@post.title}'")
|
22
|
-
Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "title='#{@post.title}'/first")
|
23
|
-
Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "blog_id=#{@post.blog_id}/id=#{@post.id}")
|
24
|
-
Kasket.cache.expects(:delete).never
|
25
|
-
|
26
|
-
@post.destroy
|
27
|
-
end
|
28
|
-
|
29
|
-
should "be removed from cache when updated" do
|
30
|
-
@post.title = "new_title"
|
31
|
-
@post.save
|
32
|
-
assert_nil(Kasket.cache.read(@post.kasket_key))
|
33
|
-
end
|
34
|
-
|
35
|
-
should "clear all indices for instance when updated" do
|
36
|
-
Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "id=#{@post.id}")
|
37
|
-
Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "title='#{@post.title}'")
|
38
|
-
Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "title='#{@post.title}'/first")
|
39
|
-
Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "title='new_title'")
|
40
|
-
Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "title='new_title'/first")
|
41
|
-
Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "blog_id=#{@post.blog_id}/id=#{@post.id}")
|
42
|
-
Kasket.cache.expects(:delete).never
|
43
|
-
|
44
|
-
@post.title = "new_title"
|
45
|
-
@post.save
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
end
|
data/test/cacheable_test.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
require File.expand_path("helper", File.dirname(__FILE__))
|
2
|
-
|
3
|
-
class CacheableTest < ActiveSupport::TestCase
|
4
|
-
context "#store_in_kasket" do
|
5
|
-
should "only cache object that are kasket_cacheable?" do
|
6
|
-
post = Post.send(:instantiate, { 'id' => 1, 'title' => 'Hello' })
|
7
|
-
|
8
|
-
post.expects(:kasket_cacheable?).returns(true)
|
9
|
-
Kasket.cache.expects(:write).once
|
10
|
-
post.store_in_kasket
|
11
|
-
|
12
|
-
post.expects(:kasket_cacheable?).returns(false)
|
13
|
-
Kasket.cache.expects(:write).never
|
14
|
-
post.store_in_kasket
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
context "caching of results of find" do
|
19
|
-
setup do
|
20
|
-
@post_database_result = { 'id' => 1, 'title' => 'Hello' }
|
21
|
-
@post_records = [Post.send(:instantiate, @post_database_result)]
|
22
|
-
Post.stubs(:find_by_sql_without_kasket).returns(@post_records)
|
23
|
-
|
24
|
-
@comment_database_result = [{ 'id' => 1, 'body' => 'Hello' }, { 'id' => 2, 'body' => 'World' }]
|
25
|
-
@comment_records = @comment_database_result.map {|r| Comment.send(:instantiate, r)}
|
26
|
-
Comment.stubs(:find_by_sql_without_kasket).returns(@comment_records)
|
27
|
-
end
|
28
|
-
|
29
|
-
context "with just one result" do
|
30
|
-
should "write result in cache if it is kasket_cacheable?" do
|
31
|
-
Post.any_instance.expects(:kasket_cacheable?).returns(true)
|
32
|
-
Kasket.cache.expects(:write).once
|
33
|
-
Post.find(1)
|
34
|
-
end
|
35
|
-
|
36
|
-
should "not write result in cache if it is not kasket_cacheable?" do
|
37
|
-
Post.any_instance.expects(:kasket_cacheable?).returns(false)
|
38
|
-
Kasket.cache.expects(:write).never
|
39
|
-
Post.find(1)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
context "with several results" do
|
44
|
-
should "write result in cache if all results are kasket_cacheable?" do
|
45
|
-
Comment.any_instance.stubs(:kasket_cacheable?).returns(true)
|
46
|
-
Kasket.cache.expects(:write).times(@comment_records.size + 1)
|
47
|
-
Comment.all(:conditions => {:post_id => 1})
|
48
|
-
end
|
49
|
-
|
50
|
-
should "not write result in cache if any of them are not kasket_cacheable?" do
|
51
|
-
@comment_records[0].expects(:kasket_cacheable?).returns(true)
|
52
|
-
@comment_records[1].expects(:kasket_cacheable?).returns(false)
|
53
|
-
Kasket.cache.expects(:write).never
|
54
|
-
Comment.all(:conditions => {:post_id => 1})
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require File.expand_path("helper", File.dirname(__FILE__))
|
2
|
-
require "digest/md5"
|
3
|
-
|
4
|
-
class ConfigurationMixinTest < ActiveSupport::TestCase
|
5
|
-
context "Generating cache keys" do
|
6
|
-
should "not choke on empty numeric attributes" do
|
7
|
-
expected_cache_key = "#{Post.kasket_key_prefix}blog_id=null"
|
8
|
-
query_attributes = [ [:blog_id, ''] ]
|
9
|
-
|
10
|
-
assert_equal expected_cache_key, Post.kasket_key_for(query_attributes)
|
11
|
-
end
|
12
|
-
|
13
|
-
should "not fail on unknown columns" do
|
14
|
-
expected_cache_key = "#{Post.kasket_key_prefix}does_not_exist=111"
|
15
|
-
query_attributes = [ [:does_not_exist, '111'] ]
|
16
|
-
|
17
|
-
assert_equal expected_cache_key, Post.kasket_key_for(query_attributes)
|
18
|
-
end
|
19
|
-
|
20
|
-
should "not generate keys longer that 255" do
|
21
|
-
very_large_number = (1..999).to_a.join
|
22
|
-
query_attributes = [ [:blog_id, very_large_number] ]
|
23
|
-
|
24
|
-
assert(Post.kasket_key_for(query_attributes).size < 255)
|
25
|
-
end
|
26
|
-
|
27
|
-
should "not generate keys with spaces" do
|
28
|
-
query_attributes = [ [:title, 'this key has speces'] ]
|
29
|
-
|
30
|
-
assert(!(Post.kasket_key_for(query_attributes) =~ /\s/))
|
31
|
-
end
|
32
|
-
|
33
|
-
should "downcase string attributes" do
|
34
|
-
query_attributes = [ [:title, 'ThIs'] ]
|
35
|
-
expected_cache_key = "#{Post.kasket_key_prefix}title='this'"
|
36
|
-
|
37
|
-
assert_equal expected_cache_key, Post.kasket_key_for(query_attributes)
|
38
|
-
end
|
39
|
-
|
40
|
-
should "build correct prefix" do
|
41
|
-
assert_equal "kasket-#{Kasket::Version::PROTOCOL}/R#{ActiveRecord::VERSION::MAJOR}#{ActiveRecord::VERSION::MINOR}/posts/version=#{POST_VERSION}/", Post.kasket_key_prefix
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
data/test/database.yml
DELETED
data/test/dirty_test.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
require File.expand_path("helper", File.dirname(__FILE__))
|
2
|
-
|
3
|
-
class DirtyTest < ActiveSupport::TestCase
|
4
|
-
fixtures :blogs, :posts
|
5
|
-
|
6
|
-
should "clear the indices when a dirty method is called" do
|
7
|
-
post = Post.first
|
8
|
-
|
9
|
-
Post.cache { pots = Post.find(post.id) }
|
10
|
-
assert(Kasket.cache.read(post.kasket_key))
|
11
|
-
|
12
|
-
post.make_dirty!
|
13
|
-
|
14
|
-
assert_nil(Kasket.cache.read(post.kasket_key))
|
15
|
-
end
|
16
|
-
end
|
data/test/find_one_test.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
require File.expand_path("helper", File.dirname(__FILE__))
|
2
|
-
|
3
|
-
class FindOneTest < ActiveSupport::TestCase
|
4
|
-
fixtures :blogs, :posts
|
5
|
-
|
6
|
-
should "cache find(id) calls" do
|
7
|
-
post = Post.first
|
8
|
-
Kasket.cache.write(post.kasket_key, nil)
|
9
|
-
assert_equal(post, Post.find(post.id))
|
10
|
-
assert(Kasket.cache.read(post.kasket_key))
|
11
|
-
Post.connection.expects(:select_all).never
|
12
|
-
assert_equal(post, Post.find(post.id))
|
13
|
-
end
|
14
|
-
|
15
|
-
should "only cache on indexed attributes" do
|
16
|
-
Kasket.cache.expects(:read).twice
|
17
|
-
Post.find_by_id(1)
|
18
|
-
Post.find_by_id(1, :conditions => {:blog_id => 2})
|
19
|
-
|
20
|
-
Kasket.cache.expects(:read).never
|
21
|
-
Post.first :conditions => {:blog_id => 2}
|
22
|
-
end
|
23
|
-
|
24
|
-
should "not use cache when using the :select option" do
|
25
|
-
post = Post.first
|
26
|
-
assert_nil(Kasket.cache.read(post.kasket_key))
|
27
|
-
|
28
|
-
Post.find(post.id, :select => 'title')
|
29
|
-
assert_nil(Kasket.cache.read(post.kasket_key))
|
30
|
-
|
31
|
-
Post.find(post.id)
|
32
|
-
assert(Kasket.cache.read(post.kasket_key))
|
33
|
-
|
34
|
-
Kasket.cache.expects(:read)
|
35
|
-
Post.find(post.id, :select => nil)
|
36
|
-
|
37
|
-
Kasket.cache.expects(:read).never
|
38
|
-
Post.find(post.id, :select => 'title')
|
39
|
-
end
|
40
|
-
|
41
|
-
should "respect scope" do
|
42
|
-
post = Post.find(Post.first.id)
|
43
|
-
other_blog = Blog.first(:conditions => "id != #{post.blog_id}")
|
44
|
-
|
45
|
-
assert(Kasket.cache.read(post.kasket_key))
|
46
|
-
|
47
|
-
assert_raise(ActiveRecord::RecordNotFound) do
|
48
|
-
other_blog.posts.find(post.id)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
should "use same scope when finding on has_many" do
|
53
|
-
post = Blog.first.posts.first
|
54
|
-
blog = Blog.first
|
55
|
-
Rails.cache.clear
|
56
|
-
|
57
|
-
post = blog.posts.find_by_id(post.id)
|
58
|
-
key = post.kasket_key.sub(%r{(/id=#{post.id})}, "/blog_id=#{Blog.first.id}\\1")
|
59
|
-
assert(Kasket.cache.read(key))
|
60
|
-
end
|
61
|
-
end
|
data/test/find_some_test.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
require File.expand_path("helper", File.dirname(__FILE__))
|
2
|
-
|
3
|
-
class FindSomeTest < ActiveSupport::TestCase
|
4
|
-
fixtures :blogs, :posts
|
5
|
-
|
6
|
-
def setup
|
7
|
-
@post1 = Post.first
|
8
|
-
@post2 = Post.last
|
9
|
-
Post.find(@post1.id, @post2.id)
|
10
|
-
assert Kasket.cache.read(@post1.kasket_key)
|
11
|
-
assert Kasket.cache.read(@post2.kasket_key)
|
12
|
-
end
|
13
|
-
|
14
|
-
should "use cache for find(id, id) calls" do
|
15
|
-
Post.connection.expects(:select_all).never
|
16
|
-
Post.find(@post1.id, @post2.id)
|
17
|
-
end
|
18
|
-
|
19
|
-
should "cache when found using find(id, id) calls" do
|
20
|
-
Kasket.cache.delete(@post1.kasket_key)
|
21
|
-
Kasket.cache.delete(@post2.kasket_key)
|
22
|
-
|
23
|
-
Post.find(@post1.id, @post2.id)
|
24
|
-
|
25
|
-
assert Kasket.cache.read(@post1.kasket_key)
|
26
|
-
assert Kasket.cache.read(@post2.kasket_key)
|
27
|
-
end
|
28
|
-
|
29
|
-
should "only lookup the records that are not in the cache" do
|
30
|
-
Kasket.cache.delete(@post2.kasket_key)
|
31
|
-
|
32
|
-
# has to lookup post2 via db
|
33
|
-
Post.expects(:find_by_sql_without_kasket).returns([@post2])
|
34
|
-
found_posts = Post.find(@post1.id, @post2.id)
|
35
|
-
assert_equal [@post1, @post2].map(&:id).sort, found_posts.map(&:id).sort
|
36
|
-
|
37
|
-
# now all are cached
|
38
|
-
Post.expects(:find_by_sql_without_kasket).never
|
39
|
-
found_posts = Post.find(@post1.id, @post2.id)
|
40
|
-
assert_equal [@post1, @post2].map(&:id).sort, found_posts.map(&:id).sort
|
41
|
-
end
|
42
|
-
|
43
|
-
context "unfound" do
|
44
|
-
should "ignore unfound when using find_all_by_id" do
|
45
|
-
found_posts = Post.find_all_by_id([@post1.id, 1231232])
|
46
|
-
assert_equal [@post1.id], found_posts.map(&:id)
|
47
|
-
end
|
48
|
-
|
49
|
-
should "not ignore unfound when using find" do
|
50
|
-
assert_raise ActiveRecord::RecordNotFound do
|
51
|
-
Post.find(@post1.id, 1231232)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
data/test/fixtures/authors.yml
DELETED
data/test/fixtures/blogs.yml
DELETED
data/test/fixtures/comments.yml
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
few_comments_1:
|
2
|
-
id: 1
|
3
|
-
post_id: 2
|
4
|
-
body: what ever body 1
|
5
|
-
|
6
|
-
few_comments_2:
|
7
|
-
id: 2
|
8
|
-
post_id: 2
|
9
|
-
body: what ever body 2
|
10
|
-
|
11
|
-
<% (1..10).each do |i| %>
|
12
|
-
many_comments_<%= i %>:
|
13
|
-
post: has_many_comments
|
14
|
-
body: what ever body <%= i %>
|
15
|
-
<% end %>
|
16
|
-
|
data/test/fixtures/posts.yml
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
no_comments:
|
2
|
-
id: 1
|
3
|
-
blog: a_blog
|
4
|
-
title: no_comments
|
5
|
-
author: mick
|
6
|
-
created_at: 2013-10-14 15:30:00
|
7
|
-
|
8
|
-
has_two_comments:
|
9
|
-
id: 2
|
10
|
-
blog: a_blog
|
11
|
-
title: few_comments
|
12
|
-
author: mick
|
13
|
-
|
14
|
-
on_other_blog:
|
15
|
-
id: 3
|
16
|
-
blog: other_blog
|
17
|
-
title: no_comments
|
18
|
-
author: eric
|
19
|
-
|
20
|
-
has_many_comments:
|
21
|
-
id: 4
|
22
|
-
blog: a_blog
|
23
|
-
title: many_comments
|
24
|
-
author: eric
|
data/test/helper.rb
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
|
3
|
-
require 'bundler'
|
4
|
-
Bundler.setup
|
5
|
-
# shoulda-matchers dependency:
|
6
|
-
require 'active_support/core_ext/module/delegation'
|
7
|
-
Bundler.require(:default, :development)
|
8
|
-
|
9
|
-
if defined?(Debugger)
|
10
|
-
::Debugger.start
|
11
|
-
::Debugger.settings[:autoeval] = true if ::Debugger.respond_to?(:settings)
|
12
|
-
end
|
13
|
-
|
14
|
-
require 'test/unit'
|
15
|
-
require 'mocha'
|
16
|
-
require 'active_record'
|
17
|
-
require "logger"
|
18
|
-
|
19
|
-
raise "Must configure #time_zone_aware_attributes prior to models" if defined?(Post)
|
20
|
-
ENV['TZ'] = 'utc'
|
21
|
-
ActiveRecord::Base.time_zone_aware_attributes = true
|
22
|
-
ActiveRecord::Base.logger = Logger.new(StringIO.new)
|
23
|
-
|
24
|
-
require 'active_record/fixtures'
|
25
|
-
|
26
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
27
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
28
|
-
require 'kasket'
|
29
|
-
|
30
|
-
Kasket.setup
|
31
|
-
|
32
|
-
class ActiveSupport::TestCase
|
33
|
-
include ActiveRecord::TestFixtures
|
34
|
-
|
35
|
-
def create_fixtures(*table_names)
|
36
|
-
if block_given?
|
37
|
-
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
|
38
|
-
else
|
39
|
-
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
self.use_transactional_fixtures = true
|
44
|
-
|
45
|
-
self.use_instantiated_fixtures = false
|
46
|
-
|
47
|
-
setup :clear_cache
|
48
|
-
def clear_cache
|
49
|
-
Kasket.cache.clear
|
50
|
-
end
|
51
|
-
|
52
|
-
def arel?
|
53
|
-
self.class.arel?
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.arel?
|
57
|
-
ActiveRecord::VERSION::MAJOR >= 3 && ActiveRecord::VERSION::MINOR >= 1
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
ActiveSupport::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
|
62
|
-
$LOAD_PATH.unshift(ActiveSupport::TestCase.fixture_path)
|
63
|
-
|
64
|
-
class ActiveSupport::TestCase
|
65
|
-
fixtures :all
|
66
|
-
end
|
67
|
-
|
68
|
-
module Rails
|
69
|
-
module_function
|
70
|
-
CACHE = ActiveSupport::Cache::MemoryStore.new
|
71
|
-
LOGGER = Logger.new(STDOUT)
|
72
|
-
|
73
|
-
def cache
|
74
|
-
CACHE
|
75
|
-
end
|
76
|
-
|
77
|
-
def logger
|
78
|
-
LOGGER
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
require 'test_models'
|
83
|
-
POST_VERSION = Post.column_names.join.sum
|
84
|
-
COMMENT_VERSION = Comment.column_names.join.sum
|
data/test/parser_test.rb
DELETED
@@ -1,153 +0,0 @@
|
|
1
|
-
require File.expand_path("helper", File.dirname(__FILE__))
|
2
|
-
require 'kasket/query_parser'
|
3
|
-
|
4
|
-
class ParserTest < ActiveSupport::TestCase
|
5
|
-
def parse(options)
|
6
|
-
scope = Post
|
7
|
-
if arel?
|
8
|
-
options.each do |k,v|
|
9
|
-
scope = case k
|
10
|
-
when :conditions then scope.where(v)
|
11
|
-
else
|
12
|
-
scope.send(k, v)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
scope.to_kasket_query
|
16
|
-
elsif ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0
|
17
|
-
@parser.parse(scope.scoped(options).to_sql)
|
18
|
-
else
|
19
|
-
sql = scope.send(:construct_finder_sql, options)
|
20
|
-
@parser.parse(sql)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
context "Parsing" do
|
25
|
-
setup do
|
26
|
-
@parser = Kasket::QueryParser.new(Post)
|
27
|
-
end
|
28
|
-
|
29
|
-
should "not support conditions with number as column (e.g. 0 = 1)" do
|
30
|
-
assert !parse(:conditions => "0 = 1")
|
31
|
-
end
|
32
|
-
|
33
|
-
should "not support conditions with number as column and parans (e.g. 0 = 1)" do
|
34
|
-
assert !parse(:conditions => "(0 = 1)")
|
35
|
-
end
|
36
|
-
|
37
|
-
should "not support :order" do
|
38
|
-
assert !parse(:conditions => "id = 1", :order => "xxx")
|
39
|
-
end
|
40
|
-
|
41
|
-
should 'not support IN queries in combination with other conditions' do
|
42
|
-
assert !parse(:conditions => {:id => [1,2,3], :is_active => true})
|
43
|
-
end
|
44
|
-
|
45
|
-
should "extract conditions" do
|
46
|
-
kasket_query = parse(:conditions => {:title => 'red', :blog_id => 1})
|
47
|
-
assert_equal [[:blog_id, "1"], [:title, "red"]], kasket_query[:attributes]
|
48
|
-
end
|
49
|
-
|
50
|
-
should "extract conditions with parans that do not surround" do
|
51
|
-
kasket_query = parse(:conditions => "(title = 'red') AND (blog_id = 1)")
|
52
|
-
if ActiveRecord::VERSION::STRING > "3.1.0"
|
53
|
-
assert !kasket_query
|
54
|
-
else
|
55
|
-
assert_equal [[:blog_id, "1"], [:title, "red"]], kasket_query[:attributes]
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
should "extract required index" do
|
60
|
-
assert_equal [:blog_id, :title], parse(:conditions => {:title => 'red', :blog_id => 1})[:index]
|
61
|
-
end
|
62
|
-
|
63
|
-
should "only support queries against its model's table" do
|
64
|
-
assert !parse(:conditions => {'blogs.id' => 2}, :from => 'apples')
|
65
|
-
end
|
66
|
-
|
67
|
-
should "support cachable queries" do
|
68
|
-
assert parse(:conditions => {:id => 1})
|
69
|
-
assert parse(:conditions => {:id => 1}, :limit => 1)
|
70
|
-
end
|
71
|
-
|
72
|
-
should "support IN queries on id" do
|
73
|
-
assert_equal [[:id, ['1', '2', '3']]], parse(:conditions => {:id => [1,2,3]})[:attributes]
|
74
|
-
end
|
75
|
-
|
76
|
-
should "not support IN queries on other attributes" do
|
77
|
-
assert !parse(:conditions => {:hest => [1,2,3]})
|
78
|
-
end
|
79
|
-
|
80
|
-
should "support vaguely formatted queries" do
|
81
|
-
assert @parser.parse('SELECT * FROM "posts" WHERE (title = red AND blog_id = big)')
|
82
|
-
end
|
83
|
-
|
84
|
-
context "extract options" do
|
85
|
-
should "provide the limit" do
|
86
|
-
assert_equal nil, parse(:conditions => {:id => 2})[:limit]
|
87
|
-
assert_equal 1, parse(:conditions => {:id => 2}, :limit => 1)[:limit]
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
context "unsupported queries" do
|
92
|
-
should "include advanced limits" do
|
93
|
-
assert !parse(:conditions => {:title => 'red', :blog_id => 1}, :limit => 2)
|
94
|
-
end
|
95
|
-
|
96
|
-
should "include joins" do
|
97
|
-
assert !parse(:conditions => {:title => 'test', 'apple.tree_id' => 'posts.id'}, :from => ['posts', 'apple'])
|
98
|
-
assert !parse(:conditions => {:title => 'test'}, :joins => :comments)
|
99
|
-
end
|
100
|
-
|
101
|
-
should "include specific selects" do
|
102
|
-
assert !parse(:conditions => {:title => 'red'}, :select => :id)
|
103
|
-
end
|
104
|
-
|
105
|
-
should "include offset" do
|
106
|
-
assert !parse(:conditions => {:title => 'red'}, :limit => 1, :offset => 2)
|
107
|
-
end
|
108
|
-
|
109
|
-
should "include order" do
|
110
|
-
assert !parse(:conditions => {:title => 'red'}, :order => :title)
|
111
|
-
end
|
112
|
-
|
113
|
-
should "include the OR operator" do
|
114
|
-
assert !parse(:conditions => "title = 'red' OR blog_id = 1")
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
context "key generation" do
|
119
|
-
should "include the table name and version" do
|
120
|
-
kasket_query = parse(:conditions => {:id => 1})
|
121
|
-
assert_match(/^kasket-#{Kasket::Version::PROTOCOL}\/R#{ActiveRecord::VERSION::MAJOR}#{ActiveRecord::VERSION::MINOR}\/posts\/version=#{POST_VERSION}\//, kasket_query[:key])
|
122
|
-
end
|
123
|
-
|
124
|
-
should "include all indexed attributes" do
|
125
|
-
kasket_query = parse(:conditions => {:id => 1})
|
126
|
-
assert_match(/id=1$/, kasket_query[:key])
|
127
|
-
|
128
|
-
kasket_query = parse(:conditions => {:id => 1, :blog_id => 2})
|
129
|
-
assert_match(/blog_id=2\/id=1$/, kasket_query[:key])
|
130
|
-
|
131
|
-
kasket_query = parse(:conditions => {:id => 1, :title => 'title'})
|
132
|
-
assert_match(/id=1\/title='title'$/, kasket_query[:key])
|
133
|
-
end
|
134
|
-
|
135
|
-
should "generate multiple keys on IN queries" do
|
136
|
-
keys = parse(:conditions => {:id => [1,2]})[:key]
|
137
|
-
assert_instance_of(Array, keys)
|
138
|
-
assert_match(/id=1$/, keys[0])
|
139
|
-
assert_match(/id=2$/, keys[1])
|
140
|
-
end
|
141
|
-
|
142
|
-
context "when limit 1" do
|
143
|
-
should "add /first to the key if the index does not include id" do
|
144
|
-
assert_match(/title='a'\/first$/, parse(:conditions => {:title => 'a'}, :limit => 1)[:key])
|
145
|
-
end
|
146
|
-
|
147
|
-
should "not add /first to the key when the index includes id" do
|
148
|
-
assert_match(/id=1$/, parse(:conditions => {:id => 1}, :limit => 1)[:key])
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|