square-arel 2.0.9.20110222133018

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 (125) hide show
  1. data/.autotest +26 -0
  2. data/History.txt +105 -0
  3. data/MIT-LICENSE.txt +20 -0
  4. data/Manifest.txt +124 -0
  5. data/README.markdown +94 -0
  6. data/Rakefile +20 -0
  7. data/lib/arel.rb +39 -0
  8. data/lib/arel/attributes.rb +20 -0
  9. data/lib/arel/attributes/attribute.rb +18 -0
  10. data/lib/arel/compatibility/wheres.rb +33 -0
  11. data/lib/arel/crud.rb +37 -0
  12. data/lib/arel/delete_manager.rb +18 -0
  13. data/lib/arel/deprecated.rb +4 -0
  14. data/lib/arel/expression.rb +4 -0
  15. data/lib/arel/expressions.rb +23 -0
  16. data/lib/arel/insert_manager.rb +34 -0
  17. data/lib/arel/nodes.rb +53 -0
  18. data/lib/arel/nodes/and.rb +6 -0
  19. data/lib/arel/nodes/as.rb +6 -0
  20. data/lib/arel/nodes/assignment.rb +6 -0
  21. data/lib/arel/nodes/avg.rb +6 -0
  22. data/lib/arel/nodes/between.rb +6 -0
  23. data/lib/arel/nodes/binary.rb +12 -0
  24. data/lib/arel/nodes/count.rb +13 -0
  25. data/lib/arel/nodes/delete_statement.rb +19 -0
  26. data/lib/arel/nodes/does_not_match.rb +6 -0
  27. data/lib/arel/nodes/equality.rb +9 -0
  28. data/lib/arel/nodes/except.rb +7 -0
  29. data/lib/arel/nodes/exists.rb +7 -0
  30. data/lib/arel/nodes/function.rb +18 -0
  31. data/lib/arel/nodes/greater_than.rb +6 -0
  32. data/lib/arel/nodes/greater_than_or_equal.rb +6 -0
  33. data/lib/arel/nodes/group.rb +6 -0
  34. data/lib/arel/nodes/grouping.rb +6 -0
  35. data/lib/arel/nodes/having.rb +6 -0
  36. data/lib/arel/nodes/in.rb +6 -0
  37. data/lib/arel/nodes/inner_join.rb +6 -0
  38. data/lib/arel/nodes/insert_statement.rb +19 -0
  39. data/lib/arel/nodes/intersect.rb +7 -0
  40. data/lib/arel/nodes/join.rb +13 -0
  41. data/lib/arel/nodes/less_than.rb +6 -0
  42. data/lib/arel/nodes/less_than_or_equal.rb +6 -0
  43. data/lib/arel/nodes/limit.rb +7 -0
  44. data/lib/arel/nodes/lock.rb +6 -0
  45. data/lib/arel/nodes/matches.rb +6 -0
  46. data/lib/arel/nodes/max.rb +6 -0
  47. data/lib/arel/nodes/min.rb +6 -0
  48. data/lib/arel/nodes/node.rb +44 -0
  49. data/lib/arel/nodes/not.rb +6 -0
  50. data/lib/arel/nodes/not_equal.rb +6 -0
  51. data/lib/arel/nodes/not_in.rb +6 -0
  52. data/lib/arel/nodes/offset.rb +7 -0
  53. data/lib/arel/nodes/on.rb +6 -0
  54. data/lib/arel/nodes/or.rb +6 -0
  55. data/lib/arel/nodes/ordering.rb +20 -0
  56. data/lib/arel/nodes/outer_join.rb +6 -0
  57. data/lib/arel/nodes/select_core.rb +26 -0
  58. data/lib/arel/nodes/select_statement.rb +22 -0
  59. data/lib/arel/nodes/sql_literal.rb +8 -0
  60. data/lib/arel/nodes/string_join.rb +11 -0
  61. data/lib/arel/nodes/sum.rb +6 -0
  62. data/lib/arel/nodes/table_alias.rb +13 -0
  63. data/lib/arel/nodes/top.rb +6 -0
  64. data/lib/arel/nodes/unary.rb +11 -0
  65. data/lib/arel/nodes/union.rb +7 -0
  66. data/lib/arel/nodes/union_all.rb +7 -0
  67. data/lib/arel/nodes/unqualified_column.rb +16 -0
  68. data/lib/arel/nodes/update_statement.rb +21 -0
  69. data/lib/arel/nodes/values.rb +14 -0
  70. data/lib/arel/predications.rb +183 -0
  71. data/lib/arel/relation.rb +6 -0
  72. data/lib/arel/select_manager.rb +237 -0
  73. data/lib/arel/sql/engine.rb +10 -0
  74. data/lib/arel/sql_literal.rb +4 -0
  75. data/lib/arel/table.rb +134 -0
  76. data/lib/arel/tree_manager.rb +36 -0
  77. data/lib/arel/update_manager.rb +49 -0
  78. data/lib/arel/visitors.rb +38 -0
  79. data/lib/arel/visitors/depth_first.rb +154 -0
  80. data/lib/arel/visitors/dot.rb +230 -0
  81. data/lib/arel/visitors/join_sql.rb +40 -0
  82. data/lib/arel/visitors/mssql.rb +16 -0
  83. data/lib/arel/visitors/mysql.rb +34 -0
  84. data/lib/arel/visitors/oracle.rb +116 -0
  85. data/lib/arel/visitors/order_clauses.rb +11 -0
  86. data/lib/arel/visitors/postgresql.rb +58 -0
  87. data/lib/arel/visitors/sqlite.rb +11 -0
  88. data/lib/arel/visitors/to_sql.rb +331 -0
  89. data/lib/arel/visitors/visitor.rb +27 -0
  90. data/lib/arel/visitors/where_sql.rb +9 -0
  91. data/square-arel.gemspec +36 -0
  92. data/test/attributes/test_attribute.rb +664 -0
  93. data/test/helper.rb +13 -0
  94. data/test/nodes/test_as.rb +16 -0
  95. data/test/nodes/test_count.rb +18 -0
  96. data/test/nodes/test_delete_statement.rb +14 -0
  97. data/test/nodes/test_equality.rb +74 -0
  98. data/test/nodes/test_insert_statement.rb +18 -0
  99. data/test/nodes/test_node.rb +33 -0
  100. data/test/nodes/test_not.rb +20 -0
  101. data/test/nodes/test_or.rb +22 -0
  102. data/test/nodes/test_select_core.rb +22 -0
  103. data/test/nodes/test_select_statement.rb +13 -0
  104. data/test/nodes/test_sql_literal.rb +52 -0
  105. data/test/nodes/test_sum.rb +12 -0
  106. data/test/nodes/test_update_statement.rb +18 -0
  107. data/test/support/fake_record.rb +91 -0
  108. data/test/test_activerecord_compat.rb +18 -0
  109. data/test/test_attributes.rb +46 -0
  110. data/test/test_crud.rb +69 -0
  111. data/test/test_delete_manager.rb +42 -0
  112. data/test/test_insert_manager.rb +125 -0
  113. data/test/test_select_manager.rb +659 -0
  114. data/test/test_table.rb +193 -0
  115. data/test/test_update_manager.rb +86 -0
  116. data/test/visitors/test_depth_first.rb +212 -0
  117. data/test/visitors/test_dot.rb +29 -0
  118. data/test/visitors/test_join_sql.rb +35 -0
  119. data/test/visitors/test_mssql.rb +18 -0
  120. data/test/visitors/test_mysql.rb +45 -0
  121. data/test/visitors/test_oracle.rb +147 -0
  122. data/test/visitors/test_postgres.rb +36 -0
  123. data/test/visitors/test_sqlite.rb +18 -0
  124. data/test/visitors/test_to_sql.rb +255 -0
  125. metadata +261 -0
@@ -0,0 +1,18 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ describe 'activerecord compatibility' do
5
+ describe 'select manager' do
6
+ it 'provides wheres' do
7
+ table = Table.new :users
8
+ manager = Arel::SelectManager.new Table.engine
9
+ manager.where table[:id].eq 1
10
+ manager.where table[:name].eq 'Aaron'
11
+
12
+ manager.wheres.map { |x|
13
+ x.value
14
+ }.join(', ').must_equal "\"users\".\"id\" = 1, \"users\".\"name\" = 'Aaron'"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,46 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ describe 'Attributes' do
5
+ describe 'for' do
6
+ it 'deals with unknown column types' do
7
+ column = Struct.new(:type).new :crazy
8
+ Attributes.for(column).must_equal Attributes::Undefined
9
+ end
10
+
11
+ it 'returns the correct constant for strings' do
12
+ [:string, :text, :binary].each do |type|
13
+ column = Struct.new(:type).new type
14
+ Attributes.for(column).must_equal Attributes::String
15
+ end
16
+ end
17
+
18
+ it 'returns the correct constant for ints' do
19
+ column = Struct.new(:type).new :integer
20
+ Attributes.for(column).must_equal Attributes::Integer
21
+ end
22
+
23
+ it 'returns the correct constant for floats' do
24
+ column = Struct.new(:type).new :float
25
+ Attributes.for(column).must_equal Attributes::Float
26
+ end
27
+
28
+ it 'returns the correct constant for decimals' do
29
+ column = Struct.new(:type).new :decimal
30
+ Attributes.for(column).must_equal Attributes::Decimal
31
+ end
32
+
33
+ it 'returns the correct constant for boolean' do
34
+ column = Struct.new(:type).new :boolean
35
+ Attributes.for(column).must_equal Attributes::Boolean
36
+ end
37
+
38
+ it 'returns the correct constant for time' do
39
+ [:date, :datetime, :timestamp, :time].each do |type|
40
+ column = Struct.new(:type).new type
41
+ Attributes.for(column).must_equal Attributes::Time
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,69 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ class FakeCrudder < SelectManager
5
+ class FakeEngine
6
+ attr_reader :calls, :connection_pool, :spec, :config
7
+
8
+ def initialize
9
+ @calls = []
10
+ @connection_pool = self
11
+ @spec = self
12
+ @config = { :adapter => 'sqlite3' }
13
+ end
14
+
15
+ def connection; self end
16
+
17
+ def method_missing name, *args
18
+ @calls << [name, args]
19
+ end
20
+ end
21
+
22
+ include Crud
23
+
24
+ attr_reader :engine
25
+ attr_accessor :ctx
26
+
27
+ def initialize engine = FakeEngine.new
28
+ super
29
+ end
30
+ end
31
+
32
+ describe 'crud' do
33
+ describe 'insert' do
34
+ it 'should call insert on the connection' do
35
+ table = Table.new :users
36
+ fc = FakeCrudder.new
37
+ fc.from table
38
+ fc.insert [[table[:id], 'foo']]
39
+ fc.engine.calls.find { |method, _|
40
+ method == :insert
41
+ }.wont_be_nil
42
+ end
43
+ end
44
+
45
+ describe 'update' do
46
+ it 'should call update on the connection' do
47
+ table = Table.new :users
48
+ fc = FakeCrudder.new
49
+ fc.from table
50
+ fc.update [[table[:id], 'foo']]
51
+ fc.engine.calls.find { |method, _|
52
+ method == :update
53
+ }.wont_be_nil
54
+ end
55
+ end
56
+
57
+ describe 'delete' do
58
+ it 'should call delete on the connection' do
59
+ table = Table.new :users
60
+ fc = FakeCrudder.new
61
+ fc.from table
62
+ fc.delete
63
+ fc.engine.calls.find { |method, _|
64
+ method == :delete
65
+ }.wont_be_nil
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,42 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ describe 'delete manager' do
5
+ describe 'new' do
6
+ it 'takes an engine' do
7
+ Arel::DeleteManager.new Table.engine
8
+ end
9
+ end
10
+
11
+ describe 'from' do
12
+ it 'uses from' do
13
+ table = Table.new(:users)
14
+ dm = Arel::DeleteManager.new Table.engine
15
+ dm.from table
16
+ dm.to_sql.must_be_like %{ DELETE FROM "users" }
17
+ end
18
+
19
+ it 'chains' do
20
+ table = Table.new(:users)
21
+ dm = Arel::DeleteManager.new Table.engine
22
+ dm.from(table).must_equal dm
23
+ end
24
+ end
25
+
26
+ describe 'where' do
27
+ it 'uses where values' do
28
+ table = Table.new(:users)
29
+ dm = Arel::DeleteManager.new Table.engine
30
+ dm.from table
31
+ dm.where table[:id].eq(10)
32
+ dm.to_sql.must_be_like %{ DELETE FROM "users" WHERE "users"."id" = 10}
33
+ end
34
+
35
+ it 'chains' do
36
+ table = Table.new(:users)
37
+ dm = Arel::DeleteManager.new Table.engine
38
+ dm.where(table[:id].eq(10)).must_equal dm
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,125 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ describe 'insert manager' do
5
+ describe 'new' do
6
+ it 'takes an engine' do
7
+ Arel::InsertManager.new Table.engine
8
+ end
9
+ end
10
+
11
+ describe 'insert' do
12
+ it "inserts false" do
13
+ table = Table.new(:users)
14
+ manager = Arel::InsertManager.new Table.engine
15
+
16
+ manager.insert [[table[:bool], false]]
17
+ manager.to_sql.must_be_like %{
18
+ INSERT INTO "users" ("bool") VALUES ('f')
19
+ }
20
+ end
21
+
22
+ it "inserts null" do
23
+ table = Table.new(:users)
24
+ manager = Arel::InsertManager.new Table.engine
25
+ manager.insert [[table[:id], nil]]
26
+ manager.to_sql.must_be_like %{
27
+ INSERT INTO "users" ("id") VALUES (NULL)
28
+ }
29
+ end
30
+
31
+ it "inserts time" do
32
+ table = Table.new(:users)
33
+ manager = Arel::InsertManager.new Table.engine
34
+
35
+ time = Time.now
36
+ attribute = table[:created_at]
37
+
38
+ manager.insert [[attribute, time]]
39
+ manager.to_sql.must_be_like %{
40
+ INSERT INTO "users" ("created_at") VALUES (#{Table.engine.connection.quote time})
41
+ }
42
+ end
43
+
44
+ it 'takes a list of lists' do
45
+ table = Table.new(:users)
46
+ manager = Arel::InsertManager.new Table.engine
47
+ manager.into table
48
+ manager.insert [[table[:id], 1], [table[:name], 'aaron']]
49
+ manager.to_sql.must_be_like %{
50
+ INSERT INTO "users" ("id", "name") VALUES (1, 'aaron')
51
+ }
52
+ end
53
+
54
+ it 'defaults the table' do
55
+ table = Table.new(:users)
56
+ manager = Arel::InsertManager.new Table.engine
57
+ manager.insert [[table[:id], 1], [table[:name], 'aaron']]
58
+ manager.to_sql.must_be_like %{
59
+ INSERT INTO "users" ("id", "name") VALUES (1, 'aaron')
60
+ }
61
+ end
62
+
63
+ it 'takes an empty list' do
64
+ manager = Arel::InsertManager.new Table.engine
65
+ manager.insert []
66
+ end
67
+ end
68
+
69
+ describe 'into' do
70
+ it 'takes an engine' do
71
+ manager = Arel::InsertManager.new Table.engine
72
+ manager.into(Table.new(:users)).must_equal manager
73
+ end
74
+
75
+ it 'converts to sql' do
76
+ table = Table.new :users
77
+ manager = Arel::InsertManager.new Table.engine
78
+ manager.into table
79
+ manager.to_sql.must_be_like %{
80
+ INSERT INTO "users"
81
+ }
82
+ end
83
+ end
84
+
85
+ describe 'columns' do
86
+ it "converts to sql" do
87
+ table = Table.new :users
88
+ manager = Arel::InsertManager.new Table.engine
89
+ manager.into table
90
+ manager.columns << table[:id]
91
+ manager.to_sql.must_be_like %{
92
+ INSERT INTO "users" ("id")
93
+ }
94
+ end
95
+ end
96
+
97
+ describe "values" do
98
+ it "converts to sql" do
99
+ table = Table.new :users
100
+ manager = Arel::InsertManager.new Table.engine
101
+ manager.into table
102
+
103
+ manager.values = Nodes::Values.new [1]
104
+ manager.to_sql.must_be_like %{
105
+ INSERT INTO "users" VALUES (1)
106
+ }
107
+ end
108
+ end
109
+
110
+ describe "combo" do
111
+ it "puts shit together" do
112
+ table = Table.new :users
113
+ manager = Arel::InsertManager.new Table.engine
114
+ manager.into table
115
+
116
+ manager.values = Nodes::Values.new [1, 'aaron']
117
+ manager.columns << table[:id]
118
+ manager.columns << table[:name]
119
+ manager.to_sql.must_be_like %{
120
+ INSERT INTO "users" ("id", "name") VALUES (1, 'aaron')
121
+ }
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,659 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ class EngineProxy
5
+ attr_reader :executed
6
+ attr_reader :connection_pool
7
+ attr_reader :spec
8
+ attr_reader :config
9
+
10
+ def initialize engine
11
+ @engine = engine
12
+ @executed = []
13
+ @connection_pool = self
14
+ @spec = self
15
+ @config = { :adapter => 'sqlite3' }
16
+ end
17
+
18
+ def with_connection
19
+ yield self
20
+ end
21
+
22
+ def connection
23
+ self
24
+ end
25
+
26
+ def quote_table_name thing; @engine.connection.quote_table_name thing end
27
+ def quote_column_name thing; @engine.connection.quote_column_name thing end
28
+ def quote thing, column; @engine.connection.quote thing, column end
29
+
30
+ def execute sql, name = nil, *args
31
+ @executed << sql
32
+ end
33
+ alias :update :execute
34
+ alias :delete :execute
35
+ alias :insert :execute
36
+ end
37
+
38
+ describe 'select manager' do
39
+ describe 'backwards compatibility' do
40
+ describe 'project' do
41
+ it 'accepts symbols as sql literals' do
42
+ table = Table.new :users
43
+ manager = Arel::SelectManager.new Table.engine
44
+ manager.project :id
45
+ manager.from table
46
+ manager.to_sql.must_be_like %{
47
+ SELECT id FROM "users"
48
+ }
49
+ end
50
+ end
51
+
52
+ describe 'order' do
53
+ it 'accepts symbols' do
54
+ table = Table.new :users
55
+ manager = Arel::SelectManager.new Table.engine
56
+ manager.project SqlLiteral.new '*'
57
+ manager.from table
58
+ manager.order :foo
59
+ manager.to_sql.must_be_like %{ SELECT * FROM "users" ORDER BY foo }
60
+ end
61
+ end
62
+
63
+ describe 'group' do
64
+ it 'takes a symbol' do
65
+ table = Table.new :users
66
+ manager = Arel::SelectManager.new Table.engine
67
+ manager.from table
68
+ manager.group :foo
69
+ manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo }
70
+ end
71
+ end
72
+
73
+ describe 'from' do
74
+ it 'ignores strings when table of same name exists' do
75
+ table = Table.new :users
76
+ manager = Arel::SelectManager.new Table.engine
77
+
78
+ manager.from table
79
+ manager.from 'users'
80
+ manager.project table['id']
81
+ manager.to_sql.must_be_like 'SELECT "users"."id" FROM users'
82
+ end
83
+ end
84
+
85
+ describe '#having' do
86
+ it 'converts strings to SQLLiterals' do
87
+ table = Table.new :users
88
+ mgr = table.from table
89
+ mgr.having 'foo'
90
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo }
91
+ end
92
+ end
93
+
94
+ describe 'on' do
95
+ it 'converts to sqlliterals' do
96
+ table = Table.new :users
97
+ right = table.alias
98
+ mgr = table.from table
99
+ mgr.join(right).on("omg")
100
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON omg }
101
+ end
102
+
103
+ it 'converts to sqlliterals' do
104
+ table = Table.new :users
105
+ right = table.alias
106
+ mgr = table.from table
107
+ mgr.join(right).on("omg", "123")
108
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON omg AND 123 }
109
+ end
110
+ end
111
+ end
112
+
113
+ describe 'clone' do
114
+ it 'creates new cores' do
115
+ table = Table.new :users, :engine => Table.engine, :as => 'foo'
116
+ mgr = table.from table
117
+ m2 = mgr.clone
118
+ m2.project "foo"
119
+ mgr.to_sql.wont_equal m2.to_sql
120
+ end
121
+ end
122
+
123
+ describe 'initialize' do
124
+ it 'uses alias in sql' do
125
+ table = Table.new :users, :engine => Table.engine, :as => 'foo'
126
+ mgr = table.from table
127
+ mgr.skip 10
128
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" "foo" OFFSET 10 }
129
+ end
130
+ end
131
+
132
+ describe 'skip' do
133
+ it 'should add an offset' do
134
+ table = Table.new :users
135
+ mgr = table.from table
136
+ mgr.skip 10
137
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 }
138
+ end
139
+
140
+ it 'should chain' do
141
+ table = Table.new :users
142
+ mgr = table.from table
143
+ mgr.skip(10).to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 }
144
+ end
145
+ end
146
+
147
+ describe 'exists' do
148
+ it 'should create an exists clause' do
149
+ table = Table.new(:users)
150
+ manager = Arel::SelectManager.new Table.engine, table
151
+ manager.project SqlLiteral.new '*'
152
+ m2 = Arel::SelectManager.new(manager.engine)
153
+ m2.project manager.exists
154
+ m2.to_sql.must_be_like %{ SELECT EXISTS (#{manager.to_sql}) }
155
+ end
156
+
157
+ it 'can be aliased' do
158
+ table = Table.new(:users)
159
+ manager = Arel::SelectManager.new Table.engine, table
160
+ manager.project SqlLiteral.new '*'
161
+ m2 = Arel::SelectManager.new(manager.engine)
162
+ m2.project manager.exists.as('foo')
163
+ m2.to_sql.must_be_like %{ SELECT EXISTS (#{manager.to_sql}) AS foo }
164
+ end
165
+ end
166
+
167
+ describe 'ast' do
168
+ it 'should return the ast' do
169
+ table = Table.new :users
170
+ mgr = table.from table
171
+ ast = mgr.ast
172
+ mgr.visitor.accept(ast).must_equal mgr.to_sql
173
+ end
174
+ end
175
+
176
+ describe 'taken' do
177
+ it 'should return limit' do
178
+ manager = Arel::SelectManager.new Table.engine
179
+ manager.take 10
180
+ manager.taken.must_equal 10
181
+ end
182
+ end
183
+
184
+ describe 'insert' do
185
+ it 'uses the select FROM' do
186
+ engine = EngineProxy.new Table.engine
187
+ table = Table.new :users
188
+ manager = Arel::SelectManager.new engine
189
+ manager.from table
190
+ manager.insert 'VALUES(NULL)'
191
+
192
+ engine.executed.last.must_be_like %{
193
+ INSERT INTO "users" VALUES(NULL)
194
+ }
195
+ end
196
+ end
197
+
198
+ describe 'lock' do
199
+ # This should fail on other databases
200
+ it 'adds a lock node' do
201
+ table = Table.new :users
202
+ mgr = table.from table
203
+ mgr.lock.to_sql.must_be_like %{ SELECT FROM "users" }
204
+ end
205
+ end
206
+
207
+ describe 'orders' do
208
+ it 'returns order clauses' do
209
+ table = Table.new :users
210
+ manager = Arel::SelectManager.new Table.engine
211
+ order = table[:id]
212
+ manager.order table[:id]
213
+ manager.orders.must_equal [order]
214
+ end
215
+ end
216
+
217
+ describe 'order' do
218
+ it 'generates order clauses' do
219
+ table = Table.new :users
220
+ manager = Arel::SelectManager.new Table.engine
221
+ manager.project SqlLiteral.new '*'
222
+ manager.from table
223
+ manager.order table[:id]
224
+ manager.to_sql.must_be_like %{
225
+ SELECT * FROM "users" ORDER BY "users"."id"
226
+ }
227
+ end
228
+
229
+ # FIXME: I would like to deprecate this
230
+ it 'takes *args' do
231
+ table = Table.new :users
232
+ manager = Arel::SelectManager.new Table.engine
233
+ manager.project SqlLiteral.new '*'
234
+ manager.from table
235
+ manager.order table[:id], table[:name]
236
+ manager.to_sql.must_be_like %{
237
+ SELECT * FROM "users" ORDER BY "users"."id", "users"."name"
238
+ }
239
+ end
240
+
241
+ it 'chains' do
242
+ table = Table.new :users
243
+ manager = Arel::SelectManager.new Table.engine
244
+ manager.order(table[:id]).must_equal manager
245
+ end
246
+ end
247
+
248
+ describe 'on' do
249
+ it 'takes two params' do
250
+ left = Table.new :users
251
+ right = left.alias
252
+ predicate = left[:id].eq(right[:id])
253
+ manager = Arel::SelectManager.new Table.engine
254
+
255
+ manager.from left
256
+ manager.join(right).on(predicate, predicate)
257
+ manager.to_sql.must_be_like %{
258
+ SELECT FROM "users"
259
+ INNER JOIN "users" "users_2"
260
+ ON "users"."id" = "users_2"."id" AND
261
+ "users"."id" = "users_2"."id"
262
+ }
263
+ end
264
+
265
+ it 'takes three params' do
266
+ left = Table.new :users
267
+ right = left.alias
268
+ predicate = left[:id].eq(right[:id])
269
+ manager = Arel::SelectManager.new Table.engine
270
+
271
+ manager.from left
272
+ manager.join(right).on(
273
+ predicate,
274
+ predicate,
275
+ left[:name].eq(right[:name])
276
+ )
277
+ manager.to_sql.must_be_like %{
278
+ SELECT FROM "users"
279
+ INNER JOIN "users" "users_2"
280
+ ON "users"."id" = "users_2"."id" AND
281
+ "users"."id" = "users_2"."id" AND
282
+ "users"."name" = "users_2"."name"
283
+ }
284
+ end
285
+ end
286
+
287
+ describe 'join' do
288
+ it 'responds to join' do
289
+ left = Table.new :users
290
+ right = left.alias
291
+ predicate = left[:id].eq(right[:id])
292
+ manager = Arel::SelectManager.new Table.engine
293
+
294
+ manager.from left
295
+ manager.join(right).on(predicate)
296
+ manager.to_sql.must_be_like %{
297
+ SELECT FROM "users"
298
+ INNER JOIN "users" "users_2"
299
+ ON "users"."id" = "users_2"."id"
300
+ }
301
+ end
302
+
303
+ it 'takes a class' do
304
+ left = Table.new :users
305
+ right = left.alias
306
+ predicate = left[:id].eq(right[:id])
307
+ manager = Arel::SelectManager.new Table.engine
308
+
309
+ manager.from left
310
+ manager.join(right, Nodes::OuterJoin).on(predicate)
311
+ manager.to_sql.must_be_like %{
312
+ SELECT FROM "users"
313
+ LEFT OUTER JOIN "users" "users_2"
314
+ ON "users"."id" = "users_2"."id"
315
+ }
316
+ end
317
+
318
+ it 'noops on nil' do
319
+ manager = Arel::SelectManager.new Table.engine
320
+ manager.join(nil).must_equal manager
321
+ end
322
+ end
323
+
324
+ describe 'joins' do
325
+ it 'returns join sql' do
326
+ table = Table.new :users
327
+ aliaz = table.alias
328
+ manager = Arel::SelectManager.new Table.engine
329
+ manager.from Nodes::InnerJoin.new(table, aliaz, table[:id].eq(aliaz[:id]))
330
+ manager.join_sql.must_be_like %{
331
+ INNER JOIN "users" "users_2" "users"."id" = "users_2"."id"
332
+ }
333
+ manager.joins(manager).must_equal manager.join_sql
334
+ end
335
+
336
+ it 'returns outer join sql' do
337
+ table = Table.new :users
338
+ aliaz = table.alias
339
+ manager = Arel::SelectManager.new Table.engine
340
+ manager.from Nodes::OuterJoin.new(table, aliaz, table[:id].eq(aliaz[:id]))
341
+ manager.join_sql.must_be_like %{
342
+ LEFT OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id"
343
+ }
344
+ manager.joins(manager).must_equal manager.join_sql
345
+ end
346
+
347
+ it 'returns string join sql' do
348
+ table = Table.new :users
349
+ manager = Arel::SelectManager.new Table.engine
350
+ manager.from Nodes::StringJoin.new(table, 'hello')
351
+ manager.join_sql.must_be_like %{ 'hello' }
352
+ manager.joins(manager).must_equal manager.join_sql
353
+ end
354
+
355
+ it 'returns nil join sql' do
356
+ manager = Arel::SelectManager.new Table.engine
357
+ manager.join_sql.must_be_nil
358
+ end
359
+ end
360
+
361
+ describe 'order_clauses' do
362
+ it 'returns order clauses as a list' do
363
+ table = Table.new :users
364
+ manager = Arel::SelectManager.new Table.engine
365
+ manager.from table
366
+ manager.order table[:id]
367
+ manager.order_clauses.first.must_be_like %{ "users"."id" }
368
+ end
369
+ end
370
+
371
+ describe 'group' do
372
+ it 'takes an attribute' do
373
+ table = Table.new :users
374
+ manager = Arel::SelectManager.new Table.engine
375
+ manager.from table
376
+ manager.group table[:id]
377
+ manager.to_sql.must_be_like %{
378
+ SELECT FROM "users" GROUP BY "users"."id"
379
+ }
380
+ end
381
+
382
+ it 'chains' do
383
+ table = Table.new :users
384
+ manager = Arel::SelectManager.new Table.engine
385
+ manager.group(table[:id]).must_equal manager
386
+ end
387
+
388
+ it 'takes multiple args' do
389
+ table = Table.new :users
390
+ manager = Arel::SelectManager.new Table.engine
391
+ manager.from table
392
+ manager.group table[:id], table[:name]
393
+ manager.to_sql.must_be_like %{
394
+ SELECT FROM "users" GROUP BY "users"."id", "users"."name"
395
+ }
396
+ end
397
+
398
+ # FIXME: backwards compat
399
+ it 'makes strings literals' do
400
+ table = Table.new :users
401
+ manager = Arel::SelectManager.new Table.engine
402
+ manager.from table
403
+ manager.group 'foo'
404
+ manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo }
405
+ end
406
+ end
407
+
408
+ describe 'delete' do
409
+ it "copies from" do
410
+ engine = EngineProxy.new Table.engine
411
+ table = Table.new :users
412
+ manager = Arel::SelectManager.new engine
413
+ manager.from table
414
+ manager.delete
415
+
416
+ engine.executed.last.must_be_like %{ DELETE FROM "users" }
417
+ end
418
+
419
+ it "copies where" do
420
+ engine = EngineProxy.new Table.engine
421
+ table = Table.new :users
422
+ manager = Arel::SelectManager.new engine
423
+ manager.from table
424
+ manager.where table[:id].eq 10
425
+ manager.delete
426
+
427
+ engine.executed.last.must_be_like %{
428
+ DELETE FROM "users" WHERE "users"."id" = 10
429
+ }
430
+ end
431
+ end
432
+
433
+ describe 'where_sql' do
434
+ it 'gives me back the where sql' do
435
+ table = Table.new :users
436
+ manager = Arel::SelectManager.new Table.engine
437
+ manager.from table
438
+ manager.where table[:id].eq 10
439
+ manager.where_sql.must_be_like %{ WHERE "users"."id" = 10 }
440
+ end
441
+
442
+ it 'returns nil when there are no wheres' do
443
+ table = Table.new :users
444
+ manager = Arel::SelectManager.new Table.engine
445
+ manager.from table
446
+ manager.where_sql.must_be_nil
447
+ end
448
+ end
449
+
450
+ describe 'update' do
451
+ it 'copies limits' do
452
+ engine = EngineProxy.new Table.engine
453
+ table = Table.new :users
454
+ manager = Arel::SelectManager.new engine
455
+ manager.from table
456
+ manager.take 1
457
+ manager.update(SqlLiteral.new('foo = bar'))
458
+
459
+ engine.executed.last.must_be_like %{
460
+ UPDATE "users" SET foo = bar
461
+ WHERE "users"."id" IN (SELECT "users"."id" FROM "users" LIMIT 1)
462
+ }
463
+ end
464
+
465
+ it 'copies order' do
466
+ engine = EngineProxy.new Table.engine
467
+ table = Table.new :users
468
+ manager = Arel::SelectManager.new engine
469
+ manager.from table
470
+ manager.order :foo
471
+ manager.update(SqlLiteral.new('foo = bar'))
472
+
473
+ engine.executed.last.must_be_like %{
474
+ UPDATE "users" SET foo = bar
475
+ WHERE "users"."id" IN (SELECT "users"."id" FROM "users" ORDER BY foo)
476
+ }
477
+ end
478
+
479
+ it 'takes a string' do
480
+ engine = EngineProxy.new Table.engine
481
+ table = Table.new :users
482
+ manager = Arel::SelectManager.new engine
483
+ manager.from table
484
+ manager.update(SqlLiteral.new('foo = bar'))
485
+
486
+ engine.executed.last.must_be_like %{ UPDATE "users" SET foo = bar }
487
+ end
488
+
489
+ it 'copies where clauses' do
490
+ engine = EngineProxy.new Table.engine
491
+ table = Table.new :users
492
+ manager = Arel::SelectManager.new engine
493
+ manager.where table[:id].eq 10
494
+ manager.from table
495
+ manager.update(table[:id] => 1)
496
+
497
+ engine.executed.last.must_be_like %{
498
+ UPDATE "users" SET "id" = 1 WHERE "users"."id" = 10
499
+ }
500
+ end
501
+
502
+ it 'executes an update statement' do
503
+ engine = EngineProxy.new Table.engine
504
+ table = Table.new :users
505
+ manager = Arel::SelectManager.new engine
506
+ manager.from table
507
+ manager.update(table[:id] => 1)
508
+
509
+ engine.executed.last.must_be_like %{
510
+ UPDATE "users" SET "id" = 1
511
+ }
512
+ end
513
+ end
514
+
515
+ describe 'project' do
516
+ it 'takes multiple args' do
517
+ manager = Arel::SelectManager.new Table.engine
518
+ manager.project Nodes::SqlLiteral.new('foo'),
519
+ Nodes::SqlLiteral.new('bar')
520
+ manager.to_sql.must_be_like %{ SELECT foo, bar }
521
+ end
522
+
523
+ it 'takes strings' do
524
+ manager = Arel::SelectManager.new Table.engine
525
+ manager.project Nodes::SqlLiteral.new('*')
526
+ manager.to_sql.must_be_like %{ SELECT * }
527
+ end
528
+
529
+ it "takes sql literals" do
530
+ manager = Arel::SelectManager.new Table.engine
531
+ manager.project Nodes::SqlLiteral.new '*'
532
+ manager.to_sql.must_be_like %{
533
+ SELECT *
534
+ }
535
+ end
536
+ end
537
+
538
+ describe 'take' do
539
+ it "knows take" do
540
+ table = Table.new :users
541
+ manager = Arel::SelectManager.new Table.engine
542
+ manager.from(table).project(table['id'])
543
+ manager.where(table['id'].eq(1))
544
+ manager.take 1
545
+
546
+ manager.to_sql.must_be_like %{
547
+ SELECT "users"."id"
548
+ FROM "users"
549
+ WHERE "users"."id" = 1
550
+ LIMIT 1
551
+ }
552
+ end
553
+
554
+ it "chains" do
555
+ manager = Arel::SelectManager.new Table.engine
556
+ manager.take(1).must_equal manager
557
+ end
558
+ end
559
+
560
+ describe 'where' do
561
+ it "knows where" do
562
+ table = Table.new :users
563
+ manager = Arel::SelectManager.new Table.engine
564
+ manager.from(table).project(table['id'])
565
+ manager.where(table['id'].eq(1))
566
+ manager.to_sql.must_be_like %{
567
+ SELECT "users"."id"
568
+ FROM "users"
569
+ WHERE "users"."id" = 1
570
+ }
571
+ end
572
+
573
+ it "chains" do
574
+ table = Table.new :users
575
+ manager = Arel::SelectManager.new Table.engine
576
+ manager.from(table)
577
+ manager.project(table['id']).where(table['id'].eq 1).must_equal manager
578
+ end
579
+ end
580
+
581
+ describe "join" do
582
+ it "joins itself" do
583
+ left = Table.new :users
584
+ right = left.alias
585
+ predicate = left[:id].eq(right[:id])
586
+
587
+ mgr = left.join(right)
588
+ mgr.project Nodes::SqlLiteral.new('*')
589
+ mgr.on(predicate).must_equal mgr
590
+
591
+ mgr.to_sql.must_be_like %{
592
+ SELECT * FROM "users"
593
+ INNER JOIN "users" "users_2"
594
+ ON "users"."id" = "users_2"."id"
595
+ }
596
+ end
597
+ end
598
+
599
+ describe 'from' do
600
+ it "makes sql" do
601
+ table = Table.new :users
602
+ manager = Arel::SelectManager.new Table.engine
603
+
604
+ manager.from table
605
+ manager.project table['id']
606
+ manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"'
607
+ end
608
+
609
+ it "chains" do
610
+ table = Table.new :users
611
+ manager = Arel::SelectManager.new Table.engine
612
+ manager.from(table).project(table['id']).must_equal manager
613
+ manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"'
614
+ end
615
+ end
616
+ end
617
+
618
+ describe 'set operations' do
619
+ before do
620
+ @table = Table.new :users
621
+ @m1 = Arel::SelectManager.new Table.engine, @table
622
+ @m1.project Arel.sql('*')
623
+ @m2 = Arel::SelectManager.new Table.engine, @table
624
+ @m2.project Arel.sql('*')
625
+ end
626
+
627
+ it 'supports union' do
628
+ @m1.where(@table[:id].lt(18))
629
+ @m2.where(@table[:id].gt(99))
630
+ (@m1.union @m2).to_sql.must_be_like %{
631
+ ( SELECT * FROM "users" WHERE "users"."id" < 18 UNION SELECT * FROM "users" WHERE "users"."id" > 99 )
632
+ }
633
+ end
634
+
635
+ it 'supports union all' do
636
+ @m1.where(@table[:id].lt(18))
637
+ @m2.where(@table[:id].gt(99))
638
+ (@m1.union :all, @m2).to_sql.must_be_like %{
639
+ ( SELECT * FROM "users" WHERE "users"."id" < 18 UNION ALL SELECT * FROM "users" WHERE "users"."id" > 99 )
640
+ }
641
+ end
642
+
643
+ it 'supports intersect' do
644
+ @m1.where(@table[:id].gt(18))
645
+ @m2.where(@table[:id].lt(99))
646
+ (@m1.intersect @m2).to_sql.must_be_like %{
647
+ ( SELECT * FROM "users" WHERE "users"."id" > 18 INTERSECT SELECT * FROM "users" WHERE "users"."id" < 99 )
648
+ }
649
+ end
650
+
651
+ it 'supports except' do
652
+ @m1.where(@table[:id].in(18..60))
653
+ @m2.where(@table[:id].in(40..99))
654
+ (@m1.except @m2).to_sql.must_be_like %{
655
+ ( SELECT * FROM "users" WHERE "users"."id" BETWEEN 18 AND 60 EXCEPT SELECT * FROM "users" WHERE "users"."id" BETWEEN 40 AND 99 )
656
+ }
657
+ end
658
+ end
659
+ end