arel 5.0.1.20140414130214 → 9.0.0

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 (153) hide show
  1. checksums.yaml +4 -4
  2. data/History.txt +44 -4
  3. data/MIT-LICENSE.txt +2 -1
  4. data/README.md +295 -0
  5. data/lib/arel/alias_predication.rb +1 -0
  6. data/lib/arel/attributes/attribute.rb +9 -0
  7. data/lib/arel/attributes.rb +1 -0
  8. data/lib/arel/collectors/bind.rb +24 -0
  9. data/lib/arel/collectors/composite.rb +32 -0
  10. data/lib/arel/collectors/plain_string.rb +19 -0
  11. data/lib/arel/collectors/sql_string.rb +24 -0
  12. data/lib/arel/collectors/substitute_binds.rb +28 -0
  13. data/lib/arel/compatibility/wheres.rb +1 -0
  14. data/lib/arel/crud.rb +5 -3
  15. data/lib/arel/delete_manager.rb +7 -1
  16. data/lib/arel/errors.rb +8 -0
  17. data/lib/arel/expressions.rb +6 -4
  18. data/lib/arel/factory_methods.rb +2 -1
  19. data/lib/arel/insert_manager.rb +12 -2
  20. data/lib/arel/math.rb +25 -0
  21. data/lib/arel/nodes/and.rb +2 -5
  22. data/lib/arel/nodes/ascending.rb +1 -0
  23. data/lib/arel/nodes/binary.rb +2 -3
  24. data/lib/arel/nodes/bind_param.rb +27 -0
  25. data/lib/arel/nodes/case.rb +58 -0
  26. data/lib/arel/nodes/casted.rb +45 -0
  27. data/lib/arel/nodes/count.rb +3 -0
  28. data/lib/arel/nodes/delete_statement.rb +3 -0
  29. data/lib/arel/nodes/descending.rb +1 -0
  30. data/lib/arel/nodes/equality.rb +1 -0
  31. data/lib/arel/nodes/extract.rb +5 -13
  32. data/lib/arel/nodes/false.rb +2 -0
  33. data/lib/arel/nodes/full_outer_join.rb +7 -0
  34. data/lib/arel/nodes/function.rb +4 -1
  35. data/lib/arel/nodes/grouping.rb +1 -0
  36. data/lib/arel/nodes/in.rb +1 -0
  37. data/lib/arel/nodes/infix_operation.rb +37 -1
  38. data/lib/arel/nodes/inner_join.rb +1 -0
  39. data/lib/arel/nodes/insert_statement.rb +6 -2
  40. data/lib/arel/nodes/join_source.rb +1 -0
  41. data/lib/arel/nodes/matches.rb +17 -0
  42. data/lib/arel/nodes/named_function.rb +1 -0
  43. data/lib/arel/nodes/node.rb +6 -1
  44. data/lib/arel/nodes/outer_join.rb +1 -0
  45. data/lib/arel/nodes/over.rb +1 -0
  46. data/lib/arel/nodes/regexp.rb +15 -0
  47. data/lib/arel/nodes/right_outer_join.rb +7 -0
  48. data/lib/arel/nodes/select_core.rb +6 -5
  49. data/lib/arel/nodes/select_statement.rb +1 -0
  50. data/lib/arel/nodes/sql_literal.rb +1 -3
  51. data/lib/arel/nodes/string_join.rb +1 -0
  52. data/lib/arel/nodes/table_alias.rb +7 -2
  53. data/lib/arel/nodes/terminal.rb +2 -0
  54. data/lib/arel/nodes/true.rb +2 -0
  55. data/lib/arel/nodes/unary.rb +7 -3
  56. data/lib/arel/nodes/unary_operation.rb +26 -0
  57. data/lib/arel/nodes/unqualified_column.rb +1 -0
  58. data/lib/arel/nodes/update_statement.rb +1 -0
  59. data/lib/arel/nodes/values.rb +1 -0
  60. data/lib/arel/nodes/values_list.rb +23 -0
  61. data/lib/arel/nodes/window.rb +25 -5
  62. data/lib/arel/nodes/with.rb +1 -0
  63. data/lib/arel/nodes.rb +13 -0
  64. data/lib/arel/order_predications.rb +1 -0
  65. data/lib/arel/predications.rb +115 -55
  66. data/lib/arel/select_manager.rb +26 -40
  67. data/lib/arel/table.rb +36 -68
  68. data/lib/arel/tree_manager.rb +13 -14
  69. data/lib/arel/update_manager.rb +4 -3
  70. data/lib/arel/visitors/depth_first.rb +85 -57
  71. data/lib/arel/visitors/dot.rb +101 -82
  72. data/lib/arel/visitors/ibm_db.rb +5 -2
  73. data/lib/arel/visitors/informix.rb +43 -21
  74. data/lib/arel/visitors/mssql.rb +75 -24
  75. data/lib/arel/visitors/mysql.rb +52 -22
  76. data/lib/arel/visitors/oracle.rb +51 -26
  77. data/lib/arel/visitors/oracle12.rb +60 -0
  78. data/lib/arel/visitors/postgresql.rb +72 -8
  79. data/lib/arel/visitors/reduce.rb +27 -0
  80. data/lib/arel/visitors/sqlite.rb +13 -2
  81. data/lib/arel/visitors/to_sql.rb +533 -287
  82. data/lib/arel/visitors/visitor.rb +18 -9
  83. data/lib/arel/visitors/where_sql.rb +15 -2
  84. data/lib/arel/visitors.rb +2 -25
  85. data/lib/arel/window_predications.rb +1 -0
  86. data/lib/arel.rb +4 -12
  87. metadata +50 -133
  88. data/.autotest +0 -26
  89. data/.gemtest +0 -0
  90. data/.travis.yml +0 -14
  91. data/Gemfile +0 -12
  92. data/Manifest.txt +0 -133
  93. data/README.markdown +0 -150
  94. data/Rakefile +0 -20
  95. data/arel.gemspec +0 -41
  96. data/lib/arel/deprecated.rb +0 -4
  97. data/lib/arel/expression.rb +0 -5
  98. data/lib/arel/sql/engine.rb +0 -10
  99. data/lib/arel/sql_literal.rb +0 -4
  100. data/lib/arel/visitors/bind_visitor.rb +0 -34
  101. data/lib/arel/visitors/join_sql.rb +0 -19
  102. data/lib/arel/visitors/order_clauses.rb +0 -11
  103. data/test/attributes/test_attribute.rb +0 -664
  104. data/test/helper.rb +0 -13
  105. data/test/nodes/test_and.rb +0 -20
  106. data/test/nodes/test_as.rb +0 -34
  107. data/test/nodes/test_ascending.rb +0 -44
  108. data/test/nodes/test_bin.rb +0 -33
  109. data/test/nodes/test_count.rb +0 -39
  110. data/test/nodes/test_delete_statement.rb +0 -34
  111. data/test/nodes/test_descending.rb +0 -44
  112. data/test/nodes/test_distinct.rb +0 -20
  113. data/test/nodes/test_equality.rb +0 -84
  114. data/test/nodes/test_extract.rb +0 -33
  115. data/test/nodes/test_false.rb +0 -20
  116. data/test/nodes/test_grouping.rb +0 -25
  117. data/test/nodes/test_infix_operation.rb +0 -40
  118. data/test/nodes/test_insert_statement.rb +0 -42
  119. data/test/nodes/test_named_function.rb +0 -46
  120. data/test/nodes/test_node.rb +0 -39
  121. data/test/nodes/test_not.rb +0 -29
  122. data/test/nodes/test_or.rb +0 -34
  123. data/test/nodes/test_over.rb +0 -67
  124. data/test/nodes/test_select_core.rb +0 -69
  125. data/test/nodes/test_select_statement.rb +0 -49
  126. data/test/nodes/test_sql_literal.rb +0 -69
  127. data/test/nodes/test_sum.rb +0 -24
  128. data/test/nodes/test_table_alias.rb +0 -36
  129. data/test/nodes/test_true.rb +0 -21
  130. data/test/nodes/test_update_statement.rb +0 -58
  131. data/test/nodes/test_window.rb +0 -73
  132. data/test/support/fake_record.rb +0 -123
  133. data/test/test_attributes.rb +0 -66
  134. data/test/test_crud.rb +0 -63
  135. data/test/test_delete_manager.rb +0 -42
  136. data/test/test_factory_methods.rb +0 -44
  137. data/test/test_insert_manager.rb +0 -142
  138. data/test/test_select_manager.rb +0 -1090
  139. data/test/test_table.rb +0 -208
  140. data/test/test_update_manager.rb +0 -124
  141. data/test/visitors/test_bind_visitor.rb +0 -58
  142. data/test/visitors/test_depth_first.rb +0 -238
  143. data/test/visitors/test_dispatch_contamination.rb +0 -22
  144. data/test/visitors/test_dot.rb +0 -76
  145. data/test/visitors/test_ibm_db.rb +0 -27
  146. data/test/visitors/test_informix.rb +0 -52
  147. data/test/visitors/test_join_sql.rb +0 -42
  148. data/test/visitors/test_mssql.rb +0 -66
  149. data/test/visitors/test_mysql.rb +0 -55
  150. data/test/visitors/test_oracle.rb +0 -156
  151. data/test/visitors/test_postgres.rb +0 -84
  152. data/test/visitors/test_sqlite.rb +0 -23
  153. data/test/visitors/test_to_sql.rb +0 -476
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 86a3156add2973e4e2cd8b3a852e82c26c073601
4
- data.tar.gz: 06fc106d1ef5fdc41de327a78a8e0b467096202b
3
+ metadata.gz: dc3719172683caa3fb2bd15ce6ef3ed477a8b2ef
4
+ data.tar.gz: 74b4f1d7d44871db56c62907ed1c4ba51040bf6e
5
5
  SHA512:
6
- metadata.gz: ba39500686768a6865b688ce693dd6bc69e2e7ea1a7acb52ab0ad1f0d00fefb85b537f4c5405e865abe67016c166f06503ded328c3b79c2a34156c8ed75e6293
7
- data.tar.gz: 1d916874f785a6fc85a2df91633edbc4b607612c876160e6fce14d03ebc17694fd87be197b793ec44f89a68a9815dba07161717333fb15575e36419efae16508
6
+ metadata.gz: bedb8b1701ee99fca067c4a52f92d096648d25d67d4809408ede3eeb40298b3fc83a9fdccf1f4195c32f871ee430eba29f11dedd19b12032639a8b03bc7ec54c
7
+ data.tar.gz: 97a3b3155db8b0c57ca4616598d45d8aad7592c56a6882e0e7f5369eeac221802cae5cd60b4d72a92d755eb13be4b39aedc9ea967e1c6faac28953a3414d1f39
data/History.txt CHANGED
@@ -1,9 +1,49 @@
1
- == 5.0.1 / 2014-04-14
1
+ === 9.0.0 / 2017-11-14
2
2
 
3
- * Bug Fixes
3
+ * Enhancements
4
+ * `InsertManager#insert` is now chainable
5
+ * Support multiple inserts
4
6
 
5
- * Fix `SqlLiteral` YAML serialization
6
- * PostgreSQL bugfix for invalid SQL in subqueries
7
+ === 8.0.0 / 2017-02-21
8
+
9
+ * Enhancements
10
+
11
+ * Remove deprecated type casting support in Arel
12
+ * Frozen all string literals in Arel
13
+
14
+ === 7.1.1 / 2016-07-27
15
+
16
+ * Bug Fixes
17
+
18
+ * Fix warning in `Casted#hash`
19
+
20
+ === 7.1.0 / 2016-07-19
21
+
22
+ * Enhancements
23
+
24
+ * Support Ruby 2.4 unified Integer class
25
+ * Implement `CASE` conditional expression
26
+ * Support for Bitwise Operations as `InfixOperations`
27
+
28
+ === 7.0.0 / 2015-12-17
29
+
30
+ * Enhancements
31
+
32
+ * Remove deprecated method `Table#primary_key`
33
+ * Remove engine from the constructor arguments `Arel::Table`
34
+ * Deprecate automatic type casting within Arel
35
+
36
+ === 6.0.0 / 2014-11-25
37
+
38
+ * Enhancements
39
+
40
+ * Remove deprecated `Arel::Expression`
41
+ * Remove deprecated `Arel::SqlLiteral`
42
+ * Remove deprecated `SelectManager#joins`
43
+ * Remove deprecated `SelectManager#to_a`
44
+ * Remove deprecated `Arel::Sql::Engine`
45
+ * Remove deprecated `Arel::InnerJoin` constant
46
+ * Remove deprecated `Arel::OuterJoin` constant
7
47
 
