kasket 3.1.5 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|