1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

qualified naming

This commit is contained in:
Nick Kallen 2008-01-05 15:24:46 -08:00
parent 346d9c6bde
commit d7b89d957d
26 changed files with 283 additions and 60 deletions

View file

@ -33,6 +33,7 @@ require 'sql_algebra/predicates/match_predicate'
require 'sql_algebra/extensions/range'
require 'sql_algebra/extensions/object'
require 'sql_algebra/extensions/array'
require 'sql_algebra/sql_builder/sql_builder'
require 'sql_algebra/sql_builder/select_builder'

View file

@ -0,0 +1,5 @@
class Array
def to_hash
Hash[*flatten]
end
end

View file

@ -3,12 +3,12 @@ class ActiveRecord::Base
object = cache.get(record % klass.primary_key) { Klass.instantiate(record % Klass.attributes) }
includes.each do |include|
case include
when Symbol
object.send(association = include).bring_forth(record)
when Hash
include.each do |association, nested_associations|
object.send(association).bring_forth(record, nested_associations)
end
when Symbol
object.send(association = include).bring_forth(record)
when Hash
include.each do |association, nested_associations|
object.send(association).bring_forth(record, nested_associations)
end
end
end
end

View file

@ -1,4 +1,8 @@
class Object
def qualify
self
end
def to_sql(builder = EqualsConditionBuilder.new)
me = self
builder.call do

View file

@ -10,6 +10,10 @@ class BinaryPredicate < Predicate
(attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2))
end
def qualify
self.class.new(attribute1.qualify, attribute2.qualify)
end
def to_sql(builder = ConditionsBuilder.new)
builder.call do
send(predicate_name) do

View file

@ -4,7 +4,7 @@ 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

View file

@ -1,45 +1,56 @@
class Attribute
attr_reader :relation, :attribute_name, :aliaz
attr_reader :relation, :name, :aliaz
def initialize(relation, attribute_name, aliaz = nil)
@relation, @attribute_name, @aliaz = relation, attribute_name, aliaz
def initialize(relation, name, aliaz = nil)
@relation, @name, @aliaz = relation, name, aliaz
end
def aliazz(aliaz)
Attribute.new(relation, attribute_name, aliaz)
Attribute.new(relation, name, aliaz)
end
def eql?(other)
relation == other.relation and attribute_name == other.attribute_name
def qualified_name
"#{relation.table}.#{name}"
end
def ==(other)
EqualityPredicate.new(self, other)
def qualify
aliazz(qualified_name)
end
module Predications
def eql?(other)
relation == other.relation and name == other.name and aliaz == other.aliaz
end
def <(other)
LessThanPredicate.new(self, other)
end
def ==(other)
EqualityPredicate.new(self, other)
end
def <=(other)
LessThanOrEqualToPredicate.new(self, other)
end
def <(other)
LessThanPredicate.new(self, other)
end
def >(other)
GreaterThanPredicate.new(self, other)
end
def <=(other)
LessThanOrEqualToPredicate.new(self, other)
end
def >=(other)
GreaterThanOrEqualToPredicate.new(self, other)
end
def >(other)
GreaterThanPredicate.new(self, other)
end
def =~(regexp)
MatchPredicate.new(self, regexp)
def >=(other)
GreaterThanOrEqualToPredicate.new(self, other)
end
def =~(regexp)
MatchPredicate.new(self, regexp)
end
end
include Predications
def to_sql(builder = SelectsBuilder.new)
builder.call do
column relation.table, attribute_name, aliaz
column relation.table, name, aliaz
end
end
end

View file

@ -16,7 +16,7 @@ class JoinRelation < Relation
end
def selects
relation1.selects + relation2.selects
relation1.send(:selects) + relation2.send(:selects)
end
def attributes

View file

@ -1,4 +1,4 @@
class OrderRelation < Relation
class OrderRelation < CompoundRelation
attr_reader :relation, :attributes
def initialize(relation, *attributes)
@ -9,6 +9,10 @@ class OrderRelation < Relation
relation == other.relation and attributes.eql?(other.attributes)
end
def qualify
OrderRelation.new(relation.qualify, *attributes.collect { |a| a.qualify })
end
def to_sql(builder = SelectBuilder.new)
relation.to_sql(builder).call do
attributes.each do |attribute|

View file

@ -9,6 +9,10 @@ class ProjectionRelation < Relation
relation == other.relation and attributes.eql?(other.attributes)
end
def qualify
ProjectionRelation.new(relation.qualify, *attributes.collect(&:qualify))
end
def to_sql(builder = SelectBuilder.new)
relation.to_sql(builder).call do
select do

View file

@ -34,7 +34,7 @@ class Relation
end
def rename(attribute, aliaz)
RenameRelation.new(self, attribute, aliaz)
RenameRelation.new(self, attribute => aliaz)
end
end
include Operations

View file

@ -0,0 +1,34 @@
class RenameRelation < CompoundRelation
attr_reader :relation, :schmattribute, :aliaz
def initialize(relation, renames)
@schmattribute, @aliaz = renames.shift
@relation = renames.empty?? relation : RenameRelation.new(relation, renames)
end
def ==(other)
relation == other.relation and schmattribute.eql?(other.schmattribute) and aliaz == other.aliaz
end
def attributes
relation.attributes.collect { |a| substitute(a) }
end
def qualify
RenameRelation.new(relation.qualify, schmattribute.qualify => aliaz)
end
protected
def attribute(name)
case
when name == aliaz then schmattribute.aliazz(aliaz)
when relation[name].eql?(schmattribute) then nil
else relation[name]
end
end
private
def substitute(a)
a.eql?(schmattribute) ? a.aliazz(aliaz) : a
end
end

View file

@ -10,6 +10,11 @@ class SelectionRelation < CompoundRelation
relation == other.relation and predicate == other.predicate
end
def qualify
SelectionRelation.new(relation.qualify, predicate.qualify)
end
protected
def selects
[predicate]
end

View file

@ -8,6 +8,10 @@ class TableRelation < Relation
def attributes
attributes_by_name.values
end
def qualify
RenameRelation.new self, qualifications
end
protected
def attribute(name)
@ -20,4 +24,8 @@ class TableRelation < Relation
attributes_by_name.merge(column.name => Attribute.new(self, column.name.to_sym))
end
end
def qualifications
attributes.zip(attributes.collect(&:qualified_name)).to_hash
end
end

View file

@ -33,4 +33,9 @@ describe 'Relational Algebra' do
users.id = 1
""")
end
it '' do
#
# @users.rename()
end
end

View file

@ -4,8 +4,8 @@ describe BinaryPredicate do
before do
@relation1 = TableRelation.new(:foo)
@relation2 = TableRelation.new(:bar)
@attribute1 = Attribute.new(@relation1, :attribute_name1)
@attribute2 = Attribute.new(@relation2, :attribute_name2)
@attribute1 = Attribute.new(@relation1, :name1)
@attribute2 = Attribute.new(@relation2, :name2)
class ConcreteBinaryPredicate < BinaryPredicate
def predicate_name
:equals
@ -31,12 +31,19 @@ describe BinaryPredicate do
end
end
describe '#qualify' do
it "manufactures an equality predicate with qualified attributes" do
ConcreteBinaryPredicate.new(@attribute1, @attribute2).qualify. \
should == ConcreteBinaryPredicate.new(@attribute1.qualify, @attribute2.qualify)
end
end
describe '#to_sql' do
it 'manufactures correct sql' do
ConcreteBinaryPredicate.new(@attribute1, @attribute2).to_sql.should == ConditionsBuilder.new do
equals do
column :foo, :attribute_name1
column :bar, :attribute_name2
column :foo, :name1
column :bar, :name2
end
end
end

View file

@ -4,11 +4,11 @@ describe EqualityPredicate 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, :name)
@attribute2 = Attribute.new(@relation2, :name)
end
describe EqualityPredicate, '==' do
describe '==' do
it "obtains if attribute1 and attribute2 are identical" do
EqualityPredicate.new(@attribute1, @attribute2).should == EqualityPredicate.new(@attribute1, @attribute2)
EqualityPredicate.new(@attribute1, @attribute2).should_not == EqualityPredicate.new(@attribute1, @attribute1)

View file

@ -6,24 +6,41 @@ describe Attribute do
@relation2 = TableRelation.new(:bar)
end
describe 'aliaz' do
describe '#aliazz' do
it "manufactures an aliased attributed" do
pending
end
it "should be renamed to #alias!" do
pending
@relation1.alias
end
end
describe '#qualified_name' do
it "manufactures an attribute name prefixed with the relation's name" do
@relation1[:id].qualified_name.should == 'foo.id'
end
end
describe '#qualify' do
it "manufactures an attribute aliased with that attributes qualified name" do
@relation1[:id].qualify == @relation1[:id].qualify
end
end
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))
Attribute.new(@relation1, :attribute_name).should_not be_eql(Attribute.new(@relation2, :attribute_name))
Attribute.new(@relation1, :name).should be_eql(Attribute.new(@relation1, :name))
Attribute.new(@relation1, :name).should_not be_eql(Attribute.new(@relation1, :another_name))
Attribute.new(@relation1, :name).should_not be_eql(Attribute.new(@relation2, :name))
end
end
describe 'predications' do
before do
@attribute1 = Attribute.new(@relation1, :attribute_name)
@attribute2 = Attribute.new(@relation2, :attribute_name)
@attribute1 = Attribute.new(@relation1, :name)
@attribute2 = Attribute.new(@relation2, :name)
end
describe '==' do
@ -63,11 +80,10 @@ describe Attribute do
end
end
describe '#to_sql' do
it "manufactures a column" do
Attribute.new(@relation1, :attribute_name, :alias).to_sql.should == SelectsBuilder.new do
column :foo, :attribute_name, :alias
Attribute.new(@relation1, :name, :alias).to_sql.should == SelectsBuilder.new do
column :foo, :name, :alias
end
end
end

View file

@ -16,6 +16,13 @@ describe OrderRelation do
end
end
describe '#qualify' do
it "manufactures an order relation with qualified attributes and qualified relation" do
OrderRelation.new(@relation1, @attribute1).qualify. \
should == OrderRelation.new(@relation1.qualify, @attribute1.qualify)
end
end
describe '#to_sql' do
it "manufactures sql with an order clause" do
OrderRelation.new(@relation1, @attribute1).to_sql.to_s.should == SelectBuilder.new do

View file

@ -16,6 +16,13 @@ describe ProjectionRelation do
end
end
describe '#qualify' do
it "manufactures a projection relation with qualified attributes and qualified relation" do
ProjectionRelation.new(@relation1, @attribute1).qualify. \
should == ProjectionRelation.new(@relation1.qualify, @attribute1.qualify)
end
end
describe '#to_sql' do
it "manufactures sql with a limited select clause" do
ProjectionRelation.new(@relation1, @attribute1).to_sql.to_s.should == SelectBuilder.new do

View file

@ -16,6 +16,12 @@ describe RangeRelation do
end
end
describe '#qualify' do
it "manufactures a range relation with a qualified relation and a qualified range" do
pending
end
end
describe '#to_sql' do
it "manufactures sql with limit and offset" do
range_size = @range2.last - @range2.first + 1

View file

@ -8,21 +8,21 @@ describe Relation do
@attribute2 = Attribute.new(@relation1, :name)
end
describe Relation, 'joins' do
describe Relation, '<=>' do
describe 'joins' do
describe '<=>' do
it "manufactures an inner join operation between those two relations" do
(@relation1 <=> @relation2).should == InnerJoinOperation.new(@relation1, @relation2)
end
end
describe Relation, '<<' do
describe '<<' do
it "manufactures a left outer join operation between those two relations" do
(@relation1 << @relation2).should == LeftOuterJoinOperation.new(@relation1, @relation2)
end
end
end
describe Relation, '[]' do
describe '[]' do
it "manufactures an attribute when given a symbol" do
@relation1[:id].should be_eql(Attribute.new(@relation1, :id))
end
@ -32,13 +32,13 @@ describe Relation do
end
end
describe Relation, '#include?' do
describe '#include?' do
it "manufactures an inclusion predicate" do
@relation1.include?(@attribute1).should == RelationInclusionPredicate.new(@attribute1, @relation1)
end
end
describe Relation, '#project' do
describe '#project' do
it "collapses identical projections" do
pending
end
@ -48,13 +48,13 @@ describe Relation do
end
end
describe Relation, '#rename' do
describe '#rename' do
it "manufactures a rename relation" do
@relation1.rename(@attribute1, :foo).should == RenameRelation.new(@relation1, @attribute1, :foo)
@relation1.rename(@attribute1, :foo).should == RenameRelation.new(@relation1, @attribute1 => :foo)
end
end
describe Relation, '#select' do
describe '#select' do
before do
@predicate = EqualityPredicate.new(@attribute1, @attribute2)
end
@ -64,7 +64,7 @@ describe Relation do
end
end
describe Relation, 'order' do
describe 'order' do
it "manufactures an order relation" do
@relation1.order(@attribute1, @attribute2).should == OrderRelation.new(@relation1, @attribute1, @attribute2)
end

View file

@ -0,0 +1,68 @@
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
describe RenameRelation do
before do
@relation = TableRelation.new(:foo)
@renamed_relation = RenameRelation.new(@relation, @relation[:id] => :schmid)
end
describe '#initialize' do
it "manufactures nested rename relations if multiple renames are provided" do
RenameRelation.new(@relation, @relation[:id] => :humpty, @relation[:name] => :dumpty). \
should == RenameRelation.new(RenameRelation.new(@relation, @relation[:id] => :humpty), @relation[:name] => :dumpty)
end
it "make this test less brittle wrt/ hash order" do
pending
end
it "raises an exception if the alias provided is already used" do
pending
end
end
describe '==' do
it "obtains if the relation, attribute, and alias are identical" do
pending
end
end
describe '#attributes' do
it "manufactures a list of attributes with the renamed attribute aliased" do
RenameRelation.new(@relation, @relation[:id] => :schmid).attributes.should ==
(@relation.attributes - [@relation[:id]]) + [@relation[:id].aliazz(:schmid)]
end
end
describe '[]' do
it 'indexes attributes by alias' do
@renamed_relation[:id].should be_nil
@renamed_relation[:schmid].should == @relation[:id]
end
end
describe '#schmattribute' do
it "should be renamed" do
pending
end
end
describe '#qualify' do
it "manufactures a rename relation with an identical attribute and alias, but with a qualified relation" do
RenameRelation.new(@relation, @relation[:id] => :schmid).qualify. \
should == RenameRelation.new(@relation.qualify, @relation[:id].qualify => :schmid)
end
end
describe '#to_sql' do
it 'manufactures sql aliasing the attribute' do
@renamed_relation.to_sql.to_s.should == SelectBuilder.new do
select do
column :foo, :name
column :foo, :id, :schmid
end
from :foo
end.to_s
end
end
end

View file

@ -26,6 +26,13 @@ describe SelectionRelation do
end
end
describe '#qualify' do
it "manufactures a selection relation with qualified predicates and qualified relation" do
SelectionRelation.new(@relation1, @predicate1).qualify. \
should == SelectionRelation.new(@relation1.qualify, @predicate1.qualify)
end
end
describe '#to_sql' do
it "manufactures sql with where clause conditions" do
SelectionRelation.new(@relation1, @predicate1).to_sql.to_s.should == SelectBuilder.new do

View file

@ -1,9 +1,13 @@
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
describe TableRelation do
before do
@relation = TableRelation.new(:users)
end
describe '#to_sql' do
it "returns a simple SELECT query" do
TableRelation.new(:users).to_sql.should == SelectBuilder.new do |s|
@relation.to_sql.should == SelectBuilder.new do |s|
select do
column :users, :name
column :users, :id
@ -18,4 +22,12 @@ describe TableRelation do
pending
end
end
describe '#qualify' do
it 'manufactures a rename relation with all attribute names qualified' do
@relation.qualify.should == RenameRelation.new(
RenameRelation.new(@relation, @relation[:id] => 'users.id'), @relation[:name] => 'users.name'
)
end
end
end

View file

@ -14,6 +14,14 @@ ActiveRecord::Base.configurations = {
}
ActiveRecord::Base.establish_connection 'sql_algebra_test'
class Hash
def shift
returning to_a.sort { |(key1, value1), (key2, value2)| key1.hash <=> key2.hash }.shift do |key, value|
delete(key)
end
end
end
Spec::Runner.configure do |config|
config.include(BeLikeMatcher)
end