arel_extensions 2.0.21 → 2.2.2
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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +1 -2
- data/.github/workflows/publish.yml +29 -0
- data/.github/workflows/release.yml +30 -0
- data/.github/workflows/ruby.yml +377 -80
- data/.gitignore +7 -6
- data/.rubocop.yml +62 -1
- data/CONTRIBUTING.md +102 -0
- data/Gemfile +2 -23
- data/NEWS.md +89 -0
- data/README.md +228 -84
- data/Rakefile +11 -4
- data/TODO +0 -1
- data/appveyor.yml +60 -22
- data/arel_extensions.gemspec +11 -12
- data/bin/build +15 -0
- data/bin/compose +6 -0
- data/bin/publish +8 -0
- data/dev/arelx.dockerfile +44 -0
- data/dev/compose.yaml +71 -0
- data/dev/postgres.dockerfile +5 -0
- data/dev/rbenv +189 -0
- data/gemfiles/rails3.gemfile +10 -10
- data/gemfiles/rails4_2.gemfile +38 -0
- data/gemfiles/rails5.gemfile +29 -0
- data/gemfiles/rails5_1_4.gemfile +13 -13
- data/gemfiles/rails5_2.gemfile +16 -14
- data/gemfiles/rails6.gemfile +18 -15
- data/gemfiles/rails6_1.gemfile +18 -15
- data/gemfiles/rails7.gemfile +33 -0
- data/gemfiles/rails7_1.gemfile +33 -0
- data/gemfiles/rails7_2.gemfile +33 -0
- data/gemspecs/arel_extensions-v1.gemspec +12 -13
- data/gemspecs/arel_extensions-v2.gemspec +11 -12
- data/init/mssql.sql +0 -0
- data/init/mysql.sql +0 -0
- data/init/oracle.sql +0 -0
- data/init/postgresql.sql +0 -0
- data/init/sqlite.sql +0 -0
- data/lib/arel_extensions/aliases.rb +14 -0
- data/lib/arel_extensions/attributes.rb +10 -2
- data/lib/arel_extensions/boolean_functions.rb +2 -4
- data/lib/arel_extensions/common_sql_functions.rb +12 -12
- data/lib/arel_extensions/comparators.rb +14 -14
- data/lib/arel_extensions/date_duration.rb +14 -9
- data/lib/arel_extensions/helpers.rb +62 -0
- data/lib/arel_extensions/insert_manager.rb +19 -17
- data/lib/arel_extensions/math.rb +48 -45
- data/lib/arel_extensions/math_functions.rb +18 -18
- data/lib/arel_extensions/nodes/abs.rb +0 -0
- data/lib/arel_extensions/nodes/aggregate_function.rb +0 -0
- data/lib/arel_extensions/nodes/blank.rb +1 -1
- data/lib/arel_extensions/nodes/case.rb +10 -12
- data/lib/arel_extensions/nodes/cast.rb +6 -6
- data/lib/arel_extensions/nodes/ceil.rb +0 -0
- data/lib/arel_extensions/nodes/change_case.rb +0 -0
- data/lib/arel_extensions/nodes/coalesce.rb +1 -1
- data/lib/arel_extensions/nodes/collate.rb +9 -9
- data/lib/arel_extensions/nodes/concat.rb +2 -2
- data/lib/arel_extensions/nodes/date_diff.rb +33 -14
- data/lib/arel_extensions/nodes/duration.rb +0 -0
- data/lib/arel_extensions/nodes/find_in_set.rb +0 -0
- data/lib/arel_extensions/nodes/floor.rb +0 -0
- data/lib/arel_extensions/nodes/format.rb +3 -2
- data/lib/arel_extensions/nodes/formatted_date.rb +42 -0
- data/lib/arel_extensions/nodes/formatted_number.rb +2 -2
- data/lib/arel_extensions/nodes/function.rb +22 -26
- data/lib/arel_extensions/nodes/is_null.rb +0 -0
- data/lib/arel_extensions/nodes/json.rb +15 -9
- data/lib/arel_extensions/nodes/length.rb +6 -0
- data/lib/arel_extensions/nodes/levenshtein_distance.rb +1 -1
- data/lib/arel_extensions/nodes/locate.rb +1 -1
- data/lib/arel_extensions/nodes/log10.rb +0 -0
- data/lib/arel_extensions/nodes/matches.rb +1 -1
- data/lib/arel_extensions/nodes/md5.rb +0 -0
- data/lib/arel_extensions/nodes/power.rb +0 -0
- data/lib/arel_extensions/nodes/rand.rb +0 -0
- data/lib/arel_extensions/nodes/repeat.rb +2 -2
- data/lib/arel_extensions/nodes/replace.rb +2 -10
- data/lib/arel_extensions/nodes/rollup.rb +36 -0
- data/lib/arel_extensions/nodes/round.rb +0 -0
- data/lib/arel_extensions/nodes/select.rb +10 -0
- data/lib/arel_extensions/nodes/soundex.rb +2 -2
- data/lib/arel_extensions/nodes/std.rb +0 -0
- data/lib/arel_extensions/nodes/substring.rb +1 -1
- data/lib/arel_extensions/nodes/sum.rb +0 -0
- data/lib/arel_extensions/nodes/then.rb +1 -1
- data/lib/arel_extensions/nodes/trim.rb +2 -2
- data/lib/arel_extensions/nodes/union.rb +5 -5
- data/lib/arel_extensions/nodes/union_all.rb +4 -4
- data/lib/arel_extensions/nodes/wday.rb +0 -0
- data/lib/arel_extensions/nodes.rb +0 -0
- data/lib/arel_extensions/null_functions.rb +16 -0
- data/lib/arel_extensions/predications.rb +10 -10
- data/lib/arel_extensions/railtie.rb +1 -1
- data/lib/arel_extensions/set_functions.rb +3 -3
- data/lib/arel_extensions/string_functions.rb +19 -10
- data/lib/arel_extensions/tasks.rb +2 -2
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors/convert_format.rb +0 -0
- data/lib/arel_extensions/visitors/ibm_db.rb +20 -20
- data/lib/arel_extensions/visitors/mssql.rb +394 -169
- data/lib/arel_extensions/visitors/mysql.rb +238 -151
- data/lib/arel_extensions/visitors/oracle.rb +170 -131
- data/lib/arel_extensions/visitors/oracle12.rb +16 -16
- data/lib/arel_extensions/visitors/postgresql.rb +170 -140
- data/lib/arel_extensions/visitors/sqlite.rb +88 -87
- data/lib/arel_extensions/visitors/to_sql.rb +185 -156
- data/lib/arel_extensions/visitors.rb +73 -60
- data/lib/arel_extensions.rb +173 -36
- data/test/arelx_test_helper.rb +49 -1
- data/test/database.yml +13 -7
- data/test/real_db_test.rb +101 -83
- data/test/support/fake_record.rb +8 -2
- data/test/test_comparators.rb +5 -5
- data/test/visitors/test_bulk_insert_oracle.rb +5 -5
- data/test/visitors/test_bulk_insert_sqlite.rb +5 -5
- data/test/visitors/test_bulk_insert_to_sql.rb +5 -5
- data/test/visitors/test_oracle.rb +14 -14
- data/test/visitors/test_to_sql.rb +121 -93
- data/test/with_ar/all_agnostic_test.rb +630 -320
- data/test/with_ar/insert_agnostic_test.rb +25 -18
- data/test/with_ar/test_bulk_sqlite.rb +11 -7
- data/test/with_ar/test_math_sqlite.rb +18 -14
- data/test/with_ar/test_string_mysql.rb +26 -22
- data/test/with_ar/test_string_sqlite.rb +26 -22
- data/version_v1.rb +1 -1
- data/version_v2.rb +1 -1
- metadata +24 -26
- data/.travis/oracle/download.js +0 -152
- data/.travis/oracle/download.sh +0 -30
- data/.travis/oracle/download_ojdbc.js +0 -116
- data/.travis/oracle/install.sh +0 -34
- data/.travis/setup_accounts.sh +0 -9
- data/.travis/sqlite3/extension-functions.sh +0 -6
- data/.travis.yml +0 -193
- data/gemfiles/rails4.gemfile +0 -29
- data/gemfiles/rails5_0.gemfile +0 -29
@@ -8,30 +8,77 @@ module ArelExtensions
|
|
8
8
|
|
9
9
|
DATE_FORMAT_DIRECTIVES = { # ISO C / POSIX
|
10
10
|
'%Y' => '%Y', '%C' => '', '%y' => '%y', '%m' => '%m', '%B' => '%M', '%b' => '%b', '%^b' => '%b', # year, month
|
11
|
-
'%
|
11
|
+
'%V' => '%v', '%G' => '%x', # ISO week number and year of week
|
12
|
+
'%d' => '%d', '%e' => '%e', '%j' => '%j', '%w' => '%w', '%a' => '%a', '%A' => '%W', # day, weekday
|
12
13
|
'%H' => '%H', '%k' => '%k', '%I' => '%I', '%l' => '%l', '%P' => '%p', '%p' => '%p', # hours
|
13
14
|
'%M' => '%i', '%S' => '%S', '%L' => '', '%N' => '%f', '%z' => ''
|
14
15
|
}.freeze
|
15
16
|
|
17
|
+
# This helper method did not exist in rails < 5.2
|
18
|
+
if !Arel::Visitors::MySQL.method_defined?(:collect_nodes_for)
|
19
|
+
def collect_nodes_for(nodes, collector, spacer, connector = ", ")
|
20
|
+
if nodes&.any?
|
21
|
+
collector << spacer
|
22
|
+
inject_join nodes, collector, connector
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# The whole purpose of this override is to fix the behavior of RollUp.
|
28
|
+
# All other databases treat RollUp sanely, execpt MySQL which requires
|
29
|
+
# that it figures as the last element of a GROUP BY.
|
30
|
+
def visit_Arel_Nodes_SelectCore(o, collector)
|
31
|
+
collector << "SELECT"
|
32
|
+
|
33
|
+
collector = collect_optimizer_hints(o, collector) if self.respond_to?(:collect_optimizer_hinsts)
|
34
|
+
collector = maybe_visit o.set_quantifier, collector
|
35
|
+
|
36
|
+
collect_nodes_for o.projections, collector, " "
|
37
|
+
|
38
|
+
if o.source && !o.source.empty?
|
39
|
+
collector << " FROM "
|
40
|
+
collector = visit o.source, collector
|
41
|
+
end
|
42
|
+
|
43
|
+
# The actual work
|
44
|
+
groups = o.groups
|
45
|
+
rollup = groups.select { |g| g.expr.class == Arel::Nodes::RollUp }.map { |r| r.expr.value }
|
46
|
+
if rollup && !rollup.empty?
|
47
|
+
groups = o.groups.reject { |g| g.expr.class == Arel::Nodes::RollUp }
|
48
|
+
groups << Arel::Nodes::RollUp.new(rollup)
|
49
|
+
end
|
50
|
+
# FIN
|
51
|
+
|
52
|
+
collect_nodes_for o.wheres, collector, " WHERE ", " AND "
|
53
|
+
collect_nodes_for groups, collector, " GROUP BY " # Look ma, I'm viring a group
|
54
|
+
collect_nodes_for o.havings, collector, " HAVING ", " AND "
|
55
|
+
collect_nodes_for o.windows, collector, " WINDOW "
|
56
|
+
|
57
|
+
if o.respond_to?(:comment)
|
58
|
+
maybe_visit o.comment, collector
|
59
|
+
else
|
60
|
+
collector
|
61
|
+
end
|
62
|
+
end
|
16
63
|
|
17
64
|
# Math functions
|
18
65
|
def visit_ArelExtensions_Nodes_Log10 o, collector
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
66
|
+
collector << 'LOG10('
|
67
|
+
o.expressions.each_with_index { |arg, i|
|
68
|
+
collector << Arel::Visitors::ToSql::COMMA if i != 0
|
69
|
+
collector = visit arg, collector
|
70
|
+
}
|
71
|
+
collector << ')'
|
72
|
+
collector
|
26
73
|
end
|
27
74
|
|
28
75
|
def visit_ArelExtensions_Nodes_Power o, collector
|
29
|
-
collector <<
|
76
|
+
collector << 'POW('
|
30
77
|
o.expressions.each_with_index { |arg, i|
|
31
78
|
collector << Arel::Visitors::ToSql::COMMA if i != 0
|
32
79
|
collector = visit arg, collector
|
33
80
|
}
|
34
|
-
collector <<
|
81
|
+
collector << ')'
|
35
82
|
collector
|
36
83
|
end
|
37
84
|
|
@@ -44,10 +91,9 @@ module ArelExtensions
|
|
44
91
|
collector << ')'
|
45
92
|
if o.escape
|
46
93
|
collector << ' ESCAPE '
|
47
|
-
visit o.escape, collector
|
48
|
-
else
|
49
|
-
collector
|
94
|
+
collector = visit o.escape, collector
|
50
95
|
end
|
96
|
+
collector
|
51
97
|
end
|
52
98
|
|
53
99
|
def visit_ArelExtensions_Nodes_AiMatches o, collector
|
@@ -56,10 +102,9 @@ module ArelExtensions
|
|
56
102
|
collector = visit o.right.ai_collate, collector
|
57
103
|
if o.escape
|
58
104
|
collector << ' ESCAPE '
|
59
|
-
visit o.escape, collector
|
60
|
-
else
|
61
|
-
collector
|
105
|
+
collector = visit o.escape, collector
|
62
106
|
end
|
107
|
+
collector
|
63
108
|
end
|
64
109
|
|
65
110
|
def visit_ArelExtensions_Nodes_AiIMatches o, collector
|
@@ -68,22 +113,20 @@ module ArelExtensions
|
|
68
113
|
collector = visit o.right.ai_collate, collector
|
69
114
|
if o.escape
|
70
115
|
collector << ' ESCAPE '
|
71
|
-
visit o.escape, collector
|
72
|
-
else
|
73
|
-
collector
|
116
|
+
collector = visit o.escape, collector
|
74
117
|
end
|
118
|
+
collector
|
75
119
|
end
|
76
120
|
|
77
121
|
def visit_ArelExtensions_Nodes_SMatches o, collector
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
122
|
+
collector = visit o.left.collate, collector
|
123
|
+
collector << ' LIKE '
|
124
|
+
collector = visit o.right.collate, collector
|
125
|
+
if o.escape
|
126
|
+
collector << ' ESCAPE '
|
127
|
+
collector = visit o.escape, collector
|
128
|
+
end
|
129
|
+
collector
|
87
130
|
end
|
88
131
|
|
89
132
|
def visit_ArelExtensions_Nodes_IDoesNotMatch o, collector
|
@@ -94,10 +137,9 @@ module ArelExtensions
|
|
94
137
|
collector << ')'
|
95
138
|
if o.escape
|
96
139
|
collector << ' ESCAPE '
|
97
|
-
visit o.escape, collector
|
98
|
-
else
|
99
|
-
collector
|
140
|
+
collector = visit o.escape, collector
|
100
141
|
end
|
142
|
+
collector
|
101
143
|
end
|
102
144
|
|
103
145
|
def visit_ArelExtensions_Nodes_Collate o, collector
|
@@ -105,7 +147,7 @@ module ArelExtensions
|
|
105
147
|
case o.expressions.first
|
106
148
|
when Arel::Attributes::Attribute
|
107
149
|
case o.option
|
108
|
-
when 'latin1','utf8'
|
150
|
+
when 'latin1', 'utf8'
|
109
151
|
o.option
|
110
152
|
else
|
111
153
|
Arel::Table.engine.connection.charset || 'utf8'
|
@@ -116,10 +158,10 @@ module ArelExtensions
|
|
116
158
|
collector = visit o.expressions.first, collector
|
117
159
|
collector <<
|
118
160
|
if o.ai
|
119
|
-
" COLLATE #{charset == 'latin1' ? 'latin1_general_ci' :
|
161
|
+
" COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : "#{charset}_unicode_ci"}"
|
120
162
|
# doesn't work in latin1
|
121
163
|
elsif o.ci
|
122
|
-
" COLLATE #{charset == 'latin1' ? 'latin1_general_ci' :
|
164
|
+
" COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : "#{charset}_unicode_ci"}"
|
123
165
|
else
|
124
166
|
" COLLATE #{charset}_bin"
|
125
167
|
end
|
@@ -127,27 +169,32 @@ module ArelExtensions
|
|
127
169
|
end
|
128
170
|
|
129
171
|
def visit_ArelExtensions_Nodes_Concat o, collector
|
130
|
-
collector <<
|
172
|
+
collector << 'CONCAT('
|
131
173
|
o.expressions.each_with_index { |arg, i|
|
132
174
|
collector << COMMA if i != 0
|
133
|
-
if
|
134
|
-
collector <<
|
175
|
+
if arg.is_a?(Numeric) || arg.is_a?(Arel::Attributes::Attribute)
|
176
|
+
collector << 'CAST('
|
135
177
|
collector = visit arg, collector
|
136
|
-
collector <<
|
178
|
+
collector << ' AS char)'
|
137
179
|
else
|
138
180
|
collector = visit arg, collector
|
139
181
|
end
|
140
182
|
}
|
141
|
-
collector <<
|
183
|
+
collector << ')'
|
142
184
|
collector
|
143
185
|
end
|
144
186
|
|
187
|
+
def visit_Arel_Nodes_RollUp(o, collector)
|
188
|
+
visit o.expr, collector
|
189
|
+
collector << " WITH ROLLUP"
|
190
|
+
end
|
191
|
+
|
145
192
|
def visit_ArelExtensions_Nodes_GroupConcat o, collector
|
146
|
-
collector <<
|
193
|
+
collector << 'GROUP_CONCAT('
|
147
194
|
collector = visit o.left, collector
|
148
195
|
if !o.order.blank?
|
149
196
|
collector << ' ORDER BY '
|
150
|
-
o.order.each_with_index do |order,i|
|
197
|
+
o.order.each_with_index do |order, i|
|
151
198
|
collector << Arel::Visitors::ToSql::COMMA if i != 0
|
152
199
|
collector = visit order, collector
|
153
200
|
end
|
@@ -156,77 +203,108 @@ module ArelExtensions
|
|
156
203
|
collector << ' SEPARATOR '
|
157
204
|
collector = visit o.separator, collector
|
158
205
|
end
|
159
|
-
collector <<
|
206
|
+
collector << ')'
|
160
207
|
collector
|
161
208
|
end
|
162
209
|
|
163
210
|
def visit_ArelExtensions_Nodes_Trim o, collector
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
211
|
+
collector << 'TRIM(' # BOTH
|
212
|
+
collector = visit o.right, collector
|
213
|
+
collector << ' FROM '
|
214
|
+
collector = visit o.left, collector
|
215
|
+
collector << ')'
|
216
|
+
collector
|
170
217
|
end
|
171
218
|
|
172
219
|
def visit_ArelExtensions_Nodes_Ltrim o, collector
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
220
|
+
collector << 'TRIM(LEADING '
|
221
|
+
collector = visit o.right, collector
|
222
|
+
collector << ' FROM '
|
223
|
+
collector = visit o.left, collector
|
224
|
+
collector << ')'
|
225
|
+
collector
|
179
226
|
end
|
180
227
|
|
181
228
|
def visit_ArelExtensions_Nodes_Rtrim o, collector
|
182
229
|
collector << 'TRIM(TRAILING '
|
183
230
|
collector = visit o.right, collector
|
184
|
-
collector <<
|
231
|
+
collector << ' FROM '
|
185
232
|
collector = visit o.left, collector
|
186
|
-
collector <<
|
233
|
+
collector << ')'
|
187
234
|
collector
|
188
235
|
end
|
189
236
|
|
190
237
|
def visit_ArelExtensions_Nodes_Repeat o, collector
|
191
|
-
collector <<
|
238
|
+
collector << 'REPEAT('
|
192
239
|
o.expressions.each_with_index { |arg, i|
|
193
240
|
collector << Arel::Visitors::ToSql::COMMA if i != 0
|
194
241
|
collector = visit arg, collector
|
195
242
|
}
|
196
|
-
collector <<
|
243
|
+
collector << ')'
|
197
244
|
collector
|
198
245
|
end
|
199
246
|
|
200
247
|
def visit_ArelExtensions_Nodes_RegexpReplace o, collector
|
201
248
|
if !regexp_replace_supported?
|
202
|
-
warn(
|
249
|
+
warn('Warning: ArelExtensions: REGEXP_REPLACE does not seem to be available in the current version of the DBMS, it might crash')
|
203
250
|
end
|
204
|
-
super(o,collector)
|
251
|
+
super(o, collector)
|
205
252
|
end
|
206
253
|
|
207
254
|
def visit_ArelExtensions_Nodes_Format o, collector
|
208
|
-
case
|
255
|
+
# One use case we met is
|
256
|
+
# `case…when…then(valid_date).else(Arel.null).format(…)`.
|
257
|
+
#
|
258
|
+
# In this case, `o.col_type` is `nil` but we have a legitimate type in
|
259
|
+
# the expression to be formatted. The following is a best effort to
|
260
|
+
# infer the proper type.
|
261
|
+
first = o.expressions[0]
|
262
|
+
type =
|
263
|
+
o.col_type.nil? \
|
264
|
+
&& (first.respond_to?(:return_type) && !first&.return_type.nil?) \
|
265
|
+
? first&.return_type \
|
266
|
+
: o.col_type
|
267
|
+
|
268
|
+
case type
|
209
269
|
when :date, :datetime, :time
|
210
|
-
|
211
|
-
collector << "DATE_FORMAT("
|
212
|
-
collector = visit o.left, collector
|
213
|
-
collector << COMMA
|
214
|
-
collector = visit Arel::Nodes.build_quoted(fmt), collector
|
215
|
-
collector << ")"
|
270
|
+
visit_ArelExtensions_Nodes_FormattedDate o, collector
|
216
271
|
when :integer, :float, :decimal
|
217
|
-
collector <<
|
272
|
+
collector << 'FORMAT('
|
218
273
|
collector = visit o.left, collector
|
219
274
|
collector << Arel::Visitors::ToSql::COMMA
|
220
275
|
collector << '2'
|
221
276
|
collector << Arel::Visitors::ToSql::COMMA
|
222
277
|
collector = visit o.right, collector
|
223
|
-
collector <<
|
278
|
+
collector << ')'
|
224
279
|
else
|
225
280
|
collector = visit o.left, collector
|
226
281
|
end
|
227
282
|
collector
|
228
283
|
end
|
229
284
|
|
285
|
+
def visit_ArelExtensions_Nodes_FormattedDate o, collector
|
286
|
+
fmt = ArelExtensions::Visitors::strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
|
287
|
+
collector << 'DATE_FORMAT('
|
288
|
+
collector << 'CONVERT_TZ(' if o.time_zone
|
289
|
+
collector = visit o.left, collector
|
290
|
+
case o.time_zone
|
291
|
+
when Hash
|
292
|
+
src_tz, dst_tz = o.time_zone.first
|
293
|
+
collector << COMMA
|
294
|
+
collector = visit Arel.quoted(src_tz), collector
|
295
|
+
collector << COMMA
|
296
|
+
collector = visit Arel.quoted(dst_tz), collector
|
297
|
+
collector << ')'
|
298
|
+
when String
|
299
|
+
collector << COMMA << "'UTC'" << COMMA
|
300
|
+
collector = visit Arel.quoted(o.time_zone), collector
|
301
|
+
collector << ')'
|
302
|
+
end
|
303
|
+
collector << COMMA
|
304
|
+
collector = visit Arel.quoted(fmt), collector
|
305
|
+
collector << ')'
|
306
|
+
end
|
307
|
+
|
230
308
|
def visit_ArelExtensions_Nodes_DateDiff o, collector
|
231
309
|
case o.right_node_type
|
232
310
|
when :ruby_date, :ruby_time, :date, :datetime, :time
|
@@ -238,7 +316,7 @@ module ArelExtensions
|
|
238
316
|
collector = visit o.right, collector
|
239
317
|
collector << COMMA
|
240
318
|
collector = visit o.left, collector
|
241
|
-
collector <<
|
319
|
+
collector << ')'
|
242
320
|
else
|
243
321
|
collector << '('
|
244
322
|
collector = visit o.left, collector
|
@@ -258,81 +336,79 @@ module ArelExtensions
|
|
258
336
|
end
|
259
337
|
|
260
338
|
def visit_ArelExtensions_Nodes_DateAdd o, collector
|
261
|
-
collector <<
|
339
|
+
collector << 'DATE_ADD('
|
262
340
|
collector = visit o.left, collector
|
263
341
|
collector << COMMA
|
264
342
|
collector = visit o.mysql_value(o.right), collector
|
265
|
-
collector <<
|
343
|
+
collector << ')'
|
266
344
|
collector
|
267
345
|
end
|
268
346
|
|
269
347
|
def visit_ArelExtensions_Nodes_Duration o, collector
|
270
348
|
if o.left == 'wd'
|
271
|
-
collector <<
|
349
|
+
collector << '(WEEKDAY('
|
272
350
|
collector = visit o.right, collector
|
273
|
-
collector <<
|
351
|
+
collector << ') + 1) % 7'
|
274
352
|
else
|
275
353
|
if o.with_interval
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
end
|
354
|
+
interval =
|
355
|
+
case o.left
|
356
|
+
when 'd', 'm', 'y'
|
357
|
+
'DAY'
|
358
|
+
when 'h', 'mn', 's'
|
359
|
+
'SECOND'
|
360
|
+
when /i\z/
|
361
|
+
DATE_MAPPING[o.left[0..-2]]
|
362
|
+
end
|
286
363
|
end
|
287
|
-
collector <<
|
364
|
+
collector << ' INTERVAL ' if o.with_interval && interval
|
288
365
|
collector << "#{DATE_MAPPING[o.left]}("
|
289
366
|
collector = visit o.right, collector
|
290
|
-
collector <<
|
367
|
+
collector << ')'
|
291
368
|
collector << " #{interval} " if o.with_interval && interval
|
292
369
|
end
|
293
370
|
collector
|
294
371
|
end
|
295
372
|
|
296
373
|
def visit_ArelExtensions_Nodes_IsNull o, collector
|
297
|
-
collector <<
|
374
|
+
collector << 'ISNULL('
|
298
375
|
collector = visit o.expr, collector
|
299
|
-
collector <<
|
376
|
+
collector << ')'
|
300
377
|
collector
|
301
378
|
end
|
302
379
|
|
303
380
|
def visit_ArelExtensions_Nodes_IsNotNull o, collector
|
304
|
-
|
381
|
+
collector << 'NOT ISNULL('
|
305
382
|
collector = visit o.expr, collector
|
306
|
-
collector <<
|
383
|
+
collector << ')'
|
307
384
|
collector
|
308
385
|
end
|
309
386
|
|
310
387
|
def visit_ArelExtensions_Nodes_Wday o, collector
|
311
|
-
collector <<
|
388
|
+
collector << '(WEEKDAY('
|
312
389
|
collector = visit o.date, collector
|
313
|
-
collector <<
|
390
|
+
collector << ') + 1) % 7'
|
314
391
|
collector
|
315
392
|
end
|
316
393
|
|
317
394
|
def visit_ArelExtensions_Nodes_Cast o, collector
|
318
|
-
collector << "CAST("
|
319
|
-
collector = visit o.left, collector
|
320
|
-
collector << " AS "
|
321
395
|
as_attr =
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
collector = visit
|
335
|
-
collector <<
|
396
|
+
case o.as_attr
|
397
|
+
when :binary then 'binary'
|
398
|
+
when :date then 'date'
|
399
|
+
when :datetime then 'datetime'
|
400
|
+
when :int then 'signed'
|
401
|
+
when :number, :decimal then 'decimal(20,6)'
|
402
|
+
when :string then 'char'
|
403
|
+
when :time then 'time'
|
404
|
+
else o.as_attr.to_s
|
405
|
+
end
|
406
|
+
|
407
|
+
collector << 'CAST('
|
408
|
+
collector = visit o.left, collector
|
409
|
+
collector << ' AS '
|
410
|
+
collector = visit Arel::Nodes::SqlLiteral.new(as_attr), collector
|
411
|
+
collector << ')'
|
336
412
|
collector
|
337
413
|
end
|
338
414
|
|
@@ -342,7 +418,7 @@ module ArelExtensions
|
|
342
418
|
o = o.dup
|
343
419
|
o.orders = []
|
344
420
|
end
|
345
|
-
old_visit_Arel_Nodes_SelectStatement(o,collector)
|
421
|
+
old_visit_Arel_Nodes_SelectStatement(o, collector)
|
346
422
|
end
|
347
423
|
|
348
424
|
alias_method(:old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As) rescue nil
|
@@ -354,16 +430,22 @@ module ArelExtensions
|
|
354
430
|
else
|
355
431
|
collector = visit o.left, collector
|
356
432
|
end
|
357
|
-
collector <<
|
433
|
+
collector << ' AS '
|
434
|
+
|
435
|
+
# sometimes these values are already quoted, if they are, don't double quote it
|
436
|
+
quote = o.right.is_a?(Arel::Nodes::SqlLiteral) && o.right[0] != '`' && o.right[-1] != '`'
|
437
|
+
|
438
|
+
collector << '`' if quote
|
358
439
|
collector = visit o.right, collector
|
359
|
-
collector <<
|
440
|
+
collector << '`' if quote
|
441
|
+
|
360
442
|
collector
|
361
443
|
end
|
362
444
|
|
363
445
|
def visit_ArelExtensions_Nodes_FormattedNumber o, collector
|
364
446
|
col = o.left.coalesce(0)
|
365
|
-
params = o.locale ? [o.precision,Arel
|
366
|
-
sign =
|
447
|
+
params = o.locale ? [o.precision, Arel.quoted(o.locale)] : [o.precision]
|
448
|
+
sign = Arel.when(col < 0).
|
367
449
|
then('-').
|
368
450
|
else(o.flags.include?('+') ? '+' : (o.flags.include?(' ') ? ' ' : ''))
|
369
451
|
sign_length = ArelExtensions::Nodes::Length.new([sign])
|
@@ -371,28 +453,33 @@ module ArelExtensions
|
|
371
453
|
number =
|
372
454
|
if o.scientific_notation
|
373
455
|
ArelExtensions::Nodes::Concat.new([
|
374
|
-
Arel::Nodes::NamedFunction.new('FORMAT',[
|
375
|
-
col.abs/Arel
|
376
|
-
]+params),
|
456
|
+
Arel::Nodes::NamedFunction.new('FORMAT', [
|
457
|
+
col.abs / Arel.quoted(10).pow(col.abs.log10.floor)
|
458
|
+
] + params),
|
377
459
|
o.type,
|
378
|
-
Arel::Nodes::NamedFunction.new('FORMAT',[
|
460
|
+
Arel::Nodes::NamedFunction.new('FORMAT', [
|
379
461
|
col.abs.log10.floor,
|
380
462
|
0
|
381
463
|
])
|
382
464
|
])
|
383
465
|
else
|
384
|
-
Arel::Nodes::NamedFunction.new('FORMAT',[col.abs]+params)
|
466
|
+
Arel::Nodes::NamedFunction.new('FORMAT', [col.abs] + params)
|
385
467
|
end
|
386
468
|
|
387
|
-
repeated_char =
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
469
|
+
repeated_char =
|
470
|
+
if o.width == 0
|
471
|
+
Arel.quoted('')
|
472
|
+
else
|
473
|
+
Arel
|
474
|
+
.when(Arel.quoted(o.width).abs - (number.length + sign_length) > 0)
|
475
|
+
.then(Arel.quoted(
|
476
|
+
o.flags.include?('-') ? ' ' : (o.flags.include?('0') ? '0' : ' ')
|
477
|
+
).repeat(Arel.quoted(o.width).abs - (number.length + sign_length))
|
478
|
+
)
|
479
|
+
.else('')
|
480
|
+
end
|
481
|
+
before = !o.flags.include?('0') && !o.flags.include?('-') ? repeated_char : ''
|
482
|
+
middle = o.flags.include?('0') && !o.flags.include?('-') ? repeated_char : ''
|
396
483
|
after = o.flags.include?('-') ? repeated_char : ''
|
397
484
|
full_number = ArelExtensions::Nodes::Concat.new([
|
398
485
|
before,
|
@@ -401,45 +488,45 @@ module ArelExtensions
|
|
401
488
|
number,
|
402
489
|
after
|
403
490
|
])
|
404
|
-
collector = visit ArelExtensions::Nodes::Concat.new([Arel
|
491
|
+
collector = visit ArelExtensions::Nodes::Concat.new([Arel.quoted(o.prefix), full_number, Arel.quoted(o.suffix)]), collector
|
405
492
|
collector
|
406
493
|
end
|
407
494
|
|
408
495
|
def visit_Aggregate_For_AggregateFunction o, collector
|
409
496
|
if !window_supported?
|
410
|
-
|
411
|
-
|
497
|
+
warn('Warning: ArelExtensions: Window Functions are not available in the current version of the DBMS.')
|
498
|
+
return collector
|
412
499
|
end
|
413
500
|
|
414
501
|
if !o.order.empty? || !o.group.empty?
|
415
|
-
collector <<
|
502
|
+
collector << ' OVER ('
|
416
503
|
if !o.group.empty?
|
417
|
-
collector <<
|
504
|
+
collector << ' PARTITION BY ('
|
418
505
|
visit o.group, collector
|
419
|
-
collector <<
|
506
|
+
collector << ')'
|
420
507
|
end
|
421
508
|
if !o.order.empty?
|
422
|
-
collector <<
|
509
|
+
collector << ' ORDER BY ('
|
423
510
|
visit o.order, collector
|
424
|
-
collector <<
|
511
|
+
collector << ')'
|
425
512
|
end
|
426
|
-
collector <<
|
513
|
+
collector << ')'
|
427
514
|
end
|
428
515
|
collector
|
429
516
|
end
|
430
517
|
|
431
518
|
def visit_ArelExtensions_Nodes_Std o, collector
|
432
|
-
collector << (o.unbiased_estimator ?
|
519
|
+
collector << (o.unbiased_estimator ? 'STDDEV_SAMP(' : 'STDDEV_POP(')
|
433
520
|
visit o.left, collector
|
434
|
-
collector <<
|
521
|
+
collector << ')'
|
435
522
|
visit_Aggregate_For_AggregateFunction o, collector
|
436
523
|
collector
|
437
524
|
end
|
438
525
|
|
439
526
|
def visit_ArelExtensions_Nodes_Variance o, collector
|
440
|
-
collector << (o.unbiased_estimator ?
|
527
|
+
collector << (o.unbiased_estimator ? 'VAR_SAMP(' : 'VAR_POP(')
|
441
528
|
visit o.left, collector
|
442
|
-
collector <<
|
529
|
+
collector << ')'
|
443
530
|
visit_Aggregate_For_AggregateFunction o, collector
|
444
531
|
collector
|
445
532
|
end
|
@@ -471,13 +558,13 @@ module ArelExtensions
|
|
471
558
|
# corresponding mysql version of the current mariadb version (which is not very helpful most of the time)
|
472
559
|
end
|
473
560
|
|
474
|
-
def visit_ArelExtensions_Nodes_Json o,collector
|
561
|
+
def visit_ArelExtensions_Nodes_Json o, collector
|
475
562
|
return super if !json_supported?
|
476
563
|
|
477
564
|
case o.dict
|
478
565
|
when Array
|
479
566
|
collector << 'JSON_ARRAY('
|
480
|
-
o.dict.each.with_index do |v,i|
|
567
|
+
o.dict.each.with_index do |v, i|
|
481
568
|
if i != 0
|
482
569
|
collector << COMMA
|
483
570
|
end
|
@@ -486,7 +573,7 @@ module ArelExtensions
|
|
486
573
|
collector << ')'
|
487
574
|
when Hash
|
488
575
|
collector << 'JSON_OBJECT('
|
489
|
-
o.dict.each.with_index do |(k,v),i|
|
576
|
+
o.dict.each.with_index do |(k, v), i|
|
490
577
|
if i != 0
|
491
578
|
collector << COMMA
|
492
579
|
end
|
@@ -501,9 +588,9 @@ module ArelExtensions
|
|
501
588
|
collector
|
502
589
|
end
|
503
590
|
|
504
|
-
def visit_ArelExtensions_Nodes_JsonMerge o,collector
|
591
|
+
def visit_ArelExtensions_Nodes_JsonMerge o, collector
|
505
592
|
collector << 'JSON_MERGE_PATCH('
|
506
|
-
o.expressions.each.with_index do |v,i|
|
593
|
+
o.expressions.each.with_index do |v, i|
|
507
594
|
if i != 0
|
508
595
|
collector << COMMA
|
509
596
|
end
|
@@ -513,27 +600,27 @@ module ArelExtensions
|
|
513
600
|
collector
|
514
601
|
end
|
515
602
|
|
516
|
-
def visit_ArelExtensions_Nodes_JsonGet o,collector
|
603
|
+
def visit_ArelExtensions_Nodes_JsonGet o, collector
|
517
604
|
collector << 'JSON_EXTRACT('
|
518
605
|
collector = visit o.dict, collector
|
519
606
|
collector << COMMA
|
520
607
|
if o.key.is_a?(Integer)
|
521
608
|
collector << "\"$[#{o.key}]\""
|
522
609
|
else
|
523
|
-
collector = visit Arel
|
610
|
+
collector = visit Arel.quoted('$.') + o.key, collector
|
524
611
|
end
|
525
612
|
collector << ')'
|
526
613
|
collector
|
527
614
|
end
|
528
615
|
|
529
|
-
def visit_ArelExtensions_Nodes_JsonSet o,collector
|
616
|
+
def visit_ArelExtensions_Nodes_JsonSet o, collector
|
530
617
|
collector << 'JSON_SET('
|
531
618
|
collector = visit o.dict, collector
|
532
619
|
collector << COMMA
|
533
620
|
if o.key.is_a?(Integer)
|
534
621
|
collector << "\"$[#{o.key}]\""
|
535
622
|
else
|
536
|
-
collector = visit Arel
|
623
|
+
collector = visit Arel.quoted('$.') + o.key, collector
|
537
624
|
end
|
538
625
|
collector << COMMA
|
539
626
|
collector = visit o.value, collector
|
@@ -552,7 +639,7 @@ module ArelExtensions
|
|
552
639
|
case o.dict
|
553
640
|
when Hash
|
554
641
|
collector << 'JSON_MERGE_PATCH(' if o.dict.length > 1
|
555
|
-
o.dict.each.with_index do |(k,v),i|
|
642
|
+
o.dict.each.with_index do |(k, v), i|
|
556
643
|
if i != 0
|
557
644
|
collector << COMMA
|
558
645
|
end
|