arel_extensions 2.3.3 → 2.4.0
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 +92 -43
- data/.rubocop.yml +4 -4
- data/Makefile +18 -0
- data/NEWS.md +7 -0
- data/README.md +21 -3
- data/dev/arelx.dockerfile +13 -16
- data/dev/compose.yaml +26 -28
- data/gemfiles/rails8.gemfile +40 -0
- data/gemfiles/rails8_1.gemfile +41 -0
- data/lib/arel_extensions/constants.rb +13 -0
- data/lib/arel_extensions/helpers.rb +3 -4
- data/lib/arel_extensions/math_functions.rb +1 -1
- data/lib/arel_extensions/nodes/byte_size.rb +11 -0
- data/lib/arel_extensions/nodes/case.rb +1 -1
- data/lib/arel_extensions/nodes/char_length.rb +11 -0
- data/lib/arel_extensions/nodes/function.rb +1 -3
- data/lib/arel_extensions/nodes/matches.rb +2 -2
- data/lib/arel_extensions/predications.rb +1 -1
- data/lib/arel_extensions/string_functions.rb +11 -1
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +23 -8
- data/lib/arel_extensions/visitors/mysql.rb +14 -0
- data/lib/arel_extensions/visitors/oracle.rb +15 -1
- data/lib/arel_extensions/visitors/postgresql.rb +14 -0
- data/lib/arel_extensions/visitors/sqlite.rb +17 -1
- data/lib/arel_extensions/visitors/to_sql.rb +1 -1
- data/lib/arel_extensions/visitors.rb +1 -1
- data/lib/arel_extensions.rb +15 -6
- data/test/arelx_test_helper.rb +8 -6
- data/test/config_loader.rb +9 -0
- data/test/database.yml +8 -6
- data/test/real_db_test.rb +2 -2
- data/test/support/fake_record.rb +3 -1
- data/test/visitors/test_bulk_insert_oracle.rb +2 -2
- data/test/visitors/test_bulk_insert_sqlite.rb +2 -2
- data/test/with_ar/all_agnostic_test.rb +65 -17
- data/test/with_ar/insert_agnostic_test.rb +2 -2
- data/test/with_ar/test_bulk_sqlite.rb +2 -2
- data/test/with_ar/test_math_sqlite.rb +2 -2
- data/test/with_ar/test_string_mysql.rb +2 -2
- data/test/with_ar/test_string_sqlite.rb +2 -2
- data/version_v1.rb +1 -1
- data/version_v2.rb +1 -1
- metadata +9 -5
- data/bin/compose +0 -6
- data/gemfiles/rails3.gemfile +0 -20
- data/gemfiles/rails4_2.gemfile +0 -38
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
module ArelExtensions
|
|
2
2
|
module Nodes
|
|
3
3
|
class IMatches < Arel::Nodes::Matches
|
|
4
|
-
attr_accessor :case_sensitive if
|
|
4
|
+
attr_accessor :case_sensitive if AREL_VERSION < V7
|
|
5
5
|
|
|
6
6
|
def initialize(left, right, escape = nil)
|
|
7
7
|
r = Arel.quoted(right)
|
|
8
|
-
if
|
|
8
|
+
if AREL_VERSION < V7 # managed by default in version 7+ (rails 5), so useful for rails 3 & 4
|
|
9
9
|
super(left, r, escape)
|
|
10
10
|
@case_sensitive = false
|
|
11
11
|
else
|
|
@@ -5,7 +5,7 @@ module ArelExtensions
|
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
def matches(other, escape = nil, case_sensitive = nil)
|
|
8
|
-
if
|
|
8
|
+
if AREL_VERSION < V7
|
|
9
9
|
Arel::Nodes::Matches.new(self, Arel.quoted(other), escape)
|
|
10
10
|
else
|
|
11
11
|
Arel::Nodes::Matches.new(self, Arel.quoted(other), escape, case_sensitive)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'arel_extensions/nodes/byte_size'
|
|
2
|
+
require 'arel_extensions/nodes/char_length'
|
|
1
3
|
require 'arel_extensions/nodes/concat' # if Arel::VERSION.to_i < 7
|
|
2
4
|
require 'arel_extensions/nodes/length'
|
|
3
5
|
require 'arel_extensions/nodes/locate'
|
|
@@ -19,6 +21,8 @@ require 'arel_extensions/nodes/md5'
|
|
|
19
21
|
|
|
20
22
|
module ArelExtensions
|
|
21
23
|
module StringFunctions
|
|
24
|
+
include ArelExtensions::Warning
|
|
25
|
+
|
|
22
26
|
# *FindInSet function .......
|
|
23
27
|
def &(other)
|
|
24
28
|
ArelExtensions::Nodes::FindInSet.new [
|
|
@@ -29,15 +33,21 @@ module ArelExtensions
|
|
|
29
33
|
|
|
30
34
|
# LENGTH function returns the length (bytewise) of the value in a text field.
|
|
31
35
|
def length
|
|
36
|
+
deprecated "Use `byte_size` or `char_length` instead. `length` relies on the vendor's `LEN/LENGTH` implementation and it's not portable"
|
|
32
37
|
ArelExtensions::Nodes::Length.new self, true
|
|
33
38
|
end
|
|
34
39
|
|
|
35
40
|
def byte_length
|
|
41
|
+
deprecated "Use `byte_size` instead. `byte_length` relies on the vendor's `LEN/LENGTH` implementation and it's not portable"
|
|
36
42
|
ArelExtensions::Nodes::Length.new self, true
|
|
37
43
|
end
|
|
38
44
|
|
|
45
|
+
def byte_size
|
|
46
|
+
ArelExtensions::Nodes::ByteSize.new self
|
|
47
|
+
end
|
|
48
|
+
|
|
39
49
|
def char_length
|
|
40
|
-
ArelExtensions::Nodes::
|
|
50
|
+
ArelExtensions::Nodes::CharLength.new self
|
|
41
51
|
end
|
|
42
52
|
|
|
43
53
|
# LOCATE function returns the first starting position of a string in another string.
|
|
@@ -76,7 +76,7 @@ module ArelExtensions
|
|
|
76
76
|
# The following is adapted from
|
|
77
77
|
# https://github.com/rails/rails/blob/main/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
|
|
78
78
|
#
|
|
79
|
-
if RUBY_PLATFORM == 'java' &&
|
|
79
|
+
if RUBY_PLATFORM == 'java' && AREL_VERSION <= V6
|
|
80
80
|
def quote_string(s)
|
|
81
81
|
s.gsub('\\', '\&\&').gsub("'", "''") # ' (for ruby-mode)
|
|
82
82
|
end
|
|
@@ -133,7 +133,7 @@ module ArelExtensions
|
|
|
133
133
|
value.to_s('F')
|
|
134
134
|
when Numeric, ActiveSupport::Duration
|
|
135
135
|
value.to_s
|
|
136
|
-
when
|
|
136
|
+
when AREL_VERSION > V6 && ActiveRecord::Type::Time::Value
|
|
137
137
|
"'#{quoted_time(value)}'"
|
|
138
138
|
when Date, Time
|
|
139
139
|
"'#{quoted_date(value)}'"
|
|
@@ -216,8 +216,6 @@ module ArelExtensions
|
|
|
216
216
|
collector
|
|
217
217
|
end
|
|
218
218
|
|
|
219
|
-
|
|
220
|
-
|
|
221
219
|
def visit_ArelExtensions_Nodes_DateDiff o, collector
|
|
222
220
|
case o.right_node_type
|
|
223
221
|
when :ruby_date, :ruby_time, :date, :datetime, :time
|
|
@@ -274,6 +272,23 @@ module ArelExtensions
|
|
|
274
272
|
collector
|
|
275
273
|
end
|
|
276
274
|
|
|
275
|
+
def visit_ArelExtensions_Nodes_ByteSize o, collector
|
|
276
|
+
collector << 'DATALENGTH(CAST('
|
|
277
|
+
collector = visit o.expr.coalesce(''), collector
|
|
278
|
+
collector << ' AS VARCHAR(MAX)))'
|
|
279
|
+
collector
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def visit_ArelExtensions_Nodes_CharLength o, collector
|
|
283
|
+
# According to the docs https://learn.microsoft.com/en-us/sql/t-sql/functions/len-transact-sql?view=sql-server-ver17
|
|
284
|
+
# LEN doesn't take into account the trailing white space, and that's why
|
|
285
|
+
# we need to do acrobatics.
|
|
286
|
+
collector << 'LEN('
|
|
287
|
+
collector = visit o.expr.coalesce(''), collector
|
|
288
|
+
collector << " + 'x') - 1"
|
|
289
|
+
collector
|
|
290
|
+
end
|
|
291
|
+
|
|
277
292
|
def visit_ArelExtensions_Nodes_Length o, collector
|
|
278
293
|
if o.bytewise
|
|
279
294
|
collector << '(DATALENGTH('
|
|
@@ -575,11 +590,11 @@ module ArelExtensions
|
|
|
575
590
|
# Sometimes these values are already quoted, if they are, don't double quote it
|
|
576
591
|
lft, rgt =
|
|
577
592
|
if o.right.is_a?(Arel::Nodes::SqlLiteral)
|
|
578
|
-
if
|
|
593
|
+
if AREL_VERSION >= V6 && o.right[0] != '[' && o.right[-1] != ']'
|
|
579
594
|
# This is a lie, it's not about arel version, but SQL Server's (>= 2000).
|
|
580
|
-
[
|
|
581
|
-
elsif o.right[0] != '"' && o.right[-1] != '"'
|
|
582
|
-
|
|
595
|
+
%w([ ])
|
|
596
|
+
elsif ACTIVE_RECORD_VERSION < V8_1 && o.right[0] != '"' && o.right[-1] != '"'
|
|
597
|
+
%w(" ")
|
|
583
598
|
else
|
|
584
599
|
[]
|
|
585
600
|
end
|
|
@@ -86,6 +86,20 @@ module ArelExtensions
|
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
# String functions
|
|
89
|
+
def visit_ArelExtensions_Nodes_ByteSize o, collector
|
|
90
|
+
collector << 'LENGTH('
|
|
91
|
+
collector = visit o.expr.coalesce(''), collector
|
|
92
|
+
collector << ')'
|
|
93
|
+
collector
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def visit_ArelExtensions_Nodes_CharLength o, collector
|
|
97
|
+
collector << 'CHAR_LENGTH('
|
|
98
|
+
collector = visit o.expr.coalesce(''), collector
|
|
99
|
+
collector << ')'
|
|
100
|
+
collector
|
|
101
|
+
end
|
|
102
|
+
|
|
89
103
|
def visit_ArelExtensions_Nodes_IMatches o, collector # insensitive on ASCII
|
|
90
104
|
collector << 'LOWER('
|
|
91
105
|
collector = visit o.left, collector
|
|
@@ -13,6 +13,20 @@ module ArelExtensions
|
|
|
13
13
|
}
|
|
14
14
|
NUMBER_COMMA_MAPPING = {'en_US' => '.,', 'fr_FR' => ',', 'sv_SE' => ', '}
|
|
15
15
|
|
|
16
|
+
def visit_ArelExtensions_Nodes_ByteSize o, collector
|
|
17
|
+
collector << 'LENGTHB('
|
|
18
|
+
collector = visit o.expr.coalesce(''), collector
|
|
19
|
+
collector << ')'
|
|
20
|
+
collector
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def visit_ArelExtensions_Nodes_CharLength o, collector
|
|
24
|
+
collector << 'LENGTH('
|
|
25
|
+
collector = visit o.expr.coalesce(''), collector
|
|
26
|
+
collector << ')'
|
|
27
|
+
collector
|
|
28
|
+
end
|
|
29
|
+
|
|
16
30
|
def visit_ArelExtensions_Nodes_Log10 o, collector
|
|
17
31
|
collector << 'LOG('
|
|
18
32
|
o.expressions.each_with_index { |arg, i|
|
|
@@ -489,7 +503,7 @@ module ArelExtensions
|
|
|
489
503
|
end
|
|
490
504
|
|
|
491
505
|
# add primary_key if not present, avoid zip
|
|
492
|
-
if
|
|
506
|
+
if AREL_VERSION < V7
|
|
493
507
|
def visit_ArelExtensions_InsertManager_BulkValues o, collector
|
|
494
508
|
collector << '('
|
|
495
509
|
o.left.each_with_index do |row, idx| # values
|
|
@@ -20,6 +20,20 @@ module ArelExtensions
|
|
|
20
20
|
'en_US' => '.,', 'fr_FR' => ',', 'sv_SE' => ', '
|
|
21
21
|
}.freeze
|
|
22
22
|
|
|
23
|
+
def visit_ArelExtensions_Nodes_ByteSize o, collector
|
|
24
|
+
collector << 'octet_length('
|
|
25
|
+
collector = visit o.expr.coalesce(''), collector
|
|
26
|
+
collector << ')'
|
|
27
|
+
collector
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def visit_ArelExtensions_Nodes_CharLength o, collector
|
|
31
|
+
collector << 'length('
|
|
32
|
+
collector = visit o.expr.coalesce(''), collector
|
|
33
|
+
collector << ')'
|
|
34
|
+
collector
|
|
35
|
+
end
|
|
36
|
+
|
|
23
37
|
def visit_ArelExtensions_Nodes_Rand o, collector
|
|
24
38
|
collector << 'RANDOM('
|
|
25
39
|
if (o.left != nil && o.right != nil)
|
|
@@ -18,6 +18,22 @@ module ArelExtensions
|
|
|
18
18
|
}.freeze
|
|
19
19
|
|
|
20
20
|
# String functions
|
|
21
|
+
def visit_ArelExtensions_Nodes_ByteSize o, collector
|
|
22
|
+
# sqlite 3.43.0 (2023-08-24) introduced `octet_length`, but we still support older versions.
|
|
23
|
+
# https://sqlite.org/changes.html
|
|
24
|
+
collector << 'length(CAST('
|
|
25
|
+
collector = visit o.expr.coalesce(''), collector
|
|
26
|
+
collector << ' AS BLOB))'
|
|
27
|
+
collector
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def visit_ArelExtensions_Nodes_CharLength o, collector
|
|
31
|
+
collector << 'length('
|
|
32
|
+
collector = visit o.expr.coalesce(''), collector
|
|
33
|
+
collector << ')'
|
|
34
|
+
collector
|
|
35
|
+
end
|
|
36
|
+
|
|
21
37
|
def visit_ArelExtensions_Nodes_IMatches o, collector # insensitive on ASCII
|
|
22
38
|
collector = visit o.left.ci_collate, collector
|
|
23
39
|
collector << ' LIKE '
|
|
@@ -237,7 +253,7 @@ module ArelExtensions
|
|
|
237
253
|
collector
|
|
238
254
|
end
|
|
239
255
|
|
|
240
|
-
if
|
|
256
|
+
if AREL_VERSION < V7
|
|
241
257
|
def visit_ArelExtensions_InsertManager_BulkValues o, collector
|
|
242
258
|
o.left.each_with_index do |row, idx|
|
|
243
259
|
collector << 'SELECT '
|
|
@@ -14,7 +14,7 @@ if RUBY_PLATFORM == 'java' \
|
|
|
14
14
|
warn 'arel/visitors/sqlserver not found: MSSQL might not work correctly.'
|
|
15
15
|
end
|
|
16
16
|
elsif RUBY_PLATFORM != 'java' \
|
|
17
|
-
&&
|
|
17
|
+
&& ArelExtensions::AREL_VERSION < ArelExtensions::V10 \
|
|
18
18
|
&& Gem::Specification.find { |g| g.name == 'activerecord-sqlserver-adapter' }
|
|
19
19
|
begin
|
|
20
20
|
require 'arel_sqlserver'
|
data/lib/arel_extensions.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'arel'
|
|
2
|
+
require 'arel_extensions/constants'
|
|
2
3
|
require 'base64'
|
|
3
4
|
|
|
4
5
|
require 'arel_extensions/railtie' if defined?(Rails::Railtie)
|
|
@@ -17,7 +18,7 @@ class Arel::Nodes::Casted
|
|
|
17
18
|
include Arel::AliasPredication
|
|
18
19
|
|
|
19
20
|
# They forget to define hash.
|
|
20
|
-
if
|
|
21
|
+
if ArelExtensions::AREL_VERSION < ArelExtensions::V10
|
|
21
22
|
def hash
|
|
22
23
|
[self.class, self.val, self.attribute].hash
|
|
23
24
|
end
|
|
@@ -45,7 +46,7 @@ class Arel::Nodes::Function
|
|
|
45
46
|
include Arel::Expressions
|
|
46
47
|
end
|
|
47
48
|
|
|
48
|
-
if
|
|
49
|
+
if ArelExtensions::AREL_VERSION >= ArelExtensions::V7_1
|
|
49
50
|
class Arel::Nodes::Case
|
|
50
51
|
include Arel::Math
|
|
51
52
|
include Arel::Expressions
|
|
@@ -199,12 +200,20 @@ class Arel::Nodes::Function
|
|
|
199
200
|
include ArelExtensions::NullFunctions
|
|
200
201
|
include ArelExtensions::Predications
|
|
201
202
|
|
|
203
|
+
if ArelExtensions::ACTIVE_RECORD_VERSION >= ArelExtensions::V8_1
|
|
204
|
+
attr_accessor :alias
|
|
205
|
+
alias_method :old_initialize, :initialize
|
|
206
|
+
|
|
207
|
+
def initialize(expr, aliaz = nil)
|
|
208
|
+
old_initialize(expr)
|
|
209
|
+
self.alias = aliaz
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
202
213
|
alias_method(:old_as, :as) rescue nil
|
|
203
214
|
def as other
|
|
204
215
|
res = Arel::Nodes::As.new(self.clone, Arel.sql(other))
|
|
205
|
-
|
|
206
|
-
self.alias = Arel.sql(other)
|
|
207
|
-
end
|
|
216
|
+
self.alias = Arel.sql(other)
|
|
208
217
|
res
|
|
209
218
|
end
|
|
210
219
|
end
|
|
@@ -325,7 +334,7 @@ class Arel::Nodes::Node
|
|
|
325
334
|
end
|
|
326
335
|
|
|
327
336
|
require 'active_record'
|
|
328
|
-
if
|
|
337
|
+
if ArelExtensions::ACTIVE_RECORD_VERSION >= ArelExtensions::V7_2
|
|
329
338
|
class ActiveRecord::Relation::WhereClause
|
|
330
339
|
def except_predicates(columns)
|
|
331
340
|
attrs = columns.extract! { |node| node.is_a?(Arel::Attribute) }
|
data/test/arelx_test_helper.rb
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
require 'rubygems'
|
|
2
|
-
require 'minitest/autorun'
|
|
3
|
-
require 'fileutils'
|
|
4
|
-
require 'arel'
|
|
5
1
|
require 'active_record'
|
|
6
|
-
|
|
2
|
+
require 'arel'
|
|
3
|
+
require 'arel_extensions/constants'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
require 'minitest/autorun'
|
|
6
|
+
require 'rubygems'
|
|
7
7
|
require 'support/fake_record'
|
|
8
8
|
|
|
9
|
+
require_relative './config_loader'
|
|
10
|
+
|
|
9
11
|
ENV['AREL_EXTENSIONS_IN_TEST'] = '1' # Useful for deprecation warnings.
|
|
10
12
|
|
|
11
13
|
def colored(color, msg)
|
|
@@ -59,7 +61,7 @@ end
|
|
|
59
61
|
|
|
60
62
|
|
|
61
63
|
def load_lib(gems)
|
|
62
|
-
if gems && (RUBY_PLATFORM == 'java' ||
|
|
64
|
+
if gems && (RUBY_PLATFORM == 'java' || ArelExtensions::AREL_VERSION > ArelExtensions::V9_0)
|
|
63
65
|
gems.each do |gem|
|
|
64
66
|
begin
|
|
65
67
|
require gem
|
data/test/database.yml
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# Updated to use ENV vars mapped in compose.yml
|
|
1
2
|
sqlite:
|
|
2
3
|
adapter: sqlite3
|
|
3
4
|
database: ":memory:"
|
|
@@ -10,27 +11,28 @@ mysql:
|
|
|
10
11
|
adapter: mysql2
|
|
11
12
|
database: arelx_test
|
|
12
13
|
username: root
|
|
13
|
-
host: 127.0.0.1
|
|
14
|
+
host: <%= ENV.fetch('MYSQL_HOST', '127.0.0.1') %>
|
|
14
15
|
port: 3306
|
|
15
|
-
encoding:
|
|
16
|
+
encoding: utf8mb4
|
|
16
17
|
jdbc-mysql:
|
|
17
18
|
adapter: jdbcmysql
|
|
18
19
|
database: arelx_test
|
|
19
20
|
username: root
|
|
20
|
-
encoding:
|
|
21
|
+
encoding: utf8mb4
|
|
22
|
+
host: <%= ENV.fetch('MYSQL_HOST', '127.0.0.1') %>
|
|
21
23
|
postgresql:
|
|
22
24
|
adapter: postgresql
|
|
23
25
|
database: arelx_test
|
|
24
26
|
username: postgres
|
|
25
27
|
password: secret
|
|
26
|
-
host: 127.0.0.1
|
|
28
|
+
host: <%= ENV.fetch('POSTGRES_HOST', '127.0.0.1') %>
|
|
27
29
|
port: 5432
|
|
28
30
|
jdbc-postgresql:
|
|
29
31
|
adapter: jdbcpostgresql
|
|
30
32
|
database: arelx_test
|
|
31
33
|
username: postgres
|
|
32
34
|
password: secret
|
|
33
|
-
host: 127.0.0.1
|
|
35
|
+
host: <%= ENV.fetch('POSTGRES_HOST', '127.0.0.1') %>
|
|
34
36
|
port: 5432
|
|
35
37
|
oracle:
|
|
36
38
|
adapter: oracle_enhanced
|
|
@@ -48,7 +50,7 @@ ibm_db:
|
|
|
48
50
|
database: arelx_test
|
|
49
51
|
mssql:
|
|
50
52
|
adapter: sqlserver
|
|
51
|
-
host: localhost
|
|
53
|
+
host: <%= ENV.fetch('MSSQL_HOST', 'localhost') %>
|
|
52
54
|
database: master
|
|
53
55
|
username: sa
|
|
54
56
|
password: Password12!
|
data/test/real_db_test.rb
CHANGED
|
@@ -6,9 +6,9 @@ $:.unshift "#{File.dirname(__FILE__)}../../lib"
|
|
|
6
6
|
require 'arel_extensions'
|
|
7
7
|
|
|
8
8
|
def setup_db
|
|
9
|
-
ActiveRecord::Base.configurations =
|
|
9
|
+
ActiveRecord::Base.configurations = ConfigLoader.load('test/database.yml')
|
|
10
10
|
ActiveRecord::Base.establish_connection(ENV['DB'].try(:to_sym) || (RUBY_PLATFORM == 'java' ? :"jdbc-sqlite" : :sqlite))
|
|
11
|
-
if
|
|
11
|
+
if ACTIVE_RECORD_VERSION >= V7_0
|
|
12
12
|
ActiveRecord.default_timezone = :utc
|
|
13
13
|
else
|
|
14
14
|
ActiveRecord::Base.default_timezone = :utc
|
data/test/support/fake_record.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'arel_extensions/constants'
|
|
2
|
+
|
|
1
3
|
module FakeRecord
|
|
2
4
|
class Column < Struct.new(:name, :type)
|
|
3
5
|
end
|
|
@@ -146,7 +148,7 @@ module FakeRecord
|
|
|
146
148
|
connection_pool.connection
|
|
147
149
|
end
|
|
148
150
|
|
|
149
|
-
if
|
|
151
|
+
if ArelExtensions::ACTIVE_RECORD_VERSION >= ArelExtensions::V7_2
|
|
150
152
|
def with_connection(*args, **kwargs, &block)
|
|
151
153
|
connection_pool.with_connection(*args, **kwargs, &block)
|
|
152
154
|
end
|
|
@@ -15,7 +15,7 @@ module ArelExtensions
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def compile node
|
|
18
|
-
if
|
|
18
|
+
if AREL_VERSION > V5
|
|
19
19
|
@visitor.accept(node, Arel::Collectors::SQLString.new).value
|
|
20
20
|
else
|
|
21
21
|
@visitor.accept(node)
|
|
@@ -23,7 +23,7 @@ module ArelExtensions
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
it 'should import large set of data in Oracle' do
|
|
26
|
-
insert_manager =
|
|
26
|
+
insert_manager = AREL_VERSION > V6 ? Arel::InsertManager.new.into(@table) : Arel::InsertManager.new(@conn).into(@table)
|
|
27
27
|
insert_manager.bulk_insert(@cols, @data)
|
|
28
28
|
_(compile(insert_manager.ast))
|
|
29
29
|
.must_be_like %Q[INSERT INTO "users" ("name", "comments", "created_at")
|
|
@@ -16,7 +16,7 @@ module ArelExtensions
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def compile node
|
|
19
|
-
if
|
|
19
|
+
if AREL_VERSION > V5
|
|
20
20
|
@visitor.accept(node, Arel::Collectors::SQLString.new).value
|
|
21
21
|
else
|
|
22
22
|
@visitor.accept(node)
|
|
@@ -24,7 +24,7 @@ module ArelExtensions
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
it 'should import large set of data' do
|
|
27
|
-
insert_manager =
|
|
27
|
+
insert_manager = AREL_VERSION > V6 ? Arel::InsertManager.new.into(@table) : Arel::InsertManager.new(@conn).into(@table)
|
|
28
28
|
insert_manager.bulk_insert(@cols, @data)
|
|
29
29
|
_(compile(insert_manager.ast))
|
|
30
30
|
.must_be_like %Q[INSERT INTO "users" ("id", "name", "comments", "created_at")
|
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
require 'arelx_test_helper'
|
|
2
2
|
require 'date'
|
|
3
3
|
|
|
4
|
+
# class ActiveRecord::ConnectionAdapters::SQLServerAdapter
|
|
5
|
+
# # We use *args to avoid breaking signature changes between versions.
|
|
6
|
+
# # internal_exec_sql_query(sql, name = "SQL", binds = [], prepare: false)
|
|
7
|
+
# def internal_exec_sql_query(*args)
|
|
8
|
+
# sql = args.first
|
|
9
|
+
# puts "[DEBUG] MSSQL Query: #{sql}\n"
|
|
10
|
+
|
|
11
|
+
# # Call original implementation (defined in the DatabaseStatements module included in this class)
|
|
12
|
+
# super
|
|
13
|
+
# rescue => e
|
|
14
|
+
# # Catch the crash to print the specific query that caused it one last time
|
|
15
|
+
# puts "[CRASH]: #{args.first}\n"
|
|
16
|
+
# raise e
|
|
17
|
+
# end
|
|
18
|
+
# end
|
|
19
|
+
|
|
4
20
|
module ArelExtensions
|
|
5
21
|
module WithAr
|
|
6
22
|
class ListTest < Minitest::Test
|
|
7
23
|
def connect_db
|
|
8
|
-
ActiveRecord::Base.configurations =
|
|
24
|
+
ActiveRecord::Base.configurations = ConfigLoader.load('test/database.yml')
|
|
9
25
|
if ENV['DB'] == 'oracle' && ((defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx') || (RUBY_PLATFORM == 'java')) # not supported
|
|
10
26
|
@env_db = (RUBY_PLATFORM == 'java' ? 'jdbc-sqlite' : 'sqlite')
|
|
11
27
|
skip "Platform not supported (DB: #{ENV['DB']}, RUBY_ENGINE: #{RUBY_ENGINE}, RUBY_PLATFORM: #{RUBY_PLATFORM})"
|
|
@@ -13,7 +29,7 @@ module ArelExtensions
|
|
|
13
29
|
@env_db = ENV['DB']
|
|
14
30
|
end
|
|
15
31
|
ActiveRecord::Base.establish_connection(@env_db.try(:to_sym) || (RUBY_PLATFORM == 'java' ? :"jdbc-sqlite" : :sqlite))
|
|
16
|
-
if
|
|
32
|
+
if ACTIVE_RECORD_VERSION >= V7_0
|
|
17
33
|
ActiveRecord.default_timezone = :utc
|
|
18
34
|
else
|
|
19
35
|
ActiveRecord::Base.default_timezone = :utc
|
|
@@ -74,7 +90,14 @@ module ArelExtensions
|
|
|
74
90
|
@justin = User.where(id: u.id)
|
|
75
91
|
u = User.create age: nil, name: 'nilly', created_at: nil, score: nil
|
|
76
92
|
@nilly = User.where(id: u.id)
|
|
77
|
-
|
|
93
|
+
u = User.create age: nil, name: 'esmé', created_at: nil, score: nil
|
|
94
|
+
@esme = User.where(id: u.id)
|
|
95
|
+
u = User.create age: nil, name: 'esmé ', created_at: nil, score: nil
|
|
96
|
+
@esme2 = User.where(id: u.id)
|
|
97
|
+
u = User.create age: nil, name: nil, created_at: nil, score: nil
|
|
98
|
+
@all_nil = User.where(id: u.id)
|
|
99
|
+
|
|
100
|
+
@id = User.arel_table[:id]
|
|
78
101
|
@age = User.arel_table[:age]
|
|
79
102
|
@name = User.arel_table[:name]
|
|
80
103
|
@score = User.arel_table[:score]
|
|
@@ -96,7 +119,9 @@ module ArelExtensions
|
|
|
96
119
|
end
|
|
97
120
|
|
|
98
121
|
def t(scope, node)
|
|
99
|
-
scope.select(node.as('res'))
|
|
122
|
+
res = scope.select(node.as('res'))
|
|
123
|
+
# puts "[scope] #{res.to_sql}"
|
|
124
|
+
res.to_a.first.res
|
|
100
125
|
end
|
|
101
126
|
|
|
102
127
|
# manage the difference between adapters that handle or not json type
|
|
@@ -150,7 +175,7 @@ module ArelExtensions
|
|
|
150
175
|
def test_rand
|
|
151
176
|
assert 42 != User.select(Arel.rand.as('res')).first.res
|
|
152
177
|
assert 0 <= User.select(Arel.rand.abs.as('res')).first.res
|
|
153
|
-
assert_equal
|
|
178
|
+
assert_equal 13, User.order(Arel.rand).limit(50).count
|
|
154
179
|
end
|
|
155
180
|
|
|
156
181
|
def test_round
|
|
@@ -253,6 +278,20 @@ module ArelExtensions
|
|
|
253
278
|
assert_equal 7, t(@camille, @name.length)
|
|
254
279
|
assert_equal 7, t(@camille, @name.length.round.abs)
|
|
255
280
|
assert_equal 42, t(@laure, @name.length + 37)
|
|
281
|
+
|
|
282
|
+
if @env_db == 'mssql'
|
|
283
|
+
# By default it's UTF-16, and configuring the CI to be UTF-8 is a bit of a hassle.
|
|
284
|
+
assert_equal 4, t(@esme, @name.byte_size)
|
|
285
|
+
assert_equal 5, t(@esme2, @name.byte_size)
|
|
286
|
+
else
|
|
287
|
+
assert_equal 5, t(@esme, @name.byte_size)
|
|
288
|
+
assert_equal 6, t(@esme2, @name.byte_size)
|
|
289
|
+
end
|
|
290
|
+
assert_equal 0, t(@all_nil, @name.byte_size)
|
|
291
|
+
|
|
292
|
+
assert_equal 4, t(@esme, @name.char_length)
|
|
293
|
+
assert_equal 5, t(@esme2, @name.char_length)
|
|
294
|
+
assert_equal 0, t(@all_nil, @name.char_length)
|
|
256
295
|
end
|
|
257
296
|
|
|
258
297
|
def test_md5
|
|
@@ -341,9 +380,9 @@ module ArelExtensions
|
|
|
341
380
|
skip "Sqlite version can't load extension for regexp" if $sqlite && $load_extension_disabled
|
|
342
381
|
skip 'SQL Server does not know about REGEXP without extensions' if @env_db == 'mssql'
|
|
343
382
|
assert_equal 1, User.where(@name =~ '^M').count
|
|
344
|
-
assert_equal
|
|
383
|
+
assert_equal 10, User.where(@name !~ '^L').count
|
|
345
384
|
assert_equal 1, User.where(@name =~ /^M/).count
|
|
346
|
-
assert_equal
|
|
385
|
+
assert_equal 10, User.where(@name !~ /^L/).count
|
|
347
386
|
end
|
|
348
387
|
|
|
349
388
|
def test_regex_matches
|
|
@@ -356,8 +395,12 @@ module ArelExtensions
|
|
|
356
395
|
def test_imatches
|
|
357
396
|
# puts User.where(@name.imatches('m%')).to_sql
|
|
358
397
|
assert_equal 1, User.where(@name.imatches('m%')).count
|
|
359
|
-
|
|
360
|
-
|
|
398
|
+
if @env_db == 'mysql'
|
|
399
|
+
assert_equal 5, User.where(@name.imatches_any(['L%', '%e'])).count
|
|
400
|
+
else
|
|
401
|
+
assert_equal 4, User.where(@name.imatches_any(['L%', '%e'])).count
|
|
402
|
+
end
|
|
403
|
+
assert_equal 10, User.where(@name.idoes_not_match('L%')).count
|
|
361
404
|
end
|
|
362
405
|
|
|
363
406
|
def test_replace
|
|
@@ -382,8 +425,8 @@ module ArelExtensions
|
|
|
382
425
|
skip "Sqlite version can't load extension for soundex" if $sqlite && $load_extension_disabled
|
|
383
426
|
skip "PostgreSql version can't load extension for soundex" if @env_db == 'postgresql'
|
|
384
427
|
assert_equal 'C540', t(@camille, @name.soundex)
|
|
385
|
-
assert_equal
|
|
386
|
-
assert_equal
|
|
428
|
+
assert_equal 12, User.where(@name.soundex.eq(@name.soundex)).count
|
|
429
|
+
assert_equal 12, User.where(@name.soundex == @name.soundex).count
|
|
387
430
|
end
|
|
388
431
|
|
|
389
432
|
def test_change_case
|
|
@@ -680,7 +723,7 @@ module ArelExtensions
|
|
|
680
723
|
def test_date_comparator
|
|
681
724
|
d = Date.new(2016, 5, 23)
|
|
682
725
|
assert_equal 0, User.where(@created_at < d).count
|
|
683
|
-
assert_equal
|
|
726
|
+
assert_equal 13, User.where(@created_at >= d).count
|
|
684
727
|
end
|
|
685
728
|
|
|
686
729
|
def test_date_duration
|
|
@@ -863,7 +906,7 @@ module ArelExtensions
|
|
|
863
906
|
def test_math_minus
|
|
864
907
|
d = Date.new(2016, 5, 20)
|
|
865
908
|
# Datediff
|
|
866
|
-
assert_equal
|
|
909
|
+
assert_equal 13, User.where((@created_at - @created_at).eq(0)).count
|
|
867
910
|
assert_equal 3, @laure.select((@created_at - d).as('res')).first.res.abs.to_i
|
|
868
911
|
# Substraction
|
|
869
912
|
assert_equal 0, User.where((@age - 10).eq(50)).count
|
|
@@ -982,10 +1025,15 @@ module ArelExtensions
|
|
|
982
1025
|
end
|
|
983
1026
|
|
|
984
1027
|
def test_subquery_with_order
|
|
985
|
-
skip if
|
|
986
|
-
assert_equal
|
|
987
|
-
assert_equal
|
|
988
|
-
|
|
1028
|
+
skip if @env_db == 'mssql' && Arel::VERSION.to_i < 10
|
|
1029
|
+
assert_equal 12, User.where(name: User.select(:name).order(:name)).count
|
|
1030
|
+
assert_equal 12, User.where(@ut[:name].in(@ut.project(@ut[:name]).order(@ut[:name]))).count
|
|
1031
|
+
|
|
1032
|
+
if %w[mssql sqlite].include? @env_db
|
|
1033
|
+
# Sqlite and mssql are sensistive to the nil value in name, defined by @all_nil
|
|
1034
|
+
assert_equal 1, User.where(name: User.select(:name).order(:name).limit(2)).count
|
|
1035
|
+
elsif @env_db != 'mysql'
|
|
1036
|
+
# MySql can't have limit in IN subquery
|
|
989
1037
|
assert_equal 2, User.where(name: User.select(:name).order(:name).limit(2)).count
|
|
990
1038
|
# assert_equal 6, User.where(name: User.select(:name).order(:name).offset(2)).count
|
|
991
1039
|
end
|