searchlogic 2.4.32 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
2
  :major: 2
3
- :minor: 4
4
- :patch: 32
3
+ :minor: 5
4
+ :patch: 0
5
5
  :build:
@@ -10,7 +10,7 @@ module Searchlogic
10
10
  alias_method_chain :merge_joins, :merged_duplicates
11
11
  end
12
12
  end
13
-
13
+
14
14
  # In AR multiple joins are sometimes in a single join query, and other times they
15
15
  # are not. The merge_joins method in AR should account for this, but it doesn't.
16
16
  # This fixes that problem. This way there is one join per string, which allows
@@ -19,7 +19,7 @@ module Searchlogic
19
19
  joins = merge_joins_without_singularity(*args)
20
20
  joins.collect { |j| j.is_a?(String) ? j.split(" ") : j }.flatten.uniq
21
21
  end
22
-
22
+
23
23
  # This method ensures that the order of the conditions in the joins are the same.
24
24
  # The strings of the joins MUST be exactly the same for AR to remove the duplicates.
25
25
  # AR is not consistent in this approach, resulting in duplicate joins errors when
@@ -38,8 +38,8 @@ module Searchlogic
38
38
  end
39
39
  end.uniq
40
40
  end
41
-
42
-
41
+
42
+
43
43
  def merge_joins_with_merged_duplicates(*args)
44
44
  args << "" if !Thread.current["searchlogic_delegation"]
45
45
  joins = merge_joins_without_merged_duplicates(*args)
@@ -14,14 +14,14 @@ module Searchlogic
14
14
  # method.
15
15
  def named_scope_options(name)
16
16
  key = scopes.key?(name.to_sym) ? name.to_sym : condition_scope_name(name)
17
-
18
- if key
17
+
18
+ if key && scopes[key]
19
19
  eval("options", scopes[key].binding)
20
20
  else
21
21
  nil
22
22
  end
23
23
  end
24
-
24
+
25
25
  # The arity for a named scope's proc is important, because we use the arity
26
26
  # to determine if the condition should be ignored when calling the search method.
27
27
  # If the condition is false and the arity is 0, then we skip it all together. Ex:
@@ -37,7 +37,7 @@ module Searchlogic
37
37
  options = named_scope_options(name)
38
38
  options.respond_to?(:arity) ? options.arity : nil
39
39
  end
40
-
40
+
41
41
  # When searchlogic calls a named_scope on a foreigh model it will execute that scope and then call scope(:find).
42
42
  # When we get these options we want this to be in an exclusive scope, especially if we are calling a condition on
43
43
  # the same originating model:
@@ -58,7 +58,7 @@ module Searchlogic
58
58
  with_exclusive_scope(&block)
59
59
  Thread.current["searchlogic_delegation"] = old
60
60
  end
61
-
61
+
62
62
  # A convenience method for creating inner join sql to that your inner joins
63
63
  # are consistent with how Active Record creates them. Basically a tool for
64
64
  # you to use when writing your own named scopes. This way you know for sure
@@ -71,7 +71,7 @@ module Searchlogic
71
71
  def inner_joins(association_name)
72
72
  ::ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, association_name, nil).join_associations.collect { |assoc| assoc.association_join }
73
73
  end
74
-
74
+
75
75
  # A convenience methods to create a join on a polymorphic associations target.
76
76
  # Ex:
77
77
  #
@@ -91,7 +91,7 @@ module Searchlogic
91
91
  "INNER JOIN #{options[:target_table]} ON #{options[:target_table]}.id = #{options[:on_table_name]}.#{options[:as]}_id AND " +
92
92
  "#{options[:on_table_name]}.#{options[:as]}_type = #{postgres ? "E" : ""}'#{target.to_s.camelize}'"
93
93
  end
94
-
94
+
95
95
  # See inner_joins. Does the same thing except creates LEFT OUTER joins.
96
96
  def left_outer_joins(association_name)
97
97
  ::ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, association_name, nil).join_associations.collect { |assoc| assoc.association_join }
@@ -0,0 +1,22 @@
1
+ module Searchlogic
2
+ module ActiveRecord
3
+ # The internals to ActiveRecord like to do scopes.include?(scope_name). And this is how they check for the existence
4
+ # of scopes, which is terrible. The problem is that searchlogic scopes are dynamically created. So the only solution
5
+ # is to override the include? method for the scopes hash, try to create the named scope, and then check it again.
6
+ # This shouldn't effect performance because once its created it never gets called again. I also cache failed names
7
+ # so we don't try to create them again.
8
+ module Scope
9
+ def scopes
10
+ read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {}.tap do |h|
11
+ h.instance_eval <<-eval
12
+ def include?(key)
13
+ result = super
14
+ return result if result
15
+ super
16
+ end
17
+ eval
18
+ end)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -4,7 +4,7 @@ module Searchlogic
4
4
  def self.included(klass)
5
5
  klass.class_eval do
6
6
  attr_accessor :searchlogic_options
7
-
7
+
8
8
  def searchlogic_options
9
9
  @searchlogic_options ||= {}
10
10
  @searchlogic_options[:type] ||= :string
@@ -45,23 +45,24 @@ module Searchlogic
45
45
  end
46
46
  end
47
47
  alias_method :scope_procedure, :alias_scope
48
-
49
- def alias_scopes # :nodoc:
50
- read_inheritable_attribute(:alias_scopes) || write_inheritable_attribute(:alias_scopes, {})
51
- end
52
-
53
- def alias_scope?(name) # :nodoc:
54
- return false if name.blank?
55
- alias_scopes.key?(name.to_sym)
56
- end
57
-
48
+
58
49
  def condition?(name) # :nodoc:
59
50
  super || alias_scope?(name)
60
51
  end
61
-
52
+
62
53
  def named_scope_options(name) # :nodoc:
63
54
  super || alias_scopes[name.to_sym]
64
55
  end
56
+
57
+ private
58
+ def alias_scopes # :nodoc:
59
+ read_inheritable_attribute(:alias_scopes) || write_inheritable_attribute(:alias_scopes, {})
60
+ end
61
+
62
+ def alias_scope?(name) # :nodoc:
63
+ return false if name.blank?
64
+ alias_scopes.key?(name.to_sym)
65
+ end
65
66
  end
66
67
  end
67
68
  end
@@ -11,12 +11,13 @@ module Searchlogic
11
11
  !association_condition_details(name).nil? unless name.to_s.downcase.match("_or_")
12
12
  end
13
13
 
14
- def method_missing(name, *args, &block)
15
- if !local_condition?(name) && details = association_condition_details(name)
16
- create_association_condition(details[:association], details[:condition], args, details[:poly_class])
17
- send(name, *args)
18
- else
19
- super
14
+ # We need to try and create other conditions first so that we give priority to conflicting names.
15
+ # Such as having a column names the exact same name as an association condition.
16
+ def create_condition(name)
17
+ if result = super
18
+ result
19
+ elsif details = association_condition_details(name)
20
+ create_association_condition(details[:association], details[:condition], details[:poly_class])
20
21
  end
21
22
  end
22
23
 
@@ -51,27 +52,27 @@ module Searchlogic
51
52
  end
52
53
  end
53
54
 
54
- def create_association_condition(association, condition_name, args, poly_class = nil)
55
+ def create_association_condition(association, condition_name, poly_class = nil)
55
56
  name = [association.name, poly_class && "#{poly_class.name.underscore}_type", condition_name].compact.join("_")
56
- named_scope(name, association_condition_options(association, condition_name, args, poly_class))
57
+ named_scope(name, association_condition_options(association, condition_name, poly_class))
57
58
  end
58
59
 
59
- def association_condition_options(association, association_condition, args, poly_class = nil)
60
+ def association_condition_options(association, association_condition, poly_class = nil)
60
61
  klass = poly_class ? poly_class : association.klass
61
- scope = klass.send(association_condition, *args)
62
- scope_options = klass.named_scope_options(association_condition)
62
+ raise ArgumentError.new("The #{klass} class does not respond to the #{association_condition} scope") if !klass.respond_to?(association_condition)
63
63
  arity = klass.named_scope_arity(association_condition)
64
64
 
65
65
  if !arity || arity == 0
66
66
  # The underlying condition doesn't require any parameters, so let's just create a simple
67
67
  # named scope that is based on a hash.
68
68
  options = {}
69
- in_searchlogic_delegation { options = scope.scope(:find) }
69
+ in_searchlogic_delegation { options = klass.send(association_condition).scope(:find) }
70
70
  prepare_named_scope_options(options, association, poly_class)
71
71
  options
72
72
  else
73
- proc_args = arity_args(arity)
73
+ scope_options = klass.named_scope_options(association_condition)
74
74
  scope_options = scope_options.respond_to?(:searchlogic_options) ? scope_options.searchlogic_options.clone : {}
75
+ proc_args = arity_args(arity)
75
76
  arg_type = scope_options.delete(:type) || :string
76
77
 
77
78
  eval <<-"end_eval"
@@ -83,7 +84,6 @@ module Searchlogic
83
84
  options = scope.scope(:find) if scope
84
85
  end
85
86
 
86
-
87
87
  prepare_named_scope_options(options, association, poly_class)
88
88
  options
89
89
  }
@@ -13,21 +13,20 @@ module Searchlogic
13
13
  def condition?(name) # :nodoc:
14
14
  super || association_ordering_condition?(name)
15
15
  end
16
-
16
+
17
17
  private
18
18
  def association_ordering_condition?(name)
19
19
  !association_ordering_condition_details(name).nil?
20
20
  end
21
-
22
- def method_missing(name, *args, &block)
21
+
22
+ def create_condition(name)
23
23
  if details = association_ordering_condition_details(name)
24
- create_association_ordering_condition(details[:association], details[:order_as], details[:condition], args)
25
- send(name, *args)
24
+ create_association_ordering_condition(details[:association], details[:order_as], details[:condition])
26
25
  else
27
26
  super
28
27
  end
29
28
  end
30
-
29
+
31
30
  def association_ordering_condition_details(name)
32
31
  associations = reflect_on_all_associations
33
32
  association_names = associations.collect { |assoc| assoc.name }
@@ -35,8 +34,8 @@ module Searchlogic
35
34
  {:order_as => $1, :association => associations.find { |a| a.name == $2.to_sym }, :condition => $3}
36
35
  end
37
36
  end
38
-
39
- def create_association_ordering_condition(association, order_as, condition, args)
37
+
38
+ def create_association_ordering_condition(association, order_as, condition)
40
39
  cond = condition
41
40
  poly_class = nil
42
41
  if condition =~ /^(\w+)_type_(\w+)$/
@@ -44,7 +43,7 @@ module Searchlogic
44
43
  cond = $2
45
44
  poly_class = poly_type.camelcase.constantize if poly_type
46
45
  end
47
- named_scope("#{order_as}_by_#{association.name}_#{condition}", association_condition_options(association, "#{order_as}_by_#{cond}", args, poly_class))
46
+ named_scope("#{order_as}_by_#{association.name}_#{condition}", association_condition_options(association, "#{order_as}_by_#{cond}", poly_class))
48
47
  end
49
48
  end
50
49
  end
@@ -0,0 +1,16 @@
1
+ module Searchlogic
2
+ module NamedScopes
3
+ module Base
4
+ def condition?(name)
5
+ existing_condition?(name)
6
+ end
7
+
8
+ private
9
+ def existing_condition?(name)
10
+ return false if name.blank?
11
+ @valid_scope_names ||= scopes.keys.reject { |k| k == :scoped }
12
+ @valid_scope_names.include?(name.to_sym)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -8,7 +8,7 @@ module Searchlogic
8
8
  # Notice the constants in this class, they define which conditions Searchlogic provides.
9
9
  #
10
10
  # See the README for a more detailed explanation.
