typed_uuid 2.1 → 3.2

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: d0743664e3f9987059821b25c8c42f80b062bbeeb3ba563e795d4b9845920505
4
- data.tar.gz: ec150decbaced84ca8cbd26b06af761551969ee9cc74145291c552215ab2a94b
3
+ metadata.gz: c9b97eecee8303b2863faf3982c4080d347c9dabc4b0fca45c2c5dc7c74b6172
4
+ data.tar.gz: 72d70bc0bc247987141c6ee4710a5ef34257693179b1d526dcc6fbf427e414f5
5
5
  SHA512:
6
- metadata.gz: e3e66ca9962d22a9ccece4458708c132e776062dc5d10071b715816c4c5329a99c6bea6b172e0f33a55c274a761e0850c1cb4a957b31de2124f3942d60204aa3
7
- data.tar.gz: 502b8f036034be6a080aa0722b26918810589fc741666d2ab4f0c125d987895bc2ba19ab886b79ff13b97e38b50698808dbc28eb80d2b1d822c1dda055f89ad3
6
+ metadata.gz: 204697bd0dc2c7dd64b62dc7b7955cb5d83242c5966bc447c84d79d343f3b0825cc8bd1bb450525a3acc3405a61a1740b06f127a9df6f5f5830f9a063a75f18a
7
+ data.tar.gz: cba9d2425930e678e4c44bfc163392fb749c249f5e2930b62998f22fae5ad10cdaa9e8df5df013b6155eac8c1c242056e4ff67b65dfb63140f82f545b24d38d4
data/README.md CHANGED
@@ -33,24 +33,27 @@ Add this to your Gemfile:
33
33
  `gem 'typed_uuid'`
34
34
 
35
35
  Once bundled you can add an initializer to Rails to register your types as shown
36
- below. This maps the __table_names__ of the models to an integer between 0 and 255.
36
+ below. This maps the __Model Classes__ to an integer between 0 and 65,535.
37
37
 
38
38
  ```ruby
39
39
  # config/initializers/uuid_types.rb
40
40
 
41
41
  ActiveRecord::Base.register_uuid_types({
42
- listings: 0,
43
- buildings: 65_535
42
+ Listing: 0,
43
+ Building: 512,
44
+ 'Building::SkyScrpaer' => 65_535
44
45
  })
45
46
 
46
47
  # Or:
47
48
 
48
49
  ActiveRecord::Base.register_uuid_types({
49
- 0 => :listings,
50
- 65_535 => :buildings
50
+ 0 => :Listing,
51
+ 512 => :Building,
52
+ 65_535 => 'Building::SkyScrpaer'
51
53
  })
52
54
  ```
53
55
 
56
+
54
57
  ## Usage
55
58
 
56
59
  In your migrations simply replace `id: :uuid` with `id: :typed_uuid` when creating
@@ -64,4 +67,12 @@ class CreateProperties < ActiveRecord::Migration[5.2]
64
67
  end
65
68
  end
66
69
  end
67
- ```
70
+ ```
71
+
72
+ ## STI Models
73
+ When using STI Model Rails will generate the UUID to be inserted. This UUID will
74
+ be calculated of the STI Model class and not the base class.
75
+
76
+ In the migration you can still used `id: :typed_uuid`, this will use the base
77
+ class to calculated the default type for the UUID. You could also set the
78
+ `id` to `:uuid` and the `default` to `false` so when no ID is given it will error.
@@ -1,18 +1,20 @@
1
1
  class AddTypedUuidFunction < ActiveRecord::Migration[6.0]
2
2
  def up
3
- enable_extension 'pgcrypto'
3
+ if connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
4
+ enable_extension 'pgcrypto'
4
5
 
5
- execute <<-SQL
6
- CREATE OR REPLACE FUNCTION typed_uuid(t bytea) RETURNS uuid AS $$
7
- DECLARE
8
- bytes bytea := gen_random_bytes(16);
9
- uuid bytea;
10
- BEGIN
11
- bytes := set_byte(bytes, 6, (get_byte(bytes, 4) # get_byte(bytes, 8)) # get_byte(t, 0));
12
- bytes := set_byte(bytes, 7, (get_byte(bytes, 5) # get_byte(bytes, 9)) # get_byte(t, 1));
13
- RETURN encode( bytes, 'hex') :: uuid;
14
- END;
15
- $$ LANGUAGE plpgsql;
16
- SQL
6
+ execute <<-SQL
7
+ CREATE OR REPLACE FUNCTION typed_uuid(t bytea) RETURNS uuid AS $$
8
+ DECLARE
9
+ bytes bytea := gen_random_bytes(16);
10
+ uuid bytea;
11
+ BEGIN
12
+ bytes := set_byte(bytes, 6, (get_byte(bytes, 4) # get_byte(bytes, 8)) # get_byte(t, 0));
13
+ bytes := set_byte(bytes, 7, (get_byte(bytes, 5) # get_byte(bytes, 9)) # get_byte(t, 1));
14
+ RETURN encode( bytes, 'hex') :: uuid;
15
+ END;
16
+ $$ LANGUAGE plpgsql;
17
+ SQL
18
+ end
17
19
  end
18
- end
20
+ end
@@ -2,6 +2,17 @@ module TypedUUID
2
2
  autoload :ActiveRecord, 'typed_uuid/active_record'
3
3
  autoload :PsqlColumnMethods, 'typed_uuid/psql_column_methods'
4
4
  autoload :PsqlSchemaDumper, 'typed_uuid/psql_schema_dumper'
5
+
6
+ def self.uuid(enum)
7
+ uuid = SecureRandom.random_bytes(16).unpack("NnnnnN")
8
+ uuid[2] = (uuid[1] ^ uuid[3]) ^ enum
9
+ "%08x-%04x-%04x-%04x-%04x%08x" % uuid
10
+ end
11
+
12
+ def self.enum(uuid)
13
+ uuid = uuid.gsub('-', '')
14
+ (uuid[8..11].to_i(16) ^ uuid[16..19].to_i(16)) ^ uuid[12..15].to_i(16)
15
+ end
5
16
  end
6
17
 
7
18
  require 'typed_uuid/railtie' if defined? Rails
@@ -1,67 +1,108 @@
1
+ require 'active_support/concern'
2
+
1
3
  module TypedUUID::ActiveRecord
4
+ extend ActiveSupport::Concern
2
5
 
3
6
  UUID_TYPE_CONFLICT_MESSAGE = \
4
- "You tried to define an UUID type %{int} for \"%{table}\", but " \
7
+ "You tried to define an UUID type %{int} for \"%{class_name}\", but " \
5
8
  " %{int} is already defined as the type for %{other}"
6
-
7
- def self.extended(base) # :nodoc:
8
- base.class_attribute(:defined_uuid_types, instance_writer: false, default: {})
9
- base.class_attribute(:uuid_type_cache, instance_writer: false, default: {})
9
+
10
+ included do
11
+ class_attribute(:defined_uuid_types, instance_writer: false, default: {})
12
+ class_attribute(:class_to_uuid_type_cache, instance_writer: false, default: Hash.new { |hash, klass|
13
+ hash[klass] = defined_uuid_types.key(klass.name)
14
+ })
15
+ class_attribute(:uuid_type_to_class_cache, instance_writer: false, default: {})
10
16
  end
11
17
 
12
- def register_uuid_type(table, int)
13
- if int < 0 || int > 65_535
14
- raise ArgumentError, "UUID type must be between 0 and 65,535"
15
- elsif defined_uuid_types.has_key?(int)
16
- raise ArgumentError, UUID_TYPE_CONFLICT_MESSAGE % {
17
- int: int,
18
- table: table,
19
- other: defined_uuid_types[int]
20
- }
21
- else
22
- defined_uuid_types[int] = table.to_s
18
+ def _create_record
19
+ klass = self.class
20
+ if !klass.descends_from_active_record? && klass.typed?
21
+ pk = klass.primary_key
22
+ write_attribute(pk, klass.typed_uuid) if pk && read_attribute(pk).nil?
23
23
  end
24
+
25
+ super
24
26
  end
25
27
 
26
- def register_uuid_types(mapping)
27
- mapping.each do |k, v|
28
- if k.is_a?(Integer)
29
- register_uuid_type(v, k)
28
+ class_methods do
29
+ def register_uuid_type(class_name, int)
30
+ if int < 0 || int > 65_535
31
+ raise ArgumentError, "UUID type must be between 0 and 65,535"
32
+ elsif defined_uuid_types.has_key?(int)
33
+ raise ArgumentError, UUID_TYPE_CONFLICT_MESSAGE % {
34
+ int: int,
35
+ class_name: class_name,
36
+ other: defined_uuid_types[int]
37
+ }
30
38
  else
31
- register_uuid_type(k, v)
39
+ defined_uuid_types[int] = class_name.to_s
40
+ end
41
+ end
42
+
43
+ def register_uuid_types(mapping)
44
+ mapping.each do |k, v|
45
+ if k.is_a?(Integer)
46
+ register_uuid_type(v, k)
47
+ else
48
+ register_uuid_type(k, v)
49
+ end
32
50
  end
33
51
  end
34
- end
35
52
 
36
- def uuid_type_from_table_name(table)
37
- type = defined_uuid_types.key(table.to_s)
38
- if type.nil?
39
- raise ArgumentError, "UUID Type for \"#{table}\" not defined"
53
+ def typed?
54
+ !!class_to_uuid_type_cache[self.base_class]
40
55
  end
41
56
 
42
- type
43
- end
57
+ def typed_uuid
58
+ TypedUUID.uuid(uuid_type_from_class(self))
59
+ end
44
60
 
45
- def class_from_uuid_type(type)
46
- if klass = uuid_type_cache[type]
47
- return klass
48
- else
49
- # Rails.application.eager_load! if !Rails.application.config.eager_load
61
+ def uuid_type_from_table_name(table)
62
+ uuid_type_from_class(class_from_table_name(table))
63
+ end
64
+
65
+ def uuid_type_from_class(klass)
66
+ type = class_to_uuid_type_cache[klass]
50
67
 
51
- ::ActiveRecord::Base.descendants.select do |klass|
68
+ if type.nil?
69
+ raise ArgumentError, "UUID Type for \"#{klass.name}\" not defined"
70
+ end
71
+
72
+ type
73
+ end
74
+
75
+ def class_from_uuid_type(type)
76
+ klass = if uuid_type_to_class_cache.has_key?(type)
77
+ uuid_type_to_class_cache[type]
78
+ else
79
+ Rails.application.eager_load! if !Rails.application.config.eager_load
80
+
81
+ ::ActiveRecord::Base.descendants.each do |klass|
82
+ next if klass.table_name.nil?
83
+
84
+ uuid_type_to_class_cache[defined_uuid_types.key(klass.name)] = klass
85
+ end
86
+
87
+ uuid_type_to_class_cache[type]
88
+ end
89
+ end
90
+
91
+ def class_from_table_name(table)
92
+ table = table.to_s
93
+ Rails.application.eager_load! if !Rails.application.config.eager_load
94
+
95
+ ::ActiveRecord::Base.descendants.find do |klass|
52
96
  next unless ( klass.superclass == ::ActiveRecord::Base || klass.superclass.abstract_class? )
53
97
  next if klass.table_name.nil?
54
-
55
- uuid_type_cache[defined_uuid_types.key(klass.table_name)] = klass
98
+
99
+ klass.table_name == table
56
100
  end
57
-
58
- uuid_type_cache[type]
59
101
  end
60
- end
61
102
 
62
- def class_from_uuid(uuid)
63
- uuid = uuid.gsub('-', '')
64
- class_from_uuid_type((uuid[8..11].to_i(16) ^ uuid[16..19].to_i(16)) ^ uuid[12..15].to_i(16))
103
+ def class_from_uuid(uuid)
104
+ class_from_uuid_type(TypedUUID.enum(uuid))
105
+ end
65
106
  end
66
107
 
67
108
  end
@@ -4,7 +4,7 @@ module TypedUUID::PsqlColumnMethods
4
4
  if type == :typed_uuid
5
5
  klass_enum = ::ActiveRecord::Base.uuid_type_from_table_name(self.name)
6
6
  options[:id] = :uuid
7
- options[:default] ||= -> { "typed_uuid('\\x#{klass_enum.to_s(16).ljust(4, '0')}')" }
7
+ options[:default] ||= -> { "typed_uuid('\\x#{klass_enum.to_s(16).rjust(4, '0')}')" }
8
8
  super(name, :uuid, **options)
9
9
  else
10
10
  super
@@ -4,12 +4,13 @@ class TypedUUID::Railtie < Rails::Railtie
4
4
  ActiveRecord::Tasks::DatabaseTasks.migrations_paths << File.expand_path('../../../db/migrate', __FILE__)
5
5
 
6
6
  ActiveSupport.on_load(:active_record) do
7
- ActiveRecord::Base.extend TypedUUID::ActiveRecord
7
+ ActiveRecord::Base.include TypedUUID::ActiveRecord
8
8
  end
9
9
 
10
- require 'active_record/connection_adapters/postgresql/schema_definitions'
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/postgresql/schema_dumper'
13
14
  ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaDumper.prepend(TypedUUID::PsqlSchemaDumper)
14
15
  end
15
16
 
@@ -1,3 +1,3 @@
1
1
  module TypedUUID
2
- VERSION = '2.1'
2
+ VERSION = '3.2'
3
3
  end
@@ -28,7 +28,9 @@ module ActiveRecord::Tasks::DatabaseTasks
28
28
  end
29
29
  TypedUUID::Railtie.initializers.each(&:run)
30
30
  Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
31
-
31
+ def MiniTest.filter_backtrace(bt)
32
+ bt
33
+ end
32
34
  class ActiveSupport::TestCase
33
35
 
34
36
  # File 'lib/active_support/testing/declarative.rb'
@@ -50,7 +52,12 @@ class ActiveSupport::TestCase
50
52
  end
51
53
 
52
54
  set_callback(:setup, :before) do
55
+ Rails.stubs(:application).returns(stub(config: stub(eager_load: true)))
53
56
  if !self.class.class_variable_defined?(:@@suite_setup_run)
57
+ ActiveRecord::Base.defined_uuid_types.clear
58
+ ActiveRecord::Base.uuid_type_to_class_cache.clear
59
+ ActiveRecord::Base.class_to_uuid_type_cache.clear
60
+
54
61
  configuration = {
55
62
  adapter: "postgresql",
56
63
  database: "uuid-types-test",
@@ -75,14 +82,14 @@ class ActiveSupport::TestCase
75
82
  self.class.class_variable_set(:@@suite_setup_run, true)
76
83
  end
77
84
 
78
- # def debug
79
- # ActiveRecord::Base.logger = Logger.new(STDOUT)
80
- # $debugging = true
81
- # yield
82
- # ensure
83
- # ActiveRecord::Base.logger = nil
84
- # $debugging = false
85
- # end
85
+ def debug
86
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
87
+ $debugging = true
88
+ yield
89
+ ensure
90
+ ActiveRecord::Base.logger = nil
91
+ $debugging = false
92
+ end
86
93
 
87
94
  def capture_sql
88
95
  # ActiveRecord::Base.connection.materialize_transactions
@@ -4,8 +4,9 @@ class FilterTest < ActiveSupport::TestCase
4
4
 
5
5
  schema do
6
6
  ActiveRecord::Base.register_uuid_types({
7
- listings: 0,
8
- buildings: 65_535
7
+ 'FilterTest::Listing' => 0,
8
+ 'FilterTest::Building' => 592,
9
+ 'FilterTest::SkyScraper' => 1_952
9
10
  })
10
11
 
11
12
  create_table :listings, id: :typed_uuid do |t|
@@ -14,6 +15,7 @@ class FilterTest < ActiveSupport::TestCase
14
15
 
15
16
  create_table :buildings, id: :typed_uuid do |t|
16
17
  t.string "name", limit: 255
18
+ t.string "type", limit: 255
17
19
  end
18
20
  end
19
21
 
@@ -22,14 +24,23 @@ class FilterTest < ActiveSupport::TestCase
22
24
 
23
25
  class Building < ActiveRecord::Base
24
26
  end
27
+
28
+ class SkyScraper < Building
29
+ end
25
30
 
31
+ class SingleFamilyHome < Building
32
+ end
33
+
34
+ class Property < ActiveRecord::Base
35
+ end
36
+
26
37
  test 'adding primary key as a typed_uuid in a migration' do
27
38
  ActiveRecord::Base.register_uuid_types({
28
- properties: 1
39
+ 1 => 'FilterTest::Property'
29
40
  })
30
41
 
31
42
  exprexted_sql = <<-SQL
32
- CREATE TABLE "properties" ("id" uuid DEFAULT typed_uuid('\\x1000') NOT NULL PRIMARY KEY, "name" character varying(255))
43
+ CREATE TABLE "properties" ("id" uuid DEFAULT typed_uuid('\\x0001') NOT NULL PRIMARY KEY, "name" character varying(255))
33
44
  SQL
34
45
 
35
46
  assert_sql exprexted_sql do
@@ -41,23 +52,48 @@ class FilterTest < ActiveSupport::TestCase
41
52
  end
42
53
  end
43
54
 
55
+ test 'typed_uuid' do
56
+ assert_equal 512, TypedUUID.enum(TypedUUID.uuid(512))
57
+ assert_equal FilterTest::Listing, ::ActiveRecord::Base.class_from_uuid(Listing.typed_uuid)
58
+ assert_equal FilterTest::Building, ::ActiveRecord::Base.class_from_uuid(Building.typed_uuid)
59
+ assert_equal FilterTest::SkyScraper, ::ActiveRecord::Base.class_from_uuid(SkyScraper.typed_uuid)
60
+
61
+ assert_raises ArgumentError do
62
+ ::ActiveRecord::Base.class_from_uuid(SingleFamilyHome.typed_uuid)
63
+ end
64
+ end
65
+
44
66
  test 'class_from uuid' do
45
67
  listing = Listing.create
46
68
  building = Building.create
69
+ skyscraper = SkyScraper.create
47
70
 
48
71
  assert_equal FilterTest::Listing, ::ActiveRecord::Base.class_from_uuid(listing.id)
49
72
  assert_equal FilterTest::Building, ::ActiveRecord::Base.class_from_uuid(building.id)
73
+ assert_equal FilterTest::SkyScraper, ::ActiveRecord::Base.class_from_uuid(skyscraper.id)
74
+
75
+ assert_raises ArgumentError do
76
+ SingleFamilyHome.create
77
+ end
50
78
  end
51
79
 
52
80
  test 'uuid_type from table_name' do
53
81
  assert_equal 0, ::ActiveRecord::Base.uuid_type_from_table_name(:listings)
54
82
  assert_equal 0, ::ActiveRecord::Base.uuid_type_from_table_name('listings')
55
- assert_equal 65_535, ::ActiveRecord::Base.uuid_type_from_table_name(:buildings)
83
+ assert_equal 592, ::ActiveRecord::Base.uuid_type_from_table_name(:buildings)
84
+ end
85
+
86
+ test 'uuid_type from class' do
87
+ assert_equal 0, ::ActiveRecord::Base.uuid_type_from_class(Listing)
88
+ assert_equal 0, ::ActiveRecord::Base.uuid_type_from_class(Listing)
89
+ assert_equal 592, ::ActiveRecord::Base.uuid_type_from_class(Building)
90
+ assert_equal 1_952, ::ActiveRecord::Base.uuid_type_from_class(SkyScraper)
56
91
  end
57
92
 
58
93
  test 'class from uuid_type' do
59
94
  assert_equal FilterTest::Listing, ::ActiveRecord::Base.class_from_uuid_type(0)
60
- assert_equal FilterTest::Building, ::ActiveRecord::Base.class_from_uuid_type(65_535)
95
+ assert_equal FilterTest::Building, ::ActiveRecord::Base.class_from_uuid_type(592)
96
+ assert_equal FilterTest::SkyScraper, ::ActiveRecord::Base.class_from_uuid_type(1_952)
61
97
  end
62
98
 
63
99
  end
@@ -24,8 +24,8 @@ Gem::Specification.new do |s|
24
24
  s.add_development_dependency 'byebug'
25
25
  s.add_development_dependency 'activesupport', '>= 6.0.0'
26
26
  s.add_development_dependency 'rails', '>= 6.0.0'
27
+ s.add_development_dependency 'pg'
27
28
 
28
29
  # Runtime
29
- s.add_runtime_dependency 'pg'
30
30
  s.add_runtime_dependency 'activerecord', '>= 6.0.0'
31
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: '2.1'
4
+ version: '3.2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Bracy
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-24 00:00:00.000000000 Z
11
+ date: 2020-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -143,7 +143,7 @@ dependencies:
143
143
  - - ">="
144
144
  - !ruby/object:Gem::Version
145
145
  version: '0'
146
- type: :runtime
146
+ type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
@@ -190,7 +190,7 @@ files:
190
190
  homepage: https://github.com/malomalo/typed_uuid
191
191
  licenses: []
192
192
  metadata: {}
193
- post_install_message:
193
+ post_install_message:
194
194
  rdoc_options: []
195
195
  require_paths:
196
196
  - lib
@@ -205,8 +205,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
205
205
  - !ruby/object:Gem::Version
206
206
  version: '0'
207
207
  requirements: []
208
- rubygems_version: 3.0.3
209
- signing_key:
208
+ rubygems_version: 3.1.4
209
+ signing_key:
210
210
  specification_version: 4
211
211
  summary: Typed UUIDs for ActiveRecord
212
212
  test_files: