square-arel 2.0.9.20110222133018

Sign up to get free protection for your applications and to get access to all the features.
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,193 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ describe Table do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ end
8
+
9
+ describe 'skip' do
10
+ it 'should add an offset' do
11
+ sm = @relation.skip 2
12
+ sm.to_sql.must_be_like "SELECT FROM \"users\" OFFSET 2"
13
+ end
14
+ end
15
+
16
+ describe 'primary_key' do
17
+ it 'should return an attribute' do
18
+ @relation.primary_key.name.must_equal :id
19
+ end
20
+ end
21
+
22
+ describe 'select_manager' do
23
+ it 'should return an empty select manager' do
24
+ sm = @relation.select_manager
25
+ sm.to_sql.must_be_like 'SELECT'
26
+ end
27
+ end
28
+
29
+ describe 'having' do
30
+ it 'adds a having clause' do
31
+ mgr = @relation.having @relation[:id].eq(10)
32
+ mgr.to_sql.must_be_like %{
33
+ SELECT FROM "users" HAVING "users"."id" = 10
34
+ }
35
+ end
36
+ end
37
+
38
+ describe 'backwards compat' do
39
+ describe 'joins' do
40
+ it 'returns nil' do
41
+ @relation.joins(nil).must_equal nil
42
+ end
43
+ end
44
+
45
+ describe 'join' do
46
+ it 'noops on nil' do
47
+ mgr = @relation.join nil
48
+
49
+ mgr.to_sql.must_be_like %{ SELECT FROM "users" }
50
+ end
51
+
52
+ it 'takes a second argument for join type' do
53
+ right = @relation.alias
54
+ predicate = @relation[:id].eq(right[:id])
55
+ mgr = @relation.join(right, Nodes::OuterJoin).on(predicate)
56
+
57
+ mgr.to_sql.must_be_like %{
58
+ SELECT FROM "users"
59
+ LEFT OUTER JOIN "users" "users_2"
60
+ ON "users"."id" = "users_2"."id"
61
+ }
62
+ end
63
+ end
64
+ end
65
+
66
+ describe 'group' do
67
+ it 'should create a group' do
68
+ manager = @relation.group @relation[:id]
69
+ manager.to_sql.must_be_like %{
70
+ SELECT FROM "users" GROUP BY "users"."id"
71
+ }
72
+ end
73
+ end
74
+
75
+ describe 'alias' do
76
+ it 'should create a node that proxies to a table' do
77
+ @relation.aliases.must_equal []
78
+
79
+ node = @relation.alias
80
+ @relation.aliases.must_equal [node]
81
+ node.name.must_equal 'users_2'
82
+ node[:id].relation.must_equal node
83
+ end
84
+ end
85
+
86
+ describe 'new' do
87
+ it 'takes :columns' do
88
+ columns = Table.engine.connection.columns("users")
89
+ @relation = Table.new(:users, :columns => columns)
90
+ @relation.columns.first.name.must_equal :id
91
+ @relation.engine.must_equal Table.engine
92
+ end
93
+
94
+ it 'should accept an engine' do
95
+ rel = Table.new :users, 'foo'
96
+ rel.engine.must_equal 'foo'
97
+ end
98
+
99
+ it 'should accept a hash' do
100
+ rel = Table.new :users, :engine => 'foo'
101
+ rel.engine.must_equal 'foo'
102
+ end
103
+
104
+ it 'ignores as if it equals name' do
105
+ rel = Table.new :users, :as => 'users'
106
+ rel.table_alias.must_be_nil
107
+ end
108
+ end
109
+
110
+ describe 'order' do
111
+ it "should take an order" do
112
+ manager = @relation.order "foo"
113
+ manager.to_sql.must_be_like %{ SELECT FROM "users" ORDER BY foo }
114
+ end
115
+ end
116
+
117
+ describe 'take' do
118
+ it "should add a limit" do
119
+ manager = @relation.take 1
120
+ manager.project SqlLiteral.new '*'
121
+ manager.to_sql.must_be_like %{ SELECT * FROM "users" LIMIT 1 }
122
+ end
123
+ end
124
+
125
+ describe 'project' do
126
+ it 'can project' do
127
+ manager = @relation.project SqlLiteral.new '*'
128
+ manager.to_sql.must_be_like %{ SELECT * FROM "users" }
129
+ end
130
+
131
+ it 'takes multiple parameters' do
132
+ manager = @relation.project SqlLiteral.new('*'), SqlLiteral.new('*')
133
+ manager.to_sql.must_be_like %{ SELECT *, * FROM "users" }
134
+ end
135
+ end
136
+
137
+ describe 'where' do
138
+ it "returns a tree manager" do
139
+ manager = @relation.where @relation[:id].eq 1
140
+ manager.project @relation[:id]
141
+ manager.must_be_kind_of TreeManager
142
+ manager.to_sql.must_be_like %{
143
+ SELECT "users"."id"
144
+ FROM "users"
145
+ WHERE "users"."id" = 1
146
+ }
147
+ end
148
+ end
149
+
150
+ describe 'columns' do
151
+ it 'returns a list of columns' do
152
+ columns = @relation.columns
153
+ columns.length.must_equal 4
154
+ columns.map { |x| x.name.to_s }.sort.must_equal %w{ created_at bool name id }.sort
155
+ end
156
+ end
157
+
158
+ it "should have a name" do
159
+ @relation.name.must_equal 'users'
160
+ end
161
+
162
+ it "should have an engine" do
163
+ @relation.engine.must_equal Table.engine
164
+ end
165
+
166
+ describe '[]' do
167
+ describe 'when given a Symbol' do
168
+ it "manufactures an attribute if the symbol names an attribute within the relation" do
169
+ column = @relation[:id]
170
+ column.name.must_equal :id
171
+ column.must_be_kind_of Attributes::Integer
172
+ end
173
+ end
174
+
175
+ describe 'when table does not exist' do
176
+ it 'returns nil' do
177
+ @relation[:foooo].must_be_nil
178
+ end
179
+ end
180
+ end
181
+ end
182
+
183
+ describe Table do
184
+ describe 'when checking the existence of a table' do
185
+ it 'should be present in the table cache despite the class of its name' do
186
+ [ 'users', :users ].each do |name|
187
+ relation = Table.new name
188
+ Table.table_cache(relation.engine).key?(relation.name).must_equal true
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,86 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ describe 'update manager' do
5
+ describe 'new' do
6
+ it 'takes an engine' do
7
+ Arel::UpdateManager.new Table.engine
8
+ end
9
+ end
10
+
11
+ it 'handles limit properly' do
12
+ table = Table.new(:users)
13
+ um = Arel::UpdateManager.new Table.engine
14
+ um.take 10
15
+ um.table table
16
+ um.set [[table[:name], nil]]
17
+ assert_match(/LIMIT 10/, um.to_sql)
18
+ end
19
+
20
+ describe 'set' do
21
+ it "updates with null" do
22
+ table = Table.new(:users)
23
+ um = Arel::UpdateManager.new Table.engine
24
+ um.table table
25
+ um.set [[table[:name], nil]]
26
+ um.to_sql.must_be_like %{ UPDATE "users" SET "name" = NULL }
27
+ end
28
+
29
+ it 'takes a string' do
30
+ table = Table.new(:users)
31
+ um = Arel::UpdateManager.new Table.engine
32
+ um.table table
33
+ um.set Nodes::SqlLiteral.new "foo = bar"
34
+ um.to_sql.must_be_like %{ UPDATE "users" SET foo = bar }
35
+ end
36
+
37
+ it 'takes a list of lists' do
38
+ table = Table.new(:users)
39
+ um = Arel::UpdateManager.new Table.engine
40
+ um.table table
41
+ um.set [[table[:id], 1], [table[:name], 'hello']]
42
+ um.to_sql.must_be_like %{
43
+ UPDATE "users" SET "id" = 1, "name" = 'hello'
44
+ }
45
+ end
46
+
47
+ it 'chains' do
48
+ table = Table.new(:users)
49
+ um = Arel::UpdateManager.new Table.engine
50
+ um.set([[table[:id], 1], [table[:name], 'hello']]).must_equal um
51
+ end
52
+ end
53
+
54
+ describe 'table' do
55
+ it 'generates an update statement' do
56
+ um = Arel::UpdateManager.new Table.engine
57
+ um.table Table.new(:users)
58
+ um.to_sql.must_be_like %{ UPDATE "users" }
59
+ end
60
+
61
+ it 'chains' do
62
+ um = Arel::UpdateManager.new Table.engine
63
+ um.table(Table.new(:users)).must_equal um
64
+ end
65
+ end
66
+
67
+ describe 'where' do
68
+ it 'generates a where clause' do
69
+ table = Table.new :users
70
+ um = Arel::UpdateManager.new Table.engine
71
+ um.table table
72
+ um.where table[:id].eq(1)
73
+ um.to_sql.must_be_like %{
74
+ UPDATE "users" WHERE "users"."id" = 1
75
+ }
76
+ end
77
+
78
+ it 'chains' do
79
+ table = Table.new :users
80
+ um = Arel::UpdateManager.new Table.engine
81
+ um.table table
82
+ um.where(table[:id].eq(1)).must_equal um
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,212 @@
1
+ require 'helper'
2
+
3
+ module Arel
4
+ module Visitors
5
+ class TestDepthFirst < MiniTest::Unit::TestCase
6
+ Collector = Struct.new(:calls) do
7
+ def call object
8
+ calls << object
9
+ end
10
+ end
11
+
12
+ def setup
13
+ @collector = Collector.new []
14
+ @visitor = Visitors::DepthFirst.new @collector
15
+ end
16
+
17
+ def test_raises_with_object
18
+ assert_raises(TypeError) do
19
+ @visitor.accept(Object.new)
20
+ end
21
+ end
22
+
23
+
24
+ # unary ops
25
+ [
26
+ Arel::Nodes::Not,
27
+ Arel::Nodes::Group,
28
+ Arel::Nodes::On,
29
+ Arel::Nodes::Grouping,
30
+ Arel::Nodes::Offset,
31
+ Arel::Nodes::Having,
32
+ Arel::Nodes::UnqualifiedColumn,
33
+ Arel::Nodes::Top,
34
+ Arel::Nodes::Limit,
35
+ ].each do |klass|
36
+ define_method("test_#{klass.name.gsub('::', '_')}") do
37
+ op = klass.new(:a)
38
+ @visitor.accept op
39
+ assert_equal [:a, op], @collector.calls
40
+ end
41
+ end
42
+
43
+ # functions
44
+ [
45
+ Arel::Nodes::Exists,
46
+ Arel::Nodes::Avg,
47
+ Arel::Nodes::Min,
48
+ Arel::Nodes::Max,
49
+ Arel::Nodes::Sum,
50
+ ].each do |klass|
51
+ define_method("test_#{klass.name.gsub('::', '_')}") do
52
+ func = klass.new(:a, :b)
53
+ @visitor.accept func
54
+ assert_equal [:a, :b, func], @collector.calls
55
+ end
56
+ end
57
+
58
+ def test_lock
59
+ lock = Nodes::Lock.new true
60
+ @visitor.accept lock
61
+ assert_equal [lock], @collector.calls
62
+ end
63
+
64
+ def test_count
65
+ count = Nodes::Count.new :a, :b, :c
66
+ @visitor.accept count
67
+ assert_equal [:a, :c, :b, count], @collector.calls
68
+ end
69
+
70
+ def test_inner_join
71
+ join = Nodes::InnerJoin.new :a, :b, :c
72
+ @visitor.accept join
73
+ assert_equal [:a, :b, :c, join], @collector.calls
74
+ end
75
+
76
+ def test_outer_join
77
+ join = Nodes::OuterJoin.new :a, :b, :c
78
+ @visitor.accept join
79
+ assert_equal [:a, :b, :c, join], @collector.calls
80
+ end
81
+
82
+ [
83
+ Arel::Nodes::And,
84
+ Arel::Nodes::Assignment,
85
+ Arel::Nodes::Between,
86
+ Arel::Nodes::DoesNotMatch,
87
+ Arel::Nodes::Equality,
88
+ Arel::Nodes::GreaterThan,
89
+ Arel::Nodes::GreaterThanOrEqual,
90
+ Arel::Nodes::In,
91
+ Arel::Nodes::LessThan,
92
+ Arel::Nodes::LessThanOrEqual,
93
+ Arel::Nodes::Matches,
94
+ Arel::Nodes::NotEqual,
95
+ Arel::Nodes::NotIn,
96
+ Arel::Nodes::Or,
97
+ Arel::Nodes::StringJoin,
98
+ Arel::Nodes::TableAlias,
99
+ Arel::Nodes::Values,
100
+ Arel::Nodes::As,
101
+ Arel::Nodes::DeleteStatement,
102
+ Arel::Nodes::Ordering,
103
+ ].each do |klass|
104
+ define_method("test_#{klass.name.gsub('::', '_')}") do
105
+ binary = klass.new(:a, :b)
106
+ @visitor.accept binary
107
+ assert_equal [:a, :b, binary], @collector.calls
108
+ end
109
+ end
110
+
111
+ [
112
+ Arel::Attributes::Integer,
113
+ Arel::Attributes::Float,
114
+ Arel::Attributes::String,
115
+ Arel::Attributes::Time,
116
+ Arel::Attributes::Boolean,
117
+ Arel::Attributes::Attribute
118
+ ].each do |klass|
119
+ define_method("test_#{klass.name.gsub('::', '_')}") do
120
+ binary = klass.new(:a, :b)
121
+ @visitor.accept binary
122
+ assert_equal [:a, :b, binary], @collector.calls
123
+ end
124
+ end
125
+
126
+ def test_table
127
+ relation = Arel::Table.new(:users)
128
+ @visitor.accept relation
129
+ assert_equal ['users', relation], @collector.calls
130
+ end
131
+
132
+ def test_array
133
+ node = Nodes::Or.new(:a, :b)
134
+ list = [node]
135
+ @visitor.accept list
136
+ assert_equal [:a, :b, node, list], @collector.calls
137
+ end
138
+
139
+ def test_hash
140
+ node = Nodes::Or.new(:a, :b)
141
+ hash = { node => node }
142
+ @visitor.accept hash
143
+ assert_equal [:a, :b, node, :a, :b, node, hash], @collector.calls
144
+ end
145
+
146
+ def test_update_statement
147
+ stmt = Nodes::UpdateStatement.new
148
+ stmt.relation = :a
149
+ stmt.values << :b
150
+ stmt.wheres << :c
151
+ stmt.orders << :d
152
+ stmt.limit = :e
153
+
154
+ @visitor.accept stmt
155
+ assert_equal [:a, :b, stmt.values, :c, stmt.wheres, :d, stmt.orders,
156
+ :e, stmt], @collector.calls
157
+ end
158
+
159
+ def test_select_core
160
+ core = Nodes::SelectCore.new
161
+ core.projections << :a
162
+ core.froms = :b
163
+ core.wheres << :c
164
+ core.groups << :d
165
+ core.having = :e
166
+
167
+ @visitor.accept core
168
+ assert_equal [
169
+ :a, core.projections,
170
+ :b,
171
+ :c, core.wheres,
172
+ :d, core.groups,
173
+ :e,
174
+ core], @collector.calls
175
+ end
176
+
177
+ def test_select_statement
178
+ ss = Nodes::SelectStatement.new
179
+ ss.cores.replace [:a]
180
+ ss.orders << :b
181
+ ss.limit = :c
182
+ ss.lock = :d
183
+ ss.offset = :e
184
+
185
+ @visitor.accept ss
186
+ assert_equal [
187
+ :a, ss.cores,
188
+ :b, ss.orders,
189
+ :c,
190
+ :d,
191
+ :e,
192
+ ss], @collector.calls
193
+ end
194
+
195
+ def test_insert_statement
196
+ stmt = Nodes::InsertStatement.new
197
+ stmt.relation = :a
198
+ stmt.columns << :b
199
+ stmt.values = :c
200
+
201
+ @visitor.accept stmt
202
+ assert_equal [:a, :b, stmt.columns, :c, stmt], @collector.calls
203
+ end
204
+
205
+ def test_node
206
+ node = Nodes::Node.new
207
+ @visitor.accept node
208
+ assert_equal [node], @collector.calls
209
+ end
210
+ end
211
+ end
212
+ end