typed_uuid 4.0.rc2 → 4.0

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: 581721d0683d1e3bf4bfa2c4bc29d4a7f5079854c85d98d8672e2f9bec6934e9
4
- data.tar.gz: cb660ea624b3be55d02084ca8175035ade7774604a7428cb4555fa00e95460e6
3
+ metadata.gz: eb375ca568f121a2a996b9afd41123e18b820621e4417b2bce05024364eef414
4
+ data.tar.gz: 15d885d11a1dbcb19ca60733312ad0b21bcf77a0f9ce165ce8b25fa24f43cecf
5
5
  SHA512:
6
- metadata.gz: 25835d74e2cf54a76f4be490f95fa98e5b0cbde8ddec6bafdd990a17d9a900fa7033f15f63a4be23609ae1164d686132a0472bec2e168d93f19e6204af1ab315
7
- data.tar.gz: 8dcd77488ddd9f45bba84db7faec4b3e1f37c4258df3dc6273bee7eef1b620799cd725d56338759dc1d488aece3c32102a7364232e03183fa123cef481aa0543
6
+ metadata.gz: 38c295658ce41fac5b51c27fdb4df1922ef426e71c2bb234e7af0e0b87abdb11e8110c3e4604e84909f30aa4a3fd2782b740b443aae9ee926fc7ad567a31a8f6
7
+ data.tar.gz: 42139374aa96e9a43b5f0f7d749a410617fa14c1affd0fa334e1fe59661189fb58d911b26056aa9e5cc6092709db6ab62541c88f788be54cfe946f45bca5868c
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+ name: TypedUUID Test
12
+ runs-on: ubuntu-20.04
13
+
14
+ steps:
15
+ - uses: ruby/setup-ruby@v1
16
+ with:
17
+ ruby-version: 3.0
18
+
19
+ - uses: actions/checkout@v2
20
+
21
+ - run: |
22
+ sudo systemctl start postgresql.service
23
+ sudo -u postgres createuser runner --superuser
24
+ sudo -u postgres createdb uuid-types-test
25
+
26
+ - run: bundle
27
+
28
+ - run: bundle exec rake test
data/README.md CHANGED
@@ -35,9 +35,17 @@ As with regular UUID Typed UUIDs come in multiple version. The current versions
35
35
  bits or a sequence counter. Then 8 random bits followed by 16 bits
36
36
  which are the UUID type.
37
37
 
38
+ - Version 3: A name-based UUID where the first 112 bits are based off the MD5
39
+ digest of the namespace and name. The following 16 bits are the
40
+ UUID type.
41
+
38
42
  - Version 4: A random UUID where the first 112 bits are random. The following
39
43
  16 bits are the UUID type.
40
44
 
45
+ - Version 5: A name-based UUID where the first 112 bits are based off the SHA1
46
+ digest of the namespace and name. The following 16 bits are the
47
+ UUID type.
48
+
41
49
  ## Install
42
50
 
43
51
  Add this to your Gemfile:
@@ -74,7 +82,7 @@ a table.
74
82
 
75
83
  ```ruby
76
84
  class CreateProperties < ActiveRecord::Migration[5.2]
77
- def change
85
+ def change
78
86
  create_table :properties, id: :typed_uuid do |t|
79
87
  t.string "name", limit: 255
80
88
  end
@@ -88,19 +96,19 @@ To add a typed UUID to an existing table:
88
96
  class UpdateProperties < ActiveRecord::Migration[6.1]
89
97
  def change
90
98
  klass_enum = ::ActiveRecord::Base.uuid_type_from_table_name(:properties)
91
-
99
+
92
100
  # Add the column
93
101
  add_column :properties, :typed_uuid, :uuid, default: -> { "typed_uuid('\\x#{klass_enum.to_s(16).rjust(4, '0')}')" }
94
-
102
+
95
103
  # Update existing properties with a new typed UUID
96
104
  execute "UPDATE properties SET id = typed_uuid('\\x#{klass_enum.to_s(16).rjust(4, '0')}');"
97
-
105
+
98
106
  # Add null constraint since we'll swap these out for the primary key
99
107
  change_column_null :properties, :typed_uuid, false
100
-
108
+
101
109
  # TODO: Here you will want to update any reference to the old primary key
102
110
  # with the new typed_uuid that will be the new primary key.
103
-
111
+
104
112
  # Replace the old primary key with the typed_uuid
105
113
  execute "ALTER TABLE properties DROP CONSTRAINT properties_pkey;"
106
114
  rename_column :properties, :typed_uuid, :id
data/lib/typed_uuid.rb CHANGED
@@ -1,52 +1,69 @@
1
+ require 'digest/sha1'
2
+
1
3
  module TypedUUID
2
4
  autoload :ActiveRecord, 'typed_uuid/active_record'
3
5
  autoload :PsqlColumnMethods, 'typed_uuid/psql_column_methods'
4
6
  autoload :PsqlSchemaDumper, 'typed_uuid/psql_schema_dumper'
5
-
6
- def self.uuid(enum, version = 4, **options)
7
- if enum < 0 || enum > 8_191
8
- raise ArgumentError, "UUID type must be between 0 and 8,191"
7
+
8
+ class << self
9
+
10
+ def uuid(enum, version = 4, **options)
11
+ if enum < 0 || enum > 8_191
12
+ raise ArgumentError, "UUID type must be between 0 and 8,191"
13
+ end
14
+
15
+ case version
16
+ when 1
17
+ timestamp_uuid(enum, **options)
18
+ when 3
19
+ namebased_uuid(enum, digester: Digest::MD5, **options)
20
+ when 4
21
+ random_uuid(enum, **options)
22
+ when 5
23
+ namebased_uuid(enum, digester: Digest::SHA1, **options)
24
+ end
9
25
  end
10
-
11
- if version == 1
12
- timestamp_uuid(enum, **options)
13
- elsif version == 4
14
- random_uuid(enum, **options)
26
+
27
+ def random_uuid(enum)
28
+ uuid = SecureRandom.random_bytes(16).unpack("nnnnnnnn")
29
+
30
+ uuid[7] = (uuid[2] ^ uuid[6]) ^ ((enum << 3) | 4)
31
+ "%04x%04x-%04x-%04x-%04x-%04x%04x%04x" % uuid
15
32
  end
16
- end
17
-
18
- def self.random_uuid(enum)
19
- uuid = SecureRandom.random_bytes(16).unpack("nnnnnnnn")
20
-
21
- uuid[7] = (uuid[2] ^ uuid[6]) ^ ((enum << 3) | 4)
22
- "%04x%04x-%04x-%04x-%04x-%04x%04x%04x" % uuid
23
- end
24
-
25
- def self.timestamp_uuid(enum, timestamp: nil, sequence: nil)
26
- timestamp ||= Time.now
27
-
28
- uuid = [timestamp.to_i * 1_000_000 + timestamp.usec].pack('Q>')[1..-1]
29
- uuid << (sequence&.pack('Q>') || SecureRandom.random_bytes(10))
30
-
31
- uuid = uuid.unpack("nnnnnnnn")
32
- uuid[7] = (uuid[2] ^ uuid[6]) ^ ((enum << 3) | 1)
33
- "%04x%04x-%04x-%04x-%04x-%04x%04x%04x" % uuid
34
- end
35
-
36
- def self.enum(uuid)
37
- uuid = uuid.gsub('-', '')
38
- ((uuid[8..11].to_i(16) ^ uuid[24..27].to_i(16)) ^ uuid[28..31].to_i(16)) >> 3
39
- end
40
-
41
- def self.version(uuid)
42
- uuid = uuid.gsub('-', '')
43
- ((uuid[8..11].to_i(16) ^ uuid[24..27].to_i(16)) ^ uuid[28..31].to_i(16)) & 0b0000000000000111
44
- end
45
-
46
- def self.timestamp(uuid)
47
- uuid = uuid.gsub('-', '')
48
- Time.at(*uuid[0..13].to_i(16).divmod(1_000_000), :usec)
33
+
34
+ def timestamp_uuid(enum, timestamp: nil, sequence: nil)
35
+ timestamp ||= Time.now
36
+
37
+ uuid = [timestamp.to_i * 1_000_000 + timestamp.usec].pack('Q>')[1..-1]
38
+ uuid << (sequence&.pack('Q>') || SecureRandom.random_bytes(10))
39
+
40
+ uuid = uuid.unpack("nnnnnnnn")
41
+ uuid[7] = (uuid[2] ^ uuid[6]) ^ ((enum << 3) | 1)
42
+ "%04x%04x-%04x-%04x-%04x-%04x%04x%04x" % uuid
43
+ end
44
+
45
+ def namebased_uuid(enum, digester:, name:, namespace: "")
46
+ uuid = digester.digest(name + namespace).unpack("nnnnnnnn")
47
+ uuid[7] = (uuid[2] ^ uuid[6]) ^ ((enum << 3) | 5)
48
+ "%04x%04x-%04x-%04x-%04x-%04x%04x%04x" % uuid
49
+ end
50
+
51
+ def enum(uuid)
52
+ uuid = uuid.gsub('-', '')
53
+ ((uuid[8..11].to_i(16) ^ uuid[24..27].to_i(16)) ^ uuid[28..31].to_i(16)) >> 3
54
+ end
55
+
56
+ def version(uuid)
57
+ uuid = uuid.gsub('-', '')
58
+ ((uuid[8..11].to_i(16) ^ uuid[24..27].to_i(16)) ^ uuid[28..31].to_i(16)) & 0b0000000000000111
59
+ end
60
+
61
+ def timestamp(uuid)
62
+ uuid = uuid.gsub('-', '')
63
+ Time.at(*uuid[0..13].to_i(16).divmod(1_000_000), :usec)
64
+ end
65
+
49
66
  end
50
67
  end
51
68
 
52
- require 'typed_uuid/railtie' if defined? Rails
69
+ require 'typed_uuid/railtie' if defined? Rails
@@ -2,16 +2,17 @@ class TypedUUID::Railtie < Rails::Railtie
2
2
 
3
3
  initializer :typed_uuid do |app|
4
4
  ActiveRecord::Tasks::DatabaseTasks.migrations_paths << File.expand_path('../../../db/migrate', __FILE__)
5
-
5
+
6
6
  ActiveSupport.on_load(:active_record) do
7
7
  ActiveRecord::Base.include TypedUUID::ActiveRecord
8
8
  end
9
-
9
+
10
10
  require 'active_record/connection_adapters/postgresql/schema_definitions'
11
11
  ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition.include(TypedUUID::PsqlColumnMethods)
12
-
12
+
13
+ require 'active_record/connection_adapters/abstract/schema_dumper'
13
14
  require 'active_record/connection_adapters/postgresql/schema_dumper'
14
15
  ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaDumper.prepend(TypedUUID::PsqlSchemaDumper)
15
16
  end
16
17
 
17
- end
18
+ end
@@ -1,3 +1,3 @@
1
1
  module TypedUUID
2
- VERSION = '4.0.rc2'
2
+ VERSION = '4.0'
3
3
  end
data/test/test_helper.rb CHANGED
@@ -32,7 +32,7 @@ def MiniTest.filter_backtrace(bt)
32
32
  bt
33
33
  end
34
34
  class ActiveSupport::TestCase
35
-
35
+
36
36
  # File 'lib/active_support/testing/declarative.rb'
37
37
  def self.test(name, &block)
38
38
  test_name = "test_#{name.gsub(/\s+/, '_')}".to_sym
@@ -46,31 +46,32 @@ class ActiveSupport::TestCase
46
46
  end
47
47
  end
48
48
  end
49
-
49
+
50
50
  def self.schema(&block)
51
51
  self.class_variable_set(:@@schema, block)
52
52
  end
53
-
53
+
54
54
  set_callback(:setup, :before) do
55
55
  Rails.stubs(:application).returns(stub(config: stub(eager_load: true)))
56
56
  if !self.class.class_variable_defined?(:@@suite_setup_run)
57
57
  ActiveRecord::Base.defined_uuid_types.clear
58
58
  ActiveRecord::Base.uuid_enum_to_class_cache.clear
59
59
  ActiveRecord::Base.class_to_uuid_type_cache.clear
60
-
60
+
61
61
  configuration = {
62
62
  adapter: "postgresql",
63
63
  database: "uuid-types-test",
64
64
  encoding: "utf8"
65
65
  }.stringify_keys
66
-
67
- db_tasks = ActiveRecord::Tasks::PostgreSQLDatabaseTasks.new(configuration)
68
- db_tasks.purge
69
-
66
+
70
67
  ActiveRecord::Base.establish_connection(configuration)
68
+
69
+ db_tasks = ActiveRecord::Tasks::PostgreSQLDatabaseTasks.new(ActiveRecord::Base.connection_db_config)
70
+ db_tasks.purge
71
+
71
72
  ActiveRecord::Migration.suppress_messages do
72
73
  AddTypedUuidFunction.migrate :up
73
-
74
+
74
75
  if self.class.class_variable_defined?(:@@schema)
75
76
  ActiveRecord::Schema.define(&self.class.class_variable_get(:@@schema))
76
77
  ActiveRecord::Migration.execute("SELECT c.relname FROM pg_class c WHERE c.relkind = 'S'").each_row do |row|
@@ -134,7 +135,7 @@ class ActiveSupport::TestCase
134
135
  end
135
136
  end
136
137
  end
137
-
138
+
138
139
  class SQLLogger
139
140
  class << self
140
141
  attr_accessor :ignored_sql, :log, :log_all
@@ -197,5 +198,5 @@ class ActiveSupport::TestCase
197
198
  alias :assert_not_predicate :refute_predicate
198
199
  alias :assert_not_respond_to :refute_respond_to
199
200
  alias :assert_not_same :refute_same
200
-
201
- end
201
+
202
+ end
@@ -1,45 +1,45 @@
1
1
  require 'test_helper'
2
2
 
3
- class FilterTest < ActiveSupport::TestCase
3
+ class UUIDTest < ActiveSupport::TestCase
4
4
 
5
5
  schema do
6
6
  ActiveRecord::Base.register_uuid_types({
7
- 'FilterTest::Listing' => {enum: 0, version: 1},
8
- 'FilterTest::Building' => 592,
9
- 'FilterTest::SkyScraper' => {enum: 1_952}
7
+ 'UUIDTest::Listing' => {enum: 0, version: 1},
8
+ 'UUIDTest::Building' => 592,
9
+ 'UUIDTest::SkyScraper' => {enum: 1_952}
10
10
  })
11
-
11
+
12
12
  create_table :listings, id: :typed_uuid do |t|
13
13
  t.string "name", limit: 255
14
14
  end
15
-
15
+
16
16
  create_table :buildings, id: :typed_uuid do |t|
17
17
  t.string "name", limit: 255
18
18
  t.string "type", limit: 255
19
19
  end
20
20
  end
21
-
21
+
22
22
  class Listing < ActiveRecord::Base
23
23
  end
24
-
24
+
25
25
  class Building < ActiveRecord::Base
26
26
  end
27
-
27
+
28
28
  class SkyScraper < Building
29
29
  end
30
30
 
31
31
  class SingleFamilyHome < Building
32
32
  end
33
-
33
+
34
34
  class Property < ActiveRecord::Base
35
35
  end
36
-
36
+
37
37
  class Lot < ActiveRecord::Base
38
38
  end
39
-
39
+
40
40
  test 'adding primary key as a typed_uuid in a migration' do
41
41
  ActiveRecord::Base.register_uuid_types({
42
- 1 => 'FilterTest::Property'
42
+ 1 => 'UUIDTest::Property'
43
43
  })
44
44
 
45
45
  exprexted_sql = <<-SQL
@@ -57,7 +57,7 @@ class FilterTest < ActiveSupport::TestCase
57
57
 
58
58
  test 'adding primary key as a typed_uuid in a migration with a version' do
59
59
  ActiveRecord::Base.register_uuid_types({
60
- 'FilterTest::Lot' => {version: 1, enum: 512}
60
+ 'UUIDTest::Lot' => {version: 1, enum: 512}
61
61
  })
62
62
 
63
63
  exprexted_sql = <<-SQL
@@ -75,58 +75,61 @@ class FilterTest < ActiveSupport::TestCase
75
75
 
76
76
  test 'typed_uuid' do
77
77
  assert_equal 512, TypedUUID.enum(TypedUUID.uuid(512))
78
- assert_equal FilterTest::Listing, ::ActiveRecord::Base.class_from_uuid(Listing.typed_uuid)
79
- assert_equal FilterTest::Building, ::ActiveRecord::Base.class_from_uuid(Building.typed_uuid)
80
- assert_equal FilterTest::SkyScraper, ::ActiveRecord::Base.class_from_uuid(SkyScraper.typed_uuid)
81
-
78
+ assert_equal 512, TypedUUID.enum(TypedUUID.uuid(512, 1))
79
+ assert_equal 512, TypedUUID.enum(TypedUUID.uuid(512, 3, name: "test"))
80
+ assert_equal 512, TypedUUID.enum(TypedUUID.uuid(512, 5, name: "test"))
81
+ assert_equal UUIDTest::Listing, ::ActiveRecord::Base.class_from_uuid(Listing.typed_uuid)
82
+ assert_equal UUIDTest::Building, ::ActiveRecord::Base.class_from_uuid(Building.typed_uuid)
83
+ assert_equal UUIDTest::SkyScraper, ::ActiveRecord::Base.class_from_uuid(SkyScraper.typed_uuid)
84
+
82
85
  assert_raises ArgumentError do
83
86
  ::ActiveRecord::Base.class_from_uuid(SingleFamilyHome.typed_uuid)
84
87
  end
85
88
  end
86
-
89
+
87
90
  test 'typed_uuid v1' do
88
91
  time = Time.at(1606612254, 370979, :usec)
89
92
  Time.stubs(:now).returns(time)
90
93
 
91
94
  uuid = TypedUUID.uuid(592, 1)
92
-
95
+
93
96
  assert_equal 1, TypedUUID.version(uuid)
94
97
  assert_equal 592, TypedUUID.enum(uuid)
95
-
98
+
96
99
  assert_equal time, TypedUUID.timestamp(uuid)
97
100
  assert_equal time.to_i, TypedUUID.timestamp(uuid).to_i
98
101
  assert_equal time.nsec, TypedUUID.timestamp(uuid).nsec
99
-
102
+
100
103
  assert_equal Listing, ::ActiveRecord::Base.class_from_uuid(Listing.typed_uuid)
101
104
  end
102
-
105
+
103
106
  test 'class_from uuid generated bye PostgresQL' do
104
107
  listing = Listing.create
105
108
  building = Building.create
106
109
  skyscraper = SkyScraper.create
107
-
108
- assert_equal FilterTest::Listing, ::ActiveRecord::Base.class_from_uuid(listing.id)
109
- assert_equal FilterTest::Building, ::ActiveRecord::Base.class_from_uuid(building.id)
110
- assert_equal FilterTest::SkyScraper, ::ActiveRecord::Base.class_from_uuid(skyscraper.id)
110
+
111
+ assert_equal UUIDTest::Listing, ::ActiveRecord::Base.class_from_uuid(listing.id)
112
+ assert_equal UUIDTest::Building, ::ActiveRecord::Base.class_from_uuid(building.id)
113
+ assert_equal UUIDTest::SkyScraper, ::ActiveRecord::Base.class_from_uuid(skyscraper.id)
111
114
 
112
115
  assert_raises ArgumentError do
113
116
  SingleFamilyHome.create
114
117
  end
115
118
  end
116
-
119
+
117
120
  test 'class_from v1 uuid generated bye PostgresQL' do
118
121
  listing = Listing.create
119
-
122
+
120
123
  assert_equal Listing, ::ActiveRecord::Base.class_from_uuid(listing.id)
121
124
  end
122
-
125
+
123
126
  test 'uuid_enum from table_name' do
124
127
  assert_equal 0, ::ActiveRecord::Base.uuid_enum_from_table_name(:listings)
125
128
  assert_equal 0, ::ActiveRecord::Base.uuid_enum_from_table_name('listings')
126
-
129
+
127
130
  assert_equal 592, ::ActiveRecord::Base.uuid_enum_from_table_name(:buildings)
128
131
  end
129
-
132
+
130
133
  test 'uuid_version from table_name' do
131
134
  assert_equal 1, ::ActiveRecord::Base.uuid_version_from_table_name(:listings)
132
135
  assert_equal 1, ::ActiveRecord::Base.uuid_version_from_table_name('listings')
@@ -144,11 +147,11 @@ class FilterTest < ActiveSupport::TestCase
144
147
  assert_equal 4, ::ActiveRecord::Base.uuid_version_from_class(Building)
145
148
  assert_equal 4, ::ActiveRecord::Base.uuid_version_from_class(SkyScraper)
146
149
  end
147
-
150
+
148
151
  test 'class from uuid_enum' do
149
- assert_equal FilterTest::Listing, ::ActiveRecord::Base.class_from_uuid_enum(0)
150
- assert_equal FilterTest::Building, ::ActiveRecord::Base.class_from_uuid_enum(592)
151
- assert_equal FilterTest::SkyScraper, ::ActiveRecord::Base.class_from_uuid_enum(1_952)
152
+ assert_equal UUIDTest::Listing, ::ActiveRecord::Base.class_from_uuid_enum(0)
153
+ assert_equal UUIDTest::Building, ::ActiveRecord::Base.class_from_uuid_enum(592)
154
+ assert_equal UUIDTest::SkyScraper, ::ActiveRecord::Base.class_from_uuid_enum(1_952)
152
155
  end
153
-
154
- end
156
+
157
+ end
data/typed_uuid.gemspec CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
14
14
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
15
  s.require_paths = ["lib"]
16
16
 
17
- # Developoment
17
+ # Developoment
18
18
  s.add_development_dependency 'rake'
19
19
  s.add_development_dependency 'bundler'
20
20
  s.add_development_dependency 'minitest'
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
25
25
  s.add_development_dependency 'activesupport', '>= 6.0.0'
26
26
  s.add_development_dependency 'rails', '>= 6.0.0'
27
27
  s.add_development_dependency 'pg'
28
-
28
+
29
29
  # Runtime
30
30
  s.add_runtime_dependency 'activerecord', '>= 6.0.0'
31
- end
31
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: typed_uuid
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.rc2
4
+ version: '4.0'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Bracy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-21 00:00:00.000000000 Z
11
+ date: 2021-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -171,6 +171,7 @@ executables: []
171
171
  extensions: []
172
172
  extra_rdoc_files: []
173
173
  files:
174
+ - ".github/workflows/ci.yml"
174
175
  - ".gitignore"
175
176
  - ".tm_properties"
176
177
  - Gemfile
@@ -201,9 +202,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
201
202
  version: '0'
202
203
  required_rubygems_version: !ruby/object:Gem::Requirement
203
204
  requirements:
204
- - - ">"
205
+ - - ">="
205
206
  - !ruby/object:Gem::Version
206
- version: 1.3.1
207
+ version: '0'
207
208
  requirements: []
208
209
  rubygems_version: 3.2.3
209
210
  signing_key: