diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc
index 810d4aea..bbadb990 100644
--- a/CHANGELOG.rdoc
+++ b/CHANGELOG.rdoc
@@ -1,9 +1,11 @@
-== 1.1.4 released 2008-09-24
+== 1.2.0 released 2008-09-24
* Added searchgasm_params and searchgasm_url helper to use outside of the control type helpers.
* Added dup and clone methods that work properly for searchgasm objects
* Fixed bug to remove nil scope values, HABTM likes to add :limit => nil
* Removed unnecessary build_search methods for associations
+* Removed support for searching with conditions only. This just made things much more complicated when you can accomplish the same thing by starting a new search and only setting conditions.
+* Fixed bug when searching with *any* conditions to use left outer joins instead of inner joins.
== 1.1.3 released 2008-09-23
diff --git a/README.rdoc b/README.rdoc
index 365d1d3e..b07c8d52 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -177,19 +177,6 @@ Any of the options used in the above example can be used in these, but for the s
search.conditions.first_name_contains = "Ben"
search.per_page = 20
search.all
-
-== Search with conditions only
-
-Don't need pagination, ordering, or any of the other options? Search with conditions only.
-
- conditions = User.new_conditions(:age_gt => 18)
- conditions.first_name_contains = "Ben"
- conditions.all
- # ... all operations above are available
-
-Pass a conditions object right into ActiveRecord:
-
- User.all(:conditions => conditions)
== Match ANY or ALL of the conditions
@@ -250,12 +237,11 @@ or
== Always use protection...against SQL injections
-If there is one thing we all know, it's to always use protection against SQL injections. That's why searchgasm protects you by default. The new\_search and new\_conditions methods protect mass assignments by default (instantiation and search.options = {}). This means that various checks are done to ensure it is not possible to perform any type of SQL injection during mass assignments. But this also limits how you can search, meaning you can't write raw SQL. If you want to be daring and search without protection, all that you have to do is add ! to the end of the methods: new\_search! and new\_conditions!.
+If there is one thing we all know, it's to always use protection against SQL injections. That's why searchgasm protects you by default. The new\_search methods protect mass assignments by default (instantiation and search.options = {}). This means that various checks are done to ensure it is not possible to perform any type of SQL injection during mass assignments. But this also limits how you can search, meaning you can't write raw SQL. If you want to be daring and search without protection, all that you have to do is add ! to the end of the method: new\_search!.
=== Protected from SQL injections
search = Account.new_search(params[:search])
- conditions = Account.new_conditions(params[:conditions])
=== *NOT* protected from SQL injections
@@ -263,11 +249,10 @@ If there is one thing we all know, it's to always use protection against SQL inj
accounts = Account.all(params[:search])
account = Account.first(params[:search])
search = Account.new_search!(params[:search])
- conditions = Account.new_conditions!(params[:conditions])
I'm sure you already knew this, but it's tempting to do this when you can pass the params hash right into these methods.
-Lesson learned: use new\_search and new\_conditions when passing in params as *ANY* of the options.
+Lesson learned: use new\_search when passing in params as *ANY* of the options.
== Available Conditions
diff --git a/lib/searchgasm.rb b/lib/searchgasm.rb
index ad25ce18..80d52718 100644
--- a/lib/searchgasm.rb
+++ b/lib/searchgasm.rb
@@ -8,7 +8,6 @@
# Shared
require "searchgasm/shared/utilities"
-require "searchgasm/shared/searching"
require "searchgasm/shared/virtual_classes"
# Base classes
@@ -23,6 +22,7 @@
require "searchgasm/search/ordering"
require "searchgasm/search/pagination"
require "searchgasm/search/conditions"
+require "searchgasm/search/searching"
require "searchgasm/search/base"
require "searchgasm/search/protection"
@@ -68,6 +68,7 @@ class Base
include Ordering
include Protection
include Pagination
+ include Searching
end
end
diff --git a/lib/searchgasm/active_record/base.rb b/lib/searchgasm/active_record/base.rb
index 0cc0494d..1d094718 100644
--- a/lib/searchgasm/active_record/base.rb
+++ b/lib/searchgasm/active_record/base.rb
@@ -11,6 +11,7 @@ module Base
def calculate_with_searchgasm(*args)
options = args.extract_options!
options = filter_options_with_searchgasm(options, false)
+ args[1] = primary_key if options[:distinct] && [nil, :all].include?(args[1]) # quick fix for adding a column name if distinct is true and no specific column is provided
args << options
calculate_without_searchgasm(*args)
end
@@ -47,30 +48,6 @@ def with_scope_with_searchgasm(method_scoping = {}, action = :merge, &block)
with_scope_without_searchgasm(method_scoping, action, &block)
end
- # This is a special method that Searchgasm adds in. It returns a new conditions object on the model. So you can search by conditions *only*.
- #
- # This method is "protected". Meaning it checks the passed options for SQL injections. So trying to write raw SQL in *any* of the option will result in a raised exception. It's safe to pass a params object when instantiating.
- #
- # === Examples
- #
- # conditions = User.new_conditions
- # conditions.first_name_contains = "Ben"
- # conditions.all # can call any search method: first, find(:all), find(:first), sum("id"), etc...
- def build_conditions(values = {}, &block)
- conditions = searchgasm_conditions
- conditions.protect = true
- conditions.conditions = values
- yield conditions if block_given?
- conditions
- end
-
- # See build_conditions. This is the same method but *without* protection. Do *NOT* pass in a params object to this method.
- def build_conditions!(values = {}, &block)
- conditions = searchgasm_conditions(values)
- yield conditions if block_given?
- conditions
- end
-
# This is a special method that Searchgasm adds in. It returns a new search object on the model. So you can search via an object.
#
# This method is "protected". Meaning it checks the passed options for SQL injections. So trying to write raw SQL in *any* of the option will result in a raised exception. It's safe to pass a params object when instantiating.
@@ -86,7 +63,7 @@ def build_conditions!(values = {}, &block)
# search.order_by = {:user_group => :name}
# search.all # can call any search method: first, find(:all), find(:first), sum("id"), etc...
def build_search(options = {}, &block)
- search = searchgasm_searcher
+ search = searchgasm_search
search.protect = true
search.options = options
yield search if block_given?
@@ -97,7 +74,7 @@ def build_search(options = {}, &block)
#
# This also has an alias "new_search!"
def build_search!(options = {}, &block)
- search = searchgasm_searcher(options)
+ search = searchgasm_search(options)
yield search if block_given?
search
end
@@ -120,7 +97,7 @@ def protected_conditions # :nodoc:
# This is the reverse of conditions_protected. You can specify conditions here and *only* these conditions will be allowed in mass assignment. Any condition not specified here will be blocked.
def conditions_accessible(*conditions)
- write_inheritable_attribute(:conditions_accessible, Set.new(conditions.map(&:to_s)) + (protected_conditions || []))
+ write_inheritable_attribute(:conditions_accessible, Set.new(conditions.map(&:to_s)) + (accessible_conditions || []))
end
def accessible_conditions # :nodoc:
@@ -130,7 +107,7 @@ def accessible_conditions # :nodoc:
private
def filter_options_with_searchgasm(options = {}, searching = true)
return options unless Searchgasm::Search::Base.needed?(self, options)
- search = Searchgasm::Search::Base.create_virtual_class(self).new # call explicitly to avoid merging the scopes into the searcher
+ search = Searchgasm::Search::Base.create_virtual_class(self).new # call explicitly to avoid merging the scopes into the search
search.acting_as_filter = true
conditions = options.delete(:conditions) || options.delete("conditions") || {}
if conditions
@@ -145,15 +122,7 @@ def filter_options_with_searchgasm(options = {}, searching = true)
search.sanitize(searching)
end
- def searchgasm_conditions(options = {})
- searcher = Searchgasm::Conditions::Base.create_virtual_class(self).new
- conditions = scope(:find) && scope(:find)[:conditions]
- searcher.scope = {:conditions => conditions} if conditions
- searcher.conditions = options
- searcher
- end
-
- def searchgasm_searcher(options = {})
+ def searchgasm_search(options = {})
scope = {}
current_scope = scope(:find) && scope(:find).deep_dup
if current_scope
@@ -168,11 +137,11 @@ def searchgasm_searcher(options = {})
current_scope.each { |k, v| new_scope[k] = v unless v.nil? }
current_scope = new_scope
end
- searcher = Searchgasm::Search::Base.create_virtual_class(self).new
- searcher.scope = scope
- searcher.options = current_scope
- searcher.options = options
- searcher
+ search = Searchgasm::Search::Base.create_virtual_class(self).new
+ search.scope = scope
+ search.options = current_scope
+ search.options = options
+ search
end
end
end
@@ -186,8 +155,6 @@ class << self
alias_method_chain :calculate, :searchgasm
alias_method_chain :find, :searchgasm
alias_method_chain :with_scope, :searchgasm
- alias_method :new_conditions, :build_conditions
- alias_method :new_conditions!, :build_conditions!
alias_method :new_search, :build_search
alias_method :new_search!, :build_search!
diff --git a/lib/searchgasm/conditions/base.rb b/lib/searchgasm/conditions/base.rb
index 7bc3ae4a..ac4ce51b 100644
--- a/lib/searchgasm/conditions/base.rb
+++ b/lib/searchgasm/conditions/base.rb
@@ -6,7 +6,6 @@ module Conditions # :nodoc:
# Each condition has its own file and class and the source for each condition is pretty self explanatory.
class Base
include Shared::Utilities
- include Shared::Searching
include Shared::VirtualClasses
attr_accessor :any, :relationship_name
@@ -65,6 +64,8 @@ def condition_names
end
def needed?(model_class, conditions) # :nodoc:
+ return false if conditions.blank?
+
if conditions.is_a?(Hash)
return true if conditions[:any]
column_names = model_class.column_names
@@ -105,11 +106,11 @@ def any?
end
# A list of joins to use when searching, includes relationships
- def joins
+ def auto_joins
j = []
associations.each do |association|
next if association.conditions.blank?
- association_joins = association.joins
+ association_joins = association.auto_joins
j << (association_joins.blank? ? association.relationship_name.to_sym : {association.relationship_name.to_sym => association_joins})
end
j.blank? ? nil : (j.size == 1 ? j.first : j)
@@ -262,7 +263,7 @@ def objects
end
def reset_objects!
- objects.each { |object| eval("@#{object.name} = nil") }
+ objects.each { |object| object.class < ::Searchgasm::Conditions::Base ? eval("@#{object.relationship_name} = nil") : eval("@#{object.name} = nil") }
objects.clear
end
diff --git a/lib/searchgasm/search/base.rb b/lib/searchgasm/search/base.rb
index a6c29642..a9b1317e 100644
--- a/lib/searchgasm/search/base.rb
+++ b/lib/searchgasm/search/base.rb
@@ -3,10 +3,8 @@ module Search #:nodoc:
# = Searchgasm
#
# Please refer the README.rdoc for usage, examples, and installation.
-
class Base
include Searchgasm::Shared::Utilities
- include Searchgasm::Shared::Searching
include Searchgasm::Shared::VirtualClasses
# Options ActiveRecord allows when searching
@@ -24,11 +22,14 @@ class Base
OPTIONS = SPECIAL_FIND_OPTIONS + AR_OPTIONS # the order is very important, these options get set in this order
attr_accessor *AR_OPTIONS
+ attr_reader :auto_joins
class << self
# Used in the ActiveRecord methods to determine if Searchgasm should get involved or not.
# This keeps Searchgasm out of the way unless it is needed.
def needed?(model_class, options)
+ return false if options.blank?
+
SPECIAL_FIND_OPTIONS.each do |option|
return true if options.symbolize_keys.keys.include?(option)
end
@@ -78,13 +79,8 @@ def inspect
"#<#{klass}Search #{current_find_options.inspect}>"
end
- def joins=(value)
- @memoized_joins = nil
- @joins = value
- end
-
def joins
- @memoized_joins ||= @joins
+ merge_joins(@joins, auto_joins)
end
def limit=(value)
@@ -128,9 +124,7 @@ def sanitize(searching = true)
if searching
find_options[:group] ||= "#{quote_table_name(klass.table_name)}.#{quote_column_name(klass.primary_key)}"
else
- # If we are calculating use includes because they use joins that grab uniq records. When calculating, includes don't have the
- # performance hit that they have when searching. Plus it's cleaner.
- find_options[:include] = merge_joins(find_options[:include], find_options.delete(:joins))
+ find_options[:distinct] = true
end
end
diff --git a/lib/searchgasm/search/conditions.rb b/lib/searchgasm/search/conditions.rb
index bb1f83e7..df621936 100644
--- a/lib/searchgasm/search/conditions.rb
+++ b/lib/searchgasm/search/conditions.rb
@@ -10,6 +10,7 @@ def self.included(klass)
alias_method_chain :initialize, :conditions
alias_method_chain :conditions=, :conditions
alias_method_chain :conditions, :conditions
+ alias_method_chain :auto_joins, :conditions
alias_method_chain :joins, :conditions
alias_method_chain :sanitize, :conditions
end
@@ -34,7 +35,7 @@ def initialize_with_conditions(init_options = {})
# now you can create the rest of your search and your "scope" will get merged into your final SQL.
# What this does is determine if the value a hash or a conditions object, if not it sets it up as a scope.
def conditions_with_conditions=(values)
- @memoized_joins = nil
+ @memoized_auto_joins = nil
case values
when Searchgasm::Conditions::Base
@conditions = values
@@ -44,7 +45,7 @@ def conditions_with_conditions=(values)
end
def conditions_with_conditions
- @memoized_joins = nil # have to assume they are calling a condition on a relationship
+ @memoized_auto_joins = nil # have to assume they are calling a condition on a relationship
conditions_without_conditions
end
@@ -52,8 +53,18 @@ def conditions_with_conditions
#
# Be careful!
# ActiveRecord associations can be an SQL train wreck. Make sure you think about what you are searching and that you aren't joining a table with a million records.
+ def auto_joins_with_conditions
+ @memoized_auto_joins ||= merge_joins(auto_joins_without_conditions, conditions.auto_joins)
+ end
+
+ # Changes joins to use left outer joins if conditions.any == true.
def joins_with_conditions
- @memoized_joins ||= merge_joins(joins_without_conditions, conditions.joins)
+ if conditions.any?
+ join_dependency = ::ActiveRecord::Associations::ClassMethods::JoinDependency.new(klass, joins_without_conditions, nil)
+ join_dependency.join_associations.collect { |assoc| assoc.association_join }.join
+ else
+ joins_without_conditions
+ end
end
def sanitize_with_conditions(searching = true) # :nodoc:
diff --git a/lib/searchgasm/search/ordering.rb b/lib/searchgasm/search/ordering.rb
index b6683b2c..a3ed8ddc 100644
--- a/lib/searchgasm/search/ordering.rb
+++ b/lib/searchgasm/search/ordering.rb
@@ -18,20 +18,20 @@ module Search
module Ordering
def self.included(klass)
klass.class_eval do
- alias_method_chain :joins, :ordering
+ alias_method_chain :auto_joins, :ordering
alias_method_chain :order=, :ordering
end
end
- def joins_with_ordering # :nodoc:
- @memoized_joins ||= merge_joins(joins_without_ordering, order_by_joins)
+ def auto_joins_with_ordering # :nodoc:
+ @memoized_auto_joins ||= merge_joins(auto_joins_without_ordering, order_by_auto_joins)
end
def order_with_ordering=(value) # :nodoc
@order_by = nil
@order_as = nil
- self.order_by_joins.clear
- @memoized_joins = nil
+ self.order_by_auto_joins.clear
+ @memoized_auto_joins = nil
self.order_without_ordering = value
end
@@ -101,19 +101,19 @@ def order_by
# order_by = [:id, name] # => users.id ASC, user.name ASC
# order_by = [:id, {:user_group => :name}] # => users.id ASC, user_groups.name ASC
def order_by=(value)
- self.order_by_joins.clear
- @memoized_joins = nil
+ self.order_by_auto_joins.clear
+ @memoized_auto_joins = nil
@order_by = get_order_by_value(value)
@order = order_by_to_order(@order_by, order_as)
@order_by
end
# Returns the joins neccessary for the "order" statement so that we don't get an SQL error
- def order_by_joins
- @order_by_joins ||= []
- @order_by_joins.compact!
- @order_by_joins.uniq!
- @order_by_joins
+ def order_by_auto_joins
+ @order_by_auto_joins ||= []
+ @order_by_auto_joins.compact!
+ @order_by_auto_joins.uniq!
+ @order_by_auto_joins
end
private
@@ -133,20 +133,20 @@ def order_by_to_order(order_by, order_as, alt_klass = nil, new_joins = [])
new_joins << key.to_sym
sql_parts << order_by_to_order(value, order_as, reflection.klass, new_joins)
when Symbol, String
- new_join = build_order_by_joins(new_joins)
- self.order_by_joins << new_join if new_join
+ new_join = build_order_by_auto_joins(new_joins)
+ self.order_by_auto_joins << new_join if new_join
sql_parts << "#{quote_table_name(table_name)}.#{quote_column_name(order_by)} #{order_as}"
end
sql_parts.join(", ")
end
- def build_order_by_joins(joins)
+ def build_order_by_auto_joins(joins)
return joins.first if joins.size <= 1
joins = joins.dup
key = joins.shift
- {key => build_order_by_joins(joins)}
+ {key => build_order_by_auto_joins(joins)}
end
def get_order_by_value(value)
diff --git a/lib/searchgasm/search/searching.rb b/lib/searchgasm/search/searching.rb
new file mode 100644
index 00000000..e9715c52
--- /dev/null
+++ b/lib/searchgasm/search/searching.rb
@@ -0,0 +1,32 @@
+module Searchgasm
+ module Search
+ # = Searchgasm Searching
+ #
+ # Implements searching functionality for searchgasm. Searchgasm::Search::Base and Searchgasm::Conditions::Base can both search and include
+ # this module.
+ module Searching
+ # Use these methods just like you would in ActiveRecord
+ SEARCH_METHODS = [:all, :find, :first]
+ CALCULATION_METHODS = [:average, :calculate, :count, :maximum, :minimum, :sum]
+
+ def self.included(klass)
+ klass.class_eval do
+ attr_accessor :scope
+ end
+ end
+
+ (SEARCH_METHODS + CALCULATION_METHODS).each do |method|
+ class_eval <<-"end_eval", __FILE__, __LINE__
+ def #{method}(*args)
+ find_options = {}
+ options = args.extract_options! # can't pass options, your options are in the search
+ klass.send(:with_scope, :find => scope) do
+ args << sanitize(#{SEARCH_METHODS.include?(method)})
+ klass.#{method}(*args)
+ end
+ end
+ end_eval
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/lib/searchgasm/shared/searching.rb b/lib/searchgasm/shared/searching.rb
deleted file mode 100644
index b635a306..00000000
--- a/lib/searchgasm/shared/searching.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-module Searchgasm
- module Shared
- # = Searchgasm Searching
- #
- # Implements searching functionality for searchgasm. Searchgasm::Search::Base and Searchgasm::Conditions::Base can both search and include
- # this module.
- module Searching
- # Use these methods just like you would in ActiveRecord
- SEARCH_METHODS = [:all, :find, :first]
- CALCULATION_METHODS = [:average, :calculate, :count, :maximum, :minimum, :sum]
-
- def self.included(klass)
- klass.class_eval do
- attr_accessor :scope
- end
- end
-
- (SEARCH_METHODS + CALCULATION_METHODS).each do |method|
- class_eval <<-"end_eval", __FILE__, __LINE__
- def #{method}(*args)
- find_options = {}
- options = args.extract_options!
- with_scopes = [scope, (self.class < Searchgasm::Conditions::Base ? {:conditions => sanitize} : sanitize(#{SEARCH_METHODS.include?(method)})), options].compact
- with_scopes.each do |with_scope|
- klass.send(:with_scope, :find => find_options) do
- klass.send(:with_scope, :find => with_scope) do
- find_options = klass.send(:scope, :find)
- end
- end
- end
-
- if self.class < Searchgasm::Search::Base
- (find_options.symbolize_keys.keys - #{SEARCH_METHODS.include?(method) ? "Search::Base::AR_FIND_OPTIONS" : "Search::Base::AR_CALCULATIONS_OPTIONS"}).each { |option| find_options.delete(option) }
- end
-
- args << find_options
- klass.#{method}(*args)
- end
- end_eval
- end
- end
- end
-end
\ No newline at end of file
diff --git a/lib/searchgasm/version.rb b/lib/searchgasm/version.rb
index 6538055b..08609a8b 100644
--- a/lib/searchgasm/version.rb
+++ b/lib/searchgasm/version.rb
@@ -66,8 +66,8 @@ def to_a
end
MAJOR = 1
- MINOR = 1
- TINY = 4
+ MINOR = 2
+ TINY = 0
# The current version as a Version instance
CURRENT = new(MAJOR, MINOR, TINY)
diff --git a/test/fixtures/user_groups.yml b/test/fixtures/user_groups.yml
new file mode 100644
index 00000000..e4c8e0ff
--- /dev/null
+++ b/test/fixtures/user_groups.yml
@@ -0,0 +1,13 @@
+neco:
+ id: 1
+ name: NECO
+ user_ids:
+ - 1
+ - 2
+
+johnsons:
+ id: 2
+ name: Johnsons
+ user_ids:
+ - 1
+ - 3
diff --git a/test/test_active_record_associations.rb b/test/test_active_record_associations.rb
index c50a7705..3103acc2 100644
--- a/test/test_active_record_associations.rb
+++ b/test/test_active_record_associations.rb
@@ -1,61 +1,81 @@
require File.dirname(__FILE__) + '/test_helper.rb'
class TestActiveRecordAssociations < Test::Unit::TestCase
- fixtures :accounts, :users, :orders
-
- def setup
- setup_db
- load_fixtures
- end
-
- def teardown
- teardown_db
- end
-
- def test_build_search
- search = Account.find(1).users.build_search
+ def test_has_many
+ search = Account.find(1).users.new_search
assert_kind_of Searchgasm::Search::Base, search
assert_equal User, search.klass
assert_equal({:conditions => "\"users\".account_id = 1"}, search.scope)
+ assert_equal User.find(1, 3), search.all
+ assert_equal User.find(1), search.first
+ assert_equal 2, search.average("id")
+ assert_equal 2, search.count
+
search.conditions.first_name_contains = "Ben"
- assert_equal({:conditions => ["\"users\".\"first_name\" LIKE ?", "%Ben%"], :limit => 25}, search.sanitize)
- end
-
- def test_searching
- assert_equal [User.find(1)], Account.find(1).users.all(:conditions => {:first_name_begins_with => "Ben"})
- assert_equal [User.find(1)], Account.find(1).users.find(:all, :conditions => {:first_name_begins_with => "Ben"})
- assert_equal User.find(1), Account.find(1).users.first(:conditions => {:first_name_begins_with => "Ben"})
- assert_equal User.find(1), Account.find(1).users.find(:first, :conditions => {:first_name_begins_with => "Ben"})
- assert_equal [], Account.find(1).users.all(:conditions => {:first_name_begins_with => "Ben"}, :per_page => 20, :page => 5)
- search = Account.find(1).users.new_search
- assert_equal User.find(1, 3), search.all
+ assert_equal [User.find(1)], search.all
assert_equal User.find(1), search.first
- end
-
- def test_calculations
- assert_equal 1, Account.find(1).users.count(:conditions => {:first_name_begins_with => "Ben"})
- assert_equal 1, Account.find(1).users.sum("id", :conditions => {:first_name_begins_with => "Ben"})
- assert_equal 1, Account.find(1).users.average("id", :conditions => {:first_name_begins_with => "Ben"})
+ assert_equal 1, search.average("id")
+ assert_equal 1, search.count
+
+ assert_equal 2, Account.find(1).users.count
+ assert_equal 1, Account.find(1).users.all(:conditions => {:first_name_contains => "Ben"}).size
+ assert_equal 0, Account.find(1).users.all(:conditions => {:first_name_contains => "No one"}).size
+ assert_equal 1, Account.find(1).users.sum("id", :conditions => {:first_name_contains => "Ben"})
+ assert_equal 0, Account.find(1).users.sum("id", :conditions => {:first_name_contains => "No one"})
+ assert_equal 1, Account.find(1).users.average("id", :conditions => {:first_name_contains => "Ben"})
end
def test_has_many_through
+ search = Account.find(1).orders.new_search
+ assert_kind_of Searchgasm::Search::Base, search
+ assert_equal Order, search.klass
+ assert_equal({:joins => "INNER JOIN users ON orders.user_id = users.id ", :conditions => "(\"users\".account_id = 1)"}, search.scope)
+
+ assert_equal [Order.find(1)], search.all
+ assert_equal Order.find(1), search.first
+ assert_equal 1, search.average("id")
+ assert_equal 1, search.count
+
+ search.conditions.total_gt = 100
+
+ assert_equal [Order.find(1)], search.all
+ assert_equal Order.find(1), search.first
+ assert_equal 1, search.average("id")
+ assert_equal 1, search.count
+
assert_equal 1, Account.find(1).orders.count
assert_equal 1, Account.find(1).orders.all(:conditions => {:total_gt => 100}).size
assert_equal 0, Account.find(1).orders.all(:conditions => {:total_gt => 1000}).size
assert_equal 1, Account.find(1).orders.sum("id", :conditions => {:total_gt => 100})
assert_equal 0, Account.find(1).orders.sum("id", :conditions => {:total_gt => 1000})
assert_equal 1, Account.find(1).orders.average("id", :conditions => {:total_gt => 100})
-
- search = Account.find(1).orders.new_search
- assert_equal [Order.find(1)], search.all
- assert_equal Order.find(1), search.first
- assert_equal 1, search.average("id")
- assert_equal 1, search.count
end
def test_habtm
+ search = UserGroup.find(1).users.new_search
+ assert_kind_of Searchgasm::Search::Base, search
+ assert_equal User, search.klass
+ assert_equal({:conditions => "\"user_groups_users\".user_group_id = 1 ", :joins => "INNER JOIN \"user_groups_users\" ON \"users\".id = \"user_groups_users\".user_id"}, search.scope)
+
+ assert_equal User.find(1, 2), search.all
+ assert_equal User.find(1), search.first
+ assert_equal 1.5, search.average("id")
+ assert_equal 2, search.count
+
+ search.conditions.first_name_contains = "Ben"
+
+ assert_equal [User.find(1)], search.all
+ assert_equal User.find(1), search.first
+ assert_equal 1, search.average("id")
+ assert_equal 1, search.count
+ assert_equal 2, UserGroup.find(1).users.count
+ assert_equal 1, UserGroup.find(1).users.all(:conditions => {:first_name_contains => "Ben"}).size
+ assert_equal 0, UserGroup.find(1).users.all(:conditions => {:first_name_contains => "No one"}).size
+ assert_equal 1, UserGroup.find(1).users.sum("id", :conditions => {:first_name_contains => "Ben"})
+ assert_equal 0, UserGroup.find(1).users.sum("id", :conditions => {:first_name_contains => "No one"})
+ assert_equal 1, UserGroup.find(1).users.average("id", :conditions => {:first_name_contains => "Ben"})
end
end
diff --git a/test/test_active_record_base.rb b/test/test_active_record_base.rb
index 0832cabd..d105d020 100644
--- a/test/test_active_record_base.rb
+++ b/test/test_active_record_base.rb
@@ -1,67 +1,46 @@
require File.dirname(__FILE__) + '/test_helper.rb'
class TestActiveRecordBase < Test::Unit::TestCase
- fixtures :accounts, :users, :orders
-
- def setup
- setup_db
- load_fixtures
- end
-
- def teardown
- teardown_db
+ def test_standard_find
+ assert_equal [1,2,3], Account.all.map(&:id)
+ assert_equal 1, Account.first.id
+ assert_equal [1,2,3], Account.find(:all).map(&:id)
+ assert_equal [1], Account.find(:all, :conditions => {:name => "Binary Logic"}).map(&:id)
+ assert_equal [1], Account.find(:all, :conditions => ["name = ?", "Binary Logic"]).map(&:id)
+ assert_equal [1], Account.find(:all, :conditions => "name = 'Binary Logic'").map(&:id)
+ assert_equal 1, Account.find(:first).id
+ assert_equal [1,2,3], Account.find(:all, nil).map(&:id)
+ assert_equal [1,2,3], Account.find(:all, {}).map(&:id)
end
- def test_standard_searches
- assert_nothing_raised { Account.all }
- assert_nothing_raised { Account.first }
- assert_nothing_raised { Account.find(:all) }
- assert_nothing_raised { Account.find(:all, :conditions => {:name => "Ben"}) }
- assert_nothing_raised { Account.find(:all, :conditions => ["name = ?", "Ben"]) }
- assert_nothing_raised { Account.find(:all, :conditions => "name = 'Ben'") }
- assert_nothing_raised { Account.find(:first) }
- assert_nothing_raised { Account.find(:all, nil) }
- assert_nothing_raised { Account.find(:all, {}) }
- assert_nothing_raised { Account.count({}) }
- assert_nothing_raised { Account.count(nil) }
- assert_nothing_raised { Account.sum("id") }
- assert_nothing_raised { Account.sum("id", {}) }
+ def test_standard_calculations
+ assert_equal 3, Account.count({})
+ assert_equal 3, Account.count(nil)
+ assert_equal 3, Account.count(:limit => 1)
+ assert_equal 0, Account.count(:limit => 10, :offset => 10)
+ assert_equal 6, Account.sum("id")
+ assert_equal 6, Account.sum("id", {})
+ assert_equal 2, Account.average("id")
+ assert_equal 3, Account.maximum("id")
+ assert_equal 1, Account.minimum("id")
end
- def test_ar_options
+ def test_valid_ar_options
assert_equal [ :conditions, :include, :joins, :limit, :offset, :order, :select, :readonly, :group, :from, :lock ], ActiveRecord::Base.valid_find_options
assert_equal [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include, :from], ActiveRecord::Base.valid_calculations_options
end
def test_build_search
- search = Account.new_search
- assert_kind_of Searchgasm::Search::Base, search
-
- search = Account.build_search(:conditions => {:name_keywords => "awesome"}, :page => 2, :per_page => 15)
+ search = Account.new_search(:conditions => {:name_keywords => "awesome"}, :page => 2, :per_page => 15)
assert_kind_of Searchgasm::Search::Base, search
+ assert_equal({}, search.scope)
assert_equal Account, search.klass
assert_equal "awesome", search.conditions.name_keywords
assert_equal 2, search.page
assert_equal 15, search.per_page
-
- search = Account.new_search(:conditions => {:name_keywords => "awesome"}, :page => 2, :per_page => 15)
- assert_equal Account, search.klass
end
- def test_build_conditions
- search = Account.new_conditions
- assert_kind_of Searchgasm::Conditions::Base, search
-
- search = Account.build_conditions(:name_keywords => "awesome")
- assert_kind_of Searchgasm::Conditions::Base, search
- assert_equal Account, search.klass
- assert_equal "awesome", search.name_keywords
-
- search = Account.new_conditions(:name_keywords => "awesome")
- assert_equal Account, search.klass
- end
-
- def test_searching
+ def test_searchgasm_searching
assert_equal Account.find(1, 3), Account.all(:conditions => {:name_contains => "Binary"})
assert_equal [Account.find(1)], Account.all(:conditions => {:name_contains => "Binary", :users => {:first_name_starts_with => "Ben"}})
assert_equal [], Account.all(:conditions => {:name_contains => "Binary", :users => {:first_name_starts_with => "Ben", :last_name => "Mills"}})
@@ -73,23 +52,34 @@ def test_searching
assert_equal [], Account.all(:conditions => {:name_contains => "Binary"}, :page => 2, :per_page => 20)
end
- def test_counting
+ def test_searchgasm_counting
assert_equal 2, Account.count(:conditions => {:name_contains => "Binary"})
assert_equal 1, Account.count(:conditions => {:name_contains => "Binary", :users => {:first_name_contains => "Ben"}})
+ assert_equal 1, Account.count(:conditions => {:name_contains => "Binary", :users => {:first_name_contains => "Ben"}}, :limit => 10, :offset => 10, :order_by => "id", :group => "id")
end
def test_scoping
- assert_equal nil, Account.send(:scope, :find)
+ assert_equal({:conditions => {:name => "Binary"}, :limit => 10, :readonly => true}, Account.send(:with_scope, :find => {:conditions => {:name => "Binary"}, :limit => 10, :readonly => true}) { Account.send(:scope, :find) })
+ assert_equal({:conditions => ["\"accounts\".\"name\" LIKE ?", "%Binary%"], :limit => 10, :offset => 20}, Account.send(:with_scope, :find => {:conditions => {:name_contains => "Binary"}, :per_page => 10, :page => 3}) { Account.send(:scope, :find) })
end
- def test_count
- assert_equal 3, Account.count
- assert_equal 3, Account.count(:limit => 1)
- assert_equal 0, Account.count(:limit => 1, :offset => 1) # not sure why AR doesn't ignore offset like it does for limit
- search = Account.new_search
- assert_equal 3, search.count
- search.per_page = 10
- search.page = 10
- assert_equal 3, search.count
+ def test_accessible_conditions
+ Account.conditions_accessible :name_contains
+ assert_equal Set.new(["name_contains"]), Account.accessible_conditions
+ Account.conditions_accessible :id_gt
+ assert_equal Set.new(["id_gt", "name_contains"]), Account.accessible_conditions
+ Account.conditions_accessible :id_gt, :name_contains
+ assert_equal Set.new(["id_gt", "name_contains"]), Account.accessible_conditions
+ Account.send(:write_inheritable_attribute, :conditions_accessible, nil)
+ end
+
+ def test_protected_conditions
+ Account.conditions_protected :name_contains
+ assert_equal Set.new(["name_contains"]), Account.protected_conditions
+ Account.conditions_protected :id_gt
+ assert_equal Set.new(["id_gt", "name_contains"]), Account.protected_conditions
+ Account.conditions_protected :id_gt, :name_contains
+ assert_equal Set.new(["id_gt", "name_contains"]), Account.protected_conditions
+ Account.send(:write_inheritable_attribute, :conditions_protected, nil)
end
end
diff --git a/test/test_condition_base.rb b/test/test_condition_base.rb
index 2a9c39b0..30a07331 100644
--- a/test/test_condition_base.rb
+++ b/test/test_condition_base.rb
@@ -1,29 +1,42 @@
require File.dirname(__FILE__) + '/test_helper.rb'
class TestConditionBase < Test::Unit::TestCase
- fixtures :accounts, :users, :orders
+ def test_condition_name
+ assert_equal "equals", Searchgasm::Condition::Equals.condition_name
+ assert_equal "keywords", Searchgasm::Condition::Keywords.condition_name
+ assert_equal "greater_than_or_equal_to", Searchgasm::Condition::GreaterThanOrEqualTo.condition_name
+ end
- def setup
- setup_db
- load_fixtures
+ def test_name_for_column
+ assert_equal "id_equals", Searchgasm::Condition::Equals.name_for_column(Account.columns_hash["id"])
+ assert_equal nil, Searchgasm::Condition::Keywords.name_for_column(Account.columns_hash["id"])
end
- def teardown
- teardown_db
+ def test_ignore_blanks?
+ assert !Searchgasm::Condition::Equals.ignore_blanks?
+ assert Searchgasm::Condition::Keywords.ignore_blanks?
end
- def test_condition_name
- assert_equal "equals", Searchgasm::Condition::Equals.condition_name
- assert_equal "keywords", Searchgasm::Condition::Keywords.condition_name
- assert_equal "greater_than_or_equal_to", Searchgasm::Condition::GreaterThanOrEqualTo.condition_name
+ def test_type_cast_value?
+ assert Searchgasm::Condition::Equals.type_cast_value?
+ assert Searchgasm::Condition::Keywords.type_cast_value?
+ assert !Searchgasm::Condition::IsNil.type_cast_value?
+ assert !Searchgasm::Condition::IsBlank.type_cast_value?
end
def test_string_column
-
+ assert !Searchgasm::Condition::Base.string_column?(Account.columns_hash["id"])
+ assert Searchgasm::Condition::Base.string_column?(Account.columns_hash["name"])
+ assert !Searchgasm::Condition::Base.string_column?(Account.columns_hash["active"])
+ assert Searchgasm::Condition::Base.string_column?(User.columns_hash["bio"])
end
def test_comparable_column
-
+ assert Searchgasm::Condition::Base.comparable_column?(Account.columns_hash["id"])
+ assert !Searchgasm::Condition::Base.comparable_column?(Account.columns_hash["name"])
+ assert !Searchgasm::Condition::Base.comparable_column?(Account.columns_hash["active"])
+ assert !Searchgasm::Condition::Base.comparable_column?(User.columns_hash["bio"])
+ assert Searchgasm::Condition::Base.comparable_column?(Order.columns_hash["total"])
end
def test_initialize
@@ -35,19 +48,29 @@ def test_initialize
assert_equal condition.column, Account.columns_hash["id"]
end
- def test_ignore_blanks?
- condition = Searchgasm::Condition::Equals.new(Account, Account.columns_hash["id"])
- assert !condition.class.ignore_blanks?
-
+ def test_explicitly_set_value
condition = Searchgasm::Condition::Keywords.new(Account, Account.columns_hash["name"])
- assert condition.class.ignore_blanks?
+ assert !condition.explicitly_set_value?
+ condition.value = "test"
+ assert condition.explicitly_set_value?
end
- def test_value
+ def test_name
+ condition = Searchgasm::Condition::Keywords.new(Account, Account.columns_hash["name"])
+ assert_equal "name_keywords", condition.name
+
+ condition = Searchgasm::Condition::DescendantOf.new(User)
+ assert_equal "descendant_of", condition.name
+ condition = Searchgasm::Condition::DescendantOf.new(Account)
+ assert_equal nil, condition.name
end
- def test_method_creation_in_scope
- # test ot make sure methods are not created across the board for all models
+ def test_sanitize
+ # This is tested thoroughly in test_condition_types
+ end
+
+ def test_value
+ # This is tested thoroughly in test_condition_types
end
end
diff --git a/test/test_condition_types.rb b/test/test_condition_types.rb
index 432faa31..09cb0d41 100644
--- a/test/test_condition_types.rb
+++ b/test/test_condition_types.rb
@@ -1,17 +1,6 @@
require File.dirname(__FILE__) + '/test_helper.rb'
class TestConditionTypes < Test::Unit::TestCase
- fixtures :accounts, :users, :orders
-
- def setup
- setup_db
- load_fixtures
- end
-
- def teardown
- teardown_db
- end
-
def test_sanitize
condition = Searchgasm::Condition::BeginsWith.new(Account, Account.columns_hash["name"])
condition.value = "Binary"
diff --git a/test/test_conditions_base.rb b/test/test_conditions_base.rb
index 7608a2be..e46e8d4d 100644
--- a/test/test_conditions_base.rb
+++ b/test/test_conditions_base.rb
@@ -1,39 +1,130 @@
require File.dirname(__FILE__) + '/test_helper.rb'
class TestConditionsBase < Test::Unit::TestCase
- fixtures :accounts, :users, :orders
-
- def setup
- setup_db
- load_fixtures
- end
-
- def teardown
- teardown_db
- end
-
def test_register_conditions
Searchgasm::Conditions::Base.register_condition(Searchgasm::Condition::Keywords)
assert [Searchgasm::Condition::Keywords], Searchgasm::Conditions::Base.conditions
Searchgasm::Conditions::Base.register_condition(Searchgasm::Condition::Contains)
assert [Searchgasm::Condition::Keywords, Searchgasm::Condition::Contains], Searchgasm::Conditions::Base.conditions
-
+ end
+
+ def test_association_names
+ assert_equal ["account", "parent", "orders", "user_groups", "children"], Searchgasm::Cache::UserConditions.association_names
+ assert_equal ["admin", "orders", "users"], Searchgasm::Cache::AccountConditions.association_names
+ end
+
+ def test_condition_names
+ # This is tested thoroughly through the tests
+ end
+
+ def test_needed
+ assert !Searchgasm::Conditions::Base.needed?(User, {})
+ assert !Searchgasm::Conditions::Base.needed?(User, {:first_name => "Ben"})
+ assert Searchgasm::Conditions::Base.needed?(User, {:first_name_contains => "Awesome"})
end
def test_initialize
- conditions = Account.new_conditions(:name_contains => "Binary")
+ conditions = Searchgasm::Cache::AccountConditions.new(:name_contains => "Binary")
assert_equal conditions.klass, Account
assert_equal conditions.name_contains, "Binary"
end
- def test_conditions_added
- # test to make sure all of the proper methods were add, testing condition_names basically
+ def test_any
+ conditions = Searchgasm::Cache::AccountConditions.new
+ assert !conditions.any?
+
+ conditions = Searchgasm::Cache::AccountConditions.new(:any => true)
+ assert conditions.any?
+ conditions.any = "false"
+ assert !conditions.any?
+
+ conditions = Searchgasm::Cache::AccountConditions.new
+ conditions.name_contains = "Binary"
+ assert_equal ["\"accounts\".\"name\" LIKE ?", "%Binary%"], conditions.sanitize
+ conditions.id = 1
+ assert_equal ["(\"accounts\".\"name\" LIKE ?) AND (\"accounts\".\"id\" = 1)", "%Binary%"], conditions.sanitize
+ conditions.any = true
+ assert_equal ["(\"accounts\".\"name\" LIKE ?) OR (\"accounts\".\"id\" = 1)", "%Binary%"], conditions.sanitize
+ conditions.any = false
+ assert_equal ["(\"accounts\".\"name\" LIKE ?) AND (\"accounts\".\"id\" = 1)", "%Binary%"], conditions.sanitize
+ end
+
+ def test_auto_joins
+ conditions = Searchgasm::Cache::AccountConditions.new
+ assert_equal conditions.auto_joins, nil
+
+ conditions.name_like = "Binary"
+ assert_equal conditions.auto_joins, nil
+
+ conditions.users.first_name_like = "Ben"
+ assert_equal conditions.auto_joins, :users
+
+ conditions.users.orders.description_like = "apple"
+ assert_equal conditions.auto_joins, {:users => :orders}
+ end
+
+ def test_inspect
+ conditions = Searchgasm::Cache::AccountConditions.new
+ assert_nothing_raised { conditions.inspect }
+ end
+
+ def test_sanitize
+ conditions = Searchgasm::Cache::AccountConditions.new
+ conditions.name_contains = "Binary"
+ conditions.id_gt = 5
+ now = Time.now
+ conditions.created_after = now
+ assert_equal conditions.sanitize, ["(\"accounts\".\"name\" LIKE ?) AND (\"accounts\".\"id\" > ?) AND (\"accounts\".\"created_at\" > ?)", "%Binary%", 5, now]
+
+ # test out associations
+ conditions.users.first_name_like = "Ben"
+ conditions.users.id_gt = 10
+ conditions.users.orders.total_lt = 500
+ assert_equal conditions.sanitize, ["(\"accounts\".\"name\" LIKE ?) AND (\"accounts\".\"id\" > ?) AND (\"accounts\".\"created_at\" > ?) AND ((\"users\".\"first_name\" LIKE ?) AND (\"users\".\"id\" > ?) AND (\"orders\".\"total\" < ?))", "%Binary%", 5, now, "%Ben%", 10, 500]
+
+ # test that raw sql is returned
+ conditions.conditions = "awesome"
+ assert_equal "awesome", conditions.sanitize
+ end
+
+ def test_conditions
+ conditions = Searchgasm::Cache::AccountConditions.new
+ now = Time.now
+ v = {:name_contains => "Binary", :created_at_greater_than => now}
+ conditions.conditions = v
+ assert_equal v, conditions.conditions
+
+ sql = "id in (1,2,3,4)"
+ conditions.conditions = sql
+ assert_equal sql, conditions.conditions
+ assert_equal [], conditions.send(:objects)
+
+ v2 = {:id_less_than => 5, :name_begins_with => "Beginning of string"}
+ conditions.conditions = v2
+ assert_equal v2, conditions.conditions
+
+ v = {:name_contains => "Binary", :created_at_greater_than => now}
+ conditions.conditions = v
+ assert_equal v2.merge(v), conditions.conditions
+
+ sql2 = "id > 5 and name = 'Test'"
+ conditions.conditions = sql2
+ assert_equal sql2, conditions.conditions
+ assert_equal [], conditions.send(:objects)
+
+ conditions.name_contains = "awesome"
+ assert_equal({:name_contains => "awesome"}, conditions.conditions)
+
+ conditions.conditions = {:id_gt => "", :name_starts_with => "Ben"}
+ assert_equal({:name_contains => "awesome", :name_begins_with => "Ben"}, conditions.conditions)
end
+ # Other general usage tests, need to clean these up
+
def test_setting_conditions
[Account, User, Order].each do |klass|
- conditions = klass.new_conditions
+ conditions = "Searchgasm::Cache::#{klass}Conditions".constantize.new
conditions.class.condition_names.each do |condition_name|
conditions.send("#{condition_name}=", 1)
assert_equal 1, conditions.send(condition_name)
@@ -43,13 +134,13 @@ def test_setting_conditions
def test_accessible_protected_conditions
Account.conditions_accessible << :name_contains
- conditions = Account.new_conditions
+ conditions = Searchgasm::Cache::AccountConditions.new
conditions.conditions = {:created_after => Time.now, :name_contains => "Binary"}
assert({:name_contains => "Binary"}, conditions.conditions)
Account.send(:write_inheritable_attribute, :conditions_accessible, nil)
Account.conditions_protected << :name_contains
- conditions = Account.new_conditions
+ conditions = Searchgasm::Cache::AccountConditions.new
now = Time.now
conditions.conditions = {:created_after => now, :name_contains => "Binary"}
assert({:created_after => now}, conditions.conditions)
@@ -57,36 +148,22 @@ def test_accessible_protected_conditions
end
def test_assert_valid_values
- conditions = User.new_conditions
+ conditions = Searchgasm::Cache::UserConditions.new
assert_raise(ArgumentError) { conditions.conditions = {:unknown => "blah"} }
assert_nothing_raised { conditions.conditions = {:first_name => "blah"} }
assert_nothing_raised { conditions.conditions = {:first_name_contains => "blah"} }
end
def test_setting_associations
- conditions = Account.new_conditions(:users => {:first_name_like => "Ben"})
+ conditions = Searchgasm::Cache::AccountConditions.new(:users => {:first_name_like => "Ben"})
assert_equal conditions.users.first_name_like, "Ben"
conditions.users.last_name_begins_with = "Ben"
assert_equal conditions.users.last_name_begins_with, "Ben"
end
- def test_joins
- conditions = Account.new_conditions
- assert_equal conditions.joins, nil
-
- conditions.name_like = "Binary"
- assert_equal conditions.joins, nil
-
- conditions.users.first_name_like = "Ben"
- assert_equal conditions.joins, :users
-
- conditions.users.orders.description_like = "apple"
- assert_equal conditions.joins, {:users => :orders}
- end
-
def test_objects
- conditions = Account.new_conditions
+ conditions = Searchgasm::Cache::AccountConditions.new
assert_equal conditions.send(:objects), []
conditions.name_contains = "Binary"
@@ -97,7 +174,7 @@ def test_objects
end
def test_reset
- conditions = Account.new_conditions
+ conditions = Searchgasm::Cache::AccountConditions.new
conditions.name_contains = "Binary"
assert_equal 1, conditions.send(:objects).size
@@ -121,88 +198,4 @@ def test_reset
conditions.reset_users!
assert_equal [], conditions.send(:objects)
end
-
- def test_sanitize
- conditions = Account.new_conditions
- conditions.name_contains = "Binary"
- conditions.id_gt = 5
- now = Time.now
- conditions.created_after = now
- assert_equal conditions.sanitize, ["(\"accounts\".\"name\" LIKE ?) AND (\"accounts\".\"id\" > ?) AND (\"accounts\".\"created_at\" > ?)", "%Binary%", 5, now]
-
- # test out associations
- conditions.users.first_name_like = "Ben"
- conditions.users.id_gt = 10
- conditions.users.orders.total_lt = 500
- assert_equal conditions.sanitize, ["(\"accounts\".\"name\" LIKE ?) AND (\"accounts\".\"id\" > ?) AND (\"accounts\".\"created_at\" > ?) AND ((\"users\".\"first_name\" LIKE ?) AND (\"users\".\"id\" > ?) AND (\"orders\".\"total\" < ?))", "%Binary%", 5, now, "%Ben%", 10, 500]
- end
-
- def test_conditions
- conditions = Account.new_conditions!
- now = Time.now
- v = {:name_contains => "Binary", :created_at_greater_than => now}
- conditions.conditions = v
- assert_equal v, conditions.conditions
-
- sql = "id in (1,2,3,4)"
- conditions.conditions = sql
- assert_equal sql, conditions.conditions
-
- v2 = {:id_less_than => 5, :name_begins_with => "Beginning of string"}
- conditions.conditions = v2
- assert_equal v2, conditions.conditions
-
- v = {:name_contains => "Binary", :created_at_greater_than => now}
- conditions.conditions = v
- assert_equal v2.merge(v), conditions.conditions
-
- sql2 = "id > 5 and name = 'Test'"
- conditions.conditions = sql2
- assert_equal sql2, conditions.conditions
-
- conditions.name_contains = "awesome"
- assert_equal({:name_contains => "awesome"}, conditions.conditions)
- end
-
- def test_searching
- conditions = Account.new_conditions
- conditions.name_contains = "Binary"
- assert_equal Account.find(1, 3), conditions.all
- assert_equal Account.find(1, 3), conditions.find(:all)
- assert_equal Account.find(1), conditions.first
- assert_equal Account.find(1), conditions.find(:first)
- assert_equal 2, conditions.average('id')
- assert_equal 2, conditions.calculate(:avg, 'id')
- assert_equal 3, conditions.calculate(:max, 'id')
- assert_equal 2, conditions.count
- assert_equal 3, conditions.maximum('id')
- assert_equal 1, conditions.minimum('id')
- assert_equal 4, conditions.sum('id')
- end
-
- def test_any
- conditions = Account.new_conditions
- conditions.name_contains = "Binary"
- assert_equal Account.find(1, 3), conditions.all
- conditions.id = 1
- assert_equal [Account.find(1)], conditions.all
- conditions.any = true
- assert_equal Account.find(1, 3), conditions.all
- conditions.any = false
- assert_equal [Account.find(1)], conditions.all
- end
-
- def test_ignoring_blanks
- conditions = Account.new_conditions(:name => "", :created_after => nil)
- assert_equal(nil, conditions.conditions)
- conditions.name = ""
- assert_equal({:name_equals => ""}, conditions.conditions)
- conditions.created_after = ""
- assert_equal({:name_equals => ""}, conditions.conditions)
- end
-
- def test_inspect
- conditions = Account.new_conditions
- assert_nothing_raised { conditions.inspect }
- end
end
diff --git a/test/test_conditions_protection.rb b/test/test_conditions_protection.rb
index 7ec620d9..94d0d3fb 100644
--- a/test/test_conditions_protection.rb
+++ b/test/test_conditions_protection.rb
@@ -1,27 +1,16 @@
require File.dirname(__FILE__) + '/test_helper.rb'
class TestConditionsProtection < Test::Unit::TestCase
- fixtures :accounts, :users, :orders
-
- def setup
- setup_db
- load_fixtures
- end
-
- def teardown
- teardown_db
- end
-
def test_protection
- assert_raise(ArgumentError) { Account.new_conditions("(DELETE FROM users)") }
- assert_nothing_raised { Account.build_conditions!("(DELETE FROM users)") }
+ assert_raise(ArgumentError) { Account.new_search(:conditions => "(DELETE FROM users)") }
+ assert_nothing_raised { Account.new_search!(:conditions => "(DELETE FROM users)") }
account = Account.first
- assert_raise(ArgumentError) { account.users.build_conditions("(DELETE FROM users)") }
- assert_nothing_raised { account.users.build_conditions!("(DELETE FROM users)") }
+ assert_raise(ArgumentError) { account.users.new_search(:conditions => "(DELETE FROM users)") }
+ assert_nothing_raised { account.users.new_search!(:conditions => "(DELETE FROM users)") }
- #search = Account.new_search
- #assert_nothing_raised { search.conditions = "(DELETE FROM users)" }
+ search = Account.new_search
+ assert_raise(ArgumentError) { search.conditions = "(DELETE FROM users)" }
end
end
diff --git a/test/test_config.rb b/test/test_config.rb
index 3da0a7d9..552b8610 100644
--- a/test/test_config.rb
+++ b/test/test_config.rb
@@ -1,17 +1,6 @@
require File.dirname(__FILE__) + '/test_helper.rb'
class TestConfig < Test::Unit::TestCase
- fixtures :accounts, :users, :orders
-
- def setup
- setup_db
- load_fixtures
- end
-
- def teardown
- teardown_db
- end
-
def test_per_page
Searchgasm::Config.per_page = 1
@@ -31,4 +20,6 @@ def test_per_page
assert User.new_search.all.size > 1
assert User.new_search(:per_page => 1).all.size == 1
end
+
+ # test that config options do not mess up regular AR searches
end
\ No newline at end of file
diff --git a/test/test_helper.rb b/test/test_helper.rb
index f7ae5695..536dc118 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -14,11 +14,15 @@ class Account < ActiveRecord::Base
has_many :orders, :through => :users
end
+class UserGroup < ActiveRecord::Base
+ has_and_belongs_to_many :users
+end
+
class User < ActiveRecord::Base
acts_as_tree
belongs_to :account
has_many :orders, :dependent => :destroy
- has_one :cool_order, :class_name => "Order", :conditions => {:total => 100}
+ has_and_belongs_to_many :user_groups
end
class Order < ActiveRecord::Base
@@ -26,11 +30,6 @@ class Order < ActiveRecord::Base
end
class Test::Unit::TestCase
- def self.fixtures(*fixtures)
- @fixtures ||= []
- @fixtures += [fixtures].flatten
- end
-
def setup_db
ActiveRecord::Schema.define(:version => 1) do
create_table :accounts do |t|
@@ -40,6 +39,17 @@ def setup_db
t.boolean :active
end
+ create_table :user_groups do |t|
+ t.datetime :created_at
+ t.datetime :updated_at
+ t.string :name
+ end
+
+ create_table :user_groups_users, :id => false do |t|
+ t.integer :user_group_id
+ t.integer :user_id
+ end
+
create_table :users do |t|
t.datetime :created_at
t.datetime :updated_at
@@ -63,7 +73,8 @@ def setup_db
end
def load_fixtures
- self.class.fixtures.each do |fixture|
+ fixtures = [:accounts, :orders, :users, :user_groups]
+ fixtures.each do |fixture|
records = YAML.load(File.read(File.dirname(__FILE__) + "/fixtures/#{fixture.to_s}.yml"))
records.each do |name, attributes|
record = fixture.to_s.singularize.classify.constantize.new
@@ -71,6 +82,17 @@ def load_fixtures
record.save!
end
end
+
+ # Not sure why I have to do this, but sick of dealing with it
+ UserGroup.all.each do |user_group|
+ user_ids = user_group.user_ids.uniq!
+ user_group.users.clear
+ user_group.user_ids = user_ids
+ user_group.save!
+ end
+
+ # Create the cached virtual classes
+ fixtures.each { |fixture| fixture.to_s.classify.constantize.new_search }
end
def teardown_db
@@ -78,4 +100,13 @@ def teardown_db
ActiveRecord::Base.connection.drop_table(table)
end
end
+
+ def setup
+ setup_db
+ load_fixtures
+ end
+
+ def teardown
+ teardown_db
+ end
end
\ No newline at end of file
diff --git a/test/test_search_base.rb b/test/test_search_base.rb
index e635cff5..0db83258 100644
--- a/test/test_search_base.rb
+++ b/test/test_search_base.rb
@@ -1,17 +1,6 @@
require File.dirname(__FILE__) + '/test_helper.rb'
class TestSearchBase < Test::Unit::TestCase
- fixtures :accounts, :users, :orders
-
- def setup
- setup_db
- load_fixtures
- end
-
- def teardown
- teardown_db
- end
-
def test_needed
assert Searchgasm::Search::Base.needed?(Account, :page => 2, :conditions => {:name => "Ben"})
assert !Searchgasm::Search::Base.needed?(Account, :conditions => {:name => "Ben"})
@@ -109,20 +98,20 @@ def test_setting_first_level_options
assert_equal search.lock, true
end
- def test_joins
+ def test_auto_joins
search = Account.new_search
- assert_equal nil, search.joins
+ assert_equal nil, search.auto_joins
search.conditions.name_contains = "Binary"
- assert_equal nil, search.joins
+ assert_equal nil, search.auto_joins
search.conditions.users.first_name_contains = "Ben"
- assert_equal(:users, search.joins)
+ assert_equal(:users, search.auto_joins)
search.conditions.users.orders.id_gt = 2
- assert_equal({:users => :orders}, search.joins)
+ assert_equal({:users => :orders}, search.auto_joins)
search.conditions.users.reset_orders!
- assert_equal(:users, search.joins)
+ assert_equal(:users, search.auto_joins)
search.conditions.users.orders.id_gt = 2
search.conditions.reset_users!
- assert_equal nil, search.joins
+ assert_equal nil, search.auto_joins
end
def test_limit
diff --git a/test/test_search_conditions.rb b/test/test_search_conditions.rb
index 2559c37d..03cd02a9 100644
--- a/test/test_search_conditions.rb
+++ b/test/test_search_conditions.rb
@@ -1,17 +1,6 @@
require File.dirname(__FILE__) + '/test_helper.rb'
class TestSearchConditions < Test::Unit::TestCase
- fixtures :accounts, :users, :orders
-
- def setup
- setup_db
- load_fixtures
- end
-
- def teardown
- teardown_db
- end
-
def test_conditions
search = Account.new_search
assert_kind_of Searchgasm::Conditions::Base, search.conditions
@@ -19,9 +8,32 @@ def test_conditions
search.conditions = {:name_like => "Binary"}
assert_kind_of Searchgasm::Conditions::Base, search.conditions
+
+ search = Account.new_search(:conditions => {:name_like => "Ben"})
+ assert_equal({:name_contains => "Ben"}, search.conditions.conditions)
+ end
+
+ def test_auto_joins
+ search = Account.new_search
+ search.conditions = {:name_like => "Binary"}
+ assert_equal nil, search.auto_joins
+ search.conditions.users.first_name_like = "Ben"
+ assert_equal :users, search.auto_joins
+ search.conditions.reset_users!
+ assert_equal nil, search.auto_joins
+ end
+
+ def test_joins
+ search = Account.new_search
+ search.conditions = {:id_lte => 2, :users => {:first_name_like => "Ben"}}
+ assert_equal :users, search.joins
+ assert_equal [Account.find(1)], search.all
+ search.conditions.any = true
+ assert_equal " LEFT OUTER JOIN \"users\" ON users.account_id = accounts.id ", search.joins
+ assert_equal Account.find(1, 2), search.all
+ end
- conditions = Account.new_conditions(:id_greater_than => 8)
- search.conditions = conditions
- assert_equal conditions, search.conditions
+ def test_sanitize
+ # This is tested in test_search_base
end
end
\ No newline at end of file
diff --git a/test/test_search_ordering.rb b/test/test_search_ordering.rb
index cd6e8280..a40536f9 100644
--- a/test/test_search_ordering.rb
+++ b/test/test_search_ordering.rb
@@ -1,17 +1,6 @@
require File.dirname(__FILE__) + '/test_helper.rb'
class TestSearchOrdering < Test::Unit::TestCase
- fixtures :accounts, :users, :orders
-
- def setup
- setup_db
- load_fixtures
- end
-
- def teardown
- teardown_db
- end
-
def test_order_as
search = Account.new_search
assert_equal nil, search.order
diff --git a/test/test_search_pagination.rb b/test/test_search_pagination.rb
index ce1cb5a0..54c9e757 100644
--- a/test/test_search_pagination.rb
+++ b/test/test_search_pagination.rb
@@ -1,17 +1,6 @@
require File.dirname(__FILE__) + '/test_helper.rb'
class TestSearchPagination < Test::Unit::TestCase
- fixtures :accounts, :users, :orders
-
- def setup
- setup_db
- load_fixtures
- end
-
- def teardown
- teardown_db
- end
-
def test_limit
search = Account.new_search
search.limit = 10
diff --git a/test/test_search_protection.rb b/test/test_search_protection.rb
index c256159e..921488c9 100644
--- a/test/test_search_protection.rb
+++ b/test/test_search_protection.rb
@@ -1,17 +1,6 @@
require File.dirname(__FILE__) + '/test_helper.rb'
class TestSearchProtection < Test::Unit::TestCase
- fixtures :accounts, :users, :orders
-
- def setup
- setup_db
- load_fixtures
- end
-
- def teardown
- teardown_db
- end
-
def test_protection
assert_raise(ArgumentError) { Account.build_search(:conditions => "(DELETE FROM users)", :page => 2, :per_page => 15) }
Searchgasm::Search::Base::VULNERABLE_FIND_OPTIONS.each { |option| assert_raise(ArgumentError) { Account.build_search(option => "(DELETE FROM users)") } }
diff --git a/test/text_config.rb b/test/text_config.rb
deleted file mode 100644
index 2cd6bc67..00000000
--- a/test/text_config.rb
+++ /dev/null
@@ -1 +0,0 @@
-# need to test that setting config doesn't mess up regular searches, only protected ones, etc
\ No newline at end of file