outoftime-record_filter 0.6.0 → 0.8.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.
- data/README.rdoc +1 -1
- data/Rakefile +35 -1
- data/VERSION.yml +2 -2
- data/lib/record_filter.rb +26 -5
- data/lib/record_filter/active_record.rb +55 -12
- data/lib/record_filter/conjunctions.rb +1 -1
- data/lib/record_filter/dsl.rb +16 -1
- data/lib/record_filter/dsl/class_join.rb +1 -1
- data/lib/record_filter/dsl/conjunction.rb +1 -1
- data/lib/record_filter/dsl/conjunction_dsl.rb +244 -18
- data/lib/record_filter/dsl/dsl.rb +90 -25
- data/lib/record_filter/dsl/dsl_factory.rb +19 -0
- data/lib/record_filter/dsl/group_by.rb +1 -1
- data/lib/record_filter/dsl/join.rb +1 -1
- data/lib/record_filter/dsl/join_condition.rb +1 -1
- data/lib/record_filter/dsl/join_dsl.rb +36 -1
- data/lib/record_filter/dsl/limit.rb +1 -1
- data/lib/record_filter/dsl/named_filter.rb +1 -1
- data/lib/record_filter/dsl/order.rb +1 -1
- data/lib/record_filter/dsl/restriction.rb +218 -22
- data/lib/record_filter/filter.rb +11 -9
- data/lib/record_filter/group_by.rb +1 -1
- data/lib/record_filter/join.rb +1 -1
- data/lib/record_filter/order.rb +1 -1
- data/lib/record_filter/query.rb +4 -4
- data/lib/record_filter/restrictions.rb +1 -1
- data/lib/record_filter/table.rb +23 -12
- data/spec/active_record_spec.rb +9 -28
- data/spec/exception_spec.rb +23 -0
- data/spec/named_filter_spec.rb +5 -2
- data/spec/restrictions_spec.rb +28 -0
- data/spec/test.db +0 -0
- data/test/performance_test.rb +36 -0
- data/{lib/record_filter/join_table.rb → test/test.db} +0 -0
- metadata +6 -3
data/README.rdoc
CHANGED
data/Rakefile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
ENV['RUBYOPT'] = '-W1'
|
1
|
+
# ENV['RUBYOPT'] = '-W1'
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'rake'
|
@@ -22,3 +22,37 @@ rescue LoadError
|
|
22
22
|
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
23
23
|
end
|
24
24
|
|
25
|
+
# Try to use hanna to create spiffier docs.
|
26
|
+
begin
|
27
|
+
require 'hanna/rdoctask'
|
28
|
+
rescue LoadError
|
29
|
+
require 'rake/rdoctask'
|
30
|
+
end
|
31
|
+
|
32
|
+
Rake::RDocTask.new do |rdoc|
|
33
|
+
if File.exist?('VERSION.yml')
|
34
|
+
config = YAML.load(File.read('VERSION.yml'))
|
35
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
36
|
+
else
|
37
|
+
version = ""
|
38
|
+
end
|
39
|
+
|
40
|
+
rdoc.rdoc_dir = 'rdoc'
|
41
|
+
rdoc.title = "record_filter #{version}"
|
42
|
+
rdoc.rdoc_files.include('README*')
|
43
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
44
|
+
end
|
45
|
+
|
46
|
+
begin
|
47
|
+
require 'ruby-prof/task'
|
48
|
+
|
49
|
+
RubyProf::ProfileTask.new do |t|
|
50
|
+
t.test_files = FileList['test/performance_test.rb']
|
51
|
+
t.output_dir = 'perf'
|
52
|
+
t.printer = :graph_html
|
53
|
+
t.min_percent = 5
|
54
|
+
end
|
55
|
+
rescue LoadError
|
56
|
+
puts 'Ruby-prof not available. Profiling tests are disabled.'
|
57
|
+
end
|
58
|
+
|
data/VERSION.yml
CHANGED
data/lib/record_filter.rb
CHANGED
@@ -6,10 +6,31 @@ require 'active_record'
|
|
6
6
|
require File.join(File.dirname(__FILE__), 'record_filter', file)
|
7
7
|
end
|
8
8
|
|
9
|
+
# The base-level namespace for the record_filter code. See RecordFilter::ActiveRecordExtension::ClassMethods
|
10
|
+
# for a description of the public API.
|
9
11
|
module RecordFilter
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
|
13
|
+
# An exception that is raised when an implicit join is attempted on an association
|
14
|
+
# that does not exist.
|
15
|
+
class AssociationNotFoundException < StandardError; end
|
16
|
+
|
17
|
+
# An exception that is raised when attempting to place restrictions or specify an
|
18
|
+
# explicit join on a column that doesn't exist.
|
19
|
+
class ColumnNotFoundException < StandardError; end
|
20
|
+
|
21
|
+
# An exception that is raised when operations such as limit, order, group_by, or
|
22
|
+
# on are called out of context.
|
23
|
+
class InvalidFilterException < StandardError; end
|
24
|
+
|
25
|
+
# An exception that is raised when attempting to create a named filter with a name that
|
26
|
+
# already exists in the class it is created on or one of its superclasses.
|
27
|
+
class InvalidFilterNameException < StandardError; end
|
28
|
+
|
29
|
+
# An exception that is raised when no columns are privided to specify an explicit join.
|
30
|
+
class InvalidJoinException < StandardError; end
|
31
|
+
|
32
|
+
# An exception raised in the case where a named filter is called from within a filter
|
33
|
+
# and the named filter does not exist.
|
34
|
+
class NamedFilterNotFoundException < StandardError; end
|
15
35
|
end
|
36
|
+
|
@@ -2,33 +2,68 @@ module RecordFilter
|
|
2
2
|
# The ActiveRecordExtension module is mixed in to ActiveRecord::Base to form the
|
3
3
|
# top-level API for interacting with record_filter. It adds public methods for
|
4
4
|
# executing ad-hoc filters as well as for creating and querying named filters.
|
5
|
+
# See RecordFilter::ActiveRecordExtension::ClassMethods for more detail on the
|
6
|
+
# API.
|
5
7
|
module ActiveRecordExtension
|
6
8
|
module ClassMethods
|
7
9
|
|
8
|
-
#
|
10
|
+
# Create a filter on the fly to find a set of results that matches the given criteria.
|
11
|
+
# This method, which can be called on any ActiveRecord::Base subclass, accepts a block
|
12
|
+
# that defines the contents of the filter and returns a Filter object that contains a list
|
13
|
+
# of the objects resulting from the query. See the documentation for RecordFilter::DSL
|
14
|
+
# for more information on how to specify the filter.
|
9
15
|
#
|
10
16
|
# ==== Parameters
|
11
|
-
# block
|
17
|
+
# block<Proc>::
|
12
18
|
# A block that specifies the contents of the filter.
|
13
19
|
#
|
14
20
|
# ==== Returns
|
15
|
-
# Filter::
|
16
|
-
# treated as an array of the results.
|
21
|
+
# Filter::
|
22
|
+
# The Filter object resulting from the query, which can be treated as an array of the results.
|
17
23
|
#
|
18
24
|
# ==== Example
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
|
25
|
+
# Blog.filter do
|
26
|
+
# having(:posts).with(:name, nil)
|
27
|
+
# end
|
28
|
+
#
|
23
29
|
# @public
|
24
30
|
def filter(&block)
|
25
31
|
Filter.new(self, nil, &block)
|
26
32
|
end
|
27
33
|
|
34
|
+
# Create a new named filter, which defines a function on the callee class that provides easy
|
35
|
+
# access to the query defined by the filter. Any number of named filters can be created on a
|
36
|
+
# class, and they can also be chained to create complex queries out of simple building blocks.
|
37
|
+
# In addition, named filters can accept any number of arguments in order to allow customization
|
38
|
+
# of their behavior when used. For more details on how to specify the contents of named filters,
|
39
|
+
# see the documentation for RecordFilter::DSL.
|
40
|
+
#
|
41
|
+
# Post.named_filter(:without_permalink) do
|
42
|
+
# with(:permalink, nil)
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# Post.named_filter(:created_after) do |time|
|
46
|
+
# with(:created_at).gt(time)
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# Post.without_permalink # :conditions => ['permalink IS NULL']
|
50
|
+
# Post.created_after(3.hours.ago) # :conditions => ['created_at > ?', 3.hours.ago]
|
51
|
+
# Post.without_permalink.created_after(3.hours.ago) # :conditions => ['permalink IS NULL AND created_at > ?', 3.hours.ago]
|
52
|
+
#
|
53
|
+
# ==== Raises
|
54
|
+
# InvalidFilterNameException::
|
55
|
+
# There is already a named filter with the given name on this class or one of its superclasses.
|
56
|
+
#
|
57
|
+
# ==== Returns
|
58
|
+
# nil
|
59
|
+
#
|
60
|
+
# @public
|
28
61
|
def named_filter(name, &block)
|
29
|
-
|
62
|
+
if named_filters.include?(name.to_sym)
|
63
|
+
raise InvalidFilterNameException.new("A named filter with the name #{name} already exists on the class #{self.name}.")
|
64
|
+
end
|
30
65
|
local_named_filters << name.to_sym
|
31
|
-
DSL::
|
66
|
+
DSL::DSLFactory::subclass(self).module_eval do
|
32
67
|
define_method(name, &block)
|
33
68
|
end
|
34
69
|
|
@@ -37,8 +72,16 @@ module RecordFilter
|
|
37
72
|
Filter.new(self, name, *args)
|
38
73
|
end
|
39
74
|
end
|
75
|
+
nil
|
40
76
|
end
|
41
77
|
|
78
|
+
# Retreive a list of named filters that apply to a specific class, including ones
|
79
|
+
# that were defined in its superclasses.
|
80
|
+
#
|
81
|
+
# ==== Returns
|
82
|
+
# Array:: A list of the names of the named filters, as symbols.
|
83
|
+
#
|
84
|
+
# @public
|
42
85
|
def named_filters
|
43
86
|
result = local_named_filters.dup
|
44
87
|
result.concat(superclass.named_filters) if (superclass && superclass.respond_to?(:named_filters))
|
@@ -46,8 +89,8 @@ module RecordFilter
|
|
46
89
|
end
|
47
90
|
|
48
91
|
protected
|
49
|
-
|
50
|
-
def local_named_filters
|
92
|
+
|
93
|
+
def local_named_filters # :nodoc:
|
51
94
|
@local_named_filters ||= []
|
52
95
|
end
|
53
96
|
end
|
data/lib/record_filter/dsl.rb
CHANGED
@@ -1,6 +1,21 @@
|
|
1
|
-
%w(class_join conjunction conjunction_dsl dsl group_by join join_dsl join_condition limit named_filter order restriction).each { |file| require File.join(File.dirname(__FILE__), 'dsl', file) }
|
1
|
+
%w(class_join conjunction conjunction_dsl dsl dsl_factory group_by join join_dsl join_condition limit named_filter order restriction).each { |file| require File.join(File.dirname(__FILE__), 'dsl', file) }
|
2
2
|
|
3
3
|
module RecordFilter
|
4
|
+
# The DSL module defines the structure of the criteria API used in calls to
|
5
|
+
# filter and named_filter. The API is defined by its four submodules, which
|
6
|
+
# define context-specific hooks for the API as well as defining a list of
|
7
|
+
# available restrictions. At the top level of a filter definition, all of the
|
8
|
+
# methods in DSL and ConjunctionDSL are available. In inner blocks, the methods
|
9
|
+
# in ConjunctionDSL are available, and within explicit joins defined using 'join'
|
10
|
+
# the methods in JoinDSL are added. The API provides access to:
|
11
|
+
#
|
12
|
+
# * Restrictions, using ConjunctionDSL.with and the methods in Restriction.
|
13
|
+
# * Conjunctions, such as all_of, any_of, etc. in ConjunctionDSL.
|
14
|
+
# * Implicit joins on associations, using ConjunctionDSL.having
|
15
|
+
# * Explicit joins, using ConjunctionDSL.join and JoinDSL.on
|
16
|
+
# * Ordering, using DSL.order
|
17
|
+
# * Grouping, using DSL.group_by
|
18
|
+
# * Limits and offsets, using DSL.limit
|
4
19
|
module DSL
|
5
20
|
end
|
6
21
|
end
|
@@ -1,78 +1,304 @@
|
|
1
1
|
module RecordFilter
|
2
2
|
module DSL
|
3
|
+
# The ConjunctionDSL is used for specifying restrictions, conjunctions and joins, with methods that
|
4
|
+
# can be accessed from any point in a filter declaration. The where method is used for creating
|
5
|
+
# restrictions, conjunctions are specified through any_of, all_of, none_of and not_all_of, and joins
|
6
|
+
# are described by having and join.
|
3
7
|
class ConjunctionDSL
|
4
8
|
|
5
|
-
attr_reader :conjunction
|
9
|
+
attr_reader :conjunction # :nodoc:
|
6
10
|
|
7
|
-
def initialize(model_class, conjunction)
|
11
|
+
def initialize(model_class, conjunction) # :nodoc:
|
8
12
|
@model_class = model_class
|
9
13
|
@conjunction = conjunction
|
10
14
|
end
|
11
15
|
|
12
|
-
#
|
16
|
+
# Specify a condition on the given column, which will be added to the WHERE clause
|
17
|
+
# of the resulting query. This method returns a Restriction object, which can be called
|
18
|
+
# with any of the specific restriction methods described there in order to create many
|
19
|
+
# types of conditions. If both a column name and a value are passed, this will automatically
|
20
|
+
# create an equality condition, so the following two examples are equal:
|
21
|
+
# with(:permalink, 'junk')
|
22
|
+
# with(:permalink).equal_to('junk')
|
23
|
+
# If nil is passed as the second argument, an is_null restriction will automatically be
|
24
|
+
# created, so these two examples are equal as well:
|
25
|
+
# with(:permalink, nil)
|
26
|
+
# with(:permalink).is_null
|
27
|
+
# This method can be called at any point in the filter specification, and the appropriate
|
28
|
+
# clauses will be created if it is called within or other conjunctions.
|
29
|
+
#
|
30
|
+
# ==== Parameters
|
31
|
+
# column<Symbol>::
|
32
|
+
# The name of the column to restrict. The column is assumed to exist in the table that is
|
33
|
+
# currently in scope. In the outer block of a filter, that would be the table being filtered,
|
34
|
+
# and within joins it would be the table being joined.
|
35
|
+
# value<value, optional>::
|
36
|
+
# If specified, the value will be used to automatically create either an equality restriction
|
37
|
+
# or an IS NULL test, as described above.
|
38
|
+
#
|
39
|
+
# ==== Returns
|
40
|
+
# Restriction::
|
41
|
+
# A restriction object that can be used to create a specific condition. See the API in
|
42
|
+
# Restriction for options.
|
43
|
+
#
|
44
|
+
# ==== Alternatives
|
45
|
+
# The value parameter is optional, as described above.
|
46
|
+
#
|
47
|
+
# @public
|
13
48
|
def with(column, value=Restriction::DEFAULT_VALUE)
|
14
49
|
return @conjunction.add_restriction(column, value)
|
15
50
|
end
|
16
51
|
|
17
|
-
#
|
52
|
+
# Add a where clause that will pass if any of the conditions specified within it
|
53
|
+
# are true. Any restrictions created inside the given block are OR'ed together
|
54
|
+
# in the final query, and the block can contain any number of joins, restrictions, or
|
55
|
+
# other conjunctions.
|
56
|
+
# Blog.filter do
|
57
|
+
# any_of do
|
58
|
+
# with(:created_at, nil)
|
59
|
+
# with(:created_at).greater_than(3.days.ago)
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# # :conditions => { ['blogs.created_at IS NULL OR blogs.created_at > ?', 3.days.ago] }
|
64
|
+
#
|
65
|
+
# ==== Parameters
|
66
|
+
# block<Proc>::
|
67
|
+
# The block can contain any sequence of calls, and the conditions that it contains will be
|
68
|
+
# OR'ed together to create a where clause.
|
69
|
+
#
|
70
|
+
# ==== Returns
|
71
|
+
# nil
|
72
|
+
#
|
73
|
+
# @public
|
18
74
|
def any_of(&block)
|
19
75
|
@conjunction.add_conjunction(:any_of, &block)
|
20
76
|
nil
|
21
77
|
end
|
22
78
|
|
23
|
-
#
|
79
|
+
# Add a where clause that will pass only if all of the conditions specified within it
|
80
|
+
# are true. Any restrictions created inside the given block are AND'ed together
|
81
|
+
# in the final query, and the block can contain any number of joins, restrictions, or
|
82
|
+
# other conjunctions.
|
83
|
+
# Blog.filter do
|
84
|
+
# all_of do
|
85
|
+
# with(:created_at, nil)
|
86
|
+
# with(:created_at).greater_than(3.days.ago)
|
87
|
+
# end
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# # :conditions => { ['blogs.created_at IS NULL AND blogs.created_at > ?', 3.days.ago] }
|
91
|
+
#
|
92
|
+
# ==== Parameters
|
93
|
+
# block<Proc>::
|
94
|
+
# The block can contain any sequence of calls, and the conditions that it contains will be
|
95
|
+
# AND'ed together to create a where clause.
|
96
|
+
#
|
97
|
+
# ==== Returns
|
98
|
+
# nil
|
99
|
+
#
|
100
|
+
# @public
|
24
101
|
def all_of(&block)
|
25
102
|
@conjunction.add_conjunction(:all_of, &block)
|
26
103
|
nil
|
27
104
|
end
|
28
105
|
|
106
|
+
# Add a where clause that will pass only if none of the conditions specified within it
|
107
|
+
# are true. Any restrictions created inside the given block are OR'ed together
|
108
|
+
# in the final query and the result is negated. The block can contain any number of joins,
|
109
|
+
# restrictions, or other conjunctions.
|
110
|
+
# Blog.filter do
|
111
|
+
# none_of do
|
112
|
+
# with(:created_at, nil)
|
113
|
+
# with(:created_at).greater_than(3.days.ago)
|
114
|
+
# end
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
# # :conditions => { ['NOT (blogs.created_at IS NULL OR blogs.created_at > ?)', 3.days.ago] }
|
118
|
+
#
|
119
|
+
# ==== Parameters
|
120
|
+
# block<Proc>::
|
121
|
+
# The block can contain any sequence of calls, and the conditions that it contains will be
|
122
|
+
# OR'ed together and then negated to create a where clause.
|
123
|
+
#
|
124
|
+
# ==== Returns
|
125
|
+
# nil
|
126
|
+
#
|
127
|
+
# @public
|
29
128
|
def none_of(&block)
|
30
129
|
@conjunction.add_conjunction(:none_of, &block)
|
31
130
|
nil
|
32
131
|
end
|
33
132
|
|
133
|
+
# Add a where clause that will pass unless all of the conditions specified within it
|
134
|
+
# are true. Any restrictions created inside the given block are AND'ed together
|
135
|
+
# in the final query and the result is negated. The block can contain any number of joins,
|
136
|
+
# restrictions, or other conjunctions.
|
137
|
+
# Blog.filter do
|
138
|
+
# none_of do
|
139
|
+
# with(:created_at, nil)
|
140
|
+
# with(:created_at).greater_than(3.days.ago)
|
141
|
+
# end
|
142
|
+
# end
|
143
|
+
#
|
144
|
+
# # :conditions => { ['NOT (blogs.created_at IS NULL AND blogs.created_at > ?)', 3.days.ago] }
|
145
|
+
#
|
146
|
+
# ==== Parameters
|
147
|
+
# block<Proc>::
|
148
|
+
# The block can contain any sequence of calls, and the conditions that it contains will be
|
149
|
+
# AND'ed together and then negated to create a where clause.
|
150
|
+
#
|
151
|
+
# ==== Returns
|
152
|
+
# nil
|
153
|
+
#
|
154
|
+
# @public
|
34
155
|
def not_all_of(&block)
|
35
156
|
@conjunction.add_conjunction(:not_all_of, &block)
|
36
157
|
nil
|
37
158
|
end
|
38
159
|
|
39
|
-
# join
|
40
|
-
|
160
|
+
# Create an implicit join using an association as the target. This method allows you to
|
161
|
+
# easily specify a join without specifying the columns to use by taking any needed data
|
162
|
+
# from the specified ActiveRecord association. If given, the block will be evaluated in
|
163
|
+
# the context of the table that has been joined, so any restrictions or other joins will
|
164
|
+
# be performed using its columns and associations. For example, if a Post has_many comments
|
165
|
+
# then the following code will join to the comments table and restrict the comments based
|
166
|
+
# on their created_at field:
|
167
|
+
# Post.filter do
|
168
|
+
# having(:comments) do
|
169
|
+
# with(:created_at).greater_than(3.days.ago)
|
170
|
+
# end
|
171
|
+
# end
|
172
|
+
# If one argument is given, it is assumed to be a symbol representing the name of the association
|
173
|
+
# that will be used for the join and a join type of :inner will be used. If two arguments are
|
174
|
+
# provided, the first one is assumed to be the join type, which can be one of :inner, :left or
|
175
|
+
# :right and the second one is the association name. An alias will automatically be created
|
176
|
+
# for the joined table named "#{left_table}__#{association_name}", so in the above example, the
|
177
|
+
# alias would be posts__comments.
|
178
|
+
#
|
179
|
+
# ==== Parameters
|
180
|
+
# join_type<Symbol>::
|
181
|
+
# Specifies the type of join to perform, and can be one of :inner, :left or :right. :left
|
182
|
+
# and :right will create left and right outer joins, respectively.
|
183
|
+
# association<Symbol>::
|
184
|
+
# The name of the association to use as a base for the join.
|
185
|
+
#
|
186
|
+
# ==== Returns
|
187
|
+
# ConjunctionDSL::
|
188
|
+
# A DSL object is returned in order to allow constructs like: having(:comments).with(:offensive, true)
|
189
|
+
#
|
190
|
+
# ==== Alternatives
|
191
|
+
# If only one argument is given, the join type will default to :inner and the first argument will
|
192
|
+
# be used as the association name.
|
193
|
+
#
|
194
|
+
# @public
|
195
|
+
def having(join_type, association=nil, &block)
|
41
196
|
if association.nil?
|
42
|
-
association, join_type =
|
43
|
-
else
|
44
|
-
join_type = join_type_or_association
|
197
|
+
association, join_type = join_type, nil
|
45
198
|
end
|
46
199
|
@conjunction.add_join(association, join_type, &block)
|
47
200
|
end
|
48
201
|
|
202
|
+
# Create an explicit join on the table of the given class. This method allows more complex
|
203
|
+
# joins to be speficied than can be created using having, including jump joins and ones that
|
204
|
+
# include conditions on column values. The method accepts a block that can contain any sequence
|
205
|
+
# of conjunctions, restrictions, or other joins, but it must also contain at least one call to
|
206
|
+
# JoinDSL.on to specify the conditions for the join.
|
207
|
+
#
|
208
|
+
# ==== Parameters
|
209
|
+
# clazz<Class>::
|
210
|
+
# The class that is being joined to.
|
211
|
+
# join_type<Symbol>::
|
212
|
+
# Indicates the type of join to use and must be one of :inner, :left or :right, where :left
|
213
|
+
# or :right will create a LEFT or RIGHT OUTER join respectively.
|
214
|
+
# table_alias<String, optional>::
|
215
|
+
# If provided, will specify an alias to use in the SQL when referring to the joined table.
|
216
|
+
# If the argument is not given, the alias will be "#{left_table}__#{clazz.name}"
|
217
|
+
# block<Proc>
|
218
|
+
# The contents of the join block can contain any sequence of conjunctions, restrictions, or joins.
|
219
|
+
#
|
220
|
+
# ==== Returns
|
221
|
+
# JoinDSL::
|
222
|
+
# A DSL object that can be used to specify the contents of the join. Returning this value allows
|
223
|
+
# for constructions like: join(Comment, :inner).on(:id => :post_id)
|
224
|
+
#
|
225
|
+
# @public
|
49
226
|
def join(clazz, join_type, table_alias=nil, &block)
|
50
227
|
@conjunction.add_class_join(clazz, join_type, table_alias, &block)
|
51
228
|
end
|
52
229
|
|
230
|
+
# Access the class that the current filter is being applied to. This is necessary
|
231
|
+
# because the filter is evaluated in the context of the DSL object, so self will
|
232
|
+
# not give access to any methods that need to be called on the filtered class.
|
233
|
+
# It is especially useful in named filters that may be defined in a way that allows
|
234
|
+
# them to apply to multiple classes.
|
235
|
+
#
|
236
|
+
# ==== Returns
|
237
|
+
# Class::
|
238
|
+
# The class that is currently being filtered.
|
239
|
+
#
|
240
|
+
# @public
|
53
241
|
def filter_class
|
54
242
|
@model_class
|
55
243
|
end
|
244
|
+
|
245
|
+
# Enable calling of named filters from within other filters by catching unknown calls
|
246
|
+
# and assuming that they are to named filters. This enables the following examples:
|
247
|
+
# class Post < ActiveRecord::Base
|
248
|
+
# has_many :comments
|
249
|
+
# named_filter(:empty) { with(:contents).nil }
|
250
|
+
# end
|
251
|
+
#
|
252
|
+
# class Comment < ActiveRecord::Base
|
253
|
+
# belongs_to :post
|
254
|
+
# named_filter(:offensive) { |value| with(:offensive, value) }
|
255
|
+
# end
|
256
|
+
#
|
257
|
+
# Post.filter do
|
258
|
+
# with(:created_at).less_than(1.hour.ago)
|
259
|
+
# empty
|
260
|
+
# end
|
261
|
+
#
|
262
|
+
# # Results in:
|
263
|
+
# # :conditions => { ['posts.created_at < ? AND posts.contents IS NULL', 1.hour.ago] }
|
264
|
+
# # And even cooler:
|
265
|
+
#
|
266
|
+
# Post.filter do
|
267
|
+
# having(:comments).offensive(true)
|
268
|
+
# end
|
269
|
+
#
|
270
|
+
# # Results in:
|
271
|
+
# # :conditions => { ['posts__comments.offensive = ?', true] }
|
272
|
+
# # :joins => { 'INNER JOIN "comments" AS posts__comments ON "posts".id = posts__comments.post_id' }
|
273
|
+
#
|
274
|
+
# ==== Parameters
|
275
|
+
# args<Array>::
|
276
|
+
# The arguments to pass to the named filter when called.
|
277
|
+
#
|
278
|
+
# @public
|
279
|
+
def method_missing(method, *args)
|
280
|
+
@conjunction.add_named_filter(method, *args)
|
281
|
+
end
|
56
282
|
|
57
|
-
|
283
|
+
#
|
284
|
+
# Define these_methods here just so that we can throw exceptions when they are called. They should not
|
285
|
+
# be callable in the scope of a conjunction_dsl.
|
286
|
+
#
|
287
|
+
def limit(offset_or_limit, limit=nil) # :nodoc:
|
58
288
|
raise InvalidFilterException.new('Calls to limit can only be made in the outer block of a filter.')
|
59
289
|
end
|
60
290
|
|
61
|
-
def order(column, direction=:asc)
|
291
|
+
def order(column, direction=:asc) # :nodoc:
|
62
292
|
raise InvalidFilterException.new('Calls to order can only be made in the outer block of a filter.')
|
63
293
|
end
|
64
294
|
|
65
|
-
def group_by(column)
|
295
|
+
def group_by(column) # :nodoc:
|
66
296
|
raise InvalidFilterException.new('Calls to group_by can only be made in the outer block of a filter.')
|
67
297
|
end
|
68
298
|
|
69
|
-
def on(column, value=Restriction::DEFAULT_VALUE)
|
299
|
+
def on(column, value=Restriction::DEFAULT_VALUE) # :nodoc:
|
70
300
|
raise InvalidFilterException.new('Calls to on can only be made in the block of a call to join.')
|
71
301
|
end
|
72
|
-
|
73
|
-
def method_missing(method, *args)
|
74
|
-
@conjunction.add_named_filter(method, *args)
|
75
|
-
end
|
76
302
|
end
|
77
303
|
end
|
78
304
|
end
|