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,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