aboutsummaryrefslogtreecommitdiffstats
path: root/lib/arel/table.rb
blob: 61210dae767bcf8bc0369afeff0a67af3e693e5a (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
module Arel
  class Table
    include Arel::Crud

    @engine = nil
    class << self; attr_accessor :engine; end

    attr_accessor :name, :engine, :aliases, :table_alias

    def initialize name, engine = Table.engine
      @name    = name
      @engine  = engine
      @columns = nil
      @aliases = []
      @table_alias = nil
      @primary_key = nil

      if Hash === engine
        @engine  = engine[:engine] || Table.engine
        @columns = attributes_for engine[:columns]

        # Sometime AR sends an :as parameter to table, to let the table know
        # that it is an Alias.  We may want to override new, and return a
        # TableAlias node?
        @table_alias = engine[:as] unless engine[:as].to_s == name.to_s
      end
    end

    def primary_key
      @primary_key ||= begin
        primary_key_name = @engine.connection.primary_key(name)
        # some tables might be without primary key
        primary_key_name && self[primary_key_name]
      end
    end

    def alias
      Nodes::TableAlias.new("#{name}_2", self).tap do |node|
        @aliases << node
      end
    end

    def from table
      SelectManager.new(@engine, table)
    end

    def joins manager
      nil
    end

    def join relation, klass = Nodes::InnerJoin
      return from(self) unless relation

      case relation
      when String, Nodes::SqlLiteral
        raise if relation.blank?
        from Nodes::StringJoin.new(self, relation)
      else
        from klass.new(self, relation, nil)
      end
    end

    def group *columns
      from(self).group(*columns)
    end

    def order *expr
      from(self).order(*expr)
    end

    def where condition
      from(self).where condition
    end

    def project *things
      from(self).project(*things)
    end

    def take amount
      from(self).take amount
    end

    def skip amount
      from(self).skip amount
    end

    def having expr
      from(self).having expr
    end

    def columns
      @columns ||=
        attributes_for @engine.connection.columns(@name, "#{@name} Columns")
    end

    def [] name
      return nil unless table_exists?

      name = name.to_sym
      columns.find { |column| column.name == name }
    end

    def select_manager
      SelectManager.new(@engine)
    end

    private

    def attributes_for columns
      return nil unless columns

      columns.map do |column|
        Attributes.for(column).new self, column.name.to_sym, column
      end
    end

    def table_exists?
      @table_exists ||= tables.key?(@name) || engine.connection.table_exists?(name)
    end

    def tables
      self.class.table_cache(@engine)
    end

    @@table_cache = nil
    def self.table_cache engine # :nodoc:
      @@table_cache ||= Hash[engine.connection.tables.map { |x| [x,true] }]
    end
  end
end