From b1acebaaf0823c093853ade5700bbf5117b4f31a Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Wed, 12 Mar 2008 23:31:18 -0700 Subject: - renamed scalar to value - added better test coverage and documentation of binary spec #to_sql --- TODO | 6 +- lib/active_relation/extensions/array.rb | 2 +- lib/active_relation/extensions/object.rb | 2 +- lib/active_relation/primitives.rb | 2 +- lib/active_relation/primitives/scalar.rb | 25 ------ lib/active_relation/primitives/value.rb | 25 ++++++ lib/active_relation/sql.rb | 14 ++-- .../active_relation/unit/predicates/binary_spec.rb | 96 +++++++++++++++++----- .../unit/predicates/relation_inclusion_spec.rb | 20 ----- spec/active_relation/unit/relations/join_spec.rb | 6 +- .../unit/relations/projection_spec.rb | 2 +- .../unit/relations/relation_spec.rb | 4 +- 12 files changed, 120 insertions(+), 84 deletions(-) delete mode 100644 lib/active_relation/primitives/scalar.rb create mode 100644 lib/active_relation/primitives/value.rb delete mode 100644 spec/active_relation/unit/predicates/relation_inclusion_spec.rb diff --git a/TODO b/TODO index f502b48a3d..fb656ef084 100644 --- a/TODO +++ b/TODO @@ -37,13 +37,13 @@ done: - get some basic aggregations working: users.project(user[:points].max) - Alias Table Names - When joining with any sort of aggregation, it needs to be a nested select -- get a scalar select working: users.project(users[:name], addresses.select(addresses[:user_id] == users[:id]).project(addresses[:id].count)) +- get a value select working: users.project(users[:name], addresses.select(addresses[:user_id] == users[:id]).project(addresses[:id].count)) - Session -- sublimate scalars to deal with the fact that they must be quoted per engine +- sublimate values to deal with the fact that they must be quoted per engine - clean-up singleton monstrosity - extract hashing module - hash custom matcher - make session engine stuff follow laws of demeter - currently doing some odd method chaining? rethink who is responsible for what - session just calls execute, passing in a connection; by default it gets a connection from the relation. -- #strategy is now on scalar, attribute and relation; you must admit it's name is confusing given that e.g., relation already has a strategy (Sql::Relation) ... should it be called predicate strategy? operand1.to_sql(operand2.predicate) maybe prefer operand1.cast(operand2) or project or in light of +- #strategy is now on value, attribute and relation; you must admit it's name is confusing given that e.g., relation already has a strategy (Sql::Relation) ... should it be called predicate strategy? operand1.to_sql(operand2.predicate) maybe prefer operand1.cast(operand2) or project or in light of - renamed to #format: operand1.format(operand2) diff --git a/lib/active_relation/extensions/array.rb b/lib/active_relation/extensions/array.rb index aa4354a78a..4bd20d8121 100644 --- a/lib/active_relation/extensions/array.rb +++ b/lib/active_relation/extensions/array.rb @@ -2,7 +2,7 @@ class Array def to_hash Hash[*flatten] end - + def to_sql(strategy = nil) "(#{collect(&:to_sql).join(', ')})" end diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index c1269ee37b..ab874150ed 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -8,7 +8,7 @@ class Object end def bind(relation) - ActiveRelation::Scalar.new(self, relation) + ActiveRelation::Value.new(self, relation) end def metaclass diff --git a/lib/active_relation/primitives.rb b/lib/active_relation/primitives.rb index 7629256034..9909734d24 100644 --- a/lib/active_relation/primitives.rb +++ b/lib/active_relation/primitives.rb @@ -1,4 +1,4 @@ require 'active_relation/primitives/attribute' -require 'active_relation/primitives/scalar' +require 'active_relation/primitives/value' require 'active_relation/primitives/expression' diff --git a/lib/active_relation/primitives/scalar.rb b/lib/active_relation/primitives/scalar.rb deleted file mode 100644 index d428541a50..0000000000 --- a/lib/active_relation/primitives/scalar.rb +++ /dev/null @@ -1,25 +0,0 @@ -module ActiveRelation - class Scalar - attr_reader :value, :relation - - def initialize(value, relation) - @value, @relation = value, relation - end - - def to_sql(strategy = Sql::Predicate.new(relation.engine)) - strategy.scalar value - end - - def format(object) - object.to_sql(Sql::Scalar.new(relation.engine)) - end - - def ==(other) - value == other.value - end - - def qualify - self - end - end -end \ No newline at end of file diff --git a/lib/active_relation/primitives/value.rb b/lib/active_relation/primitives/value.rb new file mode 100644 index 0000000000..ce9497cf34 --- /dev/null +++ b/lib/active_relation/primitives/value.rb @@ -0,0 +1,25 @@ +module ActiveRelation + class Value + attr_reader :value, :relation + + def initialize(value, relation) + @value, @relation = value, relation + end + + def to_sql(strategy = Sql::Predicate.new(relation.engine)) + strategy.value value + end + + def format(object) + object.to_sql(Sql::Value.new(relation.engine)) + end + + def ==(other) + value == other.value + end + + def qualify + self + end + end +end \ No newline at end of file diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index ff00223ce7..fb2177a55b 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -29,8 +29,8 @@ module ActiveRelation "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" end - def scalar(scalar, column = nil) - quote(scalar, column) + def value(value, column = nil) + quote(value, column) end def select(select_sql, aliaz) @@ -39,8 +39,8 @@ module ActiveRelation end class Selection < Formatter - def scalar(scalar) - scalar + def value(value) + value end end @@ -61,12 +61,12 @@ module ActiveRelation @attribute, @engine = attribute, attribute.engine end - def scalar(scalar) - quote(scalar, @attribute.column) + def value(value) + quote(value, @attribute.column) end end - class Scalar < Predicate + class Value < Predicate end end end \ No newline at end of file diff --git a/spec/active_relation/unit/predicates/binary_spec.rb b/spec/active_relation/unit/predicates/binary_spec.rb index d552d8b501..13b3f10a8c 100644 --- a/spec/active_relation/unit/predicates/binary_spec.rb +++ b/spec/active_relation/unit/predicates/binary_spec.rb @@ -3,17 +3,83 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Binary do before do - @relation1 = Table.new(:users) - @relation2 = Table.new(:photos) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:id] + @relation = Table.new(:users) + @attribute1 = @relation[:id] + @attribute2 = @relation[:name] + @value = "1-asdf".bind(@relation) class ConcreteBinary < Binary def predicate_sql "<=>" end end end - + + describe '#to_sql' do + describe 'when relating two attributes' do + it 'manufactures sql with a binary operation' do + ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(" + `users`.`id` <=> `users`.`name` + ") + end + end + + describe 'when relating an attribute and a value' do + describe 'when relating to an integer attribute' do + it 'formats values as integers' do + ConcreteBinary.new(@attribute1, @value).to_sql.should be_like(" + `users`.`id` <=> 1 + ") + end + end + + describe 'when relating to a string attribute' do + it 'formats values as strings' do + ConcreteBinary.new(@attribute2, @value).to_sql.should be_like(" + `users`.`name` <=> '1-asdf' + ") + end + end + end + + describe 'when relating two values' do + before do + @another_value = 2.bind(@relation) + end + + it 'quotes values appropriate to their type' do + ConcreteBinary.new(string = @value, integer = @another_value).to_sql.should be_like(" + '1-asdf' <=> 2 + ") + end + end + + describe 'when relating to an array' do + it 'manufactures sql with a list' do + pending + array = [1, 2, 3] + ConcreteBinary.new(@attribute1, array).to_sql.should be_like(" + `users`.`id` <=> (1,2,3) + ") + end + + it 'formats values in the array in the type of the attribute' do + pending + array = ['1-asdf', 2, 3] + ConcreteBinary.new(@attribute1, array).to_sql.should be_like(" + `users`.`id` <=> (1,2,3) + ") + end + end + + describe 'when relating to a relation' do + it 'manufactures sql with a subselect' do + ConcreteBinary.new(@attribute1, @relation).to_sql.should be_like(" + `users`.`id` <=> (SELECT `users`.`id`, `users`.`name` FROM `users`) + ") + end + end + end + describe '==' do it "obtains if attribute1 and attribute2 are identical" do Binary.new(@attribute1, @attribute2).should == Binary.new(@attribute1, @attribute2) @@ -41,23 +107,13 @@ module ActiveRelation end describe '#bind' do - it "distributes over the predicates and attributes" do - ConcreteBinary.new(@attribute1, @attribute2).bind(@relation2). \ - should == ConcreteBinary.new(@attribute1.bind(@relation2), @attribute2.bind(@relation2)) - end - end - - describe '#to_sql' do - it 'manufactures sql with a binary operation' do - ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(" - `users`.`id` <=> `photos`.`id` - ") + before do + @another_relation = Table.new(:photos) end - it 'appropriately quotes scalars' do - ConcreteBinary.new(@attribute1, "1-asdf".bind(@relation1)).to_sql.should be_like(" - `users`.`id` <=> 1 - ") + it "descends" do + ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ + should == ConcreteBinary.new(@attribute1.bind(@another_relation), @attribute2.bind(@another_relation)) end end end diff --git a/spec/active_relation/unit/predicates/relation_inclusion_spec.rb b/spec/active_relation/unit/predicates/relation_inclusion_spec.rb deleted file mode 100644 index af5846b747..0000000000 --- a/spec/active_relation/unit/predicates/relation_inclusion_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module ActiveRelation - describe RelationInclusion do - before do - users = Table.new(:users) - @relation = users.project(users[:id]) - @attribute = @relation[:id] - end - - describe RelationInclusion, '#to_sql' do - it "manufactures subselect sql" do - # remove when sufficient coverage of sql strategies exists - RelationInclusion.new(@attribute, @relation).to_sql.should be_like(" - `users`.`id` IN (SELECT `users`.`id` FROM `users`) - ") - end - end - end -end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index fdc4a4cdf2..fefe069d7b 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -103,10 +103,10 @@ module ActiveRelation describe 'with aggregated relations' do before do - @aggregation = @relation2 \ + @aggregation = @relation2 \ .aggregate(@relation2[:user_id], @relation2[:id].count) \ - .group(@relation2[:user_id]) \ - .rename(@relation2[:id].count, :cnt) \ + .group(@relation2[:user_id]) \ + .rename(@relation2[:id].count, :cnt) \ .as('photo_count') end diff --git a/spec/active_relation/unit/relations/projection_spec.rb b/spec/active_relation/unit/relations/projection_spec.rb index 9acfead8b8..78766d3308 100644 --- a/spec/active_relation/unit/relations/projection_spec.rb +++ b/spec/active_relation/unit/relations/projection_spec.rb @@ -52,7 +52,7 @@ module ActiveRelation ") end - it "manufactures sql with scalar selects" do + 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` ") diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index 5e434e52a6..b562ec2a2a 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -89,7 +89,7 @@ module ActiveRelation end it "accepts arbitrary strings" do - @relation.select("arbitrary").should == Selection.new(@relation, Scalar.new("arbitrary", @relation)) + @relation.select("arbitrary").should == Selection.new(@relation, Value.new("arbitrary", @relation)) end end @@ -145,7 +145,7 @@ module ActiveRelation describe '#update' do it 'manufactures an update relation' do Session.start do - assignments = {@relation[:name] => Scalar.new('bob', @relation)} + assignments = {@relation[:name] => Value.new('bob', @relation)} mock(Session.new).update(Update.new(@relation, assignments.bind(@relation))) @relation.update(assignments).should == @relation end -- cgit v1.2.3