11
- module Conditions
11
+ module ColumnConditions
12
12
  COMPARISON_CONDITIONS = {
13
13
  :equals => [:is, :eq],
14
14
  :does_not_equal => [:not_equal_to, :is_not, :not, :ne],
@@ -54,14 +54,19 @@ module Searchlogic
54
54
 
55
55
  # Is the name of the method a valid condition that can be dynamically created?
56
56
  def condition?(name)
57
- local_condition?(name)
57
+ super || column_condition?(name)
58
+ end
59
+
60
+ # We want to return true for any conditions that can be called, and while we're at it. We might as well
61
+ # create the condition so we don't have to do it again.
62
+ def respond_to?(*args)
63
+ super || (self != ::ActiveRecord::Base && !create_condition(args.first).blank?)
58
64
  end
59
65
 
60
66
  private
61
- def local_condition?(name)
67
+ def column_condition?(name)
62
68
  return false if name.blank?
63
- scope_names = scopes.keys.reject { |k| k == :scoped }
64
- scope_names.include?(name.to_sym) || !condition_details(name).nil? || boolean_condition?(name)
69
+ !condition_details(name).nil? || boolean_condition?(name)
65
70
  end
66
71
 
67
72
  def boolean_condition?(name)
@@ -70,13 +75,8 @@ module Searchlogic
70
75
  end
71
76
 
72
77
  def method_missing(name, *args, &block)
73
- if details = condition_details(name)
74
- create_condition(details[:column], details[:condition], args)
75
- send(name, *args)
76
- elsif boolean_condition?(name)
77
- column = name.to_s.gsub(/^not_/, "")
78
- named_scope name, :conditions => {column => (name.to_s =~ /^not_/).nil?}
79
- send(name)
78
+ if create_condition(name)
79
+ send(name, *args, &block)
80
80
  else
81
81
  super
82
82
  end
@@ -91,11 +91,21 @@ module Searchlogic
91
91
  end
92
92
  end
93
93
 
94
- def create_condition(column_name, condition, args)
95
- if PRIMARY_CONDITIONS.include?(condition.to_sym)
96
- create_primary_condition(column_name, condition)
97
- elsif ALIAS_CONDITIONS.include?(condition.to_sym)
98
- create_alias_condition(column_name, condition, args)
94
+ def create_condition(name)
95
+ @conditions_already_tried ||= []
96
+ return nil if @conditions_already_tried.include?(name.to_s)
97
+ @conditions_already_tried << name.to_s
98
+
99
+ if details = condition_details(name)
100
+ if PRIMARY_CONDITIONS.include?(details[:condition].to_sym)
101
+ create_primary_condition(details[:column], details[:condition])
102
+ elsif ALIAS_CONDITIONS.include?(details[:condition].to_sym)
103
+ create_alias_condition(details[:column], details[:condition])
104
+ end
105
+
106
+ elsif boolean_condition?(name)
107
+ column = name.to_s.gsub(/^not_/, "")
108
+ named_scope name, :conditions => {column => (name.to_s =~ /^not_/).nil?}
99
109
  end
100
110
  end
101
111
 
@@ -107,7 +117,7 @@ module Searchlogic
107
117
 
108
118
  scope_options = case condition.to_s
109
119
  when /^equals/
110
- scope_options(condition, column, lambda { |a| attribute_condition("#{table_name}.#{column.name}", a) }, :skip_conversion => skip_conversion)
120
+ scope_options(condition, column, "#{table_name}.#{column.name} = ?", :skip_conversion => skip_conversion)
111
121
  when /^does_not_equal/
112
122
  scope_options(condition, column, "#{table_name}.#{column.name} != ?", :skip_conversion => skip_conversion)
113
123
  when /^less_than_or_equal_to/
@@ -172,9 +182,9 @@ module Searchlogic
172
182
  values.flatten!
173
183
  values.collect! { |value| value_with_modifier(value, options[:value_modifier]) }
174
184
 
175
- scope_sql = values.collect { |value| sql.is_a?(Proc) ? sql.call(value) : sql }.join(join_word)
185
+ scope_sql = values.collect { |value| sql }.join(join_word)
176
186
 
177
- {:conditions => [scope_sql, *expand_range_bind_variables(values)]}
187
+ {:conditions => [scope_sql, *values]}
178
188
  end
179
189
  else
180
190
  {}
@@ -184,9 +194,7 @@ module Searchlogic
184
194
  searchlogic_lambda(column.type, :skip_conversion => options[:skip_conversion]) { |*values|
185
195
  values.collect! { |value| value_with_modifier(value, options[:value_modifier]) }
186
196
 
187
- scope_sql = sql.is_a?(Proc) ? sql.call(*values) : sql
188
-
189
- {:conditions => [scope_sql, *expand_range_bind_variables(values)]}
197
+ {:conditions => [sql, *values]}
190
198
  }
191
199
  end
192
200
  end
@@ -204,12 +212,13 @@ module Searchlogic
204
212
  end
205
213
  end
206
214
 
207
- def create_alias_condition(column_name, condition, args)
215
+ def create_alias_condition(column_name, condition)
208
216
  primary_condition = primary_condition(condition)
209
217
  alias_name = "#{column_name}_#{condition}"
210
218
  primary_name = "#{column_name}_#{primary_condition}"
211
- send(primary_name, *args) # go back to method_missing and make sure we create the method
212
- (class << self; self; end).class_eval { alias_method alias_name, primary_name }
219
+ if respond_to?(primary_name)
220
+ (class << self; self; end).class_eval { alias_method alias_name, primary_name }
221
+ end
213
222
  end
214
223
 
215
224
  # Returns the primary condition for the given alias. Ex:
@@ -5,30 +5,30 @@ module Searchlogic
5
5
  module OrConditions
6
6
  class NoConditionSpecifiedError < StandardError; end
7
7
  class UnknownConditionError < StandardError; end
8
-
8
+
9
9
  def condition?(name) # :nodoc:
10
10
  super || or_condition?(name)
11
11
  end
12
-
12
+
13
13
  def named_scope_options(name) # :nodoc:
14
14
  super || super(or_conditions(name).try(:join, "_or_"))
15
15
  end
16
-
16
+
17
17
  private
18
18
  def or_condition?(name)
19
19
  !or_conditions(name).nil?
20
20
  end
21
-
22
- def method_missing(name, *args, &block)
21
+
22
+ def create_condition(name)
23
23
  if conditions = or_conditions(name)
24
- create_or_condition(conditions, args)
25
- (class << self; self; end).class_eval { alias_method name, conditions.join("_or_") } if !respond_to?(name)
26
- send(name, *args)
24
+ create_or_condition(conditions)
25
+ alias_name = conditions.join("_or_")
26
+ (class << self; self; end).class_eval { alias_method name, conditions.join("_or_") } if name != alias_name
27
27
  else
28
28
  super
29
29
  end
30
30
  end
31
-
31
+
32
32
  def or_conditions(name)
33
33
  # First determine if we should even work on the name, we want to be as quick as possible
34
34
  # with this.
@@ -41,7 +41,7 @@ module Searchlogic
41
41
  end
42
42
  end
43
43
  end
44
-
44
+
45
45
  def split_or_condition(name)
46
46
  parts = name.to_s.split("_or_")
47
47
  new_parts = []
@@ -54,7 +54,7 @@ module Searchlogic
54
54
  end
55
55
  new_parts
56
56
  end
57
-
57
+
58
58
  # The purpose of this method is to convert the method name parts into actual condition names.
59
59
  #
60
60
  # Example:
@@ -81,7 +81,7 @@ module Searchlogic
81
81
  path = full_association_path(part, last_condition, association_details[:association])
82
82
  conditions << "#{path[:path].join("_").to_sym}_#{path[:column]}_#{path[:condition]}"
83
83
  last_condition = path[:condition] || nil
84
- elsif local_condition?(part)
84
+ elsif column_condition?(part)
85
85
  # We are a custom scope
86
86
  conditions << part
87
87
  elsif column_names.include?(part)
@@ -90,13 +90,13 @@ module Searchlogic
90
90
  raise NoConditionSpecifiedError.new("The '#{part}' column doesn't know which condition to use, if you use an exact column " +
91
91
  "name you need to specify a condition sometime after (ex: id_or_created_at_lt), where id would use the 'lt' condition.")
92
92
  end
93
-
93
+
94
94
  conditions << "#{part}_#{last_condition}"
95
95
  else
96
96
  raise UnknownConditionError.new("The condition '#{part}' is not a valid condition, we could not find any scopes that match this.")
97
97
  end
98
98
  end
99
-
99
+
100
100
  conditions.reverse
101
101
  end
102
102
 
@@ -116,8 +116,8 @@ module Searchlogic
116
116
  end
117
117
  { :path => path, :column => part, :condition => last_condition }
118
118
  end
119
-
120
- def create_or_condition(scopes, args)
119
+
120
+ def create_or_condition(scopes)
121
121
  scopes_options = scopes.collect { |scope, *args| send(scope, *args).proxy_options }
122
122
  # We're using first scope to determine column's type
123
123
  scope = named_scope_options(scopes.first)
@@ -126,7 +126,7 @@ module Searchlogic
126
126
  merge_scopes_with_or(scopes.collect { |scope| clone.send(scope, *args) })
127
127
  }
