Added the option for sanitizing find_by_sql and the offset parts in regular finds [Sam Stephenson]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@75 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
7a29764657
commit
a775cb1903
|
@ -1,5 +1,10 @@
|
|||
*CVS*
|
||||
|
||||
* Added the option for sanitizing find_by_sql and the offset parts in regular finds [Sam Stephenson]. Examples:
|
||||
|
||||
Project.find_all ["category = ?", category_name], "created ASC", ["? OFFSET ?", 15, 20]
|
||||
Post.find_by_sql ["SELECT * FROM posts WHERE author = ? AND created > ?", author_id, start_date]
|
||||
|
||||
* Fixed value quoting in all generated SQL statements, so that integers are not surrounded in quotes and that all sanitation are happening
|
||||
through the database's own quoting routine. This should hopefully make it lots easier for new adapters that doesn't accept '1' for integer
|
||||
columns.
|
||||
|
|
|
@ -274,21 +274,25 @@ module ActiveRecord #:nodoc:
|
|||
# Returns an array of all the objects that could be instantiated from the associated
|
||||
# table in the database. The +conditions+ can be used to narrow the selection of objects (WHERE-part),
|
||||
# such as by "color = 'red'", and arrangement of the selection can be done through +orderings+ (ORDER BY-part),
|
||||
# such as by "last_name, first_name DESC". A maximum of returned objects can be specified in +limit+. Example:
|
||||
# such as by "last_name, first_name DESC". A maximum of returned objects and their offset can be specified in
|
||||
# +limit+ (LIMIT...OFFSET-part). Examples:
|
||||
# Project.find_all "category = 'accounts'", "last_accessed DESC", 15
|
||||
# Project.find_all ["category = ?", category_name], "created ASC", ["? OFFSET ?", 15, 20]
|
||||
def find_all(conditions = nil, orderings = nil, limit = nil, joins = nil)
|
||||
sql = "SELECT * FROM #{table_name} "
|
||||
sql << "#{joins} " if joins
|
||||
add_conditions!(sql, conditions)
|
||||
sql << "ORDER BY #{orderings} " unless orderings.nil?
|
||||
sql << "LIMIT #{limit} " unless limit.nil?
|
||||
sql << "LIMIT #{sanitize_conditions(limit)} " unless limit.nil?
|
||||
|
||||
find_by_sql(sql)
|
||||
end
|
||||
|
||||
# Works like find_all, but requires a complete SQL string. Example:
|
||||
# Works like find_all, but requires a complete SQL string. Examples:
|
||||
# Post.find_by_sql "SELECT p.*, c.author FROM posts p, comments c WHERE p.id = c.post_id"
|
||||
# Post.find_by_sql ["SELECT * FROM posts WHERE author = ? AND created > ?", author_id, start_date]
|
||||
def find_by_sql(sql)
|
||||
sql = sanitize_conditions(sql)
|
||||
connection.select_all(sql, "#{name} Load").inject([]) { |objects, record| objects << instantiate(record) }
|
||||
end
|
||||
|
||||
|
@ -360,6 +364,7 @@ module ActiveRecord #:nodoc:
|
|||
# Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part.
|
||||
# Product.count "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
|
||||
def count_by_sql(sql)
|
||||
sql = sanitize_conditions(sql)
|
||||
count = connection.select_one(sql, "#{name} Count").values.first
|
||||
return count ? count.to_i : 0
|
||||
end
|
||||
|
@ -1073,4 +1078,4 @@ module ActiveRecord #:nodoc:
|
|||
string[0..3] == "--- "
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
require 'abstract_unit'
|
||||
require 'fixtures/company'
|
||||
require 'fixtures/topic'
|
||||
require 'fixtures/entrant'
|
||||
|
||||
class FinderTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@company_fixtures = create_fixtures("companies")
|
||||
@topic_fixtures = create_fixtures("topics")
|
||||
@entrant_fixtures = create_fixtures("entrants")
|
||||
end
|
||||
|
||||
def test_find
|
||||
|
@ -23,6 +25,20 @@ class FinderTest < Test::Unit::TestCase
|
|||
}
|
||||
end
|
||||
|
||||
def test_find_all_with_limit
|
||||
entrants = Entrant.find_all nil, "id ASC", 2
|
||||
|
||||
assert_equal(2, entrants.size)
|
||||
assert_equal(@entrant_fixtures["first"]["name"], entrants.first.name)
|
||||
end
|
||||
|
||||
def test_find_all_with_prepared_limit_and_offset
|
||||
entrants = Entrant.find_all nil, "id ASC", ["? OFFSET ?", 2, 1]
|
||||
|
||||
assert_equal(2, entrants.size)
|
||||
assert_equal(@entrant_fixtures["second"]["name"], entrants.first.name)
|
||||
end
|
||||
|
||||
def test_find_with_entire_select_statement
|
||||
topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
|
||||
|
||||
|
@ -30,6 +46,13 @@ class FinderTest < Test::Unit::TestCase
|
|||
assert_equal(@topic_fixtures["second"]["title"], topics.first.title)
|
||||
end
|
||||
|
||||
def test_find_with_prepared_select_statement
|
||||
topics = Topic.find_by_sql ["SELECT * FROM topics WHERE author_name = ?", "Mary"]
|
||||
|
||||
assert_equal(1, topics.size)
|
||||
assert_equal(@topic_fixtures["second"]["title"], topics.first.title)
|
||||
end
|
||||
|
||||
def test_find_first
|
||||
first = Topic.find_first "title = 'The First Topic'"
|
||||
assert_equal(@topic_fixtures["first"]["title"], first.title)
|
||||
|
@ -71,4 +94,16 @@ class FinderTest < Test::Unit::TestCase
|
|||
assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
|
||||
assert_equal "'something; select table'", ActiveRecord::Base.sanitize("something; select table")
|
||||
end
|
||||
end
|
||||
|
||||
def test_count
|
||||
assert_equal(0, Entrant.count("id > 3"))
|
||||
assert_equal(1, Entrant.count(["id > ?", 2]))
|
||||
assert_equal(2, Entrant.count(["id > ?", 1]))
|
||||
end
|
||||
|
||||
def test_count_by_sql
|
||||
assert_equal(0, Entrant.count_by_sql("SELECT COUNT(*) FROM entrants WHERE id > 3"))
|
||||
assert_equal(1, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 2]))
|
||||
assert_equal(2, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 1]))
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue