activerecord-sqlserver-adapter 6.0.1 → 6.1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +26 -0
  3. data/CHANGELOG.md +29 -46
  4. data/README.md +32 -3
  5. data/RUNNING_UNIT_TESTS.md +1 -1
  6. data/VERSION +1 -1
  7. data/activerecord-sqlserver-adapter.gemspec +1 -1
  8. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +2 -0
  9. data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +5 -10
  10. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +9 -2
  11. data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +2 -0
  12. data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +2 -0
  13. data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +0 -4
  14. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +28 -16
  15. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +8 -7
  16. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +22 -1
  17. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +9 -3
  18. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +31 -9
  19. data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +36 -7
  20. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +0 -1
  21. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +2 -2
  22. data/lib/active_record/connection_adapters/sqlserver/type.rb +1 -0
  23. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +2 -1
  24. data/lib/active_record/connection_adapters/sqlserver/type/decimal_without_scale.rb +22 -0
  25. data/lib/active_record/connection_adapters/sqlserver/utils.rb +1 -1
  26. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +100 -69
  27. data/lib/active_record/connection_adapters/sqlserver_column.rb +75 -19
  28. data/lib/active_record/sqlserver_base.rb +9 -15
  29. data/lib/active_record/tasks/sqlserver_database_tasks.rb +17 -14
  30. data/lib/arel/visitors/sqlserver.rb +125 -40
  31. data/test/cases/adapter_test_sqlserver.rb +50 -16
  32. data/test/cases/change_column_collation_test_sqlserver.rb +33 -0
  33. data/test/cases/coerced_tests.rb +611 -78
  34. data/test/cases/column_test_sqlserver.rb +9 -2
  35. data/test/cases/disconnected_test_sqlserver.rb +39 -0
  36. data/test/cases/execute_procedure_test_sqlserver.rb +9 -0
  37. data/test/cases/fetch_test_sqlserver.rb +18 -0
  38. data/test/cases/in_clause_test_sqlserver.rb +27 -0
  39. data/test/cases/lateral_test_sqlserver.rb +35 -0
  40. data/test/cases/migration_test_sqlserver.rb +51 -0
  41. data/test/cases/optimizer_hints_test_sqlserver.rb +72 -0
  42. data/test/cases/order_test_sqlserver.rb +7 -0
  43. data/test/cases/primary_keys_test_sqlserver.rb +103 -0
  44. data/test/cases/rake_test_sqlserver.rb +38 -2
  45. data/test/cases/schema_dumper_test_sqlserver.rb +14 -3
  46. data/test/migrations/create_clients_and_change_column_collation.rb +19 -0
  47. data/test/models/sqlserver/composite_pk.rb +9 -0
  48. data/test/models/sqlserver/sst_string_collation.rb +3 -0
  49. data/test/schema/sqlserver_specific_schema.rb +25 -0
  50. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic.dump +0 -0
  51. data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic_associations.dump +0 -0
  52. data/test/support/sql_counter_sqlserver.rb +14 -12
  53. metadata +29 -9
  54. data/.travis.yml +0 -23
  55. data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +0 -28
@@ -157,13 +157,16 @@ class ColumnTestSQLServer < ActiveRecord::TestCase
157
157
  _(col.default).must_equal BigDecimal("191")
158
158
  _(obj.numeric_18_0).must_equal BigDecimal("191")
159
159
  _(col.default_function).must_be_nil
160
+
160
161
  type = connection.lookup_cast_type_from_column(col)
161
- _(type).must_be_instance_of Type::Decimal
162
+ _(type).must_be_instance_of Type::DecimalWithoutScale
162
163
  _(type.limit).must_be_nil
163
164
  _(type.precision).must_equal 18
164
- _(type.scale).must_equal 0
165
+ _(type.scale).must_be_nil
166
+
165
167
  obj.numeric_18_0 = "192.1"
166
168
  _(obj.numeric_18_0).must_equal BigDecimal("192")
169
+
167
170
  obj.save!
168
171
  _(obj.reload.numeric_18_0).must_equal BigDecimal("192")
169
172
  end
@@ -296,6 +299,8 @@ class ColumnTestSQLServer < ActiveRecord::TestCase
296
299
  _(obj.date).must_equal Date.civil(0001, 4, 1)
297
300
  obj.reload
298
301
  _(obj.date).must_equal Date.civil(0001, 4, 1)
302
+ # Can filter by date range
303
+ _(obj).must_equal obj.class.where(date: obj.date..Date::Infinity.new).first
299
304
  # Can keep and return assigned date.
300
305
  assert_obj_set_and_save :date, Date.civil(1972, 04, 14)
301
306
  # Can accept and cast time objects.
@@ -330,6 +335,8 @@ class ColumnTestSQLServer < ActiveRecord::TestCase
330
335
  obj.reload
331
336
  _(obj.datetime).must_equal time, "Microseconds were <#{obj.datetime.usec}> vs <3000>"
332
337
  _(obj).must_equal obj.class.where(datetime: time).first
338
+ # Can filter by datetime range
339
+ _(obj).must_equal obj.class.where(datetime: time..DateTime::Infinity.new).first
333
340
  # Will cast to true DB value on attribute write, save and return again.
334
341
  time = Time.utc 2010, 04, 01, 12, 34, 56, 234567
335
342
  time2 = Time.utc 2010, 04, 01, 12, 34, 56, 233000
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper_sqlserver"
4
+
5
+ class TestDisconnectedAdapter < ActiveRecord::TestCase
6
+ self.use_transactional_tests = false
7
+
8
+ def setup
9
+ @connection = ActiveRecord::Base.connection
10
+ end
11
+
12
+ teardown do
13
+ return if in_memory_db?
14
+ db_config = ActiveRecord::Base.connection_db_config
15
+ ActiveRecord::Base.establish_connection(db_config)
16
+ end
17
+
18
+ test "can't execute procedures while disconnected" do
19
+ @connection.execute_procedure :sp_tables, "sst_datatypes"
20
+ @connection.disconnect!
21
+ assert_raises(ActiveRecord::ConnectionNotEstablished, 'SQL Server client is not connected') do
22
+ @connection.execute_procedure :sp_tables, "sst_datatypes"
23
+ end
24
+ end
25
+
26
+ test "can't execute query while disconnected" do
27
+ sql = "SELECT count(*) from products WHERE id IN(@0, @1)"
28
+ binds = [
29
+ ActiveRecord::Relation::QueryAttribute.new("id", 2, ActiveRecord::Type::BigInteger.new),
30
+ ActiveRecord::Relation::QueryAttribute.new("id", 2, ActiveRecord::Type::BigInteger.new)
31
+ ]
32
+
33
+ @connection.exec_query sql, "TEST", binds
34
+ @connection.disconnect!
35
+ assert_raises(ActiveRecord::ConnectionNotEstablished, 'SQL Server client is not connected') do
36
+ @connection.exec_query sql, "TEST", binds
37
+ end
38
+ end
39
+ end
@@ -41,4 +41,13 @@ class ExecuteProcedureTestSQLServer < ActiveRecord::TestCase
41
41
  date_base = connection.select_value("select GETUTCDATE()")
42
42
  assert_equal date_base.change(usec: 0), date_proc.change(usec: 0)
43
43
  end
44
+
45
+ it 'test deprecation with transaction return when executing procedure' do
46
+ assert_deprecated do
47
+ ActiveRecord::Base.transaction do
48
+ connection.execute_procedure("my_getutcdate")
49
+ return
50
+ end
51
+ end
52
+ end
44
53
  end
@@ -49,3 +49,21 @@ class FetchTestSqlserver < ActiveRecord::TestCase
49
49
  @books = (1..10).map { |i| Book.create! name: "Name-#{i}" }
50
50
  end
51
51
  end
52
+
53
+ class DeterministicFetchWithCompositePkTestSQLServer < ActiveRecord::TestCase
54
+ it "orders by the identity column if table has one" do
55
+ SSCompositePkWithIdentity.delete_all
56
+ SSCompositePkWithIdentity.create(pk_col_two: 2)
57
+ SSCompositePkWithIdentity.create(pk_col_two: 1)
58
+
59
+ _(SSCompositePkWithIdentity.take(1).map(&:pk_col_two)).must_equal [2]
60
+ end
61
+
62
+ it "orders by the first column if table has no identity column" do
63
+ SSCompositePkWithoutIdentity.delete_all
64
+ SSCompositePkWithoutIdentity.create(pk_col_one: 2, pk_col_two: 2)
65
+ SSCompositePkWithoutIdentity.create(pk_col_one: 1, pk_col_two: 1)
66
+
67
+ _(SSCompositePkWithoutIdentity.take(1).map(&:pk_col_two)).must_equal [1]
68
+ end
69
+ end
@@ -33,4 +33,31 @@ class InClauseTestSQLServer < ActiveRecord::TestCase
33
33
  assert_includes posts.to_sql, "ORDER BY [authors].[name]"
34
34
  assert_equal 8, posts.length
35
35
  end
36
+
37
+ it "removes ordering from 'not' subqueries" do
38
+ authors_subquery = Author.where.not(name: ["Mary", "Bob"]).order(:name)
39
+ posts = Post.where(author: authors_subquery)
40
+
41
+ assert_includes authors_subquery.to_sql, "ORDER BY [authors].[name]"
42
+ assert_not_includes posts.to_sql, "ORDER BY [authors].[name]"
43
+ assert_equal 5, posts.length
44
+ end
45
+
46
+ it "does not remove ordering from 'not' subquery that includes a limit" do
47
+ authors_subquery = Author.where.not(name: ["Ronan", "Mary", "Bob"]).order(:name).limit(2)
48
+ posts = Post.where(author: authors_subquery)
49
+
50
+ assert_includes authors_subquery.to_sql, "ORDER BY [authors].[name]"
51
+ assert_includes posts.to_sql, "ORDER BY [authors].[name]"
52
+ assert_equal 5, posts.length
53
+ end
54
+
55
+ it "does not remove ordering from 'not' subquery that includes an offset" do
56
+ authors_subquery = Author.where.not(name: ["David", "Ronan", "Cian"]).order(:name).offset(1)
57
+ posts = Post.where(author: authors_subquery)
58
+
59
+ assert_includes authors_subquery.to_sql, "ORDER BY [authors].[name]"
60
+ assert_includes posts.to_sql, "ORDER BY [authors].[name]"
61
+ assert_equal 3, posts.length
62
+ end
36
63
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper_sqlserver"
4
+ require "models/post"
5
+ require "models/author"
6
+
7
+ class LateralTestSQLServer < ActiveRecord::TestCase
8
+ fixtures :posts, :authors
9
+
10
+ it 'uses OUTER APPLY for OUTER JOIN LATERAL' do
11
+ post = Arel::Table.new(:posts)
12
+ author = Arel::Table.new(:authors)
13
+ subselect = post.project(Arel.star).take(1).where(post[:author_id].eq(author[:id])).where(post[:id].eq(42))
14
+
15
+ one = Arel::Nodes::Quoted.new(1)
16
+ eq = Arel::Nodes::Equality.new(one, one)
17
+
18
+ sql = author.project(Arel.star).where(author[:name].matches("David")).outer_join(subselect.lateral.as("bar")).on(eq).to_sql
19
+ results = ActiveRecord::Base.connection.exec_query sql
20
+ assert_equal sql, "SELECT * FROM [authors] OUTER APPLY (SELECT * FROM [posts] WHERE [posts].[author_id] = [authors].[id] AND [posts].[id] = 42 ORDER BY [posts].[id] ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY) AS bar WHERE [authors].[name] LIKE N'David'"
21
+ assert_equal results.length, 1
22
+ end
23
+
24
+ it 'uses CROSS APPLY for INNER JOIN LATERAL' do
25
+ post = Arel::Table.new(:posts)
26
+ author = Arel::Table.new(:authors)
27
+ subselect = post.project(Arel.star).take(1).where(post[:author_id].eq(author[:id])).where(post[:id].eq(42))
28
+
29
+ sql = author.project(Arel.star).where(author[:name].matches("David")).join(subselect.lateral.as("bar")).to_sql
30
+ results = ActiveRecord::Base.connection.exec_query sql
31
+
32
+ assert_equal sql, "SELECT * FROM [authors] CROSS APPLY (SELECT * FROM [posts] WHERE [posts].[author_id] = [authors].[id] AND [posts].[id] = 42 ORDER BY [posts].[id] ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY) AS bar WHERE [authors].[name] LIKE N'David'"
33
+ assert_equal results.length, 0
34
+ end
35
+ end
@@ -63,5 +63,56 @@ class MigrationTestSQLServer < ActiveRecord::TestCase
63
63
  it "change null and default" do
64
64
  assert_nothing_raised { connection.change_column :people, :first_name, :text, null: true, default: nil }
65
65
  end
66
+
67
+ it "change collation" do
68
+ assert_nothing_raised { connection.change_column :sst_string_collation, :string_with_collation, :varchar, collation: :SQL_Latin1_General_CP437_BIN }
69
+
70
+ SstStringCollation.reset_column_information
71
+ assert_equal "SQL_Latin1_General_CP437_BIN", SstStringCollation.columns_hash['string_with_collation'].collation
72
+ end
73
+ end
74
+
75
+ describe "#create_schema" do
76
+ it "creates a new schema" do
77
+ connection.create_schema("some schema")
78
+
79
+ schemas = connection.exec_query("select name from sys.schemas").to_a
80
+
81
+ assert_includes schemas, { "name" => "some schema" }
82
+ end
83
+
84
+ it "creates a new schema with an owner" do
85
+ connection.create_schema("some schema", :guest)
86
+
87
+ schemas = connection.exec_query("select name, principal_id from sys.schemas").to_a
88
+
89
+ assert_includes schemas, { "name" => "some schema", "principal_id" => 2 }
90
+ end
91
+ end
92
+
93
+ describe "#change_table_schema" do
94
+ before { connection.create_schema("foo") }
95
+
96
+ it "transfer the given table to the given schema" do
97
+ connection.change_table_schema("foo", "orders")
98
+
99
+ assert connection.data_source_exists?("foo.orders")
100
+ end
101
+ end
102
+
103
+ describe "#drop_schema" do
104
+ before { connection.create_schema("some schema") }
105
+
106
+ it "drops a schema" do
107
+ schemas = connection.exec_query("select name from sys.schemas").to_a
108
+
109
+ assert_includes schemas, { "name" => "some schema" }
110
+
111
+ connection.drop_schema("some schema")
112
+
113
+ schemas = connection.exec_query("select name from sys.schemas").to_a
114
+
115
+ refute_includes schemas, { "name" => "some schema" }
116
+ end
66
117
  end
67
118
  end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper_sqlserver"
4
+ require "models/company"
5
+
6
+ class OptimizerHitsTestSQLServer < ActiveRecord::TestCase
7
+ fixtures :companies
8
+
9
+ it "apply optimizations" do
10
+ assert_sql(%r{\ASELECT .+ FROM .+ OPTION \(HASH GROUP\)\z}) do
11
+ companies = Company.optimizer_hints("HASH GROUP")
12
+ companies = companies.distinct.select("firm_id")
13
+ assert_includes companies.explain, "| Hash Match | Aggregate |"
14
+ end
15
+
16
+ assert_sql(%r{\ASELECT .+ FROM .+ OPTION \(ORDER GROUP\)\z}) do
17
+ companies = Company.optimizer_hints("ORDER GROUP")
18
+ companies = companies.distinct.select("firm_id")
19
+ assert_includes companies.explain, "| Stream Aggregate | Aggregate |"
20
+ end
21
+ end
22
+
23
+ it "apply multiple optimizations" do
24
+ assert_sql(%r{\ASELECT .+ FROM .+ OPTION \(HASH GROUP, FAST 1\)\z}) do
25
+ companies = Company.optimizer_hints("HASH GROUP", "FAST 1")
26
+ companies = companies.distinct.select("firm_id")
27
+ assert_includes companies.explain, "| Hash Match | Flow Distinct |"
28
+ end
29
+ end
30
+
31
+ it "support subqueries" do
32
+ assert_sql(%r{.*'SELECT COUNT\(count_column\) FROM \(SELECT .*\) subquery_for_count OPTION \(MAXDOP 2\)'.*}) do
33
+ companies = Company.optimizer_hints("MAXDOP 2")
34
+ companies = companies.select(:id).where(firm_id: [0, 1]).limit(3)
35
+ assert_equal 3, companies.count
36
+ end
37
+ end
38
+
39
+ it "sanitize values" do
40
+ assert_sql(%r{\ASELECT .+ FROM .+ OPTION \(HASH GROUP\)\z}) do
41
+ companies = Company.optimizer_hints("OPTION (HASH GROUP)")
42
+ companies = companies.distinct.select("firm_id")
43
+ companies.to_a
44
+ end
45
+
46
+ assert_sql(%r{\ASELECT .+ FROM .+ OPTION \(HASH GROUP\)\z}) do
47
+ companies = Company.optimizer_hints("OPTION(HASH GROUP)")
48
+ companies = companies.distinct.select("firm_id")
49
+ companies.to_a
50
+ end
51
+
52
+ assert_sql(%r{\ASELECT .+ FROM .+ OPTION \(TABLE HINT \(\[companies\], INDEX\(1\)\)\)\z}) do
53
+ companies = Company.optimizer_hints("OPTION(TABLE HINT ([companies], INDEX(1)))")
54
+ companies = companies.distinct.select("firm_id")
55
+ companies.to_a
56
+ end
57
+
58
+ assert_sql(%r{\ASELECT .+ FROM .+ OPTION \(HASH GROUP\)\z}) do
59
+ companies = Company.optimizer_hints("Option(HASH GROUP)")
60
+ companies = companies.distinct.select("firm_id")
61
+ companies.to_a
62
+ end
63
+ end
64
+
65
+ it "skip optimization after unscope" do
66
+ assert_sql("SELECT DISTINCT [companies].[firm_id] FROM [companies]") do
67
+ companies = Company.optimizer_hints("HASH GROUP")
68
+ companies = companies.distinct.select("firm_id")
69
+ companies.unscope(:optimizer_hints).load
70
+ end
71
+ end
72
+ end
@@ -143,4 +143,11 @@ class OrderTestSQLServer < ActiveRecord::TestCase
143
143
  assert_equal post1, Post.order(Arel.sql(order)).first
144
144
  assert_equal post2, Post.order(Arel.sql(order)).second
145
145
  end
146
+
147
+ # Executing this kind of queries will raise "A column has been specified more than once in the order by list"
148
+ # This test shows that we don't do anything to prevent this
149
+ it "doesn't deduplicate semantically equal orders" do
150
+ sql = Post.order(:id).order("posts.id ASC").to_sql
151
+ assert_equal "SELECT [posts].* FROM [posts] ORDER BY [posts].[id] ASC, posts.id ASC", sql
152
+ end
146
153
  end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper_sqlserver"
4
+ require "support/schema_dumping_helper"
5
+
6
+ class PrimaryKeyUuidTypeTest < ActiveRecord::TestCase
7
+ include SchemaDumpingHelper
8
+
9
+ self.use_transactional_tests = false
10
+
11
+ class Barcode < ActiveRecord::Base
12
+ end
13
+
14
+ setup do
15
+ @connection = ActiveRecord::Base.connection
16
+ @connection.create_table(:barcodes, primary_key: "code", id: :uuid, force: true)
17
+ end
18
+
19
+ teardown do
20
+ @connection.drop_table(:barcodes, if_exists: true)
21
+ end
22
+
23
+ def test_any_type_primary_key
24
+ assert_equal "code", Barcode.primary_key
25
+
26
+ column = Barcode.column_for_attribute(Barcode.primary_key)
27
+ assert_not column.null
28
+ assert_equal :uuid, column.type
29
+ assert_not_predicate column, :is_identity?
30
+ assert_predicate column, :is_primary?
31
+ ensure
32
+ Barcode.reset_column_information
33
+ end
34
+
35
+ test "schema dump primary key includes default" do
36
+ schema = dump_table_schema "barcodes"
37
+ assert_match %r/create_table "barcodes", primary_key: "code", id: :uuid, default: -> { "newid\(\)" }/, schema
38
+ end
39
+ end
40
+
41
+ class PrimaryKeyIntegerTest < ActiveRecord::TestCase
42
+ include SchemaDumpingHelper
43
+
44
+ self.use_transactional_tests = false
45
+
46
+ class Barcode < ActiveRecord::Base
47
+ end
48
+
49
+ class Widget < ActiveRecord::Base
50
+ end
51
+
52
+ setup do
53
+ @connection = ActiveRecord::Base.connection
54
+ end
55
+
56
+ teardown do
57
+ @connection.drop_table :barcodes, if_exists: true
58
+ @connection.drop_table :widgets, if_exists: true
59
+ end
60
+
61
+ test "integer primary key without default" do
62
+ @connection.create_table(:widgets, id: :integer, force: true)
63
+ column = @connection.columns(:widgets).find { |c| c.name == "id" }
64
+ assert_predicate column, :is_primary?
65
+ assert_predicate column, :is_identity?
66
+ assert_equal :integer, column.type
67
+ assert_not_predicate column, :bigint?
68
+
69
+ schema = dump_table_schema "widgets"
70
+ assert_match %r/create_table "widgets", id: :integer, force: :cascade do/, schema
71
+ end
72
+
73
+ test "bigint primary key without default" do
74
+ @connection.create_table(:widgets, id: :bigint, force: true)
75
+ column = @connection.columns(:widgets).find { |c| c.name == "id" }
76
+ assert_predicate column, :is_primary?
77
+ assert_predicate column, :is_identity?
78
+ assert_equal :integer, column.type
79
+ assert_predicate column, :bigint?
80
+
81
+ schema = dump_table_schema "widgets"
82
+ assert_match %r/create_table "widgets", force: :cascade do/, schema
83
+ end
84
+
85
+ test "don't set identity to integer and bigint when there is a default" do
86
+ @connection.create_table(:barcodes, id: :integer, default: nil, force: true)
87
+ @connection.create_table(:widgets, id: :bigint, default: nil, force: true)
88
+
89
+ column = @connection.columns(:widgets).find { |c| c.name == "id" }
90
+ assert_predicate column, :is_primary?
91
+ assert_not_predicate column, :is_identity?
92
+
93
+ schema = dump_table_schema "widgets"
94
+ assert_match %r/create_table "widgets", id: :bigint, default: nil, force: :cascade do/, schema
95
+
96
+ column = @connection.columns(:barcodes).find { |c| c.name == "id" }
97
+ assert_predicate column, :is_primary?
98
+ assert_not_predicate column, :is_identity?
99
+
100
+ schema = dump_table_schema "barcodes"
101
+ assert_match %r/create_table "barcodes", id: :integer, default: nil, force: :cascade do/, schema
102
+ end
103
+ end
@@ -10,8 +10,9 @@ class SQLServerRakeTest < ActiveRecord::TestCase
10
10
 
11
11
  let(:db_tasks) { ActiveRecord::Tasks::DatabaseTasks }
12
12
  let(:new_database) { "activerecord_unittest_tasks" }
13
- let(:default_configuration) { ARTest.connection_config["arunit"] }
13
+ let(:default_configuration) { ARTest.test_configuration_hashes["arunit"] }
14
14
  let(:configuration) { default_configuration.merge("database" => new_database) }
15
+ let(:db_config) { ActiveRecord::Base.configurations.resolve(configuration) }
15
16
 
16
17
  before { skip "on azure" if azure_skip }
17
18
  before { disconnect! unless azure_skip }
@@ -151,7 +152,42 @@ class SQLServerRakeStructureDumpLoadTest < SQLServerRakeTest
151
152
  _(filedata).must_match %r{CREATE TABLE dbo\.users}
152
153
  db_tasks.purge(configuration)
153
154
  _(connection.tables).wont_include "users"
154
- db_tasks.load_schema configuration, :sql, filename
155
+ db_tasks.load_schema db_config, :sql, filename
155
156
  _(connection.tables).must_include "users"
156
157
  end
157
158
  end
159
+
160
+ class SQLServerRakeSchemaCacheDumpLoadTest < SQLServerRakeTest
161
+ let(:filename) { File.join ARTest::SQLServer.test_root_sqlserver, "schema_cache.yml" }
162
+ let(:filedata) { File.read(filename) }
163
+
164
+ before do
165
+ quietly { db_tasks.create(configuration) }
166
+
167
+ connection.create_table :users, force: true do |t|
168
+ t.string :name, null: false
169
+ end
170
+ end
171
+
172
+ after do
173
+ FileUtils.rm_rf(filename)
174
+ end
175
+
176
+ it "dumps schema cache with SQL Server metadata" do
177
+ quietly { db_tasks.dump_schema_cache connection, filename }
178
+
179
+ schema_cache = YAML.load(File.read(filename))
180
+
181
+ col_id, col_name = connection.schema_cache.columns("users")
182
+
183
+ assert col_id.is_identity
184
+ assert col_id.is_primary
185
+ assert_equal col_id.ordinal_position, 1
186
+ assert_equal col_id.table_name, "users"
187
+
188
+ assert_not col_name.is_identity
189
+ assert_not col_name.is_primary
190
+ assert_equal col_name.ordinal_position, 2
191
+ assert_equal col_name.table_name, "users"
192
+ end
193
+ end