128
128
  end
129
-
129
+
130
130
  def merge_scopes_with_or(scopes)
131
131
  scopes_options = scopes.collect { |scope| scope.scope(:find) }
132
132
  conditions = scopes_options.reject { |o| o[:conditions].nil? }.collect { |o| sanitize_sql(o[:conditions]) }
@@ -10,27 +10,25 @@ module Searchlogic
10
10
  def condition?(name) # :nodoc:
11
11
  super || ordering_condition?(name)
12
12
  end
13
-
13
+
14
14
  private
15
15
  def ordering_condition?(name) # :nodoc:
16
16
  !ordering_condition_details(name).nil?
17
17
  end
18
-
19
- def method_missing(name, *args, &block)
18
+
19
+ def create_condition(name)
20
20
  if name == :order
21
21
  named_scope name, lambda { |scope_name|
22
22
  return {} if !condition?(scope_name)
23
23
  send(scope_name).proxy_options
24
24
  }
25
- send(name, *args)
26
25
  elsif details = ordering_condition_details(name)
27
26
  create_ordering_conditions(details[:column])
28
- send(name, *args)
29
27
  else
30
28
  super
31
29
  end
32
30
  end
33
-
31
+
34
32
  def ordering_condition_details(name)
35
33
  if name.to_s =~ /^(ascend|descend)_by_(#{column_names.join("|")})$/
36
34
  {:order_as => $1, :column => $2}
@@ -38,7 +36,7 @@ module Searchlogic
38
36
  {}
39
37
  end
40
38
  end
41
-
39
+
42
40
  def create_ordering_conditions(column)
43
41
  named_scope("ascend_by_#{column}".to_sym, {:order => "#{table_name}.#{column} ASC"})
44
42
  named_scope("descend_by_#{column}".to_sym, {:order => "#{table_name}.#{column} DESC"})
@@ -31,13 +31,13 @@ module Searchlogic
31
31
  end
32
32
  self
33
33
  end
34
-
34
+
35
35
  private
36
36
  # This is here as a hook to allow people to modify the order in which the conditions are called, for whatever reason.
37
37
  def conditions_array
38
38
  @conditions.to_a
39
39
  end
40
-
40
+
41
41
  def write_condition(name, value)
42
42
  @conditions[name] = value
43
43
  end
@@ -49,7 +49,7 @@ module Searchlogic
49
49
  def mass_conditions
50
50
  @mass_conditions ||= {}
51
51
  end
52
-
52
+
53
53
  def ignore_value?(value)
54
54
  (value.is_a?(String) && value.blank?) || (value.is_a?(Array) && value.empty?)
55
55
  end
@@ -7,7 +7,7 @@ module Searchlogic
7
7
  include InstanceMethods
8
8
  end
9
9
  end
10
-
10
+
11
11
  module InstanceMethods
12
12
  def to_yaml( opts = {} )
13
13
  YAML::quick_emit( self, opts ) do |out|
@@ -18,7 +18,7 @@ module Searchlogic
18
18
  end
19
19
  end
20
20
  end
21
-
21
+
22
22
  def yaml_initialize(taguri, attributes = {})
23
23
  self.klass = attributes["class_name"].constantize
24
24
  self.current_scope = attributes["current_scope"]
data/lib/searchlogic.rb CHANGED
@@ -1,9 +1,10 @@
1
1
  require "searchlogic/core_ext/proc"
2
2
  require "searchlogic/core_ext/object"
3
- require "searchlogic/active_record/association_proxy"
4
3
  require "searchlogic/active_record/consistency"
5
4
  require "searchlogic/active_record/named_scope_tools"
6
- require "searchlogic/named_scopes/conditions"
5
+ require "searchlogic/active_record/scope"
6
+ require "searchlogic/named_scopes/base"
7
+ require "searchlogic/named_scopes/column_conditions"
7
8
  require "searchlogic/named_scopes/ordering"
8
9
  require "searchlogic/named_scopes/association_conditions"
9
10
  require "searchlogic/named_scopes/association_ordering"
@@ -24,19 +25,15 @@ Proc.send(:include, Searchlogic::CoreExt::Proc)
24
25
  Object.send(:include, Searchlogic::CoreExt::Object)
25
26
 
26
27
  module ActiveRecord # :nodoc: all
27
- module Associations
28
- class AssociationProxy
29
- include Searchlogic::ActiveRecord::AssociationProxy
30
- end
31
- end
32
-
33
28
  class Base
34
29
  class << self; include Searchlogic::ActiveRecord::Consistency; end
35
30
  end
36
31
  end
37
32
 
33
+ ActiveRecord::Base.extend(Searchlogic::ActiveRecord::Scope)
38
34
  ActiveRecord::Base.extend(Searchlogic::ActiveRecord::NamedScopeTools)
39
- ActiveRecord::Base.extend(Searchlogic::NamedScopes::Conditions)
35
+ ActiveRecord::Base.extend(Searchlogic::NamedScopes::Base)
36
+ ActiveRecord::Base.extend(Searchlogic::NamedScopes::ColumnConditions)
40
37
  ActiveRecord::Base.extend(Searchlogic::NamedScopes::AssociationConditions)
41
38
  ActiveRecord::Base.extend(Searchlogic::NamedScopes::AssociationOrdering)
42
39
  ActiveRecord::Base.extend(Searchlogic::NamedScopes::Ordering)
data/searchlogic.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{searchlogic}
8
- s.version = "2.4.32"
8
+ s.version = "2.5.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Ben Johnson of Binary Logic"]
@@ -25,15 +25,16 @@ Gem::Specification.new do |s|
25
25
  "VERSION.yml",
26
26
  "init.rb",
27
27
  "lib/searchlogic.rb",
28
- "lib/searchlogic/active_record/association_proxy.rb",
29
28
  "lib/searchlogic/active_record/consistency.rb",
30
29
  "lib/searchlogic/active_record/named_scope_tools.rb",
30
+ "lib/searchlogic/active_record/scope.rb",
31
31
  "lib/searchlogic/core_ext/object.rb",
32
32
  "lib/searchlogic/core_ext/proc.rb",
33
33
  "lib/searchlogic/named_scopes/alias_scope.rb",
34
34
  "lib/searchlogic/named_scopes/association_conditions.rb",
35
35
  "lib/searchlogic/named_scopes/association_ordering.rb",
36
- "lib/searchlogic/named_scopes/conditions.rb",
36
+ "lib/searchlogic/named_scopes/base.rb",
37
+ "lib/searchlogic/named_scopes/column_conditions.rb",
37
38
  "lib/searchlogic/named_scopes/or_conditions.rb",
38
39
  "lib/searchlogic/named_scopes/ordering.rb",
39
40
  "lib/searchlogic/rails_helpers.rb",
@@ -56,7 +57,7 @@ Gem::Specification.new do |s|
56
57
  "spec/searchlogic/named_scopes/alias_scope_spec.rb",
57
58
  "spec/searchlogic/named_scopes/association_conditions_spec.rb",
58
59
  "spec/searchlogic/named_scopes/association_ordering_spec.rb",
59
- "spec/searchlogic/named_scopes/conditions_spec.rb",
60
+ "spec/searchlogic/named_scopes/column_conditions_spec.rb",
60
61
  "spec/searchlogic/named_scopes/or_conditions_spec.rb",
61
62
  "spec/searchlogic/named_scopes/ordering_spec.rb",
62
63
  "spec/searchlogic/search_spec.rb",
@@ -74,7 +75,7 @@ Gem::Specification.new do |s|
74
75
  "spec/searchlogic/named_scopes/alias_scope_spec.rb",
75
76
  "spec/searchlogic/named_scopes/association_conditions_spec.rb",
76
77
  "spec/searchlogic/named_scopes/association_ordering_spec.rb",
77
- "spec/searchlogic/named_scopes/conditions_spec.rb",
78
+ "spec/searchlogic/named_scopes/column_conditions_spec.rb",
78
79
  "spec/searchlogic/named_scopes/or_conditions_spec.rb",
79
80
  "spec/searchlogic/named_scopes/ordering_spec.rb",
80
81
  "spec/searchlogic/search_spec.rb",
@@ -18,6 +18,6 @@ describe Searchlogic::NamedScopes::AliasScope do
18
18
  end
19
19
 
20
20
  it "should inherit alias scopes from superclasses" do
21
- Class.new(User).alias_scope?("username_has").should be_true
21
+ Class.new(User).condition?("username_has").should be_true
22
22
  end
23
23
  end
@@ -209,5 +209,12 @@ describe Searchlogic::NamedScopes::AssociationConditions do
209
209
  user.orders.count.should == 1
210
210
  user.orders.shipped_on_not_null.shipped_on_greater_than(2.days.ago).count.should == 1
211
211
  end
212
-
212
+
213
+ it "should allow chained dynamic scopes without losing association scope conditions" do
214
+ user = User.create
215
+ order1 = Order.create :user => user, :shipped_on => Time.now, :total => 2
216
+ order2 = Order.create :shipped_on => Time.now, :total => 2
217
+ user.orders.id_equals(order1.id).count.should == 1
218
+ user.orders.id_equals(order1.id).total_equals(2).count.should == 1
219
+ end
213
220
  end
@@ -1,9 +1,13 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
2
2
 
3
- describe Searchlogic::NamedScopes::Conditions do
3
+ describe Searchlogic::NamedScopes::ColumnConditions do
4
4
  it "should be dynamically created and then cached" do
5
- User.should_not respond_to(:age_less_than)
5
+ User.scopes.key?(:age_less_than).should == false
6
6
  User.age_less_than(5)
7
+ User.scopes.key?(:age_less_than).should == true
8
+ end
9
+
10
+ it "should respond to the scope" do
7
11
  User.should respond_to(:age_less_than)
8
12
  end
9
13
 
@@ -15,8 +19,6 @@ describe Searchlogic::NamedScopes::Conditions do
15
19
  it "should have equals" do
16
20
  (5..7).each { |age| User.create(:age => age) }
17
21
  User.age_equals(6).all.should == User.find_all_by_age(6)
