aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/sql_algebra.rb3
-rw-r--r--lib/sql_algebra/predicates/binary_predicate.rb6
-rw-r--r--lib/sql_algebra/predicates/equality_predicate.rb5
-rw-r--r--lib/sql_algebra/relations/attribute.rb4
-rw-r--r--lib/sql_algebra/relations/join_relation.rb36
-rw-r--r--lib/sql_algebra/relations/selection_relation.rb8
-rw-r--r--lib/sql_algebra/relations/table_relation.rb4
-rw-r--r--spec/predicates/binary_predicate_spec.rb26
-rw-r--r--spec/relations/attribute_spec.rb23
-rw-r--r--spec/relations/join_operation_spec.rb6
-rw-r--r--spec/relations/join_relation_spec.rb35
-rw-r--r--spec/relations/selection_relation_spec.rb16
12 files changed, 142 insertions, 30 deletions
diff --git a/lib/sql_algebra.rb b/lib/sql_algebra.rb
index 8cd44386ad..e8955ae18b 100644
--- a/lib/sql_algebra.rb
+++ b/lib/sql_algebra.rb
@@ -37,3 +37,6 @@ require 'sql_algebra/sql_builder/join_builder'
require 'sql_algebra/sql_builder/inner_join_builder'
require 'sql_algebra/sql_builder/left_outer_join_builder'
require 'sql_algebra/sql_builder/equals_condition_builder'
+require 'sql_algebra/sql_builder/column_builder'
+require 'sql_algebra/sql_builder/conditions_builder'
+
diff --git a/lib/sql_algebra/predicates/binary_predicate.rb b/lib/sql_algebra/predicates/binary_predicate.rb
index d7f4cb20e7..3e5b9ce193 100644
--- a/lib/sql_algebra/predicates/binary_predicate.rb
+++ b/lib/sql_algebra/predicates/binary_predicate.rb
@@ -9,4 +9,10 @@ class BinaryPredicate < Predicate
super and
(attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2))
end
+
+ def to_sql(builder = ConditionsBuilder.new)
+ builder.call do
+ send(predicate_name, attribute1.to_sql(self), attribute2.to_sql(self))
+ end
+ end
end \ No newline at end of file
diff --git a/lib/sql_algebra/predicates/equality_predicate.rb b/lib/sql_algebra/predicates/equality_predicate.rb
index 2d206e6c12..2061d0f644 100644
--- a/lib/sql_algebra/predicates/equality_predicate.rb
+++ b/lib/sql_algebra/predicates/equality_predicate.rb
@@ -4,4 +4,9 @@ class EqualityPredicate < BinaryPredicate
((attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2)) or
(attribute1.eql?(other.attribute2) and attribute2.eql?(other.attribute1)))
end
+
+ protected
+ def predicate_name
+ :equals
+ end
end \ No newline at end of file
diff --git a/lib/sql_algebra/relations/attribute.rb b/lib/sql_algebra/relations/attribute.rb
index c0b8df3083..7a4a0d72c5 100644
--- a/lib/sql_algebra/relations/attribute.rb
+++ b/lib/sql_algebra/relations/attribute.rb
@@ -32,4 +32,8 @@ class Attribute
def =~(regexp)
MatchPredicate.new(self, regexp)
end
+
+ def to_sql(ignore_builder_because_i_can_only_exist_atomically)
+ ColumnBuilder.new(relation.table, attribute_name)
+ end
end \ No newline at end of file
diff --git a/lib/sql_algebra/relations/join_relation.rb b/lib/sql_algebra/relations/join_relation.rb
index 64db8e0e68..4052798d51 100644
--- a/lib/sql_algebra/relations/join_relation.rb
+++ b/lib/sql_algebra/relations/join_relation.rb
@@ -10,4 +10,40 @@ class JoinRelation < Relation
((relation1 == other.relation1 and relation2 == other.relation2) or
(relation2 == other.relation1 and relation1 == other.relation2))
end
+
+ def to_sql(builder = SelectBuilder.new)
+ enclosed_join_name, enclosed_predicates = join_name, predicates
+ relation2.to_sql(Adapter.new(relation1.to_sql(builder)) do
+ define_method :from do |table|
+ send(enclosed_join_name, table) do
+ enclosed_predicates.each do |predicate|
+ predicate.to_sql(self)
+ end
+ end
+ end
+ end)
+ end
+
+ class Adapter
+ instance_methods.each { |m| undef_method m unless m =~ /^__|^instance_eval/ }
+
+ def initialize(adaptee, &block)
+ @adaptee = adaptee
+ (class << self; self end).class_eval do
+ (adaptee.methods - instance_methods).each { |m| delegate m, :to => :@adaptee }
+ end
+ (class << self; self end).class_eval(&block)
+ end
+
+ def call(&block)
+ @caller = eval("self", block.binding)
+ returning self do |adapter|
+ instance_eval(&block)
+ end
+ end
+
+ def method_missing(method, *args, &block)
+ @caller.send(method, *args, &block)
+ end
+ end
end \ No newline at end of file
diff --git a/lib/sql_algebra/relations/selection_relation.rb b/lib/sql_algebra/relations/selection_relation.rb
index 5654d8de31..cce93917c4 100644
--- a/lib/sql_algebra/relations/selection_relation.rb
+++ b/lib/sql_algebra/relations/selection_relation.rb
@@ -9,4 +9,12 @@ class SelectionRelation < Relation
def ==(other)
relation == other.relation and predicate == other.predicate
end
+
+ def to_sql(builder = SelectBuilder.new)
+ relation.to_sql(builder).call do
+ where do
+ predicate.to_sql(self)
+ end
+ end
+ end
end \ No newline at end of file
diff --git a/lib/sql_algebra/relations/table_relation.rb b/lib/sql_algebra/relations/table_relation.rb
index 17cdbab61a..eee24e5d68 100644
--- a/lib/sql_algebra/relations/table_relation.rb
+++ b/lib/sql_algebra/relations/table_relation.rb
@@ -5,8 +5,8 @@ class TableRelation < Relation
@table = table
end
- def to_sql
- SelectBuilder.new do
+ def to_sql(builder = SelectBuilder.new)
+ builder.call do
select :*
from table
end
diff --git a/spec/predicates/binary_predicate_spec.rb b/spec/predicates/binary_predicate_spec.rb
index 58e395b08d..3d9a9b3b94 100644
--- a/spec/predicates/binary_predicate_spec.rb
+++ b/spec/predicates/binary_predicate_spec.rb
@@ -4,22 +4,22 @@ describe BinaryPredicate do
before do
@relation1 = TableRelation.new(:foo)
@relation2 = TableRelation.new(:bar)
- @attribute1 = Attribute.new(@relation1, :attribute_name)
- @attribute2 = Attribute.new(@relation2, :attribute_name)
+ @attribute1 = Attribute.new(@relation1, :attribute_name1)
+ @attribute2 = Attribute.new(@relation2, :attribute_name2)
+ class ConcreteBinaryPredicate < BinaryPredicate
+ def predicate_name
+ :equals
+ end
+ end
end
- describe BinaryPredicate, '#initialize' do
+ describe '#initialize' do
it "requires that both columns come from the same relation" do
pending
end
end
- describe BinaryPredicate, '==' do
- before do
- class ConcreteBinaryPredicate < BinaryPredicate
- end
- end
-
+ describe '==' do
it "obtains if attribute1 and attribute2 are identical" do
BinaryPredicate.new(@attribute1, @attribute2).should == BinaryPredicate.new(@attribute1, @attribute2)
BinaryPredicate.new(@attribute1, @attribute2).should_not == BinaryPredicate.new(@attribute1, @attribute1)
@@ -30,4 +30,12 @@ describe BinaryPredicate do
BinaryPredicate.new(@attribute1, @attribute2).should_not == ConcreteBinaryPredicate.new(@attribute1, @attribute2)
end
end
+
+ describe '#to_sql' do
+ it '' do
+ ConcreteBinaryPredicate.new(@attribute1, @attribute2).to_sql.should == ConditionsBuilder.new do
+ equals 'foo.attribute_name1', 'bar.attribute_name2'
+ end
+ end
+ end
end \ No newline at end of file
diff --git a/spec/relations/attribute_spec.rb b/spec/relations/attribute_spec.rb
index 5f2d70ec48..78d602abf9 100644
--- a/spec/relations/attribute_spec.rb
+++ b/spec/relations/attribute_spec.rb
@@ -6,7 +6,7 @@ describe Attribute do
@relation2 = TableRelation.new(:bar)
end
- describe Attribute, '#eql?' do
+ describe '#eql?' do
it "obtains if the relation and attribute name are identical" do
Attribute.new(@relation1, :attribute_name).should be_eql(Attribute.new(@relation1, :attribute_name))
Attribute.new(@relation1, :attribute_name).should_not be_eql(Attribute.new(@relation1, :another_attribute_name))
@@ -14,47 +14,52 @@ describe Attribute do
end
end
- describe Attribute, 'predications' do
+ describe 'predications' do
before do
@attribute1 = Attribute.new(@relation1, :attribute_name)
@attribute2 = Attribute.new(@relation2, :attribute_name)
end
- describe Attribute, '==' do
+ describe '==' do
it "manufactures an equality predicate" do
(@attribute1 == @attribute2).should == EqualityPredicate.new(@attribute1, @attribute2)
end
end
- describe Attribute, '<' do
+ describe '<' do
it "manufactures a less-than predicate" do
(@attribute1 < @attribute2).should == LessThanPredicate.new(@attribute1, @attribute2)
end
end
- describe Attribute, '<=' do
+ describe '<=' do
it "manufactures a less-than or equal-to predicate" do
(@attribute1 <= @attribute2).should == LessThanOrEqualToPredicate.new(@attribute1, @attribute2)
end
end
- describe Attribute, '>' do
+ describe '>' do
it "manufactures a greater-than predicate" do
(@attribute1 > @attribute2).should == GreaterThanPredicate.new(@attribute1, @attribute2)
end
end
- describe Attribute, '>=' do
+ describe '>=' do
it "manufactures a greater-than or equal to predicate" do
(@attribute1 >= @attribute2).should == GreaterThanOrEqualToPredicate.new(@attribute1, @attribute2)
end
end
- describe Attribute, '=~' do
+ describe '=~' do
it "manufactures a match predicate" do
(@attribute1 =~ /.*/).should == MatchPredicate.new(@attribute1, @attribute2)
end
end
-
+ end
+
+ describe '#to_sql' do
+ it "manufactures a column" do
+ Attribute.new(@relation1, :attribute_name).to_sql.should == ColumnBuilder.new(@relation1.table, :attribute_name)
+ end
end
end
diff --git a/spec/relations/join_operation_spec.rb b/spec/relations/join_operation_spec.rb
index d75d2d5c93..db30198f6e 100644
--- a/spec/relations/join_operation_spec.rb
+++ b/spec/relations/join_operation_spec.rb
@@ -1,12 +1,12 @@
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
-describe JoinOperation, 'between two relations' do
+describe 'between two relations' do
before do
@relation1 = TableRelation.new(:foo)
@relation2 = TableRelation.new(:bar)
end
- describe JoinOperation, '==' do
+ describe '==' do
it "obtains if the relations of both joins are identical" do
JoinOperation.new(@relation1, @relation2).should == JoinOperation.new(@relation1, @relation2)
JoinOperation.new(@relation1, @relation2).should_not == JoinOperation.new(@relation1, @relation1)
@@ -17,7 +17,7 @@ describe JoinOperation, 'between two relations' do
end
end
- describe JoinOperation, 'on' do
+ describe 'on' do
before do
@predicate = Predicate.new
@join_operation = JoinOperation.new(@relation1, @relation2)
diff --git a/spec/relations/join_relation_spec.rb b/spec/relations/join_relation_spec.rb
index 7309563cd5..c6fae90ff3 100644
--- a/spec/relations/join_relation_spec.rb
+++ b/spec/relations/join_relation_spec.rb
@@ -1,20 +1,45 @@
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
-describe JoinRelation, 'between two relations' do
+describe 'between two relations' do
before do
@relation1 = TableRelation.new(:foo)
@relation2 = TableRelation.new(:bar)
- @predicate = Predicate.new
+ @predicate = EqualityPredicate.new(@relation1[:a], @relation2[:b])
end
- describe JoinRelation, '==' do
- it "obtains if the two relations and the predicate are identical" do
+ describe '==' do
+ it 'obtains if the two relations and the predicate are identical' do
JoinRelation.new(@relation1, @relation2, @predicate).should == JoinRelation.new(@relation1, @relation2, @predicate)
JoinRelation.new(@relation1, @relation2, @predicate).should_not == JoinRelation.new(@relation1, @relation1, @predicate)
end
- it "is commutative on the relations" do
+ it 'is commutative on the relations' do
JoinRelation.new(@relation1, @relation2, @predicate).should == JoinRelation.new(@relation2, @relation1, @predicate)
end
end
+
+ describe '#to_sql' do
+ before do
+ @relation1 = @relation1.select(@relation1[:c] == @relation2[:d])
+ class ConcreteJoinRelation < JoinRelation
+ def join_name
+ :inner_join
+ end
+ end
+ end
+
+ it 'manufactures sql joining the two tables on the predicate, merging the selects' do
+ ConcreteJoinRelation.new(@relation1, @relation2, @predicate).to_sql.to_s.should == SelectBuilder.new do
+ select :*
+ from :foo do
+ inner_join :bar do
+ equals 'foo.a', 'bar.b'
+ end
+ end
+ where do
+ equals 'foo.c', 'bar.d'
+ end
+ end.to_s
+ end
+ end
end \ No newline at end of file
diff --git a/spec/relations/selection_relation_spec.rb b/spec/relations/selection_relation_spec.rb
index 0cfd55449c..1f8b760272 100644
--- a/spec/relations/selection_relation_spec.rb
+++ b/spec/relations/selection_relation_spec.rb
@@ -8,7 +8,7 @@ describe SelectionRelation do
@predicate2 = LessThanPredicate.new(@relation1[:age], 2)
end
- describe SelectionRelation, '==' do
+ describe '==' do
it "obtains if both the predicate and the relation are identical" do
SelectionRelation.new(@relation1, @predicate1). \
should == SelectionRelation.new(@relation1, @predicate1)
@@ -19,10 +19,22 @@ describe SelectionRelation do
end
end
- describe SelectionRelation, '#initialize' do
+ describe '#initialize' do
it "manufactures nested selection relations if multiple predicates are provided" do
SelectionRelation.new(@relation1, @predicate1, @predicate2). \
should == SelectionRelation.new(SelectionRelation.new(@relation1, @predicate2), @predicate1)
end
end
+
+ describe '#to_sql' do
+ it "manufactures sql with where clause conditions" do
+ SelectionRelation.new(@relation1, @predicate1).to_sql.should == SelectBuilder.new do
+ select :*
+ from :foo
+ where do
+ equals 'foo.id', 'bar.foo_id'
+ end
+ end
+ end
+ end
end \ No newline at end of file