1
0
Fork 0
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:
Nick Kallen 2008-03-16 17:49:06 -07:00
parent 2d3681bb3c
commit cae95fc02a
5 changed files with 61 additions and 22 deletions

17
CONVENTIONS Normal file
View 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
View file

@ -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

View file

@ -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? ),

View file

@ -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

View file

@ -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