activerecord-sqlserver-adapter 4.2.18 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -223
- data/Gemfile +18 -17
- data/RAILS5-TODO.md +36 -0
- data/README.md +27 -8
- data/RUNNING_UNIT_TESTS.md +0 -17
- data/Rakefile +2 -7
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +1 -1
- data/appveyor.yml +0 -2
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +15 -8
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +45 -97
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +1 -2
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +31 -10
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +0 -18
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +101 -58
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +7 -7
- data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +56 -32
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/type.rb +34 -32
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +6 -0
- data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +3 -0
- data/lib/active_record/connection_adapters/sqlserver/type/char.rb +9 -20
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +30 -0
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +28 -4
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +28 -14
- data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +4 -16
- data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +9 -0
- data/lib/active_record/connection_adapters/sqlserver/type/float.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +3 -0
- data/lib/active_record/connection_adapters/sqlserver/type/money.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/type/real.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +8 -1
- data/lib/active_record/connection_adapters/sqlserver/type/text.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +20 -8
- data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +25 -10
- data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +3 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +6 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +7 -1
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +15 -2
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +7 -1
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +7 -1
- data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +10 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +71 -57
- data/lib/active_record/connection_adapters/sqlserver_column.rb +5 -30
- data/lib/active_record/sqlserver_base.rb +1 -5
- data/lib/arel/visitors/sqlserver.rb +11 -20
- data/test/bin/setup.sh +4 -6
- data/test/cases/adapter_test_sqlserver.rb +11 -20
- data/test/cases/coerced_tests.rb +233 -138
- data/test/cases/column_test_sqlserver.rb +244 -227
- data/test/cases/connection_test_sqlserver.rb +5 -76
- data/test/cases/fully_qualified_identifier_test_sqlserver.rb +7 -7
- data/test/cases/helper_sqlserver.rb +4 -15
- data/test/cases/pessimistic_locking_test_sqlserver.rb +1 -1
- data/test/cases/rake_test_sqlserver.rb +20 -14
- data/test/cases/schema_dumper_test_sqlserver.rb +94 -63
- data/test/cases/schema_test_sqlserver.rb +2 -2
- data/test/cases/showplan_test_sqlserver.rb +1 -1
- data/test/cases/specific_schema_test_sqlserver.rb +7 -14
- data/test/cases/transaction_test_sqlserver.rb +1 -1
- data/test/cases/uuid_test_sqlserver.rb +0 -1
- data/test/config.yml +0 -10
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +1 -1
- data/test/schema/sqlserver_specific_schema.rb +0 -16
- data/test/support/coerceable_test_sqlserver.rb +6 -2
- data/test/support/connection_reflection.rb +0 -4
- data/test/support/sql_counter_sqlserver.rb +17 -21
- metadata +9 -7
- data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +0 -34
- data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +0 -114
@@ -2,22 +2,9 @@ module ActiveRecord
|
|
2
2
|
module ConnectionAdapters
|
3
3
|
class SQLServerColumn < Column
|
4
4
|
|
5
|
-
def initialize(name, default,
|
6
|
-
|
7
|
-
|
8
|
-
@default_function = @sqlserver_options[:default_function]
|
9
|
-
end
|
10
|
-
|
11
|
-
def sql_type_for_statement
|
12
|
-
if is_integer? || is_real?
|
13
|
-
sql_type.sub(/\((\d+)?\)/, '')
|
14
|
-
else
|
15
|
-
sql_type
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def table_name
|
20
|
-
@sqlserver_options[:table_name]
|
5
|
+
def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment = nil, sqlserver_options = {})
|
6
|
+
@sqlserver_options = sqlserver_options || {}
|
7
|
+
super(name, default, sql_type_metadata, null, table_name, default_function, collation, comment: comment)
|
21
8
|
end
|
22
9
|
|
23
10
|
def is_identity?
|
@@ -29,23 +16,11 @@ module ActiveRecord
|
|
29
16
|
end
|
30
17
|
|
31
18
|
def is_utf8?
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
def is_integer?
|
36
|
-
@sql_type =~ /int/i
|
37
|
-
end
|
38
|
-
|
39
|
-
def is_real?
|
40
|
-
@sql_type =~ /real/i
|
41
|
-
end
|
42
|
-
|
43
|
-
def collation
|
44
|
-
@sqlserver_options[:collation]
|
19
|
+
sql_type =~ /nvarchar|ntext|nchar/i
|
45
20
|
end
|
46
21
|
|
47
22
|
def case_sensitive?
|
48
|
-
collation &&
|
23
|
+
collation && collation.match(/_CS/)
|
49
24
|
end
|
50
25
|
|
51
26
|
end
|
@@ -7,14 +7,10 @@ module ActiveRecord
|
|
7
7
|
case mode
|
8
8
|
when :dblib
|
9
9
|
require 'tiny_tds'
|
10
|
-
when :odbc
|
11
|
-
raise ArgumentError, 'Missing :dsn configuration.' unless config.key?(:dsn)
|
12
|
-
require 'odbc'
|
13
|
-
require 'active_record/connection_adapters/sqlserver/core_ext/odbc'
|
14
10
|
else
|
15
11
|
raise ArgumentError, "Unknown connection mode in #{config.inspect}."
|
16
12
|
end
|
17
|
-
ConnectionAdapters::SQLServerAdapter.new(nil,
|
13
|
+
ConnectionAdapters::SQLServerAdapter.new(nil, nil, config.merge(mode: mode))
|
18
14
|
end
|
19
15
|
end
|
20
16
|
end
|
@@ -19,11 +19,7 @@ module Arel
|
|
19
19
|
|
20
20
|
def visit_Arel_Nodes_Bin o, collector
|
21
21
|
visit o.expr, collector
|
22
|
-
|
23
|
-
collector
|
24
|
-
else
|
25
|
-
collector << " #{ActiveRecord::ConnectionAdapters::SQLServerAdapter.cs_equality_operator} "
|
26
|
-
end
|
22
|
+
collector << " #{ActiveRecord::ConnectionAdapters::SQLServerAdapter.cs_equality_operator} "
|
27
23
|
end
|
28
24
|
|
29
25
|
def visit_Arel_Nodes_UpdateStatement(o, a)
|
@@ -77,9 +73,13 @@ module Arel
|
|
77
73
|
# Apparently, o.engine.connection can actually be a different adapter
|
78
74
|
# than sqlserver. Can be removed if fixed in ActiveRecord. See:
|
79
75
|
# github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/450
|
80
|
-
table_name =
|
81
|
-
|
82
|
-
|
76
|
+
table_name = begin
|
77
|
+
if o.class.engine.connection.respond_to?(:sqlserver?) && o.class.engine.connection.database_prefix_remote_server?
|
78
|
+
remote_server_table_name(o)
|
79
|
+
else
|
80
|
+
quote_table_name(o.name)
|
81
|
+
end
|
82
|
+
rescue Exception => e
|
83
83
|
quote_table_name(o.name)
|
84
84
|
end
|
85
85
|
if o.table_alias
|
@@ -170,7 +170,7 @@ module Arel
|
|
170
170
|
core = o.cores.first
|
171
171
|
distinct = Nodes::Distinct === core.set_quantifier
|
172
172
|
oneasone = core.projections.all? { |x| x == ActiveRecord::FinderMethods::ONE_AS_ONE }
|
173
|
-
limitone = node_value(o.limit)
|
173
|
+
limitone = [nil, 0, 1].include? node_value(o.limit)
|
174
174
|
if distinct && oneasone && limitone && !o.offset
|
175
175
|
core.projections = [Arel.sql("TOP(1) 1 AS [one]")]
|
176
176
|
o.limit = nil
|
@@ -190,25 +190,16 @@ module Arel
|
|
190
190
|
|
191
191
|
def primary_Key_From_Table t
|
192
192
|
return unless t
|
193
|
-
|
194
|
-
if engine_pk = t.engine.primary_key
|
195
|
-
pk = t.engine.arel_table[engine_pk]
|
196
|
-
return pk if pk
|
197
|
-
end
|
198
|
-
pk = t.engine.connection.schema_cache.primary_keys(t.engine.table_name)
|
199
|
-
return pk if pk
|
200
|
-
column_name = t.engine.columns.first.try(:name)
|
193
|
+
column_name = schema_cache.primary_keys(t.name) || column_cache(t.name).first.try(:second).try(:name)
|
201
194
|
column_name ? t[column_name] : nil
|
202
195
|
end
|
203
196
|
|
204
197
|
def remote_server_table_name o
|
205
198
|
ActiveRecord::ConnectionAdapters::SQLServer::Utils.extract_identifiers(
|
206
|
-
"#{o.engine.connection.database_prefix}#{o.name}"
|
199
|
+
"#{o.class.engine.connection.database_prefix}#{o.name}"
|
207
200
|
).quoted
|
208
201
|
end
|
209
202
|
|
210
203
|
end
|
211
204
|
end
|
212
205
|
end
|
213
|
-
|
214
|
-
Arel::Visitors::VISITORS['sqlserver'] = Arel::Visitors::SQLServer
|
data/test/bin/setup.sh
CHANGED
@@ -3,17 +3,15 @@
|
|
3
3
|
set -x
|
4
4
|
set -e
|
5
5
|
|
6
|
-
|
6
|
+
docker pull metaskills/mssql-server-linux-rails
|
7
7
|
|
8
|
-
docker
|
9
|
-
|
10
|
-
container=$(docker ps -a -q --filter ancestor=metaskills/mssql-server-linux-rails:$tag)
|
8
|
+
container=$(docker ps -a -q --filter ancestor=metaskills/mssql-server-linux-rails)
|
11
9
|
if [[ -z $container ]]; then
|
12
|
-
docker run -p 1433:1433 -d metaskills/mssql-server-linux-rails
|
10
|
+
docker run -p 1433:1433 -d metaskills/mssql-server-linux-rails && sleep 10
|
13
11
|
exit
|
14
12
|
fi
|
15
13
|
|
16
|
-
container=$(docker ps -q --filter ancestor=metaskills/mssql-server-linux-rails
|
14
|
+
container=$(docker ps -q --filter ancestor=metaskills/mssql-server-linux-rails)
|
17
15
|
if [[ -z $container ]]; then
|
18
16
|
docker start $container && sleep 10
|
19
17
|
fi
|
@@ -17,7 +17,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
17
17
|
string = connection.inspect
|
18
18
|
string.must_match %r{ActiveRecord::ConnectionAdapters::SQLServerAdapter}
|
19
19
|
string.must_match %r{version\: \d.\d}
|
20
|
-
string.must_match %r{mode:
|
20
|
+
string.must_match %r{mode: dblib}
|
21
21
|
string.must_match %r{azure: (true|false)}
|
22
22
|
string.wont_match %r{host}
|
23
23
|
string.wont_match %r{password}
|
@@ -96,7 +96,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
96
96
|
connection.send :initialize_dateformatter
|
97
97
|
assert_nothing_raised do
|
98
98
|
starting = Time.utc(2000, 1, 31, 5, 42, 0)
|
99
|
-
ending =
|
99
|
+
ending = Time.new(2006, 12, 31)
|
100
100
|
Task.create! starting: starting, ending: ending
|
101
101
|
end
|
102
102
|
end
|
@@ -158,14 +158,14 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
158
158
|
end
|
159
159
|
end
|
160
160
|
|
161
|
-
it 'find identity column using #
|
161
|
+
it 'find identity column using #identity_columns' do
|
162
162
|
task_id_column = Task.columns_hash['id']
|
163
|
-
assert_equal task_id_column.name, connection.send(:
|
164
|
-
assert_equal task_id_column.sql_type, connection.send(:
|
163
|
+
assert_equal task_id_column.name, connection.send(:identity_columns, Task.table_name).first.name
|
164
|
+
assert_equal task_id_column.sql_type, connection.send(:identity_columns, Task.table_name).first.sql_type
|
165
165
|
end
|
166
166
|
|
167
|
-
it 'return
|
168
|
-
|
167
|
+
it 'return an empty array when calling #identity_columns for a table_name with no identity' do
|
168
|
+
connection.send(:identity_columns, Subscriber.table_name).must_equal []
|
169
169
|
end
|
170
170
|
|
171
171
|
end
|
@@ -364,8 +364,8 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
364
364
|
assert_equal 0, SSTestCustomersView.new.balance
|
365
365
|
end
|
366
366
|
|
367
|
-
it 'respond true to
|
368
|
-
assert SSTestCustomersView.
|
367
|
+
it 'respond true to data_source_exists?' do
|
368
|
+
assert SSTestCustomersView.connection.data_source_exists?(SSTestCustomersView.table_name)
|
369
369
|
end
|
370
370
|
|
371
371
|
# With aliased column names
|
@@ -392,17 +392,8 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
392
392
|
SSTestStringDefaultsView.columns_hash['pretend_null'].inspect
|
393
393
|
end
|
394
394
|
|
395
|
-
it 'respond true to
|
396
|
-
assert SSTestStringDefaultsView.
|
397
|
-
end
|
398
|
-
|
399
|
-
# Doing identity inserts
|
400
|
-
|
401
|
-
it 'be able to do an identity insert' do
|
402
|
-
customer = SSTestCustomersView.new
|
403
|
-
customer.id = 420
|
404
|
-
customer.save!
|
405
|
-
assert SSTestCustomersView.find(420)
|
395
|
+
it 'respond true to data_source_exists?' do
|
396
|
+
assert SSTestStringDefaultsView.connection.data_source_exists?(SSTestStringDefaultsView.table_name)
|
406
397
|
end
|
407
398
|
|
408
399
|
# That have more than 4000 chars for their defintion
|
data/test/cases/coerced_tests.rb
CHANGED
@@ -1,30 +1,49 @@
|
|
1
1
|
require 'cases/helper_sqlserver'
|
2
2
|
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
|
5
|
+
require 'models/event'
|
6
|
+
class UniquenessValidationTest < ActiveRecord::TestCase
|
7
|
+
# So sp_executesql swallows this exception. Run without prpared to see it.
|
8
|
+
coerce_tests! :test_validate_uniqueness_with_limit
|
9
|
+
def test_validate_uniqueness_with_limit_coerced
|
10
|
+
connection.unprepared_statement do
|
11
|
+
assert_raise(ActiveRecord::ValueTooLong) do
|
12
|
+
Event.create(title: "abcdefgh")
|
13
|
+
end
|
14
|
+
end
|
14
15
|
end
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
|
17
|
+
# So sp_executesql swallows this exception. Run without prpared to see it.
|
18
|
+
coerce_tests! :test_validate_uniqueness_with_limit_and_utf8
|
19
|
+
def test_validate_uniqueness_with_limit_and_utf8_coerced
|
20
|
+
connection.unprepared_statement do
|
21
|
+
assert_raise(ActiveRecord::ValueTooLong) do
|
22
|
+
Event.create(title: "一二三四五六七八")
|
23
|
+
end
|
24
|
+
end
|
18
25
|
end
|
19
26
|
end
|
20
27
|
|
21
28
|
|
29
|
+
|
30
|
+
|
31
|
+
require 'models/event'
|
22
32
|
module ActiveRecord
|
23
33
|
class AdapterTest < ActiveRecord::TestCase
|
24
|
-
|
25
34
|
# As far as I can tell, SQL Server does not support null bytes in strings.
|
26
35
|
coerce_tests! :test_update_prepared_statement
|
27
36
|
|
37
|
+
# So sp_executesql swallows this exception. Run without prpared to see it.
|
38
|
+
coerce_tests! :test_value_limit_violations_are_translated_to_specific_exception
|
39
|
+
def test_value_limit_violations_are_translated_to_specific_exception_coerced
|
40
|
+
connection.unprepared_statement do
|
41
|
+
error = assert_raises(ActiveRecord::ValueTooLong) do
|
42
|
+
Event.create(title: 'abcdefgh')
|
43
|
+
end
|
44
|
+
assert_not_nil error.cause
|
45
|
+
end
|
46
|
+
end
|
28
47
|
end
|
29
48
|
end
|
30
49
|
|
@@ -33,7 +52,6 @@ end
|
|
33
52
|
|
34
53
|
require 'models/topic'
|
35
54
|
class AttributeMethodsTest < ActiveRecord::TestCase
|
36
|
-
|
37
55
|
coerce_tests! :test_typecast_attribute_from_select_to_false
|
38
56
|
def test_typecast_attribute_from_select_to_false_coerced
|
39
57
|
Topic.create(:title => 'Budget')
|
@@ -47,26 +65,19 @@ class AttributeMethodsTest < ActiveRecord::TestCase
|
|
47
65
|
topic = Topic.all.merge!(:select => "topics.*, IIF (1 = 1, 1, 0) as is_test").first
|
48
66
|
assert topic.is_test?
|
49
67
|
end
|
50
|
-
|
51
68
|
end
|
52
69
|
|
53
70
|
|
54
71
|
|
55
72
|
|
56
73
|
class BasicsTest < ActiveRecord::TestCase
|
57
|
-
|
58
74
|
coerce_tests! :test_column_names_are_escaped
|
59
75
|
def test_column_names_are_escaped_coerced
|
60
|
-
conn
|
61
|
-
|
62
|
-
badchar = "'"
|
63
|
-
quoted = conn.quote_column_name "foo#{badchar}bar"
|
64
|
-
assert_equal "[foo'bar]", quoted
|
76
|
+
conn = ActiveRecord::Base.connection
|
77
|
+
assert_equal '[t]]]', conn.quote_column_name('t]')
|
65
78
|
end
|
66
79
|
|
67
|
-
#
|
68
|
-
# This test has a few problems. First, it would require that we use the
|
69
|
-
# `Type::SQLServer::BigInteger.new(limit: 8)` for the `world_population` attribute.
|
80
|
+
# We do not have do the DecimalWithoutScale type.
|
70
81
|
coerce_tests! :test_numeric_fields
|
71
82
|
coerce_tests! :test_numeric_fields_with_scale
|
72
83
|
|
@@ -76,14 +87,12 @@ class BasicsTest < ActiveRecord::TestCase
|
|
76
87
|
# Caused in Rails v4.2.5 by adding `firm_id` column in this http://git.io/vBfMs
|
77
88
|
# commit. Trust Rails has this covered.
|
78
89
|
coerce_tests! :test_find_keeps_multiple_group_values
|
79
|
-
|
80
90
|
end
|
81
91
|
|
82
92
|
|
83
93
|
|
84
94
|
|
85
95
|
class BelongsToAssociationsTest < ActiveRecord::TestCase
|
86
|
-
|
87
96
|
# Since @client.firm is a single first/top, and we use FETCH the order clause is used.
|
88
97
|
coerce_tests! :test_belongs_to_does_not_use_order_by
|
89
98
|
|
@@ -93,7 +102,6 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
|
|
93
102
|
assert_no_match(/\[firm_with_primary_keys_companies\]\.\[id\]/, sql)
|
94
103
|
assert_match(/\[firm_with_primary_keys_companies\]\.\[name\]/, sql)
|
95
104
|
end
|
96
|
-
|
97
105
|
end
|
98
106
|
|
99
107
|
|
@@ -101,11 +109,8 @@ end
|
|
101
109
|
|
102
110
|
module ActiveRecord
|
103
111
|
class BindParameterTest < ActiveRecord::TestCase
|
104
|
-
|
105
112
|
# Never finds `sql` since we use `EXEC sp_executesql` wrappers.
|
106
|
-
coerce_tests! :test_binds_are_logged
|
107
|
-
:test_binds_are_logged_after_type_cast
|
108
|
-
|
113
|
+
coerce_tests! :test_binds_are_logged
|
109
114
|
end
|
110
115
|
end
|
111
116
|
|
@@ -113,7 +118,6 @@ end
|
|
113
118
|
|
114
119
|
|
115
120
|
class CalculationsTest < ActiveRecord::TestCase
|
116
|
-
|
117
121
|
# Are decimal, not integer.
|
118
122
|
coerce_tests! :test_should_return_decimal_average_of_integer_field
|
119
123
|
def test_should_return_decimal_average_of_integer_field_coerced
|
@@ -123,38 +127,34 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
123
127
|
|
124
128
|
coerce_tests! :test_limit_is_kept
|
125
129
|
def test_limit_is_kept_coerced
|
126
|
-
queries =
|
130
|
+
queries = capture_sql_ss { Account.limit(1).count }
|
127
131
|
assert_equal 1, queries.length
|
128
|
-
queries.first.must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET 0 ROWS FETCH NEXT
|
132
|
+
queries.first.must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.*@0 = 1}
|
129
133
|
end
|
130
134
|
|
131
135
|
coerce_tests! :test_limit_with_offset_is_kept
|
132
136
|
def test_limit_with_offset_is_kept_coerced
|
133
|
-
queries =
|
137
|
+
queries = capture_sql_ss { Account.limit(1).offset(1).count }
|
134
138
|
assert_equal 1, queries.length
|
135
|
-
queries.first.must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET
|
139
|
+
queries.first.must_match %r{ORDER BY \[accounts\]\.\[id\] ASC OFFSET @0 ROWS FETCH NEXT @1 ROWS ONLY.*@0 = 1, @1 = 1}
|
136
140
|
end
|
137
141
|
|
142
|
+
# Leave it up to users to format selects/functions so HAVING works correctly.
|
143
|
+
coerce_tests! :test_having_with_strong_parameters
|
138
144
|
end
|
139
145
|
|
140
146
|
|
141
147
|
|
142
|
-
|
143
148
|
module ActiveRecord
|
144
149
|
class Migration
|
145
150
|
class ChangeSchemaTest < ActiveRecord::TestCase
|
146
|
-
|
147
151
|
# We test these.
|
148
152
|
coerce_tests! :test_create_table_with_bigint,
|
149
153
|
:test_create_table_with_defaults
|
150
|
-
|
151
|
-
|
152
154
|
end
|
153
155
|
class ChangeSchemaWithDependentObjectsTest < ActiveRecord::TestCase
|
154
|
-
|
155
156
|
# In SQL Server you have to delete the tables yourself in the right order.
|
156
157
|
coerce_tests! :test_create_table_with_force_cascade_drops_dependent_objects
|
157
|
-
|
158
158
|
end
|
159
159
|
end
|
160
160
|
end
|
@@ -165,7 +165,6 @@ end
|
|
165
165
|
module ActiveRecord
|
166
166
|
class Migration
|
167
167
|
class ColumnAttributesTest < ActiveRecord::TestCase
|
168
|
-
|
169
168
|
# We have a default 4000 varying character limit.
|
170
169
|
coerce_tests! :test_add_column_without_limit
|
171
170
|
def test_add_column_without_limit_coerced
|
@@ -173,7 +172,6 @@ module ActiveRecord
|
|
173
172
|
TestModel.reset_column_information
|
174
173
|
TestModel.columns_hash["description"].limit.must_equal 4000
|
175
174
|
end
|
176
|
-
|
177
175
|
end
|
178
176
|
end
|
179
177
|
end
|
@@ -184,14 +182,14 @@ end
|
|
184
182
|
module ActiveRecord
|
185
183
|
class Migration
|
186
184
|
class ColumnsTest
|
187
|
-
|
188
|
-
# Our defaults are reall 70000 integers vs '70000' strings.
|
185
|
+
# Our defaults are real 70000 integers vs '70000' strings.
|
189
186
|
coerce_tests! :test_rename_column_preserves_default_value_not_null
|
190
187
|
def test_rename_column_preserves_default_value_not_null_coerced
|
191
188
|
add_column 'test_models', 'salary', :integer, :default => 70000
|
192
189
|
default_before = connection.columns("test_models").find { |c| c.name == "salary" }.default
|
193
190
|
assert_equal 70000, default_before
|
194
191
|
rename_column "test_models", "salary", "annual_salary"
|
192
|
+
TestModel.reset_column_information
|
195
193
|
assert TestModel.column_names.include?("annual_salary")
|
196
194
|
default_after = connection.columns("test_models").find { |c| c.name == "annual_salary" }.default
|
197
195
|
assert_equal 70000, default_after
|
@@ -208,6 +206,14 @@ module ActiveRecord
|
|
208
206
|
assert_equal [], connection.indexes('test_models').map(&:name)
|
209
207
|
end
|
210
208
|
|
209
|
+
# Choose `StatementInvalid` vs `ActiveRecordError`.
|
210
|
+
coerce_tests! :test_rename_nonexistent_column
|
211
|
+
def test_rename_nonexistent_column_coerced
|
212
|
+
exception = ActiveRecord::StatementInvalid
|
213
|
+
assert_raise(exception) do
|
214
|
+
rename_column "test_models", "nonexistent", "should_fail"
|
215
|
+
end
|
216
|
+
end
|
211
217
|
end
|
212
218
|
end
|
213
219
|
end
|
@@ -215,13 +221,53 @@ end
|
|
215
221
|
|
216
222
|
|
217
223
|
|
218
|
-
class
|
224
|
+
class MigrationTest < ActiveRecord::TestCase
|
225
|
+
# We do not have do the DecimalWithoutScale type.
|
226
|
+
coerce_tests! :test_add_table_with_decimals
|
227
|
+
def test_add_table_with_decimals_coerced
|
228
|
+
Person.connection.drop_table :big_numbers rescue nil
|
229
|
+
assert !BigNumber.table_exists?
|
230
|
+
GiveMeBigNumbers.up
|
231
|
+
BigNumber.reset_column_information
|
232
|
+
assert BigNumber.create(
|
233
|
+
:bank_balance => 1586.43,
|
234
|
+
:big_bank_balance => BigDecimal("1000234000567.95"),
|
235
|
+
:world_population => 6000000000,
|
236
|
+
:my_house_population => 3,
|
237
|
+
:value_of_e => BigDecimal("2.7182818284590452353602875")
|
238
|
+
)
|
239
|
+
b = BigNumber.first
|
240
|
+
assert_not_nil b
|
241
|
+
assert_not_nil b.bank_balance
|
242
|
+
assert_not_nil b.big_bank_balance
|
243
|
+
assert_not_nil b.world_population
|
244
|
+
assert_not_nil b.my_house_population
|
245
|
+
assert_not_nil b.value_of_e
|
246
|
+
assert_kind_of BigDecimal, b.world_population
|
247
|
+
assert_equal '6000000000.0', b.world_population.to_s
|
248
|
+
assert_kind_of Integer, b.my_house_population
|
249
|
+
assert_equal 3, b.my_house_population
|
250
|
+
assert_kind_of BigDecimal, b.bank_balance
|
251
|
+
assert_equal BigDecimal("1586.43"), b.bank_balance
|
252
|
+
assert_kind_of BigDecimal, b.big_bank_balance
|
253
|
+
assert_equal BigDecimal("1000234000567.95"), b.big_bank_balance
|
254
|
+
GiveMeBigNumbers.down
|
255
|
+
assert_raise(ActiveRecord::StatementInvalid) { BigNumber.first }
|
256
|
+
end
|
257
|
+
|
258
|
+
# For some reason our tests set Rails.@_env which breaks test env switching.
|
259
|
+
coerce_tests! :test_migration_sets_internal_metadata_even_when_fully_migrated
|
260
|
+
coerce_tests! :test_internal_metadata_stores_environment
|
261
|
+
end
|
262
|
+
|
263
|
+
|
219
264
|
|
265
|
+
|
266
|
+
class CoreTest < ActiveRecord::TestCase
|
220
267
|
# I think fixtures are useing the wrong time zone and the `:first`
|
221
268
|
# `topics`.`bonus_time` attribute of 2005-01-30t15:28:00.00+01:00 is
|
222
269
|
# getting local EST time for me and set to "09:28:00.0000000".
|
223
270
|
coerce_tests! :test_pretty_print_persisted
|
224
|
-
|
225
271
|
end
|
226
272
|
|
227
273
|
|
@@ -229,7 +275,6 @@ end
|
|
229
275
|
|
230
276
|
module ActiveRecord
|
231
277
|
module ConnectionAdapters
|
232
|
-
|
233
278
|
# Just like PostgreSQLAdapter does.
|
234
279
|
TypeLookupTest.coerce_all_tests! if defined?(TypeLookupTest)
|
235
280
|
|
@@ -237,7 +282,6 @@ module ActiveRecord
|
|
237
282
|
# a value of 'default_env' will still show tests failing. Just ignoring all
|
238
283
|
# of them since we have no monkey in this circus.
|
239
284
|
MergeAndResolveDefaultUrlConfigTest.coerce_all_tests! if defined?(MergeAndResolveDefaultUrlConfigTest)
|
240
|
-
|
241
285
|
end
|
242
286
|
end
|
243
287
|
|
@@ -259,10 +303,16 @@ end
|
|
259
303
|
|
260
304
|
|
261
305
|
class DefaultScopingTest < ActiveRecord::TestCase
|
262
|
-
|
263
306
|
# We are not doing order duplicate removal anymore.
|
264
307
|
coerce_tests! :test_order_in_default_scope_should_not_prevail
|
265
308
|
|
309
|
+
# Use our escaped format in assertion.
|
310
|
+
coerce_tests! :test_with_abstract_class_scope_should_be_executed_in_correct_context
|
311
|
+
def test_with_abstract_class_scope_should_be_executed_in_correct_context_coerced
|
312
|
+
vegetarian_pattern, gender_pattern = [/[lions].[is_vegetarian]/, /[lions].[gender]/]
|
313
|
+
assert_match vegetarian_pattern, Lion.all.to_sql
|
314
|
+
assert_match gender_pattern, Lion.female.to_sql
|
315
|
+
end
|
266
316
|
end
|
267
317
|
|
268
318
|
|
@@ -271,7 +321,7 @@ end
|
|
271
321
|
require 'models/post'
|
272
322
|
require 'models/subscriber'
|
273
323
|
class EachTest < ActiveRecord::TestCase
|
274
|
-
|
324
|
+
# Quoting in tests does not cope with bracket quoting.
|
275
325
|
coerce_tests! :test_find_in_batches_should_quote_batch_order
|
276
326
|
def test_find_in_batches_should_quote_batch_order_coerced
|
277
327
|
c = Post.connection
|
@@ -283,20 +333,23 @@ class EachTest < ActiveRecord::TestCase
|
|
283
333
|
end
|
284
334
|
end
|
285
335
|
|
336
|
+
# Quoting in tests does not cope with bracket quoting.
|
337
|
+
coerce_tests! :test_in_batches_should_quote_batch_order
|
338
|
+
def test_in_batches_should_quote_batch_order_coerced
|
339
|
+
c = Post.connection
|
340
|
+
assert_sql(/ORDER BY \[posts\]\.\[id\]/) do
|
341
|
+
Post.in_batches(of: 1) do |relation|
|
342
|
+
assert_kind_of ActiveRecord::Relation, relation
|
343
|
+
assert_kind_of Post, relation.first
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
286
347
|
end
|
287
348
|
|
288
349
|
|
289
350
|
|
290
351
|
|
291
|
-
require 'models/owner'
|
292
|
-
class Owner < ActiveRecord::Base
|
293
|
-
scope :including_last_pet, -> {
|
294
|
-
select('owners.*, (select TOP (1) p.pet_id from pets p where p.owner_id = owners.owner_id order by p.name desc ) as last_pet_id').
|
295
|
-
includes(:last_pet)
|
296
|
-
}
|
297
|
-
end
|
298
352
|
class EagerAssociationTest < ActiveRecord::TestCase
|
299
|
-
|
300
353
|
# Use LEN() vs length() function.
|
301
354
|
coerce_tests! :test_count_with_include
|
302
355
|
def test_count_with_include_coerced
|
@@ -305,10 +358,6 @@ class EagerAssociationTest < ActiveRecord::TestCase
|
|
305
358
|
|
306
359
|
# Use TOP (1) in scope vs limit 1.
|
307
360
|
coerce_tests! %r{including association based on sql condition and no database column}
|
308
|
-
it "including association based on sql condition and no database column coerced" do
|
309
|
-
assert_equal pets(:parrot), Owner.including_last_pet.first.last_pet
|
310
|
-
end
|
311
|
-
|
312
361
|
end
|
313
362
|
|
314
363
|
|
@@ -316,13 +365,12 @@ end
|
|
316
365
|
|
317
366
|
require 'models/topic'
|
318
367
|
class FinderTest < ActiveRecord::TestCase
|
319
|
-
|
320
368
|
coerce_tests! %r{doesn't have implicit ordering},
|
321
369
|
:test_find_doesnt_have_implicit_ordering # We have implicit ordering, via FETCH.
|
322
370
|
|
323
371
|
coerce_tests! :test_exists_does_not_select_columns_without_alias
|
324
372
|
def test_exists_does_not_select_columns_without_alias_coerced
|
325
|
-
assert_sql(/SELECT\s+1 AS one FROM \[topics\].*OFFSET 0 ROWS FETCH NEXT
|
373
|
+
assert_sql(/SELECT\s+1 AS one FROM \[topics\].*OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.*@0 = 1/i) do
|
326
374
|
Topic.exists?
|
327
375
|
end
|
328
376
|
end
|
@@ -335,14 +383,35 @@ class FinderTest < ActiveRecord::TestCase
|
|
335
383
|
|
336
384
|
coerce_tests! :test_take_and_first_and_last_with_integer_should_use_sql_limit
|
337
385
|
def test_take_and_first_and_last_with_integer_should_use_sql_limit_coerced
|
338
|
-
assert_sql(/OFFSET 0 ROWS FETCH NEXT
|
339
|
-
assert_sql(/OFFSET 0 ROWS FETCH NEXT
|
340
|
-
assert_sql(/OFFSET 0 ROWS FETCH NEXT
|
386
|
+
assert_sql(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.* @0 = 3/) { Topic.take(3).entries }
|
387
|
+
assert_sql(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.* @0 = 2/) { Topic.first(2).entries }
|
388
|
+
assert_sql(/OFFSET 0 ROWS FETCH NEXT @0 ROWS ONLY.* @0 = 5/) { Topic.last(5).entries }
|
341
389
|
end
|
342
390
|
|
343
391
|
# This fails only when run in the full test suite task. Just taking it out of the mix.
|
344
392
|
coerce_tests! :test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct
|
345
393
|
|
394
|
+
# Can not use array condition due to not finding right type and hence fractional second quoting.
|
395
|
+
coerce_tests! :test_condition_utc_time_interpolation_with_default_timezone_local
|
396
|
+
def test_condition_utc_time_interpolation_with_default_timezone_local_coerced
|
397
|
+
with_env_tz 'America/New_York' do
|
398
|
+
with_timezone_config default: :local do
|
399
|
+
topic = Topic.first
|
400
|
+
assert_equal topic, Topic.where(written_on: topic.written_on.getutc).first
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
# Can not use array condition due to not finding right type and hence fractional second quoting.
|
406
|
+
coerce_tests! :test_condition_local_time_interpolation_with_default_timezone_utc
|
407
|
+
def test_condition_local_time_interpolation_with_default_timezone_utc_coerced
|
408
|
+
with_env_tz 'America/New_York' do
|
409
|
+
with_timezone_config default: :utc do
|
410
|
+
topic = Topic.first
|
411
|
+
assert_equal topic, Topic.where(written_on: topic.written_on.getlocal).first
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
346
415
|
end
|
347
416
|
|
348
417
|
|
@@ -351,7 +420,6 @@ end
|
|
351
420
|
module ActiveRecord
|
352
421
|
class Migration
|
353
422
|
class ForeignKeyTest < ActiveRecord::TestCase
|
354
|
-
|
355
423
|
# We do not support :restrict.
|
356
424
|
coerce_tests! :test_add_on_delete_restrict_foreign_key
|
357
425
|
def test_add_on_delete_restrict_foreign_key_coerced
|
@@ -362,7 +430,6 @@ module ActiveRecord
|
|
362
430
|
@connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_update: :restrict
|
363
431
|
end
|
364
432
|
end
|
365
|
-
|
366
433
|
end
|
367
434
|
end
|
368
435
|
end
|
@@ -371,10 +438,8 @@ end
|
|
371
438
|
|
372
439
|
|
373
440
|
class HasOneAssociationsTest < ActiveRecord::TestCase
|
374
|
-
|
375
441
|
# We use OFFSET/FETCH vs TOP. So we always have an order.
|
376
442
|
coerce_tests! :test_has_one_does_not_use_order_by
|
377
|
-
|
378
443
|
end
|
379
444
|
|
380
445
|
|
@@ -382,7 +447,6 @@ end
|
|
382
447
|
|
383
448
|
require 'models/company'
|
384
449
|
class InheritanceTest < ActiveRecord::TestCase
|
385
|
-
|
386
450
|
coerce_tests! :test_a_bad_type_column
|
387
451
|
def test_a_bad_type_column_coerced
|
388
452
|
Company.connection.with_identity_insert_enabled('companies') do
|
@@ -394,32 +458,24 @@ class InheritanceTest < ActiveRecord::TestCase
|
|
394
458
|
coerce_tests! :test_eager_load_belongs_to_primary_key_quoting
|
395
459
|
def test_eager_load_belongs_to_primary_key_quoting_coerced
|
396
460
|
con = Account.connection
|
397
|
-
assert_sql(/\[companies\]\.\[id\]
|
461
|
+
assert_sql(/\[companies\]\.\[id\] = 1/) do
|
398
462
|
Account.all.merge!(:includes => :firm).find(1)
|
399
463
|
end
|
400
464
|
end
|
401
|
-
|
402
465
|
end
|
403
466
|
|
404
467
|
|
405
468
|
|
406
469
|
|
407
|
-
class
|
408
|
-
|
409
|
-
|
410
|
-
end
|
411
|
-
class MigrationTest < ActiveRecord::TestCase
|
412
|
-
|
413
|
-
# PENDING: [Rails5.x] Remove coerced tests and use simple symbol types.
|
414
|
-
coerce_tests! :test_add_table_with_decimals
|
415
|
-
|
470
|
+
class LeftOuterJoinAssociationTest < ActiveRecord::TestCase
|
471
|
+
# Uses || operator in SQL. Just trust core gets value out of this test.
|
472
|
+
coerce_tests! :test_does_not_override_select
|
416
473
|
end
|
417
474
|
|
418
475
|
|
419
476
|
|
420
477
|
|
421
478
|
class NamedScopingTest < ActiveRecord::TestCase
|
422
|
-
|
423
479
|
# This works now because we add an `order(:id)` sort to break the order tie for deterministic results.
|
424
480
|
coerce_tests! :test_scopes_honor_current_scopes_from_when_defined
|
425
481
|
def test_scopes_honor_current_scopes_from_when_defined_coerced
|
@@ -431,7 +487,6 @@ class NamedScopingTest < ActiveRecord::TestCase
|
|
431
487
|
assert_equal authors(:david).posts.ranked_by_comments.limit_by(5).to_a.sort_by(&:id), authors(:david).posts.top(5).to_a.sort_by(&:id)
|
432
488
|
assert_equal Post.ranked_by_comments.limit_by(5), Post.top(5)
|
433
489
|
end
|
434
|
-
|
435
490
|
end
|
436
491
|
|
437
492
|
|
@@ -440,7 +495,6 @@ end
|
|
440
495
|
require 'models/developer'
|
441
496
|
require 'models/computer'
|
442
497
|
class NestedRelationScopingTest < ActiveRecord::TestCase
|
443
|
-
|
444
498
|
coerce_tests! :test_merge_options
|
445
499
|
def test_merge_options_coerced
|
446
500
|
Developer.where('salary = 80000').scoping do
|
@@ -452,7 +506,6 @@ class NestedRelationScopingTest < ActiveRecord::TestCase
|
|
452
506
|
end
|
453
507
|
end
|
454
508
|
end
|
455
|
-
|
456
509
|
end
|
457
510
|
|
458
511
|
|
@@ -460,7 +513,6 @@ end
|
|
460
513
|
|
461
514
|
require 'models/topic'
|
462
515
|
class PersistenceTest < ActiveRecord::TestCase
|
463
|
-
|
464
516
|
# We can not UPDATE identity columns.
|
465
517
|
coerce_tests! :test_update_columns_changing_id
|
466
518
|
|
@@ -501,7 +553,6 @@ class PersistenceTest < ActiveRecord::TestCase
|
|
501
553
|
# assert_nothing_raised { topic.reload }
|
502
554
|
# assert_equal topic.title, Topic.find(1234).title
|
503
555
|
end
|
504
|
-
|
505
556
|
end
|
506
557
|
|
507
558
|
|
@@ -510,15 +561,15 @@ end
|
|
510
561
|
require 'models/topic'
|
511
562
|
module ActiveRecord
|
512
563
|
class PredicateBuilderTest < ActiveRecord::TestCase
|
513
|
-
|
514
564
|
coerce_tests! :test_registering_new_handlers
|
515
565
|
def test_registering_new_handlers_coerced
|
516
|
-
|
566
|
+
Topic.predicate_builder.register_handler(Regexp, proc do |column, value|
|
517
567
|
Arel::Nodes::InfixOperation.new('~', column, Arel.sql(value.source))
|
518
568
|
end)
|
519
|
-
assert_match %r{\[topics\]
|
569
|
+
assert_match %r{\[topics\].\[title\] ~ rails}i, Topic.where(title: /rails/).to_sql
|
570
|
+
ensure
|
571
|
+
Topic.reset_column_information
|
520
572
|
end
|
521
|
-
|
522
573
|
end
|
523
574
|
end
|
524
575
|
|
@@ -527,14 +578,12 @@ end
|
|
527
578
|
|
528
579
|
require 'models/task'
|
529
580
|
class QueryCacheTest < ActiveRecord::TestCase
|
530
|
-
|
531
581
|
coerce_tests! :test_cache_does_not_wrap_string_results_in_arrays
|
532
582
|
def test_cache_does_not_wrap_string_results_in_arrays_coerced
|
533
583
|
Task.cache do
|
534
584
|
assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
|
535
585
|
end
|
536
586
|
end
|
537
|
-
|
538
587
|
end
|
539
588
|
|
540
589
|
|
@@ -542,6 +591,21 @@ end
|
|
542
591
|
|
543
592
|
require 'models/post'
|
544
593
|
class RelationTest < ActiveRecord::TestCase
|
594
|
+
# Use LEN vs LENGTH function.
|
595
|
+
coerce_tests! :test_reverse_order_with_function
|
596
|
+
def test_reverse_order_with_function_coerced
|
597
|
+
topics = Topic.order("LEN(title)").reverse_order
|
598
|
+
assert_equal topics(:second).title, topics.first.title
|
599
|
+
end
|
600
|
+
|
601
|
+
# Use LEN vs LENGTH function.
|
602
|
+
coerce_tests! :test_reverse_order_with_function_other_predicates
|
603
|
+
def test_reverse_order_with_function_other_predicates_coerced
|
604
|
+
topics = Topic.order("author_name, LEN(title), id").reverse_order
|
605
|
+
assert_equal topics(:second).title, topics.first.title
|
606
|
+
topics = Topic.order("LEN(author_name), id, LEN(title)").reverse_order
|
607
|
+
assert_equal topics(:fifth).title, topics.first.title
|
608
|
+
end
|
545
609
|
|
546
610
|
# We have implicit ordering, via FETCH.
|
547
611
|
coerce_tests! %r{doesn't have implicit ordering}
|
@@ -549,18 +613,12 @@ class RelationTest < ActiveRecord::TestCase
|
|
549
613
|
# We are not doing order duplicate removal anymore.
|
550
614
|
coerce_tests! :test_order_using_scoping
|
551
615
|
|
552
|
-
# Account for our `EXEC sp_executesql...` statements.
|
553
|
-
coerce_tests! :test_to_sql_on_eager_join
|
554
|
-
def test_to_sql_on_eager_join_coerced
|
555
|
-
expected = assert_sql { Post.eager_load(:last_comment).order('comments.id DESC').to_a }.first
|
556
|
-
actual = Post.eager_load(:last_comment).order('comments.id DESC').to_sql
|
557
|
-
actual = "EXEC sp_executesql N'#{ActiveRecord::ConnectionAdapters::SQLServer::Utils.quote_string(actual)}'"
|
558
|
-
assert_equal expected, actual
|
559
|
-
end
|
560
|
-
|
561
616
|
# We are not doing order duplicate removal anymore.
|
562
617
|
coerce_tests! :test_default_scope_order_with_scope_order
|
563
618
|
|
619
|
+
# Leave it up to users to format selects/functions so HAVING works correctly.
|
620
|
+
coerce_tests! :test_multiple_where_and_having_clauses
|
621
|
+
coerce_tests! :test_having_with_binds_for_both_where_and_having
|
564
622
|
end
|
565
623
|
|
566
624
|
|
@@ -568,7 +626,6 @@ end
|
|
568
626
|
|
569
627
|
require 'models/post'
|
570
628
|
class SanitizeTest < ActiveRecord::TestCase
|
571
|
-
|
572
629
|
coerce_tests! :test_sanitize_sql_like_example_use_case
|
573
630
|
def test_sanitize_sql_like_example_use_case_coerced
|
574
631
|
searchable_post = Class.new(Post) do
|
@@ -576,18 +633,16 @@ class SanitizeTest < ActiveRecord::TestCase
|
|
576
633
|
where("title LIKE ?", sanitize_sql_like(term, '!'))
|
577
634
|
end
|
578
635
|
end
|
579
|
-
assert_sql(/\(title LIKE N'
|
636
|
+
assert_sql(/\(title LIKE N'20!% !_reduction!_!!'\)/) do
|
580
637
|
searchable_post.search("20% _reduction_!").to_a
|
581
638
|
end
|
582
639
|
end
|
583
|
-
|
584
640
|
end
|
585
641
|
|
586
642
|
|
587
643
|
|
588
644
|
|
589
645
|
class SchemaDumperTest < ActiveRecord::TestCase
|
590
|
-
|
591
646
|
# We have precision to 38.
|
592
647
|
coerce_tests! :test_schema_dump_keeps_large_precision_integer_columns_as_decimal
|
593
648
|
def test_schema_dump_keeps_large_precision_integer_columns_as_decimal_coerced
|
@@ -604,27 +659,29 @@ class SchemaDumperTest < ActiveRecord::TestCase
|
|
604
659
|
# Fall through false positive with no filter.
|
605
660
|
coerce_tests! :test_schema_dumps_partial_indices
|
606
661
|
def test_schema_dumps_partial_indices_coerced
|
607
|
-
index_definition = standard_dump.split(/\n/).grep(/
|
608
|
-
assert_equal '
|
662
|
+
index_definition = standard_dump.split(/\n/).grep(/t.index.*company_partial_index/).first.strip
|
663
|
+
assert_equal 't.index ["firm_id", "type"], name: "company_partial_index", where: "([rating]>(10))"', index_definition
|
609
664
|
end
|
610
665
|
|
666
|
+
# We do not quote the 2.78 string default.
|
667
|
+
coerce_tests! :test_schema_dump_includes_decimal_options
|
668
|
+
def test_schema_dump_includes_decimal_options_coerced
|
669
|
+
output = dump_all_table_schema([/^[^n]/])
|
670
|
+
assert_match %r{precision: 3,[[:space:]]+scale: 2,[[:space:]]+default: 2\.78}, output
|
671
|
+
end
|
611
672
|
end
|
612
673
|
|
613
674
|
class SchemaDumperDefaultsTest < ActiveRecord::TestCase
|
614
|
-
|
615
675
|
# These date formats do not match ours. We got these covered in our dumper tests.
|
616
676
|
coerce_tests! :test_schema_dump_defaults_with_universally_supported_types
|
617
|
-
|
618
677
|
end
|
619
678
|
|
620
679
|
|
621
680
|
|
622
681
|
|
623
682
|
class TestAdapterWithInvalidConnection < ActiveRecord::TestCase
|
624
|
-
|
625
683
|
# We trust Rails on this since we do not want to install mysql.
|
626
684
|
coerce_tests! %r{inspect on Model class does not raise}
|
627
|
-
|
628
685
|
end
|
629
686
|
|
630
687
|
|
@@ -632,7 +689,6 @@ end
|
|
632
689
|
|
633
690
|
require 'models/topic'
|
634
691
|
class TransactionTest < ActiveRecord::TestCase
|
635
|
-
|
636
692
|
coerce_tests! :test_releasing_named_savepoints
|
637
693
|
def test_releasing_named_savepoints_coerced
|
638
694
|
Topic.transaction do
|
@@ -642,7 +698,6 @@ class TransactionTest < ActiveRecord::TestCase
|
|
642
698
|
Topic.connection.release_savepoint("another")
|
643
699
|
end
|
644
700
|
end
|
645
|
-
|
646
701
|
end
|
647
702
|
|
648
703
|
|
@@ -650,7 +705,6 @@ end
|
|
650
705
|
|
651
706
|
require 'models/tag'
|
652
707
|
class TransactionIsolationTest < ActiveRecord::TestCase
|
653
|
-
|
654
708
|
# SQL Server will lock the table for counts even when both
|
655
709
|
# connections are `READ COMMITTED`. So we bypass with `READPAST`.
|
656
710
|
coerce_tests! %r{read committed}
|
@@ -667,32 +721,32 @@ class TransactionIsolationTest < ActiveRecord::TestCase
|
|
667
721
|
|
668
722
|
# I really need some help understanding this one.
|
669
723
|
coerce_tests! %r{repeatable read}
|
670
|
-
|
671
|
-
end
|
672
|
-
|
673
|
-
|
674
|
-
require 'models/post'
|
675
|
-
module ActiveRecord
|
676
|
-
class WhereChainTest < ActiveRecord::TestCase
|
677
|
-
|
678
|
-
coerce_tests! :test_not_eq_with_array_parameter
|
679
|
-
def test_not_eq_with_array_parameter_coerced
|
680
|
-
expected = Arel::Nodes::Not.new("title = N'hello'")
|
681
|
-
relation = Post.where.not(['title = ?', 'hello'])
|
682
|
-
assert_equal([expected], relation.where_values)
|
683
|
-
end
|
684
|
-
|
685
|
-
end
|
686
724
|
end
|
687
725
|
|
688
726
|
|
689
727
|
|
690
728
|
|
729
|
+
require 'models/book'
|
691
730
|
class ViewWithPrimaryKeyTest < ActiveRecord::TestCase
|
731
|
+
# We have a few view tables. use includes vs equality.
|
732
|
+
coerce_tests! :test_views
|
733
|
+
def test_views_coerced
|
734
|
+
assert_includes @connection.views, Ebook.table_name
|
735
|
+
end
|
692
736
|
|
693
737
|
# We do better than ActiveRecord and find the views PK.
|
694
738
|
coerce_tests! :test_does_not_assume_id_column_as_primary_key
|
695
|
-
|
739
|
+
def test_does_not_assume_id_column_as_primary_key_coerced
|
740
|
+
model = Class.new(ActiveRecord::Base) { self.table_name = "ebooks" }
|
741
|
+
assert_equal 'id', model.primary_key
|
742
|
+
end
|
743
|
+
end
|
744
|
+
class ViewWithoutPrimaryKeyTest < ActiveRecord::TestCase
|
745
|
+
# We have a few view tables. use includes vs equality.
|
746
|
+
coerce_tests! :test_views
|
747
|
+
def test_views_coerced
|
748
|
+
assert_includes @connection.views, Paperback.table_name
|
749
|
+
end
|
696
750
|
end
|
697
751
|
|
698
752
|
|
@@ -700,7 +754,6 @@ end
|
|
700
754
|
|
701
755
|
require 'models/author'
|
702
756
|
class YamlSerializationTest < ActiveRecord::TestCase
|
703
|
-
|
704
757
|
coerce_tests! :test_types_of_virtual_columns_are_not_changed_on_round_trip
|
705
758
|
def test_types_of_virtual_columns_are_not_changed_on_round_trip_coerced
|
706
759
|
author = Author.select('authors.*, 5 as posts_count').first
|
@@ -708,6 +761,48 @@ class YamlSerializationTest < ActiveRecord::TestCase
|
|
708
761
|
assert_equal 5, author.posts_count
|
709
762
|
assert_equal 5, dumped.posts_count
|
710
763
|
end
|
764
|
+
end
|
765
|
+
|
766
|
+
|
767
|
+
|
768
|
+
|
769
|
+
class DateTimePrecisionTest < ActiveRecord::TestCase
|
770
|
+
# Original test had `7` which we support vs `8` which we use.
|
771
|
+
coerce_tests! :test_invalid_datetime_precision_raises_error
|
772
|
+
def test_invalid_datetime_precision_raises_error_coerced
|
773
|
+
assert_raises ActiveRecord::ActiveRecordError do
|
774
|
+
@connection.create_table(:foos, force: true) do |t|
|
775
|
+
t.timestamps precision: 8
|
776
|
+
end
|
777
|
+
end
|
778
|
+
end
|
779
|
+
end
|
780
|
+
|
781
|
+
|
782
|
+
|
711
783
|
|
784
|
+
class DefaultNumbersTest < ActiveRecord::TestCase
|
785
|
+
# We do better with native types and do not return strings for everything.
|
786
|
+
coerce_tests! :test_default_positive_integer
|
787
|
+
def test_default_positive_integer_coerced
|
788
|
+
record = DefaultNumber.new
|
789
|
+
assert_equal 7, record.positive_integer
|
790
|
+
assert_equal 7, record.positive_integer_before_type_cast
|
791
|
+
end
|
792
|
+
coerce_tests! :test_default_negative_integer
|
793
|
+
def test_default_negative_integer_coerced
|
794
|
+
record = DefaultNumber.new
|
795
|
+
assert_equal -5, record.negative_integer
|
796
|
+
assert_equal -5, record.negative_integer_before_type_cast
|
797
|
+
end
|
712
798
|
end
|
713
799
|
|
800
|
+
|
801
|
+
|
802
|
+
|
803
|
+
module ActiveRecord
|
804
|
+
class CollectionCacheKeyTest < ActiveRecord::TestCase
|
805
|
+
# Will trust rails has this sorted since you cant offset without a limit.
|
806
|
+
coerce_tests! %r{with offset which return 0 rows}
|
807
|
+
end
|
808
|
+
end
|