activerecord-sqlserver-adapter 7.1.0.rc2 → 7.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ddd1e2bb81c9a6675d4a8f561c585869b0fafb6ecfe3c513e7e69d8bc3646d9f
4
- data.tar.gz: 0d669eaaa14be843acc19cc887c47a3f8eecfb3552e8477a062df688d9ef1172
3
+ metadata.gz: 670622c4f84954789b5050d84bbe47ce3235a614bcd12a083716d9c2c8b775c7
4
+ data.tar.gz: 07720ea291eabf91fbb2def06c493a423795533a08394a2837faff4825ef660a
5
5
  SHA512:
6
- metadata.gz: 879aeb90caaef5bb0218651407ec5a978d4a62d51682e92d55fbda2d3eed2fd37e8348e72aa8c4c92cab856c8eebc2fa4bf1c2166ad13d99c983f1310d3b66ab
7
- data.tar.gz: 15030862f3ae2044dd780a62f4a8868dc383cd6e9775fcedff214b1429bdbf2881be503e670cf2cbcfcbe92c0583c2a89d53f30ddd988a5425649ff29ef2c971
6
+ metadata.gz: 0144e10d2f2670cf7ab24fc9e5ca50351474b09e82a8d2322a4a402ce5d3365e697f487db5741b9b8199afbe68319093d7c14cd3fbfecce49f041d8b3ee295d7
7
+ data.tar.gz: c4d3666c0f01d14e7985651cbd7fd40da9e5bfb03e509e53a5709fe0fcd956efff3d01bdb7a97c12037c80a1588c8afa34e1eaad11623341ba748cff9195e112
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## v7.1.1
2
+
3
+ #### Fixed
4
+
5
+ - [#1145](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1145) Ensure correct order of COLLATE and NOT NULL in CREATE TABLE statements
6
+ - [#1144](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1144) Fix precision handling in time migration
7
+ - [#1143](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1143) Fix precision handling for datetimeoffset migration
8
+
9
+ ## v7.1.0
10
+
11
+ #### Added
12
+
13
+ - [#1141](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1141) Added support for check constraints.
14
+
1
15
  ## v7.1.0.rc2
2
16
 
3
17
  #### Added
data/README.md CHANGED
@@ -11,16 +11,16 @@ The SQL Server adapter for ActiveRecord using SQL Server 2012 or higher.
11
11
 
12
12
  Interested in older versions? We follow a rational versioning policy that tracks Rails. That means that our 7.x version of the adapter is only for the latest 7.x version of Rails. If you need the adapter for SQL Server 2008 or 2005, you are still in the right spot. Just install the latest 3.2.x to 4.1.x version of the adapter that matches your Rails version. We also have stable branches for each major/minor release of ActiveRecord.
13
13
 
14
- | Adapter Version | Rails Version | Support | Branch |
15
- |-----------------|---------------|----------------|-------------------------------------------------------------------------------------------------|
16
- | `7.1.0.rc2` | `7.1.x` | In development | [main](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/main) |
17
- | `7.0.5.1` | `7.0.x` | Active | [7-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-0-stable) |
18
- | `6.1.3.0` | `6.1.x` | Active | [6-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-1-stable) |
19
- | `6.0.3` | `6.0.x` | Ended | [6-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-0-stable) |
20
- | `5.2.1` | `5.2.x` | Ended | [5-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-2-stable) |
21
- | `5.1.6` | `5.1.x` | Ended | [5-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-1-stable) |
22
- | `4.2.18` | `4.2.x` | Ended | [4-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-2-stable) |
23
- | `4.1.8` | `4.1.x` | Ended | [4-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-1-stable) |
14
+ | Adapter Version | Rails Version | Support | Branch |
15
+ |-----------------|---------------|---------|--------------------------------------------------------------------------------------------------|
16
+ | `7.1.1` | `7.1.x` | Active | [main](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/main) |
17
+ | `7.0.5.1` | `7.0.x` | Active | [7-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-0-stable) |
18
+ | `6.1.3.0` | `6.1.x` | Active | [6-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-1-stable) |
19
+ | `6.0.3` | `6.0.x` | Ended | [6-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-0-stable) |
20
+ | `5.2.1` | `5.2.x` | Ended | [5-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-2-stable) |
21
+ | `5.1.6` | `5.1.x` | Ended | [5-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-1-stable) |
22
+ | `4.2.18` | `4.2.x` | Ended | [4-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-2-stable) |
23
+ | `4.1.8` | `4.1.x` | Ended | [4-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-1-stable) |
24
24
 
25
25
  For older versions, please check their stable branches.
26
26
 
@@ -100,7 +100,7 @@ module ActiveRecord
100
100
  class SQLServerAdapter < AbstractAdapter
101
101
  def configure_connection
102
102
  super
103
- raw_connection_do "SET TEXTSIZE #{64.megabytes}"
103
+ @raw_connection.execute("SET TEXTSIZE #{64.megabytes}").do
104
104
  end
105
105
  end
106
106
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 7.1.0.rc2
1
+ 7.1.1
@@ -51,12 +51,12 @@ module ActiveRecord
51
51
 
52
52
  def add_column_options!(sql, options)
53
53
  sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
54
- if options[:null] == false
55
- sql << " NOT NULL"
56
- end
57
54
  if options[:collation].present?
58
55
  sql << " COLLATE #{options[:collation]}"
59
56
  end
57
+ if options[:null] == false
58
+ sql << " NOT NULL"
59
+ end
60
60
  if options[:is_identity] == true
61
61
  sql << " IDENTITY(1,1)"
62
62
  end
@@ -267,6 +267,29 @@ module ActiveRecord
267
267
  end
268
268
  end
269
269
 
270
+ def check_constraints(table_name)
271
+ sql = <<~SQL
272
+ select chk.name AS 'name',
273
+ chk.definition AS 'expression'
274
+ from sys.check_constraints chk
275
+ inner join sys.tables st on chk.parent_object_id = st.object_id
276
+ where
277
+ st.name = '#{table_name}'
278
+ SQL
279
+
280
+ chk_info = internal_exec_query(sql, "SCHEMA")
281
+
282
+ chk_info.map do |row|
283
+ options = {
284
+ name: row["name"]
285
+ }
286
+ expression = row["expression"]
287
+ expression = expression[1..-2] if expression.start_with?("(") && expression.end_with?(")")
288
+
289
+ CheckConstraintDefinition.new(table_name, expression, options)
290
+ end
291
+ end
292
+
270
293
  def type_to_sql(type, limit: nil, precision: nil, scale: nil, **)
271
294
  type_limitable = %w(string integer float char nchar varchar nvarchar).include?(type.to_s)
272
295
  limit = nil unless type_limitable
@@ -280,6 +303,16 @@ module ActiveRecord
280
303
  when 5..8 then "bigint"
281
304
  else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
282
305
  end
306
+ when "time" # https://learn.microsoft.com/en-us/sql/t-sql/data-types/time-transact-sql
307
+ column_type_sql = type.to_s
308
+ if precision
309
+ if (0..7) === precision
310
+ column_type_sql << "(#{precision})"
311
+ else
312
+ raise(ActiveRecordError, "The time type has precision of #{precision}. The allowed range of precision is from 0 to 7")
313
+ end
314
+ end
315
+ column_type_sql
283
316
  when "datetime2"
284
317
  column_type_sql = super
285
318
  if precision
@@ -290,6 +323,16 @@ module ActiveRecord
290
323
  end
291
324
  end
292
325
  column_type_sql
326
+ when "datetimeoffset"
327
+ column_type_sql = super
328
+ if precision
329
+ if (0..7) === precision
330
+ column_type_sql << "(#{precision})"
331
+ else
332
+ raise(ActiveRecordError, "The datetimeoffset type has precision of #{precision}. The allowed range of precision is from 0 to 7")
333
+ end
334
+ end
335
+ column_type_sql
293
336
  else
294
337
  super
295
338
  end
@@ -171,6 +171,10 @@ module ActiveRecord
171
171
  true
172
172
  end
173
173
 
174
+ def supports_check_constraints?
175
+ true
176
+ end
177
+
174
178
  def supports_json?
175
179
  version_year >= 2016
176
180
  end
@@ -3,43 +3,43 @@
3
3
  require "cases/helper_sqlserver"
4
4
 
5
5
  class ActiveSchemaTestSQLServer < ActiveRecord::TestCase
6
- before do
7
- connection.create_table :schema_test_table, force: true, id: false do |t|
8
- t.column :foo, :string, limit: 100
9
- t.column :state, :string
6
+ describe "indexes" do
7
+ before do
8
+ connection.create_table :schema_test_table, force: true, id: false do |t|
9
+ t.column :foo, :string, limit: 100
10
+ t.column :state, :string
11
+ end
10
12
  end
11
- end
12
13
 
13
- after do
14
- connection.drop_table :schema_test_table rescue nil
15
- end
14
+ after do
15
+ connection.drop_table :schema_test_table rescue nil
16
+ end
16
17
 
17
- it 'default index' do
18
- assert_sql('CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
19
- connection.add_index :schema_test_table, "foo"
18
+ it 'default index' do
19
+ assert_sql('CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
20
+ connection.add_index :schema_test_table, "foo"
21
+ end
20
22
  end
21
- end
22
23
 
23
- it 'unique index' do
24
- assert_sql('CREATE UNIQUE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
25
- connection.add_index :schema_test_table, "foo", unique: true
24
+ it 'unique index' do
25
+ assert_sql('CREATE UNIQUE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
26
+ connection.add_index :schema_test_table, "foo", unique: true
27
+ end
26
28
  end
27
- end
28
29
 
29
- it 'where condition on index' do
30
- assert_sql("CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo]) WHERE state = 'active'") do
31
- connection.add_index :schema_test_table, "foo", where: "state = 'active'"
30
+ it 'where condition on index' do
31
+ assert_sql("CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo]) WHERE state = 'active'") do
32
+ connection.add_index :schema_test_table, "foo", where: "state = 'active'"
33
+ end
32
34
  end
33
- end
34
35
 
35
- it 'if index does not exist' do
36
- assert_sql("IF NOT EXISTS (SELECT name FROM sysindexes WHERE name = 'index_schema_test_table_on_foo') " \
37
- "CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])") do
38
- connection.add_index :schema_test_table, "foo", if_not_exists: true
36
+ it 'if index does not exist' do
37
+ assert_sql("IF NOT EXISTS (SELECT name FROM sysindexes WHERE name = 'index_schema_test_table_on_foo') " \
38
+ "CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])") do
39
+ connection.add_index :schema_test_table, "foo", if_not_exists: true
40
+ end
39
41
  end
40
- end
41
42
 
42
- describe "index types" do
43
43
  it 'clustered index' do
44
44
  assert_sql('CREATE CLUSTERED INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
45
45
  connection.add_index :schema_test_table, "foo", type: :clustered
@@ -52,4 +52,76 @@ class ActiveSchemaTestSQLServer < ActiveRecord::TestCase
52
52
  end
53
53
  end
54
54
  end
55
+
56
+ describe 'collation' do
57
+ it "create column with NOT NULL and COLLATE" do
58
+ assert_nothing_raised do
59
+ connection.create_table :not_null_with_collation_table, force: true, id: false do |t|
60
+ t.text :not_null_text_with_collation, null: false, collation: "Latin1_General_CS_AS"
61
+ end
62
+ end
63
+ ensure
64
+ connection.drop_table :not_null_with_collation_table rescue nil
65
+ end
66
+ end
67
+
68
+ describe 'datetimeoffset precision' do
69
+ it 'valid precisions are correct' do
70
+ assert_nothing_raised do
71
+ connection.create_table :datetimeoffset_precisions do |t|
72
+ t.datetimeoffset :precision_default
73
+ t.datetimeoffset :precision_5, precision: 5
74
+ t.datetimeoffset :precision_7, precision: 7
75
+ end
76
+ end
77
+
78
+ columns = connection.columns("datetimeoffset_precisions")
79
+
80
+ assert_equal columns.find { |column| column.name == "precision_default" }.precision, 7
81
+ assert_equal columns.find { |column| column.name == "precision_5" }.precision, 5
82
+ assert_equal columns.find { |column| column.name == "precision_7" }.precision, 7
83
+ ensure
84
+ connection.drop_table :datetimeoffset_precisions rescue nil
85
+ end
86
+
87
+ it 'invalid precision raises exception' do
88
+ assert_raise(ActiveRecord::ActiveRecordError) do
89
+ connection.create_table :datetimeoffset_precisions do |t|
90
+ t.datetimeoffset :precision_8, precision: 8
91
+ end
92
+ end
93
+ ensure
94
+ connection.drop_table :datetimeoffset_precisions rescue nil
95
+ end
96
+ end
97
+
98
+ describe 'time precision' do
99
+ it 'valid precisions are correct' do
100
+ assert_nothing_raised do
101
+ connection.create_table :time_precisions do |t|
102
+ t.time :precision_default
103
+ t.time :precision_5, precision: 5
104
+ t.time :precision_7, precision: 7
105
+ end
106
+ end
107
+
108
+ columns = connection.columns("time_precisions")
109
+
110
+ assert_equal columns.find { |column| column.name == "precision_default" }.precision, 7
111
+ assert_equal columns.find { |column| column.name == "precision_5" }.precision, 5
112
+ assert_equal columns.find { |column| column.name == "precision_7" }.precision, 7
113
+ ensure
114
+ connection.drop_table :time_precisions rescue nil
115
+ end
116
+
117
+ it 'invalid precision raises exception' do
118
+ assert_raise(ActiveRecord::ActiveRecordError) do
119
+ connection.create_table :time_precisions do |t|
120
+ t.time :precision_8, precision: 8
121
+ end
122
+ end
123
+ ensure
124
+ connection.drop_table :time_precisions rescue nil
125
+ end
126
+ end
55
127
  end
@@ -1580,6 +1580,13 @@ class SchemaDumperTest < ActiveRecord::TestCase
1580
1580
 
1581
1581
  # Tests are not about a specific adapter.
1582
1582
  coerce_tests! :test_do_not_dump_foreign_keys_when_bypassed_by_config
1583
+
1584
+ # SQL Server formats the check constraint expression differently.
1585
+ coerce_tests! :test_schema_dumps_check_constraints
1586
+ def test_schema_dumps_check_constraints_coerced
1587
+ constraint_definition = dump_table_schema("products").split(/\n/).grep(/t.check_constraint.*products_price_check/).first.strip
1588
+ assert_equal 't.check_constraint "[price]>[discounted_price]", name: "products_price_check"', constraint_definition
1589
+ end
1583
1590
  end
1584
1591
 
1585
1592
  class SchemaDumperDefaultsTest < ActiveRecord::TestCase
@@ -1825,6 +1832,9 @@ class TimePrecisionTest < ActiveRecord::TestCase
1825
1832
 
1826
1833
  # SQL Server uses default precision for time.
1827
1834
  coerce_tests! :test_no_time_precision_isnt_truncated_on_assignment
1835
+
1836
+ # SQL Server accepts precision of 7 for time.
1837
+ coerce_tests! :test_invalid_time_precision_raises_error
1828
1838
  end
1829
1839
 
1830
1840
  class DefaultNumbersTest < ActiveRecord::TestCase
@@ -2585,3 +2595,54 @@ module ActiveRecord
2585
2595
  end
2586
2596
  end
2587
2597
  end
2598
+
2599
+ module ActiveRecord
2600
+ class Migration
2601
+ class CheckConstraintTest < ActiveRecord::TestCase
2602
+ # SQL Server formats the check constraint expression differently.
2603
+ coerce_tests! :test_check_constraints
2604
+ def test_check_constraints_coerced
2605
+ check_constraints = @connection.check_constraints("products")
2606
+ assert_equal 1, check_constraints.size
2607
+
2608
+ constraint = check_constraints.first
2609
+ assert_equal "products", constraint.table_name
2610
+ assert_equal "products_price_check", constraint.name
2611
+ assert_equal "[price]>[discounted_price]", constraint.expression
2612
+ end
2613
+
2614
+ # SQL Server formats the check constraint expression differently.
2615
+ coerce_tests! :test_add_check_constraint
2616
+ def test_add_check_constraint_coerced
2617
+ @connection.add_check_constraint :trades, "quantity > 0"
2618
+
2619
+ check_constraints = @connection.check_constraints("trades")
2620
+ assert_equal 1, check_constraints.size
2621
+
2622
+ constraint = check_constraints.first
2623
+ assert_equal "trades", constraint.table_name
2624
+ assert_equal "chk_rails_2189e9f96c", constraint.name
2625
+ assert_equal "[quantity]>(0)", constraint.expression
2626
+ end
2627
+
2628
+ # SQL Server formats the check constraint expression differently.
2629
+ coerce_tests! :test_remove_check_constraint
2630
+ def test_remove_check_constraint_coerced
2631
+ @connection.add_check_constraint :trades, "price > 0", name: "price_check"
2632
+ @connection.add_check_constraint :trades, "quantity > 0", name: "quantity_check"
2633
+
2634
+ assert_equal 2, @connection.check_constraints("trades").size
2635
+ @connection.remove_check_constraint :trades, name: "quantity_check"
2636
+ assert_equal 1, @connection.check_constraints("trades").size
2637
+
2638
+ constraint = @connection.check_constraints("trades").first
2639
+ assert_equal "trades", constraint.table_name
2640
+ assert_equal "price_check", constraint.name
2641
+ assert_equal "[price]>(0)", constraint.expression
2642
+
2643
+ @connection.remove_check_constraint :trades, name: :price_check # name as a symbol
2644
+ assert_empty @connection.check_constraints("trades")
2645
+ end
2646
+ end
2647
+ end
2648
+ end
@@ -435,13 +435,15 @@ class ColumnTestSQLServer < ActiveRecord::TestCase
435
435
  _(type.limit).must_be_nil
436
436
  _(type.precision).must_equal 7
437
437
  _(type.scale).must_be_nil
438
- # Can save 100 nanosecond precisoins and return again.
438
+
439
+ # Can save 100 nanosecond precisions and return again.
439
440
  obj.datetimeoffset_7 = Time.new(2010, 4, 1, 12, 34, 56, +18000).change(nsec: 123456755)
440
441
  _(obj.datetimeoffset_7).must_equal Time.new(2010, 4, 1, 12, 34, 56, +18000).change(nsec: 123456800), "Nanoseconds were <#{obj.datetimeoffset_7.nsec}> vs <123456800>"
441
442
  obj.save!
442
443
  _(obj.datetimeoffset_7).must_equal Time.new(2010, 4, 1, 12, 34, 56, +18000).change(nsec: 123456800), "Nanoseconds were <#{obj.datetimeoffset_7.nsec}> vs <123456800>"
443
444
  obj.reload
444
445
  _(obj.datetimeoffset_7).must_equal Time.new(2010, 4, 1, 12, 34, 56, +18000).change(nsec: 123456800), "Nanoseconds were <#{obj.datetimeoffset_7.nsec}> vs <123456800>"
446
+
445
447
  # Maintains the timezone
446
448
  time = ActiveSupport::TimeZone["America/Los_Angeles"].local 2010, 12, 31, 23, 59, 59, Rational(123456800, 1000)
447
449
  obj.datetimeoffset_7 = time
@@ -449,6 +451,7 @@ class ColumnTestSQLServer < ActiveRecord::TestCase
449
451
  obj.save!
450
452
  _(obj.datetimeoffset_7).must_equal time
451
453
  _(obj.reload.datetimeoffset_7).must_equal time
454
+
452
455
  # With other precisions.
453
456
  time = ActiveSupport::TimeZone["America/Los_Angeles"].local 2010, 12, 31, 23, 59, 59, Rational(123456755, 1000)
454
457
  col = column("datetimeoffset_3")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-sqlserver-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.1.0.rc2
4
+ version: 7.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ken Collins
@@ -15,7 +15,7 @@ authors:
15
15
  autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
- date: 2023-11-14 00:00:00.000000000 Z
18
+ date: 2024-01-08 00:00:00.000000000 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: activerecord
@@ -235,8 +235,8 @@ licenses:
235
235
  - MIT
236
236
  metadata:
237
237
  bug_tracker_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues
238
- changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v7.1.0.rc2/CHANGELOG.md
239
- source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v7.1.0.rc2
238
+ changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v7.1.1/CHANGELOG.md
239
+ source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v7.1.1
240
240
  post_install_message:
241
241
  rdoc_options: []
242
242
  require_paths:
@@ -248,9 +248,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
248
248
  version: 2.7.0
249
249
  required_rubygems_version: !ruby/object:Gem::Requirement
250
250
  requirements:
251
- - - ">"
251
+ - - ">="
252
252
  - !ruby/object:Gem::Version
253
- version: 1.3.1
253
+ version: '0'
254
254
  requirements: []
255
255
  rubygems_version: 3.4.7
256
256
  signing_key: