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
@@ -4,7 +4,6 @@ require 'arel/algebra/relations/utilities/nil'
4
4
  require 'arel/algebra/relations/utilities/externalization'
5
5
  require 'arel/algebra/relations/row'
6
6
  require 'arel/algebra/relations/writes'
7
- require 'arel/algebra/relations/operations/alias'
8
7
  require 'arel/algebra/relations/operations/from'
9
8
  require 'arel/algebra/relations/operations/group'
10
9
  require 'arel/algebra/relations/operations/having'
@@ -1,6 +1,14 @@
1
1
  module Arel
2
2
  class From < Compound
3
- attributes :relation, :sources
4
- deriving :initialize, :==
3
+ attr_reader :sources
4
+
5
+ def initialize relation, sources
6
+ super(relation)
7
+ @sources = sources
8
+ end
9
+
10
+ def eval
11
+ unoperated_rows[sources..-1]
12
+ end
5
13
  end
6
14
  end
@@ -1,12 +1,14 @@
1
1
  module Arel
2
2
  class Group < Compound
3
- attributes :relation, :groupings
4
- deriving :==
3
+ attr_reader :groupings
5
4
 
6
- def initialize(relation, *groupings, &block)
7
- @relation = relation
8
- @groupings = (groupings + arguments_from_block(relation, &block)) \
9
- .collect { |g| g.bind(relation) }
5
+ def initialize(relation, groupings)
6
+ super(relation)
7
+ @groupings = groupings.collect { |g| g.bind(relation) }
8
+ end
9
+
10
+ def eval
11
+ raise NotImplementedError
10
12
  end
11
13
  end
12
14
  end
@@ -1,13 +1,10 @@
1
1
  module Arel
2
2
  class Having < Compound
3
- attributes :relation, :predicates
4
- deriving :==
5
- requires :restricting
3
+ attr_reader :predicates
6
4
 
7
- def initialize(relation, *predicates, &block)
8
- predicates = [yield(relation)] + predicates if block_given?
5
+ def initialize(relation, predicates)
6
+ super(relation)
9
7
  @predicates = predicates.map { |p| p.bind(relation) }
10
- @relation = relation
11
8
  end
12
9
 
13
10
  def havings
@@ -2,20 +2,17 @@ module Arel
2
2
  class Join
3
3
  include Relation
4
4
 
5
- attributes :relation1, :relation2, :predicates
6
- deriving :==
7
- delegate :name, :to => :relation1
5
+ attr_reader :relation1, :relation2, :predicates
8
6
 
9
7
  def initialize(relation1, relation2 = Nil.instance, *predicates)
10
- @relation1, @relation2, @predicates = relation1, relation2, predicates
8
+ @relation1 = relation1
9
+ @relation2 = relation2
10
+ @predicates = predicates
11
+ @attributes = nil
11
12
  end
12
13
 
13
- def hash
14
- @hash ||= :relation1.hash
15
- end
16
-
17
- def eql?(other)
18
- self == other
14
+ def name
15
+ relation1.name
19
16
  end
20
17
 
21
18
  def attributes
@@ -43,11 +40,54 @@ module Arel
43
40
  def engine
44
41
  relation1.engine != relation2.engine ? Memory::Engine.new : relation1.engine
45
42
  end
43
+
44
+ def table_sql(formatter = Sql::TableReference.new(self))
45
+ relation1.externalize.table_sql(formatter)
46
+ end
47
+
48
+ def joins(environment, formatter = Sql::TableReference.new(environment))
49
+ @joins ||= begin
50
+ this_join = [
51
+ join_sql,
52
+ relation2.externalize.table_sql(formatter),
53
+ ("ON" unless predicates.blank?),
54
+ (ons + relation2.externalize.wheres).collect { |p| p.bind(environment.relation).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ')
55
+ ].compact.join(" ")
56
+ [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ")
57
+ end
58
+ end
59
+
60
+ def eval
61
+ result = []
62
+ relation1.call.each do |row1|
63
+ relation2.call.each do |row2|
64
+ combined_row = row1.combine(row2, self)
65
+ if predicates.all? { |p| p.eval(combined_row) }
66
+ result << combined_row
67
+ end
68
+ end
69
+ end
70
+ result
71
+ end
72
+
73
+ def to_sql(formatter = nil)
74
+ compiler.select_sql
75
+ end
76
+ end
77
+
78
+ class InnerJoin < Join
79
+ def join_sql; "INNER JOIN" end
80
+ end
81
+
82
+ class OuterJoin < Join
83
+ def join_sql; "LEFT OUTER JOIN" end
46
84
  end
47
85
 
48
- class InnerJoin < Join; end
49
- class OuterJoin < Join; end
50
86
  class StringJoin < Join
87
+ def joins(environment, formatter = Sql::TableReference.new(environment))
88
+ [relation1.joins(environment), relation2].compact.join(" ")
89
+ end
90
+
51
91
  def externalizable?
52
92
  relation1.externalizable?
53
93
  end
@@ -60,10 +100,4 @@ module Arel
60
100
  relation1.engine
61
101
  end
62
102
  end
63
-
64
- module Relation
65
- def join?
66
- false
67
- end
68
- end
69
103
  end
@@ -1,12 +1,10 @@
1
1
  module Arel
2
2
  class Lock < Compound
3
- attributes :relation, :locked
4
- deriving :initialize, :==
3
+ attr_reader :locked
5
4
 
6
- def initialize(relation, locked, &block)
7
- @relation = relation
8
- @locked = locked.blank? ? " FOR UPDATE" : locked
5
+ def initialize(relation, locked)
6
+ super(relation)
7
+ @locked = true == locked ? " FOR UPDATE" : locked
9
8
  end
10
9
  end
11
10
  end
12
-
@@ -1,13 +1,10 @@
1
1
  module Arel
2
2
  class Order < Compound
3
- attributes :relation, :orderings
4
- deriving :==
5
- requires :ordering
3
+ attr_reader :orderings
6
4
 
7
- def initialize(relation, *orderings, &block)
8
- @relation = relation
9
- @orderings = (orderings + arguments_from_block(relation, &block)) \
10
- .collect { |o| o.bind(relation) }
5
+ def initialize(relation, orderings)
6
+ super(relation)
7
+ @orderings = orderings.collect { |o| o.bind(relation) }
11
8
  end
12
9
 
13
10
  # TESTME
@@ -15,5 +12,12 @@ module Arel
15
12
  # QUESTION - do we still need relation.orders ?
16
13
  (orderings + relation.orders).collect { |o| o.bind(self) }.collect { |o| o.to_ordering }
17
14
  end
15
+
16
+ def eval
17
+ unoperated_rows.sort do |row1, row2|
18
+ ordering = orders.detect { |o| o.eval(row1, row2) != 0 } || orders.last
19
+ ordering.eval(row1, row2)
20
+ end
21
+ end
18
22
  end
19
23
  end
@@ -1,20 +1,20 @@
1
1
  module Arel
2
2
  class Project < Compound
3
- attributes :relation, :projections
4
- deriving :==
3
+ attr_reader :projections, :attributes, :christener
5
4
 
6
- def initialize(relation, *projections, &block)
7
- @relation = relation
8
- @projections = (projections + arguments_from_block(relation, &block)) \
9
- .collect { |p| p.bind(relation) }
10
- end
11
-
12
- def attributes
13
- @attributes ||= Header.new(projections).bind(self)
5
+ def initialize(relation, projections)
6
+ super(relation)
7
+ @projections = projections.map { |p| p.bind(relation) }
8
+ @christener = Sql::Christener.new
9
+ @attributes = Header.new(projections.map { |x| x.bind(self) })
14
10
  end
15
11
 
16
12
  def externalizable?
17
13
  attributes.any? { |a| a.respond_to?(:aggregation?) && a.aggregation? } || relation.externalizable?
18
14
  end
15
+
16
+ def eval
17
+ unoperated_rows.collect { |r| r.slice(*projections) }
18
+ end
19
19
  end
20
20
  end
@@ -1,7 +1,14 @@
1
1
  module Arel
2
2
  class Skip < Compound
3
- attributes :relation, :skipped
4
- deriving :initialize, :==
5
- requires :skipping
3
+ attr_reader :relation, :skipped
4
+
5
+ def initialize relation, skipped
6
+ super(relation)
7
+ @skipped = skipped
8
+ end
9
+
10
+ def eval
11
+ unoperated_rows[skipped..-1]
12
+ end
6
13
  end
7
14
  end
@@ -1,11 +1,18 @@
1
1
  module Arel
2
2
  class Take < Compound
3
- attributes :relation, :taken
4
- deriving :initialize, :==
5
- requires :limiting
3
+ attr_reader :taken
4
+
5
+ def initialize relation, taken
6
+ super(relation)
7
+ @taken = taken
8
+ end
6
9
 
7
10
  def externalizable?
8
11
  true
9
12
  end
13
+
14
+ def eval
15
+ unoperated_rows[0, taken]
16
+ end
10
17
  end
11
18
  end
@@ -1,17 +1,23 @@
1
1
  module Arel
2
2
  class Where < Compound
3
- attributes :relation, :predicates
4
- deriving :==
5
- requires :restricting
3
+ attr_reader :predicates
6
4
 
7
- def initialize(relation, *predicates, &block)
8
- predicates = [yield(relation)] + predicates if block_given?
5
+ def initialize(relation, predicates)
6
+ super(relation)
9
7
  @predicates = predicates.map { |p| p.bind(relation) }
10
- @relation = relation
8
+ @wheres = nil
11
9
  end
12
10
 
13
11
  def wheres
14
12
  @wheres ||= relation.wheres + predicates
15
13
  end
14
+
15
+ def eval
16
+ unoperated_rows.select { |row| predicates.all? { |p| p.eval(row) } }
17
+ end
18
+
19
+ def to_sql(formatter = nil)
20
+ compiler.select_sql
21
+ end
16
22
  end
17
23
  end
@@ -1,9 +1,17 @@
1
1
  module Arel
2
2
  module Relation
3
+ include Enumerable
4
+
5
+ @@connection_tables_primary_keys = {}
6
+
3
7
  attr_reader :count
4
8
 
5
9
  def session
6
- Session.new
10
+ Session.instance
11
+ end
12
+
13
+ def join?
14
+ false
7
15
  end
8
16
 
9
17
  def call
@@ -14,123 +22,184 @@ module Arel
14
22
  self
15
23
  end
16
24
 
17
- module Enumerable
18
- include ::Enumerable
25
+ def externalize
26
+ @externalized ||= externalizable?? Externalization.new(self) : self
27
+ end
28
+
29
+ def externalizable?
30
+ false
31
+ end
19
32
 
20
- def each(&block)
21
- session.read(self).each(&block)
33
+ def compiler
34
+ @compiler ||= begin
35
+ Arel::SqlCompiler.const_get("#{engine.adapter_name}Compiler").new(self)
36
+ rescue
37
+ Arel::SqlCompiler::GenericCompiler.new(self)
22
38
  end
39
+ end
40
+
41
+ def to_sql(formatter = nil)
42
+ sql = compiler.select_sql
43
+
44
+ return sql unless formatter
45
+ formatter.select sql, self
46
+ end
47
+
48
+ def christener
49
+ @christener ||= Sql::Christener.new
50
+ end
51
+
52
+ def inclusion_predicate_sql
53
+ "IN"
54
+ end
55
+
56
+ def exclusion_predicate_sql
57
+ "NOT IN"
58
+ end
23
59
 
24
- def first
25
- session.read(self).first
60
+ def primary_key
61
+ connection_id = engine.connection.object_id
62
+ if @@connection_tables_primary_keys[connection_id] && @@connection_tables_primary_keys[connection_id].has_key?(table.name)
63
+ @@connection_tables_primary_keys[connection_id][table.name]
64
+ else
65
+ @@connection_tables_primary_keys[connection_id] ||= {}
66
+ @@connection_tables_primary_keys[connection_id][table.name] = engine.connection.primary_key(table.name)
26
67
  end
27
68
  end
28
- include Enumerable
29
69
 
30
- module Operable
31
- def join(other_relation = nil, join_class = InnerJoin)
32
- case other_relation
33
- when String
34
- StringJoin.new(self, other_relation)
35
- when Relation
36
- JoinOperation.new(join_class, self, other_relation)
70
+ def select_clauses
71
+ attributes.map { |a|
72
+ case a
73
+ when Value
74
+ a.value
37
75
  else
38
- self
76
+ a.to_sql(Sql::SelectClause.new(self))
39
77
  end
40
- end
78
+ }
79
+ end
80
+
81
+ def from_clauses
82
+ sources.empty? ? table_sql : sources
83
+ end
84
+
85
+ def where_clauses
86
+ wheres.map { |w| w.value }
87
+ end
88
+
89
+ def group_clauses
90
+ groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }
91
+ end
41
92
 
42
- def outer_join(other_relation = nil)
43
- join(other_relation, OuterJoin)
93
+ def having_clauses
94
+ havings.collect { |g| g.to_sql(Sql::HavingClause.new(self)) }
95
+ end
96
+
97
+ def order_clauses
98
+ orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) }
99
+ end
100
+
101
+ def each
102
+ session.read(self).each { |e| yield e }
103
+ end
104
+
105
+ def join(other_relation = nil, join_class = InnerJoin)
106
+ case other_relation
107
+ when String
108
+ StringJoin.new(self, other_relation)
109
+ when Relation
110
+ JoinOperation.new(join_class, self, other_relation)
111
+ else
112
+ self
44
113
  end
114
+ end
45
115
 
46
- [:where, :project, :order, :take, :skip, :group, :from, :having].each do |operation_name|
47
- class_eval <<-OPERATION, __FILE__, __LINE__
48
- def #{operation_name}(*arguments, &block)
49
- arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block)
116
+ def outer_join(other_relation = nil)
117
+ join(other_relation, OuterJoin)
118
+ end
119
+
120
+ %w{
121
+ having group order
122
+ }.each do |op|
123
+ class_eval <<-OPERATION, __FILE__, __LINE__
124
+ def #{op}(*args)
125
+ args.all? { |x| x.blank? } ? self : #{op.capitalize}.new(self, args)
50
126
  end
51
- OPERATION
52
- end
127
+ OPERATION
128
+ end
53
129
 
54
- def lock(locking = nil)
55
- Lock.new(self, locking)
56
- end
130
+ def project *args
131
+ args.empty? ? self : Project.new(self, args)
132
+ end
57
133
 
58
- def alias
59
- Alias.new(self)
60
- end
134
+ def where clause = nil
135
+ clause ? Where.new(self, Array(clause)) : self
136
+ end
61
137
 
62
- module Writable
63
- def insert(record)
64
- session.create Insert.new(self, record)
65
- end
138
+ def skip thing = nil
139
+ thing ? Skip.new(self, thing) : self
140
+ end
66
141
 
67
- def update(assignments)
68
- session.update Update.new(self, assignments)
69
- end
142
+ def take count
143
+ Take.new self, count
144
+ end
70
145
 
71
- def delete
72
- session.delete Deletion.new(self)
73
- end
74
- end
75
- include Writable
146
+ def from thing
147
+ From.new self, thing
148
+ end
76
149
 
77
- JoinOperation = Struct.new(:join_class, :relation1, :relation2) do
78
- def on(*predicates)
79
- join_class.new(relation1, relation2, *predicates)
80
- end
81
- end
150
+ def lock(locking = true)
151
+ Lock.new(self, locking)
82
152
  end
83
- include Operable
84
153
 
85
- module AttributeAccessable
86
- def [](index)
87
- attributes[index]
88
- end
154
+ def alias
155
+ Alias.new(self)
156
+ end
89
157
 
90
- def find_attribute_matching_name(name)
91
- attributes.detect { |a| a.named?(name) } || Attribute.new(self, name)
92
- end
158
+ def insert(record)
159
+ session.create Insert.new(self, record)
160
+ end
93
161
 
94
- def find_attribute_matching_attribute(attribute)
95
- matching_attributes(attribute).max do |a1, a2|
96
- (a1.original_attribute / attribute) <=> (a2.original_attribute / attribute)
97
- end
98
- end
162
+ def update(assignments)
163
+ session.update Update.new(self, assignments)
164
+ end
99
165
 
100
- def position_of(attribute)
101
- (@position_of ||= Hash.new do |h, attribute|
102
- h[attribute] = attributes.index(self[attribute])
103
- end)[attribute]
104
- end
166
+ def delete
167
+ session.delete Deletion.new(self)
168
+ end
105
169
 
106
- private
107
- def matching_attributes(attribute)
108
- (@matching_attributes ||= attributes.inject({}) do |hash, a|
109
- (hash[a.is_a?(Value) ? a.value : a.root] ||= []) << a
110
- hash
111
- end)[attribute.root] || []
170
+ JoinOperation = Struct.new(:join_class, :relation1, :relation2) do
171
+ def on(*predicates)
172
+ join_class.new(relation1, relation2, *predicates)
112
173
  end
174
+ end
113
175
 
114
- def has_attribute?(attribute)
115
- !matching_attributes(attribute).empty?
116
- end
176
+ def [](index)
177
+ attributes[index]
178
+ end
179
+
180
+ def find_attribute_matching_name(name)
181
+ attributes.detect { |a| a.named?(name) } || Attribute.new(self, name)
182
+ end
183
+
184
+ def position_of(attribute)
185
+ @position_of ||= {}
186
+
187
+ return @position_of[attribute] if @position_of.key? attribute
188
+
189
+ @position_of[attribute] = attributes.index(attributes[attribute])
117
190
  end
118
- include AttributeAccessable
119
-
120
- module DefaultOperations
121
- def attributes; Header.new end
122
- def projections; [] end
123
- def wheres; [] end
124
- def orders; [] end
125
- def inserts; [] end
126
- def groupings; [] end
127
- def havings; [] end
128
- def joins(formatter = nil); nil end # FIXME
129
- def taken; nil end
130
- def skipped; nil end
131
- def sources; [] end
132
- def locked; [] end
133
- end
134
- include DefaultOperations
191
+
192
+ def attributes; Header.new end
193
+ def projections; [] end
194
+ def wheres; [] end
195
+ def orders; [] end
196
+ def inserts; [] end
197
+ def groupings; [] end
198
+ def havings; [] end
199
+ def joins(formatter = nil); nil end # FIXME
200
+ def taken; nil end
201
+ def skipped; nil end
202
+ def sources; [] end
203
+ def locked; [] end
135
204
  end
136
205
  end