mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
new conception of grouping and aggregation functionality
This commit is contained in:
parent
4466409205
commit
04c8e48311
11 changed files with 95 additions and 53 deletions
|
@ -10,6 +10,10 @@ module ActiveRelation
|
|||
def alias_or_name
|
||||
@alias || name
|
||||
end
|
||||
|
||||
def aggregation?
|
||||
false
|
||||
end
|
||||
|
||||
module Transformations
|
||||
def as(aliaz = nil)
|
||||
|
@ -56,10 +60,8 @@ module ActiveRelation
|
|||
end
|
||||
|
||||
def %(other)
|
||||
if other
|
||||
(history - other.history) + (other.history - history)
|
||||
else
|
||||
history
|
||||
if other then (history - other.history) + (other.history - history)
|
||||
else history
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -29,6 +29,10 @@ module ActiveRelation
|
|||
"#{function_sql}(#{attribute.to_sql})" + (@alias ? " AS #{quote_column_name(@alias)}" : '')
|
||||
end
|
||||
|
||||
def aggregation?
|
||||
true
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
self.class == other.class and
|
||||
attribute == other.attribute and
|
||||
|
|
|
@ -4,7 +4,7 @@ require 'active_relation/relations/compound'
|
|||
require 'active_relation/relations/writing'
|
||||
require 'active_relation/relations/table'
|
||||
require 'active_relation/relations/join'
|
||||
require 'active_relation/relations/aggregation'
|
||||
require 'active_relation/relations/grouping'
|
||||
require 'active_relation/relations/projection'
|
||||
require 'active_relation/relations/selection'
|
||||
require 'active_relation/relations/order'
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
module ActiveRelation
|
||||
class Aggregation < Compound
|
||||
attr_reader :expressions, :groupings
|
||||
|
||||
def initialize(relation, options)
|
||||
@relation, @expressions, @groupings = relation, options[:expressions], options[:groupings]
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
self.class == other.class and
|
||||
relation == other.relation and
|
||||
groupings == other.groupings and
|
||||
expressions == other.expressions
|
||||
end
|
||||
|
||||
def attributes
|
||||
expressions.collect { |e| e.bind(self) }
|
||||
end
|
||||
|
||||
def aggregation?
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
19
lib/active_relation/relations/grouping.rb
Normal file
19
lib/active_relation/relations/grouping.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
module ActiveRelation
|
||||
class Grouping < Compound
|
||||
attr_reader :expressions, :groupings
|
||||
|
||||
def initialize(relation, *groupings)
|
||||
@relation, @groupings = relation, groupings.collect { |g| g.bind(relation) }
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
self.class == other.class and
|
||||
relation == other.relation and
|
||||
groupings == other.groupings
|
||||
end
|
||||
|
||||
def aggregation?
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
|
@ -15,5 +15,9 @@ module ActiveRelation
|
|||
relation == other.relation and
|
||||
projections == other.projections
|
||||
end
|
||||
|
||||
def aggregation?
|
||||
attributes.any?(&:aggregation?)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -66,8 +66,8 @@ module ActiveRelation
|
|||
skipped.blank?? self : Skip.new(self, skipped)
|
||||
end
|
||||
|
||||
def aggregate(*expressions)
|
||||
AggregateOperation.new(self, expressions)
|
||||
def group(*groupings)
|
||||
groupings.all?(&:blank?) ? self : Grouping.new(self, *groupings)
|
||||
end
|
||||
|
||||
module Writes
|
||||
|
@ -90,12 +90,6 @@ module ActiveRelation
|
|||
Join.new(join_sql, relation1, relation2, *predicates)
|
||||
end
|
||||
end
|
||||
|
||||
AggregateOperation = Struct.new(:relation, :expressions) do
|
||||
def group(*groupings)
|
||||
Aggregation.new(relation, :expressions => expressions, :groupings => groupings)
|
||||
end
|
||||
end
|
||||
end
|
||||
include Operations
|
||||
|
||||
|
|
33
spec/active_relation/unit/relations/grouping_spec.rb
Normal file
33
spec/active_relation/unit/relations/grouping_spec.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper')
|
||||
|
||||
module ActiveRelation
|
||||
describe Grouping do
|
||||
before do
|
||||
@relation = Table.new(:users)
|
||||
@attribute = @relation[:id]
|
||||
end
|
||||
|
||||
describe '#to_sql' do
|
||||
describe 'when given a predicate' do
|
||||
it "manufactures sql with where clause conditions" do
|
||||
Grouping.new(@relation, @attribute).to_sql.should be_like("
|
||||
SELECT `users`.`id`, `users`.`name`
|
||||
FROM `users`
|
||||
GROUP BY `users`.`id`
|
||||
")
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when given a string' do
|
||||
it "passes the string through to the where clause" do
|
||||
pending 'it should not quote asdf'
|
||||
Grouping.new(@relation, 'asdf').to_sql.should be_like("
|
||||
SELECT `users`.`id`, `users`.`name`
|
||||
FROM `users`
|
||||
GROUP BY asdf
|
||||
")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -97,8 +97,8 @@ module ActiveRelation
|
|||
describe 'when joining aggregated relations' do
|
||||
before do
|
||||
@aggregation = @relation2 \
|
||||
.aggregate(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \
|
||||
.group(@relation2[:user_id]) \
|
||||
.project(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \
|
||||
.as('photo_count')
|
||||
end
|
||||
|
||||
|
|
|
@ -53,16 +53,29 @@ module ActiveRelation
|
|||
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("
|
||||
Projection.new(@relation, 'asdf').to_sql.should be_like("
|
||||
SELECT asdf FROM `users`
|
||||
")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Projection::Externalizable do
|
||||
describe '#aggregation?' do
|
||||
describe 'when the projections are attributes' do
|
||||
it 'returns false' do
|
||||
Projection.new(@relation, @attribute).should_not be_aggregation
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when the projections include an aggregation' do
|
||||
it "obtains" do
|
||||
Projection.new(@relation, @attribute.sum).should be_aggregation
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -154,18 +154,15 @@ module ActiveRelation
|
|||
end
|
||||
end
|
||||
|
||||
describe '#aggregate' do
|
||||
before do
|
||||
@expression1 = @attribute1.sum
|
||||
@expression2 = @attribute2.sum
|
||||
describe '#group' do
|
||||
it 'manufactures a group relation' do
|
||||
@relation.group(@attribute1, @attribute2).should == Grouping.new(@relation, @attribute1, @attribute2)
|
||||
end
|
||||
|
||||
it 'manufactures a group relation' do
|
||||
@relation.aggregate(@expression1, @expression2).group(@attribute1, @attribute2). \
|
||||
should == Aggregation.new(@relation,
|
||||
:expressions => [@expression1, @expression2],
|
||||
:groupings => [@attribute1, @attribute2]
|
||||
)
|
||||
describe 'when given blank groupings' do
|
||||
it 'returns self' do
|
||||
@relation.group.should == @relation
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue