activerecord-sqlserver-adapter 6.1.0.0 → 7.0.0.0.rc1
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/ci.yml +4 -1
- data/CHANGELOG.md +12 -23
- data/Gemfile +1 -0
- data/MIT-LICENSE +1 -1
- data/README.md +31 -16
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +2 -2
- data/appveyor.yml +4 -6
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +2 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +5 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +2 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +2 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +7 -13
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +15 -6
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +4 -5
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +28 -9
- data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +14 -5
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +3 -2
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +16 -1
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +99 -76
- data/lib/active_record/connection_adapters/sqlserver_column.rb +74 -35
- data/lib/arel/visitors/sqlserver.rb +17 -2
- data/test/cases/adapter_test_sqlserver.rb +10 -2
- data/test/cases/coerced_tests.rb +314 -85
- data/test/cases/column_test_sqlserver.rb +62 -58
- data/test/cases/eager_load_too_many_ids_test_sqlserver.rb +18 -0
- data/test/cases/fetch_test_sqlserver.rb +18 -0
- data/test/cases/rake_test_sqlserver.rb +36 -0
- data/test/cases/schema_dumper_test_sqlserver.rb +2 -2
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +1 -1
- data/test/models/sqlserver/composite_pk.rb +9 -0
- data/test/schema/sqlserver_specific_schema.rb +18 -0
- data/test/support/coerceable_test_sqlserver.rb +4 -4
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic_associations.dump +0 -0
- data/test/support/rake_helpers.rb +3 -1
- metadata +18 -15
- data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +0 -28
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic_associations.dump +0 -0
data/test/cases/coerced_tests.rb
CHANGED
@@ -52,7 +52,6 @@ module ActiveRecord
|
|
52
52
|
class AdapterTest < ActiveRecord::TestCase
|
53
53
|
# Legacy binds are not supported.
|
54
54
|
coerce_tests! :test_select_all_insert_update_delete_with_casted_binds
|
55
|
-
coerce_tests! :test_select_all_insert_update_delete_with_legacy_binds
|
56
55
|
|
57
56
|
# As far as I can tell, SQL Server does not support null bytes in strings.
|
58
57
|
coerce_tests! :test_update_prepared_statement
|
@@ -92,6 +91,18 @@ module ActiveRecord
|
|
92
91
|
Subscriber.send(:load_schema!)
|
93
92
|
original_test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_is_called_while_preventing_writes
|
94
93
|
end
|
94
|
+
|
95
|
+
coerce_tests! :test_doesnt_error_when_a_select_query_has_encoding_errors
|
96
|
+
def test_doesnt_error_when_a_select_query_has_encoding_errors_coerced
|
97
|
+
ActiveRecord::Base.while_preventing_writes do
|
98
|
+
# TinyTDS fail on encoding errors.
|
99
|
+
# But at least we can assert it fails in the client and not before when trying to
|
100
|
+
# match the query.
|
101
|
+
assert_raises ActiveRecord::StatementInvalid do
|
102
|
+
@connection.select_all("SELECT '\xC8'")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
95
106
|
end
|
96
107
|
end
|
97
108
|
|
@@ -531,29 +542,33 @@ module ActiveRecord
|
|
531
542
|
assert_equal 1, four.default
|
532
543
|
assert_equal "hello", five.default
|
533
544
|
end
|
534
|
-
end
|
535
|
-
end
|
536
|
-
end
|
537
545
|
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
def test_quote_ar_object_coerced
|
544
|
-
value = DatetimePrimaryKey.new(id: @time)
|
545
|
-
assert_deprecated do
|
546
|
-
assert_equal "'02-14-2017 12:34:56.79'", @connection.quote(value)
|
546
|
+
# Rails adds precision 6 by default, sql server uses datetime2 for datetimes with precision
|
547
|
+
coerce_tests! :test_add_column_with_postgresql_datetime_type
|
548
|
+
def test_add_column_with_postgresql_datetime_type_coerced
|
549
|
+
connection.create_table :testings do |t|
|
550
|
+
t.column :foo, :datetime
|
547
551
|
end
|
552
|
+
|
553
|
+
column = connection.columns(:testings).find { |c| c.name == "foo" }
|
554
|
+
|
555
|
+
assert_equal :datetime, column.type
|
556
|
+
assert_equal "datetime2(6)", column.sql_type
|
548
557
|
end
|
549
558
|
|
550
|
-
#
|
551
|
-
coerce_tests! :
|
552
|
-
def
|
553
|
-
|
554
|
-
|
555
|
-
assert_equal "02-14-2017 12:34:56.79", @connection.type_cast(value)
|
559
|
+
# timestamp is datetime with default limit
|
560
|
+
coerce_tests! :test_change_column_with_timestamp_type
|
561
|
+
def test_change_column_with_timestamp_type_coerced
|
562
|
+
connection.create_table :testings do |t|
|
563
|
+
t.column :foo, :datetime, null: false
|
556
564
|
end
|
565
|
+
|
566
|
+
connection.change_column :testings, :foo, :timestamp
|
567
|
+
|
568
|
+
column = connection.columns(:testings).find { |c| c.name == "foo" }
|
569
|
+
|
570
|
+
assert_equal :datetime, column.type
|
571
|
+
assert_equal "datetime", column.sql_type
|
557
572
|
end
|
558
573
|
end
|
559
574
|
end
|
@@ -616,6 +631,36 @@ class MigrationTest < ActiveRecord::TestCase
|
|
616
631
|
# For some reason our tests set Rails.@_env which breaks test env switching.
|
617
632
|
coerce_tests! :test_internal_metadata_stores_environment_when_other_data_exists
|
618
633
|
coerce_tests! :test_internal_metadata_stores_environment
|
634
|
+
|
635
|
+
# Same as original but using binary type instead of blob
|
636
|
+
coerce_tests! :test_add_column_with_casted_type_if_not_exists_set_to_true
|
637
|
+
def test_add_column_with_casted_type_if_not_exists_set_to_true_coerced
|
638
|
+
migration_a = Class.new(ActiveRecord::Migration::Current) {
|
639
|
+
def version; 100 end
|
640
|
+
def migrate(x)
|
641
|
+
add_column "people", "last_name", :binary
|
642
|
+
end
|
643
|
+
}.new
|
644
|
+
|
645
|
+
migration_b = Class.new(ActiveRecord::Migration::Current) {
|
646
|
+
def version; 101 end
|
647
|
+
def migrate(x)
|
648
|
+
add_column "people", "last_name", :binary, if_not_exists: true
|
649
|
+
end
|
650
|
+
}.new
|
651
|
+
|
652
|
+
ActiveRecord::Migrator.new(:up, [migration_a], @schema_migration, 100).migrate
|
653
|
+
assert_column Person, :last_name, "migration_a should have created the last_name column on people"
|
654
|
+
|
655
|
+
assert_nothing_raised do
|
656
|
+
ActiveRecord::Migrator.new(:up, [migration_b], @schema_migration, 101).migrate
|
657
|
+
end
|
658
|
+
ensure
|
659
|
+
Person.reset_column_information
|
660
|
+
if Person.column_names.include?("last_name")
|
661
|
+
Person.connection.remove_column("people", "last_name")
|
662
|
+
end
|
663
|
+
end
|
619
664
|
end
|
620
665
|
|
621
666
|
class CoreTest < ActiveRecord::TestCase
|
@@ -977,6 +1022,19 @@ module ActiveRecord
|
|
977
1022
|
@connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_update: :restrict
|
978
1023
|
end
|
979
1024
|
end
|
1025
|
+
|
1026
|
+
# Error message depends on the database adapter.
|
1027
|
+
coerce_tests! :test_add_foreign_key_with_if_not_exists_not_set
|
1028
|
+
def test_add_foreign_key_with_if_not_exists_not_set_coerced
|
1029
|
+
@connection.add_foreign_key :astronauts, :rockets
|
1030
|
+
assert_equal 1, @connection.foreign_keys("astronauts").size
|
1031
|
+
|
1032
|
+
error = assert_raises do
|
1033
|
+
@connection.add_foreign_key :astronauts, :rockets
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
assert_match(/TinyTds::Error: There is already an object named '.*' in the database/, error.message)
|
1037
|
+
end
|
980
1038
|
end
|
981
1039
|
end
|
982
1040
|
end
|
@@ -1090,6 +1148,40 @@ class UpdateAllTest < ActiveRecord::TestCase
|
|
1090
1148
|
_(david.reload.name).must_equal "David"
|
1091
1149
|
_(mary.reload.name).must_equal "Test"
|
1092
1150
|
end
|
1151
|
+
|
1152
|
+
# SELECT columns must be in the GROUP clause.
|
1153
|
+
coerce_tests! :test_update_all_with_group_by
|
1154
|
+
def test_update_all_with_group_by_coerced
|
1155
|
+
minimum_comments_count = 2
|
1156
|
+
|
1157
|
+
Post.most_commented(minimum_comments_count).update_all(title: "ig")
|
1158
|
+
posts = Post.select(:id, :title).group(:title).most_commented(minimum_comments_count).all.to_a
|
1159
|
+
|
1160
|
+
assert_operator posts.length, :>, 0
|
1161
|
+
assert posts.all? { |post| post.comments.length >= minimum_comments_count }
|
1162
|
+
assert posts.all? { |post| "ig" == post.title }
|
1163
|
+
|
1164
|
+
post = Post.select(:id, :title).group(:title).joins(:comments).group("posts.id").having("count(comments.id) < #{minimum_comments_count}").first
|
1165
|
+
assert_not_equal "ig", post.title
|
1166
|
+
end
|
1167
|
+
end
|
1168
|
+
|
1169
|
+
class DeleteAllTest < ActiveRecord::TestCase
|
1170
|
+
# SELECT columns must be in the GROUP clause.
|
1171
|
+
coerce_tests! :test_delete_all_with_group_by_and_having
|
1172
|
+
def test_delete_all_with_group_by_and_having_coerced
|
1173
|
+
minimum_comments_count = 2
|
1174
|
+
posts_to_be_deleted = Post.select(:id).most_commented(minimum_comments_count).all.to_a
|
1175
|
+
assert_operator posts_to_be_deleted.length, :>, 0
|
1176
|
+
|
1177
|
+
assert_difference("Post.count", -posts_to_be_deleted.length) do
|
1178
|
+
Post.most_commented(minimum_comments_count).delete_all
|
1179
|
+
end
|
1180
|
+
|
1181
|
+
posts_to_be_deleted.each do |deleted_post|
|
1182
|
+
assert_raise(ActiveRecord::RecordNotFound) { deleted_post.reload }
|
1183
|
+
end
|
1184
|
+
end
|
1093
1185
|
end
|
1094
1186
|
|
1095
1187
|
require "models/topic"
|
@@ -1131,7 +1223,8 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|
1131
1223
|
end
|
1132
1224
|
end
|
1133
1225
|
|
1134
|
-
# Same as original test except that we expect one query to be performed to retrieve the table's primary key
|
1226
|
+
# Same as original test except that we expect one query to be performed to retrieve the table's primary key
|
1227
|
+
# and we don't call `reload_type_map` because SQL Server adapter doesn't support it.
|
1135
1228
|
# When we generate the SQL for the `find` it includes ordering on the primary key. If we reset the column
|
1136
1229
|
# information then the primary key needs to be retrieved from the database again to generate the SQL causing the
|
1137
1230
|
# original test's `assert_no_queries` assertion to fail. Assert that the query was to get the primary key.
|
@@ -1141,9 +1234,6 @@ class QueryCacheTest < ActiveRecord::TestCase
|
|
1141
1234
|
# Warm the cache
|
1142
1235
|
Task.find(1)
|
1143
1236
|
|
1144
|
-
# Preload the type cache again (so we don't have those queries issued during our assertions)
|
1145
|
-
Task.connection.send(:reload_type_map)
|
1146
|
-
|
1147
1237
|
# Clear places where type information is cached
|
1148
1238
|
Task.reset_column_information
|
1149
1239
|
Task.initialize_find_by_cache
|
@@ -1192,16 +1282,11 @@ class RelationTest < ActiveRecord::TestCase
|
|
1192
1282
|
# We have implicit ordering, via FETCH.
|
1193
1283
|
coerce_tests! :test_reorder_with_first
|
1194
1284
|
def test_reorder_with_first_coerced
|
1285
|
+
post = nil
|
1195
1286
|
sql_log = capture_sql do
|
1196
|
-
|
1197
|
-
`.reorder(nil)` with `.first` / `.first!` no longer
|
1198
|
-
takes non-deterministic result in Rails 6.2.
|
1199
|
-
To continue taking non-deterministic result, use `.take` / `.take!` instead.
|
1200
|
-
MSG
|
1201
|
-
assert_deprecated(message) do
|
1202
|
-
assert Post.order(:title).reorder(nil).first
|
1203
|
-
end
|
1287
|
+
post = Post.order(:title).reorder(nil).first
|
1204
1288
|
end
|
1289
|
+
assert_equal posts(:welcome), post
|
1205
1290
|
assert sql_log.none? { |sql| /order by [posts].[title]/i.match?(sql) }, "ORDER BY title was used in the query: #{sql_log}"
|
1206
1291
|
assert sql_log.all? { |sql| /order by \[posts\]\.\[id\]/i.match?(sql) }, "default ORDER BY ID was not used in the query: #{sql_log}"
|
1207
1292
|
end
|
@@ -1266,14 +1351,13 @@ module ActiveRecord
|
|
1266
1351
|
assert_equal expected, query
|
1267
1352
|
end
|
1268
1353
|
|
1269
|
-
#
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
)
|
1276
|
-
assert_equal 11, Marshal.load(File.binread(path)).size
|
1354
|
+
# Workaround for randomly failing test. Ordering of results not guaranteed.
|
1355
|
+
# TODO: Remove coerced test when https://github.com/rails/rails/pull/44168 merged.
|
1356
|
+
coerce_tests! :test_select_quotes_when_using_from_clause
|
1357
|
+
def test_select_quotes_when_using_from_clause_coerced
|
1358
|
+
quoted_join = ActiveRecord::Base.connection.quote_table_name("join")
|
1359
|
+
selected = Post.select(:join).from(Post.select("id as #{quoted_join}")).map(&:join)
|
1360
|
+
assert_equal Post.pluck(:id).sort, selected.sort
|
1277
1361
|
end
|
1278
1362
|
end
|
1279
1363
|
end
|
@@ -1402,7 +1486,8 @@ class YamlSerializationTest < ActiveRecord::TestCase
|
|
1402
1486
|
coerce_tests! :test_types_of_virtual_columns_are_not_changed_on_round_trip
|
1403
1487
|
def test_types_of_virtual_columns_are_not_changed_on_round_trip_coerced
|
1404
1488
|
author = Author.select("authors.*, 5 as posts_count").first
|
1405
|
-
|
1489
|
+
dumped_author = YAML.dump(author)
|
1490
|
+
dumped = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(dumped_author) : YAML.load(dumped_author)
|
1406
1491
|
assert_equal 5, author.posts_count
|
1407
1492
|
assert_equal 5, dumped.posts_count
|
1408
1493
|
end
|
@@ -1521,6 +1606,7 @@ module ActiveRecord
|
|
1521
1606
|
|
1522
1607
|
original_test_statement_cache_values_differ
|
1523
1608
|
ensure
|
1609
|
+
Book.where(author_id: nil, name: 'my book').delete_all
|
1524
1610
|
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
1525
1611
|
end
|
1526
1612
|
end
|
@@ -1748,6 +1834,7 @@ class EnumTest < ActiveRecord::TestCase
|
|
1748
1834
|
|
1749
1835
|
send(:'original_enums are distinct per class')
|
1750
1836
|
ensure
|
1837
|
+
Book.where(author_id: nil, name: nil).delete_all
|
1751
1838
|
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
1752
1839
|
end
|
1753
1840
|
|
@@ -1758,6 +1845,7 @@ class EnumTest < ActiveRecord::TestCase
|
|
1758
1845
|
|
1759
1846
|
send(:'original_creating new objects with enum scopes')
|
1760
1847
|
ensure
|
1848
|
+
Book.where(author_id: nil, name: nil).delete_all
|
1761
1849
|
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
1762
1850
|
end
|
1763
1851
|
|
@@ -1768,6 +1856,7 @@ class EnumTest < ActiveRecord::TestCase
|
|
1768
1856
|
|
1769
1857
|
send(:'original_enums are inheritable')
|
1770
1858
|
ensure
|
1859
|
+
Book.where(author_id: nil, name: nil).delete_all
|
1771
1860
|
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
1772
1861
|
end
|
1773
1862
|
|
@@ -1778,6 +1867,18 @@ class EnumTest < ActiveRecord::TestCase
|
|
1778
1867
|
|
1779
1868
|
send(:'original_declare multiple enums at a time')
|
1780
1869
|
ensure
|
1870
|
+
Book.where(author_id: nil, name: nil).delete_all
|
1871
|
+
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
1872
|
+
end
|
1873
|
+
|
1874
|
+
# Need to remove index as SQL Server considers NULLs on a unique-index to be equal unlike PostgreSQL/MySQL/SQLite.
|
1875
|
+
coerce_tests! %r{serializable\? with large number label}
|
1876
|
+
test "serializable? with large number label coerced" do
|
1877
|
+
Book.connection.remove_index(:books, column: [:author_id, :name])
|
1878
|
+
|
1879
|
+
send(:'original_serializable\? with large number label')
|
1880
|
+
ensure
|
1881
|
+
Book.where(author_id: nil, name: nil).delete_all
|
1781
1882
|
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
1782
1883
|
end
|
1783
1884
|
end
|
@@ -1839,9 +1940,17 @@ end
|
|
1839
1940
|
|
1840
1941
|
class LogSubscriberTest < ActiveRecord::TestCase
|
1841
1942
|
# Call original test from coerced test. Fixes issue on CI with Rails installed as a gem.
|
1842
|
-
coerce_tests! :
|
1843
|
-
def
|
1844
|
-
|
1943
|
+
coerce_tests! :test_verbose_query_logs
|
1944
|
+
def test_verbose_query_logs_coerced
|
1945
|
+
original_test_verbose_query_logs
|
1946
|
+
end
|
1947
|
+
|
1948
|
+
# Bindings logged slightly differently.
|
1949
|
+
coerce_tests! :test_where_in_binds_logging_include_attribute_names
|
1950
|
+
def test_where_in_binds_logging_include_attribute_names_coerced
|
1951
|
+
Developer.where(id: [1, 2, 3, 4, 5]).load
|
1952
|
+
wait
|
1953
|
+
assert_match(%{@0 = 1, @1 = 2, @2 = 3, @3 = 4, @4 = 5 [["id", nil], ["id", nil], ["id", nil], ["id", nil], ["id", nil]]}, @logger.logged(:debug).last)
|
1845
1954
|
end
|
1846
1955
|
end
|
1847
1956
|
|
@@ -1860,48 +1969,6 @@ class ReloadModelsTest < ActiveRecord::TestCase
|
|
1860
1969
|
coerce_tests! :test_has_one_with_reload if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
|
1861
1970
|
end
|
1862
1971
|
|
1863
|
-
require "models/post"
|
1864
|
-
class AnnotateTest < ActiveRecord::TestCase
|
1865
|
-
# Same as original coerced test except our SQL starts with `EXEC sp_executesql`.
|
1866
|
-
# TODO: Remove coerce after Rails 7 (see https://github.com/rails/rails/pull/42027)
|
1867
|
-
coerce_tests! :test_annotate_wraps_content_in_an_inline_comment
|
1868
|
-
def test_annotate_wraps_content_in_an_inline_comment_coerced
|
1869
|
-
quoted_posts_id, quoted_posts = regexp_escape_table_name("posts.id"), regexp_escape_table_name("posts")
|
1870
|
-
|
1871
|
-
assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/}i) do
|
1872
|
-
posts = Post.select(:id).annotate("foo")
|
1873
|
-
assert posts.first
|
1874
|
-
end
|
1875
|
-
end
|
1876
|
-
|
1877
|
-
# Same as original coerced test except our SQL starts with `EXEC sp_executesql`.
|
1878
|
-
# TODO: Remove coerce after Rails 7 (see https://github.com/rails/rails/pull/42027)
|
1879
|
-
coerce_tests! :test_annotate_is_sanitized
|
1880
|
-
def test_annotate_is_sanitized_coerced
|
1881
|
-
quoted_posts_id, quoted_posts = regexp_escape_table_name("posts.id"), regexp_escape_table_name("posts")
|
1882
|
-
|
1883
|
-
assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/}i) do
|
1884
|
-
posts = Post.select(:id).annotate("*/foo/*")
|
1885
|
-
assert posts.first
|
1886
|
-
end
|
1887
|
-
|
1888
|
-
assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/}i) do
|
1889
|
-
posts = Post.select(:id).annotate("**//foo//**")
|
1890
|
-
assert posts.first
|
1891
|
-
end
|
1892
|
-
|
1893
|
-
assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/ /\* bar \*/}i) do
|
1894
|
-
posts = Post.select(:id).annotate("*/foo/*").annotate("*/bar")
|
1895
|
-
assert posts.first
|
1896
|
-
end
|
1897
|
-
|
1898
|
-
assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* \+ MAX_EXECUTION_TIME\(1\) \*/}i) do
|
1899
|
-
posts = Post.select(:id).annotate("+ MAX_EXECUTION_TIME(1)")
|
1900
|
-
assert posts.first
|
1901
|
-
end
|
1902
|
-
end
|
1903
|
-
end
|
1904
|
-
|
1905
1972
|
class MarshalSerializationTest < ActiveRecord::TestCase
|
1906
1973
|
private
|
1907
1974
|
|
@@ -1976,3 +2043,165 @@ class MultiDbMigratorTest < ActiveRecord::TestCase
|
|
1976
2043
|
# Test fails on Windows AppVeyor CI for unknown reason.
|
1977
2044
|
coerce_tests! :test_migrator_db_has_no_schema_migrations_table if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
|
1978
2045
|
end
|
2046
|
+
|
2047
|
+
require "models/book"
|
2048
|
+
class FieldOrderedValuesTest < ActiveRecord::TestCase
|
2049
|
+
# Need to remove index as SQL Server considers NULLs on a unique-index to be equal unlike PostgreSQL/MySQL/SQLite.
|
2050
|
+
coerce_tests! :test_in_order_of_with_enums_values
|
2051
|
+
def test_in_order_of_with_enums_values_coerced
|
2052
|
+
Book.connection.remove_index(:books, column: [:author_id, :name])
|
2053
|
+
|
2054
|
+
original_test_in_order_of_with_enums_values
|
2055
|
+
ensure
|
2056
|
+
Book.where(author_id: nil, name: nil).delete_all
|
2057
|
+
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
2058
|
+
end
|
2059
|
+
|
2060
|
+
# Need to remove index as SQL Server considers NULLs on a unique-index to be equal unlike PostgreSQL/MySQL/SQLite.
|
2061
|
+
coerce_tests! :test_in_order_of_with_enums_keys
|
2062
|
+
def test_in_order_of_with_enums_keys_coerced
|
2063
|
+
Book.connection.remove_index(:books, column: [:author_id, :name])
|
2064
|
+
|
2065
|
+
original_test_in_order_of_with_enums_keys
|
2066
|
+
ensure
|
2067
|
+
Book.where(author_id: nil, name: nil).delete_all
|
2068
|
+
Book.connection.add_index(:books, [:author_id, :name], unique: true)
|
2069
|
+
end
|
2070
|
+
end
|
2071
|
+
|
2072
|
+
require "models/dashboard"
|
2073
|
+
class QueryLogsTest < ActiveRecord::TestCase
|
2074
|
+
# Same as original coerced test except our SQL ends with binding.
|
2075
|
+
# TODO: Remove coerce after Rails 7.1.0 (see https://github.com/rails/rails/pull/44053)
|
2076
|
+
coerce_tests! :test_custom_basic_tags, :test_custom_proc_tags, :test_multiple_custom_tags, :test_custom_proc_context_tags
|
2077
|
+
def test_custom_basic_tags_coerced
|
2078
|
+
ActiveRecord::QueryLogs.tags = [ :application, { custom_string: "test content" } ]
|
2079
|
+
|
2080
|
+
assert_sql(%r{/\*application:active_record,custom_string:test content\*/}) do
|
2081
|
+
Dashboard.first
|
2082
|
+
end
|
2083
|
+
end
|
2084
|
+
|
2085
|
+
def test_custom_proc_tags_coerced
|
2086
|
+
ActiveRecord::QueryLogs.tags = [ :application, { custom_proc: -> { "test content" } } ]
|
2087
|
+
|
2088
|
+
assert_sql(%r{/\*application:active_record,custom_proc:test content\*/}) do
|
2089
|
+
Dashboard.first
|
2090
|
+
end
|
2091
|
+
end
|
2092
|
+
|
2093
|
+
def test_multiple_custom_tags_coerced
|
2094
|
+
ActiveRecord::QueryLogs.tags = [
|
2095
|
+
:application,
|
2096
|
+
{ custom_proc: -> { "test content" }, another_proc: -> { "more test content" } },
|
2097
|
+
]
|
2098
|
+
|
2099
|
+
assert_sql(%r{/\*application:active_record,custom_proc:test content,another_proc:more test content\*/}) do
|
2100
|
+
Dashboard.first
|
2101
|
+
end
|
2102
|
+
end
|
2103
|
+
|
2104
|
+
def test_custom_proc_context_tags_coerced
|
2105
|
+
ActiveSupport::ExecutionContext[:foo] = "bar"
|
2106
|
+
ActiveRecord::QueryLogs.tags = [ :application, { custom_context_proc: ->(context) { context[:foo] } } ]
|
2107
|
+
|
2108
|
+
assert_sql(%r{/\*application:active_record,custom_context_proc:bar\*/}) do
|
2109
|
+
Dashboard.first
|
2110
|
+
end
|
2111
|
+
end
|
2112
|
+
end
|
2113
|
+
|
2114
|
+
# SQL Server does not support upsert yet
|
2115
|
+
# TODO: Remove coerce after Rails 7.1.0 (see https://github.com/rails/rails/pull/44050)
|
2116
|
+
class InsertAllTest < ActiveRecord::TestCase
|
2117
|
+
coerce_tests! :test_upsert_all_only_updates_the_column_provided_via_update_only
|
2118
|
+
def test_upsert_all_only_updates_the_column_provided_via_update_only_coerced
|
2119
|
+
assert_raises(ArgumentError, /does not support upsert/) do
|
2120
|
+
original_test_upsert_all_only_updates_the_column_provided_via_update_only
|
2121
|
+
end
|
2122
|
+
end
|
2123
|
+
|
2124
|
+
coerce_tests! :test_upsert_all_only_updates_the_list_of_columns_provided_via_update_only
|
2125
|
+
def test_upsert_all_only_updates_the_list_of_columns_provided_via_update_only_coerced
|
2126
|
+
assert_raises(ArgumentError, /does not support upsert/) do
|
2127
|
+
original_test_upsert_all_only_updates_the_list_of_columns_provided_via_update_only
|
2128
|
+
end
|
2129
|
+
end
|
2130
|
+
|
2131
|
+
coerce_tests! :test_upsert_all_implicitly_sets_timestamps_on_create_when_model_record_timestamps_is_true
|
2132
|
+
def test_upsert_all_implicitly_sets_timestamps_on_create_when_model_record_timestamps_is_true_coerced
|
2133
|
+
assert_raises(ArgumentError, /does not support upsert/) do
|
2134
|
+
original_test_upsert_all_implicitly_sets_timestamps_on_create_when_model_record_timestamps_is_true
|
2135
|
+
end
|
2136
|
+
end
|
2137
|
+
|
2138
|
+
coerce_tests! :test_upsert_all_respects_created_at_precision_when_touched_implicitly
|
2139
|
+
def test_upsert_all_respects_created_at_precision_when_touched_implicitly_coerced
|
2140
|
+
assert_raises(ArgumentError, /does not support upsert/) do
|
2141
|
+
original_test_upsert_all_respects_created_at_precision_when_touched_implicitly
|
2142
|
+
end
|
2143
|
+
end
|
2144
|
+
|
2145
|
+
coerce_tests! :test_upsert_all_does_not_implicitly_set_timestamps_on_create_when_model_record_timestamps_is_true_but_overridden
|
2146
|
+
def test_upsert_all_does_not_implicitly_set_timestamps_on_create_when_model_record_timestamps_is_true_but_overridden_coerced
|
2147
|
+
assert_raises(ArgumentError, /does not support upsert/) do
|
2148
|
+
original_test_upsert_all_does_not_implicitly_set_timestamps_on_create_when_model_record_timestamps_is_true_but_overridden
|
2149
|
+
end
|
2150
|
+
end
|
2151
|
+
|
2152
|
+
coerce_tests! :test_upsert_all_does_not_implicitly_set_timestamps_on_create_when_model_record_timestamps_is_false
|
2153
|
+
def test_upsert_all_does_not_implicitly_set_timestamps_on_create_when_model_record_timestamps_is_false_coerced
|
2154
|
+
assert_raises(ArgumentError, /does not support upsert/) do
|
2155
|
+
original_test_upsert_all_does_not_implicitly_set_timestamps_on_create_when_model_record_timestamps_is_false
|
2156
|
+
end
|
2157
|
+
end
|
2158
|
+
|
2159
|
+
coerce_tests! :test_upsert_all_implicitly_sets_timestamps_on_create_when_model_record_timestamps_is_false_but_overridden
|
2160
|
+
def test_upsert_all_implicitly_sets_timestamps_on_create_when_model_record_timestamps_is_false_but_overridden_coerced
|
2161
|
+
assert_raises(ArgumentError, /does not support upsert/) do
|
2162
|
+
original_test_upsert_all_implicitly_sets_timestamps_on_create_when_model_record_timestamps_is_false_but_overridden
|
2163
|
+
end
|
2164
|
+
end
|
2165
|
+
end
|
2166
|
+
|
2167
|
+
class HasOneThroughDisableJoinsAssociationsTest < ActiveRecord::TestCase
|
2168
|
+
# TODO: Remove coerce after Rails 7.1.0 (see https://github.com/rails/rails/pull/44051)
|
2169
|
+
coerce_tests! :test_disable_joins_through_with_enum_type
|
2170
|
+
def test_disable_joins_through_with_enum_type_coerced
|
2171
|
+
joins = capture_sql { @member.club }
|
2172
|
+
no_joins = capture_sql { @member.club_without_joins }
|
2173
|
+
|
2174
|
+
assert_equal 1, joins.size
|
2175
|
+
assert_equal 2, no_joins.size
|
2176
|
+
|
2177
|
+
assert_match(/INNER JOIN/, joins.first)
|
2178
|
+
no_joins.each do |nj|
|
2179
|
+
assert_no_match(/INNER JOIN/, nj)
|
2180
|
+
end
|
2181
|
+
|
2182
|
+
assert_match(/\[memberships\]\.\[type\]/, no_joins.first)
|
2183
|
+
end
|
2184
|
+
end
|
2185
|
+
|
2186
|
+
class InsertAllTest < ActiveRecord::TestCase
|
2187
|
+
coerce_tests! :test_insert_all_returns_requested_sql_fields
|
2188
|
+
# Same as original but using INSERTED.name as UPPER argument
|
2189
|
+
def test_insert_all_returns_requested_sql_fields_coerced
|
2190
|
+
skip unless supports_insert_returning?
|
2191
|
+
|
2192
|
+
result = Book.insert_all! [{ name: "Rework", author_id: 1 }], returning: Arel.sql("UPPER(INSERTED.name) as name")
|
2193
|
+
assert_equal %w[ REWORK ], result.pluck("name")
|
2194
|
+
end
|
2195
|
+
end
|
2196
|
+
|
2197
|
+
class ActiveRecord::Encryption::EncryptableRecordTest < ActiveRecord::EncryptionTestCase
|
2198
|
+
# TODO: Remove coerce after Rails 7.1.0 (see https://github.com/rails/rails/pull/44052)
|
2199
|
+
# Same as original but SQL Server string is varchar(4000), not varchar(255) as other adapters. Produce invalid strings with 4001 characters
|
2200
|
+
coerce_tests! %r{validate column sizes}
|
2201
|
+
test "validate column sizes coerced" do
|
2202
|
+
assert EncryptedAuthor.new(name: "jorge").valid?
|
2203
|
+
assert_not EncryptedAuthor.new(name: "a" * 4001).valid?
|
2204
|
+
author = EncryptedAuthor.create(name: "a" * 4001)
|
2205
|
+
assert_not author.valid?
|
2206
|
+
end
|
2207
|
+
end
|