activerecord-sqlserver-adapter 8.0.10 → 8.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +1 -1
  3. data/.github/workflows/ci.yml +34 -3
  4. data/CHANGELOG.md +14 -68
  5. data/Dockerfile.ci +1 -1
  6. data/Gemfile +7 -9
  7. data/Guardfile +2 -2
  8. data/README.md +33 -13
  9. data/Rakefile +1 -1
  10. data/VERSION +1 -1
  11. data/activerecord-sqlserver-adapter.gemspec +15 -16
  12. data/compose.ci.yaml +8 -1
  13. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +1 -1
  14. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +1 -2
  15. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +1 -1
  16. data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +4 -4
  17. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +118 -83
  18. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +3 -4
  19. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +7 -7
  20. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +24 -12
  21. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +17 -8
  22. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +162 -156
  23. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +2 -2
  24. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +5 -5
  25. data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +2 -7
  26. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +3 -1
  27. data/lib/active_record/connection_adapters/sqlserver/type/data.rb +3 -3
  28. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +3 -3
  29. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +3 -4
  30. data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +1 -1
  31. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +4 -6
  32. data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +1 -1
  33. data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +0 -2
  34. data/lib/active_record/connection_adapters/sqlserver/utils.rb +10 -12
  35. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +118 -66
  36. data/lib/active_record/connection_adapters/sqlserver_column.rb +17 -9
  37. data/lib/active_record/tasks/sqlserver_database_tasks.rb +5 -5
  38. data/lib/arel/visitors/sqlserver.rb +55 -26
  39. data/test/cases/active_schema_test_sqlserver.rb +45 -23
  40. data/test/cases/adapter_test_sqlserver.rb +72 -59
  41. data/test/cases/coerced_tests.rb +365 -161
  42. data/test/cases/column_test_sqlserver.rb +328 -316
  43. data/test/cases/connection_test_sqlserver.rb +15 -11
  44. data/test/cases/enum_test_sqlserver.rb +8 -9
  45. data/test/cases/execute_procedure_test_sqlserver.rb +1 -1
  46. data/test/cases/fetch_test_sqlserver.rb +1 -1
  47. data/test/cases/helper_sqlserver.rb +7 -3
  48. data/test/cases/index_test_sqlserver.rb +8 -6
  49. data/test/cases/insert_all_test_sqlserver.rb +3 -28
  50. data/test/cases/json_test_sqlserver.rb +8 -8
  51. data/test/cases/lateral_test_sqlserver.rb +2 -2
  52. data/test/cases/migration_test_sqlserver.rb +12 -12
  53. data/test/cases/pessimistic_locking_test_sqlserver.rb +6 -6
  54. data/test/cases/primary_keys_test_sqlserver.rb +4 -4
  55. data/test/cases/rake_test_sqlserver.rb +15 -7
  56. data/test/cases/schema_dumper_test_sqlserver.rb +109 -113
  57. data/test/cases/schema_test_sqlserver.rb +7 -7
  58. data/test/cases/transaction_test_sqlserver.rb +6 -8
  59. data/test/cases/trigger_test_sqlserver.rb +1 -1
  60. data/test/cases/utils_test_sqlserver.rb +3 -3
  61. data/test/cases/view_test_sqlserver.rb +12 -8
  62. data/test/cases/virtual_column_test_sqlserver.rb +113 -0
  63. data/test/migrations/create_clients_and_change_column_collation.rb +2 -2
  64. data/test/models/sqlserver/edge_schema.rb +2 -2
  65. data/test/schema/sqlserver_specific_schema.rb +49 -37
  66. data/test/support/coerceable_test_sqlserver.rb +10 -10
  67. data/test/support/connection_reflection.rb +0 -5
  68. data/test/support/core_ext/backtrace_cleaner.rb +36 -0
  69. data/test/support/query_assertions.rb +6 -6
  70. data/test/support/rake_helpers.rb +6 -10
  71. metadata +12 -107
@@ -6,56 +6,52 @@ require "stringio"
6
6
  class SchemaDumperTestSQLServer < ActiveRecord::TestCase
7
7
  before { all_tables }
8
8
 
9
- let(:all_tables) { ActiveRecord::Base.lease_connection.tables }
10
- let(:schema) { @generated_schema }
9
+ let(:all_tables) { ActiveRecord::Base.lease_connection.tables }
10
+ let(:schema) { @generated_schema }
11
11
 
12
12
  it "sst_datatypes" do
13
13
  generate_schema_for_table "sst_datatypes"
14
14
 
15
- assert_line :bigint, type: "bigint", default: 42
16
- assert_line :int, type: "integer", default: 42
17
- assert_line :smallint, type: "integer", limit: 2, default: 42
18
- assert_line :tinyint, type: "integer", limit: 1, default: 42
19
- assert_line :bit, type: "boolean", default: true
20
- assert_line :decimal_9_2, type: "decimal", precision: 9, scale: 2, default: 12345.01
21
- assert_line :numeric_18_0, type: "decimal", precision: 18, default: 191
22
- assert_line :numeric_36_2, type: "decimal", precision: 36, scale: 2, default: 12345678901234567890.01
23
- assert_line :money, type: "money", precision: 19, scale: 4, default: 4.2
24
- assert_line :smallmoney, type: "smallmoney", precision: 10, scale: 4, default: 4.2
15
+ assert_line :bigint, type: "bigint", default: 42
16
+ assert_line :int, type: "integer", default: 42
17
+ assert_line :smallint, type: "integer", limit: 2, default: 42
18
+ assert_line :tinyint, type: "integer", limit: 1, default: 42
19
+ assert_line :bit, type: "boolean", default: true
20
+ assert_line :decimal_9_2, type: "decimal", precision: 9, scale: 2, default: 12345.01
21
+ assert_line :numeric_18_0, type: "decimal", precision: 18, default: 191
22
+ assert_line :numeric_36_2, type: "decimal", precision: 36, scale: 2, default: 12345678901234567890.01
23
+ assert_line :money, type: "money", precision: 19, scale: 4, default: 4.2
24
+ assert_line :smallmoney, type: "smallmoney", precision: 10, scale: 4, default: 4.2
25
25
  # Approximate Numerics
26
- assert_line :float, type: "float", default: 123.00000001
27
- assert_line :real, type: "real", default: 123.45
26
+ assert_line :float, type: "float", default: 123.00000001
27
+ assert_line :real, type: "real", default: 123.45
28
28
  # Date and Time
29
- assert_line :date, type: "date", default: "01-01-0001"
30
- assert_line :datetime, type: "datetime", precision: nil, default: "01-01-1753 00:00:00.123"
31
- if connection_tds_73
32
- assert_line :datetime2_7, type: "datetime", precision: 7, default: "12-31-9999 23:59:59.9999999"
33
- assert_line :datetime2_3, type: "datetime", precision: 3
34
- assert_line :datetime2_1, type: "datetime", precision: 1
35
- end
36
- assert_line :smalldatetime, type: "smalldatetime", default: "01-01-1901 15:45:00.0"
37
- if connection_tds_73
38
- assert_line :time_7, type: "time", precision: 7, default: "04:20:00.2883215"
39
- assert_line :time_2, type: "time", precision: 2
40
- assert_line :time_default, type: "time", precision: 7, default: "15:03:42.0621978"
41
- end
29
+ assert_line :date, type: "date", default: "01-01-0001"
30
+ assert_line :datetime, type: "datetime", precision: nil, default: "01-01-1753 00:00:00.123"
31
+ assert_line :datetime2_7, type: "datetime", precision: 7, default: "12-31-9999 23:59:59.9999999"
32
+ assert_line :datetime2_3, type: "datetime", precision: 3
33
+ assert_line :datetime2_1, type: "datetime", precision: 1
34
+ assert_line :smalldatetime, type: "smalldatetime", default: "01-01-1901 15:45:00.0"
35
+ assert_line :time_7, type: "time", precision: 7, default: "04:20:00.2883215"
36
+ assert_line :time_2, type: "time", precision: 2
37
+ assert_line :time_default, type: "time", precision: 7, default: "15:03:42.0621978"
42
38
  # Character Strings
43
- assert_line :char_10, type: "char", limit: 10, default: "1234567890"
44
- assert_line :varchar_50, type: "varchar", limit: 50, default: "test varchar_50"
45
- assert_line :varchar_max, type: "varchar_max", default: "test varchar_max"
46
- assert_line :text, type: "text_basic", default: "test text"
39
+ assert_line :char_10, type: "char", limit: 10, default: "1234567890"
40
+ assert_line :varchar_50, type: "varchar", limit: 50, default: "test varchar_50"
41
+ assert_line :varchar_max, type: "varchar_max", default: "test varchar_max"
42
+ assert_line :text, type: "text_basic", default: "test text"
47
43
  # Unicode Character Strings
48
- assert_line :nchar_10, type: "nchar", limit: 10, default: "12345678åå"
49
- assert_line :nvarchar_50, type: "string", limit: 50, default: "test nvarchar_50 åå"
50
- assert_line :nvarchar_max, type: "text", default: "test nvarchar_max åå"
51
- assert_line :ntext, type: "ntext", default: "test ntext åå"
44
+ assert_line :nchar_10, type: "nchar", limit: 10, default: "12345678åå"
45
+ assert_line :nvarchar_50, type: "string", limit: 50, default: "test nvarchar_50 åå"
46
+ assert_line :nvarchar_max, type: "text", default: "test nvarchar_max åå"
47
+ assert_line :ntext, type: "ntext", default: "test ntext åå"
52
48
  # Binary Strings
53
- assert_line :binary_49, type: "binary_basic", limit: 49
54
- assert_line :varbinary_49, type: "varbinary", limit: 49
55
- assert_line :varbinary_max, type: "binary"
49
+ assert_line :binary_49, type: "binary_basic", limit: 49
50
+ assert_line :varbinary_49, type: "varbinary", limit: 49
51
+ assert_line :varbinary_max, type: "binary"
56
52
  # Other Data Types
57
- assert_line :uniqueidentifier, type: "uuid", default: -> { "newid()" }
58
- assert_line :timestamp, type: "ss_timestamp"
53
+ assert_line :uniqueidentifier, type: "uuid", default: -> { "newid()" }
54
+ assert_line :timestamp, type: "ss_timestamp"
59
55
  end
60
56
 
61
57
  it "sst_datatypes_migration" do
@@ -63,80 +59,80 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
63
59
  generate_schema_for_table "sst_datatypes_migration"
64
60
 
65
61
  # Simple Rails conventions
66
- _(columns["integer_col"].sql_type).must_equal "int(4)"
67
- _(columns["bigint_col"].sql_type).must_equal "bigint(8)"
68
- _(columns["boolean_col"].sql_type).must_equal "bit"
69
- _(columns["decimal_col"].sql_type).must_equal "decimal(18,0)"
70
- _(columns["float_col"].sql_type).must_equal "float"
71
- _(columns["string_col"].sql_type).must_equal "nvarchar(4000)"
72
- _(columns["text_col"].sql_type).must_equal "nvarchar(max)"
62
+ _(columns["integer_col"].sql_type).must_equal "int(4)"
63
+ _(columns["bigint_col"].sql_type).must_equal "bigint(8)"
64
+ _(columns["boolean_col"].sql_type).must_equal "bit"
65
+ _(columns["decimal_col"].sql_type).must_equal "decimal(18,0)"
66
+ _(columns["float_col"].sql_type).must_equal "float"
67
+ _(columns["string_col"].sql_type).must_equal "nvarchar(4000)"
68
+ _(columns["text_col"].sql_type).must_equal "nvarchar(max)"
73
69
  _(columns["datetime_nil_precision_col"].sql_type).must_equal "datetime"
74
- _(columns["datetime_col"].sql_type).must_equal "datetime2(6)"
75
- _(columns["timestamp_col"].sql_type).must_equal "datetime2(6)"
76
- _(columns["time_col"].sql_type).must_equal "time(7)"
77
- _(columns["date_col"].sql_type).must_equal "date"
78
- _(columns["binary_col"].sql_type).must_equal "varbinary(max)"
79
-
80
- assert_line :integer_col, type: "integer"
81
- assert_line :bigint_col, type: "bigint"
82
- assert_line :boolean_col, type: "boolean"
83
- assert_line :decimal_col, type: "decimal", precision: 18
84
- assert_line :float_col, type: "float"
85
- assert_line :string_col, type: "string"
86
- assert_line :text_col, type: "text"
87
- assert_line :datetime_nil_precision_col, type: "datetime", precision: nil
88
- assert_line :datetime_col, type: "datetime"
89
- assert_line :datetime_col, type: "datetime"
90
- assert_line :timestamp_col, type: "datetime"
91
- assert_line :time_col, type: "time", precision: 7
92
- assert_line :date_col, type: "date"
93
- assert_line :binary_col, type: "binary"
70
+ _(columns["datetime_col"].sql_type).must_equal "datetime2(6)"
71
+ _(columns["timestamp_col"].sql_type).must_equal "datetime2(6)"
72
+ _(columns["time_col"].sql_type).must_equal "time(7)"
73
+ _(columns["date_col"].sql_type).must_equal "date"
74
+ _(columns["binary_col"].sql_type).must_equal "varbinary(max)"
75
+
76
+ assert_line :integer_col, type: "integer"
77
+ assert_line :bigint_col, type: "bigint"
78
+ assert_line :boolean_col, type: "boolean"
79
+ assert_line :decimal_col, type: "decimal", precision: 18
80
+ assert_line :float_col, type: "float"
81
+ assert_line :string_col, type: "string"
82
+ assert_line :text_col, type: "text"
83
+ assert_line :datetime_nil_precision_col, type: "datetime", precision: nil
84
+ assert_line :datetime_col, type: "datetime"
85
+ assert_line :datetime_col, type: "datetime"
86
+ assert_line :timestamp_col, type: "datetime"
87
+ assert_line :time_col, type: "time", precision: 7
88
+ assert_line :date_col, type: "date"
89
+ assert_line :binary_col, type: "binary"
94
90
 
95
91
  # Our type methods.
96
- _(columns["real_col"].sql_type).must_equal "real"
97
- _(columns["money_col"].sql_type).must_equal "money"
98
- _(columns["smalldatetime_col"].sql_type).must_equal "smalldatetime"
99
- _(columns["datetime2_col"].sql_type).must_equal "datetime2(7)"
100
- _(columns["datetimeoffset"].sql_type).must_equal "datetimeoffset(7)"
101
- _(columns["smallmoney_col"].sql_type).must_equal "smallmoney"
102
- _(columns["char_col"].sql_type).must_equal "char(1)"
103
- _(columns["varchar_col"].sql_type).must_equal "varchar(8000)"
104
- _(columns["text_basic_col"].sql_type).must_equal "text"
105
- _(columns["nchar_col"].sql_type).must_equal "nchar(1)"
106
- _(columns["ntext_col"].sql_type).must_equal "ntext"
107
- _(columns["binary_basic_col"].sql_type).must_equal "binary(1)"
92
+ _(columns["real_col"].sql_type).must_equal "real"
93
+ _(columns["money_col"].sql_type).must_equal "money"
94
+ _(columns["smalldatetime_col"].sql_type).must_equal "smalldatetime"
95
+ _(columns["datetime2_col"].sql_type).must_equal "datetime2(7)"
96
+ _(columns["datetimeoffset"].sql_type).must_equal "datetimeoffset(7)"
97
+ _(columns["smallmoney_col"].sql_type).must_equal "smallmoney"
98
+ _(columns["char_col"].sql_type).must_equal "char(1)"
99
+ _(columns["varchar_col"].sql_type).must_equal "varchar(8000)"
100
+ _(columns["text_basic_col"].sql_type).must_equal "text"
101
+ _(columns["nchar_col"].sql_type).must_equal "nchar(1)"
102
+ _(columns["ntext_col"].sql_type).must_equal "ntext"
103
+ _(columns["binary_basic_col"].sql_type).must_equal "binary(1)"
108
104
  _(columns["binary_basic_16_col"].sql_type).must_equal "binary(16)"
109
- _(columns["varbinary_col"].sql_type).must_equal "varbinary(8000)"
110
- _(columns["uuid_col"].sql_type).must_equal "uniqueidentifier"
111
- _(columns["sstimestamp_col"].sql_type).must_equal "timestamp"
112
- _(columns["json_col"].sql_type).must_equal "nvarchar(max)"
113
-
114
- assert_line :real_col, type: "real"
115
- assert_line :money_col, type: "money", precision: 19, scale: 4
116
- assert_line :smalldatetime_col, type: "smalldatetime"
117
- assert_line :datetime2_col, type: "datetime", precision: 7
118
- assert_line :datetimeoffset, type: "datetimeoffset", precision: 7
119
- assert_line :smallmoney_col, type: "smallmoney", precision: 10, scale: 4
120
- assert_line :char_col, type: "char", limit: 1
121
- assert_line :varchar_col, type: "varchar"
122
- assert_line :text_basic_col, type: "text_basic"
123
- assert_line :nchar_col, type: "nchar", limit: 1
124
- assert_line :ntext_col, type: "ntext"
125
- assert_line :binary_basic_col, type: "binary_basic", limit: 1
126
- assert_line :binary_basic_16_col, type: "binary_basic", limit: 16
127
- assert_line :varbinary_col, type: "varbinary"
128
- assert_line :uuid_col, type: "uuid"
129
- assert_line :sstimestamp_col, type: "ss_timestamp", null: false
130
- assert_line :json_col, type: "text"
105
+ _(columns["varbinary_col"].sql_type).must_equal "varbinary(8000)"
106
+ _(columns["uuid_col"].sql_type).must_equal "uniqueidentifier"
107
+ _(columns["sstimestamp_col"].sql_type).must_equal "timestamp"
108
+ _(columns["json_col"].sql_type).must_equal "nvarchar(max)"
109
+
110
+ assert_line :real_col, type: "real"
111
+ assert_line :money_col, type: "money", precision: 19, scale: 4
112
+ assert_line :smalldatetime_col, type: "smalldatetime"
113
+ assert_line :datetime2_col, type: "datetime", precision: 7
114
+ assert_line :datetimeoffset, type: "datetimeoffset", precision: 7
115
+ assert_line :smallmoney_col, type: "smallmoney", precision: 10, scale: 4
116
+ assert_line :char_col, type: "char", limit: 1
117
+ assert_line :varchar_col, type: "varchar"
118
+ assert_line :text_basic_col, type: "text_basic"
119
+ assert_line :nchar_col, type: "nchar", limit: 1
120
+ assert_line :ntext_col, type: "ntext"
121
+ assert_line :binary_basic_col, type: "binary_basic", limit: 1
122
+ assert_line :binary_basic_16_col, type: "binary_basic", limit: 16
123
+ assert_line :varbinary_col, type: "varbinary"
124
+ assert_line :uuid_col, type: "uuid"
125
+ assert_line :sstimestamp_col, type: "ss_timestamp", null: false
126
+ assert_line :json_col, type: "text"
131
127
  end
132
128
 
133
129
  it "dump column collation" do
134
- generate_schema_for_table('sst_string_collation')
130
+ generate_schema_for_table("sst_string_collation")
135
131
 
136
132
  assert_line :string_without_collation, type: "string"
137
133
  assert_line :string_default_collation, type: "varchar"
138
- assert_line :string_with_collation, type: "varchar", collation: "SQL_Latin1_General_CP1_CS_AS"
139
- assert_line :varchar_with_collation, type: "varchar", collation: "SQL_Latin1_General_CP1_CS_AS"
134
+ assert_line :string_with_collation, type: "varchar", collation: "SQL_Latin1_General_CP1_CS_AS"
135
+ assert_line :varchar_with_collation, type: "varchar", collation: "SQL_Latin1_General_CP1_CS_AS"
140
136
  end
141
137
 
142
138
  # Special Cases
@@ -145,7 +141,7 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
145
141
  generate_schema_for_table("movies") do |output|
146
142
  match = output.match(%r{create_table "movies"(.*)do})
147
143
  assert_not_nil(match, "non-standard primary key table not found")
148
- assert_match %r(primary_key: "movieid"), match[1], "non-standard primary key not preserved"
144
+ assert_match %r{primary_key: "movieid"}, match[1], "non-standard primary key not preserved"
149
145
  end
150
146
  end
151
147
 
@@ -193,7 +189,7 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
193
189
 
194
190
  @generated_schema = stream.string
195
191
  yield @generated_schema if block_given?
196
- @schema_lines = Hash.new
192
+ @schema_lines = {}
197
193
  type_matcher = /\A\s+t\.\w+\s+"(.*?)"[,\n]/
198
194
  @generated_schema.each_line do |line|
199
195
  next unless line =~ type_matcher
@@ -216,13 +212,13 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
216
212
  # Check that the expected and actual option keys.
217
213
  expected_options_keys = expected_options.keys
218
214
  expected_options_keys.delete(:type)
219
- _(expected_options_keys.sort).must_equal (line.options.keys.sort), "For column '#{column_name}' expected schema options and actual schema options do not match."
215
+ _(expected_options_keys.sort).must_equal line.options.keys.sort, "For column '#{column_name}' expected schema options and actual schema options do not match."
220
216
 
221
217
  # Check the expected and actual option values.
222
218
  expected_options.each do |key, expected|
223
- actual = key == :type ? line.send(:type_method) : line.send(key)
219
+ actual = (key == :type) ? line.send(:type_method) : line.send(key)
224
220
 
225
- message = "#{key.to_s.titleize} of #{expected.inspect} not found in:\n#{line}"
221
+ message = "#{key.to_s.titleize} of #{expected.inspect} not found in:\n#{line}"
226
222
 
227
223
  if expected.nil?
228
224
  _(actual).must_be_nil message
@@ -242,9 +238,9 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
242
238
  LINE_PARSER = %r{t\.(\w+)\s+"(.*?)"[,\s+](.*)}
243
239
 
244
240
  attr_reader :line,
245
- :type_method,
246
- :col_name,
247
- :options
241
+ :type_method,
242
+ :col_name,
243
+ :options
248
244
 
249
245
  def self.option(method_name)
250
246
  define_method(method_name) do
@@ -287,7 +283,7 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
287
283
 
288
284
  def parse_options(opts)
289
285
  if opts.present?
290
- eval "{#{opts}}"
286
+ eval("{#{opts}}", binding, __FILE__, __LINE__) # standard:disable Security/Eval
291
287
  else
292
288
  {}
293
289
  end
@@ -23,7 +23,7 @@ class SchemaTestSQLServer < ActiveRecord::TestCase
23
23
  columns = connection.columns("test.sst_schema_identity")
24
24
 
25
25
  assert_equal 2, columns.size
26
- assert_equal 1, columns.select { |c| c.is_identity? }.size
26
+ assert_equal 1, columns.count { |c| c.is_identity? }
27
27
  end
28
28
 
29
29
  it "read only column properties for table in specific schema" do
@@ -34,9 +34,9 @@ class SchemaTestSQLServer < ActiveRecord::TestCase
34
34
  assert_equal 7, test_columns.size
35
35
  assert_equal 2, dbo_columns.size
36
36
  assert_equal 2, columns.size
37
- assert_equal 1, test_columns.select { |c| c.is_identity? }.size
38
- assert_equal 1, dbo_columns.select { |c| c.is_identity? }.size
39
- assert_equal 1, columns.select { |c| c.is_identity? }.size
37
+ assert_equal 1, test_columns.count { |c| c.is_identity? }
38
+ assert_equal 1, dbo_columns.count { |c| c.is_identity? }
39
+ assert_equal 1, columns.count { |c| c.is_identity? }
40
40
  end
41
41
 
42
42
  it "return correct varchar and nvarchar column limit length when table is in non-dbo schema" do
@@ -50,7 +50,7 @@ class SchemaTestSQLServer < ActiveRecord::TestCase
50
50
  end
51
51
 
52
52
  describe "parsing table name from raw SQL" do
53
- describe 'SELECT statements' do
53
+ describe "SELECT statements" do
54
54
  it do
55
55
  assert_equal "[sst_schema_columns]", connection.send(:get_raw_table_name, "SELECT [sst_schema_columns].[id] FROM [sst_schema_columns]")
56
56
  end
@@ -72,7 +72,7 @@ class SchemaTestSQLServer < ActiveRecord::TestCase
72
72
  end
73
73
  end
74
74
 
75
- describe 'INSERT statements' do
75
+ describe "INSERT statements" do
76
76
  it do
77
77
  assert_equal "[dashboards]", connection.send(:get_raw_table_name, "INSERT INTO [dashboards] DEFAULT VALUES; SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident")
78
78
  end
@@ -124,7 +124,7 @@ class SchemaTestSQLServer < ActiveRecord::TestCase
124
124
  end
125
125
  end
126
126
 
127
- describe 'CREATE VIEW statements' do
127
+ describe "CREATE VIEW statements" do
128
128
  it do
129
129
  assert_equal "test_table_as", connection.send(:get_raw_table_name, "CREATE VIEW test_views ( test_table_a_id, test_table_b_id ) AS SELECT test_table_as.id as test_table_a_id, test_table_bs.id as test_table_b_id FROM (test_table_as with(nolock) LEFT JOIN test_table_bs with(nolock) ON (test_table_as.id = test_table_bs.test_table_a_id))")
130
130
  end
@@ -18,17 +18,15 @@ class TransactionTestSQLServer < ActiveRecord::TestCase
18
18
  end
19
19
 
20
20
  it "allow nested transactions to totally rollback" do
21
- begin
21
+ Ship.transaction do
22
+ Ship.create! name: "Black Pearl"
22
23
  Ship.transaction do
23
- Ship.create! name: "Black Pearl"
24
- Ship.transaction do
25
- Ship.create! name: "Flying Dutchman"
26
- raise "HELL"
27
- end
24
+ Ship.create! name: "Flying Dutchman"
25
+ raise "HELL"
28
26
  end
29
- rescue Exception
30
- assert_no_ships
31
27
  end
28
+ rescue
29
+ assert_no_ships
32
30
  end
33
31
 
34
32
  it "can use an isolation level and reverts back to starting isolation level" do
@@ -40,7 +40,7 @@ class SQLServerTriggerTest < ActiveRecord::TestCase
40
40
  end
41
41
 
42
42
  it "can insert into a table with composite pk with different data type with output inserted - with a hash setting for table name" do
43
- exclude_output_inserted_table_names["sst_table_with_composite_pk_trigger_with_different_data_type"] = { pk_col_one: "uniqueidentifier", pk_col_two: "int" }
43
+ exclude_output_inserted_table_names["sst_table_with_composite_pk_trigger_with_different_data_type"] = {pk_col_one: "uniqueidentifier", pk_col_two: "int"}
44
44
  assert SSTestTriggerHistory.all.empty?
45
45
  obj = SSTestTriggerCompositePkWithDefferentDataType.create! pk_col_two: 123, event_name: "test trigger"
46
46
  _(obj.event_name).must_equal "test trigger"
@@ -44,9 +44,9 @@ class UtilsTestSQLServer < ActiveRecord::TestCase
44
44
  ]
45
45
  }
46
46
 
47
- let(:server_names) { valid_names.partition { |name| name =~ /server/ } }
47
+ let(:server_names) { valid_names.partition { |name| name =~ /server/ } }
48
48
  let(:database_names) { valid_names.partition { |name| name =~ /database/ } }
49
- let(:schema_names) { valid_names.partition { |name| name =~ /schema/ } }
49
+ let(:schema_names) { valid_names.partition { |name| name =~ /schema/ } }
50
50
 
51
51
  it "extracts and returns #object identifier unquoted by default or quoted as needed" do
52
52
  valid_names.each do |n|
@@ -61,7 +61,7 @@ class UtilsTestSQLServer < ActiveRecord::TestCase
61
61
  present, blank = send(:"#{part}_names")
62
62
  present.each do |n|
63
63
  name = extract_identifiers(n)
64
- _(name.send(:"#{part}")).must_equal "#{part}", "With #{n.inspect} for ##{part} method"
64
+ _(name.send(:"#{part}")).must_equal part.to_s, "With #{n.inspect} for ##{part} method"
65
65
  _(name.send(:"#{part}_quoted")).must_equal "[#{part}]", "With #{n.inspect} for ##{part}_quoted method"
66
66
  end
67
67
  blank.each do |n|
@@ -5,14 +5,18 @@ require "cases/helper_sqlserver"
5
5
  class ViewTestSQLServer < ActiveRecord::TestCase
6
6
  let(:connection) { ActiveRecord::Base.lease_connection }
7
7
 
8
- describe 'view with default values' do
8
+ describe "view with default values" do
9
9
  before do
10
- connection.drop_table :view_casing_table rescue nil
10
+ begin
11
+ connection.drop_table :view_casing_table
12
+ rescue
13
+ nil
14
+ end
11
15
  connection.create_table :view_casing_table, force: true do |t|
12
- t.boolean :Default_Falsey, null: false, default: false
13
- t.boolean :Default_Truthy, null: false, default: true
14
- t.string :default_string_null, null: true, default: nil
15
- t.string :default_string, null: false, default: "abc"
16
+ t.boolean :Default_Falsey, null: false, default: false
17
+ t.boolean :Default_Truthy, null: false, default: true
18
+ t.string :default_string_null, null: true, default: nil
19
+ t.string :default_string, null: false, default: "abc"
16
20
  end
17
21
 
18
22
  connection.execute("DROP VIEW IF EXISTS view_casing_table_view;")
@@ -36,14 +40,14 @@ class ViewTestSQLServer < ActiveRecord::TestCase
36
40
  assert_equal false, obj.falsey
37
41
  assert_equal true, obj.truthy
38
42
  assert_equal "abc", obj.s
39
- assert_nil obj.s_null
43
+ assert_nil obj.s_null
40
44
  assert_equal 0, klass.count
41
45
 
42
46
  obj.save!
43
47
  assert_equal false, obj.falsey
44
48
  assert_equal true, obj.truthy
45
49
  assert_equal "abc", obj.s
46
- assert_nil obj.s_null
50
+ assert_nil obj.s_null
47
51
  assert_equal 1, klass.count
48
52
  end
49
53
  end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper_sqlserver"
4
+ require "support/schema_dumping_helper"
5
+
6
+ class VirtualColumnTestSQLServer < ActiveRecord::TestCase
7
+ include SchemaDumpingHelper
8
+
9
+ class VirtualColumn < ActiveRecord::Base
10
+ end
11
+
12
+ def setup
13
+ @connection = ActiveRecord::Base.lease_connection
14
+ @connection.create_table :virtual_columns, force: true do |t|
15
+ t.string :name
16
+ t.virtual :upper_name, as: "UPPER(name)", stored: true
17
+ t.virtual :lower_name, as: "LOWER(name)", stored: false
18
+ t.virtual :octet_name, as: "LEN(name)"
19
+ t.virtual :mutated_name, as: "REPLACE(name, 'l', 'L')"
20
+ t.integer :column1
21
+ end
22
+ VirtualColumn.create(name: "Rails", column1: 10)
23
+ end
24
+
25
+ def teardown
26
+ @connection.drop_table :virtual_columns, if_exists: true
27
+ VirtualColumn.reset_column_information
28
+ end
29
+
30
+ def test_virtual_column_with_full_inserts
31
+ partial_inserts_was = VirtualColumn.partial_inserts
32
+ VirtualColumn.partial_inserts = false
33
+ assert_nothing_raised do
34
+ VirtualColumn.create!(name: "Rails")
35
+ end
36
+ ensure
37
+ VirtualColumn.partial_inserts = partial_inserts_was
38
+ end
39
+
40
+ def test_stored_column
41
+ column = VirtualColumn.columns_hash["upper_name"]
42
+ assert_predicate column, :virtual?
43
+ assert_predicate column, :virtual_stored?
44
+ assert_equal "RAILS", VirtualColumn.take.upper_name
45
+ end
46
+
47
+ def test_explicit_virtual_column
48
+ column = VirtualColumn.columns_hash["lower_name"]
49
+ assert_predicate column, :virtual?
50
+ assert_not_predicate column, :virtual_stored?
51
+ assert_equal "rails", VirtualColumn.take.lower_name
52
+ end
53
+
54
+ def test_implicit_virtual_column
55
+ column = VirtualColumn.columns_hash["octet_name"]
56
+ assert_predicate column, :virtual?
57
+ assert_not_predicate column, :virtual_stored?
58
+ assert_equal 5, VirtualColumn.take.octet_name
59
+ end
60
+
61
+ def test_virtual_column_with_comma_in_definition
62
+ column = VirtualColumn.columns_hash["mutated_name"]
63
+ assert_predicate column, :virtual?
64
+ assert_not_predicate column, :virtual_stored?
65
+ assert_not_nil column.default_function
66
+ assert_equal "RaiLs", VirtualColumn.take.mutated_name
67
+ end
68
+
69
+ def test_change_table_with_stored_generated_column
70
+ @connection.change_table :virtual_columns do |t|
71
+ t.virtual :decr_column1, as: "column1 - 1", stored: true
72
+ end
73
+ VirtualColumn.reset_column_information
74
+ column = VirtualColumn.columns_hash["decr_column1"]
75
+ assert_predicate column, :virtual?
76
+ assert_predicate column, :virtual_stored?
77
+ assert_equal 9, VirtualColumn.take.decr_column1
78
+ end
79
+
80
+ def test_change_table_with_explicit_virtual_generated_column
81
+ @connection.change_table :virtual_columns do |t|
82
+ t.virtual :incr_column1, as: "column1 + 1", stored: false
83
+ end
84
+ VirtualColumn.reset_column_information
85
+ column = VirtualColumn.columns_hash["incr_column1"]
86
+ assert_predicate column, :virtual?
87
+ assert_not_predicate column, :virtual_stored?
88
+ assert_equal 11, VirtualColumn.take.incr_column1
89
+ end
90
+
91
+ def test_change_table_with_implicit_virtual_generated_column
92
+ @connection.change_table :virtual_columns do |t|
93
+ t.virtual :sqr_column1, as: "power(column1, 2)"
94
+ end
95
+ VirtualColumn.reset_column_information
96
+ column = VirtualColumn.columns_hash["sqr_column1"]
97
+ assert_predicate column, :virtual?
98
+ assert_not_predicate column, :virtual_stored?
99
+ assert_equal 100, VirtualColumn.take.sqr_column1
100
+ end
101
+
102
+ def test_schema_dumping
103
+ output = dump_table_schema("virtual_columns")
104
+ assert_match(/t\.virtual\s+"lower_name",\s+as: "\(lower\(\[name\]\)\)", stored: false$/i, output)
105
+ assert_match(/t\.virtual\s+"upper_name",\s+as: "\(upper\(\[name\]\)\)", stored: true$/i, output)
106
+ assert_match(/t\.virtual\s+"octet_name",\s+as: "\(len\(\[name\]\)\)", stored: false$/i, output)
107
+ end
108
+
109
+ def test_build_fixture_sql
110
+ fixtures = ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT, :virtual_columns).first
111
+ assert_equal 2, fixtures.size
112
+ end
113
+ end
@@ -9,8 +9,8 @@ class CreateClientsAndChangeColumnCollation < ActiveRecord::Migration[5.2]
9
9
  t.timestamps
10
10
  end
11
11
 
12
- change_column :clients, :name, :string, collation: 'SQL_Latin1_General_CP1_CS_AS'
13
- change_column :clients, :code, :string, collation: 'SQL_Latin1_General_CP1_CI_AS'
12
+ change_column :clients, :name, :string, collation: "SQL_Latin1_General_CP1_CS_AS"
13
+ change_column :clients, :code, :string, collation: "SQL_Latin1_General_CP1_CI_AS"
14
14
  end
15
15
 
16
16
  def down
@@ -4,10 +4,10 @@ class SSTestEdgeSchema < ActiveRecord::Base
4
4
  self.table_name = "sst_edge_schemas"
5
5
 
6
6
  def with_spaces
7
- read_attribute :'with spaces'
7
+ read_attribute :"with spaces"
8
8
  end
9
9
 
10
10
  def with_spaces=(value)
11
- write_attribute :'with spaces', value
11
+ write_attribute :"with spaces", value
12
12
  end
13
13
  end