activerecord-jdbcsqlserver-adapter 50.0.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 (148) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.travis.yml +27 -0
  4. data/CHANGELOG.md +124 -0
  5. data/CODE_OF_CONDUCT.md +31 -0
  6. data/Dockerfile +20 -0
  7. data/Gemfile +77 -0
  8. data/Guardfile +29 -0
  9. data/MIT-LICENSE +20 -0
  10. data/RAILS5-TODO.md +5 -0
  11. data/README.md +93 -0
  12. data/RUNNING_UNIT_TESTS.md +96 -0
  13. data/Rakefile +46 -0
  14. data/VERSION +1 -0
  15. data/activerecord-jdbcsqlserver-adapter.gemspec +21 -0
  16. data/appveyor.yml +39 -0
  17. data/docker-compose.ci.yml +11 -0
  18. data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +27 -0
  19. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +25 -0
  20. data/lib/active_record/connection_adapters/sqlserver/core_ext/date_time.rb +58 -0
  21. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +47 -0
  22. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +4 -0
  23. data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +49 -0
  24. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +362 -0
  25. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +67 -0
  26. data/lib/active_record/connection_adapters/sqlserver/errors.rb +7 -0
  27. data/lib/active_record/connection_adapters/sqlserver/jdbc_overrides.rb +192 -0
  28. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +99 -0
  29. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +34 -0
  30. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +16 -0
  31. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +517 -0
  32. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +66 -0
  33. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +66 -0
  34. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +22 -0
  35. data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +20 -0
  36. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +112 -0
  37. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +64 -0
  38. data/lib/active_record/connection_adapters/sqlserver/type.rb +49 -0
  39. data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +19 -0
  40. data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +21 -0
  41. data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +15 -0
  42. data/lib/active_record/connection_adapters/sqlserver/type/char.rb +32 -0
  43. data/lib/active_record/connection_adapters/sqlserver/type/data.rb +30 -0
  44. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +61 -0
  45. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +71 -0
  46. data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +17 -0
  47. data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +23 -0
  48. data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +21 -0
  49. data/lib/active_record/connection_adapters/sqlserver/type/float.rb +19 -0
  50. data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +15 -0
  51. data/lib/active_record/connection_adapters/sqlserver/type/json.rb +11 -0
  52. data/lib/active_record/connection_adapters/sqlserver/type/money.rb +25 -0
  53. data/lib/active_record/connection_adapters/sqlserver/type/real.rb +19 -0
  54. data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +15 -0
  55. data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +25 -0
  56. data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +29 -0
  57. data/lib/active_record/connection_adapters/sqlserver/type/string.rb +12 -0
  58. data/lib/active_record/connection_adapters/sqlserver/type/text.rb +19 -0
  59. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +68 -0
  60. data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +93 -0
  61. data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +19 -0
  62. data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +25 -0
  63. data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +21 -0
  64. data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +12 -0
  65. data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +19 -0
  66. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +26 -0
  67. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +24 -0
  68. data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +36 -0
  69. data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +26 -0
  70. data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +24 -0
  71. data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +26 -0
  72. data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +24 -0
  73. data/lib/active_record/connection_adapters/sqlserver/utils.rb +146 -0
  74. data/lib/active_record/connection_adapters/sqlserver/version.rb +11 -0
  75. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +445 -0
  76. data/lib/active_record/connection_adapters/sqlserver_column.rb +28 -0
  77. data/lib/active_record/jdbc_sqlserver_connection_methods.rb +31 -0
  78. data/lib/active_record/sqlserver_base.rb +16 -0
  79. data/lib/active_record/tasks/sqlserver_database_tasks.rb +131 -0
  80. data/lib/activerecord-jdbcsqlserver-adapter.rb +24 -0
  81. data/lib/activerecord-sqlserver-adapter.rb +1 -0
  82. data/lib/arel/visitors/sqlserver.rb +205 -0
  83. data/lib/arel_sqlserver.rb +3 -0
  84. data/test/appveyor/dbsetup.ps1 +27 -0
  85. data/test/appveyor/dbsetup.sql +11 -0
  86. data/test/bin/wait-for.sh +79 -0
  87. data/test/cases/adapter_test_sqlserver.rb +430 -0
  88. data/test/cases/coerced_tests.rb +845 -0
  89. data/test/cases/column_test_sqlserver.rb +812 -0
  90. data/test/cases/connection_test_sqlserver.rb +71 -0
  91. data/test/cases/execute_procedure_test_sqlserver.rb +45 -0
  92. data/test/cases/fetch_test_sqlserver.rb +57 -0
  93. data/test/cases/fully_qualified_identifier_test_sqlserver.rb +76 -0
  94. data/test/cases/helper_sqlserver.rb +44 -0
  95. data/test/cases/index_test_sqlserver.rb +47 -0
  96. data/test/cases/json_test_sqlserver.rb +32 -0
  97. data/test/cases/migration_test_sqlserver.rb +61 -0
  98. data/test/cases/order_test_sqlserver.rb +147 -0
  99. data/test/cases/pessimistic_locking_test_sqlserver.rb +94 -0
  100. data/test/cases/rake_test_sqlserver.rb +169 -0
  101. data/test/cases/schema_dumper_test_sqlserver.rb +234 -0
  102. data/test/cases/schema_test_sqlserver.rb +54 -0
  103. data/test/cases/scratchpad_test_sqlserver.rb +8 -0
  104. data/test/cases/showplan_test_sqlserver.rb +65 -0
  105. data/test/cases/specific_schema_test_sqlserver.rb +180 -0
  106. data/test/cases/transaction_test_sqlserver.rb +91 -0
  107. data/test/cases/utils_test_sqlserver.rb +129 -0
  108. data/test/cases/uuid_test_sqlserver.rb +49 -0
  109. data/test/config.yml +38 -0
  110. data/test/debug.rb +14 -0
  111. data/test/fixtures/1px.gif +0 -0
  112. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +11 -0
  113. data/test/models/sqlserver/booking.rb +3 -0
  114. data/test/models/sqlserver/customers_view.rb +3 -0
  115. data/test/models/sqlserver/datatype.rb +3 -0
  116. data/test/models/sqlserver/datatype_migration.rb +8 -0
  117. data/test/models/sqlserver/dollar_table_name.rb +3 -0
  118. data/test/models/sqlserver/dot_table_name.rb +3 -0
  119. data/test/models/sqlserver/edge_schema.rb +13 -0
  120. data/test/models/sqlserver/fk_has_fk.rb +3 -0
  121. data/test/models/sqlserver/fk_has_pk.rb +3 -0
  122. data/test/models/sqlserver/natural_pk_data.rb +4 -0
  123. data/test/models/sqlserver/natural_pk_int_data.rb +3 -0
  124. data/test/models/sqlserver/no_pk_data.rb +3 -0
  125. data/test/models/sqlserver/object_default.rb +3 -0
  126. data/test/models/sqlserver/quoted_table.rb +7 -0
  127. data/test/models/sqlserver/quoted_view_1.rb +3 -0
  128. data/test/models/sqlserver/quoted_view_2.rb +3 -0
  129. data/test/models/sqlserver/sst_memory.rb +3 -0
  130. data/test/models/sqlserver/string_default.rb +3 -0
  131. data/test/models/sqlserver/string_defaults_big_view.rb +3 -0
  132. data/test/models/sqlserver/string_defaults_view.rb +3 -0
  133. data/test/models/sqlserver/tinyint_pk.rb +3 -0
  134. data/test/models/sqlserver/upper.rb +3 -0
  135. data/test/models/sqlserver/uppered.rb +3 -0
  136. data/test/models/sqlserver/uuid.rb +3 -0
  137. data/test/schema/datatypes/2012.sql +55 -0
  138. data/test/schema/enable-in-memory-oltp.sql +81 -0
  139. data/test/schema/sqlserver_specific_schema.rb +238 -0
  140. data/test/support/coerceable_test_sqlserver.rb +49 -0
  141. data/test/support/connection_reflection.rb +34 -0
  142. data/test/support/load_schema_sqlserver.rb +29 -0
  143. data/test/support/minitest_sqlserver.rb +1 -0
  144. data/test/support/paths_sqlserver.rb +50 -0
  145. data/test/support/rake_helpers.rb +41 -0
  146. data/test/support/sql_counter_sqlserver.rb +28 -0
  147. data/test/support/test_in_memory_oltp.rb +15 -0
  148. metadata +310 -0
@@ -0,0 +1,71 @@
1
+ require 'cases/helper_sqlserver'
2
+ require 'models/reply'
3
+ require 'models/topic'
4
+
5
+ class ConnectionTestSQLServer < ActiveRecord::TestCase
6
+
7
+ self.use_transactional_tests = false
8
+
9
+ fixtures :topics, :accounts
10
+
11
+ before do
12
+ connection.reconnect!
13
+ assert connection.active?
14
+ end
15
+
16
+ it 'affect rows' do
17
+ topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
18
+ updated = Topic.update(topic_data.keys, topic_data.values)
19
+ assert_equal 2, updated.size
20
+ assert_equal "1 updated", Topic.find(1).content
21
+ assert_equal "2 updated", Topic.find(2).content
22
+ assert_equal 2, Topic.delete([1, 2])
23
+ end
24
+
25
+ it 'allow usage of :database connection option to remove setting from dsn' do
26
+ assert_equal 'activerecord_unittest', connection.current_database
27
+ begin
28
+ connection.use_database('activerecord_unittest2')
29
+ assert_equal 'activerecord_unittest2', connection.current_database
30
+ ensure
31
+ connection.use_database
32
+ assert_equal 'activerecord_unittest', connection.current_database, 'Would default back to connection options'
33
+ end
34
+ end unless connection_sqlserver_azure?
35
+
36
+ describe 'Connection management' do
37
+
38
+ it 'set spid on connect' do
39
+ ['Fixnum', 'Integer'].must_include connection.spid.class.name
40
+ end
41
+
42
+ it 'reset spid on disconnect!' do
43
+ connection.disconnect!
44
+ assert connection.spid.nil?
45
+ end
46
+
47
+ it 'reset the connection' do
48
+ connection.disconnect!
49
+ connection.raw_connection.must_be_nil
50
+ end unless defined? JRUBY_VERSION
51
+
52
+ it 'be able to disconnect and reconnect at will' do
53
+ disconnect_raw_connection!
54
+ assert !connection.active?
55
+ connection.reconnect!
56
+ assert connection.active?
57
+ end
58
+
59
+ end
60
+
61
+
62
+ private
63
+
64
+ def disconnect_raw_connection!
65
+ #case connection_options[:mode]
66
+ #when :dblib
67
+ connection.raw_connection.close #rescue nil
68
+ #end
69
+ end
70
+
71
+ end
@@ -0,0 +1,45 @@
1
+ require 'cases/helper_sqlserver'
2
+
3
+ class ExecuteProcedureTestSQLServer < ActiveRecord::TestCase
4
+
5
+ it 'execute a simple procedure' do
6
+ tables = ActiveRecord::Base.execute_procedure :sp_tables
7
+ assert_instance_of Array, tables
8
+ assert tables.first.respond_to?(:keys)
9
+ end
10
+
11
+ it 'take parameter arguments' do
12
+ tables = ActiveRecord::Base.execute_procedure :sp_tables, 'sst_datatypes'
13
+ table_info = tables.first
14
+ assert_equal 1, tables.size
15
+ assert_equal (ENV['ARUNIT_DB_NAME'] || 'activerecord_unittest'), table_info['TABLE_QUALIFIER'], "Table Info: #{table_info.inspect}"
16
+ assert_equal 'TABLE', table_info['TABLE_TYPE'], "Table Info: #{table_info.inspect}"
17
+ end
18
+
19
+ it 'allow multiple result sets to be returned' do
20
+ skip 'For whatever reason, this stored procedure is only returning 1 result so this test does not work' if defined? JRUBY_VERSION
21
+ results1, results2 = ActiveRecord::Base.execute_procedure('sp_helpconstraint','accounts')
22
+ assert_instance_of Array, results1
23
+ assert results1.first.respond_to?(:keys)
24
+ assert results1.first['Object Name']
25
+ assert_instance_of Array, results2
26
+ assert results2.first.respond_to?(:keys)
27
+ assert results2.first['constraint_name']
28
+ assert results2.first['constraint_type']
29
+ end
30
+
31
+ it 'take named parameter arguments' do
32
+ tables = ActiveRecord::Base.execute_procedure :sp_tables, table_name: 'tables', table_owner: 'sys'
33
+ table_info = tables.first
34
+ assert_equal 1, tables.size
35
+ assert_equal (ENV['ARUNIT_DB_NAME'] || 'activerecord_unittest'), table_info['TABLE_QUALIFIER'], "Table Info: #{table_info.inspect}"
36
+ assert_equal 'VIEW', table_info['TABLE_TYPE'], "Table Info: #{table_info.inspect}"
37
+ end
38
+
39
+ it 'uses the proper timezone' do
40
+ date_proc = connection.execute_procedure('my_getutcdate').first['utcdate']
41
+ date_base = connection.select_value('select GETUTCDATE()')
42
+ assert_equal date_base.change(usec: 0), date_proc.change(usec: 0)
43
+ end
44
+
45
+ end
@@ -0,0 +1,57 @@
1
+ require 'cases/helper_sqlserver'
2
+ require 'models/book'
3
+
4
+ class FetchTestSqlserver < ActiveRecord::TestCase
5
+
6
+ let(:books) { @books }
7
+
8
+ before { create_10_books }
9
+
10
+ it 'work with fully qualified table and columns in select' do
11
+ books = Book.select('books.id, books.name').limit(3).offset(5)
12
+ assert_equal Book.all[5,3].map(&:id), books.map(&:id)
13
+ end
14
+
15
+ describe 'count' do
16
+
17
+ it 'gauntlet' do
18
+ books[0].destroy
19
+ books[1].destroy
20
+ books[2].destroy
21
+ assert_equal 7, Book.count
22
+ assert_equal 1, Book.limit(1).offset(1).count
23
+ assert_equal 1, Book.limit(1).offset(5).count
24
+ assert_equal 1, Book.limit(1).offset(6).count
25
+ assert_equal 0, Book.limit(1).offset(7).count
26
+ assert_equal 3, Book.limit(3).offset(4).count
27
+ assert_equal 2, Book.limit(3).offset(5).count
28
+ assert_equal 1, Book.limit(3).offset(6).count
29
+ assert_equal 0, Book.limit(3).offset(7).count
30
+ assert_equal 0, Book.limit(3).offset(8).count
31
+ end
32
+
33
+ end
34
+
35
+ describe 'order' do
36
+
37
+ it 'gauntlet' do
38
+ Book.where(name:'Name-10').delete_all
39
+ Book.order(:name).limit(1).offset(1).map(&:name).must_equal ['Name-2']
40
+ Book.order(:name).limit(2).offset(2).map(&:name).must_equal ['Name-3', 'Name-4']
41
+ Book.order(:name).limit(2).offset(7).map(&:name).must_equal ['Name-8', 'Name-9']
42
+ Book.order(:name).limit(3).offset(7).map(&:name).must_equal ['Name-8', 'Name-9']
43
+ Book.order(:name).limit(3).offset(9).map(&:name).must_equal []
44
+ end
45
+
46
+ end
47
+
48
+
49
+ protected
50
+
51
+ def create_10_books
52
+ Book.delete_all
53
+ @books = (1..10).map { |i| Book.create! name: "Name-#{i}" }
54
+ end
55
+
56
+ end
57
+
@@ -0,0 +1,76 @@
1
+ require 'cases/helper_sqlserver'
2
+
3
+ class FullyQualifiedIdentifierTestSQLServer < ActiveRecord::TestCase
4
+
5
+ describe 'local server' do
6
+
7
+ it 'should use table name in select projections' do
8
+ table = Arel::Table.new(:table)
9
+ expected_sql = "SELECT [table].[name] FROM [table]"
10
+ assert_equal expected_sql, table.project(table[:name]).to_sql
11
+ end
12
+
13
+ end
14
+
15
+ describe 'remote server' do
16
+
17
+ before do
18
+ connection_options[:database_prefix] = "[my.server].db.schema."
19
+ end
20
+
21
+ after do
22
+ connection_options.delete :database_prefix
23
+ end
24
+
25
+ it 'should use fully qualified table name in select from clause' do
26
+ table = Arel::Table.new(:table)
27
+ expected_sql = "SELECT * FROM [my.server].[db].[schema].[table]"
28
+ assert_equal expected_sql, table.project(Arel.star).to_sql
29
+ end
30
+
31
+ it 'should not use fully qualified table name in select projections' do
32
+ table = Arel::Table.new(:table)
33
+ expected_sql = "SELECT [table].[name] FROM [my.server].[db].[schema].[table]"
34
+ assert_equal expected_sql, table.project(table[:name]).to_sql
35
+ end
36
+
37
+ it 'should not use fully qualified table name in where clause' do
38
+ table = Arel::Table.new(:table)
39
+ expected_sql = "SELECT * FROM [my.server].[db].[schema].[table] WHERE [table].[id] = 42"
40
+ quietly { assert_equal expected_sql, table.project(Arel.star).where(table[:id].eq(42)).to_sql }
41
+ end
42
+
43
+ it 'should not use fully qualified table name in order clause' do
44
+ table = Arel::Table.new(:table)
45
+ expected_sql = "SELECT * FROM [my.server].[db].[schema].[table] ORDER BY [table].[name]"
46
+ assert_equal expected_sql, table.project(Arel.star).order(table[:name]).to_sql
47
+ end
48
+
49
+ it 'should use fully qualified table name in insert statement' do
50
+ manager = Arel::InsertManager.new
51
+ manager.into Arel::Table.new(:table)
52
+ manager.values = manager.create_values [Arel.sql('*')], %w{ a }
53
+ expected_sql = "INSERT INTO [my.server].[db].[schema].[table] VALUES (*)"
54
+ quietly { assert_equal expected_sql, manager.to_sql }
55
+ end
56
+
57
+ it 'should use fully qualified table name in update statement' do
58
+ table = Arel::Table.new(:table)
59
+ manager = Arel::UpdateManager.new
60
+ manager.table(table).where(table[:id].eq(42))
61
+ manager.set([[table[:name], "Bob"]])
62
+ expected_sql = "UPDATE [my.server].[db].[schema].[table] SET [name] = N'Bob' WHERE [table].[id] = 42"
63
+ quietly { assert_equal expected_sql, manager.to_sql }
64
+ end
65
+
66
+ it 'should use fully qualified table name in delete statement' do
67
+ table = Arel::Table.new(:table)
68
+ manager = Arel::DeleteManager.new
69
+ manager.from(table).where(table[:id].eq(42))
70
+ expected_sql = "DELETE FROM [my.server].[db].[schema].[table] WHERE [table].[id] = 42"
71
+ quietly { assert_equal expected_sql, manager.to_sql }
72
+ end
73
+
74
+ end
75
+
76
+ end
@@ -0,0 +1,44 @@
1
+ require 'support/paths_sqlserver'
2
+ require 'bundler/setup'
3
+ Bundler.require :default, :development
4
+ require 'pry'
5
+ require 'support/minitest_sqlserver'
6
+ require 'support/test_in_memory_oltp'
7
+ require 'cases/helper'
8
+ require 'support/load_schema_sqlserver'
9
+ require 'support/coerceable_test_sqlserver'
10
+ require 'support/sql_counter_sqlserver'
11
+ require 'support/connection_reflection'
12
+ require 'mocha/mini_test'
13
+
14
+ module ActiveRecord
15
+ class TestCase < ActiveSupport::TestCase
16
+
17
+ SQLServer = ActiveRecord::ConnectionAdapters::SQLServer
18
+
19
+ include ARTest::SQLServer::CoerceableTest,
20
+ ARTest::SQLServer::ConnectionReflection,
21
+ ARTest::SQLServer::SqlCounterSqlserver,
22
+ ActiveSupport::Testing::Stream
23
+
24
+ let(:logger) { ActiveRecord::Base.logger }
25
+
26
+
27
+ private
28
+
29
+ def host_windows?
30
+ RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
31
+ end
32
+
33
+ def with_use_output_inserted_disabled
34
+ klass = ActiveRecord::ConnectionAdapters::SQLServerAdapter
35
+ klass.use_output_inserted = false
36
+ yield
37
+ ensure
38
+ klass.use_output_inserted = true
39
+ end
40
+
41
+ end
42
+ end
43
+
44
+ Dir["#{ARTest::SQLServer.test_root_sqlserver}/models/**/*.rb"].each { |f| require f }
@@ -0,0 +1,47 @@
1
+ require 'cases/helper_sqlserver'
2
+
3
+ class IndexTestSQLServer < ActiveRecord::TestCase
4
+
5
+ before do
6
+ connection.create_table(:testings) do |t|
7
+ t.column :foo, :string, limit: 100
8
+ t.column :bar, :string, limit: 100
9
+ t.string :first_name
10
+ t.string :last_name, limit: 100
11
+ t.string :key, limit: 100
12
+ t.boolean :administrator
13
+ end
14
+ end
15
+
16
+ after do
17
+ connection.drop_table :testings rescue nil
18
+ end
19
+
20
+ it 'add index with order' do
21
+ assert_sql(/CREATE.*INDEX.*\(\[last_name\] DESC\)/i) do
22
+ connection.add_index 'testings', ['last_name'], order: { last_name: :desc }
23
+ connection.remove_index 'testings', ['last_name']
24
+ end
25
+ assert_sql(/CREATE.*INDEX.*\(\[last_name\] DESC, \[first_name\]\)/i) do
26
+ connection.add_index 'testings', ['last_name', 'first_name'], order: { last_name: :desc }
27
+ connection.remove_index 'testings', ['last_name', 'first_name']
28
+ end
29
+ assert_sql(/CREATE.*INDEX.*\(\[last_name\] DESC, \[first_name\] ASC\)/i) do
30
+ connection.add_index 'testings', ['last_name', 'first_name'], order: { last_name: :desc, first_name: :asc }
31
+ connection.remove_index 'testings', ['last_name', 'first_name']
32
+ end
33
+ end
34
+
35
+ it 'add index with where' do
36
+ assert_sql(/CREATE.*INDEX.*\(\[last_name\]\) WHERE \[first_name\] = N'john doe'/i) do
37
+ connection.add_index 'testings', 'last_name', where: "[first_name] = N'john doe'"
38
+ connection.remove_index 'testings', 'last_name'
39
+ end
40
+ end
41
+
42
+ it 'add index with expression' do
43
+ connection.execute "ALTER TABLE [testings] ADD [first_name_upper] AS UPPER([first_name])"
44
+ connection.add_index 'testings', 'first_name_upper'
45
+ end
46
+
47
+ end
@@ -0,0 +1,32 @@
1
+ require 'cases/helper_sqlserver'
2
+
3
+ if ActiveRecord::Base.connection.supports_json?
4
+ class JsonTestSQLServer < ActiveRecord::TestCase
5
+
6
+ before do
7
+ @o1 = SSTestDatatypeMigrationJson.create! json_col: { 'a' => 'a', 'b' => 'b', 'c' => 'c' }
8
+ @o2 = SSTestDatatypeMigrationJson.create! json_col: { 'a' => nil, 'b' => 'b', 'c' => 'c' }
9
+ @o3 = SSTestDatatypeMigrationJson.create! json_col: { 'x' => 1, 'y' => 2, 'z' => 3 }
10
+ @o4 = SSTestDatatypeMigrationJson.create! json_col: { 'array' => [1, 2, 3] }
11
+ @o5 = SSTestDatatypeMigrationJson.create! json_col: nil
12
+ end
13
+
14
+ it 'can return and save JSON data' do
15
+ SSTestDatatypeMigrationJson.find(@o1.id).json_col.must_equal({ 'a' => 'a', 'b' => 'b', 'c' => 'c' })
16
+ @o1.json_col = { 'a' => 'a' }
17
+ @o1.json_col.must_equal({ 'a' => 'a' })
18
+ @o1.save!
19
+ @o1.reload.json_col.must_equal({ 'a' => 'a' })
20
+ end
21
+
22
+ it 'can use ISJSON function' do
23
+ SSTestDatatypeMigrationJson.where('ISJSON(json_col) > 0').count.must_equal 4
24
+ SSTestDatatypeMigrationJson.where('ISJSON(json_col) IS NULL').count.must_equal 1
25
+ end
26
+
27
+ it 'can use JSON_VALUE function' do
28
+ SSTestDatatypeMigrationJson.where("JSON_VALUE(json_col, '$.b') = 'b'").count.must_equal 2
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,61 @@
1
+ require 'cases/helper_sqlserver'
2
+ require 'models/person'
3
+
4
+ class MigrationTestSQLServer < ActiveRecord::TestCase
5
+
6
+ describe 'For transactions' do
7
+
8
+ before do
9
+ @trans_test_table1 = 'sqlserver_trans_table1'
10
+ @trans_test_table2 = 'sqlserver_trans_table2'
11
+ @trans_tables = [@trans_test_table1,@trans_test_table2]
12
+ end
13
+
14
+ after do
15
+ @trans_tables.each do |table_name|
16
+ ActiveRecord::Migration.drop_table(table_name) if connection.tables.include?(table_name)
17
+ end
18
+ end
19
+
20
+ it 'not create a tables if error in migrations' do
21
+ begin
22
+ migrations_dir = File.join ARTest::SQLServer.migrations_root, 'transaction_table'
23
+ quietly { ActiveRecord::Migrator.up(migrations_dir) }
24
+ rescue Exception => e
25
+ assert_match %r|this and all later migrations canceled|, e.message
26
+ end
27
+ connection.tables.wont_include @trans_test_table1
28
+ connection.tables.wont_include @trans_test_table2
29
+ end
30
+
31
+ end
32
+
33
+ describe 'For changing column' do
34
+
35
+ it 'not raise exception when column contains default constraint' do
36
+ lock_version_column = Person.columns_hash['lock_version']
37
+ assert_equal :integer, lock_version_column.type
38
+ assert lock_version_column.default.present?
39
+ assert_nothing_raised { connection.change_column 'people', 'lock_version', :string }
40
+ Person.reset_column_information
41
+ lock_version_column = Person.columns_hash['lock_version']
42
+ assert_equal :string, lock_version_column.type
43
+ assert lock_version_column.default.nil?
44
+ end
45
+
46
+ it 'not drop the default contraint if just renaming' do
47
+ find_default = lambda do
48
+ connection.execute_procedure(:sp_helpconstraint, 'sst_string_defaults', 'nomsg').select do |row|
49
+ row['constraint_type'] == "DEFAULT on column string_with_pretend_paren_three"
50
+ end.last
51
+ end
52
+ default_before = find_default.call
53
+ connection.change_column :sst_string_defaults, :string_with_pretend_paren_three, :string, limit: 255
54
+ default_after = find_default.call
55
+ assert default_after
56
+ assert_equal default_before['constraint_keys'], default_after['constraint_keys']
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,147 @@
1
+ require 'cases/helper_sqlserver'
2
+ require 'models/post'
3
+
4
+ class OrderTestSQLServer < ActiveRecord::TestCase
5
+
6
+ fixtures :posts
7
+
8
+ it 'not mangel complex order clauses' do
9
+ xyz_order = "CASE WHEN [title] LIKE N'XYZ%' THEN 0 ELSE 1 END"
10
+ xyz_post = Post.create title: 'XYZ Post', body: 'Test cased orders.'
11
+ assert_equal xyz_post, Post.order(Arel.sql(xyz_order)).first
12
+ end
13
+
14
+ it 'support column' do
15
+ order = "title"
16
+ post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
17
+ assert_equal post1, Post.order(order).first
18
+ end
19
+
20
+ it 'support column ASC' do
21
+ order = "title ASC"
22
+ post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
23
+ assert_equal post1, Post.order(order).first
24
+ end
25
+
26
+ it 'support column DESC' do
27
+ order = "title DESC"
28
+ post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
29
+ assert_equal post1, Post.order(order).first
30
+ end
31
+
32
+ it 'support column as symbol' do
33
+ order = :title
34
+ post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
35
+ assert_equal post1, Post.order(order).first
36
+ end
37
+
38
+ it 'support table and column' do
39
+ order = "posts.title"
40
+ post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
41
+ assert_equal post1, Post.order(order).first
42
+ end
43
+
44
+ it 'support quoted column' do
45
+ order = "[title]"
46
+ post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
47
+ assert_equal post1, Post.order(order).first
48
+ end
49
+
50
+ it 'support quoted table and column' do
51
+ order = "[posts].[title]"
52
+ post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
53
+ assert_equal post1, Post.order(order).first
54
+ end
55
+
56
+ it 'support primary: column, secondary: column' do
57
+ order = "title DESC, body"
58
+ post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
59
+ post2 = Post.create title: 'ZZZ Post', body: 'ZZZ Test cased orders.'
60
+ assert_equal post1, Post.order(order).first
61
+ assert_equal post2, Post.order(order).second
62
+ end
63
+
64
+ it 'support primary: table and column, secondary: column' do
65
+ order = "posts.title DESC, body"
66
+ post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
67
+ post2 = Post.create title: 'ZZZ Post', body: 'ZZZ Test cased orders.'
68
+ assert_equal post1, Post.order(order).first
69
+ assert_equal post2, Post.order(order).second
70
+ end
71
+
72
+ it 'support primary: case expression, secondary: column' do
73
+ order = "(CASE WHEN [title] LIKE N'ZZZ%' THEN title ELSE '' END) DESC, body"
74
+ post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
75
+ post2 = Post.create title: 'ZZZ Post', body: 'ZZZ Test cased orders.'
76
+ assert_equal post1, Post.order(order).first
77
+ assert_equal post2, Post.order(order).second
78
+ end
79
+
80
+ it 'support primary: quoted table and column, secondary: case expresion' do
81
+ order = "[posts].[body] DESC, (CASE WHEN [title] LIKE N'ZZZ%' THEN title ELSE '' END) DESC"
82
+ post1 = Post.create title: 'ZZZ Post', body: 'ZZZ Test cased orders.'
83
+ post2 = Post.create title: 'ZZY Post', body: 'ZZZ Test cased orders.'
84
+ assert_equal post1, Post.order(order).first
85
+ assert_equal post2, Post.order(order).second
86
+ end
87
+
88
+ it 'support inline function' do
89
+ order = "LEN(title)"
90
+ post1 = Post.create title: 'A', body: 'AAA Test cased orders.'
91
+ assert_equal post1, Post.order(order).first
92
+ end
93
+
94
+ it 'support inline function with parameters' do
95
+ order = "SUBSTRING(title, 1, 3)"
96
+ post1 = Post.create title: 'AAA Post', body: 'Test cased orders.'
97
+ assert_equal post1, Post.order(order).first
98
+ end
99
+
100
+ it 'support inline function with parameters DESC' do
101
+ order = "SUBSTRING(title, 1, 3) DESC"
102
+ post1 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
103
+ assert_equal post1, Post.order(order).first
104
+ end
105
+
106
+ it 'support primary: inline function, secondary: column' do
107
+ order = "LEN(title), body"
108
+ post1 = Post.create title: 'A', body: 'AAA Test cased orders.'
109
+ post2 = Post.create title: 'A', body: 'Test cased orders.'
110
+ assert_equal post1, Post.order(order).first
111
+ assert_equal post2, Post.order(order).second
112
+ end
113
+
114
+ it 'support primary: inline function, secondary: column with direction' do
115
+ order = "LEN(title) ASC, body DESC"
116
+ post1 = Post.create title: 'A', body: 'ZZZ Test cased orders.'
117
+ post2 = Post.create title: 'A', body: 'Test cased orders.'
118
+ assert_equal post1, Post.order(order).first
119
+ assert_equal post2, Post.order(order).second
120
+ end
121
+
122
+ it 'support primary: column, secondary: inline function' do
123
+ order = "body DESC, LEN(title)"
124
+ post1 = Post.create title: 'Post', body: 'ZZZ Test cased orders.'
125
+ post2 = Post.create title: 'Longer Post', body: 'ZZZ Test cased orders.'
126
+ assert_equal post1, Post.order(order).first
127
+ assert_equal post2, Post.order(order).second
128
+ end
129
+
130
+ it 'support primary: case expression, secondary: inline function' do
131
+ order = "CASE WHEN [title] LIKE N'ZZZ%' THEN title ELSE '' END DESC, LEN(body) ASC"
132
+ post1 = Post.create title: 'ZZZ Post', body: 'Z'
133
+ post2 = Post.create title: 'ZZZ Post', body: 'Test cased orders.'
134
+ assert_equal post1, Post.order(order).first
135
+ assert_equal post2, Post.order(order).second
136
+ end
137
+
138
+ it 'support primary: inline function, secondary: case expression' do
139
+ order = "LEN(body), CASE WHEN [title] LIKE N'ZZZ%' THEN title ELSE '' END DESC"
140
+ post1 = Post.create title: 'ZZZ Post', body: 'Z'
141
+ post2 = Post.create title: 'Post', body: 'Z'
142
+ assert_equal post1, Post.order(order).first
143
+ assert_equal post2, Post.order(order).second
144
+ end
145
+
146
+
147
+ end