Skip to content

Commit ab34f08

Browse files
committed
UUID now passing with real type.
1 parent 54254f9 commit ab34f08

File tree

13 files changed

+105
-171
lines changed

13 files changed

+105
-171
lines changed

lib/active_record/connection_adapters/sqlserver/schema_creation.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@ def visit_ColumnDefinition(o)
1616

1717
def add_column_options!(sql, options)
1818
column = options.fetch(:column) { return super }
19-
if [:uniqueidentifier, :uuid].include?(column.type) && options[:default] =~ /\(\)/
19+
if (column.type == :uuid || column.type == :uniqueidentifier) && options[:default] =~ /\(\)/
2020
sql << " DEFAULT #{options.delete(:default)}"
21-
super
2221
else
2322
super
2423
end

lib/active_record/connection_adapters/sqlserver/table_definition.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def varbinary(name, options = {})
5555
end
5656

5757
def uuid(name, options = {})
58-
column(name, 'uniqueidentifier', options)
58+
column(name, :uniqueidentifier, options)
5959
end
6060

6161
end

lib/active_record/connection_adapters/sqlserver/type.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@
3535
require 'active_record/connection_adapters/sqlserver/type/binary.rb'
3636
require 'active_record/connection_adapters/sqlserver/type/varbinary.rb'
3737
require 'active_record/connection_adapters/sqlserver/type/varbinary_max.rb'
38+
# Other Data Types
39+
require 'active_record/connection_adapters/sqlserver/type/uuid.rb'
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module ActiveRecord
2+
module ConnectionAdapters
3+
module SQLServer
4+
module Type
5+
class Uuid < String
6+
7+
ACCEPTABLE_UUID = %r{\A\{?([a-fA-F0-9]{4}-?){8}\}?\z}x
8+
9+
alias_method :type_cast_for_database, :type_cast_from_database
10+
11+
def type
12+
:uuid
13+
end
14+
15+
def type_cast(value)
16+
value.to_s[ACCEPTABLE_UUID, 0]
17+
end
18+
19+
end
20+
end
21+
end
22+
end
23+
end

lib/active_record/connection_adapters/sqlserver_adapter.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ def valid_type?(type)
6161
!native_database_types[type].nil?
6262
end
6363

64+
def schema_creation
65+
SQLServer::SchemaCreation.new self
66+
end
67+
6468
def adapter_name
6569
ADAPTER_NAME
6670
end
@@ -151,10 +155,6 @@ def primary_key(table_name)
151155
identity_column(table_name).try(:name) || schema_cache.columns(table_name).find(&:is_primary?).try(:name)
152156
end
153157

154-
def schema_creation
155-
SQLServer::SchemaCreation.new self
156-
end
157-
158158
# === SQLServer Specific (DB Reflection) ======================== #
159159

160160
def sqlserver?
@@ -237,6 +237,8 @@ def initialize_type_map(m)
237237
register_class_with_limit m, %r{\Abinary}i, SQLServer::Type::Binary
238238
register_class_with_limit m, %r{\Avarbinary}i, SQLServer::Type::Varbinary
239239
m.register_type 'varbinary(max)', SQLServer::Type::VarbinaryMax.new
240+
# Other Data Types
241+
m.register_type 'uniqueidentifier', SQLServer::Type::Uuid.new
240242
end
241243

242244
def translate_exception(e, message)

test/cases/column_test_sqlserver.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,32 @@ def assert_obj_set_and_save(attribute, value)
644644
assert_obj_set_and_save :varbinary_max, binary_data
645645
end
646646

647+
# Other Data Types
648+
649+
it 'uniqueidentifier' do
650+
col = column('uniqueidentifier')
651+
col.sql_type.must_equal 'uniqueidentifier'
652+
col.null.must_equal true
653+
col.default.must_equal nil
654+
col.default_function.must_equal 'newid()'
655+
type = col.cast_type
656+
type.must_be_instance_of Type::Uuid
657+
type.type.must_equal :uuid
658+
type.wont_be :number?
659+
type.limit.must_equal nil
660+
type.precision.must_equal nil
661+
type.scale.must_equal nil
662+
# Basic set and save.
663+
obj.uniqueidentifier = "this will not qualify as valid"
664+
obj.uniqueidentifier.must_equal nil
665+
obj.save! ; obj.reload
666+
obj.uniqueidentifier.must_match Type::Uuid::ACCEPTABLE_UUID
667+
obj.uniqueidentifier = "6F9619FF-8B86-D011-B42D-00C04FC964FF"
668+
obj.uniqueidentifier.must_equal "6F9619FF-8B86-D011-B42D-00C04FC964FF"
669+
obj.save! ; obj.reload
670+
obj.uniqueidentifier.must_equal "6F9619FF-8B86-D011-B42D-00C04FC964FF"
671+
end
672+
647673
end
648674

649675
end

test/cases/schema_dumper_test_sqlserver.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
4343
assert_line :binary_49, type: 'binary_basic', limit: '49', precision: nil, scale: nil, default: nil
4444
assert_line :varbinary_49, type: 'varbinary', limit: '49', precision: nil, scale: nil, default: nil
4545
assert_line :varbinary_max, type: 'binary', limit: '2147483647', precision: nil, scale: nil, default: nil
46+
# Other Data Types
47+
assert_line :uniqueidentifier, type: 'uuid', limit: nil, precision: nil, scale: nil, default: nil
4648
end
4749

4850
it 'sst_datatypes_migration' do
@@ -84,6 +86,7 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
8486
columns['ntext_col'].sql_type.must_equal 'ntext'
8587
columns['binary_basic_col'].sql_type.must_equal 'binary(1)'
8688
columns['varbinary_col'].sql_type.must_equal 'varbinary(8000)'
89+
columns['uuid_col'].sql_type.must_equal 'uniqueidentifier'
8790
assert_line :real_col, type: 'real', limit: nil, precision: nil, scale: nil, default: nil
8891
assert_line :money_col, type: 'money', limit: nil, precision: '19', scale: '4', default: nil
8992
assert_line :smallmoney_col, type: 'smallmoney', limit: nil, precision: '10', scale: '4', default: nil
@@ -94,6 +97,7 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
9497
assert_line :ntext_col, type: 'ntext', limit: '2147483647', precision: nil, scale: nil, default: nil
9598
assert_line :binary_basic_col, type: 'binary_basic', limit: '1', precision: nil, scale: nil, default: nil
9699
assert_line :varbinary_col, type: 'varbinary', limit: '8000', precision: nil, scale: nil, default: nil
100+
assert_line :uuid_col, type: 'uuid', limit: nil, precision: nil, scale: nil, default: nil
97101
end
98102

99103
# Special Cases

test/cases/specific_schema_test_sqlserver.rb

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -99,42 +99,12 @@ class SpecificSchemaTestSQLServer < ActiveRecord::TestCase
9999
assert_equal ['C','B','A'], SSTestEdgeSchema.order('description DESC').map(&:description)
100100
end
101101

102-
# With uniqueidentifier column
103-
104-
let(:newid) { ActiveRecord::Base.connection.newid_function }
102+
# For uniqueidentifier model helpers
105103

106104
it 'returns a new id via connection newid_function' do
107-
assert_guid newid
108-
end
109-
110-
it 'allow a simple insert and read of a column without a default function' do
111-
obj = SSTestEdgeSchema.create! guid: newid
112-
assert_equal newid, SSTestEdgeSchema.find(obj.id).guid
113-
end
114-
115-
it 'record the default function name in the column definition but still show a nil real default, will use one day for insert/update' do
116-
newid_column = SSTestEdgeSchema.columns_hash['guid_newid']
117-
assert newid_column.default_function.present?
118-
assert_nil newid_column.default
119-
assert_equal 'newid()', newid_column.default_function
120-
newseqid_column = SSTestEdgeSchema.columns_hash['guid_newseqid']
121-
assert newseqid_column.default_function.present?
122-
assert_nil newseqid_column.default
123-
assert_equal 'newsequentialid()', newseqid_column.default_function
124-
end
125-
126-
it 'use model callback to set get a new guid' do
127-
obj = SSTestEdgeSchema.new
128-
obj.new_id_setting = true
129-
obj.save!
130-
assert_guid obj.guid_newid
131-
end
132-
133-
134-
protected
135-
136-
def assert_guid(guid)
137-
assert_match %r|\w{8}-\w{4}-\w{4}-\w{4}-\w{12}|, guid
105+
acceptable_uuid = ActiveRecord::ConnectionAdapters::SQLServer::Type::Uuid::ACCEPTABLE_UUID
106+
db_uuid = ActiveRecord::Base.connection.newid_function
107+
db_uuid.must_match(acceptable_uuid)
138108
end
139109

140110
end

test/cases/uuid_test_sqlserver.rb

Lines changed: 26 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,41 @@
11
require 'cases/helper_sqlserver'
22

3-
class SQLServerUUIDTest < ActiveRecord::TestCase
4-
class UUID < ActiveRecord::Base
5-
self.table_name = 'sql_server_uuids'
6-
end
7-
8-
def setup
9-
@connection = ActiveRecord::Base.connection
10-
11-
@connection.reconnect!
12-
13-
@connection.transaction do
14-
@connection.create_table('sql_server_uuids', id: :uuid, default: 'NEWSEQUENTIALID()') do |t|
15-
t.string 'name'
16-
t.uuid 'other_uuid', default: 'NEWID()'
17-
end
18-
end
19-
end
20-
21-
def teardown
22-
@connection.execute "IF OBJECT_ID('sql_server_uuids', 'U') IS NOT NULL DROP TABLE sql_server_uuids"
23-
end
24-
25-
def test_id_is_uuid
26-
assert_equal :uuid, UUID.columns_hash['id'].type
27-
assert UUID.primary_key
28-
end
3+
class SQLServerUuidTest < ActiveRecord::TestCase
294

30-
def test_id_has_a_default
31-
u = UUID.create
32-
assert_not_nil u.id
33-
end
5+
let(:acceptable_uuid) { ActiveRecord::ConnectionAdapters::SQLServer::Type::Uuid::ACCEPTABLE_UUID }
346

35-
def test_auto_create_uuid
36-
u = UUID.create
37-
u.reload
38-
assert_not_nil u.other_uuid
7+
it 'has a uuid primary key' do
8+
SSTestUuid.columns_hash['id'].type.must_equal :uuid
9+
assert SSTestUuid.primary_key
3910
end
4011

41-
def test_pk_and_sequence_for_uuid_primary_key
42-
pk, seq = @connection.pk_and_sequence_for('sql_server_uuids')
43-
assert_equal 'id', pk
44-
assert_equal nil, seq
12+
it 'can create with a new pk' do
13+
obj = SSTestUuid.create!
14+
obj.id.must_be :present?
15+
obj.id.must_match acceptable_uuid
4516
end
4617

47-
def primary_key_for_uuid_primary_key
48-
assert_equal 'id', @connection.primary_key('sql_server_uuids')
18+
it 'can create other uuid column on reload' do
19+
obj = SSTestUuid.create!
20+
obj.reload
21+
obj.other_uuid.must_match acceptable_uuid
4922
end
5023

51-
def test_change_column_default
52-
@connection.add_column :sql_server_uuids, :thingy, :uuid, null: false, default: "NEWSEQUENTIALID()"
53-
UUID.reset_column_information
54-
column = UUID.columns.find { |c| c.name == 'thingy' }
55-
assert_equal "newsequentialid()", column.default_function
56-
57-
@connection.change_column :sql_server_uuids, :thingy, :uuid, null: false, default: "NEWID()"
58-
59-
UUID.reset_column_information
60-
column = UUID.columns.find { |c| c.name == 'thingy' }
61-
assert_equal "newid()", column.default_function
24+
it 'can find uuid pk via connection' do
25+
connection.primary_key(SSTestUuid.table_name).must_equal 'id'
6226
end
63-
end
6427

65-
class SQLServerUUIDTestNilDefault < ActiveRecord::TestCase
66-
class UUID < ActiveRecord::Base
67-
self.table_name = 'sql_server_uuids'
28+
it 'changing column default' do
29+
table_name = SSTestUuid.table_name
30+
connection.add_column table_name, :thingy, :uuid, null: false, default: "NEWSEQUENTIALID()"
31+
SSTestUuid.reset_column_information
32+
column = SSTestUuid.columns_hash['thingy']
33+
column.default_function.must_equal "newsequentialid()"
34+
# Now to a different function.
35+
connection.change_column table_name, :thingy, :uuid, null: false, default: "NEWID()"
36+
SSTestUuid.reset_column_information
37+
column = SSTestUuid.columns_hash['thingy']
38+
column.default_function.must_equal "newid()"
6839
end
6940

70-
def setup
71-
@connection = ActiveRecord::Base.connection
72-
73-
@connection.reconnect!
74-
75-
@connection.transaction do
76-
@connection.create_table('sql_server_uuids', id: false) do |t|
77-
t.primary_key :id, :uuid, default: nil
78-
t.string 'name'
79-
end
80-
end
81-
end
82-
83-
def teardown
84-
@connection.execute "IF OBJECT_ID('sql_server_uuids', 'U') IS NOT NULL DROP TABLE sql_server_uuids"
85-
end
86-
87-
end
88-
89-
class SQLServerUUIDTestInverseOf < ActiveRecord::TestCase
90-
class UuidPost < ActiveRecord::Base
91-
self.table_name = 'sql_server_uuid_posts'
92-
has_many :uuid_comments, inverse_of: :uuid_post
93-
end
94-
95-
class UuidComment < ActiveRecord::Base
96-
self.table_name = 'sql_server_uuid_comments'
97-
belongs_to :uuid_post
98-
end
99-
100-
def setup
101-
@connection = ActiveRecord::Base.connection
102-
@connection.reconnect!
103-
104-
@connection.transaction do
105-
@connection.create_table('sql_server_uuid_posts', id: :uuid) do |t|
106-
t.string 'title'
107-
end
108-
@connection.create_table('sql_server_uuid_comments', id: :uuid) do |t|
109-
t.uuid :uuid_post_id, default: 'NEWID()'
110-
t.string 'content'
111-
end
112-
end
113-
end
114-
115-
def teardown
116-
@connection.transaction do
117-
@connection.execute "IF OBJECT_ID('sql_server_uuid_comments', 'U') IS NOT NULL DROP TABLE sql_server_uuid_comments"
118-
@connection.execute "IF OBJECT_ID('sql_server_uuid_posts', 'U') IS NOT NULL DROP TABLE sql_server_uuid_posts"
119-
end
120-
end
121-
122-
def test_collection_association_with_uuid
123-
post = UuidPost.create!
124-
comment = post.uuid_comments.create!
125-
assert post.uuid_comments.find(comment.id)
126-
end
12741
end

test/models/sqlserver/edge_schema.rb

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@ class SSTestEdgeSchema < ActiveRecord::Base
22

33
self.table_name = 'sst_edge_schemas'
44

5-
attr_accessor :new_id_setting
6-
7-
before_create :set_new_id
8-
95
def with_spaces
106
read_attribute :'with spaces'
117
end
@@ -14,10 +10,4 @@ def with_spaces=(value)
1410
write_attribute :'with spaces', value
1511
end
1612

17-
protected
18-
19-
def set_new_id
20-
self[:guid_newid] ||= self.class.connection.newid_function if new_id_setting
21-
end
22-
2313
end

0 commit comments

Comments
 (0)