mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
projections now support string passthrough
- there is a weird inconsistency in where bind is called on values; this needs to be resolved
This commit is contained in:
parent
2d3681bb3c
commit
cae95fc02a
5 changed files with 61 additions and 22 deletions
17
CONVENTIONS
Normal file
17
CONVENTIONS
Normal file
|
@ -0,0 +1,17 @@
|
|||
This file should ultimately be replaced by a series of tests, something like a lint tool.
|
||||
|
||||
- all describes and its should use single quotes unless they have nested quotes.
|
||||
- object instantiation in tests for all objects that are not the SUT should be manufactured in a before
|
||||
- 'should' and other counterfactuals/subjunctive forms should not be used in tests
|
||||
- no doubles should be used except for behaviorist testing
|
||||
- behaviorist testing is desirable only when interacting with the database or the session
|
||||
- when unit testing, always demonstrate behavior by using a real world example (as in, a public use of the API), so as to provide documentation.
|
||||
- use collect rather than map
|
||||
- jargon:
|
||||
- 'obtains' is preferred to 'returns true'
|
||||
- 'manufactures'
|
||||
- in tests
|
||||
- when manufacturing expected values (right-hand-side of should), avoid convenience methods -- construct it by initializing the object directly (Foo.new(...)). This ensures equality expectations in tests is rigorous.
|
||||
- the SUT should be manufactured inline inside the test, not in a before
|
||||
- dependencies for the SUT should be manufactured using convenience methods (or whatever is most terse).
|
||||
- group conceptually related methods in a class within an inline module; immediately include that module.
|
18
TODO
18
TODO
|
@ -1,34 +1,26 @@
|
|||
todo:
|
||||
- string passthrough:
|
||||
:joins=>"INNER JOIN posts ON comments.post_id = posts.id"
|
||||
:conditions=>"(`posts`.author_id = 1)",
|
||||
:select=>"`comments`.*"
|
||||
:conditions=>"1 = 1"
|
||||
|
||||
- need adapters for this form:
|
||||
{:conditions=>["approved = ?", false]}
|
||||
{:conditions=>{:approved=>false}}
|
||||
{:conditions=>{"topics.approved"=>false}}
|
||||
{:conditions=>{:address=>#<Address:0x3489b3c @street="Funny Street", @country="Loony Land", @city="Scary Town">, "customers.name"=>"David1"}}
|
||||
|
||||
- orders need string pass through
|
||||
:order=>"developers.name desc, developers.id desc",
|
||||
|
||||
- orders need to be composable
|
||||
- re-evaluate bind -- does bind belong inside the relation / predicate classes or in the factory methods?
|
||||
- #bind in Attribute and Expression should be doing a descend?
|
||||
- try to make aggration testing in join spec to be a bit more unit-like
|
||||
- finish pending tests
|
||||
- test relation, table reset
|
||||
- cache expiry on write
|
||||
- rewrite of querycache test in light of this
|
||||
- relation inclusion when given an array (1,2,3,4) should quote the elements using the appropriate quoting formatter taken from the attribute
|
||||
- descend on array, along with bind written in terms of it
|
||||
- standardize quoting
|
||||
- use strings everywhere, not symbols ?
|
||||
- "unit" test sql strategies
|
||||
- use real world examples, so they should be like a tutorial.
|
||||
- rename the tion (Selection) classes so that words that don't end in tion don't seem inconsistent
|
||||
- re-evaluate bind
|
||||
- mock out database
|
||||
|
||||
done:
|
||||
|
@ -67,4 +59,10 @@ done:
|
|||
- renamed to #format: operand1.format(operand2)
|
||||
- rename sql strategies
|
||||
- need to_sql for ranges
|
||||
- {:conditions=>{:id=>2..3}}
|
||||
- {:conditions=>{:id=>2..3}}
|
||||
- nested orderings
|
||||
- string passthrough
|
||||
- conditions
|
||||
- orderings
|
||||
- relation inclusion when given an array (1,2,3,4) should quote the elements using the appropriate quoting formatter taken from the attribute
|
||||
- descend on array, along with bind written in terms of it
|
||||
|
|
|
@ -42,7 +42,7 @@ module ActiveRelation
|
|||
end
|
||||
|
||||
def project(*attributes)
|
||||
Projection.new(self, *attributes.collect {|a| a.bind(self)})
|
||||
Projection.new(self, *attributes)
|
||||
end
|
||||
|
||||
def as(aliaz)
|
||||
|
@ -103,7 +103,7 @@ module ActiveRelation
|
|||
|
||||
def to_sql(formatter = Sql::SelectStatement.new(engine))
|
||||
formatter.select [
|
||||
"SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectExpression.new(engine)) }.join(', ')}",
|
||||
"SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(engine)) }.join(', ')}",
|
||||
"FROM #{table_sql}",
|
||||
(joins unless joins.blank? ),
|
||||
("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(engine)) }.join("\n\tAND ")}" unless selects.blank? ),
|
||||
|
|
|
@ -14,7 +14,7 @@ module ActiveRelation
|
|||
end
|
||||
end
|
||||
|
||||
class SelectExpression < Formatter
|
||||
class SelectClause < Formatter
|
||||
def attribute(relation_name, attribute_name, aliaz)
|
||||
"#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" + (aliaz ? " AS #{quote(aliaz.to_s)}" : "")
|
||||
end
|
||||
|
@ -22,6 +22,10 @@ module ActiveRelation
|
|||
def select(select_sql, aliaz)
|
||||
"(#{select_sql})" + (aliaz ? " AS #{quote(aliaz)}" : "")
|
||||
end
|
||||
|
||||
def value(value)
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
class PassThrough < Formatter
|
||||
|
|
|
@ -45,17 +45,37 @@ module ActiveRelation
|
|||
end
|
||||
|
||||
describe '#to_sql' do
|
||||
it "manufactures sql with a limited select clause" do
|
||||
Projection.new(@relation, @attribute).to_sql.should be_like("
|
||||
SELECT `users`.`id`
|
||||
FROM `users`
|
||||
")
|
||||
describe 'when given an attribute' do
|
||||
it "manufactures sql with a limited select clause" do
|
||||
Projection.new(@relation, @attribute).to_sql.should be_like("
|
||||
SELECT `users`.`id`
|
||||
FROM `users`
|
||||
")
|
||||
end
|
||||
end
|
||||
|
||||
it "manufactures sql with value selects" do
|
||||
Projection.new(@relation, Projection.new(@relation, @relation[:name])).to_sql.should be_like("
|
||||
SELECT (SELECT `users`.`name` FROM `users`) FROM `users`
|
||||
")
|
||||
describe 'when given a relation' do
|
||||
before do
|
||||
@scalar_relation = Projection.new(@relation, @relation[:name])
|
||||
end
|
||||
|
||||
it "manufactures sql with scalar selects" do
|
||||
Projection.new(@relation, @scalar_relation).to_sql.should be_like("
|
||||
SELECT (SELECT `users`.`name` FROM `users`) FROM `users`
|
||||
")
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when given a string' do
|
||||
before do
|
||||
@string = "asdf"
|
||||
end
|
||||
|
||||
it "passes the string through to the select clause" do
|
||||
Projection.new(@relation, @string).to_sql.should be_like("
|
||||
SELECT asdf FROM `users`
|
||||
")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue