arel_extensions 1.3.6 → 1.3.7
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/.github/workflows/ruby.yml +80 -65
- data/NEWS.md +20 -3
- data/README.md +34 -9
- data/gemfiles/rails6_1.gemfile +1 -1
- data/gemfiles/rails7.gemfile +1 -1
- data/lib/arel_extensions/date_duration.rb +5 -0
- data/lib/arel_extensions/nodes/formatted_date.rb +42 -0
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +4 -0
- data/lib/arel_extensions/visitors/mysql.rb +28 -22
- data/lib/arel_extensions/visitors/oracle.rb +4 -0
- data/lib/arel_extensions/visitors/postgresql.rb +4 -0
- data/lib/arel_extensions/visitors/to_sql.rb +20 -0
- data/test/with_ar/all_agnostic_test.rb +141 -121
- data/version_v1.rb +1 -1
- data/version_v2.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6d8d074334ab5ecab7fc6b0d4d9a24180b83d4d3c9a0e7c9237d9ec567146272
|
|
4
|
+
data.tar.gz: 0cf4c51ebd196eb2671506f0aef243c9cd6332bb5f55eac89c77024c105390ff
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 89ae8015b86e8ead47050f5af4dba33f851d02eeafa9a8123752fb24911ae46124391fdc7e3e5f09da41f0efc092ee4b7f084b6f01572e07ab5376d507c2741c
|
|
7
|
+
data.tar.gz: 988bef22406e320405f71dec5ca8e666de0acc8f87bc3b67f755951788ddca7fb92b65d2e313144413c3cde2adb4363e0e87aea418dfd691889a650e2fd57166
|
data/.github/workflows/ruby.yml
CHANGED
|
@@ -13,19 +13,21 @@ jobs:
|
|
|
13
13
|
fail-fast: false
|
|
14
14
|
matrix:
|
|
15
15
|
versions: [
|
|
16
|
-
{ruby: 3.
|
|
17
|
-
{ruby: 3.
|
|
18
|
-
{ruby: 3.
|
|
19
|
-
{ruby: 3.
|
|
20
|
-
{ruby:
|
|
21
|
-
{ruby:
|
|
22
|
-
{ruby: 2.7,
|
|
23
|
-
{ruby: 2.7,
|
|
24
|
-
{ruby: 2.7,
|
|
25
|
-
{ruby: 2.
|
|
26
|
-
{ruby: 2.
|
|
27
|
-
{ruby: 2.5,
|
|
28
|
-
{ruby: 2.5,
|
|
16
|
+
{ruby: '3.2', rails: 7, arelx: 2},
|
|
17
|
+
{ruby: '3.2', rails: 6_1, arelx: 2},
|
|
18
|
+
{ruby: '3.1', rails: 7, arelx: 2},
|
|
19
|
+
{ruby: '3.1', rails: 6_1, arelx: 2},
|
|
20
|
+
{ruby: '3.0', rails: 7, arelx: 2},
|
|
21
|
+
{ruby: '3.0', rails: 6_1, arelx: 2},
|
|
22
|
+
{ruby: '2.7', rails: 7, arelx: 2},
|
|
23
|
+
{ruby: '2.7', rails: 6_1, arelx: 2},
|
|
24
|
+
{ruby: '2.7', rails: 6, arelx: 2},
|
|
25
|
+
{ruby: '2.7', rails: 5_2, arelx: 1},
|
|
26
|
+
{ruby: '2.7', rails: 4_2, arelx: 1},
|
|
27
|
+
{ruby: '2.5', rails: 6_1, arelx: 2},
|
|
28
|
+
{ruby: '2.5', rails: 6, arelx: 2},
|
|
29
|
+
{ruby: '2.5', rails: 5_2, arelx: 1},
|
|
30
|
+
{ruby: '2.5', rails: 4_2, arelx: 1},
|
|
29
31
|
{ruby: jruby-9.2, rails: 6_1, arelx: 2},
|
|
30
32
|
{ruby: jruby-9.2, rails: 6, arelx: 2},
|
|
31
33
|
{ruby: jruby-9.2, rails: 5_2, arelx: 1},
|
|
@@ -44,6 +46,7 @@ jobs:
|
|
|
44
46
|
sudo apt-get update -q
|
|
45
47
|
sudo apt-get install -y freetds-dev
|
|
46
48
|
- name: Update system-wide gems
|
|
49
|
+
if: ${{ !contains(fromJson('["2.5", "jruby-9.2"]'), matrix.versions.ruby) }}
|
|
47
50
|
run: gem update --system --no-document
|
|
48
51
|
- name: Setup Gemfile for arelx 2.x
|
|
49
52
|
if: ${{ matrix.versions.arelx == 2 }}
|
|
@@ -65,19 +68,21 @@ jobs:
|
|
|
65
68
|
fail-fast: false
|
|
66
69
|
matrix:
|
|
67
70
|
versions: [
|
|
68
|
-
{ruby: 3.
|
|
69
|
-
{ruby: 3.
|
|
70
|
-
{ruby: 3.
|
|
71
|
-
{ruby: 3.
|
|
72
|
-
{ruby:
|
|
73
|
-
{ruby:
|
|
74
|
-
{ruby: 2.7,
|
|
75
|
-
{ruby: 2.7,
|
|
76
|
-
{ruby: 2.7,
|
|
77
|
-
{ruby: 2.
|
|
78
|
-
{ruby: 2.
|
|
79
|
-
{ruby: 2.5,
|
|
80
|
-
{ruby: 2.5,
|
|
71
|
+
{ruby: '3.2', rails: 7, arelx: 2},
|
|
72
|
+
{ruby: '3.2', rails: 6_1, arelx: 2},
|
|
73
|
+
{ruby: '3.1', rails: 7, arelx: 2},
|
|
74
|
+
{ruby: '3.1', rails: 6_1, arelx: 2},
|
|
75
|
+
{ruby: '3.0', rails: 7, arelx: 2},
|
|
76
|
+
{ruby: '3.0', rails: 6_1, arelx: 2},
|
|
77
|
+
{ruby: '2.7', rails: 7, arelx: 2},
|
|
78
|
+
{ruby: '2.7', rails: 6_1, arelx: 2},
|
|
79
|
+
{ruby: '2.7', rails: 6, arelx: 2},
|
|
80
|
+
{ruby: '2.7', rails: 5_2, arelx: 1},
|
|
81
|
+
{ruby: '2.7', rails: 4_2, arelx: 1},
|
|
82
|
+
{ruby: '2.5', rails: 6_1, arelx: 2},
|
|
83
|
+
{ruby: '2.5', rails: 6, arelx: 2},
|
|
84
|
+
{ruby: '2.5', rails: 5_2, arelx: 1},
|
|
85
|
+
{ruby: '2.5', rails: 4_2, arelx: 1},
|
|
81
86
|
{ruby: jruby-9.2, rails: 6_1, arelx: 2},
|
|
82
87
|
{ruby: jruby-9.2, rails: 6, arelx: 2},
|
|
83
88
|
{ruby: jruby-9.2, rails: 5_2, arelx: 1},
|
|
@@ -97,6 +102,7 @@ jobs:
|
|
|
97
102
|
sudo apt-get update -q
|
|
98
103
|
sudo apt-get install -y freetds-dev
|
|
99
104
|
- name: Update system-wide gems
|
|
105
|
+
if: ${{ !contains(fromJson('["2.5", "jruby-9.2"]'), matrix.versions.ruby) }}
|
|
100
106
|
run: gem update --system --no-document
|
|
101
107
|
- name: Setup Gemfile
|
|
102
108
|
if: ${{ matrix.versions.arelx == 2 }}
|
|
@@ -118,19 +124,21 @@ jobs:
|
|
|
118
124
|
fail-fast: false
|
|
119
125
|
matrix:
|
|
120
126
|
versions: [
|
|
121
|
-
{ruby: 3.
|
|
122
|
-
{ruby: 3.
|
|
123
|
-
{ruby: 3.
|
|
124
|
-
{ruby: 3.
|
|
125
|
-
{ruby:
|
|
126
|
-
{ruby:
|
|
127
|
-
{ruby: 2.7,
|
|
128
|
-
{ruby: 2.7,
|
|
129
|
-
{ruby: 2.7,
|
|
130
|
-
{ruby: 2.
|
|
131
|
-
{ruby: 2.
|
|
132
|
-
{ruby: 2.5,
|
|
133
|
-
{ruby: 2.5,
|
|
127
|
+
{ruby: '3.2', rails: 7, arelx: 2},
|
|
128
|
+
{ruby: '3.2', rails: 6_1, arelx: 2},
|
|
129
|
+
{ruby: '3.1', rails: 7, arelx: 2},
|
|
130
|
+
{ruby: '3.1', rails: 6_1, arelx: 2},
|
|
131
|
+
{ruby: '3.0', rails: 7, arelx: 2},
|
|
132
|
+
{ruby: '3.0', rails: 6_1, arelx: 2},
|
|
133
|
+
{ruby: '2.7', rails: 7, arelx: 2},
|
|
134
|
+
{ruby: '2.7', rails: 6_1, arelx: 2},
|
|
135
|
+
{ruby: '2.7', rails: 6, arelx: 2},
|
|
136
|
+
{ruby: '2.7', rails: 5_2, arelx: 1},
|
|
137
|
+
{ruby: '2.7', rails: 4_2, arelx: 1},
|
|
138
|
+
{ruby: '2.5', rails: 6_1, arelx: 2},
|
|
139
|
+
{ruby: '2.5', rails: 6, arelx: 2},
|
|
140
|
+
{ruby: '2.5', rails: 5_2, arelx: 1},
|
|
141
|
+
{ruby: '2.5', rails: 4_2, arelx: 1},
|
|
134
142
|
{ruby: jruby-9.2, rails: 6_1, arelx: 2},
|
|
135
143
|
{ruby: jruby-9.2, rails: 6, arelx: 2},
|
|
136
144
|
{ruby: jruby-9.2, rails: 5_2, arelx: 1},
|
|
@@ -172,6 +180,7 @@ jobs:
|
|
|
172
180
|
sudo apt-get update -q
|
|
173
181
|
sudo apt-get install -y freetds-dev
|
|
174
182
|
- name: Update system-wide gems
|
|
183
|
+
if: ${{ !contains(fromJson('["2.5", "jruby-9.2"]'), matrix.versions.ruby) }}
|
|
175
184
|
run: gem update --system --no-document
|
|
176
185
|
- name: Setup Gemfile
|
|
177
186
|
if: ${{ matrix.versions.arelx == 2 }}
|
|
@@ -196,19 +205,21 @@ jobs:
|
|
|
196
205
|
fail-fast: false
|
|
197
206
|
matrix:
|
|
198
207
|
versions: [
|
|
199
|
-
{ruby: 3.
|
|
200
|
-
{ruby: 3.
|
|
201
|
-
{ruby: 3.
|
|
202
|
-
{ruby: 3.
|
|
203
|
-
{ruby:
|
|
204
|
-
{ruby:
|
|
205
|
-
{ruby: 2.7,
|
|
206
|
-
{ruby: 2.7,
|
|
207
|
-
{ruby: 2.7,
|
|
208
|
-
{ruby: 2.
|
|
209
|
-
{ruby: 2.
|
|
210
|
-
{ruby: 2.5,
|
|
211
|
-
{ruby: 2.5,
|
|
208
|
+
{ruby: '3.2', rails: 7, arelx: 2},
|
|
209
|
+
{ruby: '3.2', rails: 6_1, arelx: 2},
|
|
210
|
+
{ruby: '3.1', rails: 7, arelx: 2},
|
|
211
|
+
{ruby: '3.1', rails: 6_1, arelx: 2},
|
|
212
|
+
{ruby: '3.0', rails: 7, arelx: 2},
|
|
213
|
+
{ruby: '3.0', rails: 6_1, arelx: 2},
|
|
214
|
+
{ruby: '2.7', rails: 7, arelx: 2},
|
|
215
|
+
{ruby: '2.7', rails: 6_1, arelx: 2},
|
|
216
|
+
{ruby: '2.7', rails: 6, arelx: 2},
|
|
217
|
+
{ruby: '2.7', rails: 5_2, arelx: 1},
|
|
218
|
+
{ruby: '2.7', rails: 4_2, arelx: 1},
|
|
219
|
+
{ruby: '2.5', rails: 6_1, arelx: 2},
|
|
220
|
+
{ruby: '2.5', rails: 6, arelx: 2},
|
|
221
|
+
{ruby: '2.5', rails: 5_2, arelx: 1},
|
|
222
|
+
{ruby: '2.5', rails: 4_2, arelx: 1},
|
|
212
223
|
{ruby: jruby-9.2, rails: 6_1, arelx: 2},
|
|
213
224
|
{ruby: jruby-9.2, rails: 6, arelx: 2},
|
|
214
225
|
{ruby: jruby-9.2, rails: 5_2, arelx: 1},
|
|
@@ -242,6 +253,7 @@ jobs:
|
|
|
242
253
|
sudo apt-get update -q
|
|
243
254
|
sudo apt-get install -y freetds-dev
|
|
244
255
|
- name: Update system-wide gems
|
|
256
|
+
if: ${{ !contains(fromJson('["2.5", "jruby-9.2"]'), matrix.versions.ruby) }}
|
|
245
257
|
run: gem update --system --no-document
|
|
246
258
|
- name: Setup Gemfile
|
|
247
259
|
if: ${{ matrix.versions.arelx == 2 }}
|
|
@@ -269,19 +281,21 @@ jobs:
|
|
|
269
281
|
fail-fast: false
|
|
270
282
|
matrix:
|
|
271
283
|
versions: [
|
|
272
|
-
# {ruby: 3.
|
|
273
|
-
{ruby: 3.
|
|
274
|
-
# {ruby: 3.
|
|
275
|
-
{ruby: 3.
|
|
276
|
-
# {ruby:
|
|
277
|
-
{ruby:
|
|
278
|
-
{ruby: 2.7,
|
|
279
|
-
{ruby: 2.7,
|
|
280
|
-
{ruby: 2.7,
|
|
281
|
-
{ruby: 2.
|
|
282
|
-
{ruby: 2.
|
|
283
|
-
{ruby: 2.5,
|
|
284
|
-
{ruby: 2.5,
|
|
284
|
+
# {ruby: '3.2', rails: 7, arelx: 2},
|
|
285
|
+
{ruby: '3.2', rails: 6_1, arelx: 2},
|
|
286
|
+
# {ruby: '3.1', rails: 7, arelx: 2},
|
|
287
|
+
{ruby: '3.1', rails: 6_1, arelx: 2},
|
|
288
|
+
# {ruby: '3.0', rails: 7, arelx: 2},
|
|
289
|
+
{ruby: '3.0', rails: 6_1, arelx: 2},
|
|
290
|
+
# {ruby: '2.7', rails: 7, arelx: 2},
|
|
291
|
+
{ruby: '2.7', rails: 6_1, arelx: 2},
|
|
292
|
+
{ruby: '2.7', rails: 6, arelx: 2},
|
|
293
|
+
{ruby: '2.7', rails: 5_2, arelx: 1},
|
|
294
|
+
{ruby: '2.7', rails: 4_2, arelx: 1},
|
|
295
|
+
{ruby: '2.5', rails: 6_1, arelx: 2},
|
|
296
|
+
{ruby: '2.5', rails: 6, arelx: 2},
|
|
297
|
+
{ruby: '2.5', rails: 5_2, arelx: 1},
|
|
298
|
+
{ruby: '2.5', rails: 4_2, arelx: 1},
|
|
285
299
|
# {ruby: jruby-9.2, rails: 6_1, arelx: 2},
|
|
286
300
|
# {ruby: jruby-9.2, rails: 6, arelx: 2},
|
|
287
301
|
{ruby: jruby-9.2, rails: 5_2, arelx: 1},
|
|
@@ -308,6 +322,7 @@ jobs:
|
|
|
308
322
|
install: sqlengine, sqlclient, sqlpackage, localdb
|
|
309
323
|
sa-password: Password12!
|
|
310
324
|
- name: Update system-wide gems
|
|
325
|
+
if: ${{ !contains(fromJson('["2.5", "jruby-9.2"]'), matrix.versions.ruby) }}
|
|
311
326
|
run: gem update --system --no-document
|
|
312
327
|
- name: Setup Gemfile
|
|
313
328
|
if: ${{ matrix.versions.arelx == 2 }}
|
data/NEWS.md
CHANGED
|
@@ -1,13 +1,30 @@
|
|
|
1
|
-
#
|
|
1
|
+
# News
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Current Release
|
|
4
|
+
|
|
5
|
+
### New Features
|
|
6
|
+
|
|
7
|
+
- `o.format_date` as an alternative to `o.format`
|
|
8
|
+
The actual behavior of `format` is inconsistent across DB vendors: in mysql we
|
|
9
|
+
can format dates and numbers with it, and in the other ones we only format
|
|
10
|
+
dates.
|
|
11
|
+
|
|
12
|
+
We're planning on normalizing this behavior. We want `format` to "cleverly"
|
|
13
|
+
format dates or numbers, and `format_date` / `format_number` to strictly
|
|
14
|
+
format dates / numbers.
|
|
15
|
+
|
|
16
|
+
The introduction of `format_date` is the first step in this direction.
|
|
17
|
+
|
|
18
|
+
## Release v2.1.6/v1.3.6
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
4
21
|
|
|
5
22
|
- This used to fail.
|
|
6
23
|
```
|
|
7
24
|
Arel.when(a).then(b).format('%Y-%m-%d')
|
|
8
25
|
```
|
|
9
26
|
|
|
10
|
-
|
|
27
|
+
### New Features
|
|
11
28
|
|
|
12
29
|
- `o.present`, a synonym for `o.not_blank`
|
|
13
30
|
- `o.coalesce_blank(a, b, c)`
|
data/README.md
CHANGED
|
@@ -36,7 +36,8 @@ It will add common SQL features in your DB to align ti with current routines. Te
|
|
|
36
36
|
|
|
37
37
|
## Examples
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
In the following examples
|
|
40
|
+
`t` is an `Arel::Table` for table `my_table` (i.e., `t = Arel::Table.new('my_table')`).
|
|
40
41
|
|
|
41
42
|
## Comparators
|
|
42
43
|
|
|
@@ -50,7 +51,7 @@ t is an Arel::Table for table my_table
|
|
|
50
51
|
# => my_table.nb > 42
|
|
51
52
|
```
|
|
52
53
|
|
|
53
|
-
Other operators
|
|
54
|
+
Other operators: <, >=, <=, =~
|
|
54
55
|
|
|
55
56
|
|
|
56
57
|
## Maths
|
|
@@ -73,7 +74,7 @@ With Arel Extensions:
|
|
|
73
74
|
# => SUM(my_table.nb) + 42
|
|
74
75
|
```
|
|
75
76
|
|
|
76
|
-
Other functions
|
|
77
|
+
Other functions: ABS, RAND, ROUND, FLOOR, CEIL, FORMAT
|
|
77
78
|
|
|
78
79
|
For Example:
|
|
79
80
|
```ruby
|
|
@@ -94,14 +95,29 @@ t[:price].format_number("%07.2f €","fr_FR")
|
|
|
94
95
|
# => TRIM(TRIM(TRIM(COALESCE(my_table.name, '')), '\t'), '\n') = ''
|
|
95
96
|
|
|
96
97
|
(t[:name] =~ /\A[a-d_]+/).to_sql
|
|
97
|
-
# => my_table.name REGEXP '
|
|
98
|
+
# => my_table.name REGEXP '^[a-d_]+'
|
|
98
99
|
```
|
|
99
100
|
|
|
100
|
-
|
|
101
|
+
The `replace` function supports string and regex patterns.
|
|
102
|
+
For instance
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
t[:email].replace('@', ' at ').replace('.', ' dot ').to_sql
|
|
106
|
+
# => REPLACE(REPLACE(`my_table`.`email`, '@', ' at '), '.', ' dot ')
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Captures are supported when using regex patterns. The replace string may then reference the capture groups using `\1`, `\2`, etc. For instance
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
t[:email].replace(/^(.*)@(.*)$/, 'user: \1, host: \2').to_sql
|
|
113
|
+
# => REGEXP_REPLACE(`my_table`.`email`, '(?-mix:^(.*)@(.*)$)', 'user: \\1, host: \\2')
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Other functions: SOUNDEX, LENGTH, REPLACE, LOCATE, SUBSTRING, TRIM
|
|
101
117
|
|
|
102
118
|
### String Array operations
|
|
103
119
|
|
|
104
|
-
|
|
120
|
+
`t[:list]` is a classical varchar containing a comma separated list (`"1,2,3,4"`).
|
|
105
121
|
|
|
106
122
|
```ruby
|
|
107
123
|
(t[:list] & 3).to_sql
|
|
@@ -228,15 +244,15 @@ t[:id].cast('char').to_sql
|
|
|
228
244
|
## Stored Procedures and User-defined functions
|
|
229
245
|
|
|
230
246
|
To optimize queries, some classical functions are defined in databases missing any alternative native functions.
|
|
231
|
-
Examples
|
|
232
|
-
- FIND_IN_SET
|
|
247
|
+
Examples:
|
|
248
|
+
- `FIND_IN_SET`
|
|
233
249
|
|
|
234
250
|
## BULK INSERT / UPSERT
|
|
235
251
|
|
|
236
252
|
Arel Extensions improves InsertManager by adding bulk_insert method, which allows to insert multiple rows in one insert.
|
|
237
253
|
|
|
238
254
|
|
|
239
|
-
```
|
|
255
|
+
```ruby
|
|
240
256
|
@cols = ['id', 'name', 'comments', 'created_at']
|
|
241
257
|
@data = [
|
|
242
258
|
[23, 'name1', "sdfdsfdsfsdf", '2016-01-01'],
|
|
@@ -437,6 +453,15 @@ User.connection.execute(insert_manager.to_sql)
|
|
|
437
453
|
<td class="ok">✔</td>
|
|
438
454
|
<td class="ok">✔</td>
|
|
439
455
|
</tr>
|
|
456
|
+
<tr>
|
|
457
|
+
<td class="tg-yw4l">REPLACE<br>column.replace(/re/,"X")</td>
|
|
458
|
+
<td class="ok">✔</td>
|
|
459
|
+
<td class="ok">✔</td>
|
|
460
|
+
<td class="ok">✔</td>
|
|
461
|
+
<td class="ok">✔</td>
|
|
462
|
+
<td class="ok">✔</td>
|
|
463
|
+
<td class="ok">✔</td>
|
|
464
|
+
</tr>
|
|
440
465
|
<tr>
|
|
441
466
|
<td class="tg-yw4l">SOUNDEX<br>column.soundex</td>
|
|
442
467
|
<td class="ok">✔</td>
|
data/gemfiles/rails6_1.gemfile
CHANGED
|
@@ -9,7 +9,7 @@ group :development, :test do
|
|
|
9
9
|
gem 'activerecord', '~> 6.1.0'
|
|
10
10
|
|
|
11
11
|
gem 'sqlite3', '~> 1.4', platforms: [:mri]
|
|
12
|
-
gem 'mysql2', '0.5
|
|
12
|
+
gem 'mysql2', '~>0.5', platforms: [:mri]
|
|
13
13
|
gem 'pg', '~> 1.1', platforms: [:mri]
|
|
14
14
|
|
|
15
15
|
gem 'tiny_tds', platforms: %i[mri mingw x64_mingw mswin]
|
data/gemfiles/rails7.gemfile
CHANGED
|
@@ -9,7 +9,7 @@ group :development, :test do
|
|
|
9
9
|
gem 'activerecord', '~> 7.0.1'
|
|
10
10
|
|
|
11
11
|
gem 'sqlite3', '~> 1.4', platforms: [:mri]
|
|
12
|
-
gem 'mysql2', '0.5
|
|
12
|
+
gem 'mysql2', '~>0.5', platforms: [:mri]
|
|
13
13
|
gem 'pg', '~> 1.1', platforms: [:mri]
|
|
14
14
|
|
|
15
15
|
gem 'tiny_tds', platforms: %i[mri mingw x64_mingw mswin]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'arel_extensions/nodes/format'
|
|
2
|
+
require 'arel_extensions/nodes/formatted_date'
|
|
2
3
|
require 'arel_extensions/nodes/duration'
|
|
3
4
|
require 'arel_extensions/nodes/wday'
|
|
4
5
|
|
|
@@ -43,5 +44,9 @@ module ArelExtensions
|
|
|
43
44
|
def format(tpl, time_zone = nil)
|
|
44
45
|
ArelExtensions::Nodes::Format.new [self, tpl, time_zone]
|
|
45
46
|
end
|
|
47
|
+
|
|
48
|
+
def format_date(tpl, time_zone = nil)
|
|
49
|
+
ArelExtensions::Nodes::FormattedDate.new [self, tpl, time_zone]
|
|
50
|
+
end
|
|
46
51
|
end
|
|
47
52
|
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'strscan'
|
|
2
|
+
|
|
3
|
+
module ArelExtensions
|
|
4
|
+
module Nodes
|
|
5
|
+
class FormattedDate < Function
|
|
6
|
+
RETURN_TYPE = :string
|
|
7
|
+
|
|
8
|
+
attr_accessor :col_type, :iso_format, :time_zone
|
|
9
|
+
|
|
10
|
+
def initialize expr
|
|
11
|
+
col = expr[0]
|
|
12
|
+
@iso_format = convert_format(expr[1])
|
|
13
|
+
@time_zone = expr[2]
|
|
14
|
+
@col_type = type_of_attribute(col)
|
|
15
|
+
super [col, convert_to_string_node(@iso_format)]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
# Address portability issues with some of the formats.
|
|
21
|
+
def convert_format(fmt)
|
|
22
|
+
s = StringScanner.new fmt
|
|
23
|
+
res = StringIO.new
|
|
24
|
+
while !s.eos?
|
|
25
|
+
res <<
|
|
26
|
+
case
|
|
27
|
+
when s.scan(/%D/) then '%m/%d/%y'
|
|
28
|
+
when s.scan(/%F/) then '%Y-%m-%d'
|
|
29
|
+
when s.scan(/%R/) then '%H:%M'
|
|
30
|
+
when s.scan(/%r/) then '%I:%M:%S %p'
|
|
31
|
+
when s.scan(/%T/) then '%H:%M:%S'
|
|
32
|
+
when s.scan(/%v/) then '%e-%b-%Y'
|
|
33
|
+
|
|
34
|
+
when s.scan(/[^%]+/) then s.matched
|
|
35
|
+
when s.scan(/./) then s.matched
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
res.string
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -355,6 +355,10 @@ module ArelExtensions
|
|
|
355
355
|
end
|
|
356
356
|
|
|
357
357
|
def visit_ArelExtensions_Nodes_Format o, collector
|
|
358
|
+
visit_ArelExtensions_Nodes_FormattedDate o, collector
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
def visit_ArelExtensions_Nodes_FormattedDate o, collector
|
|
358
362
|
f = ArelExtensions::Visitors::strftime_to_format(o.iso_format, LOADED_VISITOR::DATE_FORMAT_DIRECTIVES)
|
|
359
363
|
if fmt = LOADED_VISITOR::DATE_CONVERT_FORMATS[f]
|
|
360
364
|
collector << "CONVERT(VARCHAR(#{f.length})"
|
|
@@ -258,33 +258,16 @@ module ArelExtensions
|
|
|
258
258
|
# In this case, `o.col_type` is `nil` but we have a legitimate type in
|
|
259
259
|
# the expression to be formatted. The following is a best effort to
|
|
260
260
|
# infer the proper type.
|
|
261
|
+
first = o.expressions[0]
|
|
261
262
|
type =
|
|
262
|
-
o.col_type.nil?
|
|
263
|
-
|
|
263
|
+
o.col_type.nil? \
|
|
264
|
+
&& (first.respond_to?(:return_type) && !first&.return_type.nil?) \
|
|
265
|
+
? first&.return_type \
|
|
264
266
|
: o.col_type
|
|
265
267
|
|
|
266
268
|
case type
|
|
267
269
|
when :date, :datetime, :time
|
|
268
|
-
|
|
269
|
-
collector << 'DATE_FORMAT('
|
|
270
|
-
collector << 'CONVERT_TZ(' if o.time_zone
|
|
271
|
-
collector = visit o.left, collector
|
|
272
|
-
case o.time_zone
|
|
273
|
-
when Hash
|
|
274
|
-
src_tz, dst_tz = o.time_zone.first
|
|
275
|
-
collector << COMMA
|
|
276
|
-
collector = visit Arel.quoted(src_tz), collector
|
|
277
|
-
collector << COMMA
|
|
278
|
-
collector = visit Arel.quoted(dst_tz), collector
|
|
279
|
-
collector << ')'
|
|
280
|
-
when String
|
|
281
|
-
collector << COMMA << "'UTC'" << COMMA
|
|
282
|
-
collector = visit Arel.quoted(o.time_zone), collector
|
|
283
|
-
collector << ')'
|
|
284
|
-
end
|
|
285
|
-
collector << COMMA
|
|
286
|
-
collector = visit Arel.quoted(fmt), collector
|
|
287
|
-
collector << ')'
|
|
270
|
+
visit_ArelExtensions_Nodes_FormattedDate o, collector
|
|
288
271
|
when :integer, :float, :decimal
|
|
289
272
|
collector << 'FORMAT('
|
|
290
273
|
collector = visit o.left, collector
|
|
@@ -299,6 +282,29 @@ module ArelExtensions
|
|
|
299
282
|
collector
|
|
300
283
|
end
|
|
301
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
|
+
|
|
302
308
|
def visit_ArelExtensions_Nodes_DateDiff o, collector
|
|
303
309
|
case o.right_node_type
|
|
304
310
|
when :ruby_date, :ruby_time, :date, :datetime, :time
|
|
@@ -451,6 +451,10 @@ module ArelExtensions
|
|
|
451
451
|
end
|
|
452
452
|
|
|
453
453
|
def visit_ArelExtensions_Nodes_Format o, collector
|
|
454
|
+
visit_ArelExtensions_Nodes_FormattedDate o, collector
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
def visit_ArelExtensions_Nodes_FormattedDate o, collector
|
|
454
458
|
fmt = ArelExtensions::Visitors::strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
|
|
455
459
|
collector << 'TO_CHAR('
|
|
456
460
|
collector << 'CAST(' if o.time_zone
|
|
@@ -174,6 +174,10 @@ module ArelExtensions
|
|
|
174
174
|
end
|
|
175
175
|
|
|
176
176
|
def visit_ArelExtensions_Nodes_Format o, collector
|
|
177
|
+
visit_ArelExtensions_Nodes_FormattedDate o, collector
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def visit_ArelExtensions_Nodes_FormattedDate o, collector
|
|
177
181
|
fmt = ArelExtensions::Visitors::strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
|
|
178
182
|
collector << 'TO_CHAR('
|
|
179
183
|
collector << '(' if o.time_zone
|
|
@@ -289,6 +289,26 @@ module ArelExtensions
|
|
|
289
289
|
collector
|
|
290
290
|
end
|
|
291
291
|
|
|
292
|
+
def visit_ArelExtensions_Nodes_FormattedDate o, collector
|
|
293
|
+
case o.col_type
|
|
294
|
+
when :date, :datetime, :time
|
|
295
|
+
collector << 'STRFTIME('
|
|
296
|
+
collector = visit o.right, collector
|
|
297
|
+
collector << COMMA
|
|
298
|
+
collector = visit o.left, collector
|
|
299
|
+
collector << ')'
|
|
300
|
+
when :integer, :float, :decimal
|
|
301
|
+
collector << 'FORMAT('
|
|
302
|
+
collector = visit o.left, collector
|
|
303
|
+
collector << COMMA
|
|
304
|
+
collector = visit o.right, collector
|
|
305
|
+
collector << ')'
|
|
306
|
+
else
|
|
307
|
+
collector = visit o.left, collector
|
|
308
|
+
end
|
|
309
|
+
collector
|
|
310
|
+
end
|
|
311
|
+
|
|
292
312
|
# comparators
|
|
293
313
|
|
|
294
314
|
def visit_ArelExtensions_Nodes_Cast o, collector
|
|
@@ -437,123 +437,134 @@ module ArelExtensions
|
|
|
437
437
|
end
|
|
438
438
|
|
|
439
439
|
def test_format
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
tz = ENV['DB'] == 'mssql' ? time_zones['mssql'] : time_zones['posix']
|
|
492
|
-
|
|
493
|
-
assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', tz['utc']))
|
|
494
|
-
assert_equal '2014/03/03 09:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['sao_paulo']}))
|
|
495
|
-
assert_equal '2014/03/03 02:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['tahiti']}))
|
|
440
|
+
%i[format format_date].each do |method|
|
|
441
|
+
assert_equal '2016-05-23', t(@lucas, @created_at.send(method, '%Y-%m-%d'))
|
|
442
|
+
assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.send(method, '%Y/%m/%d %H:%M:%S'))
|
|
443
|
+
assert_equal '12:42%', t(@lucas, @updated_at.send(method, '%R%%'))
|
|
444
|
+
|
|
445
|
+
# The following tests will ensure proper conversion of timestamps to
|
|
446
|
+
# requested timezones.
|
|
447
|
+
#
|
|
448
|
+
# The names of the timezones is highly dependant on the underlying
|
|
449
|
+
# operating system, and this is why we need to handle each database
|
|
450
|
+
# separately: the images we're using to test these databases are
|
|
451
|
+
# different. So don't rely on the provided examples. Your setup is your
|
|
452
|
+
# reference.
|
|
453
|
+
#
|
|
454
|
+
# One could always have portable code if s/he uses standard
|
|
455
|
+
# abbreviations, like:
|
|
456
|
+
#
|
|
457
|
+
# 1. CET => Central European Time
|
|
458
|
+
# 2. CEST => Central European Summer Time
|
|
459
|
+
#
|
|
460
|
+
# Which implies that the caller should handle daylight saving detection.
|
|
461
|
+
# In fact, CET will handle daylight saving in MySQL but not Postgres.
|
|
462
|
+
#
|
|
463
|
+
# It looks like the posix convention is supported by mysql and
|
|
464
|
+
# postgresql, e.g.:
|
|
465
|
+
#
|
|
466
|
+
# posix/Europe/Paris
|
|
467
|
+
# posix/America/Nipigon
|
|
468
|
+
#
|
|
469
|
+
# so it looks like a more reliably portable way of specifying it.
|
|
470
|
+
time_zones = {
|
|
471
|
+
'mssql' => {
|
|
472
|
+
'utc' => 'UTC',
|
|
473
|
+
'sao_paulo' => 'Argentina Standard Time',
|
|
474
|
+
'tahiti' => 'Hawaiian Standard Time',
|
|
475
|
+
'paris' => 'Central European Standard Time'
|
|
476
|
+
},
|
|
477
|
+
'posix' => {
|
|
478
|
+
'utc' => 'UTC',
|
|
479
|
+
'sao_paulo' => 'America/Sao_Paulo',
|
|
480
|
+
'tahiti' => 'Pacific/Tahiti',
|
|
481
|
+
'paris' => 'Europe/Paris'
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
skip "Unsupported timezone conversion for DB=#{ENV['DB']}" if !%w[mssql mysql oracle postgresql].include?(ENV['DB'])
|
|
486
|
+
# TODO: Standarize timezone conversion across all databases.
|
|
487
|
+
# This test case will be refactored and should work the same across all vendors.
|
|
488
|
+
if ENV['DB'] == 'mssql' && /Microsoft SQL Server (\d+)/.match(ActiveRecord::Base.connection.select_value('SELECT @@version'))[1].to_i < 2016
|
|
489
|
+
skip "SQL Server < 2016 is not currently supported"
|
|
490
|
+
end
|
|
496
491
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
assert_equal '
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
assert_equal '
|
|
492
|
+
tz = ENV['DB'] == 'mssql' ? time_zones['mssql'] : time_zones['posix']
|
|
493
|
+
|
|
494
|
+
assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.send(method, '%Y/%m/%d %H:%M:%S', tz['utc']))
|
|
495
|
+
assert_equal '2014/03/03 09:42:00', t(@lucas, @updated_at.send(method, '%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['sao_paulo']}))
|
|
496
|
+
assert_equal '2014/03/03 02:42:00', t(@lucas, @updated_at.send(method, '%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['tahiti']}))
|
|
497
|
+
|
|
498
|
+
# Skipping conversion from UTC to the desired timezones fails in SQL
|
|
499
|
+
# Server and Postgres. This is mainly due to the fact that timezone
|
|
500
|
+
# information is not preserved in the column itself.
|
|
501
|
+
#
|
|
502
|
+
# MySQL is happy to consider that times by default are in UTC.
|
|
503
|
+
assert_equal '2014/03/03 13:42:00', t(@lucas, @updated_at.send(method, '%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
|
|
504
|
+
refute_equal '2014/03/03 13:42:00', t(@lucas, @updated_at.send(method, '%Y/%m/%d %H:%M:%S', tz['paris'])) if !['mysql'].include?(ENV['DB'])
|
|
505
|
+
|
|
506
|
+
# Winter/Summer time
|
|
507
|
+
assert_equal '2014/08/03 14:42:00', t(@lucas, (@updated_at + 5.months).send(method, '%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
|
|
508
|
+
if ENV['DB'] == 'mssql'
|
|
509
|
+
assert_equal '2022/02/01 11:42:00', t(@lucas, Arel.quoted('2022-02-01 10:42:00').cast(:datetime).send(method, '%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
|
|
510
|
+
assert_equal '2022/08/01 12:42:00', t(@lucas, Arel.quoted('2022-08-01 10:42:00').cast(:datetime).send(method, '%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
|
|
511
|
+
else
|
|
512
|
+
assert_equal '2022/02/01 11:42:00', t(@lucas, Arel.quoted('2022-02-01 10:42:00').cast(:datetime).send(method, '%Y/%m/%d %H:%M:%S', tz['paris']))
|
|
513
|
+
assert_equal '2022/08/01 12:42:00', t(@lucas, Arel.quoted('2022-08-01 10:42:00').cast(:datetime).send(method, '%Y/%m/%d %H:%M:%S', tz['paris']))
|
|
514
|
+
end
|
|
513
515
|
end
|
|
514
516
|
end
|
|
515
517
|
|
|
516
518
|
def test_format_iso_week
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
519
|
+
%i[format format_date].each do |method|
|
|
520
|
+
skip "Unsupported ISO week number for DB=#{ENV['DB']}" if ['sqlite'].include?(ENV['DB'])
|
|
521
|
+
assert_equal '10', t(@lucas, @updated_at.send(method, '%V'))
|
|
522
|
+
{
|
|
523
|
+
'2024-01-01 10:42:00' => '01', # Monday
|
|
524
|
+
'2030-01-01 10:42:00' => '01', # Tuesday
|
|
525
|
+
'2025-01-01 10:42:00' => '01', # Wednesday
|
|
526
|
+
'2026-01-01 10:42:00' => '01', # Thursday
|
|
527
|
+
'2027-01-01 10:42:00' => '53', # Friday
|
|
528
|
+
'2028-01-01 10:42:00' => '52', # Saturday
|
|
529
|
+
'2034-01-01 10:42:00' => '52', # Sunday
|
|
530
|
+
}.each do |date, exp|
|
|
531
|
+
assert_equal exp, t(@lucas, Arel.quoted(date).cast(:datetime).send(method, '%V'))
|
|
532
|
+
end
|
|
529
533
|
end
|
|
530
534
|
end
|
|
531
535
|
|
|
532
536
|
def test_format_iso_year_of_week
|
|
533
537
|
skip "Unsupported ISO year of week for DB=#{ENV['DB']}" if %w[mssql sqlite].include?(ENV['DB'])
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
538
|
+
%i[format format_date].each do |method|
|
|
539
|
+
assert_equal '2014', t(@lucas, @updated_at.send(method, '%G'))
|
|
540
|
+
|
|
541
|
+
{
|
|
542
|
+
'2024-01-01 10:42:00' => '2024', # Monday
|
|
543
|
+
'2030-01-01 10:42:00' => '2030', # Tuesday
|
|
544
|
+
'2025-01-01 10:42:00' => '2025', # Wednesday
|
|
545
|
+
'2026-01-01 10:42:00' => '2026', # Thursday
|
|
546
|
+
'2027-01-01 10:42:00' => '2026', # Friday
|
|
547
|
+
'2028-01-01 10:42:00' => '2027', # Saturday
|
|
548
|
+
'2034-01-01 10:42:00' => '2033', # Sunday
|
|
549
|
+
}.each do |date, exp|
|
|
550
|
+
assert_equal exp, t(@lucas, Arel.quoted(date).cast(:datetime).send(method, '%G'))
|
|
551
|
+
end
|
|
546
552
|
end
|
|
547
553
|
end
|
|
548
554
|
|
|
549
555
|
def test_format_date_with_names
|
|
550
556
|
skip "#{ENV['DB']} does not support a variety of word-based formatting for month and day names" if %w[mssql sqlite].include?(ENV['DB'])
|
|
551
|
-
|
|
552
|
-
|
|
557
|
+
%i[format format_date].each do |method|
|
|
558
|
+
assert_equal 'Mon, 03 Mar 14', t(@lucas, @updated_at.send(method, '%a, %d %b %y'))
|
|
559
|
+
assert_equal 'Monday, 03 March 14', t(@lucas, @updated_at.send(method, '%A, %d %B %y'))
|
|
560
|
+
end
|
|
553
561
|
|
|
554
562
|
skip "#{ENV['DB']} does not support ALLCAPS month and day names" if ['mysql'].include?(ENV['DB'])
|
|
555
|
-
|
|
556
|
-
|
|
563
|
+
%i[format format_date].each do |method|
|
|
564
|
+
|
|
565
|
+
assert_equal 'Mon, 03 MAR 14', t(@lucas, @updated_at.send(method, '%a, %d %^b %y'))
|
|
566
|
+
assert_equal 'Monday, 03 MARCH 14', t(@lucas, @updated_at.send(method, '%A, %d %^B %y'))
|
|
567
|
+
end
|
|
557
568
|
end
|
|
558
569
|
|
|
559
570
|
def switch_to_lang(lang)
|
|
@@ -580,28 +591,30 @@ module ArelExtensions
|
|
|
580
591
|
#
|
|
581
592
|
# Tests should assert one single thing in principle, but until we
|
|
582
593
|
# refactor this whole thing, we'll have to do tricks of this sort.
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
594
|
+
%i[format format_date].each do |method|
|
|
595
|
+
begin
|
|
596
|
+
switch_to_lang(:en)
|
|
597
|
+
case ENV['DB']
|
|
598
|
+
when 'mysql', 'postgresql'
|
|
599
|
+
assert_equal 'Mon, 03 Mar 14', t(@lucas, @updated_at.send(method, '%a, %d %b %y'))
|
|
600
|
+
assert_equal 'Monday, 03 March 14', t(@lucas, @updated_at.send(method, '%A, %d %B %y'))
|
|
601
|
+
when 'mssql'
|
|
602
|
+
assert_equal 'Monday, 03 March 2014', t(@lucas, @updated_at.send(method, '%A, %d %B %y'))
|
|
603
|
+
end
|
|
604
|
+
switch_to_lang(:fr)
|
|
605
|
+
case ENV['DB']
|
|
606
|
+
when 'mysql'
|
|
607
|
+
assert_equal 'lun, 03 mar 14', t(@lucas, @updated_at.send(method, '%a, %d %b %y'))
|
|
608
|
+
assert_equal 'lundi, 03 mars 14', t(@lucas, @updated_at.send(method, '%A, %d %B %y'))
|
|
609
|
+
when 'postgresql'
|
|
610
|
+
assert_equal 'Lun., 03 Mars 14', t(@lucas, @updated_at.send(method, '%a, %d %b %y'))
|
|
611
|
+
assert_equal 'Lundi, 03 Mars 14', t(@lucas, @updated_at.send(method, '%A, %d %B %y'))
|
|
612
|
+
when 'mssql'
|
|
613
|
+
assert_equal 'lundi, 03 mars 2014', t(@lucas, @updated_at.send(method, '%A, %d %B %y'))
|
|
614
|
+
end
|
|
615
|
+
ensure
|
|
616
|
+
switch_to_lang(:en)
|
|
602
617
|
end
|
|
603
|
-
ensure
|
|
604
|
-
switch_to_lang(:en)
|
|
605
618
|
end
|
|
606
619
|
end
|
|
607
620
|
|
|
@@ -632,6 +645,7 @@ module ArelExtensions
|
|
|
632
645
|
assert_equal 'Myung', t(@myung, @comments.coalesce_blank('', ' ', ' ').coalesce_blank('Myung'))
|
|
633
646
|
assert_equal 'Myung', t(@myung, @comments.coalesce_blank('', ' ', ' ', 'Myung'))
|
|
634
647
|
assert_equal '2016-05-23', t(@myung, @created_at.coalesce_blank(Date.new(2022, 1, 1)).format('%Y-%m-%d'))
|
|
648
|
+
assert_equal '2016-05-23', t(@myung, @created_at.coalesce_blank(Date.new(2022, 1, 1)).format_date('%Y-%m-%d'))
|
|
635
649
|
assert_equal 'Laure', t(@laure, @comments.coalesce_blank('Laure'))
|
|
636
650
|
assert_equal 100, t(@test, @age.coalesce_blank(100))
|
|
637
651
|
assert_equal 20, t(@test, @age.coalesce_blank(20))
|
|
@@ -734,8 +748,10 @@ module ArelExtensions
|
|
|
734
748
|
t(@lucas, (@updated_at + Arel.duration('mn', (@updated_at.hour * 60 + @updated_at.minute))))
|
|
735
749
|
|
|
736
750
|
assert_includes ['2024-03-03'], t(@lucas, (@updated_at + durPos).format('%Y-%m-%d'))
|
|
751
|
+
assert_includes ['2024-03-03'], t(@lucas, (@updated_at + durPos).format_date('%Y-%m-%d'))
|
|
737
752
|
# puts (@updated_at - durPos).to_sql
|
|
738
753
|
assert_includes ['2004-03-03'], t(@lucas, (@updated_at - durPos).format('%Y-%m-%d'))
|
|
754
|
+
assert_includes ['2004-03-03'], t(@lucas, (@updated_at - durPos).format_date('%Y-%m-%d'))
|
|
739
755
|
|
|
740
756
|
|
|
741
757
|
# we test with the ruby object or the string because some adapters don't return an object Date
|
|
@@ -775,9 +791,11 @@ module ArelExtensions
|
|
|
775
791
|
assert_equal 0, t(@myung, @comments.if_present.count)
|
|
776
792
|
assert_equal 20.16, t(@myung, @score.if_present)
|
|
777
793
|
assert_equal '2016-05-23', t(@myung, @created_at.if_present.format('%Y-%m-%d'))
|
|
794
|
+
assert_equal '2016-05-23', t(@myung, @created_at.if_present.format_date('%Y-%m-%d'))
|
|
778
795
|
assert_nil t(@laure, @comments.if_present)
|
|
779
796
|
|
|
780
797
|
assert_nil t(@nilly, @duration.if_present.format('%Y-%m-%d'))
|
|
798
|
+
assert_nil t(@nilly, @duration.if_present.format_date('%Y-%m-%d'))
|
|
781
799
|
|
|
782
800
|
# NOTE: here we're testing the capacity to format a nil value,
|
|
783
801
|
# however, @comments is a text field, and not a date/datetime field,
|
|
@@ -785,8 +803,10 @@ module ArelExtensions
|
|
|
785
803
|
# we need to cast it first.
|
|
786
804
|
if @env_db == 'postgresql'
|
|
787
805
|
assert_nil t(@laure, @comments.cast(:date).if_present.format('%Y-%m-%d'))
|
|
806
|
+
assert_nil t(@laure, @comments.cast(:date).if_present.format_date('%Y-%m-%d'))
|
|
788
807
|
else
|
|
789
808
|
assert_nil t(@laure, @comments.if_present.format('%Y-%m-%d'))
|
|
809
|
+
assert_nil t(@laure, @comments.if_present.format_date('%Y-%m-%d'))
|
|
790
810
|
end
|
|
791
811
|
end
|
|
792
812
|
|
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.7
|
|
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:
|
|
13
|
+
date: 2023-01-27 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: arel
|
|
@@ -123,6 +123,7 @@ files:
|
|
|
123
123
|
- lib/arel_extensions/nodes/find_in_set.rb
|
|
124
124
|
- lib/arel_extensions/nodes/floor.rb
|
|
125
125
|
- lib/arel_extensions/nodes/format.rb
|
|
126
|
+
- lib/arel_extensions/nodes/formatted_date.rb
|
|
126
127
|
- lib/arel_extensions/nodes/formatted_number.rb
|
|
127
128
|
- lib/arel_extensions/nodes/function.rb
|
|
128
129
|
- lib/arel_extensions/nodes/is_null.rb
|
|
@@ -207,7 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
207
208
|
- !ruby/object:Gem::Version
|
|
208
209
|
version: '0'
|
|
209
210
|
requirements: []
|
|
210
|
-
rubygems_version: 3.
|
|
211
|
+
rubygems_version: 3.3.5
|
|
211
212
|
signing_key:
|
|
212
213
|
specification_version: 4
|
|
213
214
|
summary: Extending Arel
|