typed_uuid 4.0.rc2 → 4.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.
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: