activerecord-refined 0.3.0 → 0.3.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.
@@ -2,31 +2,31 @@ require_relative 'test_helper'
2
2
 
3
3
  class TestBlockSyntax < Minitest::Test
4
4
  def test_equal
5
- assert_match(/WHERE "users"."name" = 'matz'/, User.where { :name == 'matz' }.to_sql)
5
+ assert_sql(/WHERE "users"."name" = 'matz'/, User.where { :name == 'matz' }.to_sql)
6
6
  end
7
7
 
8
8
  def test_not_equal
9
- assert_match(/WHERE "users"."name" != 'nobu'/, User.where { :name != 'nobu' }.to_sql)
9
+ assert_sql(/WHERE "users"."name" != 'nobu'/, User.where { :name != 'nobu' }.to_sql)
10
10
  end
11
11
 
12
12
  def test_greater_than
13
- assert_match(/WHERE "users"."age" > 3/, User.where { :age > 3 }.to_sql)
13
+ assert_sql(/WHERE "users"."age" > 3/, User.where { :age > 3 }.to_sql)
14
14
  end
15
15
 
16
16
  def test_greater_than_or_equal
17
- assert_match(/WHERE "users"."age" >= 18/, User.where { :age >= 18 }.to_sql)
17
+ assert_sql(/WHERE "users"."age" >= 18/, User.where { :age >= 18 }.to_sql)
18
18
  end
19
19
 
20
20
  def test_less_than
21
- assert_match(/WHERE "users"."age" < 60/, User.where { :age < 60 }.to_sql)
21
+ assert_sql(/WHERE "users"."age" < 60/, User.where { :age < 60 }.to_sql)
22
22
  end
23
23
 
24
24
  def test_less_than_or_equal
25
- assert_match(/WHERE "users"."age" <= 35/, User.where { :age <= 35 }.to_sql)
25
+ assert_sql(/WHERE "users"."age" <= 35/, User.where { :age <= 35 }.to_sql)
26
26
  end
27
27
 
28
28
  def test_like
29
- assert_match(/WHERE "users"."name" LIKE 'tender%'/, User.where { :name =~ 'tender%' }.to_sql)
29
+ assert_sql(/WHERE "users"."name" LIKE 'tender%'/, User.where { :name.like?('tender%') }.to_sql)
30
30
  end
31
31
 
32
32
  def test_outside_of_where_block
@@ -34,149 +34,279 @@ class TestBlockSyntax < Minitest::Test
34
34
  end
35
35
 
36
36
  def test_and
