arel_extensions 1.3.1 → 1.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +23 -2
- data/lib/arel_extensions/nodes/format.rb +1 -1
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +20 -6
- data/lib/arel_extensions/visitors/mysql.rb +10 -2
- data/lib/arel_extensions/visitors/oracle.rb +10 -3
- data/lib/arel_extensions/visitors/postgresql.rb +11 -3
- data/test/arelx_test_helper.rb +0 -1
- data/test/with_ar/all_agnostic_test.rb +24 -20
- data/version_v1.rb +1 -1
- data/version_v2.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a07429d6f459dff77dc3fa56aa258f1fee94ecb7401772ec3ceaea8dc0a8c4d7
|
4
|
+
data.tar.gz: d1600677cf0e63777bd8d8b656f4e17f0fa534e23579cfe3c18044e855a6115b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 752646ca62337cff68c38bcda876d5aa1f7cf6cb8f31906b6d6335237aa1a074daf4891b94b45486d758f1af035d87aac2449951aab683d35f84c123b10c39f8
|
7
|
+
data.tar.gz: d3002160ab13dc1ecbdac0d863a72847a4b3f151cfe12ada6d694b4fb02d70a7e16facbe455d474a5e2ce51ca5686c8abfee26962b91f04023e2fdeb335e22e0
|
data/README.md
CHANGED
@@ -152,7 +152,9 @@ t[:birthdate].format('%Y-%m-%d').to_sql
|
|
152
152
|
```
|
153
153
|
|
154
154
|
Which formats the datetime without any time zone conversion.
|
155
|
-
The second form
|
155
|
+
The second form accepts 2 kinds of values:
|
156
|
+
|
157
|
+
1. String:
|
156
158
|
|
157
159
|
```ruby
|
158
160
|
t[:birthdate].format('%Y/%m/%d %H:%M:%S', 'posix/Pacific/Tahiti')
|
@@ -162,7 +164,18 @@ t[:birthdate].format('%Y/%m/%d %H:%M:%S', 'posix/Pacific/Tahiti')
|
|
162
164
|
# ^^^^^^^^^^^^^^^^^^^^ 🚨 Invalid timezone for SQL Server. Explanation below.
|
163
165
|
```
|
164
166
|
|
165
|
-
|
167
|
+
which will convert the datetime field to the supplied time zone. This generally
|
168
|
+
means that you're letting the RDBMS decide or infer what is the timezone of the
|
169
|
+
column before conversion to the supplied timezone.
|
170
|
+
|
171
|
+
1. Hash of the form `{ src_time_zone => dst_time_zone }`:
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
t[:birthdate].format('%Y/%m/%d %H:%M:%S', { 'posix/Europe/Paris' => 'posix/Pacific/Tahiti' })
|
175
|
+
```
|
176
|
+
|
177
|
+
which will explicitly indicate the original timestamp that should be considered
|
178
|
+
by the RDBMS.
|
166
179
|
|
167
180
|
Warning:
|
168
181
|
|
@@ -176,6 +189,14 @@ Warning:
|
|
176
189
|
- ☣️ Choosing abbreviate forms like `CET`, which stands for `Central European
|
177
190
|
Time` will behave differently on `PostgreSQL` and `MySQL`. Don't assume
|
178
191
|
uniform behavior, or even a _rational_ one.
|
192
|
+
- ⚠️ Pay attention to the type of the `datetime` column you're working with. For
|
193
|
+
example, in Postgres, a `datetime` can be one of the following types:
|
194
|
+
1. `timestamp with time zone`
|
195
|
+
2. `timestamp without time zone`
|
196
|
+
In the first case, you don't need to supply a conversion hash because postgres
|
197
|
+
knows how to convert it to the desired time zone. However, if you do the same
|
198
|
+
for the second case, you might get surprises, especially if your Postgres
|
199
|
+
installation's default timezone is not `UTC`.
|
179
200
|
- ⚠️ SQLite is not supported.
|
180
201
|
- 🚨 Always test against your setup 🚨
|
181
202
|
|
@@ -10,7 +10,7 @@ module ArelExtensions
|
|
10
10
|
def initialize expr
|
11
11
|
col = expr[0]
|
12
12
|
@iso_format = convert_format(expr[1])
|
13
|
-
@time_zone =
|
13
|
+
@time_zone = expr[2]
|
14
14
|
@col_type = type_of_attribute(col)
|
15
15
|
super [col, convert_to_string_node(@iso_format)]
|
16
16
|
end
|
@@ -276,9 +276,16 @@ module ArelExtensions
|
|
276
276
|
collector << ' '
|
277
277
|
end
|
278
278
|
collector = visit o.left, collector
|
279
|
-
|
280
|
-
|
281
|
-
|
279
|
+
case o.time_zone
|
280
|
+
when Hash
|
281
|
+
src_tz, dst_tz = o.time_zone.first
|
282
|
+
collector << ') AT TIME ZONE '
|
283
|
+
collector = visit Arel::Nodes.build_quoted(src_tz), collector
|
284
|
+
collector << ' AT TIME ZONE '
|
285
|
+
collector = visit Arel::Nodes.build_quoted(dst_tz), collector
|
286
|
+
when String
|
287
|
+
collector << ') AT TIME ZONE '
|
288
|
+
collector = visit Arel::Nodes.build_quoted(o.time_zone), collector
|
282
289
|
end
|
283
290
|
collector << LOADED_VISITOR::COMMA
|
284
291
|
collector << fmt.to_s
|
@@ -307,9 +314,16 @@ module ArelExtensions
|
|
307
314
|
collector << ' '
|
308
315
|
end
|
309
316
|
collector = visit o.left, collector
|
310
|
-
|
311
|
-
|
312
|
-
|
317
|
+
case o.time_zone
|
318
|
+
when Hash
|
319
|
+
src_tz, dst_tz = o.time_zone.first.first, o.time_zone.first.second
|
320
|
+
collector << ") AT TIME ZONE "
|
321
|
+
collector = visit Arel::Nodes.build_quoted(src_tz), collector
|
322
|
+
collector << " AT TIME ZONE "
|
323
|
+
collector = visit Arel::Nodes.build_quoted(dst_tz), collector
|
324
|
+
when String
|
325
|
+
collector << ") AT TIME ZONE "
|
326
|
+
collector = visit Arel::Nodes.build_quoted(o.time_zone), collector
|
313
327
|
end
|
314
328
|
collector << ')'
|
315
329
|
collector << ')' if !fmt
|
@@ -211,9 +211,17 @@ module ArelExtensions
|
|
211
211
|
collector << "DATE_FORMAT("
|
212
212
|
collector << "CONVERT_TZ(" if o.time_zone
|
213
213
|
collector = visit o.left, collector
|
214
|
-
|
214
|
+
case o.time_zone
|
215
|
+
when Hash
|
216
|
+
src_tz, dst_tz = o.time_zone.first
|
217
|
+
collector << COMMA
|
218
|
+
collector = visit Arel::Nodes.build_quoted(src_tz), collector
|
219
|
+
collector << COMMA
|
220
|
+
collector = visit Arel::Nodes.build_quoted(dst_tz), collector
|
221
|
+
collector << ')'
|
222
|
+
when String
|
215
223
|
collector << COMMA << "'UTC'" << COMMA
|
216
|
-
collector = visit o.time_zone, collector
|
224
|
+
collector = visit Arel::Nodes.build_quoted(o.time_zone), collector
|
217
225
|
collector << ')'
|
218
226
|
end
|
219
227
|
collector << COMMA
|
@@ -449,9 +449,16 @@ module ArelExtensions
|
|
449
449
|
collector << "TO_CHAR("
|
450
450
|
collector << "CAST(" if o.time_zone
|
451
451
|
collector = visit o.left, collector
|
452
|
-
|
453
|
-
|
454
|
-
|
452
|
+
case o.time_zone
|
453
|
+
when Hash
|
454
|
+
src_tz, dst_tz = o.time_zone.first
|
455
|
+
collector << ' as timestamp) at time zone '
|
456
|
+
collector = visit Arel::Nodes.build_quoted(src_tz), collector
|
457
|
+
collecto < ' at time zone '
|
458
|
+
collector = visit Arel::Nodes.build_quoted(dst_tz), collector
|
459
|
+
when String
|
460
|
+
collector << ' as timestamp) at time zone '
|
461
|
+
collector = visit Arel::Nodes.build_quoted(o.time_zone), collector
|
455
462
|
end
|
456
463
|
collector << COMMA
|
457
464
|
collector = visit Arel::Nodes.build_quoted(fmt), collector
|
@@ -175,10 +175,18 @@ module ArelExtensions
|
|
175
175
|
def visit_ArelExtensions_Nodes_Format o, collector
|
176
176
|
fmt = ArelExtensions::Visitors::strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
|
177
177
|
collector << "TO_CHAR("
|
178
|
+
collector << '(' if o.time_zone
|
178
179
|
collector = visit o.left, collector
|
179
|
-
|
180
|
-
|
181
|
-
|
180
|
+
case o.time_zone
|
181
|
+
when Hash
|
182
|
+
src_tz, dst_tz = o.time_zone.first
|
183
|
+
collector << ') AT TIME ZONE '
|
184
|
+
collector = visit Arel::Nodes.build_quoted(src_tz), collector
|
185
|
+
collector << ' AT TIME ZONE '
|
186
|
+
collector = visit Arel::Nodes.build_quoted(dst_tz), collector
|
187
|
+
when String
|
188
|
+
collector << ') AT TIME ZONE '
|
189
|
+
collector = visit Arel::Nodes.build_quoted(o.time_zone), collector
|
182
190
|
end
|
183
191
|
collector << COMMA
|
184
192
|
collector = visit Arel::Nodes.build_quoted(fmt), collector
|
data/test/arelx_test_helper.rb
CHANGED
@@ -403,35 +403,39 @@ module ArelExtensions
|
|
403
403
|
'tahiti' => 'Hawaiian Standard Time',
|
404
404
|
'paris' => 'Central European Standard Time'
|
405
405
|
},
|
406
|
-
'
|
406
|
+
'posix' => {
|
407
407
|
'utc' => 'UTC',
|
408
408
|
'sao_paulo' => 'America/Sao_Paulo',
|
409
409
|
'tahiti' => 'Pacific/Tahiti',
|
410
410
|
'paris' => 'Europe/Paris'
|
411
|
-
}
|
412
|
-
'oracle' => {
|
413
|
-
'utc' => 'UTC',
|
414
|
-
'sao_paulo' => 'America/Sao_Paulo',
|
415
|
-
'tahiti' => 'Pacific/Tahiti',
|
416
|
-
'paris' => 'Europe/Paris'
|
417
|
-
},
|
418
|
-
'postgresql' => {
|
419
|
-
'utc' => 'UTC',
|
420
|
-
'sao_paulo' => 'America/Sao Paulo (-03)',
|
421
|
-
'tahiti' => 'Pacific/Tahiti (-10)',
|
422
|
-
'paris' => 'Europe/Paris'
|
423
|
-
},
|
411
|
+
}
|
424
412
|
}
|
425
413
|
|
426
|
-
|
427
|
-
|
414
|
+
skip "Unsupported timezone conversion for DB=#{ENV['DB']}" if !['mssql', 'mysql', 'oracle', 'postgresql'].include?(ENV['DB'])
|
415
|
+
|
416
|
+
tz = ENV['DB'] == 'mssql' ? time_zones['mssql'] : time_zones['posix']
|
417
|
+
|
428
418
|
assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', tz['utc']))
|
429
|
-
assert_equal '2014/03/03 09:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', tz['sao_paulo']))
|
430
|
-
assert_equal '2014/03/03 02:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', tz['tahiti']))
|
419
|
+
assert_equal '2014/03/03 09:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', { tz['utc'] => tz['sao_paulo'] }))
|
420
|
+
assert_equal '2014/03/03 02:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', { tz['utc'] => tz['tahiti'] }))
|
421
|
+
|
422
|
+
# Skipping conversion from UTC to the desired timezones fails in SQL
|
423
|
+
# Server and Postgres. This is mainly due to the fact that timezone
|
424
|
+
# information is not preserved in the column itself.
|
425
|
+
#
|
426
|
+
# MySQL is happy to consider that times by default are in UTC.
|
427
|
+
assert_equal '2014/03/03 13:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', { tz['utc'] => tz['paris'] }))
|
428
|
+
refute_equal '2014/03/03 13:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', tz['paris'])) if !['mysql'].include?(ENV['DB'])
|
431
429
|
|
432
430
|
# Winter/Summer time
|
433
|
-
assert_equal '
|
434
|
-
|
431
|
+
assert_equal '2014/08/03 14:42:00', t(@lucas, (@updated_at + 5.months).format('%Y/%m/%d %H:%M:%S', { tz['utc'] => tz['paris'] }))
|
432
|
+
if ENV['DB'] == 'mssql'
|
433
|
+
assert_equal '2022/02/01 11:42:00', t(@lucas, Arel::Nodes.build_quoted('2022-02-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', { tz['utc'] => tz['paris'] }))
|
434
|
+
assert_equal '2022/08/01 12:42:00', t(@lucas, Arel::Nodes.build_quoted('2022-08-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', { tz['utc'] => tz['paris'] }))
|
435
|
+
else
|
436
|
+
assert_equal '2022/02/01 11:42:00', t(@lucas, Arel::Nodes.build_quoted('2022-02-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', tz['paris']))
|
437
|
+
assert_equal '2022/08/01 12:42:00', t(@lucas, Arel::Nodes.build_quoted('2022-08-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', tz['paris']))
|
438
|
+
end
|
435
439
|
end
|
436
440
|
|
437
441
|
def test_coalesce
|
data/version_v1.rb
CHANGED
data/version_v2.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arel_extensions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yann Azoury
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2022-03-
|
13
|
+
date: 2022-03-04 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: arel
|