8
48
  == 5.0.0 / 2013-12-04
9
49
 
data/MIT-LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2007-2010 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson
1
+ Copyright (c) 2007-2016 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -18,3 +18,4 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
18
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
19
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
data/README.md ADDED
@@ -0,0 +1,295 @@
1
+ # Arel
2
+
3
+ * http://github.com/rails/arel
4
+ * [API Documentation](http://www.rubydoc.info/github/rails/arel)
5
+
6
+ ## DESCRIPTION
7
+
8
+ Arel Really Exasperates Logicians
9
+
10
+ Arel is a SQL AST manager for Ruby. It
11
+
12
+ 1. simplifies the generation of complex SQL queries, and
13
+ 2. adapts to various RDBMSes.
14
+
15
+ It is intended to be a framework framework; that is, you can build your own ORM
16
+ with it, focusing on innovative object and collection modeling as opposed to
17
+ database compatibility and query generation.
18
+
19
+ ## Status
20
+
21
+ For the moment, Arel uses Active Record's connection adapters to connect to the various engines and perform connection pooling, quoting, and type conversion.
22
+
23
+ ## A Gentle Introduction
24
+
25
+ Generating a query with Arel is simple. For example, in order to produce
26
+
27
+ ```sql
28
+ SELECT * FROM users
29
+ ```
30
+
31
+ you construct a table relation and convert it to SQL:
32
+
33
+ ```ruby
34
+ users = Arel::Table.new(:users)
35
+ query = users.project(Arel.sql('*'))
36
+ query.to_sql
37
+ ```
38
+
39
+ ### More Sophisticated Queries
40
+
41
+ Here is a whirlwind tour through the most common SQL operators. These will probably cover 80% of all interaction with the database.
42
+
43
+ First is the 'restriction' operator, `where`:
44
+
45
+ ```ruby
46
+ users.where(users[:name].eq('amy'))
47
+ # => SELECT * FROM users WHERE users.name = 'amy'
48
+ ```
49
+
50
+ What would, in SQL, be part of the `SELECT` clause is called in Arel a `projection`:
51
+
52
+ ```ruby
53
+ users.project(users[:id])
54
+ # => SELECT users.id FROM users
55
+ ```
56
+
57
+ Comparison operators `=`, `!=`, `<`, `>`, `<=`, `>=`, `IN`:
58
+
59
+ ```ruby
60
+ users.where(users[:age].eq(10)).project(Arel.sql('*'))
61
+ # => SELECT * FROM "users" WHERE "users"."age" = 10
62
+
63
+ users.where(users[:age].not_eq(10)).project(Arel.sql('*'))
64
+ # => SELECT * FROM "users" WHERE "users"."age" != 10
65
+
66
+ users.where(users[:age].lt(10)).project(Arel.sql('*'))
67
+ # => SELECT * FROM "users" WHERE "users"."age" < 10
68
+
69
+ users.where(users[:age].gt(10)).project(Arel.sql('*'))
70
+ # => SELECT * FROM "users" WHERE "users"."age" > 10
71
+
72
+ users.where(users[:age].lteq(10)).project(Arel.sql('*'))
73
+ # => SELECT * FROM "users" WHERE "users"."age" <= 10
74
+
75
+ users.where(users[:age].gteq(10)).project(Arel.sql('*'))
76
+ # => SELECT * FROM "users" WHERE "users"."age" >= 10
77
+
78
+ users.where(users[:age].in([20, 16, 17])).project(Arel.sql('*'))
79
+ # => SELECT * FROM "users" WHERE "users"."age" IN (20, 16, 17)
80
+ ```
81
+
82
+ Bitwise operators `&`, `|`, `^`, `<<`, `>>`:
83
+
84
+ ```ruby
85
+ users.where((users[:bitmap] & 16).gt(0)).project(Arel.sql('*'))
86
+ # => SELECT * FROM "users" WHERE ("users"."bitmap" & 16) > 0
87
+
88
+ users.where((users[:bitmap] | 16).gt(0)).project(Arel.sql('*'))
89
+ # => SELECT * FROM "users" WHERE ("users"."bitmap" | 16) > 0
90
+
91
+ users.where((users[:bitmap] ^ 16).gt(0)).project(Arel.sql('*'))
92
+ # => SELECT * FROM "users" WHERE ("users"."bitmap" ^ 16) > 0
93
+
94
+ users.where((users[:bitmap] << 1).gt(0)).project(Arel.sql('*'))
95
+ # => SELECT * FROM "users" WHERE ("users"."bitmap" << 1) > 0
96
+
97
+ users.where((users[:bitmap] >> 1).gt(0)).project(Arel.sql('*'))
98
+ # => SELECT * FROM "users" WHERE ("users"."bitmap" >> 1) > 0
99
+
100
+ users.where((~ users[:bitmap]).gt(0)).project(Arel.sql('*'))
101
+ # => SELECT * FROM "users" WHERE ~ "users"."bitmap" > 0
102
+ ```
103
+
104
+ Joins resemble SQL strongly:
105
+
106
+ ```ruby
107
+ users.join(photos).on(users[:id].eq(photos[:user_id]))
108
+ # => SELECT * FROM users INNER JOIN photos ON users.id = photos.user_id
109
+ ```
110
+
111
+ Left joins:
112
+
113
+ ```ruby
114
+ users.join(photos, Arel::Nodes::OuterJoin).on(users[:id].eq(photos[:user_id]))
115
+ # => SELECT FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id
116
+ ```
117
+
118
+ What are called `LIMIT` and `OFFSET` in SQL are called `take` and `skip` in Arel:
119
+
120
+ ```ruby
121
+ users.take(5) # => SELECT * FROM users LIMIT 5
122
+ users.skip(4) # => SELECT * FROM users OFFSET 4
123
+ ```
124
+
125
+ `GROUP BY` is called `group`:
126
+
127
+ ```ruby
128
+ users.project(users[:name]).group(users[:name])
129
+ # => SELECT users.name FROM users GROUP BY users.name
130
+ ```
131
+
132
+ The best property of Arel is its "composability," or closure under all operations. For example, to restrict AND project, just "chain" the method invocations:
133
+
134
+ ```ruby
135
+ users \
136
+ .where(users[:name].eq('amy')) \
137
+ .project(users[:id]) \
138
+ # => SELECT users.id FROM users WHERE users.name = 'amy'
139
+ ```
140
+
141
+ All operators are chainable in this way, and they are chainable any number of times, in any order.
142
+
143
+ ```ruby
144
+ users.where(users[:name].eq('bob')).where(users[:age].lt(25))
145
+ ```
146
+
147
+ The `OR` operator works like this:
148
+
149
+ ```ruby
150
+ users.where(users[:name].eq('bob').or(users[:age].lt(25)))
151
+ ```
152
+
153
+ The `AND` operator behaves similarly. Here is an example of the `DISTINCT` operator:
154
+
155
+ ```ruby
156
+ posts = Arel::Table.new(:posts)
157
+ posts.project(posts[:title])
158
+ posts.distinct
159
+ posts.to_sql # => 'SELECT DISTINCT "posts"."title" FROM "posts"'
160
+ ```
161
+
162
+ Aggregate functions `AVG`, `SUM`, `COUNT`, `MIN`, `MAX`, `HAVING`:
163
+
164
+ ```ruby
165
+ photos.group(photos[:user_id]).having(photos[:id].count.gt(5))
166
+ # => SELECT FROM photos GROUP BY photos.user_id HAVING COUNT(photos.id) > 5
167
+
168
+ users.project(users[:age].sum)
169
+ # => SELECT SUM(users.age) FROM users
170
+
171
+ users.project(users[:age].average)
172
+ # => SELECT AVG(users.age) FROM users
173
+
174
+ users.project(users[:age].maximum)
175
+ # => SELECT MAX(users.age) FROM users
176
+
177
+ users.project(users[:age].minimum)
178
+ # => SELECT MIN(users.age) FROM users
179
+
180
+ users.project(users[:age].count)
181
+ # => SELECT COUNT(users.age) FROM users
182
+ ```
183
+
184
+ Aliasing Aggregate Functions:
185
+
186
+ ```ruby
187
+ users.project(users[:age].average.as("mean_age"))
188
+ # => SELECT AVG(users.age) AS mean_age FROM users
189
+ ```
190
+
191
+ ### The Advanced Features
192
+
193
+ The examples above are fairly simple and other libraries match or come close to matching the expressiveness of Arel (e.g. `Sequel` in Ruby).
194
+
195
+ #### Inline math operations
196
+
197
+ Suppose we have a table `products` with prices in different currencies. And we have a table `currency_rates`, of constantly changing currency rates. In Arel:
198
+
199
+ ```ruby
200
+ products = Arel::Table.new(:products)
201
+ # Attributes: [:id, :name, :price, :currency_id]
202
+
203
+ currency_rates = Arel::Table.new(:currency_rates)
204
+ # Attributes: [:from_id, :to_id, :date, :rate]
205
+ ```
206
+
207
+ Now, to order products by price in user preferred currency simply call:
208
+
209
+ ```ruby
210
+ products.
211
+ join(:currency_rates).on(products[:currency_id].eq(currency_rates[:from_id])).
212
+ where(currency_rates[:to_id].eq(user_preferred_currency), currency_rates[:date].eq(Date.today)).
213
+ order(products[:price] * currency_rates[:rate])
214
+ ```
215
+
216
+ #### Complex Joins
217
+
218
+ ##### Alias
219
+ Where Arel really shines is in its ability to handle complex joins and aggregations. As a first example, let's consider an "adjacency list", a tree represented in a table. Suppose we have a table `comments`, representing a threaded discussion:
220
+
221
+ ```ruby
222
+ comments = Arel::Table.new(:comments)
223
+ ```
224
+
225
+ And this table has the following attributes:
226
+
227
+ ```ruby
228
+ # [:id, :body, :parent_id]
229
+ ```
230
+
231
+ The `parent_id` column is a foreign key from the `comments` table to itself.
232
+ Joining a table to itself requires aliasing in SQL. This aliasing can be handled from Arel as below:
233
+
234
+ ```ruby
235
+ replies = comments.alias
236
+ comments_with_replies = \
237
+ comments.join(replies).on(replies[:parent_id].eq(comments[:id])).where(comments[:id].eq(1))
238
+ # => SELECT * FROM comments INNER JOIN comments AS comments_2
239
+ # WHERE comments_2.parent_id = comments.id AND comments.id = 1
240
+ ```
241
+
242
+ This will return the reply for the first comment.
243
+
244
+ ##### CTE
245
+ [Common Table Expressions (CTE)](https://en.wikipedia.org/wiki/Common_table_expressions#Common_table_expression) support via:
246
+
247
+ Create a `CTE`
248
+
249
+ ```ruby
250
+ cte_table = Arel::Table.new(:cte_table)
251
+ composed_cte = Arel::Nodes::As.new(cte_table, photos.where(photos[:created_at].gt(Date.current)))
252
+ ```
253
+
254
+ Use the created `CTE`:
255
+
256
+ ```ruby
257
+ users.
258
+ join(cte_table).on(users[:id].eq(cte_table[:user_id])).
259
+ project(users[:id], cte_table[:click].sum).
260
+ with(composed_cte)
261
+
262
+ # => WITH cte_table AS (SELECT FROM photos WHERE photos.created_at > '2014-05-02')
263
+ # SELECT users.id, SUM(cte_table.click)
264
+ # FROM users INNER JOIN cte_table ON users.id = cte_table.user_id
265
+ ```
266
+
267
+ #### Write SQL strings
268
+ When your query is too complex for `Arel`, you can use `Arel::SqlLiteral`:
269
+
270
+ ```ruby
271
+ photo_clicks = Arel::Nodes::SqlLiteral.new(<<-SQL
272
+ CASE WHEN condition1 THEN calculation1
273
+ WHEN condition2 THEN calculation2
274
+ WHEN condition3 THEN calculation3
275
+ ELSE default_calculation END
276
+ SQL
277
+ )
278
+
279
+ photos.project(photo_clicks.as("photo_clicks"))
280
+ # => SELECT CASE WHEN condition1 THEN calculation1
281
+ # WHEN condition2 THEN calculation2
282
+ # WHEN condition3 THEN calculation3
283
+ # ELSE default_calculation END
284
+ # FROM "photos"
285
+ ```
286
+
287
+ ## Contributing to Arel
288
+
289
+ Arel is the work of many contributors. You're encouraged to submit pull requests, propose
290
+ features and discuss issues.
291
+
292
+ See [CONTRIBUTING](CONTRIBUTING.md).
293
+
294
+ ## License
295
+ Arel is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Arel
2
3
  module AliasPredication
3
4
  def as other
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Arel
2
3
  module Attributes
3
4
  class Attribute < Struct.new :relation, :name
@@ -12,6 +13,14 @@ module Arel
12
13
  def lower
13
14
  relation.lower self
14
15
  end
16
+
17
+ def type_cast_for_database(value)
18
+ relation.type_cast_for_database(name, value)
19
+ end
20
+
21
+ def able_to_type_cast?
22
+ relation.able_to_type_cast?
23
+ end
15
24
  end
16
25
 
17
26
  class String < Attribute; end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'arel/attributes/attribute'
2
3
 
3
4
  module Arel
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arel
4
+ module Collectors
5
+ class Bind
6
+ def initialize
7
+ @binds = []
8
+ end
9
+
10
+ def << str
11
+ self
12
+ end
13
+
14
+ def add_bind bind
15
+ @binds << bind
16
+ self
17
+ end
18
+
19
+ def value
20
+ @binds
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arel
4
+ module Collectors
5
+ class Composite
6
+ def initialize(left, right)
7
+ @left = left
8
+ @right = right
9
+ end
10
+
11
+ def << str
12
+ left << str
13
+ right << str
14
+ self
15
+ end
16
+
17
+ def add_bind bind, &block
18
+ left.add_bind bind, &block
19
+ right.add_bind bind, &block
20
+ self
21
+ end
22
+
23
+ def value
24
+ [left.value, right.value]
25
+ end
26
+
27
+ protected
28
+
29
+ attr_reader :left, :right
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ module Arel
3
+ module Collectors
4
+ class PlainString
5
+ def initialize
6
+ @str = ''.dup
7
+ end
8
+
9
+ def value
10
+ @str
11
+ end
12
+
13
+ def << str
14
+ @str << str
15
+ self
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'arel/collectors/plain_string'
4
+
5
+ module Arel
6
+ module Collectors
7
+ class SQLString < PlainString
8
+ def initialize(*)
9
+ super
10
+ @bind_index = 1
11
+ end
12
+
13
+ def add_bind bind
14
+ self << yield(@bind_index)
15
+ @bind_index += 1
16
+ self
17
+ end
18
+
19
+ def compile bvs
20
+ value
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ module Arel
3
+ module Collectors
4
+ class SubstituteBinds
5
+ def initialize(quoter, delegate_collector)
6
+ @quoter = quoter
7
+ @delegate = delegate_collector
8
+ end
9
+
10
+ def << str
11
+ delegate << str
12
+ self
13
+ end
14
+
15
+ def add_bind bind
16
+ self << quoter.quote(bind)
17
+ end
18
+
19
+ def value
20
+ delegate.value
21
+ end
22
+
23
+ protected
24
+
25
+ attr_reader :quoter, :delegate
26
+ end
27
+ end
28
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Arel
2
3
  module Compatibility # :nodoc:
3
4
  class Wheres # :nodoc:
data/lib/arel/crud.rb CHANGED
@@ -1,9 +1,10 @@
1
+ # frozen_string_literal: true
1
2
  module Arel
2
3
  ###
3
4
  # FIXME hopefully we can remove this
4
5
  module Crud
5
6
  def compile_update values, pk
6
- um = UpdateManager.new @engine
7
+ um = UpdateManager.new
7
8
 
8
9
  if Nodes::SqlLiteral === values
9
10
  relation = @ctx.from
@@ -26,11 +27,12 @@ module Arel
26
27
  end
27
28
 
28
29
  def create_insert
29
- InsertManager.new @engine
30
+ InsertManager.new
30
31
  end
31
32
 
32
33
  def compile_delete
33
- dm = DeleteManager.new @engine
34
+ dm = DeleteManager.new
35
+ dm.take @ast.limit.expr if @ast.limit
34
36
  dm.wheres = @ctx.wheres
35
37
  dm.from @ctx.froms
36
38
  dm
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
1
2
  module Arel
2
3
  class DeleteManager < Arel::TreeManager
3
- def initialize engine
4
+ def initialize
4
5
  super
5
6
  @ast = Nodes::DeleteStatement.new
6
7
  @ctx = @ast
@@ -11,6 +12,11 @@ module Arel
11
12
  self
12
13
  end
13
14
 
15
+ def take limit
16
+ @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) if limit
17
+ self
18
+ end
19
+
14
20
  def wheres= list
15
21
  @ast.wheres = list
16
22
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+ module Arel
3
+ class ArelError < StandardError
4
+ end
5
+
6
+ class EmptyJoinError < ArelError
7
+ end
8
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Arel
2
3
  module Expressions
3
4
  def count distinct = false
@@ -5,23 +6,24 @@ module Arel
5
6
  end
6
7
 
7
8
  def sum
8
- Nodes::Sum.new [self], Nodes::SqlLiteral.new('sum_id')
9
+ Nodes::Sum.new [self]
9
10
  end
10
11
 
11
12
  def maximum
12
- Nodes::Max.new [self], Nodes::SqlLiteral.new('max_id')
13
+ Nodes::Max.new [self]
13
14
  end
14
15
 
15
16
  def minimum
16
- Nodes::Min.new [self], Nodes::SqlLiteral.new('min_id')
17
+ Nodes::Min.new [self]
17
18
  end
18
19
 
19
20
  def average
20
- Nodes::Avg.new [self], Nodes::SqlLiteral.new('avg_id')
21
+ Nodes::Avg.new [self]
21
22
  end
22
23
 
23
24
  def extract field
24
25
  Nodes::Extract.new [self], field
25
26
  end
27
+
26
28
  end
27
29
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Arel
2
3
  ###
3
4
  # Methods for creating various nodes
@@ -37,7 +38,7 @@ module Arel
37
38
  ###
38
39
  # Create a LOWER() function
39
40
  def lower column
40
- Nodes::NamedFunction.new 'LOWER', [column]
41
+ Nodes::NamedFunction.new 'LOWER', [Nodes.build_quoted(column)]
41
42
  end
42
43
  end
43
44
  end
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
1
2
  module Arel
2
3
  class InsertManager < Arel::TreeManager
3
- def initialize engine
4
+ def initialize
4
5
  super
5
6
  @ast = Nodes::InsertStatement.new
6
7
  end
@@ -13,11 +14,15 @@ module Arel
13
14
  def columns; @ast.columns end
14
15
  def values= val; @ast.values = val; end
15
16
 
17
+ def select select
18
+ @ast.select = select
19
+ end
20
+
16
21
  def insert fields
17
22
  return if fields.empty?
18
23
 
19
24
  if String === fields
20
- @ast.values = SqlLiteral.new(fields)
25
+ @ast.values = Nodes::SqlLiteral.new(fields)
21
26
  else
22
27
  @ast.relation ||= fields.first.first.relation
23
28
 
@@ -29,10 +34,15 @@ module Arel
29
34
  end
30
35
  @ast.values = create_values values, @ast.columns
31
36
  end
37
+ self
32
38
  end
33
39
 
34
40
  def create_values values, columns
35
41
  Nodes::Values.new values, columns
36
42
  end
43
+
44
+ def create_values_list(rows)
45
+ Nodes::ValuesList.new(rows)
46
+ end
37
47
  end
38
48
  end