aub-record_filter 0.9.3 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -19,6 +19,10 @@ intended to be a getting started guide that should cover the most common uses.
19
19
 
20
20
  gem install aub-record_filter --source=http://gems.github.com
21
21
 
22
+ In Rails, you'll need to add this to your config/environment.rb file:
23
+
24
+ config.gem 'aub-record_filter', :lib => 'record_filter', :source => 'http://gems.github.com'
25
+
22
26
  == Using Filters
23
27
 
24
28
  Given a Blog model having a has_many relationship with a Post model, a simple
@@ -31,24 +35,27 @@ filter with conditions and joins might look like this.
31
35
 
32
36
  This could be expressed in ActiveRecord as:
33
37
 
34
- Blog.find(
35
- :all,
38
+ Blog.all(
36
39
  :joins => :posts,
37
- :conditions => ['posts.permalink IS NULL AND blogs.created_at > ?', 'blog-post', 1.day.ago)
40
+ :conditions => {
41
+ :posts => {:permalink => nil},
42
+ :created_at => 1.day.ago..Time.now
43
+ }
44
+ )
38
45
 
39
46
  and it returns the same result, a list of Blog objects that are the result of the query. This
40
47
  type of filter is designed to be created on the fly, but if you have a filter that you would like
41
48
  to use in more than one place, it can be added to a class as a named filter. The following example
42
49
  creates the same filter as above and executes it:
43
50
 
44
- class Post < ActiveRecord::Base
45
- named_filter(:new_with_nil_permalink) do
51
+ class Blog < ActiveRecord::Base
52
+ named_filter(:new_with_unlinked_posts) do
46
53
  with(:created_at).greater_than(1.day.ago)
47
54
  having(:posts).with(:permalink, nil)
48
55
  end
49
56
  end
50
57
 
51
- Post.new_with_nil_permalink
58
+ Blog.new_with_unlinked_posts
52
59
 
53
60
  This returns the same result as the example above but with the advantages that it is
54
61
  easily reusable and that it can be combined with other named filters to produce a more
@@ -85,13 +92,15 @@ model even if called from a join.
85
92
  end
86
93
 
87
94
  class Post < ActiveRecord::Base
88
- named_filter(:recursive_test) do
95
+ named_filter(:using_other_filter) do
89
96
  having(:comments) do
90
97
  offensive
91
98
  end
92
99
  end
93
100
  end
94
101
 
102
+ Post.using_other_filter
103
+
95
104
  == Specifying Filters
96
105
 
97
106
  record_filter supports all of the SQL query abstractions provided by ActiveRecord, specifically:
@@ -125,13 +134,13 @@ the name of the column to restrict. If a second argument is given, it will autom
125
134
  be used as the value in an equality condition. The 'with' function will return a Restriction
126
135
  object that has methods to specify a number of different conditions and to negate them:
127
136
 
128
- with(:permalink, 'aardvarks') # :conditions => ['permalink = ?', 'aardvarks']
129
- with(:permalink).equal_to('sheep') # :conditions => ['permalink = ?', 'sheep']
130
- with(:permalink).not.equal_to('cats') # :conditions => ['permailnk <> ?', 'cats']
137
+ with(:permalink, 'aardvarks') # ['permalink = ?', 'aardvarks']
138
+ with(:permalink).equal_to('sheep') # ['permalink = ?', 'sheep']
139
+ with(:permalink).not.equal_to('cats') # ['permailnk <> ?', 'cats']
131
140
 
132
- with(:permalink, nil) # :conditions => ['permalink IS NULL']
133
- with(:permalink).is_null # :conditions => ['permalink IS NULL']
134
- with(:permalink, nil).not # :conditions => ['permalink IS NOT NULL']
141
+ with(:permalink, nil) # ['permalink IS NULL']
142
+ with(:permalink).is_null # ['permalink IS NULL']
143
+ with(:permalink, nil).not # ['permalink IS NOT NULL']
135
144
 
136
145
  The following condition types are supported through the Restriction API:
137
146
 
@@ -141,8 +150,23 @@ The following condition types are supported through the Restriction API:
141
150
  * In
142
151
  * Is null
143
152
  * Like
153
+ * Negation of all of the above
154
+
155
+ And here are some examples. See the RDoc page for
156
+ {DSL::Restriction}[http://aub.github.com/record_filter/rdoc/classes/RecordFilter/DSL/Restriction.html]
157
+ for more details on how to use them.
158
+
159
+ with(:featured_at).greater_than(Time.now) # ['featured_at > ?', Time.now]
160
+
161
+ with(:price).lte(1000) # ['price <= ?', 1000]
162
+
163
+ with(:created_at).between(time_a..time_b) # ['created_at BETWEEN ? AND ?', time_a, time_b]
144
164
 
145
- See the RDoc page for {DSL::Restriction}[http://aub.github.com/record_filter/rdoc/classes/RecordFilter/DSL/Restriction.html] for specifics on how to use these.
165
+ with(:id).in([1, 2, 3]) # ['id in (?)', [1, 2, 3]]
166
+
167
+ with(:content).like('%easy%') # ['content LIKE ?', '%easy%']
168
+
169
+ with(:content).not.like('%hard%') # ['content NOT LIKE ?', '%hard%']
146
170
 
147
171
  === Boolean Operations
148
172
 
@@ -156,25 +180,34 @@ joins or other boolean operations. The default operator is all_of.
156
180
  with(:permalink, 'ack')
157
181
  end
158
182
 
159
- :conditions => ['id = ? AND permalink = ?', 4, 'ack']
183
+ # ['id = ? AND permalink = ?', 4, 'ack']
160
184
 
161
185
  Post.filter do
162
- any_of
186
+ any_of do
163
187
  with(:id, 3)
164
188
  with(:permalink, 'booya')
165
189
  end
166
190
  end
167
191
 
168
- :conditions => ['id = ? OR permalink = ?', 3, 'booya']
192
+ # ['id = ? OR permalink = ?', 3, 'booya']
169
193
 
170
194
  Post.filter do
171
- none_of
195
+ none_of do
172
196
  with(:id, 2)
173
197
  with(:permalink, 'ouch')
174
198
  end
175
199
  end
176
200
 
177
- :conditions => ['NOT (id = ? OR permalink = ?', 2, 'ouch']
201
+ # ['NOT (id = ? OR permalink = ?)', 2, 'ouch']
202
+
203
+ Post.filter do
204
+ not_all_of do
205
+ with(:id, 1)
206
+ with(:permalink, 'bonobo')
207
+ end
208
+ end
209
+
210
+ # ['NOT (id = ? AND permalink = ?)', 1, 'bonobo']
178
211
 
179
212
  === Joins
180
213
 
@@ -257,7 +290,7 @@ order in which they were given.
257
290
 
258
291
  (The MIT License)
259
292
 
260
- Copyright (c) 2008 Aubrey Holland, Mat Brown
293
+ Copyright (c) 2008-2009 Aubrey Holland, Mat Brown
261
294
 
262
295
  Permission is hereby granted, free of charge, to any person obtaining
263
296
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -1,12 +1,10 @@
1
- # ENV['RUBYOPT'] = '-W1'
2
-
3
1
  require 'rubygems'
4
2
  require 'rake'
5
3
  require 'rake/testtask'
6
4
 
7
5
  FileList['tasks/**/*.rake'].each { |file| load file }
8
6
 
9
- task :default => :spec
7
+ task :default => ["db:spec:prepare", :spec]
10
8
 
11
9
  begin
12
10
  require 'jeweler'
@@ -41,6 +39,7 @@ Rake::RDocTask.new do |rdoc|
41
39
  rdoc.title = "record_filter #{version}"
42
40
  rdoc.rdoc_files.include('README*')
43
41
  rdoc.rdoc_files.include('lib/**/*.rb')
42
+ rdoc.options << '--webcvs=http://github.com/aub/record_filter/tree/master/'
44
43
  end
45
44
 
46
45
  begin
@@ -56,3 +55,32 @@ rescue LoadError
56
55
  puts 'Ruby-prof not available. Profiling tests are disabled.'
57
56
  end
58
57
 
58
+ begin
59
+ require 'metric_fu'
60
+ MetricFu::Configuration.run do |config|
61
+ #define which metrics you want to use
62
+ config.metrics = [:churn, :flog, :flay, :reek, :roodi, :rcov] # :saikuro, :stats
63
+ config.flay = { :dirs_to_flay => ['lib'] }
64
+ config.flog = { :dirs_to_flog => ['lib'] }
65
+ config.reek = { :dirs_to_reek => ['lib'] }
66
+ config.roodi = { :dirs_to_roodi => ['lib'] }
67
+ config.saikuro = { :output_directory => 'scratch_directory/saikuro',
68
+ :input_directory => ['lib'],
69
+ :cyclo => "",
70
+ :filter_cyclo => "0",
71
+ :warn_cyclo => "5",
72
+ :error_cyclo => "7",
73
+ :formater => "text"} #this needs to be set to "text"
74
+ config.churn = { :start_date => "1 year ago", :minimum_churn_count => 10}
75
+ config.rcov = { :test_files => ['spec/**/*_spec.rb'],
76
+ :rcov_opts => ["--sort coverage",
77
+ "--no-html",
78
+ "--text-coverage",
79
+ "--no-color",
80
+ "--profile",
81
+ "--exclude spec"]}
82
+ end
83
+ rescue LoadError
84
+ puts 'Install metric_fu for code quality metric tests.'
85
+ end
86
+
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 9
4
- :patch: 3
4
+ :patch: 4
@@ -59,16 +59,17 @@ module RecordFilter
59
59
  #
60
60
  # @public
61
61
  def named_filter(name, &block)
62
- if named_filters.include?(name.to_sym)
62
+ name = name.to_sym
63
+ if named_filters.include?(name)
63
64
  raise InvalidFilterNameException.new("A named filter with the name #{name} already exists on the class #{self.name}.")
64
65
  end
65
- local_named_filters << name.to_sym
66
+ local_named_filters << name
66
67
  DSL::DSLFactory::get_subclass(self).module_eval do
67
68
  define_method(name, &block)
68
69
  end
69
70
 
70
71
  (class << self; self; end).instance_eval do
71
- define_method(name.to_s) do |*args|
72
+ define_method(name) do |*args|
72
73
  Filter.new(self, name, *args)
73
74
  end
74
75
  end
@@ -0,0 +1,14 @@
1
+ module RecordFilter
2
+ module ColumnParser # :nodoc: all
3
+
4
+ protected
5
+
6
+ def parse_column_in_table(column, table)
7
+ while column.is_a?(Hash)
8
+ table = table.join_association(column.keys[0]).right_table
9
+ column = column.values[0]
10
+ end
11
+ [column, table]
12
+ end
13
+ end
14
+ end
@@ -9,6 +9,7 @@ module RecordFilter
9
9
  when :all_of then AllOf.new(table)
10
10
  when :none_of then NoneOf.new(table)
11
11
  when :not_all_of then NotAllOf.new(table)
12
+ else raise InvalidFilterException.new("An invalid conjunction type of #{dsl_conjunction.type} was used.")
12
13
  end
13
14
 
14
15
  dsl_conjunction.steps.each do |step|
@@ -32,6 +33,7 @@ module RecordFilter
32
33
  result.add_group_by(step.column)
33
34
  when DSL::NamedFilter
34
35
  result.add_named_filter(step.name, step.args)
36
+ else raise InvalidFilterException.new('And invalid filter step was provided.')
35
37
  end
36
38
  end
37
39
  result
@@ -46,8 +48,7 @@ module RecordFilter
46
48
 
47
49
  def add_restriction(column_name, operator, value, options={})
48
50
  check_column_exists!(column_name)
49
- restriction_class = RecordFilter::Restrictions::Base.class_from_operator(operator)
50
- restriction = restriction_class.new("#{@table_name}.#{column_name}", value, options)
51
+ restriction = RestrictionFactory.build(operator, "#{@table_name}.#{column_name}", value, options)
51
52
  self << restriction
52
53
  restriction
53
54
  end
@@ -60,8 +61,7 @@ module RecordFilter
60
61
  def add_join_on_association(association_name, join_type)
61
62
  table = @table
62
63
  while association_name.is_a?(Hash)
63
- result = table.join_association(association_name.keys[0], join_type)
64
- table = result.right_table
64
+ table = table.join_association(association_name.keys[0], join_type).right_table
65
65
  association_name = association_name.values[0]
66
66
  end
67
67
  table.join_association(association_name, join_type)
@@ -30,6 +30,24 @@ module RecordFilter
30
30
  nil
31
31
  end
32
32
 
33
+ # Define an offset for the results returned from the current
34
+ # filter. This method can only be called from the outermost scope of a filter
35
+ # (i.e. not inside of a having block, etc.). If it is called multiple times, the
36
+ # last one will override any others.
37
+ #
38
+ # ==== Parameters
39
+ # offset<Integer>::
40
+ # The offset of the query.
41
+ #
42
+ # ==== Returns
43
+ # nil
44
+ #
45
+ # @public
46
+ def offset(offset)
47
+ @conjunction.add_limit(nil, offset)
48
+ nil
49
+ end
50
+
33
51
  # Define an order clause for the current query, with options for specifying
34
52
  # both the column to use as well as the direction. This method can only be called
35
53
  # in the outermost scope of a filter (i.e. not inside of a having block, etc.).
@@ -51,9 +69,11 @@ module RecordFilter
51
69
  # column<Symbol, Hash>::
52
70
  # Specify the column for the ordering. If a symbol is given, it is assumed to represent
53
71
  # a column in the class that is being filtered. With a hash argument, it is possible
54
- # to specify a path to a column in one of the joined tables, as seen above.
72
+ # to specify a path to a column in one of the joined tables, as seen above. If a string
73
+ # is given and it doesn't match up with a column name, it is used as a literal string
74
+ # for ordering.
55
75
  # direction<Symbol>::
56
- # Specifies the direction of the join. Should be either :asc or :desc and defaults to :asc.
76
+ # Specifies the direction of the order. Should be either :asc or :desc and defaults to :asc.
57
77
  #
58
78
  # ==== Returns
59
79
  # nil
@@ -63,7 +83,7 @@ module RecordFilter
63
83
  # If the direction is neither :asc nor :desc.
64
84
  #
65
85
  # ==== Alternatives
66
- # As described above, it is possible to pass either a symbol or a hash as the first
86
+ # As described above, it is possible to pass a symbol, a hash or a string as the first
67
87
  # argument.
68
88
  #
69
89
  # @public
@@ -190,7 +190,7 @@ module RecordFilter
190
190
  #
191
191
  # ==== Parameters
192
192
  # value::
193
- # Either a single item or an array of values to form the values to be tested for inclusion.
193
+ # Either a single item, an array of values, or a range to form the values to be tested for inclusion.
194
194
  #
195
195
  # ==== Returns
196
196
  # Restriction:: self
@@ -1,5 +1,7 @@
1
1
  module RecordFilter
2
2
  class GroupBy # :nodoc: all
3
+ include ColumnParser
4
+
3
5
  attr_reader :column, :table
4
6
 
5
7
  def initialize(column, table)
@@ -7,11 +9,7 @@ module RecordFilter
7
9
  end
8
10
 
9
11
  def to_sql
10
- table, column = @table, @column
11
- while column.is_a?(Hash)
12
- table = table.join_association(column.keys[0]).right_table
13
- column = column.values[0]
14
- end
12
+ column, table = parse_column_in_table(@column, @table)
15
13
 
16
14
  if (table.has_column(column))
17
15
  "#{table.table_alias}.#{column}"
@@ -46,9 +46,11 @@ module RecordFilter
46
46
  unless @right_table.has_column(dsl_restriction.column)
47
47
  raise ColumnNotFoundException.new("The column #{dsl_restriction.column} was not found in the table #{@right_table.table_name}")
48
48
  end
49
- restriction_class = RecordFilter::Restrictions::Base.class_from_operator(dsl_restriction.operator)
50
- restriction = restriction_class.new(
51
- "#{@right_table.table_alias}.#{dsl_restriction.column}", dsl_restriction.value, :negated => dsl_restriction.negated)
49
+ restriction = RestrictionFactory.build(
50
+ dsl_restriction.operator,
51
+ "#{@right_table.table_alias}.#{dsl_restriction.column}",
52
+ dsl_restriction.value,
53
+ :negated => dsl_restriction.negated)
52
54
  @right_table.model_class.merge_conditions(restriction.to_conditions)
53
55
  end
54
56
 
@@ -1,5 +1,7 @@
1
1
  module RecordFilter
2
2
  class Order # :nodoc: all
3
+ include ColumnParser
4
+
3
5
  attr_reader :column, :direction, :table
4
6
 
5
7
  def initialize(column, direction, table)
@@ -10,19 +12,16 @@ module RecordFilter
10
12
  dir = case @direction
11
13
  when :asc then 'ASC'
12
14
  when :desc then 'DESC'
13
- end
14
-
15
- table, column = @table, @column
16
- while column.is_a?(Hash)
17
- table = table.join_association(column.keys[0]).right_table
18
- column = column.values[0]
15
+ else raise InvalidFilterException.new("An invalid order of #{@direction} was specified.")
19
16
  end
20
17
 
21
- if (!table.has_column(column))
22
- raise ColumnNotFoundException.new("The column #{column} was not found in #{table.table_name}.")
23
- end
18
+ column, table = parse_column_in_table(@column, @table)
24
19
 
25
- "#{table.table_alias}.#{column} #{dir}"
20
+ if (table.has_column(column))
21
+ "#{table.table_alias}.#{column} #{dir}"
22
+ else
23
+ "#{column} #{dir}"
24
+ end
26
25
  end
27
26
  end
28
27
  end
@@ -20,15 +20,7 @@ module RecordFilter
20
20
  params = {}
21
21
  conditions = @conjunction.to_conditions
22
22
  params = { :conditions => conditions } if conditions
23
- joins = @table.all_joins
24
- params[:joins] = joins.map { |join| join.to_sql } unless joins.empty?
25
- if (joins.any? { |j| j.requires_distinct_select? })
26
- if count_query
27
- params[:select] = "DISTINCT #{@table.model_class.quoted_table_name}.#{@table.model_class.primary_key}"
28
- else
29
- params[:select] = "DISTINCT #{@table.model_class.quoted_table_name}.*"
30
- end
31
- end
23
+ add_joins(params, count_query)
32
24
  orders = @table.orders
33
25
  params[:order] = orders.map { |order| order.to_sql } * ', ' unless orders.empty?
34
26
  group_bys = @table.group_bys
@@ -41,6 +33,18 @@ module RecordFilter
41
33
 
42
34
  protected
43
35
 
36
+ def add_joins(params, count_query)
37
+ joins = @table.all_joins
38
+ params[:joins] = joins.map { |join| join.to_sql } unless joins.empty?
39
+ if (joins.any? { |j| j.requires_distinct_select? })
40
+ if count_query
41
+ params[:select] = "DISTINCT #{@table.table_name}.#{@table.model_class.primary_key}"
42
+ else
43
+ params[:select] = "DISTINCT #{@table.table_name}.*"
44
+ end
45
+ end
46
+ end
47
+
44
48
  def dsl_for_named_filter(clazz, named_filter)
45
49
  return DSL::DSLFactory.create(clazz) if named_filter.blank?
46
50
  while (clazz)
@@ -0,0 +1,21 @@
1
+ module RecordFilter
2
+ class RestrictionFactory # :nodoc: all
3
+
4
+ OPERATOR_HASH = {
5
+ :equal_to => Restrictions::EqualTo,
6
+ :is_null => Restrictions::IsNull,
7
+ :less_than => Restrictions::LessThan,
8
+ :less_than_or_equal_to => Restrictions::LessThanOrEqualTo,
9
+ :greater_than => Restrictions::GreaterThan,
10
+ :greater_than_or_equal_to => Restrictions::GreaterThanOrEqualTo,
11
+ :in => Restrictions::In,
12
+ :between => Restrictions::Between,
13
+ :like => Restrictions::Like
14
+ }
15
+
16
+ def self.build(operator, column_name, value, options)
17
+ OPERATOR_HASH[operator].new(column_name, value, options)
18
+ end
19
+ end
20
+ end
21
+
@@ -17,10 +17,6 @@ module RecordFilter
17
17
  def to_negative_sql
18
18
  "NOT (#{to_positive_sql})"
19
19
  end
20
-
21
- def self.class_from_operator(operator)
22
- "RecordFilter::Restrictions::#{operator.to_s.camelize}".constantize
23
- end
24
20
  end
25
21
 
26
22
  class EqualTo < Base
@@ -5,7 +5,7 @@ module RecordFilter
5
5
  def initialize(model_class, table_alias = nil)
6
6
  @model_class = model_class
7
7
  @aliased = !table_alias.nil?
8
- @table_alias = table_alias || model_class.quoted_table_name
8
+ @table_alias = table_alias || table_name
9
9
  @joins_cache = {}
10
10
  @joins = []
11
11
  @orders = []
@@ -13,7 +13,7 @@ module RecordFilter
13
13
  end
14
14
 
15
15
  def table_name
16
- @model_class.quoted_table_name
16
+ @table_name ||= @model_class.quoted_table_name
17
17
  end
18
18
 
19
19
  def join_association(association_name, join_type=nil, options={})
@@ -41,6 +41,7 @@ module RecordFilter
41
41
  simple_join(association, join_type, options)
42
42
  when :has_and_belongs_to_many
43
43
  compound_join(association, join_type)
44
+ else raise InvalidJoinException.new("I don't know how to join on an association of type #{association.macro}.")
44
45
  end
45
46
  end
46
47
  end
@@ -77,13 +78,7 @@ module RecordFilter
77
78
  private
78
79
 
79
80
  def simple_join(association, join_type, options)
80
- join_predicate =
81
- case association.macro
82
- when :belongs_to
83
- [{ association.options[:foreign_key] || association.primary_key_name.to_sym => @model_class.primary_key }]
84
- when :has_many, :has_one
85
- [{ association.options[:primary_key] || @model_class.primary_key => association.primary_key_name.to_sym }]
86
- end
81
+ join_predicate = simple_join_predicate(association)
87
82
 
88
83
  if association.options[:as]
89
84
  join_predicate << DSL::Restriction.new(association.options[:as].to_s + '_type').equal_to(association.active_record.base_class.name)
@@ -101,6 +96,17 @@ module RecordFilter
101
96
  join
102
97
  end
103
98
 
99
+ def simple_join_predicate(association)
100
+ join_predicate =
101
+ case association.macro
102
+ when :belongs_to
103
+ [{ association.options[:foreign_key] || association.primary_key_name.to_sym => @model_class.primary_key }]
104
+ when :has_many, :has_one
105
+ [{ association.options[:primary_key] || @model_class.primary_key => association.primary_key_name.to_sym }]
106
+ else raise InvalidJoinException.new("I don't know how to do a simple join on an association of type #{association.macro}.")
107
+ end
108
+ end
109
+
104
110
  def compound_join(association, join_type)
105
111
  pivot_join_predicate = [{ @model_class.primary_key => association.primary_key_name.to_sym }]
106
112
  table_name = @model_class.connection.quote_table_name(association.options[:join_table])
@@ -116,7 +122,9 @@ module RecordFilter
116
122
  protected
117
123
 
118
124
  def alias_for_association(association)
119
- "#{@aliased ? @table_alias.to_s : @model_class.table_name}__#{association.name.to_s.downcase}"
125
+ @alias_cache ||= {}
126
+ @alias_cache[association.name] ||=
127
+ "#{@aliased ? @table_alias.to_s : @model_class.table_name}__#{association.name.to_s.downcase}"
120
128
  end
121
129
 
122
130
  alias_method :alias_for_class, :alias_for_association
data/lib/record_filter.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require 'rubygems'
2
- gem 'activerecord', '~> 2.2'
2
+ gem 'activerecord', '~> 2.3'
3
3
  require 'active_record'
4
4
 
5
- %w(active_record query table conjunctions restrictions filter join order group_by dsl).each do |file|
5
+ %w(active_record column_parser query table conjunctions restrictions restriction_factory filter join order group_by dsl).each do |file|
6
6
  require File.join(File.dirname(__FILE__), 'record_filter', file)
7
7
  end
8
8
 
@@ -34,12 +34,12 @@ describe 'raising exceptions' do
34
34
  }.should raise_error(RecordFilter::ColumnNotFoundException)
35
35
  end
36
36
 
37
- it 'should get ColumnNotFoundException for order' do
37
+ it 'should not get ColumnNotFoundException for order' do
38
38
  lambda {
39
39
  Post.filter do
40
- order(:this_is_not_there, :asc)
40
+ order('this_is_not_there', :asc)
41
41
  end.inspect
42
- }.should raise_error(RecordFilter::ColumnNotFoundException)
42
+ }.should_not raise_error(RecordFilter::ColumnNotFoundException)
43
43
  end
44
44
 
45
45
  it 'should not get ColumnNotFoundException for group_by' do
@@ -63,6 +63,50 @@ describe 'filter qualifiers' do
63
63
  end
64
64
  end
65
65
 
66
+ describe 'offsets' do
67
+ describe 'simple offset setting' do
68
+ before do
69
+ Post.filter do
70
+ with :published, true
71
+ offset 10
72
+ end.inspect
73
+ end
74
+
75
+ it 'should add the offset to the parameters' do
76
+ Post.last_find[:offset].should == 10
77
+ end
78
+ end
79
+
80
+ describe 'with multiple calls to offset' do
81
+ before do
82
+ Post.filter do
83
+ offset 5
84
+ with :published, true
85
+ offset 6
86
+ end.inspect
87
+ end
88
+
89
+ it 'should add the offset to the parameters' do
90
+ Post.last_find[:offset].should == 6
91
+ end
92
+ end
93
+
94
+ describe 'offsetting named scopes' do
95
+ before do
96
+ @post = Class.new(Post)
97
+ @post.named_filter(:published_ones) do
98
+ offset(2)
99
+ with(:published, false)
100
+ end
101
+ end
102
+
103
+ it 'should offset the query' do
104
+ @post.published_ones.inspect
105
+ @post.last_find[:offset].should == 2
106
+ end
107
+ end
108
+ end
109
+
66
110
  describe 'ordering' do
67
111
  describe 'with a simple order supplied' do
68
112
  before do
@@ -115,10 +159,24 @@ describe 'filter qualifiers' do
115
159
  end.inspect
116
160
  end
117
161
 
118
- it 'should add the limit to the parameters' do
162
+ it 'should add the order to the parameters' do
119
163
  Post.last_find[:order].should == %q(posts__photo.path DESC, "posts".permalink ASC)
120
164
  end
121
165
  end
166
+
167
+ describe 'with the order supplied as a string' do
168
+ before do
169
+ Post.filter do
170
+ with :published, true
171
+ group_by(:published)
172
+ order('SUM(id)', :desc)
173
+ end.inspect
174
+ end
175
+
176
+ it 'should add the order to the query' do
177
+ Post.last_find[:order].should == %q(SUM(id) DESC)
178
+ end
179
+ end
122
180
  end
123
181
 
124
182
  describe 'group_by' do
@@ -89,6 +89,13 @@ describe 'RecordFilter restrictions' do
89
89
  Post.last_find.should == { :conditions => [%q("posts".blog_id IN (?)), nil] }
90
90
  end
91
91
 
92
+ it 'should do the right thing for IN filters with a range' do
93
+ Post.filter do
94
+ with(:blog_id).in(1..5)
95
+ end.inspect
96
+ Post.last_find.should == { :conditions => [%q("posts".blog_id IN (?)), 1..5] }
97
+ end
98
+
92
99
  it 'should negate is_not_null conditions correctly' do
93
100
  Post.filter do
94
101
  with(:blog_id).is_not_null.not
data/spec/test.db CHANGED
Binary file
@@ -19,6 +19,7 @@ ActiveRecord::Base.establish_connection(
19
19
  @blog.named_filter :somethings do
20
20
  having(:ads) do
21
21
  with(:content, nil)
22
+ with(:id).greater_than(25)
22
23
  end
23
24
  join(Post, :left) do
24
25
  on(:id => :blog_id)
@@ -28,6 +29,8 @@ ActiveRecord::Base.establish_connection(
28
29
  end
29
30
  end
30
31
  group_by(:id)
32
+ limit(10, 100)
33
+ order(:ads => :id)
31
34
  end
32
35
 
33
36
  10000.times do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aub-record_filter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aubrey Holland
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-05-07 00:00:00 -07:00
13
+ date: 2009-05-09 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -28,6 +28,7 @@ files:
28
28
  - VERSION.yml
29
29
  - lib/record_filter.rb
30
30
  - lib/record_filter/active_record.rb
31
+ - lib/record_filter/column_parser.rb
31
32
  - lib/record_filter/conjunctions.rb
32
33
  - lib/record_filter/dsl.rb
33
34
  - lib/record_filter/dsl/class_join.rb
@@ -48,6 +49,7 @@ files:
48
49
  - lib/record_filter/join.rb
49
50
  - lib/record_filter/order.rb
50
51
  - lib/record_filter/query.rb
52
+ - lib/record_filter/restriction_factory.rb
51
53
  - lib/record_filter/restrictions.rb
52
54
  - lib/record_filter/table.rb
53
55
  - spec/active_record_spec.rb
@@ -64,7 +66,7 @@ files:
64
66
  - spec/test.db
65
67
  - test/performance_test.rb
66
68
  - test/test.db
67
- has_rdoc: true
69
+ has_rdoc: false
68
70
  homepage: http://github.com/aub/record_filter/tree/master
69
71
  post_install_message:
70
72
  rdoc_options: