arel 0.4.0 → 1.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. data/README.markdown +24 -0
  2. data/lib/arel.rb +3 -1
  3. data/lib/arel/algebra/attributes/attribute.rb +175 -141
  4. data/lib/arel/algebra/core_extensions.rb +0 -1
  5. data/lib/arel/algebra/core_extensions/hash.rb +5 -9
  6. data/lib/arel/algebra/core_extensions/object.rb +0 -4
  7. data/lib/arel/algebra/expression.rb +37 -24
  8. data/lib/arel/algebra/header.rb +5 -6
  9. data/lib/arel/algebra/ordering.rb +13 -5
  10. data/lib/arel/algebra/predicates.rb +143 -27
  11. data/lib/arel/algebra/relations.rb +0 -1
  12. data/lib/arel/algebra/relations/operations/from.rb +10 -2
  13. data/lib/arel/algebra/relations/operations/group.rb +8 -6
  14. data/lib/arel/algebra/relations/operations/having.rb +3 -6
  15. data/lib/arel/algebra/relations/operations/join.rb +52 -18
  16. data/lib/arel/algebra/relations/operations/lock.rb +4 -6
  17. data/lib/arel/algebra/relations/operations/order.rb +11 -7
  18. data/lib/arel/algebra/relations/operations/project.rb +10 -10
  19. data/lib/arel/algebra/relations/operations/skip.rb +10 -3
  20. data/lib/arel/algebra/relations/operations/take.rb +10 -3
  21. data/lib/arel/algebra/relations/operations/where.rb +12 -6
  22. data/lib/arel/algebra/relations/relation.rb +161 -92
  23. data/lib/arel/algebra/relations/row.rb +8 -5
  24. data/lib/arel/algebra/relations/utilities/compound.rb +34 -33
  25. data/lib/arel/algebra/relations/utilities/externalization.rb +10 -8
  26. data/lib/arel/algebra/relations/writes.rb +24 -13
  27. data/lib/arel/algebra/value.rb +41 -2
  28. data/lib/arel/engines/memory.rb +0 -2
  29. data/lib/arel/engines/memory/engine.rb +3 -9
  30. data/lib/arel/engines/memory/relations.rb +0 -3
  31. data/lib/arel/engines/memory/relations/array.rb +5 -3
  32. data/lib/arel/engines/memory/relations/operations.rb +2 -60
  33. data/lib/arel/engines/sql.rb +0 -2
  34. data/lib/arel/engines/sql/christener.rb +12 -6
  35. data/lib/arel/engines/sql/compilers/oracle_compiler.rb +34 -23
  36. data/lib/arel/engines/sql/compilers/postgresql_compiler.rb +23 -15
  37. data/lib/arel/engines/sql/engine.rb +19 -27
  38. data/lib/arel/engines/sql/formatters.rb +26 -10
  39. data/lib/arel/engines/sql/relations.rb +0 -7
  40. data/lib/arel/engines/sql/relations/compiler.rb +70 -35
  41. data/lib/arel/engines/sql/relations/table.rb +44 -32
  42. data/lib/arel/{engines/sql/relations/utilities/recursion.rb → recursion/base_case.rb} +0 -0
  43. data/lib/arel/session.rb +24 -40
  44. data/lib/arel/sql_literal.rb +13 -0
  45. data/lib/arel/version.rb +1 -1
  46. data/spec/algebra/unit/predicates/inequality_spec.rb +32 -0
  47. data/spec/algebra/unit/predicates/predicate_spec.rb +22 -0
  48. data/spec/algebra/unit/primitives/attribute_spec.rb +3 -9
  49. data/spec/algebra/unit/primitives/expression_spec.rb +1 -7
  50. data/spec/algebra/unit/relations/join_spec.rb +0 -7
  51. data/spec/algebra/unit/relations/project_spec.rb +3 -3
  52. data/spec/algebra/unit/relations/relation_spec.rb +74 -25
  53. data/spec/algebra/unit/session/session_spec.rb +7 -7
  54. data/spec/engines/memory/integration/joins/cross_engine_spec.rb +20 -10
  55. data/spec/engines/memory/unit/relations/array_spec.rb +6 -5
  56. data/spec/engines/memory/unit/relations/join_spec.rb +7 -6
  57. data/spec/engines/memory/unit/relations/order_spec.rb +7 -6
  58. data/spec/engines/memory/unit/relations/project_spec.rb +6 -6
  59. data/spec/engines/memory/unit/relations/skip_spec.rb +10 -5
  60. data/spec/engines/memory/unit/relations/take_spec.rb +7 -5
  61. data/spec/engines/memory/unit/relations/where_spec.rb +13 -9
  62. data/spec/engines/sql/unit/engine_spec.rb +20 -0
  63. data/spec/engines/sql/unit/relations/group_spec.rb +2 -2
  64. data/spec/engines/sql/unit/relations/order_spec.rb +5 -5
  65. data/spec/engines/sql/unit/relations/project_spec.rb +4 -4
  66. data/spec/engines/sql/unit/relations/table_spec.rb +0 -7
  67. data/spec/engines/sql/unit/relations/take_spec.rb +26 -0
  68. data/spec/engines/sql/unit/relations/where_spec.rb +1 -1
  69. data/spec/spec_helper.rb +1 -4
  70. data/spec/sql/christener_spec.rb +70 -0
  71. data/spec/support/model.rb +7 -2
  72. metadata +109 -23
  73. data/lib/arel/algebra/core_extensions/class.rb +0 -32
  74. data/lib/arel/algebra/relations/operations/alias.rb +0 -7
  75. data/lib/arel/engines/memory/predicates.rb +0 -99
  76. data/lib/arel/engines/memory/primitives.rb +0 -27
  77. data/lib/arel/engines/memory/relations/compound.rb +0 -9
  78. data/lib/arel/engines/memory/relations/writes.rb +0 -7
  79. data/lib/arel/engines/sql/predicates.rb +0 -103
  80. data/lib/arel/engines/sql/primitives.rb +0 -97
  81. data/lib/arel/engines/sql/relations/operations/alias.rb +0 -5
  82. data/lib/arel/engines/sql/relations/operations/join.rb +0 -33
  83. data/lib/arel/engines/sql/relations/relation.rb +0 -65
  84. data/lib/arel/engines/sql/relations/utilities/compound.rb +0 -10
  85. data/lib/arel/engines/sql/relations/utilities/externalization.rb +0 -14
  86. data/lib/arel/engines/sql/relations/writes.rb +0 -19
@@ -3,28 +3,36 @@ module Arel
3
3
  class PostgreSQLCompiler < GenericCompiler
4
4
 
5
5
  def select_sql
6
- if !orders.blank? && using_distinct_on?
7
- subquery = build_query \
8
- "SELECT #{select_clauses.kind_of?(::Array) ? select_clauses.join("") : select_clauses.to_s}",
9
- "FROM #{from_clauses}",
10
- (joins(self) unless joins(self).blank? ),
11
- ("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ),
12
- ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ),
13
- ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ),
14
- ("#{locked}" unless locked.blank? )
6
+ if !relation.orders.blank? && using_distinct_on?
7
+ selects = relation.select_clauses
8
+ joins = relation.joins(self)
9
+ wheres = relation.where_clauses
10
+ groups = relation.group_clauses
11
+ havings = relation.having_clauses
12
+ orders = relation.order_clauses
13
+
14
+ subquery_clauses = [ "",
15
+ "SELECT #{selects.kind_of?(::Array) ? selects.join("") : selects.to_s}",
16
+ "FROM #{relation.from_clauses}",
17
+ joins,
18
+ ("WHERE #{wheres.join(' AND ')}" unless wheres.empty?),
19
+ ("GROUP BY #{groups.join(', ')}" unless groups.empty?),
20
+ ("HAVING #{havings.join(' AND ')}" unless havings.empty?)
21
+ ].compact.join ' '
22
+ subquery_clauses << " #{locked}" unless locked.blank?
15
23
 
16
24
  build_query \
17
- "SELECT * FROM (#{subquery}) AS id_list",
18
- "ORDER BY #{aliased_orders(order_clauses)}",
19
- ("LIMIT #{taken}" unless taken.blank? ),
20
- ("OFFSET #{skipped}" unless skipped.blank? )
25
+ "SELECT * FROM (#{build_query subquery_clauses}) AS id_list",
26
+ "ORDER BY #{aliased_orders(orders)}",
27
+ ("LIMIT #{relation.taken}" unless relation.taken.blank? ),
28
+ ("OFFSET #{relation.skipped}" unless relation.skipped.blank? )
21
29
  else
22
30
  super
23
31
  end
24
32
  end
25
33
 
26
34
  def using_distinct_on?
27
- select_clauses.any? { |x| x =~ /DISTINCT ON/ }
35
+ relation.select_clauses.any? { |x| x =~ /DISTINCT ON/ }
28
36
  end
29
37
 
30
38
  def aliased_orders(orders)
@@ -35,7 +43,7 @@ module Arel
35
43
  end
36
44
 
37
45
  def supports_insert_with_returning?
38
- engine.postgresql_version >= 80200
46
+ engine.connection.send(:postgresql_version) >= 80200
39
47
  end
40
48
  end
41
49
  end
@@ -1,13 +1,12 @@
1
1
  module Arel
2
2
  module Sql
3
3
  class Engine
4
-
5
4
  def initialize(ar = nil)
6
5
  @ar = ar
7
6
  end
8
7
 
9
8
  def connection
10
- @ar ? @ar.connection : nil
9
+ @ar && @ar.connection
11
10
  end
12
11
 
13
12
  def adapter_name
@@ -20,36 +19,29 @@ module Arel
20
19
  end
21
20
  end
22
21
 
23
- def method_missing(method, *args, &block)
24
- @ar.connection.send(method, *args, &block)
25
- end
26
-
27
- module CRUD
28
- def create(relation)
29
- primary_key_value = if relation.primary_key.blank?
30
- nil
31
- elsif relation.record.is_a?(Hash)
32
- attribute = relation.record.detect { |attr, _| attr.name.to_s == relation.primary_key.to_s }
33
- attribute && attribute.last.value
34
- end
35
-
36
- connection.insert(relation.to_sql(false), nil, relation.primary_key, primary_key_value)
22
+ def create(relation)
23
+ primary_key_value = if relation.primary_key.blank?
24
+ nil
25
+ elsif relation.record.is_a?(Hash)
26
+ attribute = relation.record.detect { |attr, _| attr.name.to_s == relation.primary_key.to_s }
27
+ attribute && attribute.last.value
37
28
  end
38
29
 
39
- def read(relation)
40
- rows = connection.select_rows(relation.to_sql)
41
- Array.new(rows, relation.attributes)
42
- end
30
+ connection.insert(relation.to_sql(false), nil, relation.primary_key, primary_key_value)
31
+ end
43
32
 
44
- def update(relation)
45
- connection.update(relation.to_sql)
46
- end
33
+ def read(relation)
34
+ rows = connection.select_rows(relation.to_sql)
35
+ Array.new(rows, relation.attributes)
36
+ end
47
37
 
48
- def delete(relation)
49
- connection.delete(relation.to_sql)
50
- end
38
+ def update(relation)
39
+ connection.update(relation.to_sql)
40
+ end
41
+
42
+ def delete(relation)
43
+ connection.delete(relation.to_sql)
51
44
  end
52
- include CRUD
53
45
  end
54
46
  end
55
47
  end
@@ -1,13 +1,28 @@
1
1
  module Arel
2
2
  module Sql
3
3
  class Formatter
4
- attr_reader :environment
5
- delegate :christener, :engine, :to => :environment
6
- delegate :name_for, :to => :christener
7
- delegate :quote_table_name, :quote_column_name, :quote, :to => :engine
4
+ attr_reader :environment, :christener, :engine
8
5
 
9
6
  def initialize(environment)
10
7
  @environment = environment
8
+ @christener = environment.christener
9
+ @engine = environment.engine
10
+ end
11
+
12
+ def name_for thing
13
+ @christener.name_for thing
14
+ end
15
+
16
+ def quote_column_name name
17
+ @engine.connection.quote_column_name name
18
+ end
19
+
20
+ def quote_table_name name
21
+ @engine.connection.quote_table_name name
22
+ end
23
+
24
+ def quote value, column = nil
25
+ @engine.connection.quote value, column
11
26
  end
12
27
  end
13
28
 
@@ -97,12 +112,13 @@ module Arel
97
112
  end
98
113
 
99
114
  def table(table)
100
- if table.name =~ /\s/
101
- table.name
102
- else
103
- quote_table_name(table.name) +
104
- (table.name != name_for(table) ? " #{quote_table_name(name_for(table))}" : '')
105
- end
115
+ table_name = table.name
116
+ return table_name if table_name =~ /\s/
117
+
118
+ unique_name = name_for(table)
119
+
120
+ quote_table_name(table_name) +
121
+ (table_name != unique_name ? " #{quote_table_name(unique_name)}" : '')
106
122
  end
107
123
  end
108
124
 
@@ -1,10 +1,3 @@
1
- require 'arel/engines/sql/relations/utilities/compound'
2
- require 'arel/engines/sql/relations/utilities/recursion'
3
- require 'arel/engines/sql/relations/utilities/externalization'
4
1
  require 'arel/engines/sql/relations/utilities/nil'
5
2
  require 'arel/engines/sql/relations/compiler'
6
- require 'arel/engines/sql/relations/relation'
7
3
  require 'arel/engines/sql/relations/table'
8
- require 'arel/engines/sql/relations/operations/join'
9
- require 'arel/engines/sql/relations/operations/alias'
10
- require 'arel/engines/sql/relations/writes'
@@ -1,32 +1,65 @@
1
1
  module Arel
2
2
  module SqlCompiler
3
3
  class GenericCompiler
4
- attr_reader :relation
4
+ attr_reader :relation, :engine
5
5
 
6
6
  def initialize(relation)
7
7
  @relation = relation
8
+ @engine = relation.engine
9
+ end
10
+
11
+ def christener
12
+ relation.christener
8
13
  end
9
14
 
10
15
  def select_sql
11
- query = build_query \
12
- "SELECT #{select_clauses.join(', ')}",
13
- "FROM #{from_clauses}",
14
- (joins(self) unless joins(self).blank? ),
15
- ("WHERE #{where_clauses.join(' AND ')}" unless wheres.blank? ),
16
- ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ),
17
- ("HAVING #{having_clauses.join(' AND ')}" unless havings.blank? ),
18
- ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? )
19
- engine.add_limit_offset!(query,{ :limit => taken, :offset => skipped }) if taken || skipped
20
- query << " #{locked}" unless locked.blank?
21
- query
16
+ projections = @relation.projections
17
+ if Count === projections.first && projections.size == 1 &&
18
+ (relation.taken.present? || relation.wheres.present?) && relation.joins(self).blank?
19
+ subquery = [
20
+ "SELECT 1 FROM #{relation.from_clauses}", build_clauses
21
+ ].join ' '
22
+ query = "SELECT COUNT(*) AS count_id FROM (#{subquery}) AS subquery"
23
+ else
24
+ query = [
25
+ "SELECT #{relation.select_clauses.join(', ')}",
26
+ "FROM #{relation.from_clauses}",
27
+ build_clauses
28
+ ].compact.join ' '
29
+ end
30
+ query
31
+ end
32
+
33
+ def build_clauses
34
+ joins = relation.joins(self)
35
+ wheres = relation.where_clauses
36
+ groups = relation.group_clauses
37
+ havings = relation.having_clauses
38
+ orders = relation.order_clauses
39
+
40
+ clauses = [ "",
41
+ joins,
42
+ ("WHERE #{wheres.join(' AND ')}" unless wheres.empty?),
43
+ ("GROUP BY #{groups.join(', ')}" unless groups.empty?),
44
+ ("HAVING #{havings.join(' AND ')}" unless havings.empty?),
45
+ ("ORDER BY #{orders.join(', ')}" unless orders.empty?)
46
+ ].compact.join ' '
47
+
48
+ offset = relation.skipped
49
+ limit = relation.taken
50
+ @engine.connection.add_limit_offset!(clauses, :limit => limit,
51
+ :offset => offset) if offset || limit
52
+
53
+ clauses << " #{locked}" unless locked.blank?
54
+ clauses unless clauses.blank?
22
55
  end
23
56
 
24
57
  def delete_sql
25
58
  build_query \
26
59
  "DELETE",
27
- "FROM #{table_sql}",
28
- ("WHERE #{wheres.collect(&:to_sql).join(' AND ')}" unless wheres.blank? ),
29
- (add_limit_on_delete(taken) unless taken.blank? )
60
+ "FROM #{relation.table_sql}",
61
+ ("WHERE #{relation.wheres.collect { |x| x.to_sql }.join(' AND ')}" unless relation.wheres.blank? ),
62
+ (add_limit_on_delete(relation.taken) unless relation.taken.blank? )
30
63
  end
31
64
 
32
65
  def add_limit_on_delete(taken)
@@ -34,19 +67,19 @@ module Arel
34
67
  end
35
68
 
36
69
  def insert_sql(include_returning = true)
37
- insertion_attributes_values_sql = if record.is_a?(Value)
38
- record.value
70
+ insertion_attributes_values_sql = if relation.record.is_a?(Value)
71
+ relation.record.value
39
72
  else
40
- attributes = record.keys.sort_by do |attribute|
73
+ attributes = relation.record.keys.sort_by do |attribute|
41
74
  attribute.name.to_s
42
75
  end
43
76
 
44
77
  first = attributes.collect do |key|
45
- engine.quote_column_name(key.name)
78
+ @engine.connection.quote_column_name(key.name)
46
79
  end.join(', ')
47
80
 
48
81
  second = attributes.collect do |key|
49
- key.format(record[key])
82
+ key.format(relation.record[key])
50
83
  end.join(', ')
51
84
 
52
85
  build_query "(#{first})", "VALUES (#{second})"
@@ -54,9 +87,9 @@ module Arel
54
87
 
55
88
  build_query \
56
89
  "INSERT",
57
- "INTO #{table_sql}",
90
+ "INTO #{relation.table_sql}",
58
91
  insertion_attributes_values_sql,
59
- ("RETURNING #{engine.quote_column_name(primary_key)}" if include_returning && compiler.supports_insert_with_returning?)
92
+ ("RETURNING #{engine.connection.quote_column_name(relation.primary_key)}" if include_returning && relation.compiler.supports_insert_with_returning?)
60
93
  end
61
94
 
62
95
  def supports_insert_with_returning?
@@ -65,14 +98,15 @@ module Arel
65
98
 
66
99
  def update_sql
67
100
  build_query \
68
- "UPDATE #{table_sql} SET",
101
+ "UPDATE #{relation.table_sql} SET",
69
102
  assignment_sql,
70
103
  build_update_conditions_sql
71
104
  end
72
105
 
73
- protected
74
- def method_missing(method, *args, &block)
75
- relation.send(method, *args, &block)
106
+ protected
107
+
108
+ def locked
109
+ relation.locked
76
110
  end
77
111
 
78
112
  def build_query(*parts)
@@ -80,25 +114,26 @@ module Arel
80
114
  end
81
115
 
82
116
  def assignment_sql
83
- if assignments.respond_to?(:collect)
84
- attributes = assignments.keys.sort_by do |attribute|
117
+ if relation.assignments.respond_to?(:collect)
118
+ attributes = relation.assignments.keys.sort_by do |attribute|
85
119
  attribute.name.to_s
86
120
  end
87
121
 
88
122
  attributes.map do |attribute|
89
- value = assignments[attribute]
90
- "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}"
123
+ value = relation.assignments[attribute]
124
+ "#{@engine.connection.quote_column_name(attribute.name)} = #{attribute.format(value)}"
91
125
  end.join(", ")
92
126
  else
93
- assignments.value
127
+ relation.assignments.value
94
128
  end
95
129
  end
96
130
 
97
131
  def build_update_conditions_sql
98
132
  conditions = ""
99
- conditions << " WHERE #{wheres.collect(&:to_sql).join(' AND ')}" unless wheres.blank?
100
- conditions << " ORDER BY #{order_clauses.join(', ')}" unless orders.blank?
133
+ conditions << " WHERE #{relation.wheres.map { |x| x.to_sql }.join(' AND ')}" unless relation.wheres.blank?
134
+ conditions << " ORDER BY #{relation.order_clauses.join(', ')}" unless relation.orders.blank?
101
135
 
136
+ taken = relation.taken
102
137
  unless taken.blank?
103
138
  conditions = limited_update_conditions(conditions, taken)
104
139
  end
@@ -108,8 +143,8 @@ module Arel
108
143
 
109
144
  def limited_update_conditions(conditions, taken)
110
145
  conditions << " LIMIT #{taken}"
111
- quoted_primary_key = engine.quote_column_name(primary_key)
112
- "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions})"
146
+ quoted_primary_key = @engine.connection.quote_column_name(relation.primary_key)
147
+ "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{@engine.connection.quote_table_name relation.table.name} #{conditions})"
113
148
  end
114
149
 
115
150
  end
@@ -2,17 +2,36 @@ module Arel
2
2
  class Table
