arel_extensions 1.2.23 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +358 -71
- data/Gemfile +8 -8
- data/README.md +86 -0
- data/arel_extensions.gemspec +1 -1
- data/gemfiles/rails5_2.gemfile +8 -7
- data/gemfiles/rails6.gemfile +7 -8
- data/gemfiles/rails6_1.gemfile +6 -7
- data/gemfiles/rails7.gemfile +22 -0
- data/gemspecs/arel_extensions-v1.gemspec +1 -1
- data/gemspecs/arel_extensions-v2.gemspec +1 -1
- data/lib/arel_extensions/aliases.rb +14 -0
- data/lib/arel_extensions/attributes.rb +2 -0
- data/lib/arel_extensions/date_duration.rb +2 -2
- data/lib/arel_extensions/helpers.rb +48 -0
- data/lib/arel_extensions/insert_manager.rb +19 -17
- data/lib/arel_extensions/math.rb +22 -32
- data/lib/arel_extensions/nodes/case.rb +5 -6
- data/lib/arel_extensions/nodes/cast.rb +1 -1
- data/lib/arel_extensions/nodes/date_diff.rb +23 -4
- data/lib/arel_extensions/nodes/format.rb +3 -2
- data/lib/arel_extensions/nodes/function.rb +2 -6
- data/lib/arel_extensions/nodes/json.rb +3 -1
- data/lib/arel_extensions/nodes/length.rb +6 -0
- data/lib/arel_extensions/nodes/replace.rb +0 -8
- data/lib/arel_extensions/nodes/union.rb +1 -1
- data/lib/arel_extensions/nodes/union_all.rb +1 -1
- data/lib/arel_extensions/string_functions.rb +10 -2
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +109 -51
- data/lib/arel_extensions/visitors/mysql.rb +15 -2
- data/lib/arel_extensions/visitors/oracle.rb +8 -3
- data/lib/arel_extensions/visitors/postgresql.rb +21 -11
- data/lib/arel_extensions/visitors/sqlite.rb +6 -3
- data/lib/arel_extensions/visitors/to_sql.rb +14 -9
- data/lib/arel_extensions/visitors.rb +9 -1
- data/lib/arel_extensions.rb +66 -12
- data/test/arelx_test_helper.rb +45 -0
- data/test/database.yml +8 -2
- data/test/real_db_test.rb +5 -1
- data/test/support/fake_record.rb +1 -1
- data/test/visitors/test_to_sql.rb +39 -11
- data/test/with_ar/all_agnostic_test.rb +79 -6
- data/test/with_ar/insert_agnostic_test.rb +6 -2
- data/test/with_ar/test_bulk_sqlite.rb +6 -2
- data/test/with_ar/test_math_sqlite.rb +6 -2
- data/test/with_ar/test_string_mysql.rb +6 -2
- data/test/with_ar/test_string_sqlite.rb +6 -2
- data/version_v1.rb +1 -1
- data/version_v2.rb +1 -1
- metadata +10 -8
- data/appveyor.yml +0 -44
data/lib/arel_extensions.rb
CHANGED
@@ -33,6 +33,12 @@ class Arel::Nodes::Grouping
|
|
33
33
|
include Arel::OrderPredications
|
34
34
|
end
|
35
35
|
|
36
|
+
class Arel::Nodes::Ordering
|
37
|
+
def eql? other
|
38
|
+
self.hash.eql? other.hash
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
36
42
|
class Arel::Nodes::Function
|
37
43
|
include Arel::Math
|
38
44
|
include Arel::Expressions
|
@@ -46,6 +52,7 @@ if Gem::Version.new(Arel::VERSION) >= Gem::Version.new("7.1.0")
|
|
46
52
|
end
|
47
53
|
|
48
54
|
require 'arel_extensions/version'
|
55
|
+
require 'arel_extensions/aliases'
|
49
56
|
require 'arel_extensions/attributes'
|
50
57
|
require 'arel_extensions/visitors'
|
51
58
|
require 'arel_extensions/nodes'
|
@@ -70,7 +77,17 @@ require 'arel_extensions/nodes/soundex'
|
|
70
77
|
require 'arel_extensions/nodes/cast'
|
71
78
|
require 'arel_extensions/nodes/json'
|
72
79
|
|
73
|
-
|
80
|
+
# It seems like the code in lib/arel_extensions/visitors.rb that is supposed
|
81
|
+
# to inject ArelExtension is not enough. Different versions of the sqlserver
|
82
|
+
# adapter behave differently. It doesn't always proc, so we added this for
|
83
|
+
# coverage.
|
84
|
+
if defined?(Arel::Visitors::SQLServer)
|
85
|
+
Arel::Visitors.const_set('MSSQL', Arel::Visitors::SQLServer)
|
86
|
+
require 'arel_extensions/visitors/mssql'
|
87
|
+
class Arel::Visitors::SQLServer
|
88
|
+
include ArelExtensions::Visitors::MSSQL
|
89
|
+
end
|
90
|
+
end
|
74
91
|
|
75
92
|
module Arel
|
76
93
|
def self.rand
|
@@ -82,11 +99,13 @@ module Arel
|
|
82
99
|
end
|
83
100
|
|
84
101
|
def self.json *expr
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
102
|
+
ArelExtensions::Nodes::Json.new(
|
103
|
+
if expr.length == 1
|
104
|
+
expr.first
|
105
|
+
else
|
106
|
+
expr
|
107
|
+
end
|
108
|
+
)
|
90
109
|
end
|
91
110
|
|
92
111
|
def self.when condition
|
@@ -94,20 +113,31 @@ module Arel
|
|
94
113
|
end
|
95
114
|
|
96
115
|
def self.duration s, expr
|
97
|
-
ArelExtensions::Nodes::Duration.new(s
|
116
|
+
ArelExtensions::Nodes::Duration.new("#{s}i", expr)
|
98
117
|
end
|
99
118
|
|
119
|
+
def self.grouping *v
|
120
|
+
Arel::Nodes::Grouping.new(*v)
|
121
|
+
end
|
122
|
+
|
123
|
+
# The TRUE pseudo literal.
|
100
124
|
def self.true
|
101
|
-
Arel::Nodes::Equality.new(1,1)
|
125
|
+
Arel::Nodes::Equality.new(1, 1)
|
102
126
|
end
|
103
127
|
|
128
|
+
# The FALSE pseudo literal.
|
104
129
|
def self.false
|
105
|
-
Arel::Nodes::Equality.new(1,0)
|
130
|
+
Arel::Nodes::Equality.new(1, 0)
|
131
|
+
end
|
132
|
+
|
133
|
+
# The NULL literal.
|
134
|
+
def self.null
|
135
|
+
Arel::Nodes.build_quoted(nil)
|
106
136
|
end
|
107
137
|
|
108
138
|
def self.tuple *v
|
109
|
-
tmp = Arel
|
110
|
-
Arel
|
139
|
+
tmp = Arel.grouping(nil)
|
140
|
+
Arel.grouping v.map{|e| tmp.convert_to_node(e)}
|
111
141
|
end
|
112
142
|
end
|
113
143
|
|
@@ -117,6 +147,7 @@ class Arel::Attributes::Attribute
|
|
117
147
|
end
|
118
148
|
|
119
149
|
class Arel::Nodes::Function
|
150
|
+
include ArelExtensions::Aliases
|
120
151
|
include ArelExtensions::Math
|
121
152
|
include ArelExtensions::Comparators
|
122
153
|
include ArelExtensions::DateDuration
|
@@ -152,6 +183,9 @@ class Arel::Nodes::Unary
|
|
152
183
|
include ArelExtensions::MathFunctions
|
153
184
|
include ArelExtensions::Comparators
|
154
185
|
include ArelExtensions::Predications
|
186
|
+
def eql? other
|
187
|
+
hash == other.hash
|
188
|
+
end
|
155
189
|
end
|
156
190
|
|
157
191
|
class Arel::Nodes::Binary
|
@@ -161,6 +195,9 @@ class Arel::Nodes::Binary
|
|
161
195
|
include ArelExtensions::Comparators
|
162
196
|
include ArelExtensions::BooleanFunctions
|
163
197
|
include ArelExtensions::Predications
|
198
|
+
def eql? other
|
199
|
+
hash == other.hash
|
200
|
+
end
|
164
201
|
end
|
165
202
|
|
166
203
|
class Arel::Nodes::Equality
|
@@ -177,6 +214,19 @@ end
|
|
177
214
|
class Arel::SelectManager
|
178
215
|
include ArelExtensions::SetFunctions
|
179
216
|
include ArelExtensions::Nodes
|
217
|
+
|
218
|
+
def as table_name
|
219
|
+
Arel::Nodes::TableAlias.new(self, table_name)
|
220
|
+
end
|
221
|
+
|
222
|
+
# Install an alias, if present.
|
223
|
+
def xas table_name
|
224
|
+
if table_name.present?
|
225
|
+
as table_name
|
226
|
+
else
|
227
|
+
self
|
228
|
+
end
|
229
|
+
end
|
180
230
|
end
|
181
231
|
|
182
232
|
class Arel::Nodes::As
|
@@ -186,7 +236,11 @@ end
|
|
186
236
|
class Arel::Table
|
187
237
|
alias_method(:old_alias, :alias) rescue nil
|
188
238
|
def alias(name = "#{self.name}_2")
|
189
|
-
name.
|
239
|
+
if name.present?
|
240
|
+
Arel::Nodes::TableAlias.new(self, name)
|
241
|
+
else
|
242
|
+
self
|
243
|
+
end
|
190
244
|
end
|
191
245
|
end
|
192
246
|
|
data/test/arelx_test_helper.rb
CHANGED
@@ -6,6 +6,51 @@ require 'active_record'
|
|
6
6
|
|
7
7
|
require 'support/fake_record'
|
8
8
|
|
9
|
+
def colored(color, msg)
|
10
|
+
ENV["TERM"] =~ /^xterm|-256color$/ ? "\x1b[#{color}m#{msg}\x1b[89m\x1b[0m" : "#{msg}"
|
11
|
+
end
|
12
|
+
|
13
|
+
YELLOW = "33"
|
14
|
+
|
15
|
+
def warn(msg)
|
16
|
+
$stderr.puts(colored(YELLOW, msg))
|
17
|
+
end
|
18
|
+
|
19
|
+
# Load gems specific to databases
|
20
|
+
# NOTE:
|
21
|
+
# It's strongly advised to test each database on its own. Loading multiple
|
22
|
+
# backend gems leads to undefined behavior according to tests; the backend
|
23
|
+
# might not recognize the correct DB visitor and will fallback to `ToSQL`
|
24
|
+
# and screw all tests.
|
25
|
+
#
|
26
|
+
# The issue also seems to be related to arel version: at some point, arel
|
27
|
+
# dropped its wide support for DBs and kept Postgres, MySQL and SQLite.
|
28
|
+
# Here, we're just trying to load the correct ones.
|
29
|
+
db_and_gem = if RUBY_ENGINE == 'jruby'
|
30
|
+
{
|
31
|
+
'oracle' => 'activerecord-oracle_enhanced-adapter',
|
32
|
+
'mssql' => 'activerecord-jdbcsqlserver-adapter'
|
33
|
+
}
|
34
|
+
else
|
35
|
+
{
|
36
|
+
'oracle' => 'activerecord-oracle_enhanced-adapter',
|
37
|
+
'mssql' => 'activerecord-sqlserver-adapter'
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def load_lib(gem)
|
42
|
+
if gem && (RUBY_ENGINE == 'jruby' || Arel::VERSION.to_i > 9)
|
43
|
+
begin
|
44
|
+
Gem::Specification.find_by_name(gem)
|
45
|
+
require gem
|
46
|
+
rescue Gem::MissingSpecError
|
47
|
+
warn "Warning: failed to load gem #{gem}. Are you sure it's installed?"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
load_lib(db_and_gem[ENV['DB']])
|
53
|
+
|
9
54
|
require 'arel_extensions'
|
10
55
|
Arel::Table.engine = FakeRecord::Base.new
|
11
56
|
|
data/test/database.yml
CHANGED
@@ -9,23 +9,29 @@ jdbc-sqlite:
|
|
9
9
|
mysql:
|
10
10
|
adapter: mysql2
|
11
11
|
database: arext_test
|
12
|
-
username:
|
12
|
+
username: root
|
13
13
|
host: 127.0.0.1
|
14
14
|
port: 3306
|
15
15
|
encoding: utf8
|
16
16
|
jdbc-mysql:
|
17
17
|
adapter: jdbcmysql
|
18
18
|
database: arext_test
|
19
|
-
username:
|
19
|
+
username: root
|
20
20
|
encoding: utf8
|
21
21
|
postgresql:
|
22
22
|
adapter: postgresql
|
23
23
|
database: arext_test
|
24
24
|
username: postgres
|
25
|
+
password: secret
|
26
|
+
host: 127.0.0.1
|
27
|
+
port: 5432
|
25
28
|
jdbc-postgresql:
|
26
29
|
adapter: jdbcpostgresql
|
27
30
|
database: arext_test
|
28
31
|
username: postgres
|
32
|
+
password: secret
|
33
|
+
host: 127.0.0.1
|
34
|
+
port: 5432
|
29
35
|
oracle:
|
30
36
|
adapter: oracle_enhanced
|
31
37
|
database: xe
|
data/test/real_db_test.rb
CHANGED
@@ -8,7 +8,11 @@ require 'arel_extensions'
|
|
8
8
|
def setup_db
|
9
9
|
ActiveRecord::Base.configurations = YAML.load_file('test/database.yml')
|
10
10
|
ActiveRecord::Base.establish_connection(ENV['DB'].try(:to_sym) || (RUBY_PLATFORM == 'java' ? :"jdbc-sqlite" : :sqlite))
|
11
|
-
ActiveRecord::
|
11
|
+
if ActiveRecord::VERSION::MAJOR >= 7
|
12
|
+
ActiveRecord.default_timezone = :utc
|
13
|
+
else
|
14
|
+
ActiveRecord::Base.default_timezone = :utc
|
15
|
+
end
|
12
16
|
@cnx = ActiveRecord::Base.connection
|
13
17
|
if ActiveRecord::Base.connection.adapter_name =~ /sqlite/i
|
14
18
|
$sqlite = true
|
data/test/support/fake_record.rb
CHANGED
@@ -105,7 +105,7 @@ module FakeRecord
|
|
105
105
|
attr_reader :spec, :connection
|
106
106
|
|
107
107
|
def initialize
|
108
|
-
@spec = Spec.new(:adapter => 'america')
|
108
|
+
@spec = Spec.new({:adapter => 'america'})
|
109
109
|
@connection = Connection.new
|
110
110
|
@connection.visitor = Arel::Visitors::ToSql.new(connection)
|
111
111
|
end
|
@@ -5,6 +5,27 @@ module ArelExtensions
|
|
5
5
|
module VisitorToSql
|
6
6
|
describe 'the to_sql visitor' do
|
7
7
|
before do
|
8
|
+
if Arel::Table.engine.is_a?(ActiveRecord::Base)
|
9
|
+
puts "This is a hack."
|
10
|
+
# As a matter of fact, if the whole if-block is removed, the to_sql
|
11
|
+
# test become flaky.
|
12
|
+
#
|
13
|
+
# The first time `Arel::Table.engine` is called
|
14
|
+
# from `ArelExtenstions::column_of_via_arel_table(table_name, column_name)`
|
15
|
+
# in `lib/arel_extensions/helpers.rb`
|
16
|
+
# will almost always fail. It's important to note that when the test
|
17
|
+
# fails, it's always on 1 test case, and every subsequent test that
|
18
|
+
# calls to these methods passes.
|
19
|
+
#
|
20
|
+
# After investigation, it turned out that `Arel::Table.engine` will be
|
21
|
+
# of type `ActiveRecord::Base` instead of the expected `FakeRecord::Base`
|
22
|
+
# as set in this `before` block, in the `@conn` instance variable.
|
23
|
+
# Subsequent calls to `column_of_via_arel_table` will have
|
24
|
+
# `Arel::Table.engine` of the expected type.
|
25
|
+
#
|
26
|
+
# It is still unclear why the call in the condition of this if-block
|
27
|
+
# fixes this behavior.
|
28
|
+
end
|
8
29
|
@conn = FakeRecord::Base.new
|
9
30
|
Arel::Table.engine = @conn
|
10
31
|
@visitor = Arel::Visitors::ToSql.new @conn.connection
|
@@ -282,16 +303,23 @@ module ArelExtensions
|
|
282
303
|
.must_be_like %{CASE "users"."name" WHEN 'smith' THEN 'cool' ELSE 'uncool' END ILIKE 'value'}
|
283
304
|
end
|
284
305
|
|
285
|
-
it "should be possible to use as on anything" do
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
.
|
306
|
+
it "should be possible to use as/xas on anything" do
|
307
|
+
{
|
308
|
+
@table[:name] => %{"users"."name" AS alias},
|
309
|
+
@table[:name].concat(' test') => %{CONCAT("users"."name", ' test') AS alias},
|
310
|
+
(@table[:name] + ' test') => %{CONCAT("users"."name", ' test') AS alias},
|
311
|
+
(@table[:age] + 42) => %{("users"."age" + 42) AS alias},
|
312
|
+
@table[:name].coalesce('') => %{COALESCE("users"."name", '') AS alias},
|
313
|
+
Arel::Nodes.build_quoted('test') => %{'test' AS alias},
|
314
|
+
@table.project(@table[:name]) => %{(SELECT "users"."name" FROM "users") "alias"},
|
315
|
+
@table[:name].when("smith").then("cool").else("uncool") => %{CASE "users"."name" WHEN 'smith' THEN 'cool' ELSE 'uncool' END AS alias},
|
316
|
+
}.each do |exp, res|
|
317
|
+
_(compile(exp.as('alias'))).must_be_like res
|
318
|
+
_(compile(exp.xas('alias'))).must_be_like res
|
319
|
+
|
320
|
+
res_no_alias = res.gsub(/\s*(?:AS alias|"alias")\s*\z/, '')
|
321
|
+
_(compile(exp.xas(nil))).must_be_like res_no_alias
|
322
|
+
end
|
295
323
|
end
|
296
324
|
|
297
325
|
it "should accept comparators on functions" do
|
@@ -373,7 +401,7 @@ module ArelExtensions
|
|
373
401
|
end
|
374
402
|
|
375
403
|
it "should respecting Grouping" do
|
376
|
-
g = ->(*v) { Arel
|
404
|
+
g = ->(*v) { Arel.grouping(v) }
|
377
405
|
_(compile(g[@table[:id], @table[:age]].in [g[1, 42]]))
|
378
406
|
.must_be_like %{("users"."id", "users"."age") IN ((1, 42))}
|
379
407
|
_(compile(g[@table[:id], @table[:age]].in [g[1, 42], g[2, 51]]))
|
@@ -2,7 +2,7 @@ require 'arelx_test_helper'
|
|
2
2
|
require 'date'
|
3
3
|
|
4
4
|
module ArelExtensions
|
5
|
-
module
|
5
|
+
module WithAr
|
6
6
|
class ListTest < Minitest::Test
|
7
7
|
require 'minitest/pride'
|
8
8
|
def connect_db
|
@@ -14,7 +14,11 @@ module ArelExtensions
|
|
14
14
|
@env_db = ENV['DB']
|
15
15
|
end
|
16
16
|
ActiveRecord::Base.establish_connection(@env_db.try(:to_sym) || (RUBY_PLATFORM == 'java' ? :"jdbc-sqlite" : :sqlite))
|
17
|
-
ActiveRecord::
|
17
|
+
if ActiveRecord::VERSION::MAJOR >= 7
|
18
|
+
ActiveRecord.default_timezone = :utc
|
19
|
+
else
|
20
|
+
ActiveRecord::Base.default_timezone = :utc
|
21
|
+
end
|
18
22
|
@cnx = ActiveRecord::Base.connection
|
19
23
|
$sqlite = @cnx.adapter_name =~ /sqlite/i
|
20
24
|
$load_extension_disabled ||= false
|
@@ -29,7 +33,7 @@ module ArelExtensions
|
|
29
33
|
t.column :name, :string
|
30
34
|
t.column :comments, :text
|
31
35
|
t.column :created_at, :date
|
32
|
-
t.column :updated_at, :datetime
|
36
|
+
t.column :updated_at, :datetime, precision: nil
|
33
37
|
t.column :duration, :time
|
34
38
|
t.column :other, :string
|
35
39
|
t.column :score, :decimal, :precision => 20, :scale => 10
|
@@ -166,6 +170,12 @@ module ArelExtensions
|
|
166
170
|
# Since Arel10 (Rails6.1), some unwanted behaviors on aggregated calculation were present.
|
167
171
|
# This should works no matter which version of rails is used
|
168
172
|
assert User.group(:score).average(:id).values.all?{|e| !e.nil?}
|
173
|
+
|
174
|
+
# Since Rails 7, a patch to calculations.rb has tirggered a double
|
175
|
+
# quoting of the alias name. See https://github.com/rails/rails/commit/7e6e9091e55c3357b0162d44b6ab955ed0c718d5
|
176
|
+
# Before the patch that fixed this the following error would occur:
|
177
|
+
# ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: zero-length delimited identifier at or near """"
|
178
|
+
assert User.group(:score).count(:id).values.all?{|e| !e.nil?}
|
169
179
|
end
|
170
180
|
|
171
181
|
# String Functions
|
@@ -358,9 +368,70 @@ module ArelExtensions
|
|
358
368
|
|
359
369
|
def test_format
|
360
370
|
assert_equal '2016-05-23', t(@lucas, @created_at.format('%Y-%m-%d'))
|
361
|
-
skip "SQL Server does not accept any format" if @env_db == 'mssql'
|
362
371
|
assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S'))
|
363
372
|
assert_equal '12:42%', t(@lucas, @updated_at.format('%R%%'))
|
373
|
+
|
374
|
+
# The following tests will ensure proper conversion of timestamps to
|
375
|
+
# requested timezones.
|
376
|
+
#
|
377
|
+
# The names of the timezones is highly dependant on the underlying
|
378
|
+
# operating system, and this is why we need to handle each database
|
379
|
+
# separately: the images we're using to test these databases are
|
380
|
+
# different. So don't rely on the provided examples. Your setup is your
|
381
|
+
# reference.
|
382
|
+
#
|
383
|
+
# One could always have portable code if s/he uses standard
|
384
|
+
# abbreviations, like:
|
385
|
+
#
|
386
|
+
# 1. CET => Central European Time
|
387
|
+
# 2. CEST => Central European Summer Time
|
388
|
+
#
|
389
|
+
# Which implies that the caller should handle daylight saving detection.
|
390
|
+
# In fact, CET will handle daylight saving in MySQL but not Postgres.
|
391
|
+
#
|
392
|
+
# It looks like the posix convention is supported by mysql and
|
393
|
+
# postgresql, e.g.:
|
394
|
+
#
|
395
|
+
# posix/Europe/Paris
|
396
|
+
# posix/America/Nipigon
|
397
|
+
#
|
398
|
+
# so it looks like a more reliably portable way of specifying it.
|
399
|
+
time_zones = {
|
400
|
+
'mssql' => {
|
401
|
+
'utc' => 'UTC',
|
402
|
+
'sao_paulo' => 'Argentina Standard Time',
|
403
|
+
'tahiti' => 'Hawaiian Standard Time',
|
404
|
+
'paris' => 'Central European Standard Time'
|
405
|
+
},
|
406
|
+
'mysql' => {
|
407
|
+
'utc' => 'UTC',
|
408
|
+
'sao_paulo' => 'America/Sao_Paulo',
|
409
|
+
'tahiti' => 'Pacific/Tahiti',
|
410
|
+
'paris' => 'Europe/Paris'
|
411
|
+
},
|
412
|
+
'oracle' => {
|
413
|
+
'utc' => 'UTC',
|
414
|
+
'sao_paulo' => 'America/Sao_Paulo',
|
415
|
+
'tahiti' => 'Pacific/Tahiti',
|
416
|
+
'paris' => 'Europe/Paris'
|
417
|
+
},
|
418
|
+
'postgresql' => {
|
419
|
+
'utc' => 'UTC',
|
420
|
+
'sao_paulo' => 'America/Sao Paulo (-03)',
|
421
|
+
'tahiti' => 'Pacific/Tahiti (-10)',
|
422
|
+
'paris' => 'Europe/Paris'
|
423
|
+
},
|
424
|
+
}
|
425
|
+
|
426
|
+
tz = time_zones[ENV['DB']]
|
427
|
+
skip "Unsupported timezone conversion for DB=#{ENV['DB']}" if tz.nil?
|
428
|
+
assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', tz['utc']))
|
429
|
+
assert_equal '2014/03/03 09:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', tz['sao_paulo']))
|
430
|
+
assert_equal '2014/03/03 02:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S', tz['tahiti']))
|
431
|
+
|
432
|
+
# Winter/Summer time
|
433
|
+
assert_equal '2022/02/01 11:42:00', t(@lucas, Arel::Nodes.build_quoted('2022-02-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', tz['paris']))
|
434
|
+
assert_equal '2022/08/01 12:42:00', t(@lucas, Arel::Nodes.build_quoted('2022-08-01 10:42:00').cast(:datetime).format('%Y/%m/%d %H:%M:%S', tz['paris']))
|
364
435
|
end
|
365
436
|
|
366
437
|
def test_coalesce
|
@@ -500,7 +571,8 @@ module ArelExtensions
|
|
500
571
|
assert_equal Time, t(@lucas,@updated_at.cast(:string).cast(:datetime)).class
|
501
572
|
assert_equal Time, t(@lucas,@updated_at.cast(:time)).class
|
502
573
|
|
503
|
-
|
574
|
+
# mysql adapter in rails7 adds some infos we just squeeze here
|
575
|
+
assert_equal "2014-03-03 12:42:00", t(@lucas,@updated_at.cast(:string)).split('.').first unless @env_db == 'mssql' # locale dependent
|
504
576
|
assert_equal Date.parse("2014-03-03"), t(@lucas,Arel::Nodes.build_quoted('2014-03-03').cast(:date))
|
505
577
|
assert_equal Date.parse("5014-03-03"), t(@lucas,(@age.cast(:string) + '014-03-03').cast(:date))
|
506
578
|
assert_equal Time.parse("2014-03-03 12:42:00 UTC"), t(@lucas,@updated_at.cast(:string).cast(:datetime))
|
@@ -515,7 +587,7 @@ module ArelExtensions
|
|
515
587
|
# puts @age.is_null.inspect
|
516
588
|
# puts @age.is_null.to_sql
|
517
589
|
# puts @age=='34'
|
518
|
-
assert_equal "Test", User.select(@name).where(@age.is_null
|
590
|
+
assert_equal "Test", User.select(@name).where(@age.is_null).first.name
|
519
591
|
end
|
520
592
|
|
521
593
|
def test_math_plus
|
@@ -663,6 +735,7 @@ module ArelExtensions
|
|
663
735
|
end
|
664
736
|
|
665
737
|
def test_subquery_with_order
|
738
|
+
skip if ['mssql'].include?(@env_db) && Arel::VERSION.to_i < 10
|
666
739
|
assert_equal 9, User.where(:name => User.select(:name).order(:name)).count
|
667
740
|
assert_equal 9, User.where(@ut[:name].in(@ut.project(@ut[:name]).order(@ut[:name]))).count
|
668
741
|
if !['mysql'].include?(@env_db) # MySql can't have limit in IN subquery
|
@@ -2,7 +2,7 @@ require 'arelx_test_helper'
|
|
2
2
|
require 'date'
|
3
3
|
|
4
4
|
module ArelExtensions
|
5
|
-
module
|
5
|
+
module WithAr
|
6
6
|
class InsertManagerTest < Minitest::Test
|
7
7
|
def setup_db
|
8
8
|
ActiveRecord::Base.configurations = YAML.load_file('test/database.yml')
|
@@ -13,7 +13,11 @@ module ArelExtensions
|
|
13
13
|
@env_db = ENV['DB']
|
14
14
|
end
|
15
15
|
ActiveRecord::Base.establish_connection(@env_db.try(:to_sym) || (RUBY_PLATFORM == 'java' ? :"jdbc-sqlite" : :sqlite))
|
16
|
-
ActiveRecord::
|
16
|
+
if ActiveRecord::VERSION::MAJOR >= 7
|
17
|
+
ActiveRecord.default_timezone = :utc
|
18
|
+
else
|
19
|
+
ActiveRecord::Base.default_timezone = :utc
|
20
|
+
end
|
17
21
|
@cnx = ActiveRecord::Base.connection
|
18
22
|
Arel::Table.engine = ActiveRecord::Base
|
19
23
|
if File.exist?("init/#{@env_db}.sql")
|
@@ -1,12 +1,16 @@
|
|
1
1
|
require 'arelx_test_helper'
|
2
2
|
|
3
3
|
module ArelExtensions
|
4
|
-
module
|
4
|
+
module WithAr
|
5
5
|
describe 'the sqlite visitor' do
|
6
6
|
before do
|
7
7
|
ActiveRecord::Base.configurations = YAML.load_file('test/database.yml')
|
8
8
|
ActiveRecord::Base.establish_connection(ENV['DB'] || (RUBY_PLATFORM == 'java' ? :"jdbc-sqlite" : :sqlite))
|
9
|
-
ActiveRecord::
|
9
|
+
if ActiveRecord::VERSION::MAJOR >= 7
|
10
|
+
ActiveRecord.default_timezone = :utc
|
11
|
+
else
|
12
|
+
ActiveRecord::Base.default_timezone = :utc
|
13
|
+
end
|
10
14
|
@cnx = ActiveRecord::Base.connection
|
11
15
|
Arel::Table.engine = ActiveRecord::Base
|
12
16
|
@cnx.drop_table(:users) rescue nil
|
@@ -1,12 +1,16 @@
|
|
1
1
|
require 'arelx_test_helper'
|
2
2
|
|
3
3
|
module ArelExtensions
|
4
|
-
module
|
4
|
+
module WithAr
|
5
5
|
describe 'the sqlite visitor can do maths' do
|
6
6
|
before do
|
7
7
|
ActiveRecord::Base.configurations = YAML.load_file('test/database.yml')
|
8
8
|
ActiveRecord::Base.establish_connection(ENV['DB'] || (RUBY_PLATFORM == 'java' ? :"jdbc-sqlite" : :sqlite))
|
9
|
-
ActiveRecord::
|
9
|
+
if ActiveRecord::VERSION::MAJOR >= 7
|
10
|
+
ActiveRecord.default_timezone = :utc
|
11
|
+
else
|
12
|
+
ActiveRecord::Base.default_timezone = :utc
|
13
|
+
end
|
10
14
|
Arel::Table.engine = ActiveRecord::Base
|
11
15
|
@cnx = ActiveRecord::Base.connection
|
12
16
|
@cnx.drop_table(:users) rescue nil
|
@@ -2,12 +2,16 @@ require 'arelx_test_helper'
|
|
2
2
|
require 'date'
|
3
3
|
|
4
4
|
module ArelExtensions
|
5
|
-
module
|
5
|
+
module WithAr
|
6
6
|
describe 'the mysql visitor can do string operations' do
|
7
7
|
before do
|
8
8
|
ActiveRecord::Base.configurations = YAML.load_file('test/database.yml')
|
9
9
|
ActiveRecord::Base.establish_connection(ENV['DB'] || (RUBY_PLATFORM == 'java' ? :"jdbc-mysql" : :mysql))
|
10
|
-
ActiveRecord::
|
10
|
+
if ActiveRecord::VERSION::MAJOR >= 7
|
11
|
+
ActiveRecord.default_timezone = :utc
|
12
|
+
else
|
13
|
+
ActiveRecord::Base.default_timezone = :utc
|
14
|
+
end
|
11
15
|
begin
|
12
16
|
@cnx = ActiveRecord::Base.connection
|
13
17
|
rescue => e
|
@@ -2,12 +2,16 @@ require 'arelx_test_helper'
|
|
2
2
|
require 'date'
|
3
3
|
|
4
4
|
module ArelExtensions
|
5
|
-
module
|
5
|
+
module WithAr
|
6
6
|
describe 'the sqlite visitor can do string operations' do
|
7
7
|
before do
|
8
8
|
ActiveRecord::Base.configurations = YAML.load_file('test/database.yml')
|
9
9
|
ActiveRecord::Base.establish_connection(ENV['DB'] || (RUBY_PLATFORM == 'java' ? :"jdbc-sqlite" : :sqlite))
|
10
|
-
ActiveRecord::
|
10
|
+
if ActiveRecord::VERSION::MAJOR >= 7
|
11
|
+
ActiveRecord.default_timezone = :utc
|
12
|
+
else
|
13
|
+
ActiveRecord::Base.default_timezone = :utc
|
14
|
+
end
|
11
15
|
@cnx = ActiveRecord::Base.connection
|
12
16
|
Arel::Table.engine = ActiveRecord::Base
|
13
17
|
@cnx.drop_table(:users) rescue nil
|
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.
|
4
|
+
version: 1.3.1
|
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: 2022-03-03 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: arel
|
@@ -44,16 +44,16 @@ dependencies:
|
|
44
44
|
name: rdoc
|
45
45
|
requirement: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
|
-
- - "
|
47
|
+
- - ">="
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version:
|
49
|
+
version: 6.3.1
|
50
50
|
type: :development
|
51
51
|
prerelease: false
|
52
52
|
version_requirements: !ruby/object:Gem::Requirement
|
53
53
|
requirements:
|
54
|
-
- - "
|
54
|
+
- - ">="
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version:
|
56
|
+
version: 6.3.1
|
57
57
|
- !ruby/object:Gem::Dependency
|
58
58
|
name: rake
|
59
59
|
requirement: !ruby/object:Gem::Requirement
|
@@ -97,7 +97,6 @@ files:
|
|
97
97
|
- Rakefile
|
98
98
|
- SQL_Challenges.md
|
99
99
|
- TODO
|
100
|
-
- appveyor.yml
|
101
100
|
- arel_extensions.gemspec
|
102
101
|
- functions.html
|
103
102
|
- gemfiles/rails3.gemfile
|
@@ -107,6 +106,7 @@ files:
|
|
107
106
|
- gemfiles/rails5_2.gemfile
|
108
107
|
- gemfiles/rails6.gemfile
|
109
108
|
- gemfiles/rails6_1.gemfile
|
109
|
+
- gemfiles/rails7.gemfile
|
110
110
|
- gemspecs/arel_extensions-v1.gemspec
|
111
111
|
- gemspecs/arel_extensions-v2.gemspec
|
112
112
|
- generate_gems.sh
|
@@ -116,11 +116,13 @@ files:
|
|
116
116
|
- init/postgresql.sql
|
117
117
|
- init/sqlite.sql
|
118
118
|
- lib/arel_extensions.rb
|
119
|
+
- lib/arel_extensions/aliases.rb
|
119
120
|
- lib/arel_extensions/attributes.rb
|
120
121
|
- lib/arel_extensions/boolean_functions.rb
|
121
122
|
- lib/arel_extensions/common_sql_functions.rb
|
122
123
|
- lib/arel_extensions/comparators.rb
|
123
124
|
- lib/arel_extensions/date_duration.rb
|
125
|
+
- lib/arel_extensions/helpers.rb
|
124
126
|
- lib/arel_extensions/insert_manager.rb
|
125
127
|
- lib/arel_extensions/math.rb
|
126
128
|
- lib/arel_extensions/math_functions.rb
|
@@ -222,7 +224,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
222
224
|
- !ruby/object:Gem::Version
|
223
225
|
version: '0'
|
224
226
|
requirements: []
|
225
|
-
rubygems_version: 3.
|
227
|
+
rubygems_version: 3.2.3
|
226
228
|
signing_key:
|
227
229
|
specification_version: 4
|
228
230
|
summary: Extending Arel
|