18
- User.age_equals(5..6).all.should == User.find_all_by_age(5..6)
19
- User.age_equals([5, 7]).all.should == User.find_all_by_age([5, 7])
20
22
  end
21
23
 
22
24
  it "should have does not equal" do
@@ -1,12 +1,6 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
2
2
 
3
3
  describe Searchlogic::NamedScopes::Ordering do
4
- it "should be dynamically created and then cached" do
5
- User.should_not respond_to(:ascend_by_username)
6
- User.ascend_by_username
7
- User.should respond_to(:ascend_by_username)
8
- end
9
-
10
4
  it "should have ascending" do
11
5
  %w(bjohnson thunt).each { |username| User.create(:username => username) }
12
6
  User.ascend_by_username.all.should == User.all(:order => "username ASC")
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: searchlogic
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 2.4.32
5
+ version: 2.5.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Ben Johnson of Binary Logic
@@ -53,15 +53,16 @@ files:
53
53
  - VERSION.yml
54
54
  - init.rb
55
55
  - lib/searchlogic.rb
56
- - lib/searchlogic/active_record/association_proxy.rb
57
56
  - lib/searchlogic/active_record/consistency.rb
58
57
  - lib/searchlogic/active_record/named_scope_tools.rb
58
+ - lib/searchlogic/active_record/scope.rb
59
59
  - lib/searchlogic/core_ext/object.rb
60
60
  - lib/searchlogic/core_ext/proc.rb
61
61
  - lib/searchlogic/named_scopes/alias_scope.rb
62
62
  - lib/searchlogic/named_scopes/association_conditions.rb
63
63
  - lib/searchlogic/named_scopes/association_ordering.rb
64
- - lib/searchlogic/named_scopes/conditions.rb
64
+ - lib/searchlogic/named_scopes/base.rb
65
+ - lib/searchlogic/named_scopes/column_conditions.rb
65
66
  - lib/searchlogic/named_scopes/or_conditions.rb
66
67
  - lib/searchlogic/named_scopes/ordering.rb
67
68
  - lib/searchlogic/rails_helpers.rb
@@ -84,7 +85,7 @@ files:
84
85
  - spec/searchlogic/named_scopes/alias_scope_spec.rb
85
86
  - spec/searchlogic/named_scopes/association_conditions_spec.rb
86
87
  - spec/searchlogic/named_scopes/association_ordering_spec.rb
87
- - spec/searchlogic/named_scopes/conditions_spec.rb
88
+ - spec/searchlogic/named_scopes/column_conditions_spec.rb
88
89
  - spec/searchlogic/named_scopes/or_conditions_spec.rb
89
90
  - spec/searchlogic/named_scopes/ordering_spec.rb
90
91
  - spec/searchlogic/search_spec.rb
@@ -103,7 +104,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
104
  requirements:
104
105
  - - ">="
105
106
  - !ruby/object:Gem::Version
106
- hash: -3829860769572842136
107
+ hash: -2184682576118207105
107
108
  segments:
108
109
  - 0
109
110
  version: "0"
@@ -128,7 +129,7 @@ test_files:
128
129
  - spec/searchlogic/named_scopes/alias_scope_spec.rb
129
130
  - spec/searchlogic/named_scopes/association_conditions_spec.rb
130
131
  - spec/searchlogic/named_scopes/association_ordering_spec.rb
131
- - spec/searchlogic/named_scopes/conditions_spec.rb
132
+ - spec/searchlogic/named_scopes/column_conditions_spec.rb
132
133
  - spec/searchlogic/named_scopes/or_conditions_spec.rb
133
134
  - spec/searchlogic/named_scopes/ordering_spec.rb
134
135
  - spec/searchlogic/search_spec.rb
@@ -1,20 +0,0 @@
1
- module Searchlogic
2
- module ActiveRecord
3
- module AssociationProxy
4
- def self.included(klass)
5
- klass.class_eval do
6
- alias_method_chain :send, :searchlogic
7
- end
8
- end
9
-
10
- def send_with_searchlogic(method, *args, &block)
11
- # create the scope if it doesn't exist yet, then delegate back to the original method
12
- if !proxy_respond_to?(method) && proxy_reflection.macro != :belongs_to && !proxy_reflection.options[:polymorphic] && proxy_reflection.klass.condition?(method)
13
- proxy_reflection.klass.send(method, *args, &block)
14
- end
15
-
16
- send_without_searchlogic(method, *args, &block)
17
- end
18
- end
19
- end
20
- end