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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +4 -1
  3. data/CHANGELOG.md +12 -23
  4. data/Gemfile +1 -0
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +31 -16
  7. data/VERSION +1 -1
  8. data/activerecord-sqlserver-adapter.gemspec +2 -2
  9. data/appveyor.yml +4 -6
  10. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +2 -0
  11. data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +5 -1
  12. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +2 -0
  13. data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +2 -0
  14. data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +7 -13
  15. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +15 -6
  16. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +4 -5
  17. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +28 -9
  18. data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +14 -5
  19. data/lib/active_record/connection_adapters/sqlserver/type/data.rb +3 -1
  20. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +3 -2
  21. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +1 -1
  22. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +1 -1
  23. data/lib/active_record/connection_adapters/sqlserver/utils.rb +16 -1
  24. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +99 -76
  25. data/lib/active_record/connection_adapters/sqlserver_column.rb +74 -35
  26. data/lib/arel/visitors/sqlserver.rb +17 -2
  27. data/test/cases/adapter_test_sqlserver.rb +10 -2
  28. data/test/cases/coerced_tests.rb +314 -85
  29. data/test/cases/column_test_sqlserver.rb +62 -58
  30. data/test/cases/eager_load_too_many_ids_test_sqlserver.rb +18 -0
  31. data/test/cases/fetch_test_sqlserver.rb +18 -0
  32. data/test/cases/rake_test_sqlserver.rb +36 -0
  33. data/test/cases/schema_dumper_test_sqlserver.rb +2 -2
  34. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +1 -1
  35. data/test/models/sqlserver/composite_pk.rb +9 -0
  36. data/test/schema/sqlserver_specific_schema.rb +18 -0
  37. data/test/support/coerceable_test_sqlserver.rb +4 -4
  38. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic.dump +0 -0
  39. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic_associations.dump +0 -0
  40. data/test/support/rake_helpers.rb +3 -1
  41. metadata +18 -15
  42. data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +0 -28
  43. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic.dump +0 -0
  44. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic_associations.dump +0 -0
@@ -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
- module ActiveRecord
539
- module ConnectionAdapters
540
- class QuoteARBaseTest < ActiveRecord::TestCase
541
- # Use our date format.
542
- coerce_tests! :test_quote_ar_object
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
- # Use our date format.
551
- coerce_tests! :test_type_cast_ar_object
552
- def test_type_cast_ar_object_coerced
553
- value = DatetimePrimaryKey.new(id: @time)
554
- assert_deprecated do
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
- message = <<~MSG.squish
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
- # Original Rails test fails on Windows CI because the dump file was not being binary read.
1270
- coerce_tests! :test_marshal_load_legacy_relation
1271
- def test_marshal_load_legacy_relation_coerced
1272
- path = File.expand_path(
1273
- "support/marshal_compatibility_fixtures/legacy_relation.dump",
1274
- ARTest::SQLServer.root_activerecord_test
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
- dumped = YAML.load(YAML.dump(author))
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! :test_vebose_query_logs
1843
- def test_vebose_query_logs_coerced
1844
- original_test_vebose_query_logs
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