aboutsummaryrefslogtreecommitdiffstats
path: root/lib/arel/primitives/attribute.rb
blob: 30c03839e2da0369370ae46acf87083d8b4a3f77 (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
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 alias_or_name
      @alias || name
    end
    
    def aggregation?
      false
    end

    def column
      original_relation.column_for(self)
    end
    
    def original_relation
      relation.relation_for(self)
    end

    def format(object)
      object.to_sql(formatter)
    end

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

    module Transformations
      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 self.included(klass)
        klass.hash_on :name
      end
      
      def history
        [self] + (ancestor ? [ancestor, ancestor.history].flatten : [])
      end
      
      def =~(other)
        !(history & other.history).empty?
      end
      
      def /(other)
        if other then (history & other.history).size.to_f / Set.new(history + other.history).size
        else 0
        end
      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
    
    private
    def formatter
      Sql::Attribute.new(self)
    end
  end
end