record_filter 0.9.12
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.
- data/.gitignore +9 -0
- data/CHANGELOG +232 -0
- data/README.rdoc +354 -0
- data/Rakefile +92 -0
- data/TODO +3 -0
- data/VERSION.yml +4 -0
- data/config/roodi.yml +14 -0
- data/lib/record_filter/active_record.rb +108 -0
- data/lib/record_filter/column_parser.rb +14 -0
- data/lib/record_filter/conjunctions.rb +169 -0
- data/lib/record_filter/dsl/class_join.rb +16 -0
- data/lib/record_filter/dsl/conjunction.rb +57 -0
- data/lib/record_filter/dsl/conjunction_dsl.rb +317 -0
- data/lib/record_filter/dsl/dsl.rb +143 -0
- data/lib/record_filter/dsl/dsl_factory.rb +19 -0
- data/lib/record_filter/dsl/group_by.rb +11 -0
- data/lib/record_filter/dsl/join.rb +12 -0
- data/lib/record_filter/dsl/join_condition.rb +21 -0
- data/lib/record_filter/dsl/join_dsl.rb +49 -0
- data/lib/record_filter/dsl/limit.rb +12 -0
- data/lib/record_filter/dsl/named_filter.rb +12 -0
- data/lib/record_filter/dsl/order.rb +12 -0
- data/lib/record_filter/dsl/restriction.rb +314 -0
- data/lib/record_filter/dsl.rb +21 -0
- data/lib/record_filter/filter.rb +105 -0
- data/lib/record_filter/group_by.rb +21 -0
- data/lib/record_filter/join.rb +66 -0
- data/lib/record_filter/order.rb +27 -0
- data/lib/record_filter/query.rb +60 -0
- data/lib/record_filter/restriction_factory.rb +21 -0
- data/lib/record_filter/restrictions.rb +97 -0
- data/lib/record_filter/table.rb +172 -0
- data/lib/record_filter.rb +35 -0
- data/record_filter.gemspec +108 -0
- data/script/console +8 -0
- data/spec/active_record_spec.rb +211 -0
- data/spec/exception_spec.rb +208 -0
- data/spec/explicit_join_spec.rb +132 -0
- data/spec/implicit_join_spec.rb +403 -0
- data/spec/limits_and_ordering_spec.rb +230 -0
- data/spec/models.rb +109 -0
- data/spec/named_filter_spec.rb +264 -0
- data/spec/proxying_spec.rb +63 -0
- data/spec/restrictions_spec.rb +251 -0
- data/spec/select_spec.rb +79 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/test.db +0 -0
- data/tasks/db.rake +106 -0
- data/tasks/rcov.rake +9 -0
- data/tasks/spec.rake +10 -0
- data/test/performance_test.rb +39 -0
- data/test/test.db +0 -0
- metadata +137 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
|
2
|
+
|
|
3
|
+
describe 'raising exceptions' do
|
|
4
|
+
before do
|
|
5
|
+
TestModel.extended_models.each { |model| model.last_find = {} }
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe 'on missing associations' do
|
|
9
|
+
it 'should get AssociationNotFoundException' do
|
|
10
|
+
lambda {
|
|
11
|
+
Post.filter do
|
|
12
|
+
having(:something_that_does_not_exist) do
|
|
13
|
+
with(:something_bad)
|
|
14
|
+
end
|
|
15
|
+
end.inspect
|
|
16
|
+
}.should raise_error(RecordFilter::AssociationNotFoundException)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe 'on missing columns' do
|
|
21
|
+
it 'should get ColumnNotFoundException for with' do
|
|
22
|
+
lambda {
|
|
23
|
+
Post.filter do
|
|
24
|
+
with(:this_is_not_there, 2)
|
|
25
|
+
end.inspect
|
|
26
|
+
}.should raise_error(RecordFilter::ColumnNotFoundException)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'should get ColumnNotFoundException for with.not' do
|
|
30
|
+
lambda {
|
|
31
|
+
Post.filter do
|
|
32
|
+
with(:this_is_not_there).not.equal_to(2)
|
|
33
|
+
end.inspect
|
|
34
|
+
}.should raise_error(RecordFilter::ColumnNotFoundException)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'should not get ColumnNotFoundException for order' do
|
|
38
|
+
lambda {
|
|
39
|
+
Post.filter do
|
|
40
|
+
order('this_is_not_there', :asc)
|
|
41
|
+
end.inspect
|
|
42
|
+
}.should_not raise_error(RecordFilter::ColumnNotFoundException)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'should not get ColumnNotFoundException for group_by' do
|
|
46
|
+
lambda {
|
|
47
|
+
Post.filter do
|
|
48
|
+
group_by(:this_is_not_there)
|
|
49
|
+
end.inspect
|
|
50
|
+
}.should_not raise_error(RecordFilter::ColumnNotFoundException)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'should get AssociationNotFoundException for orders on bad associations' do
|
|
54
|
+
lambda {
|
|
55
|
+
Post.filter do
|
|
56
|
+
order({ :this_is_not_there => :eh }, :asc)
|
|
57
|
+
end.inspect
|
|
58
|
+
}.should raise_error(RecordFilter::InvalidJoinException)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'should raise ColumnNotFoundException for explicit joins on bad column names for the right table' do
|
|
62
|
+
lambda {
|
|
63
|
+
Review.filter do
|
|
64
|
+
join(Feature, :join_type => :left) do
|
|
65
|
+
on(:reviewable_id => :ftrable_id)
|
|
66
|
+
on(:reviewable_type => :ftrable_type)
|
|
67
|
+
with(:priority, 5)
|
|
68
|
+
end
|
|
69
|
+
end.inspect
|
|
70
|
+
}.should raise_error(RecordFilter::ColumnNotFoundException)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it 'should raise ColumnNotFoundException for explicit joins on bad column names for the left table' do
|
|
74
|
+
lambda {
|
|
75
|
+
Review.filter do
|
|
76
|
+
join(Feature, :join_type => :inner) do
|
|
77
|
+
on(:rvwable_id => :featurable_id)
|
|
78
|
+
on(:rvwable_type => :featurable_type)
|
|
79
|
+
with(:priority, 5)
|
|
80
|
+
end
|
|
81
|
+
end.inspect
|
|
82
|
+
}.should raise_error(RecordFilter::ColumnNotFoundException)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'should raise ColumnNotFoundException for explicit joins on bad column names in conditions' do
|
|
86
|
+
lambda {
|
|
87
|
+
Review.filter do
|
|
88
|
+
join(Feature, :join_type => :inner) do
|
|
89
|
+
on(:reviewable_id).gt(12)
|
|
90
|
+
end
|
|
91
|
+
end.inspect
|
|
92
|
+
}.should raise_error(RecordFilter::ColumnNotFoundException)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it 'should raise an ArgumentError if an invalid join type is specified' do
|
|
96
|
+
lambda {
|
|
97
|
+
Review.filter do
|
|
98
|
+
join(Feature, :join_type => :crazy) do
|
|
99
|
+
on(:reviewable_type => :featurable_type)
|
|
100
|
+
end
|
|
101
|
+
end.inspect
|
|
102
|
+
}.should raise_error(ArgumentError)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it 'should raise an InvalidJoinException if no columns are specified for the join' do
|
|
106
|
+
lambda {
|
|
107
|
+
Review.filter do
|
|
108
|
+
join(Feature, :join_type => :inner)
|
|
109
|
+
end.inspect
|
|
110
|
+
}.should raise_error(RecordFilter::InvalidJoinException)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe 'limiting methods within joins and conjunctions' do
|
|
115
|
+
it 'should not allow calls to limit within joins' do
|
|
116
|
+
lambda {
|
|
117
|
+
Post.filter do
|
|
118
|
+
having(:photo) do
|
|
119
|
+
limit 2
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
}.should raise_error(RecordFilter::InvalidFilterException)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it 'should not allow calls to group_by within joins' do
|
|
126
|
+
lambda {
|
|
127
|
+
Post.filter do
|
|
128
|
+
having(:photo) do
|
|
129
|
+
group_by(:id)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
}.should raise_error(RecordFilter::InvalidFilterException)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it 'should not allow calls to order within joins' do
|
|
136
|
+
lambda {
|
|
137
|
+
Post.filter do
|
|
138
|
+
having(:photo) do
|
|
139
|
+
order :id
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
}.should raise_error(RecordFilter::InvalidFilterException)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it 'should not allow calls to limit within conjunctions' do
|
|
146
|
+
lambda {
|
|
147
|
+
Post.filter do
|
|
148
|
+
all_of do
|
|
149
|
+
limit 2
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
}.should raise_error(RecordFilter::InvalidFilterException)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it 'should not allow calls to order within joins' do
|
|
156
|
+
lambda {
|
|
157
|
+
Post.filter do
|
|
158
|
+
all_of do
|
|
159
|
+
order :id
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
}.should raise_error(RecordFilter::InvalidFilterException)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
describe 'limiting calls to on' do
|
|
167
|
+
it 'should not allow calls to on in the outer scope' do
|
|
168
|
+
lambda {
|
|
169
|
+
Post.filter do
|
|
170
|
+
on(:a => :b)
|
|
171
|
+
end
|
|
172
|
+
}.should raise_error(RecordFilter::InvalidFilterException)
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
describe 'calling order with an invalid direction' do
|
|
177
|
+
it 'should raise an InvalidFilterException' do
|
|
178
|
+
lambda {
|
|
179
|
+
Post.filter do
|
|
180
|
+
order(:id, :oops)
|
|
181
|
+
end
|
|
182
|
+
}.should raise_error(RecordFilter::InvalidFilterException)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
describe 'calling named filters within filters' do
|
|
187
|
+
it 'should raise an excpetion if the named filter does not exist' do
|
|
188
|
+
lambda {
|
|
189
|
+
Post.filter do
|
|
190
|
+
having(:comments).does_not_exist
|
|
191
|
+
end
|
|
192
|
+
}.should raise_error(RecordFilter::NamedFilterNotFoundException)
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
describe 'creating named filters with the same name as an existing one' do
|
|
197
|
+
it 'should raise an InvalidFilterNameException' do
|
|
198
|
+
Post.named_filter(:original) do
|
|
199
|
+
with(:permalink, 'abc')
|
|
200
|
+
end
|
|
201
|
+
lambda {
|
|
202
|
+
Post.named_filter(:original) do
|
|
203
|
+
with(:permalink, 'def')
|
|
204
|
+
end
|
|
205
|
+
}.should raise_error(RecordFilter::InvalidFilterNameException)
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
|
2
|
+
|
|
3
|
+
describe 'explicit joins' do
|
|
4
|
+
before do
|
|
5
|
+
TestModel.extended_models.each { |model| model.last_find = {} }
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe 'specifying a simple join' do
|
|
9
|
+
before do
|
|
10
|
+
Post.filter do
|
|
11
|
+
join(Blog, :join_type => :left, :alias => :posts_blogs) do
|
|
12
|
+
on(:blog_id => :id)
|
|
13
|
+
with(:name, 'Test Name')
|
|
14
|
+
end
|
|
15
|
+
end.inspect
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'should add correct join' do
|
|
19
|
+
Post.last_find[:joins].should == [%q(LEFT OUTER JOIN "blogs" AS posts_blogs ON "posts".blog_id = posts_blogs.id)]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'should query against condition on join table' do
|
|
23
|
+
Post.last_find[:conditions].should == ['posts_blogs.name = ?', 'Test Name']
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe 'specifying a complex join through polymorphic associations' do
|
|
28
|
+
before do
|
|
29
|
+
Review.filter do
|
|
30
|
+
join(Feature, :join_type => :left, :alias => :reviews_features) do
|
|
31
|
+
on(:reviewable_id => :featurable_id)
|
|
32
|
+
on(:reviewable_type => :featurable_type)
|
|
33
|
+
with(:priority, 5)
|
|
34
|
+
end
|
|
35
|
+
end.inspect
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'should add correct join' do
|
|
39
|
+
Review.last_find[:joins].should == [%q(LEFT OUTER JOIN "features" AS reviews_features ON "reviews".reviewable_id = reviews_features.featurable_id AND "reviews".reviewable_type = reviews_features.featurable_type)]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'should query against condition on join table' do
|
|
43
|
+
Review.last_find[:conditions].should == ['reviews_features.priority = ?', 5]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe 'should use values as join parameters instead of columns if given' do
|
|
48
|
+
before do
|
|
49
|
+
Review.filter do
|
|
50
|
+
join(Feature, :join_type => :left) do
|
|
51
|
+
on(:reviewable_id => :featurable_id)
|
|
52
|
+
on(:reviewable_type => :featurable_type)
|
|
53
|
+
on(:featurable_type, 'SomeType')
|
|
54
|
+
with(:priority, 5)
|
|
55
|
+
end
|
|
56
|
+
end.inspect
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'should add correct join' do
|
|
60
|
+
Review.last_find[:joins].should == [%q(LEFT OUTER JOIN "features" AS reviews__feature ON "reviews".reviewable_id = reviews__feature.featurable_id AND "reviews".reviewable_type = reviews__feature.featurable_type AND (reviews__feature.featurable_type = 'SomeType'))]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe 'using restrictions on join conditions' do
|
|
65
|
+
before do
|
|
66
|
+
Review.filter do
|
|
67
|
+
join(Feature, :join_type => :left) do
|
|
68
|
+
on(:featurable_type, nil)
|
|
69
|
+
on(:featurable_id).gte(12)
|
|
70
|
+
on(:priority).not(6)
|
|
71
|
+
end
|
|
72
|
+
end.inspect
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'should add the correct join' do
|
|
76
|
+
Review.last_find[:joins].should == [%q(LEFT OUTER JOIN "features" AS reviews__feature ON (reviews__feature.featurable_type IS NULL) AND (reviews__feature.featurable_id >= 12) AND (reviews__feature.priority <> 6))]
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe 'using implicit and explicit joins together with conditions' do
|
|
81
|
+
before do
|
|
82
|
+
@blog = Class.new(Blog)
|
|
83
|
+
@blog.named_filter :somethings do
|
|
84
|
+
having(:ads) do
|
|
85
|
+
with(:content, nil)
|
|
86
|
+
end
|
|
87
|
+
join(Post, :join_type => :left) do
|
|
88
|
+
on(:id => :blog_id)
|
|
89
|
+
join(Comment, :join_type => :inner) do
|
|
90
|
+
on(:id => :post_id)
|
|
91
|
+
on(:offensive, true)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
group_by(:id)
|
|
95
|
+
end
|
|
96
|
+
@blog.somethings.inspect
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'should produce the correct conditions' do
|
|
100
|
+
@blog.last_find[:conditions].should == [%q((blogs__ads.content IS NULL))]
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'should produce the correct join' do
|
|
104
|
+
@blog.last_find[:joins].should == [%q(INNER JOIN "ads" AS blogs__ads ON "blogs".id = blogs__ads.blog_id), %q(LEFT OUTER JOIN "posts" AS blogs__post ON "blogs".id = blogs__post.blog_id), %q(INNER JOIN "comments" AS blogs__post__comment ON blogs__post.id = blogs__post__comment.post_id AND (blogs__post__comment.offensive = 't'))]
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
describe 'using the same join multiple times' do
|
|
109
|
+
before do
|
|
110
|
+
@blog = Class.new(Blog)
|
|
111
|
+
@blog.named_filter(:things) do
|
|
112
|
+
join(Post, :join_type => :inner, :alias => 'blogs_posts_1') do
|
|
113
|
+
on(:id => :blog_id)
|
|
114
|
+
with(:title, 'ack')
|
|
115
|
+
end
|
|
116
|
+
join(Post, :join_type => :inner, :alias => 'blogs_posts_2') do
|
|
117
|
+
on(:id => :blog_id)
|
|
118
|
+
with(:title, 'hmm')
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
@blog.things.inspect
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it 'should create the correct join' do
|
|
125
|
+
@blog.last_find[:joins].should == [%q(INNER JOIN "posts" AS blogs_posts_1 ON "blogs".id = blogs_posts_1.blog_id), %q(INNER JOIN "posts" AS blogs_posts_2 ON "blogs".id = blogs_posts_2.blog_id)]
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it 'should create the correct conditions' do
|
|
129
|
+
@blog.last_find[:conditions].should == [%q((blogs_posts_1.title = ?) AND (blogs_posts_2.title = ?)), 'ack', 'hmm']
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|