aboutsummaryrefslogtreecommitdiffstats
path: root/lib/arel/primitives/attribute.rb
blob: 5e769ac0eb47d5b8ce8b9bfb525d9a1b3a2b2a87 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
require 'set'

module Arel
  class Attribute
    attr_reader :relation, :name, :alias, :ancestor
    delegate :engine, :christener, :to => :relation

    def initialize(relation, name, options = {})
      @relation, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor]
    end
    
    def named?(hypothetical_name)
      (@alias || name).to_s == hypothetical_name.to_s
    end
    
    def aggregation?
      false
    end

    def column
      original_relation.column_for(self)
    end
        
    def format(object)
      object.to_sql(Sql::Attribute.new(self))
    end

    def to_sql(formatter = Sql::WhereCondition.new(relation))
      formatter.attribute self
    end
    
    def ==(other)
      Attribute   == other.class     and
      name        == other.name      and
      @alias      == other.alias     and
      ancestor    == other.ancestor  and
      relation    == other.relation
    end

    def original_relation
      @original_relation ||= relation.relation_for(self)
    end
    
    def original_attribute
      @original_attribute ||= original_relation[self]
    end

    module Transformations
      delegate :size, :to => :history
      
      def self.included(klass)
        klass.send :alias_method, :eql?, :==
      end
      
      def hash
        @hash ||= history.size + name.hash + relation.hash
      end
      
      def as(aliaz = nil)
        Attribute.new(relation, name, :alias => aliaz, :ancestor => self)
      end
    
      def bind(new_relation)
        relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self)
      end

      def to_attribute
        self
      end
    end
    include Transformations
    
    module Congruence
      def history
        @history ||= [self] + (ancestor ? ancestor.history : [])
      end
      
      def match?(other)
        history.last == other.history.last
      end
      
      def root
        history.last
      end
      
      def descends_from?(other)
        history.include?(other)
      end
      
      def /(other)
        other ? (history & other.history).size : 0
      end
    end
    include Congruence
    
    module Predications
      def eq(other)
        Equality.new(self, other)
      end

      def lt(other)
        LessThan.new(self, other)
      end

      def lteq(other)
        LessThanOrEqualTo.new(self, other)
      end

      def gt(other)
        GreaterThan.new(self, other)
      end

      def gteq(other)
        GreaterThanOrEqualTo.new(self, other)
      end

      def matches(regexp)
        Match.new(self, regexp)
      end
      
      def in(array)
        In.new(self, array)
      end
    end
    include Predications
    
    module Expressions
      def count
        Expression.new(self, "COUNT")
      end
      
      def sum
        Expression.new(self, "SUM")
      end
      
      def maximum
        Expression.new(self, "MAX")
      end
      
      def minimum
        Expression.new(self, "MIN")
      end
      
      def average
        Expression.new(self, "AVG")
      end
    end
    include Expressions
  end
end