mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Introduced concept of session. It does not yet support multiple databases, nor transactions, but it's a start!
This commit is contained in:
parent
f10d3be703
commit
51fdd769c0
13 changed files with 189 additions and 70 deletions
|
@ -11,4 +11,5 @@ require 'active_relation/relations/rename'
|
|||
require 'active_relation/relations/deletion'
|
||||
require 'active_relation/relations/insertion'
|
||||
require 'active_relation/relations/update'
|
||||
require 'active_relation/relations/alias'
|
||||
require 'active_relation/relations/alias'
|
||||
require 'active_relation/sessions/session'
|
|
@ -10,6 +10,11 @@ module ActiveRelation
|
|||
"FROM #{table_sql}",
|
||||
("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?)
|
||||
].compact.join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
self.class == other.class and
|
||||
relation == other.relation
|
||||
end
|
||||
end
|
||||
end
|
|
@ -11,13 +11,14 @@ module ActiveRelation
|
|||
"INSERT",
|
||||
"INTO #{table_sql}",
|
||||
"(#{record.keys.collect(&:to_sql).join(', ')})",
|
||||
"VALUES #{inserts.collect(&:to_sql).join(', ')}"
|
||||
"VALUES #{record.to_sql}"
|
||||
].join("\n")
|
||||
end
|
||||
|
||||
protected
|
||||
def inserts
|
||||
relation.inserts + [record]
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
self.class == other.class and
|
||||
relation == other.relation and
|
||||
record == other.record
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,18 +2,22 @@ module ActiveRelation
|
|||
class Relation
|
||||
include Sql::Quoting
|
||||
|
||||
module Iteration
|
||||
include Enumerable
|
||||
|
||||
def session
|
||||
Session.instance
|
||||
end
|
||||
|
||||
module Enumerable
|
||||
include ::Enumerable
|
||||
|
||||
def each(&block)
|
||||
connection.select_all(to_s).each(&block)
|
||||
session.read(self).each(&block)
|
||||
end
|
||||
|
||||
|
||||
def first
|
||||
connection.select_one(to_s)
|
||||
session.read(self).first
|
||||
end
|
||||
end
|
||||
include Iteration
|
||||
include Enumerable
|
||||
|
||||
module Operations
|
||||
def join(other)
|
||||
|
@ -58,18 +62,25 @@ module ActiveRelation
|
|||
def rename(attribute, aliaz)
|
||||
Rename.new(self, attribute => aliaz)
|
||||
end
|
||||
|
||||
def insert(record)
|
||||
Insertion.new(self, record)
|
||||
end
|
||||
|
||||
def delete
|
||||
Deletion.new(self)
|
||||
end
|
||||
|
||||
|
||||
def aggregate(*expressions)
|
||||
AggregateOperation.new(self, expressions)
|
||||
end
|
||||
|
||||
module Writes
|
||||
def insert(record)
|
||||
session.create Insertion.new(self, record); self
|
||||
end
|
||||
|
||||
def update(assignments)
|
||||
session.update Update.new(self, assignments); self
|
||||
end
|
||||
|
||||
def delete
|
||||
session.delete Deletion.new(self); self
|
||||
end
|
||||
end
|
||||
include Writes
|
||||
|
||||
JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do
|
||||
def on(*predicates)
|
||||
|
@ -84,7 +95,7 @@ module ActiveRelation
|
|||
end
|
||||
end
|
||||
include Operations
|
||||
|
||||
|
||||
def aggregation?
|
||||
false
|
||||
end
|
||||
|
|
|
@ -12,6 +12,12 @@ module ActiveRelation
|
|||
assignments.inject([]) { |assignments, (attribute, value)| assignments << "#{attribute.to_sql} = #{value.to_sql}" }.join(" "),
|
||||
("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?)
|
||||
].join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
self.class == other.class and
|
||||
relation == other.relation and
|
||||
assignments == other.assignments
|
||||
end
|
||||
end
|
||||
end
|
38
lib/active_relation/sessions/session.rb
Normal file
38
lib/active_relation/sessions/session.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
require 'singleton'
|
||||
|
||||
module ActiveRelation
|
||||
class Session
|
||||
include Singleton
|
||||
|
||||
module CRUD
|
||||
def connection
|
||||
ActiveRecord::Base.connection
|
||||
end
|
||||
|
||||
def create(insert)
|
||||
connection.insert(insert.to_sql)
|
||||
end
|
||||
|
||||
def read(select)
|
||||
connection.select_all(select.to_sql)
|
||||
end
|
||||
|
||||
def update(update)
|
||||
connection.update(update.to_sql)
|
||||
end
|
||||
|
||||
def delete(delete)
|
||||
connection.delete(delete.to_sql)
|
||||
end
|
||||
end
|
||||
include CRUD
|
||||
|
||||
module Transactions
|
||||
end
|
||||
include Transactions
|
||||
|
||||
module UnitOfWork
|
||||
end
|
||||
include UnitOfWork
|
||||
end
|
||||
end
|
|
@ -2,7 +2,7 @@ module ActiveRelation
|
|||
module Sql
|
||||
module Quoting
|
||||
def connection
|
||||
ActiveRecord::Base.connection
|
||||
Session.instance.connection
|
||||
end
|
||||
|
||||
delegate :quote_table_name, :quote_column_name, :quote, :to => :connection
|
||||
|
|
|
@ -136,24 +136,6 @@ describe 'ActiveRelation', 'A proposed refactoring to ActiveRecord, introducing
|
|||
""")
|
||||
end
|
||||
|
||||
describe 'write operations' do
|
||||
it 'generates the query for user.destroy' do
|
||||
@user.delete.to_sql.should be_like("""
|
||||
DELETE
|
||||
FROM `users`
|
||||
WHERE `users`.`id` = 1
|
||||
""")
|
||||
end
|
||||
|
||||
it 'generates an efficient query for two User.creates -- UnitOfWork is within reach!' do
|
||||
@users.insert(@users[:name] => "humpty").insert(@users[:name] => "dumpty").to_sql.should be_like("""
|
||||
INSERT
|
||||
INTO `users`
|
||||
(`users`.`name`) VALUES ('humpty'), ('dumpty')
|
||||
""")
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with_scope' do
|
||||
it 'obviates the need for with_scope merging logic since, e.g.,
|
||||
`with_scope :conditions => ...` is just a #select operation on the relation' do
|
||||
|
|
|
@ -14,15 +14,6 @@ module ActiveRelation
|
|||
(`users`.`name`) VALUES ('nick')
|
||||
""")
|
||||
end
|
||||
|
||||
it 'manufactures sql inserting the data for multiple items' do
|
||||
nested_insertion = Insertion.new(@relation, @relation[:name] => "cobra")
|
||||
Insertion.new(nested_insertion, nested_insertion[:name] => "commander").to_sql.should be_like("""
|
||||
INSERT
|
||||
INTO `users`
|
||||
(`users`.`name`) VALUES ('cobra'), ('commander')
|
||||
""")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -36,13 +36,13 @@ module ActiveRelation
|
|||
end
|
||||
end
|
||||
|
||||
describe '#Expression?' do
|
||||
describe '#aggregation?' do
|
||||
it "returns false" do
|
||||
@relation.should_not be_aggregation
|
||||
end
|
||||
end
|
||||
|
||||
describe 'read operations' do
|
||||
describe Relation::Operations do
|
||||
describe 'joins' do
|
||||
before do
|
||||
@predicate = @relation[:id].equals(@relation[:id])
|
||||
|
@ -105,19 +105,34 @@ module ActiveRelation
|
|||
should == Aggregation.new(@relation, :expressions => [@expresion, @expression2], :groupings => [@attribute1, @attribute2])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'write operations' do
|
||||
describe '#delete' do
|
||||
it 'manufactures a deletion relation' do
|
||||
@relation.delete.should be_kind_of(Deletion)
|
||||
|
||||
describe Relation::Operations::Writes do
|
||||
describe '#delete' do
|
||||
it 'manufactures a deletion relation' do
|
||||
mock(Session.instance).delete(Deletion.new(@relation))
|
||||
@relation.delete.should == @relation
|
||||
end
|
||||
end
|
||||
|
||||
describe '#insert' do
|
||||
it 'manufactures an insertion relation' do
|
||||
mock(Session.instance).create(Insertion.new(@relation, record = {@relation[:name] => 'carl'}))
|
||||
@relation.insert(record).should == @relation
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update' do
|
||||
it 'manufactures an update relation' do
|
||||
mock(Session.instance).update(Update.new(@relation, assignments = {@relation[:name] => 'bob'}))
|
||||
@relation.update(assignments).should == @relation
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#insert' do
|
||||
it 'manufactures an insertion relation' do
|
||||
@relation.insert(record = {:id => 1}).should be_kind_of(Insertion)
|
||||
end
|
||||
end
|
||||
|
||||
describe Relation::Enumerable do
|
||||
it "is enumerable" do
|
||||
pending
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,7 +21,6 @@ module ActiveRelation
|
|||
WHERE `users`.`id` = 1
|
||||
""")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
70
spec/active_relation/unit/session/session_spec.rb
Normal file
70
spec/active_relation/unit/session/session_spec.rb
Normal file
|
@ -0,0 +1,70 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper')
|
||||
|
||||
module ActiveRelation
|
||||
describe Session do
|
||||
before do
|
||||
@relation = Table.new(:users)
|
||||
@session = Session.instance
|
||||
end
|
||||
|
||||
describe Singleton do
|
||||
it "is a singleton" do
|
||||
Session.instance.should be_equal(Session.instance)
|
||||
lambda { Session.new }.should raise_error
|
||||
end
|
||||
end
|
||||
|
||||
describe Session::CRUD do
|
||||
before do
|
||||
@insert = Insertion.new(@relation, @relation[:name] => 'nick')
|
||||
@update = Update.new(@relation, @relation[:name] => 'nick')
|
||||
@delete = Deletion.new(@relation)
|
||||
@select = @relation
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
it "should execute an insertion on the connection" do
|
||||
mock(@session.connection).insert(@insert.to_sql)
|
||||
@session.create(@insert)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#read' do
|
||||
it "should execute an selection on the connection" do
|
||||
mock(@session.connection).select_all(@select.to_sql)
|
||||
@session.read(@select)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update' do
|
||||
it "should execute an update on the connection" do
|
||||
mock(@session.connection).update(@update.to_sql)
|
||||
@session.update(@update)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#delete' do
|
||||
it "should execute a delete on the connection" do
|
||||
mock(@session.connection).delete(@delete.to_sql)
|
||||
@session.delete(@delete)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Session::Transactions do
|
||||
describe '#begin' do
|
||||
end
|
||||
|
||||
describe '#end' do
|
||||
end
|
||||
end
|
||||
|
||||
describe Session::UnitOfWork do
|
||||
describe '#flush' do
|
||||
end
|
||||
|
||||
describe '#clear' do
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -7,7 +7,7 @@ Dir["#{dir}/matchers/*"].each { |m| require "#{dir}/matchers/#{File.basename(m)}
|
|||
require 'active_relation'
|
||||
|
||||
ActiveRecord::Base.configurations = {
|
||||
'sql_algebra_test' => {
|
||||
'test' => {
|
||||
:adapter => 'mysql',
|
||||
:username => 'root',
|
||||
:password => 'password',
|
||||
|
@ -15,7 +15,7 @@ ActiveRecord::Base.configurations = {
|
|||
:database => 'sql_algebra_test',
|
||||
},
|
||||
}
|
||||
ActiveRecord::Base.establish_connection 'sql_algebra_test'
|
||||
ActiveRecord::Base.establish_connection 'test'
|
||||
|
||||
class Hash
|
||||
def shift
|
||||
|
|
Loading…
Reference in a new issue