3
3
  include Relation, Recursion::BaseCase
4
4
 
5
- cattr_accessor :engine, :tables
6
- attr_reader :name, :engine, :table_alias, :options
5
+ @@engine = nil
6
+ @@tables = nil
7
+ class << self # FIXME: Do we really need these?
8
+ def engine; @@engine; end
9
+ def engine= e; @@engine = e; end
10
+
11
+ def tables; @@tables; end
12
+ def tables= e; @@tables = e; end
13
+ end
14
+
15
+ attr_reader :name, :engine, :table_alias, :options, :christener
16
+ attr_reader :table_exists
17
+ alias :table_exists? :table_exists
7
18
 
8
19
  def initialize(name, options = {})
9
20
  @name = name.to_s
10
21
  @table_exists = nil
22
+ @table_alias = nil
23
+ @christener = Sql::Christener.new
24
+ @attributes = nil
25
+ @matching_attributes = nil
11
26
 
12
27
  if options.is_a?(Hash)
13
28
  @options = options
14
29
  @engine = options[:engine] || Table.engine
15
- @table_alias = options[:as].to_s if options[:as].present? && options[:as].to_s != @name
30
+
31
+ if options[:as]
32
+ as = options[:as].to_s
33
+ @table_alias = as unless as == @name
34
+ end
16
35
  else
17
36
  @engine = options # Table.new('foo', engine)
18
37
  end
@@ -20,10 +39,18 @@ module Arel
20
39
  if @engine.connection
21
40
  begin
22
41
  require "arel/engines/sql/compilers/#{@engine.adapter_name.downcase}_compiler"
23
- @@tables ||= engine.tables
24
42
  rescue LoadError
25
- raise "#{@engine.adapter_name} is not supported by Arel."
43
+ begin
44
+ # try to load an externally defined compiler, in case this adapter has defined the compiler on its own.
45
+ require "#{@engine.adapter_name.downcase}/arel_compiler"
46
+ rescue LoadError
47
+ raise "#{@engine.adapter_name} is not supported by Arel."
48
+ end
26
49
  end
50
+
51
+ @@tables ||= engine.connection.tables
52
+ @table_exists = @@tables.include?(name) ||
53
+ @engine.connection.table_exists?(name)
27
54
  end
28
55
  end
29
56
 
@@ -31,42 +58,24 @@ module Arel
31
58
  Table.new(name, options.merge(:as => table_alias))
32
59
  end
33
60
 
34
- def table_exists?
35
- if @table_exists
36
- true
37
- else
38
- @table_exists = @@tables.include?(name) || engine.table_exists?(name)
39
- end
40
- end
41
-
42
61
  def attributes
43
- return @attributes if defined?(@attributes)
62
+ return @attributes if @attributes
44
63
  if table_exists?
45
- @attributes ||= begin
46
- attrs = columns.collect do |column|
47
- Sql::Attributes.for(column).new(column, self, column.name.to_sym)
48
- end
49
- Header.new(attrs)
64
+ attrs = columns.collect do |column|
65
+ Sql::Attributes.for(column).new(column, self, column.name.to_sym)
50
66
  end
67
+ @attributes = Header.new(attrs)
51
68
  else
52
69
  Header.new
53
70
  end
54
71
  end
55
72
 
56
- def eql?(other)
57
- self == other
58
- end
59
-
60
- def hash
61
- @hash ||= :name.hash
62
- end
63
-
64
73
  def column_for(attribute)
65
74
  has_attribute?(attribute) and columns.detect { |c| c.name == attribute.name.to_s }
66
75
  end
67
76
 
68
77
  def columns
69
- @columns ||= engine.columns(name, "#{name} Columns")
78
+ @columns ||= engine.connection.columns(name, "#{name} Columns")
70
79
  end
71
80
 
72
81
  def reset
@@ -74,10 +83,13 @@ module Arel
74
83
  @attributes = Header.new([])
75
84
  end
76
85
 
77
- def ==(other)
78
- Table === other and
79
- name == other.name and
80
- table_alias == other.table_alias
86
+ private
87
+ def matching_attributes
88
+ @matching_attributes ||= Hash[attributes.map { |a| [a.root, true] }]
89
+ end
90
+
91
+ def has_attribute?(attribute)
92
+ matching_attributes.key? attribute.root
81
93
  end
82
94
  end
83
95
  end