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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0076504922a3f08d3770d9bedca4b24f0b2d19b080abcfd925f3ab928a1d7802'
4
- data.tar.gz: '080a98b49a9a43f1ad319933c77befd0a8947b0d3f3fc503058cfc81b863d815'
3
+ metadata.gz: 6d8d074334ab5ecab7fc6b0d4d9a24180b83d4d3c9a0e7c9237d9ec567146272
4
+ data.tar.gz: 0cf4c51ebd196eb2671506f0aef243c9cd6332bb5f55eac89c77024c105390ff
5
5
  SHA512:
6
- metadata.gz: d658b44c16c1af76c9c6e55c084186a663683269c974757e70333755b8986b2226e7561261776ce0fb41acf063469628f215627ea80991e977968d47851af831
7
- data.tar.gz: c9f0b4f123fac561f1aedcf93bc162d8bfa0f31740b539efe599f7f12725b995279b541dd7d501d3d8bdec636880ceade3eb1346f6c5fed90d67ea7124d6e9fd
6
+ metadata.gz: 89ae8015b86e8ead47050f5af4dba33f851d02eeafa9a8123752fb24911ae46124391fdc7e3e5f09da41f0efc092ee4b7f084b6f01572e07ab5376d507c2741c
7
+ data.tar.gz: 988bef22406e320405f71dec5ca8e666de0acc8f87bc3b67f755951788ddca7fb92b65d2e313144413c3cde2adb4363e0e87aea418dfd691889a650e2fd57166
@@ -13,19 +13,21 @@ jobs:
13
13
  fail-fast: false
14
14
  matrix:
15
15
  versions: [
16
- {ruby: 3.1, rails: 7, arelx: 2},
17
- {ruby: 3.1, rails: 6_1, arelx: 2},
18
- {ruby: 3.0, rails: 7, arelx: 2},
19
- {ruby: 3.0, rails: 6_1, arelx: 2},
20
- {ruby: 2.7, rails: 7, arelx: 2},
21
- {ruby: 2.7, rails: 6_1, arelx: 2},
22
- {ruby: 2.7, rails: 6, arelx: 2},
23
- {ruby: 2.7, rails: 5_2, arelx: 1},
24
- {ruby: 2.7, rails: 4_2, arelx: 1},
25
- {ruby: 2.5, rails: 6_1, arelx: 2},
26
- {ruby: 2.5, rails: 6, arelx: 2},
27
- {ruby: 2.5, rails: 5_2, arelx: 1},
28
- {ruby: 2.5, rails: 4_2, arelx: 1},
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.1, rails: 7, arelx: 2},
69
- {ruby: 3.1, rails: 6_1, arelx: 2},
70
- {ruby: 3.0, rails: 7, arelx: 2},
71
- {ruby: 3.0, rails: 6_1, arelx: 2},
72
- {ruby: 2.7, rails: 7, arelx: 2},
73
- {ruby: 2.7, rails: 6_1, arelx: 2},
74
- {ruby: 2.7, rails: 6, arelx: 2},
75
- {ruby: 2.7, rails: 5_2, arelx: 1},
76
- {ruby: 2.7, rails: 4_2, arelx: 1},
77
- {ruby: 2.5, rails: 6_1, arelx: 2},
78
- {ruby: 2.5, rails: 6, arelx: 2},
79
- {ruby: 2.5, rails: 5_2, arelx: 1},
80
- {ruby: 2.5, rails: 4_2, arelx: 1},
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.1, rails: 7, arelx: 2},
122
- {ruby: 3.1, rails: 6_1, arelx: 2},
123
- {ruby: 3.0, rails: 7, arelx: 2},
124
- {ruby: 3.0, rails: 6_1, arelx: 2},
125
- {ruby: 2.7, rails: 7, arelx: 2},
126
- {ruby: 2.7, rails: 6_1, arelx: 2},
127
- {ruby: 2.7, rails: 6, arelx: 2},
128
- {ruby: 2.7, rails: 5_2, arelx: 1},
129
- {ruby: 2.7, rails: 4_2, arelx: 1},
130
- {ruby: 2.5, rails: 6_1, arelx: 2},
131
- {ruby: 2.5, rails: 6, arelx: 2},
132
- {ruby: 2.5, rails: 5_2, arelx: 1},
133
- {ruby: 2.5, rails: 4_2, arelx: 1},
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.1, rails: 7, arelx: 2},
200
- {ruby: 3.1, rails: 6_1, arelx: 2},
201
- {ruby: 3.0, rails: 7, arelx: 2},
202
- {ruby: 3.0, rails: 6_1, arelx: 2},
203
- {ruby: 2.7, rails: 7, arelx: 2},
204
- {ruby: 2.7, rails: 6_1, arelx: 2},
205
- {ruby: 2.7, rails: 6, arelx: 2},
206
- {ruby: 2.7, rails: 5_2, arelx: 1},
207
- {ruby: 2.7, rails: 4_2, arelx: 1},
208
- {ruby: 2.5, rails: 6_1, arelx: 2},
209
- {ruby: 2.5, rails: 6, arelx: 2},
210
- {ruby: 2.5, rails: 5_2, arelx: 1},
211
- {ruby: 2.5, rails: 4_2, arelx: 1},
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.1, rails: 7, arelx: 2},
273
- {ruby: 3.1, rails: 6_1, arelx: 2},
274
- # {ruby: 3.0, rails: 7, arelx: 2},
275
- {ruby: 3.0, rails: 6_1, arelx: 2},
276
- # {ruby: 2.7, rails: 7, arelx: 2},
277
- {ruby: 2.7, rails: 6_1, arelx: 2},
278
- {ruby: 2.7, rails: 6, arelx: 2},
279
- {ruby: 2.7, rails: 5_2, arelx: 1},
280
- {ruby: 2.7, rails: 4_2, arelx: 1},
281
- {ruby: 2.5, rails: 6_1, arelx: 2},
282
- {ruby: 2.5, rails: 6, arelx: 2},
283
- {ruby: 2.5, rails: 5_2, arelx: 1},
284
- {ruby: 2.5, rails: 4_2, arelx: 1},
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
- # Release
1
+ # News
2
2
 
3
- ## Bug Fixes
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
- ## New Features
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
- t is an Arel::Table for table my_table
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 : ABS, RAND, ROUND, FLOOR, CEIL, FORMAT
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 '\^[a-d_]+'
98
+ # => my_table.name REGEXP '^[a-d_]+'
98
99
  ```
99
100
 
100
- Other functions : SOUNDEX, LENGTH, REPLACE, LOCATE, SUBSTRING, TRIM
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
- ```t[:list]``` is a classical varchar containing a comma separated list ("1,2,3,4")
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>
@@ -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.2', platforms: [:mri]
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]
@@ -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.2', platforms: [:mri]
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
@@ -1,3 +1,3 @@
1
1
  module ArelExtensions
2
- VERSION = '1.3.6'.freeze
2
+ VERSION = '1.3.7'.freeze
3
3
  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? && !o.expressions[0].return_type.nil? \
263
- ? o.expressions[0].return_type \
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
- fmt = ArelExtensions::Visitors::strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
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
- assert_equal '2016-05-23', t(@lucas, @created_at.format('%Y-%m-%d'))
441
- assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S'))
442
- assert_equal '12:42%', t(@lucas, @updated_at.format('%R%%'))
443
-
444
- # The following tests will ensure proper conversion of timestamps to
445
- # requested timezones.
446
- #
447
- # The names of the timezones is highly dependant on the underlying
448
- # operating system, and this is why we need to handle each database
449
- # separately: the images we're using to test these databases are
450
- # different. So don't rely on the provided examples. Your setup is your
451
- # reference.
452
- #
453
- # One could always have portable code if s/he uses standard
454
- # abbreviations, like:
455
- #
456
- # 1. CET => Central European Time
457
- # 2. CEST => Central European Summer Time
458
- #
459
- # Which implies that the caller should handle daylight saving detection.
460
- # In fact, CET will handle daylight saving in MySQL but not Postgres.
461
- #
462
- # It looks like the posix convention is supported by mysql and
463
- # postgresql, e.g.:
464
- #
465
- # posix/Europe/Paris
466
- # posix/America/Nipigon
467
- #
468
- # so it looks like a more reliably portable way of specifying it.
469
- time_zones = {
470
- 'mssql' => {
471
- 'utc' => 'UTC',
472
- 'sao_paulo' => 'Argentina Standard Time',
473
- 'tahiti' => 'Hawaiian Standard Time',
474
- 'paris' => 'Central European Standard Time'
475
- },
476
- 'posix' => {
477
- 'utc' => 'UTC',
478
- 'sao_paulo' => 'America/Sao_Paulo',
479
- 'tahiti' => 'Pacific/Tahiti',
480
- 'paris' => 'Europe/Paris'
481
- }
482
- }
483
-
484
- skip "Unsupported timezone conversion for DB=#{ENV['DB']}" if !%w[mssql mysql oracle postgresql].include?(ENV['DB'])
485
- # TODO: Standarize timezone conversion across all databases.
486
- # This test case will be refactored and should work the same across all vendors.
487
- if ENV['DB'] == 'mssql' && /Microsoft SQL Server (\d+)/.match(ActiveRecord::Base.connection.select_value('SELECT @@version'))[1].to_i < 2016
488
- skip "SQL Server < 2016 is not currently supported"
489
- end
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
- # Skipping conversion from UTC to the desired timezones fails in SQL
498
- # Server and Postgres. This is mainly due to the fact that timezone
499
- # information is not preserved in the column itself.
500
- #
501
- # MySQL is happy to consider that times by default are in UTC.
502
- assert_equal '2014/03/03 13:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
503
- 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'])
504
-
505
- # Winter/Summer time
506
- 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']}))
507
- if ENV['DB'] == 'mssql'
508
- assert_equal '2022/02/01 11:42:00', t(@lucas, Arel.quoted('2022-02-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
509
- assert_equal '2022/08/01 12:42:00', t(@lucas, Arel.quoted('2022-08-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', {tz['utc'] => tz['paris']}))
510
- else
511
- assert_equal '2022/02/01 11:42:00', t(@lucas, Arel.quoted('2022-02-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', tz['paris']))
512
- assert_equal '2022/08/01 12:42:00', t(@lucas, Arel.quoted('2022-08-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', tz['paris']))
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
- skip "Unsupported ISO week number for DB=#{ENV['DB']}" if ['sqlite'].include?(ENV['DB'])
518
- assert_equal '10', t(@lucas, @updated_at.format('%V'))
519
- {
520
- '2024-01-01 10:42:00' => '01', # Monday
521
- '2030-01-01 10:42:00' => '01', # Tuesday
522
- '2025-01-01 10:42:00' => '01', # Wednesday
523
- '2026-01-01 10:42:00' => '01', # Thursday
524
- '2027-01-01 10:42:00' => '53', # Friday
525
- '2028-01-01 10:42:00' => '52', # Saturday
526
- '2034-01-01 10:42:00' => '52', # Sunday
527
- }.each do |date, exp|
528
- assert_equal exp, t(@lucas, Arel.quoted(date).cast(:datetime).format('%V'))
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
- assert_equal '2014', t(@lucas, @updated_at.format('%G'))
535
-
536
- {
537
- '2024-01-01 10:42:00' => '2024', # Monday
538
- '2030-01-01 10:42:00' => '2030', # Tuesday
539
- '2025-01-01 10:42:00' => '2025', # Wednesday
540
- '2026-01-01 10:42:00' => '2026', # Thursday
541
- '2027-01-01 10:42:00' => '2026', # Friday
542
- '2028-01-01 10:42:00' => '2027', # Saturday
543
- '2034-01-01 10:42:00' => '2033', # Sunday
544
- }.each do |date, exp|
545
- assert_equal exp, t(@lucas, Arel.quoted(date).cast(:datetime).format('%G'))
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
- assert_equal 'Mon, 03 Mar 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
552
- assert_equal 'Monday, 03 March 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
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
- assert_equal 'Mon, 03 MAR 14', t(@lucas, @updated_at.format('%a, %d %^b %y'))
556
- assert_equal 'Monday, 03 MARCH 14', t(@lucas, @updated_at.format('%A, %d %^B %y'))
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
- begin
584
- switch_to_lang(:en)
585
- case ENV['DB']
586
- when 'mysql', 'postgresql'
587
- assert_equal 'Mon, 03 Mar 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
588
- assert_equal 'Monday, 03 March 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
589
- when 'mssql'
590
- assert_equal 'Monday, 03 March 2014', t(@lucas, @updated_at.format('%A, %d %B %y'))
591
- end
592
- switch_to_lang(:fr)
593
- case ENV['DB']
594
- when 'mysql'
595
- assert_equal 'lun, 03 mar 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
596
- assert_equal 'lundi, 03 mars 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
597
- when 'postgresql'
598
- assert_equal 'Lun., 03 Mars 14', t(@lucas, @updated_at.format('%a, %d %b %y'))
599
- assert_equal 'Lundi, 03 Mars 14', t(@lucas, @updated_at.format('%A, %d %B %y'))
600
- when 'mssql'
601
- assert_equal 'lundi, 03 mars 2014', t(@lucas, @updated_at.format('%A, %d %B %y'))
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
@@ -1,3 +1,3 @@
1
1
  module ArelExtensions
2
- VERSION = '1.3.6'.freeze
2
+ VERSION = '1.3.7'.freeze
3
3
  end
data/version_v2.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ArelExtensions
2
- VERSION = '2.1.6'.freeze
2
+ VERSION = '2.1.7'.freeze
3
3
  end
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.6
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: 2022-11-22 00:00:00.000000000 Z
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.2.3
211
+ rubygems_version: 3.3.5
211
212
  signing_key:
212
213
  specification_version: 4
213
214
  summary: Extending Arel