arel_extensions 2.1.1 → 2.1.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/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: c069fafddb858e0acc7cee0bf1bc435c2127ccdf6e5d870b8e9caff0d31abdb1
|
4
|
+
data.tar.gz: 2d0898c4d35fbe0ac72ccb395ef79ae63f10b662ce6003cea0702d55c27b2729
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa4f685f2548b172488d6f3537754c51ad269773a2ff525b7e114e8d4da38bfe41c38cbeee20cb67d7557b46c39c10d218e80181ffa5ebe6be393763981d57d3
|
7
|
+
data.tar.gz: 664cf3c829c5df39b3ef8c9913cec516214482e328f01a8c71370aa937abc47194a20b31b8d930a297c322e22025d1af9b1b49384df08ec65860203b8bf27f78
|
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: 2.1.
|
4
|
+
version: 2.1.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: activerecord
|