activerecord-sqlserver-adapter_new 4.2.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/CHANGELOG.md +212 -0
- data/CODE_OF_CONDUCT.md +31 -0
- data/Gemfile +61 -0
- data/Guardfile +29 -0
- data/MIT-LICENSE +20 -0
- data/README.md +201 -0
- data/RUNNING_UNIT_TESTS.md +121 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/activerecord-sqlserver-adapter_new.gemspec +20 -0
- data/appveyor.yml +39 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +27 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +25 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +40 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +4 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +34 -0
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +49 -0
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +386 -0
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +68 -0
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +7 -0
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +69 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +114 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +52 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +473 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +66 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +66 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +76 -0
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +57 -0
- data/lib/active_record/connection_adapters/sqlserver/type.rb +46 -0
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/char.rb +38 -0
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +21 -0
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +41 -0
- data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +17 -0
- data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +31 -0
- data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/float.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/money.rb +21 -0
- data/lib/active_record/connection_adapters/sqlserver/type/real.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +13 -0
- data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +21 -0
- data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/type/string.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/text.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +40 -0
- data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +76 -0
- data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +22 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +12 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +15 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +23 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +136 -0
- data/lib/active_record/connection_adapters/sqlserver/version.rb +11 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +405 -0
- data/lib/active_record/connection_adapters/sqlserver_column.rb +53 -0
- data/lib/active_record/sqlserver_base.rb +20 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +131 -0
- data/lib/activerecord-sqlserver-adapter.rb +1 -0
- data/lib/arel/visitors/sqlserver.rb +214 -0
- data/lib/arel_sqlserver.rb +3 -0
- data/test/appveyor/dbsetup.ps1 +27 -0
- data/test/appveyor/dbsetup.sql +11 -0
- data/test/cases/adapter_test_sqlserver.rb +444 -0
- data/test/cases/coerced_tests.rb +713 -0
- data/test/cases/column_test_sqlserver.rb +780 -0
- data/test/cases/connection_test_sqlserver.rb +142 -0
- data/test/cases/execute_procedure_test_sqlserver.rb +44 -0
- data/test/cases/fetch_test_sqlserver.rb +57 -0
- data/test/cases/fully_qualified_identifier_test_sqlserver.rb +76 -0
- data/test/cases/helper_sqlserver.rb +54 -0
- data/test/cases/migration_test_sqlserver.rb +61 -0
- data/test/cases/order_test_sqlserver.rb +147 -0
- data/test/cases/pessimistic_locking_test_sqlserver.rb +90 -0
- data/test/cases/rake_test_sqlserver.rb +163 -0
- data/test/cases/schema_dumper_test_sqlserver.rb +198 -0
- data/test/cases/schema_test_sqlserver.rb +54 -0
- data/test/cases/scratchpad_test_sqlserver.rb +9 -0
- data/test/cases/showplan_test_sqlserver.rb +65 -0
- data/test/cases/specific_schema_test_sqlserver.rb +167 -0
- data/test/cases/transaction_test_sqlserver.rb +66 -0
- data/test/cases/utils_test_sqlserver.rb +129 -0
- data/test/cases/uuid_test_sqlserver.rb +48 -0
- data/test/config.yml +41 -0
- data/test/debug.rb +14 -0
- data/test/fixtures/1px.gif +0 -0
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +11 -0
- data/test/models/sqlserver/booking.rb +3 -0
- data/test/models/sqlserver/customers_view.rb +3 -0
- data/test/models/sqlserver/datatype.rb +3 -0
- data/test/models/sqlserver/datatype_migration.rb +3 -0
- data/test/models/sqlserver/dollar_table_name.rb +3 -0
- data/test/models/sqlserver/dot_table_name.rb +3 -0
- data/test/models/sqlserver/edge_schema.rb +13 -0
- data/test/models/sqlserver/fk_has_fk.rb +3 -0
- data/test/models/sqlserver/fk_has_pk.rb +3 -0
- data/test/models/sqlserver/natural_pk_data.rb +4 -0
- data/test/models/sqlserver/natural_pk_int_data.rb +3 -0
- data/test/models/sqlserver/no_pk_data.rb +3 -0
- data/test/models/sqlserver/object_default.rb +3 -0
- data/test/models/sqlserver/quoted_table.rb +7 -0
- data/test/models/sqlserver/quoted_view_1.rb +3 -0
- data/test/models/sqlserver/quoted_view_2.rb +3 -0
- data/test/models/sqlserver/string_default.rb +3 -0
- data/test/models/sqlserver/string_defaults_big_view.rb +3 -0
- data/test/models/sqlserver/string_defaults_view.rb +3 -0
- data/test/models/sqlserver/tinyint_pk.rb +3 -0
- data/test/models/sqlserver/upper.rb +3 -0
- data/test/models/sqlserver/uppered.rb +3 -0
- data/test/models/sqlserver/uuid.rb +3 -0
- data/test/schema/datatypes/2012.sql +55 -0
- data/test/schema/sqlserver_specific_schema.rb +207 -0
- data/test/support/coerceable_test_sqlserver.rb +45 -0
- data/test/support/connection_reflection.rb +37 -0
- data/test/support/load_schema_sqlserver.rb +29 -0
- data/test/support/minitest_sqlserver.rb +1 -0
- data/test/support/paths_sqlserver.rb +50 -0
- data/test/support/rake_helpers.rb +41 -0
- data/test/support/sql_counter_sqlserver.rb +32 -0
- metadata +253 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'cases/helper_sqlserver'
|
2
|
+
require 'models/person'
|
3
|
+
require 'models/reader'
|
4
|
+
|
5
|
+
class PessimisticLockingTestSQLServer < ActiveRecord::TestCase
|
6
|
+
|
7
|
+
fixtures :people, :readers
|
8
|
+
|
9
|
+
before do
|
10
|
+
Person.columns
|
11
|
+
Reader.columns
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'uses with updlock by default' do
|
15
|
+
assert_sql %r|SELECT \[people\]\.\* FROM \[people\] WITH\(UPDLOCK\)| do
|
16
|
+
Person.lock(true).to_a.must_equal Person.all.to_a
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'For simple finds with default lock option' do
|
21
|
+
|
22
|
+
it 'lock with simple find' do
|
23
|
+
assert_nothing_raised do
|
24
|
+
Person.transaction do
|
25
|
+
Person.lock(true).find(1).must_equal Person.find(1)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'lock with scoped find' do
|
31
|
+
assert_nothing_raised do
|
32
|
+
Person.transaction do
|
33
|
+
Person.lock(true).scoping do
|
34
|
+
Person.find(1).must_equal Person.find(1)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'lock with eager find' do
|
41
|
+
assert_nothing_raised do
|
42
|
+
Person.transaction do
|
43
|
+
person = Person.lock(true).includes(:readers).find(1)
|
44
|
+
person.must_equal Person.find(1)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'reload with lock when #lock! called' do
|
50
|
+
assert_nothing_raised do
|
51
|
+
Person.transaction do
|
52
|
+
person = Person.find 1
|
53
|
+
old, person.first_name = person.first_name, 'fooman'
|
54
|
+
person.lock!
|
55
|
+
assert_equal old, person.first_name
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'can add a custom lock directive' do
|
61
|
+
assert_sql %r|SELECT \[people\]\.\* FROM \[people\] WITH\(HOLDLOCK, ROWLOCK\)| do
|
62
|
+
Person.lock('WITH(HOLDLOCK, ROWLOCK)').load
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
describe 'For paginated finds' do
|
69
|
+
|
70
|
+
before do
|
71
|
+
Person.delete_all
|
72
|
+
20.times { |n| Person.create!(first_name: "Thing_#{n}") }
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'copes with eager loading un-locked paginated' do
|
76
|
+
eager_ids_sql = /SELECT\s+DISTINCT \[people\].\[id\] FROM \[people\] WITH\(UPDLOCK\) LEFT OUTER JOIN \[readers\] WITH\(UPDLOCK\)\s+ON \[readers\].\[person_id\] = \[people\].\[id\]\s+ORDER BY \[people\].\[id\] ASC OFFSET 10 ROWS FETCH NEXT 5 ROWS ONLY/
|
77
|
+
loader_sql = /SELECT.*FROM \[people\] WITH\(UPDLOCK\).*WHERE \[people\]\.\[id\] IN/
|
78
|
+
assert_sql(eager_ids_sql, loader_sql) do
|
79
|
+
people = Person.lock(true).limit(5).offset(10).includes(:readers).references(:readers).to_a
|
80
|
+
people[0].first_name.must_equal 'Thing_10'
|
81
|
+
people[1].first_name.must_equal 'Thing_11'
|
82
|
+
people[2].first_name.must_equal 'Thing_12'
|
83
|
+
people[3].first_name.must_equal 'Thing_13'
|
84
|
+
people[4].first_name.must_equal 'Thing_14'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'cases/helper_sqlserver'
|
2
|
+
|
3
|
+
class SQLServerRakeTest < ActiveRecord::TestCase
|
4
|
+
|
5
|
+
self.use_transactional_fixtures = false
|
6
|
+
|
7
|
+
cattr_accessor :azure_skip
|
8
|
+
self.azure_skip = connection_sqlserver_azure?
|
9
|
+
|
10
|
+
let(:db_tasks) { ActiveRecord::Tasks::DatabaseTasks }
|
11
|
+
let(:new_database) { 'activerecord_unittest_tasks' }
|
12
|
+
let(:default_configuration) { ARTest.connection_config['arunit'] }
|
13
|
+
let(:configuration) { default_configuration.merge('database' => new_database) }
|
14
|
+
|
15
|
+
before { skip 'on azure' if azure_skip }
|
16
|
+
before { disconnect! unless azure_skip }
|
17
|
+
after { reconnect unless azure_skip }
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def disconnect!
|
22
|
+
connection.disconnect!
|
23
|
+
end
|
24
|
+
|
25
|
+
def reconnect
|
26
|
+
config = default_configuration
|
27
|
+
if connection_sqlserver_azure?
|
28
|
+
ActiveRecord::Base.establish_connection(config.merge('database' => 'master'))
|
29
|
+
connection.drop_database(new_database) rescue nil
|
30
|
+
disconnect!
|
31
|
+
ActiveRecord::Base.establish_connection(config)
|
32
|
+
else
|
33
|
+
ActiveRecord::Base.establish_connection(config)
|
34
|
+
connection.drop_database(new_database) rescue nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
class SQLServerRakeCreateTest < SQLServerRakeTest
|
41
|
+
|
42
|
+
self.azure_skip = false
|
43
|
+
|
44
|
+
it 'establishes connection to database after create ' do
|
45
|
+
db_tasks.create configuration
|
46
|
+
connection.current_database.must_equal(new_database)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'creates database with default collation' do
|
50
|
+
db_tasks.create configuration
|
51
|
+
connection.collation.must_equal 'SQL_Latin1_General_CP1_CI_AS'
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'creates database with given collation' do
|
55
|
+
db_tasks.create configuration.merge('collation' => 'Latin1_General_CI_AS')
|
56
|
+
connection.collation.must_equal 'Latin1_General_CI_AS'
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'prints error message when database exists' do
|
60
|
+
db_tasks.create configuration
|
61
|
+
message = capture(:stderr) { db_tasks.create configuration }
|
62
|
+
message.must_match %r{activerecord_unittest_tasks already exists}
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
class SQLServerRakeDropTest < SQLServerRakeTest
|
68
|
+
|
69
|
+
self.azure_skip = false
|
70
|
+
|
71
|
+
it 'drops database and uses master' do
|
72
|
+
db_tasks.create configuration
|
73
|
+
db_tasks.drop configuration
|
74
|
+
connection.current_database.must_equal 'master'
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'prints error message when database does not exist' do
|
78
|
+
message = capture(:stderr) { db_tasks.drop configuration.merge('database' => 'doesnotexist') }
|
79
|
+
message.must_match %r{'doesnotexist' does not exist}
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
class SQLServerRakePurgeTest < SQLServerRakeTest
|
85
|
+
|
86
|
+
before do
|
87
|
+
db_tasks.create(configuration)
|
88
|
+
connection.create_table :users, force: true do |t|
|
89
|
+
t.string :name, :email
|
90
|
+
t.timestamps null: false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'clears active connections, drops database, and recreates with established connection' do
|
95
|
+
connection.current_database.must_equal(new_database)
|
96
|
+
connection.tables.must_include 'users'
|
97
|
+
db_tasks.purge(configuration)
|
98
|
+
connection.current_database.must_equal(new_database)
|
99
|
+
connection.tables.wont_include 'users'
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
class SQLServerRakeCharsetTest < SQLServerRakeTest
|
105
|
+
|
106
|
+
before { db_tasks.create(configuration) }
|
107
|
+
|
108
|
+
it 'retrieves charset' do
|
109
|
+
db_tasks.charset(configuration).must_equal 'iso_1'
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
class SQLServerRakeCollationTest < SQLServerRakeTest
|
115
|
+
|
116
|
+
before { db_tasks.create(configuration) }
|
117
|
+
|
118
|
+
it 'retrieves collation' do
|
119
|
+
db_tasks.collation(configuration).must_equal 'SQL_Latin1_General_CP1_CI_AS'
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
class SQLServerRakeStructureDumpLoadTest < SQLServerRakeTest
|
125
|
+
|
126
|
+
let(:filename) { File.join ARTest::SQLServer.migrations_root, 'structure.sql' }
|
127
|
+
let(:filedata) { File.read(filename) }
|
128
|
+
|
129
|
+
before do
|
130
|
+
db_tasks.create(configuration)
|
131
|
+
connection.create_table :users, force: true do |t|
|
132
|
+
t.string :name, :email
|
133
|
+
t.text :background1
|
134
|
+
t.text_basic :background2
|
135
|
+
t.timestamps null: false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
after do
|
140
|
+
FileUtils.rm_rf(filename)
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'dumps structure and accounts for defncopy oddities' do
|
144
|
+
skip 'debug defncopy on windows later' if host_windows?
|
145
|
+
quietly { db_tasks.structure_dump configuration, filename }
|
146
|
+
filedata.wont_match %r{\AUSE.*\z}
|
147
|
+
filedata.wont_match %r{\AGO.*\z}
|
148
|
+
filedata.must_match %r{email\s+nvarchar\(4000\)}
|
149
|
+
filedata.must_match %r{background1\s+nvarchar\(max\)}
|
150
|
+
filedata.must_match %r{background2\s+text\s+}
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'can load dumped structure' do
|
154
|
+
skip 'debug defncopy on windows later' if host_windows?
|
155
|
+
quietly { db_tasks.structure_dump configuration, filename }
|
156
|
+
filedata.must_match %r{CREATE TABLE dbo\.users}
|
157
|
+
db_tasks.purge(configuration)
|
158
|
+
connection.tables.wont_include 'users'
|
159
|
+
db_tasks.load_schema_for configuration, :sql, filename
|
160
|
+
connection.tables.must_include 'users'
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'cases/helper_sqlserver'
|
2
|
+
|
3
|
+
class SchemaDumperTestSQLServer < ActiveRecord::TestCase
|
4
|
+
|
5
|
+
before { all_tables }
|
6
|
+
|
7
|
+
let(:all_tables) { ActiveRecord::Base.connection.tables }
|
8
|
+
let(:schema) { @generated_schema }
|
9
|
+
|
10
|
+
it 'sst_datatypes' do
|
11
|
+
generate_schema_for_table 'sst_datatypes'
|
12
|
+
# Exact Numerics
|
13
|
+
assert_line :bigint, type: 'bigint', limit: '8', precision: nil, scale: nil, default: '42'
|
14
|
+
assert_line :int, type: 'integer', limit: '4', precision: nil, scale: nil, default: '42'
|
15
|
+
assert_line :smallint, type: 'integer', limit: '2', precision: nil, scale: nil, default: '42'
|
16
|
+
assert_line :tinyint, type: 'integer', limit: '1', precision: nil, scale: nil, default: '42'
|
17
|
+
assert_line :bit, type: 'boolean', limit: nil, precision: nil, scale: nil, default: 'true'
|
18
|
+
assert_line :decimal_9_2, type: 'decimal', limit: nil, precision: '9', scale: '2', default: '12345.01'
|
19
|
+
assert_line :numeric_18_0, type: 'decimal', limit: nil, precision: '18', scale: '0', default: '191.0'
|
20
|
+
assert_line :numeric_36_2, type: 'decimal', limit: nil, precision: '36', scale: '2', default: '12345678901234567890.01'
|
21
|
+
assert_line :money, type: 'money', limit: nil, precision: '19', scale: '4', default: '4.2'
|
22
|
+
assert_line :smallmoney, type: 'smallmoney', limit: nil, precision: '10', scale: '4', default: '4.2'
|
23
|
+
# Approximate Numerics
|
24
|
+
assert_line :float, type: 'float', limit: nil, precision: nil, scale: nil, default: '123.00000001'
|
25
|
+
assert_line :real, type: 'real', limit: nil, precision: nil, scale: nil, default: %r{123.4[45]}
|
26
|
+
# Date and Time
|
27
|
+
assert_line :date, type: 'date', limit: nil, precision: nil, scale: nil, default: "\"01-01-0001\""
|
28
|
+
assert_line :datetime, type: 'datetime', limit: nil, precision: nil, scale: nil, default: "\"01-01-1753 00:00:00.123\""
|
29
|
+
if connection_dblib_73?
|
30
|
+
assert_line :datetime2_7, type: 'datetime2', limit: nil, precision: '7', scale: nil, default: "\"12-31-9999 23:59:59.9999999\""
|
31
|
+
assert_line :datetime2_3, type: 'datetime2', limit: nil, precision: '3', scale: nil, default: nil
|
32
|
+
assert_line :datetime2_1, type: 'datetime2', limit: nil, precision: '1', scale: nil, default: nil
|
33
|
+
end
|
34
|
+
assert_line :smalldatetime, type: 'smalldatetime',limit: nil, precision: nil, scale: nil, default: "\"01-01-1901 15:45:00\""
|
35
|
+
if connection_dblib_73?
|
36
|
+
assert_line :time_7, type: 'time', limit: nil, precision: '7', scale: nil, default: "\"04:20:00.2883215\""
|
37
|
+
assert_line :time_2, type: 'time', limit: nil, precision: '2', scale: nil, default: nil
|
38
|
+
end
|
39
|
+
# Character Strings
|
40
|
+
assert_line :char_10, type: 'char', limit: '10', precision: nil, scale: nil, default: "\"1234567890\""
|
41
|
+
assert_line :varchar_50, type: 'varchar', limit: '50', precision: nil, scale: nil, default: "\"test varchar_50\""
|
42
|
+
assert_line :varchar_max, type: 'varchar_max', limit: '2147483647', precision: nil, scale: nil, default: "\"test varchar_max\""
|
43
|
+
assert_line :text, type: 'text_basic', limit: '2147483647', precision: nil, scale: nil, default: "\"test text\""
|
44
|
+
# Unicode Character Strings
|
45
|
+
assert_line :nchar_10, type: 'nchar', limit: '10', precision: nil, scale: nil, default: "\"12345678åå\""
|
46
|
+
assert_line :nvarchar_50, type: 'string', limit: '50', precision: nil, scale: nil, default: "\"test nvarchar_50 åå\""
|
47
|
+
assert_line :nvarchar_max, type: 'text', limit: '2147483647', precision: nil, scale: nil, default: "\"test nvarchar_max åå\""
|
48
|
+
assert_line :ntext, type: 'ntext', limit: '2147483647', precision: nil, scale: nil, default: "\"test ntext åå\""
|
49
|
+
# Binary Strings
|
50
|
+
assert_line :binary_49, type: 'binary_basic', limit: '49', precision: nil, scale: nil, default: nil
|
51
|
+
assert_line :varbinary_49, type: 'varbinary', limit: '49', precision: nil, scale: nil, default: nil
|
52
|
+
assert_line :varbinary_max, type: 'binary', limit: '2147483647', precision: nil, scale: nil, default: nil
|
53
|
+
# Other Data Types
|
54
|
+
assert_line :uniqueidentifier, type: 'uuid', limit: nil, precision: nil, scale: nil, default: nil
|
55
|
+
assert_line :timestamp, type: 'ss_timestamp', limit: nil, precision: nil, scale: nil, default: nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'sst_datatypes_migration' do
|
59
|
+
columns = SSTestDatatypeMigration.columns_hash
|
60
|
+
generate_schema_for_table 'sst_datatypes_migration'
|
61
|
+
# Simple Rails conventions
|
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)'
|
69
|
+
columns['datetime_col'].sql_type.must_equal 'datetime'
|
70
|
+
columns['timestamp_col'].sql_type.must_equal 'datetime'
|
71
|
+
columns['time_col'].sql_type.must_equal 'time(7)'
|
72
|
+
columns['date_col'].sql_type.must_equal 'date'
|
73
|
+
columns['binary_col'].sql_type.must_equal 'varbinary(max)'
|
74
|
+
assert_line :integer_col, type: 'integer', limit: '4', precision: nil, scale: nil, default: nil
|
75
|
+
assert_line :bigint_col, type: 'bigint', limit: '8', precision: nil, scale: nil, default: nil
|
76
|
+
assert_line :boolean_col, type: 'boolean', limit: nil, precision: nil, scale: nil, default: nil
|
77
|
+
assert_line :decimal_col, type: 'decimal', limit: nil, precision: '18', scale: '0', default: nil
|
78
|
+
assert_line :float_col, type: 'float', limit: nil, precision: nil, scale: nil, default: nil
|
79
|
+
assert_line :string_col, type: 'string', limit: '4000', precision: nil, scale: nil, default: nil
|
80
|
+
assert_line :text_col, type: 'text', limit: '2147483647', precision: nil, scale: nil, default: nil
|
81
|
+
assert_line :datetime_col, type: 'datetime', limit: nil, precision: nil, scale: nil, default: nil
|
82
|
+
assert_line :timestamp_col, type: 'datetime', limit: nil, precision: nil, scale: nil, default: nil
|
83
|
+
assert_line :time_col, type: 'time', limit: nil, precision: '7', scale: nil, default: nil
|
84
|
+
assert_line :date_col, type: 'date', limit: nil, precision: nil, scale: nil, default: nil
|
85
|
+
assert_line :binary_col, type: 'binary', limit: '2147483647', precision: nil, scale: nil, default: nil
|
86
|
+
# Our type methods.
|
87
|
+
columns['real_col'].sql_type.must_equal 'real'
|
88
|
+
columns['money_col'].sql_type.must_equal 'money'
|
89
|
+
columns['datetime2_col'].sql_type.must_equal 'datetime2(7)'
|
90
|
+
columns['datetimeoffset'].sql_type.must_equal 'datetimeoffset(7)'
|
91
|
+
columns['smallmoney_col'].sql_type.must_equal 'smallmoney'
|
92
|
+
columns['char_col'].sql_type.must_equal 'char(1)'
|
93
|
+
columns['varchar_col'].sql_type.must_equal 'varchar(8000)'
|
94
|
+
columns['text_basic_col'].sql_type.must_equal 'text'
|
95
|
+
columns['nchar_col'].sql_type.must_equal 'nchar(1)'
|
96
|
+
columns['ntext_col'].sql_type.must_equal 'ntext'
|
97
|
+
columns['binary_basic_col'].sql_type.must_equal 'binary(1)'
|
98
|
+
columns['varbinary_col'].sql_type.must_equal 'varbinary(8000)'
|
99
|
+
columns['uuid_col'].sql_type.must_equal 'uniqueidentifier'
|
100
|
+
columns['sstimestamp_col'].sql_type.must_equal 'timestamp'
|
101
|
+
assert_line :real_col, type: 'real', limit: nil, precision: nil, scale: nil, default: nil
|
102
|
+
assert_line :money_col, type: 'money', limit: nil, precision: '19', scale: '4', default: nil
|
103
|
+
assert_line :datetime2_col, type: 'datetime2', limit: nil, precision: '7', scale: nil, default: nil
|
104
|
+
assert_line :smallmoney_col, type: 'smallmoney', limit: nil, precision: '10', scale: '4', default: nil
|
105
|
+
assert_line :char_col, type: 'char', limit: '1', precision: nil, scale: nil, default: nil
|
106
|
+
assert_line :varchar_col, type: 'varchar', limit: '8000', precision: nil, scale: nil, default: nil
|
107
|
+
assert_line :text_basic_col, type: 'text_basic', limit: '2147483647', precision: nil, scale: nil, default: nil
|
108
|
+
assert_line :nchar_col, type: 'nchar', limit: '1', precision: nil, scale: nil, default: nil
|
109
|
+
assert_line :ntext_col, type: 'ntext', limit: '2147483647', precision: nil, scale: nil, default: nil
|
110
|
+
assert_line :binary_basic_col, type: 'binary_basic', limit: '1', precision: nil, scale: nil, default: nil
|
111
|
+
assert_line :varbinary_col, type: 'varbinary', limit: '8000', precision: nil, scale: nil, default: nil
|
112
|
+
assert_line :uuid_col, type: 'uuid', limit: nil, precision: nil, scale: nil, default: nil
|
113
|
+
assert_line :sstimestamp_col, type: 'ss_timestamp', limit: nil, precision: nil, scale: nil, default: nil
|
114
|
+
end
|
115
|
+
|
116
|
+
# Special Cases
|
117
|
+
|
118
|
+
it 'honor nonstandard primary keys' do
|
119
|
+
generate_schema_for_table('movies') do |output|
|
120
|
+
match = output.match(%r{create_table "movies"(.*)do})
|
121
|
+
assert_not_nil(match, "nonstandardpk table not found")
|
122
|
+
assert_match %r(primary_key: "movieid"), match[1], "non-standard primary key not preserved"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'no id with model driven primary key' do
|
127
|
+
output = generate_schema_for_table 'sst_no_pk_data'
|
128
|
+
output.must_match %r{create_table "sst_no_pk_data".*id:\sfalse.*do}
|
129
|
+
assert_line :name, type: 'string', limit: '4000'
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def generate_schema_for_table(*table_names)
|
136
|
+
require 'stringio'
|
137
|
+
stream = StringIO.new
|
138
|
+
ActiveRecord::SchemaDumper.ignore_tables = all_tables - table_names
|
139
|
+
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
140
|
+
@generated_schema = stream.string
|
141
|
+
yield @generated_schema if block_given?
|
142
|
+
@schema_lines = Hash.new
|
143
|
+
type_matcher = /\A\s+t\.\w+\s+"(.*?)"[,\n]/
|
144
|
+
@generated_schema.each_line do |line|
|
145
|
+
next unless line =~ type_matcher
|
146
|
+
@schema_lines[Regexp.last_match[1]] = SchemaLine.new(line)
|
147
|
+
end
|
148
|
+
@generated_schema
|
149
|
+
end
|
150
|
+
|
151
|
+
def line(column_name)
|
152
|
+
@schema_lines[column_name.to_s]
|
153
|
+
end
|
154
|
+
|
155
|
+
def assert_line(column_name, options={})
|
156
|
+
line = line(column_name)
|
157
|
+
assert line, "Count not find line with column name: #{column_name.inspect} in schema:\n#{schema}"
|
158
|
+
[:type, :limit, :precision, :scale, :default].each do |key|
|
159
|
+
next unless options.key?(key)
|
160
|
+
actual = key == :type ? line.send(:type_method) : line.send(key)
|
161
|
+
expected = options[key]
|
162
|
+
message = "#{key.to_s.titleize} of #{expected.inspect} not found in:\n#{line}"
|
163
|
+
if expected.nil?
|
164
|
+
actual.must_be_nil message
|
165
|
+
elsif expected.is_a?(Regexp)
|
166
|
+
actual.must_match expected, message
|
167
|
+
else
|
168
|
+
actual.must_equal expected, message
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class SchemaLine
|
174
|
+
|
175
|
+
attr_reader :line
|
176
|
+
|
177
|
+
def self.match(method_name, pattern)
|
178
|
+
define_method(method_name) { line.match(pattern).try :[], 1 }
|
179
|
+
end
|
180
|
+
|
181
|
+
def initialize(line)
|
182
|
+
@line = line
|
183
|
+
end
|
184
|
+
|
185
|
+
match :type_method, %r{\A\s+t\.(.*?)\s}
|
186
|
+
match :limit, %r{\slimit:\s(.*?)[,\s]}
|
187
|
+
match :default, %r{\sdefault:\s(.*)\n}
|
188
|
+
match :precision, %r{\sprecision:\s(.*?)[,\s]}
|
189
|
+
match :scale, %r{\sscale:\s(.*?)[,\s]}
|
190
|
+
|
191
|
+
def to_s
|
192
|
+
line
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|