37
- assert_match(/WHERE "users"."name" = 'matz' AND "users"."age" > 18/,
37
+ assert_sql(/WHERE "users"."name" = 'matz' AND "users"."age" > 18/,
38
38
  User.where { (:name == 'matz') & (:age > 18) }.to_sql)
39
39
  end
40
40
 
41
41
  def test_or
42
- assert_match(/WHERE \(?\"users\".\"name\" = 'matz' OR \"users\".\"name\" = 'nobu'\)?/,
42
+ assert_sql(/WHERE \(?\"users\".\"name\" = 'matz' OR \"users\".\"name\" = 'nobu'\)?/,
43
43
  User.where { (:name == 'matz') | (:name == 'nobu') }.to_sql)
44
44
  end
45
45
 
46
46
  def test_not
47
- assert_match(/WHERE NOT \(?\"users\".\"name\" = 'matz'\)?/,
47
+ assert_sql(/WHERE NOT \(?\"users\".\"name\" = 'matz'\)?/,
48
48
  User.where { !(:name == 'matz') }.to_sql)
49
49
  end
50
50
 
51
51
  def test_complex_combination
52
52
  sql = User.where { ((:name == 'matz') & (:age > 18)) | !(:name == 'nobu') }.to_sql
53
- assert_match(/"users"."name" = 'matz'/, sql)
54
- assert_match(/"users"."age" > 18/, sql)
55
- assert_match(/NOT/, sql)
56
- assert_match(/OR/, sql)
53
+ assert_sql(/"users"."name" = 'matz'/, sql)
54
+ assert_sql(/"users"."age" > 18/, sql)
55
+ assert_sql(/NOT/, sql)
56
+ assert_sql(/OR/, sql)
57
57
  end
58
58
 
59
- def test_between
60
- assert_match(/WHERE "users"."age" BETWEEN 18 AND 65/,
61
- User.where { :age == (18..65) }.to_sql)
59
+ def test_like_qualified
60
+ assert_sql(/WHERE "users"."name" LIKE 'tender%'/,
61
+ User.where { :users[:name].like?('tender%') }.to_sql)
62
62
  end
63
63
 
64
64
  def test_not_like
65
- assert_match(/WHERE "users"."name" NOT LIKE 'tender%'/,
66
- User.where { :name !~ 'tender%' }.to_sql)
65
+ assert_sql(/WHERE NOT \("users"."name" LIKE 'tender%'\)/,
66
+ User.where { !:name.like?('tender%') }.to_sql)
67
+ end
68
+
69
+ def test_start_with
70
+ assert_sql(/WHERE "users"."name" LIKE 'tender%' ESCAPE '\\'/,
71
+ User.where { :name.start_with?('tender') }.to_sql)
72
+ end
73
+
74
+ def test_end_with
75
+ assert_sql(/WHERE "users"."name" LIKE '%love' ESCAPE '\\'/,
76
+ User.where { :name.end_with?('love') }.to_sql)
77
+ end
78
+
79
+ def test_include
80
+ assert_sql(/WHERE "users"."name" LIKE '%der%' ESCAPE '\\'/,
81
+ User.where { :name.include?('der') }.to_sql)
82
+ end
83
+
84
+ def test_start_with_escapes_wildcards
85
+ assert_sql(/WHERE "users"."name" LIKE '100\\%\\_%' ESCAPE '\\'/,
86
+ User.where { :name.start_with?('100%_') }.to_sql)
87
+ end
88
+
89
+ def test_include_escapes_wildcards
90
+ assert_sql(/WHERE "users"."name" LIKE '%100\\%%' ESCAPE '\\'/,
91
+ User.where { :name.include?('100%') }.to_sql)
92
+ end
93
+
94
+ def test_regexp
95
+ skip_without_regexp_support
96
+ assert_sql(/WHERE "users"."name" #{regexp_operator} '\^ma'/,
97
+ User.where { :name =~ '^ma' }.to_sql)
98
+ end
99
+
100
+ def test_not_regexp
101
+ skip_without_regexp_support
102
+ assert_sql(/WHERE "users"."name" #{not_regexp_operator} '\^ma'/,
103
+ User.where { :name !~ '^ma' }.to_sql)
104
+ end
105
+
106
+ def test_regexp_qualified
107
+ skip_without_regexp_support
108
+ assert_sql(/WHERE "users"."name" #{regexp_operator} '\^ma'/,
109
+ User.where { :users[:name] =~ '^ma' }.to_sql)
110
+ end
111
+
112
+ def test_regexp_on_function
113
+ skip_without_regexp_support
114
+ assert_sql(/WHERE UPPER\("users"."name"\) #{regexp_operator} '\^MA'/,
115
+ User.where { upper(:name) =~ '^MA' }.to_sql)
116
+ end
117
+
118
+ def test_regexp_literal
119
+ skip_without_regexp_support
120
+ assert_sql(/WHERE "users"."name" #{regexp_operator} 'love\$'/,
121
+ User.where { :name =~ /love$/ }.to_sql)
122
+ end
123
+
124
+ # Rejected while the block runs, so this holds on every adapter.
125
+ def test_regexp_literal_with_options_is_rejected
126
+ assert_raises(ArgumentError) { User.where { :name =~ /^ma/i } }
127
+ end
128
+
129
+ def test_between
130
+ assert_sql(/WHERE "users"."age" BETWEEN 18 AND 65/,
131
+ User.where { :age.between?(18, 65) }.to_sql)
132
+ end
133
+
134
+ def test_in_range
135
+ assert_sql(/WHERE "users"."age" BETWEEN 18 AND 65/,
136
+ User.where { :age.in?(18..65) }.to_sql)
137
+ end
138
+
139
+ def test_in_endless_range
140
+ assert_sql(/WHERE "users"."age" >= 18/,
141
+ User.where { :age.in?(18..) }.to_sql)
142
+ end
143
+
144
+ def test_in_exclusive_range
145
+ assert_sql(/WHERE "users"."age" >= 18 AND "users"."age" < 65/,
146
+ User.where { :age.in?(18...65) }.to_sql)
67
147
  end
68
148
 
69
149
  def test_not_between
70
- # Arel expands a bounded NOT BETWEEN into an OR of comparisons
71
- assert_match(/WHERE \("users"."age" < 18 OR "users"."age" > 65\)/,
72
- User.where { :age != (18..65) }.to_sql)
150
+ assert_sql(/WHERE NOT \("users"."age" BETWEEN 18 AND 65\)/,
151
+ User.where { !:age.between?(18, 65) }.to_sql)
73
152
  end
74
153
 
75
154
  def test_is_null
76
- assert_match(/WHERE "users"."name" IS NULL/,
155
+ assert_sql(/WHERE "users"."name" IS NULL/,
77
156
  User.where { :name.null? }.to_sql)
78
157
  end
79
158
 
80
159
  def test_is_null_qualified
81
- assert_match(/WHERE "users"."name" IS NULL/,
160
+ assert_sql(/WHERE "users"."name" IS NULL/,
82
161
  User.where { :users[:name].null? }.to_sql)
83
162
  end
84
163
 
85
164
  def test_in
86
- assert_match(/WHERE "users"."age" IN \(1, 2, 3\)/,
87
- User.where { :age == [1, 2, 3] }.to_sql)
165
+ assert_sql(/WHERE "users"."age" IN \(1, 2, 3\)/,
166
+ User.where { :age.in?([1, 2, 3]) }.to_sql)
167
+ end
168
+
169
+ def test_in_qualified
170
+ assert_sql(/WHERE "users"."age" IN \(1, 2, 3\)/,
171
+ User.where { :users[:age].in?([1, 2, 3]) }.to_sql)
88
172
  end
89
173
 
90
174
  def test_not_in
91
- assert_match(/WHERE "users"."age" NOT IN \(1, 2, 3\)/,
92
- User.where { :age != [1, 2, 3] }.to_sql)
175
+ assert_sql(/WHERE NOT \("users"."age" IN \(1, 2, 3\)\)/,
176
+ User.where { !:age.in?([1, 2, 3]) }.to_sql)
177
+ end
178
+
179
+ # == passes a Range or an Array through as a value rather than expanding it,
180
+ # so that it compares against a PostgreSQL range or array column. The SQL
181
+ # literal depends on the column type, so assert on the Arel node instead.
182
+ def test_equal_range_is_an_equality
183
+ node = ActiveRecord::Refined::AST::Comparison.new(:period, :==, 18..65).
184
+ to_arel(User.arel_table)
185
+ assert_instance_of(Arel::Nodes::Equality, node)
186
+ assert_equal(18..65, node.right.value)
187
+ end
188
+
189
+ def test_equal_array_is_an_equality
190
+ node = ActiveRecord::Refined::AST::Comparison.new(:tags, :==, [1, 2, 3]).
191
+ to_arel(User.arel_table)
192
+ assert_instance_of(Arel::Nodes::Equality, node)
193
+ assert_equal([1, 2, 3], node.right.value)
194
+ end
195
+
196
+ def test_not_equal_array_is_an_inequality
197
+ node = ActiveRecord::Refined::AST::Comparison.new(:tags, :!=, [1, 2, 3]).
198
+ to_arel(User.arel_table)
199
+ assert_instance_of(Arel::Nodes::NotEqual, node)
200
+ assert_equal([1, 2, 3], node.right.value)
93
201
  end
94
202
 
95
203
  def test_qualified_column
96
- assert_match(/WHERE "users"."name" = 'matz'/,
204
+ assert_sql(/WHERE "users"."name" = 'matz'/,
97
205
  User.where { :users[:name] == 'matz' }.to_sql)
98
206
  end
99
207
 
100
208
  def test_column_to_column_comparison
101
209
  sql = User.where { :users[:name] == :users[:age] }.to_sql
102
- assert_match(/"users"."name" = "users"."age"/, sql)
210
+ assert_sql(/"users"."name" = "users"."age"/, sql)
103
211
  end
104
212
 
105
213
  def test_joins_with_block
106
214
  sql = Author.joins(:posts) { :posts[:author_id] == :authors[:id] }.to_sql
107
- assert_match(/INNER JOIN "posts" ON "posts"."author_id" = "authors"."id"/, sql)
215
+ assert_sql(/INNER JOIN "posts" ON "posts"."author_id" = "authors"."id"/, sql)
108
216
  end
109
217
 
110
218
  def test_left_outer_joins_with_block
111
219
  sql = Author.left_outer_joins(:posts) { :posts[:author_id] == :authors[:id] }.to_sql
112
- assert_match(/LEFT OUTER JOIN "posts" ON "posts"."author_id" = "authors"."id"/, sql)
220
+ assert_sql(/LEFT OUTER JOIN "posts" ON "posts"."author_id" = "authors"."id"/, sql)
113
221
  end
114
222
 
115
223
  def test_select_aggregate
116
- assert_match(/SELECT SUM\("users"."age"\)/,
224
+ assert_sql(/SELECT SUM\("users"."age"\)/,
117
225
  User.select { :age.sum }.to_sql)
118
226
  end
119
227
 
120
228
  def test_select_aggregate_qualified
121
- assert_match(/SELECT COUNT\("users"."id"\)/,
229
+ assert_sql(/SELECT COUNT\("users"."id"\)/,
122
230
  User.select { :users[:id].count }.to_sql)
123
231
  end
124
232
 
125
233
  def test_select_average
126
- assert_match(/SELECT AVG\("users"."age"\)/,
234
+ assert_sql(/SELECT AVG\("users"."age"\)/,
127
235
  User.select { :age.average }.to_sql)
128
236
  end
129
237
 
130
238
  def test_select_maximum
131
- assert_match(/SELECT MAX\("users"."age"\)/,
239
+ assert_sql(/SELECT MAX\("users"."age"\)/,
132
240
  User.select { :age.maximum }.to_sql)
133
241
  end
134
242
 
135
243
  def test_select_minimum
136
- assert_match(/SELECT MIN\("users"."age"\)/,
244
+ assert_sql(/SELECT MIN\("users"."age"\)/,
137
245
  User.select { :age.minimum }.to_sql)
138
246
  end
139
247
 
140
248
  def test_having_aggregate
141
249
  sql = User.group(:name).having { :age.sum > 100 }.to_sql
142
- assert_match(/GROUP BY "users"."name"/, sql)
143
- assert_match(/HAVING SUM\("users"."age"\) > 100/, sql)
250
+ assert_sql(/GROUP BY "users"."name"/, sql)
251
+ assert_sql(/HAVING SUM\("users"."age"\) > 100/, sql)
144
252
  end
145
253
 
146
254
  def test_select_avg_function
147
- assert_match(/SELECT AVG\("users"."age"\)/,
255
+ assert_sql(/SELECT AVG\("users"."age"\)/,
148
256
  User.select { avg(:age) }.to_sql)
149
257
  end
150
258
 
151
259
  def test_select_count_function
152
- assert_match(/SELECT COUNT\("users"."id"\)/,
260
+ assert_sql(/SELECT COUNT\("users"."id"\)/,
153
261
  User.select { count(:id) }.to_sql)
154
262
  end
155
263
 
264
+ def test_select_count_star
265
+ assert_sql(/SELECT COUNT\(\*\)/,
266
+ User.select { count(:*) }.to_sql)
267
+ end
268
+
269
+ def test_select_count_star_alias
270
+ assert_sql(/SELECT COUNT\(\*\) AS cnt/,
271
+ User.select { count(:*).as(:cnt) }.to_sql)
272
+ end
273
+
274
+ def test_having_count_star
275
+ sql = Author.joins(:posts) { :posts[:author_id] == :authors[:id] }.
276
+ group { :authors[:id] }.
277
+ having { count(:*) > 1 }.to_sql
278
+ assert_sql(/HAVING COUNT\(\*\) > 1/, sql)
279
+ end
280
+
281
+ def test_order_count_star
282
+ assert_sql(/ORDER BY COUNT\(\*\) DESC/,
283
+ User.group(:name).order { count(:*).desc }.to_sql)
284
+ end
285
+
156
286
  def test_select_sum_function
157
- assert_match(/SELECT SUM\("users"."age"\)/,
287
+ assert_sql(/SELECT SUM\("users"."age"\)/,
158
288
  User.select { sum(:age) }.to_sql)
159
289
  end
160
290
 
161
291
  def test_select_min_function
162
- assert_match(/SELECT MIN\("users"."age"\)/,
292
+ assert_sql(/SELECT MIN\("users"."age"\)/,
163
293
  User.select { min(:age) }.to_sql)
164
294
  end
165
295
 
166
296
  def test_select_max_function
167
- assert_match(/SELECT MAX\("users"."age"\)/,
297
+ assert_sql(/SELECT MAX\("users"."age"\)/,
168
298
  User.select { max(:age) }.to_sql)
169
299
  end
170
300
 
171
301
  def test_function_qualified_column
172
- assert_match(/SELECT AVG\("users"."age"\)/,
302
+ assert_sql(/SELECT AVG\("users"."age"\)/,
173
303
  User.select { avg(:users[:age]) }.to_sql)
174
304
  end
175
305
 
176
306
  def test_having_function
177
307
  sql = User.group(:name).having { sum(:age) > 100 }.to_sql
178
- assert_match(/GROUP BY "users"."name"/, sql)
179
- assert_match(/HAVING SUM\("users"."age"\) > 100/, sql)
308
+ assert_sql(/GROUP BY "users"."name"/, sql)
309
+ assert_sql(/HAVING SUM\("users"."age"\) > 100/, sql)
180
310
  end
181
311
 
182
312
  def test_function_and_method_syntax_match
@@ -185,123 +315,138 @@ class TestBlockSyntax < Minitest::Test
185
315
  end
186
316
 
187
317
  def test_upper_function
188
- assert_match(/SELECT UPPER\("users"."name"\)/,
318
+ assert_sql(/SELECT UPPER\("users"."name"\)/,
189
319
  User.select { upper(:name) }.to_sql)
190
320
  end
191
321
 
192
322
  def test_lower_function
193
- assert_match(/SELECT LOWER\("users"."name"\)/,
323
+ assert_sql(/SELECT LOWER\("users"."name"\)/,
194
324
  User.select { lower(:name) }.to_sql)
195
325
  end
196
326
 
197
327
  def test_length_function_in_where
198
- assert_match(/WHERE LENGTH\("users"."name"\) > 3/,
328
+ assert_sql(/WHERE LENGTH\("users"."name"\) > 3/,
199
329
  User.where { length(:name) > 3 }.to_sql)
200
330
  end
201
331
 
202
332
  def test_coalesce_function_with_literal
203
- assert_match(/SELECT COALESCE\("users"."name", 'unknown'\)/,
333
+ assert_sql(/SELECT COALESCE\("users"."name", 'unknown'\)/,
204
334
  User.select { coalesce(:name, 'unknown') }.to_sql)
205
335
  end
206
336
 
207
337
  def test_function_comparison
208
- assert_match(/WHERE UPPER\("users"."name"\) = 'MATZ'/,
338
+ assert_sql(/WHERE UPPER\("users"."name"\) = 'MATZ'/,
209
339
  User.where { upper(:name) == 'MATZ' }.to_sql)
210
340
  end
211
341
 
342
+ def test_function_like
343
+ assert_sql(/WHERE UPPER\("users"."name"\) LIKE 'MA%'/,
344
+ User.where { upper(:name).like?('MA%') }.to_sql)
345
+ end
346
+
347
+ def test_function_in
348
+ assert_sql(/WHERE UPPER\("users"."name"\) IN \('MATZ', 'NOBU'\)/,
349
+ User.where { upper(:name).in?(%w[MATZ NOBU]) }.to_sql)
350
+ end
351
+
352
+ def test_aggregate_in
353
+ assert_sql(/HAVING SUM\("users"."age"\) BETWEEN 1 AND 10/,
354
+ User.group(:name).having { :age.sum.in?(1..10) }.to_sql)
355
+ end
356
+
212
357
  def test_nested_function
213
- assert_match(/SELECT UPPER\(COALESCE\("users"."name", 'x'\)\)/,
358
+ assert_sql(/SELECT UPPER\(COALESCE\("users"."name", 'x'\)\)/,
214
359
  User.select { upper(coalesce(:name, 'x')) }.to_sql)
215
360
  end
216
361
 
217
362
  def test_function_qualified_column_arg
218
- assert_match(/SELECT UPPER\("users"."name"\)/,
363
+ assert_sql(/SELECT UPPER\("users"."name"\)/,
219
364
  User.select { upper(:users[:name]) }.to_sql)
220
365
  end
221
366
 
222
367
  def test_select_multiple_fields
223
- assert_match(/SELECT UPPER\("users"."name"\), "users"."age"/,
368
+ assert_sql(/SELECT UPPER\("users"."name"\), "users"."age"/,
224
369
  User.select { [upper(:name), :age] }.to_sql)
225
370
  end
226
371
 
227
372
  def test_select_multiple_columns
228
- assert_match(/SELECT "users"."name", "users"."age"/,
373
+ assert_sql(/SELECT "users"."name", "users"."age"/,
229
374
  User.select { [:name, :age] }.to_sql)
230
375
  end
231
376
 
232
377
  def test_select_multiple_with_aggregate
233
- assert_match(/SELECT "users"."name", SUM\("users"."age"\)/,
378
+ assert_sql(/SELECT "users"."name", SUM\("users"."age"\)/,
234
379
  User.select { [:name, sum(:age)] }.to_sql)
235
380
  end
236
381
 
237
382
  def test_select_function_with_alias
238
- assert_match(/SELECT UPPER\("users"."name"\) AS upper_name, "users"."age"/,
383
+ assert_sql(/SELECT UPPER\("users"."name"\) AS upper_name, "users"."age"/,
239
384
  User.select { [upper(:name).as(:upper_name), :age] }.to_sql)
240
385
  end
241
386
 
242
387
  def test_select_column_alias
243
- assert_match(/SELECT "users"."name" AS n/,
388
+ assert_sql(/SELECT "users"."name" AS n/,
244
389
  User.select { :name.as(:n) }.to_sql)
245
390
  end
246
391
 
247
392
  def test_select_qualified_column_alias
248
- assert_match(/SELECT "users"."name" AS n/,
393
+ assert_sql(/SELECT "users"."name" AS n/,
249
394
  User.select { :users[:name].as(:n) }.to_sql)
250
395
  end
251
396
 
252
397
  def test_select_aggregate_alias
253
- assert_match(/SELECT COUNT\("users"."id"\) AS cnt/,
398
+ assert_sql(/SELECT COUNT\("users"."id"\) AS cnt/,
254
399
  User.select { count(:id).as(:cnt) }.to_sql)
255
400
  end
256
401
 
257
402
  def test_order_default_asc
258
- assert_match(/ORDER BY "users"."age"/,
403
+ assert_sql(/ORDER BY "users"."age"/,
259
404
  User.order { :age }.to_sql)
260
405
  end
261
406
 
262
407
  def test_order_desc
263
- assert_match(/ORDER BY "users"."age" DESC/,
408
+ assert_sql(/ORDER BY "users"."age" DESC/,
264
409
  User.order { :age.desc }.to_sql)
265
410
  end
266
411
 
267
412
  def test_order_asc
268
- assert_match(/ORDER BY "users"."age" ASC/,
413
+ assert_sql(/ORDER BY "users"."age" ASC/,
269
414
  User.order { :age.asc }.to_sql)
270
415
  end
271
416
 
272
417
  def test_order_multiple
273
- assert_match(/ORDER BY "users"."age" DESC, "users"."name" ASC/,
418
+ assert_sql(/ORDER BY "users"."age" DESC, "users"."name" ASC/,
274
419
  User.order { [:age.desc, :name.asc] }.to_sql)
275
420
  end
276
421
 
277
422
  def test_order_qualified_column
278
- assert_match(/ORDER BY "users"."name" DESC/,
423
+ assert_sql(/ORDER BY "users"."name" DESC/,
279
424
  User.order { :users[:name].desc }.to_sql)
280
425
  end
281
426
 
282
427
  def test_group_single
283
- assert_match(/GROUP BY "users"."name"/,
428
+ assert_sql(/GROUP BY "users"."name"/,
284
429
  User.group { :name }.to_sql)
285
430
  end
286
431
 
287
432
  def test_group_multiple
288
- assert_match(/GROUP BY "users"."name", "users"."age"/,
433
+ assert_sql(/GROUP BY "users"."name", "users"."age"/,
289
434
  User.group { [:name, :age] }.to_sql)
290
435
  end
291
436
 
292
437
  def test_group_qualified_column
293
- assert_match(/GROUP BY "users"."name"/,
438
+ assert_sql(/GROUP BY "users"."name"/,
294
439
  User.group { :users[:name] }.to_sql)
295
440
  end
296
441
 
297
442
  def test_group_with_having
298
443
  sql = User.group { :name }.having { sum(:age) > 100 }.to_sql
299
- assert_match(/GROUP BY "users"."name"/, sql)
300
- assert_match(/HAVING SUM\("users"."age"\) > 100/, sql)
444
+ assert_sql(/GROUP BY "users"."name"/, sql)
445
+ assert_sql(/HAVING SUM\("users"."age"\) > 100/, sql)
301
446
  end
302
447
 
303
448
  def test_default_where_syntax
304
- assert_match(/WHERE "users"."name" = 'Ruby' AND "users"."age" = 19/,
449
+ assert_sql(/WHERE "users"."name" = 'Ruby' AND "users"."age" = 19/,
305
450
  User.where(name: 'Ruby', age: 19).to_sql)
306
451
  end
307
452
  end
data/test/test_helper.rb CHANGED
@@ -5,9 +5,89 @@ require 'minitest/autorun'
5
5
  Bundler.require
6
6
 
7
7
  require 'active_record'
8
+ require 'etc'
8
9
 
9
- config = {:adapter => 'sqlite3', :database => ':memory:'}
10
- ActiveRecord::Base.establish_connection(config)
10
+ # Which database to generate SQL for. The tests only build queries, so any
11
+ # server reachable without further setup will do; the devcontainer runs
12
+ # PostgreSQL and MariaDB on localhost with a passwordless account named after
13
+ # the container user.
14
+ #
15
+ # rake test # sqlite3
16
+ # ADAPTER=postgresql rake test
17
+ # ADAPTER=mysql2 rake test
18
+ # rake test:all # all three in turn
19
+ ADAPTER = ENV.fetch('ADAPTER', 'sqlite3')
20
+
21
+ DATABASE_NAME = 'activerecord_refined_test'.freeze
22
+
23
+ DATABASE_CONFIG =
24
+ case ADAPTER
25
+ when 'sqlite3'
26
+ {adapter: 'sqlite3', database: ':memory:'}
27
+ when 'postgresql', 'mysql2'
28
+ {
29
+ adapter: ADAPTER,
30
+ host: ENV.fetch('DB_HOST', '127.0.0.1'),
31
+ username: ENV.fetch('DB_USERNAME') { Etc.getlogin },
32
+ password: ENV['DB_PASSWORD'],
33
+ database: DATABASE_NAME,
34
+ }
35
+ else
36
+ raise ArgumentError, "unknown ADAPTER: #{ADAPTER}"
37
+ end
38
+
39
+ # The server databases persist between runs, so create one on first use.
40
+ unless ADAPTER == 'sqlite3'
41
+ maintenance_database = ADAPTER == 'postgresql' ? 'postgres' : 'mysql'
42
+ ActiveRecord::Base.establish_connection(
43
+ DATABASE_CONFIG.merge(database: maintenance_database))
44
+ begin
45
+ ActiveRecord::Base.lease_connection.create_database(DATABASE_NAME)
46
+ rescue ActiveRecord::DatabaseAlreadyExists
47
+ end
48
+ ActiveRecord::Base.remove_connection
49
+ end
50
+
51
+ ActiveRecord::Base.establish_connection(DATABASE_CONFIG)
52
+
53
+ module SqlAssertions
54
+ # Arel spells the regexp match differently per adapter, and raises on the
55
+ # ones missing from this list.
56
+ REGEXP_OPERATORS = {
57
+ 'postgresql' => ['~', '!~'],
58
+ 'mysql2' => ['REGEXP', 'NOT REGEXP'],
59
+ }.freeze
60
+
61
+ def skip_without_regexp_support
62
+ skip "#{ADAPTER} has no regexp operator" unless REGEXP_OPERATORS.key?(ADAPTER)
63
+ end
64
+
65
+ def regexp_operator
66
+ Regexp.escape(REGEXP_OPERATORS.fetch(ADAPTER).first)
67
+ end
68
+
69
+ def not_regexp_operator
70
+ Regexp.escape(REGEXP_OPERATORS.fetch(ADAPTER).last)
71
+ end
72
+
73
+ # MySQL quotes identifiers with backticks instead of double quotes, and
74
+ # doubles the backslashes inside string literals because backslash is itself
75
+ # an escape character there. Normalising both lets a single expectation
76
+ # cover every adapter.
77
+ def normalize_sql(sql)
78
+ sql.tr('`', '"').gsub("\\\\") { "\\" }
79
+ end
80
+
81
+ # Takes a relation or the SQL string of one.
82
+ def assert_sql(pattern, relation_or_sql)
83
+ sql = relation_or_sql.respond_to?(:to_sql) ? relation_or_sql.to_sql : relation_or_sql
84
+ assert_match(pattern, normalize_sql(sql))
85
+ end
86
+ end
87
+
88
+ class Minitest::Test
89
+ include SqlAssertions
90
+ end
11
91
 
12
92
  class User < ActiveRecord::Base
13
93
  end
@@ -22,6 +102,9 @@ end
22
102
 
23
103
  class CreateAllTables < ActiveRecord::Migration[8.1]
24
104
  def up
105
+ drop_table(:users, if_exists: true)
106
+ drop_table(:authors, if_exists: true)
107
+ drop_table(:posts, if_exists: true)
25
108
  create_table(:users) {|t| t.string :name; t.integer :age}
26
109
  create_table(:authors) {|t| t.string :name}
27
110
  create_table(:posts) {|t| t.string :title; t.integer :author_id}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-refined
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shugo Maeda
@@ -80,12 +80,16 @@ executables: []
80
80
  extensions: []
81
81
  extra_rdoc_files: []
82
82
  files:
83
+ - .github/workflows/push_gem.yml
84
+ - .github/workflows/test.yml
83
85
  - .gitignore
84
86
  - Gemfile
85
87
  - LICENSE.txt
86
88
  - README.md
87
89
  - Rakefile
88
90
  - activerecord-refined.gemspec
91
+ - examples/aggregations.rb
92
+ - examples/complex_joins.rb
89
93
  - lib/active_record/refined.rb
90
94
  - lib/active_record/refined/ast.rb
91
95
  - lib/activerecord-refined.rb
@@ -113,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
117
  requirements: []
114
118
  rubygems_version: 4.1.0.dev
115
119
  specification_version: 4
116
- summary: ActiveRecord + Ruby 2.0 refinements
120
+ summary: "ActiveRecord + Ruby 4.1 Proc#refined"
117
121
  test_files:
118
122
  - test/test_block_syntax.rb
119
123
  - test/test_helper.rb