typed_uuid 1.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 +7 -0
- data/.gitignore +3 -0
- data/.tm_properties +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +168 -0
- data/LICENSE +21 -0
- data/README.md +67 -0
- data/Rakefile +13 -0
- data/db/migrate/20191222234546_add_typed_uuid_function.rb +18 -0
- data/lib/typed_uuid/active_record.rb +67 -0
- data/lib/typed_uuid/psql_column_methods.rb +14 -0
- data/lib/typed_uuid/railtie.rb +14 -0
- data/lib/typed_uuid/version.rb +3 -0
- data/lib/typed_uuid.rb +6 -0
- data/test/test_helper.rb +194 -0
- data/test/typed_uuid_test.rb +63 -0
- data/typed_uuid.gemspec +31 -0
- metadata +214 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 5c5433e604f5994bc1cb5787813f0948c7b1c5448aa6e78b61e0d5a5dec056bc
|
|
4
|
+
data.tar.gz: f38b7f09d39467074e06c62e7edb28f34b1426b1f089e61b31457d6a79f002dc
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: d5b2fc14ab95352601cdd86218d0594399f6bf838a3bb097a50996536ba1ac41dc1b44398fc1e342c743854069b8120800a80f1067b16922966c244a31fd0c9c
|
|
7
|
+
data.tar.gz: 561171c47297962e4c0ac880d7515f3fffafabbb07e606f3d551acc080476bab505496994de79296025f179615f868294b1b410a0eda9c96880135980a1805af
|
data/.gitignore
ADDED
data/.tm_properties
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
exclude = '{$exclude,log,tmp,.tm_properties,coverage}'
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
typed_uuid (0.1)
|
|
5
|
+
activerecord (>= 6.0.0)
|
|
6
|
+
pg
|
|
7
|
+
|
|
8
|
+
GEM
|
|
9
|
+
remote: https://rubygems.org/
|
|
10
|
+
specs:
|
|
11
|
+
actioncable (6.0.2.1)
|
|
12
|
+
actionpack (= 6.0.2.1)
|
|
13
|
+
nio4r (~> 2.0)
|
|
14
|
+
websocket-driver (>= 0.6.1)
|
|
15
|
+
actionmailbox (6.0.2.1)
|
|
16
|
+
actionpack (= 6.0.2.1)
|
|
17
|
+
activejob (= 6.0.2.1)
|
|
18
|
+
activerecord (= 6.0.2.1)
|
|
19
|
+
activestorage (= 6.0.2.1)
|
|
20
|
+
activesupport (= 6.0.2.1)
|
|
21
|
+
mail (>= 2.7.1)
|
|
22
|
+
actionmailer (6.0.2.1)
|
|
23
|
+
actionpack (= 6.0.2.1)
|
|
24
|
+
actionview (= 6.0.2.1)
|
|
25
|
+
activejob (= 6.0.2.1)
|
|
26
|
+
mail (~> 2.5, >= 2.5.4)
|
|
27
|
+
rails-dom-testing (~> 2.0)
|
|
28
|
+
actionpack (6.0.2.1)
|
|
29
|
+
actionview (= 6.0.2.1)
|
|
30
|
+
activesupport (= 6.0.2.1)
|
|
31
|
+
rack (~> 2.0, >= 2.0.8)
|
|
32
|
+
rack-test (>= 0.6.3)
|
|
33
|
+
rails-dom-testing (~> 2.0)
|
|
34
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
|
35
|
+
actiontext (6.0.2.1)
|
|
36
|
+
actionpack (= 6.0.2.1)
|
|
37
|
+
activerecord (= 6.0.2.1)
|
|
38
|
+
activestorage (= 6.0.2.1)
|
|
39
|
+
activesupport (= 6.0.2.1)
|
|
40
|
+
nokogiri (>= 1.8.5)
|
|
41
|
+
actionview (6.0.2.1)
|
|
42
|
+
activesupport (= 6.0.2.1)
|
|
43
|
+
builder (~> 3.1)
|
|
44
|
+
erubi (~> 1.4)
|
|
45
|
+
rails-dom-testing (~> 2.0)
|
|
46
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
|
47
|
+
activejob (6.0.2.1)
|
|
48
|
+
activesupport (= 6.0.2.1)
|
|
49
|
+
globalid (>= 0.3.6)
|
|
50
|
+
activemodel (6.0.2.1)
|
|
51
|
+
activesupport (= 6.0.2.1)
|
|
52
|
+
activerecord (6.0.2.1)
|
|
53
|
+
activemodel (= 6.0.2.1)
|
|
54
|
+
activesupport (= 6.0.2.1)
|
|
55
|
+
activestorage (6.0.2.1)
|
|
56
|
+
actionpack (= 6.0.2.1)
|
|
57
|
+
activejob (= 6.0.2.1)
|
|
58
|
+
activerecord (= 6.0.2.1)
|
|
59
|
+
marcel (~> 0.3.1)
|
|
60
|
+
activesupport (6.0.2.1)
|
|
61
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
62
|
+
i18n (>= 0.7, < 2)
|
|
63
|
+
minitest (~> 5.1)
|
|
64
|
+
tzinfo (~> 1.1)
|
|
65
|
+
zeitwerk (~> 2.2)
|
|
66
|
+
ansi (1.5.0)
|
|
67
|
+
builder (3.2.4)
|
|
68
|
+
byebug (11.0.1)
|
|
69
|
+
concurrent-ruby (1.1.5)
|
|
70
|
+
crass (1.0.5)
|
|
71
|
+
docile (1.3.2)
|
|
72
|
+
erubi (1.9.0)
|
|
73
|
+
globalid (0.4.2)
|
|
74
|
+
activesupport (>= 4.2.0)
|
|
75
|
+
i18n (1.7.0)
|
|
76
|
+
concurrent-ruby (~> 1.0)
|
|
77
|
+
json (2.3.0)
|
|
78
|
+
loofah (2.4.0)
|
|
79
|
+
crass (~> 1.0.2)
|
|
80
|
+
nokogiri (>= 1.5.9)
|
|
81
|
+
mail (2.7.1)
|
|
82
|
+
mini_mime (>= 0.1.1)
|
|
83
|
+
marcel (0.3.3)
|
|
84
|
+
mimemagic (~> 0.3.2)
|
|
85
|
+
method_source (0.9.2)
|
|
86
|
+
mimemagic (0.3.3)
|
|
87
|
+
mini_mime (1.0.2)
|
|
88
|
+
mini_portile2 (2.4.0)
|
|
89
|
+
minitest (5.13.0)
|
|
90
|
+
minitest-reporters (1.4.2)
|
|
91
|
+
ansi
|
|
92
|
+
builder
|
|
93
|
+
minitest (>= 5.0)
|
|
94
|
+
ruby-progressbar
|
|
95
|
+
mocha (1.11.1)
|
|
96
|
+
nio4r (2.5.2)
|
|
97
|
+
nokogiri (1.10.7)
|
|
98
|
+
mini_portile2 (~> 2.4.0)
|
|
99
|
+
pg (1.1.4)
|
|
100
|
+
rack (2.0.8)
|
|
101
|
+
rack-test (1.1.0)
|
|
102
|
+
rack (>= 1.0, < 3)
|
|
103
|
+
rails (6.0.2.1)
|
|
104
|
+
actioncable (= 6.0.2.1)
|
|
105
|
+
actionmailbox (= 6.0.2.1)
|
|
106
|
+
actionmailer (= 6.0.2.1)
|
|
107
|
+
actionpack (= 6.0.2.1)
|
|
108
|
+
actiontext (= 6.0.2.1)
|
|
109
|
+
actionview (= 6.0.2.1)
|
|
110
|
+
activejob (= 6.0.2.1)
|
|
111
|
+
activemodel (= 6.0.2.1)
|
|
112
|
+
activerecord (= 6.0.2.1)
|
|
113
|
+
activestorage (= 6.0.2.1)
|
|
114
|
+
activesupport (= 6.0.2.1)
|
|
115
|
+
bundler (>= 1.3.0)
|
|
116
|
+
railties (= 6.0.2.1)
|
|
117
|
+
sprockets-rails (>= 2.0.0)
|
|
118
|
+
rails-dom-testing (2.0.3)
|
|
119
|
+
activesupport (>= 4.2.0)
|
|
120
|
+
nokogiri (>= 1.6)
|
|
121
|
+
rails-html-sanitizer (1.3.0)
|
|
122
|
+
loofah (~> 2.3)
|
|
123
|
+
railties (6.0.2.1)
|
|
124
|
+
actionpack (= 6.0.2.1)
|
|
125
|
+
activesupport (= 6.0.2.1)
|
|
126
|
+
method_source
|
|
127
|
+
rake (>= 0.8.7)
|
|
128
|
+
thor (>= 0.20.3, < 2.0)
|
|
129
|
+
rake (13.0.1)
|
|
130
|
+
ruby-progressbar (1.10.1)
|
|
131
|
+
simplecov (0.17.1)
|
|
132
|
+
docile (~> 1.1)
|
|
133
|
+
json (>= 1.8, < 3)
|
|
134
|
+
simplecov-html (~> 0.10.0)
|
|
135
|
+
simplecov-html (0.10.2)
|
|
136
|
+
sprockets (4.0.0)
|
|
137
|
+
concurrent-ruby (~> 1.0)
|
|
138
|
+
rack (> 1, < 3)
|
|
139
|
+
sprockets-rails (3.2.1)
|
|
140
|
+
actionpack (>= 4.0)
|
|
141
|
+
activesupport (>= 4.0)
|
|
142
|
+
sprockets (>= 3.0.0)
|
|
143
|
+
thor (1.0.1)
|
|
144
|
+
thread_safe (0.3.6)
|
|
145
|
+
tzinfo (1.2.5)
|
|
146
|
+
thread_safe (~> 0.1)
|
|
147
|
+
websocket-driver (0.7.1)
|
|
148
|
+
websocket-extensions (>= 0.1.0)
|
|
149
|
+
websocket-extensions (0.1.4)
|
|
150
|
+
zeitwerk (2.2.2)
|
|
151
|
+
|
|
152
|
+
PLATFORMS
|
|
153
|
+
ruby
|
|
154
|
+
|
|
155
|
+
DEPENDENCIES
|
|
156
|
+
activesupport (>= 6.0.0)
|
|
157
|
+
bundler
|
|
158
|
+
byebug
|
|
159
|
+
minitest
|
|
160
|
+
minitest-reporters
|
|
161
|
+
mocha
|
|
162
|
+
rails (>= 6.0.0)
|
|
163
|
+
rake
|
|
164
|
+
simplecov
|
|
165
|
+
typed_uuid!
|
|
166
|
+
|
|
167
|
+
BUNDLED WITH
|
|
168
|
+
2.0.2
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 Jon Bracy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# TypedUUID
|
|
2
|
+
|
|
3
|
+
A __Typed UUID__ is an UUID with an enum embeded within the UUID.
|
|
4
|
+
|
|
5
|
+
UUIDs are 128bit or 16bytes. The hex format is represented below where x is
|
|
6
|
+
a hex representation of 4 bits.
|
|
7
|
+
|
|
8
|
+
`xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx`
|
|
9
|
+
|
|
10
|
+
Where:
|
|
11
|
+
|
|
12
|
+
- M is 4 bits and is the Version
|
|
13
|
+
- N is 3 bits and is the Variant of the Version followed a bit
|
|
14
|
+
|
|
15
|
+
We modify this and use the following structure where the 7th & 8th bytes in the
|
|
16
|
+
UUID are enum XORed with bytes 5 & 6.
|
|
17
|
+
|
|
18
|
+
`xxxxxxxx-YYYY-TTTT-xxxx-xxxxxxxxxxxx`
|
|
19
|
+
|
|
20
|
+
Where:
|
|
21
|
+
|
|
22
|
+
- TTTT is the Class ENUM 0bNNNN_NNNN_NNNN_NNNN (0 - 65,535) XORed with YYYY
|
|
23
|
+
- YYYY are the bytes to be XORed with the Class ENUM to produce the identifying
|
|
24
|
+
bytes
|
|
25
|
+
|
|
26
|
+
XORing bytes 7 & 8 with bytes 5 & 6 of the Typed UUID will give us back the ENUM
|
|
27
|
+
of the Type using soley the UUID.
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
Add this to your Gemfile:
|
|
32
|
+
|
|
33
|
+
`gem 'typed_uuid'`
|
|
34
|
+
|
|
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.
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
# config/initializers/uuid_types.rb
|
|
40
|
+
|
|
41
|
+
ActiveRecord::Base.register_uuid_types({
|
|
42
|
+
listings: 0,
|
|
43
|
+
buildings: 65_535
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
# Or:
|
|
47
|
+
|
|
48
|
+
ActiveRecord::Base.register_uuid_types({
|
|
49
|
+
0 => :listings,
|
|
50
|
+
65_535 => :buildings
|
|
51
|
+
})
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Usage
|
|
55
|
+
|
|
56
|
+
In your migrations simply replace `id: :uuid` with `id: :typed_uuid` when creating
|
|
57
|
+
a table.
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
class CreateProperties < ActiveRecord::Migration[5.2]
|
|
61
|
+
def change
|
|
62
|
+
create_table :properties, id: :typed_uuid do |t|
|
|
63
|
+
t.string "name", limit: 255
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
```
|
data/Rakefile
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'bundler/setup'
|
|
2
|
+
require "bundler/gem_tasks"
|
|
3
|
+
Bundler.require(:development)
|
|
4
|
+
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require "rake/testtask"
|
|
7
|
+
|
|
8
|
+
Rake::TestTask.new do |t|
|
|
9
|
+
t.libs << 'lib' << 'test'
|
|
10
|
+
t.test_files = FileList['test/**/*_test.rb']
|
|
11
|
+
t.warning = true
|
|
12
|
+
# t.verbose = true
|
|
13
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class AddTypedUuidFunction < ActiveRecord::Migration[6.0]
|
|
2
|
+
def up
|
|
3
|
+
enable_extension 'pgcrypto'
|
|
4
|
+
|
|
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(t, 0));
|
|
12
|
+
bytes := set_byte(bytes, 7, get_byte(bytes, 5) # get_byte(t, 1));
|
|
13
|
+
RETURN encode( bytes, 'hex') :: uuid;
|
|
14
|
+
END;
|
|
15
|
+
$$ LANGUAGE plpgsql;
|
|
16
|
+
SQL
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module TypedUUID::ActiveRecord
|
|
2
|
+
|
|
3
|
+
UUID_TYPE_CONFLICT_MESSAGE = \
|
|
4
|
+
"You tried to define an UUID type %{int} for \"%{table}\", but " \
|
|
5
|
+
" %{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: {})
|
|
10
|
+
end
|
|
11
|
+
|
|
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
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def register_uuid_types(mapping)
|
|
27
|
+
mapping.each do |k, v|
|
|
28
|
+
if k.is_a?(Integer)
|
|
29
|
+
register_uuid_type(v, k)
|
|
30
|
+
else
|
|
31
|
+
register_uuid_type(k, v)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
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"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
type
|
|
43
|
+
end
|
|
44
|
+
|
|
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
|
|
50
|
+
|
|
51
|
+
::ActiveRecord::Base.descendants.select do |klass|
|
|
52
|
+
next unless ( klass.superclass == ::ActiveRecord::Base || klass.superclass.abstract_class? )
|
|
53
|
+
next if klass.table_name.nil?
|
|
54
|
+
|
|
55
|
+
uuid_type_cache[defined_uuid_types.key(klass.table_name)] = klass
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
uuid_type_cache[type]
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def class_from_uuid(uuid)
|
|
63
|
+
uuid = uuid.gsub('-', '')
|
|
64
|
+
class_from_uuid_type(uuid[8..11].to_i(16) ^ uuid[12..15].to_i(16))
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module TypedUUID::PsqlColumnMethods
|
|
2
|
+
|
|
3
|
+
def primary_key(name, type = :primary_key, **options)
|
|
4
|
+
if type == :typed_uuid
|
|
5
|
+
klass_enum = ::ActiveRecord::Base.uuid_type_from_table_name(self.name)
|
|
6
|
+
options[:id] = :uuid
|
|
7
|
+
options[:default] ||= -> { "typed_uuid('\\x#{klass_enum.to_s(16).ljust(4, '0')}')" }
|
|
8
|
+
super(name, :uuid, **options)
|
|
9
|
+
else
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class TypedUUID::Railtie < Rails::Railtie
|
|
2
|
+
|
|
3
|
+
initializer :typed_uuid do |app|
|
|
4
|
+
ActiveRecord::Tasks::DatabaseTasks.migrations_paths << File.expand_path('../../../db/migrate', __FILE__)
|
|
5
|
+
|
|
6
|
+
ActiveSupport.on_load(:active_record) do
|
|
7
|
+
ActiveRecord::Base.extend TypedUUID::ActiveRecord
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
require 'active_record/connection_adapters/postgresql/schema_definitions'
|
|
11
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition.include TypedUUID::PsqlColumnMethods
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
data/lib/typed_uuid.rb
ADDED
data/test/test_helper.rb
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
require 'simplecov'
|
|
2
|
+
SimpleCov.start do
|
|
3
|
+
add_filter %r{^/test/}
|
|
4
|
+
# add_group 'lib', 'sunstone/lib'
|
|
5
|
+
# add_group 'ext', 'sunstone/ext'
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# To make testing/debugging easier, test within this source tree versus an
|
|
9
|
+
# installed gem
|
|
10
|
+
$LOAD_PATH << File.expand_path('../lib', __FILE__)
|
|
11
|
+
|
|
12
|
+
require 'byebug'
|
|
13
|
+
require "minitest/autorun"
|
|
14
|
+
require 'minitest/unit'
|
|
15
|
+
require 'minitest/reporters'
|
|
16
|
+
require 'mocha/minitest'
|
|
17
|
+
require 'active_support'
|
|
18
|
+
require 'active_record'
|
|
19
|
+
require 'rails'
|
|
20
|
+
require 'typed_uuid'
|
|
21
|
+
require 'typed_uuid/railtie'
|
|
22
|
+
require File.expand_path('../../db/migrate/20191122234546_add_typed_uuid_function', __FILE__)
|
|
23
|
+
|
|
24
|
+
module ActiveRecord::Tasks::DatabaseTasks
|
|
25
|
+
def migrations_paths
|
|
26
|
+
[]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
TypedUUID::Railtie.initializers.each(&:run)
|
|
30
|
+
Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
|
|
31
|
+
|
|
32
|
+
class ActiveSupport::TestCase
|
|
33
|
+
|
|
34
|
+
# File 'lib/active_support/testing/declarative.rb'
|
|
35
|
+
def self.test(name, &block)
|
|
36
|
+
test_name = "test_#{name.gsub(/\s+/, '_')}".to_sym
|
|
37
|
+
defined = method_defined? test_name
|
|
38
|
+
raise "#{test_name} is already defined in #{self}" if defined
|
|
39
|
+
if block_given?
|
|
40
|
+
define_method(test_name, &block)
|
|
41
|
+
else
|
|
42
|
+
define_method(test_name) do
|
|
43
|
+
skip "No implementation provided for #{name}"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.schema(&block)
|
|
49
|
+
self.class_variable_set(:@@schema, block)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
set_callback(:setup, :before) do
|
|
53
|
+
if !self.class.class_variable_defined?(:@@suite_setup_run)
|
|
54
|
+
configuration = {
|
|
55
|
+
adapter: "postgresql",
|
|
56
|
+
database: "uuid-types-test",
|
|
57
|
+
encoding: "utf8"
|
|
58
|
+
}.stringify_keys
|
|
59
|
+
|
|
60
|
+
db_tasks = ActiveRecord::Tasks::PostgreSQLDatabaseTasks.new(configuration)
|
|
61
|
+
db_tasks.purge
|
|
62
|
+
|
|
63
|
+
ActiveRecord::Base.establish_connection(configuration)
|
|
64
|
+
ActiveRecord::Migration.suppress_messages do
|
|
65
|
+
AddTypedUuidFunction.migrate :up
|
|
66
|
+
|
|
67
|
+
if self.class.class_variable_defined?(:@@schema)
|
|
68
|
+
ActiveRecord::Schema.define(&self.class.class_variable_get(:@@schema))
|
|
69
|
+
ActiveRecord::Migration.execute("SELECT c.relname FROM pg_class c WHERE c.relkind = 'S'").each_row do |row|
|
|
70
|
+
ActiveRecord::Migration.execute("ALTER SEQUENCE #{row[0]} RESTART WITH #{rand(50_000)}")
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
self.class.class_variable_set(:@@suite_setup_run, true)
|
|
76
|
+
end
|
|
77
|
+
|
|
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
|
|
86
|
+
|
|
87
|
+
def capture_sql
|
|
88
|
+
# ActiveRecord::Base.connection.materialize_transactions
|
|
89
|
+
SQLLogger.clear_log
|
|
90
|
+
yield
|
|
91
|
+
SQLLogger.log_all.dup
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def assert_sql(*patterns_to_match)
|
|
95
|
+
if patterns_to_match.all? { |s| s.is_a?(String) } && patterns_to_match.size > 1
|
|
96
|
+
assert_equal(*patterns_to_match.take(2).map { |sql| sql.gsub(/( +|\n\s*|\s+)/, ' ').strip })
|
|
97
|
+
else
|
|
98
|
+
begin
|
|
99
|
+
ret_value = nil
|
|
100
|
+
capture_sql { ret_value = yield }
|
|
101
|
+
ret_value
|
|
102
|
+
ensure
|
|
103
|
+
patterns_to_match.map! {|p| p.is_a?(String) ? p.gsub(/( +|\n\s*|\s+)/, ' ').strip : p }
|
|
104
|
+
failed_patterns = []
|
|
105
|
+
patterns_to_match.each do |pattern|
|
|
106
|
+
failed_patterns << pattern unless SQLLogger.log_all.any?{ |sql| pattern === sql.gsub(/( +|\n\s*|\s+)/, ' ').strip }
|
|
107
|
+
end
|
|
108
|
+
assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map(&:inspect).join(', ')} not found.#{SQLLogger.log.size == 0 ? '' : "\nQueries:\n#{SQLLogger.log.join("\n")}"}"
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def assert_no_sql(*patterns_to_match)
|
|
114
|
+
if patterns_to_match.all? { |s| s.is_a?(String) }
|
|
115
|
+
assert_not_equal(*patterns_to_match.take(2).map { |sql| sql.gsub(/( +|\n\s*|\s+)/, ' ').strip })
|
|
116
|
+
else
|
|
117
|
+
begin
|
|
118
|
+
ret_value = nil
|
|
119
|
+
capture_sql { ret_value = yield }
|
|
120
|
+
ret_value
|
|
121
|
+
ensure
|
|
122
|
+
failed_patterns = []
|
|
123
|
+
patterns_to_match.each do |pattern|
|
|
124
|
+
failed_patterns << pattern unless SQLLogger.log_all.any?{ |sql| pattern === sql }
|
|
125
|
+
end
|
|
126
|
+
assert !failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map(&:inspect).join(', ')} found.#{SQLLogger.log.size == 0 ? '' : "\nQueries:\n#{SQLLogger.log.join("\n")}"}"
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
class SQLLogger
|
|
132
|
+
class << self
|
|
133
|
+
attr_accessor :ignored_sql, :log, :log_all
|
|
134
|
+
def clear_log; self.log = []; self.log_all = []; end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
self.clear_log
|
|
138
|
+
|
|
139
|
+
self.ignored_sql = [/^PRAGMA/i, /^SELECT currval/i, /^SELECT CAST/i, /^SELECT @@IDENTITY/i, /^SELECT @@ROWCOUNT/i, /^SAVEPOINT/i, /^ROLLBACK TO SAVEPOINT/i, /^RELEASE SAVEPOINT/i, /^SHOW max_identifier_length/i, /^BEGIN/i, /^COMMIT/i]
|
|
140
|
+
|
|
141
|
+
# FIXME: this needs to be refactored so specific database can add their own
|
|
142
|
+
# ignored SQL, or better yet, use a different notification for the queries
|
|
143
|
+
# instead examining the SQL content.
|
|
144
|
+
oracle_ignored = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from all_triggers/im, /^\s*select .* from all_constraints/im, /^\s*select .* from all_tab_cols/im]
|
|
145
|
+
mysql_ignored = [/^SHOW FULL TABLES/i, /^SHOW FULL FIELDS/, /^SHOW CREATE TABLE /i, /^SHOW VARIABLES /, /^\s*SELECT (?:column_name|table_name)\b.*\bFROM information_schema\.(?:key_column_usage|tables)\b/im]
|
|
146
|
+
postgresql_ignored = [/^\s*select\b.*\bfrom\b.*pg_namespace\b/im, /^\s*select tablename\b.*from pg_tables\b/im, /^\s*select\b.*\battname\b.*\bfrom\b.*\bpg_attribute\b/im, /^SHOW search_path/i]
|
|
147
|
+
sqlite3_ignored = [/^\s*SELECT name\b.*\bFROM sqlite_master/im, /^\s*SELECT sql\b.*\bFROM sqlite_master/im]
|
|
148
|
+
|
|
149
|
+
[oracle_ignored, mysql_ignored, postgresql_ignored, sqlite3_ignored].each do |db_ignored_sql|
|
|
150
|
+
ignored_sql.concat db_ignored_sql
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
attr_reader :ignore
|
|
154
|
+
|
|
155
|
+
def initialize(ignore = Regexp.union(self.class.ignored_sql))
|
|
156
|
+
@ignore = ignore
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def call(name, start, finish, message_id, values)
|
|
160
|
+
sql = values[:sql]
|
|
161
|
+
|
|
162
|
+
# FIXME: this seems bad. we should probably have a better way to indicate
|
|
163
|
+
# the query was cached
|
|
164
|
+
return if 'CACHE' == values[:name]
|
|
165
|
+
|
|
166
|
+
self.class.log_all << sql
|
|
167
|
+
unless ignore =~ sql
|
|
168
|
+
# if $debugging
|
|
169
|
+
# puts caller.select { |l| l.starts_with?(File.expand_path('../../lib', __FILE__)) }
|
|
170
|
+
# puts "\n\n"
|
|
171
|
+
# end
|
|
172
|
+
end
|
|
173
|
+
self.class.log << sql unless ignore =~ sql
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
ActiveSupport::Notifications.subscribe('sql.active_record', SQLLogger.new)
|
|
177
|
+
|
|
178
|
+
# test/unit backwards compatibility methods
|
|
179
|
+
alias :assert_raise :assert_raises
|
|
180
|
+
alias :assert_not_empty :refute_empty
|
|
181
|
+
alias :assert_not_equal :refute_equal
|
|
182
|
+
alias :assert_not_in_delta :refute_in_delta
|
|
183
|
+
alias :assert_not_in_epsilon :refute_in_epsilon
|
|
184
|
+
alias :assert_not_includes :refute_includes
|
|
185
|
+
alias :assert_not_instance_of :refute_instance_of
|
|
186
|
+
alias :assert_not_kind_of :refute_kind_of
|
|
187
|
+
alias :assert_no_match :refute_match
|
|
188
|
+
alias :assert_not_nil :refute_nil
|
|
189
|
+
alias :assert_not_operator :refute_operator
|
|
190
|
+
alias :assert_not_predicate :refute_predicate
|
|
191
|
+
alias :assert_not_respond_to :refute_respond_to
|
|
192
|
+
alias :assert_not_same :refute_same
|
|
193
|
+
|
|
194
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class FilterTest < ActiveSupport::TestCase
|
|
4
|
+
|
|
5
|
+
schema do
|
|
6
|
+
ActiveRecord::Base.register_uuid_types({
|
|
7
|
+
listings: 0,
|
|
8
|
+
buildings: 65_535
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
create_table :listings, id: :typed_uuid do |t|
|
|
12
|
+
t.string "name", limit: 255
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
create_table :buildings, id: :typed_uuid do |t|
|
|
16
|
+
t.string "name", limit: 255
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Listing < ActiveRecord::Base
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class Building < ActiveRecord::Base
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
test 'adding primary key as a typed_uuid in a migration' do
|
|
27
|
+
ActiveRecord::Base.register_uuid_types({
|
|
28
|
+
properties: 1
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
exprexted_sql = <<-SQL
|
|
32
|
+
CREATE TABLE "properties" ("id" uuid DEFAULT typed_uuid('\\x1000') NOT NULL PRIMARY KEY, "name" character varying(255))
|
|
33
|
+
SQL
|
|
34
|
+
|
|
35
|
+
assert_sql exprexted_sql do
|
|
36
|
+
ActiveRecord::Migration.suppress_messages do
|
|
37
|
+
ActiveRecord::Migration.create_table :properties, id: :typed_uuid do |t|
|
|
38
|
+
t.string "name", limit: 255
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
test 'class_from uuid' do
|
|
45
|
+
listing = Listing.create
|
|
46
|
+
building = Building.create
|
|
47
|
+
|
|
48
|
+
assert_equal FilterTest::Listing, ::ActiveRecord::Base.class_from_uuid(listing.id)
|
|
49
|
+
assert_equal FilterTest::Building, ::ActiveRecord::Base.class_from_uuid(building.id)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
test 'uuid_type from table_name' do
|
|
53
|
+
assert_equal 0, ::ActiveRecord::Base.uuid_type_from_table_name(:listings)
|
|
54
|
+
assert_equal 0, ::ActiveRecord::Base.uuid_type_from_table_name('listings')
|
|
55
|
+
assert_equal 65_535, ::ActiveRecord::Base.uuid_type_from_table_name(:buildings)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
test 'class from uuid_type' do
|
|
59
|
+
assert_equal FilterTest::Listing, ::ActiveRecord::Base.class_from_uuid_type(0)
|
|
60
|
+
assert_equal FilterTest::Building, ::ActiveRecord::Base.class_from_uuid_type(65_535)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
data/typed_uuid.gemspec
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require File.expand_path("../lib/typed_uuid/version", __FILE__)
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = "typed_uuid"
|
|
5
|
+
s.version = TypedUUID::VERSION
|
|
6
|
+
s.authors = ["Jon Bracy"]
|
|
7
|
+
s.email = ["jonbracy@gmail.com"]
|
|
8
|
+
s.homepage = "https://github.com/malomalo/typed_uuid"
|
|
9
|
+
s.summary = %q{Typed UUIDs for ActiveRecord}
|
|
10
|
+
s.description = %q{Typed UUIDs 2 bytes are reserved in the UUID for the class enum}
|
|
11
|
+
|
|
12
|
+
s.files = `git ls-files`.split("\n")
|
|
13
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
14
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
15
|
+
s.require_paths = ["lib"]
|
|
16
|
+
|
|
17
|
+
# Developoment
|
|
18
|
+
s.add_development_dependency 'rake'
|
|
19
|
+
s.add_development_dependency 'bundler'
|
|
20
|
+
s.add_development_dependency 'minitest'
|
|
21
|
+
s.add_development_dependency 'minitest-reporters'
|
|
22
|
+
s.add_development_dependency 'simplecov'
|
|
23
|
+
s.add_development_dependency 'mocha'
|
|
24
|
+
s.add_development_dependency 'byebug'
|
|
25
|
+
s.add_development_dependency 'activesupport', '>= 6.0.0'
|
|
26
|
+
s.add_development_dependency 'rails', '>= 6.0.0'
|
|
27
|
+
|
|
28
|
+
# Runtime
|
|
29
|
+
s.add_runtime_dependency 'pg'
|
|
30
|
+
s.add_runtime_dependency 'activerecord', '>= 6.0.0'
|
|
31
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: typed_uuid
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: '1.0'
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Jon Bracy
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2019-12-23 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rake
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: bundler
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: minitest
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: minitest-reporters
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: simplecov
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: mocha
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: byebug
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: activesupport
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - ">="
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: 6.0.0
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - ">="
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: 6.0.0
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: rails
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - ">="
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: 6.0.0
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - ">="
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: 6.0.0
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: pg
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - ">="
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0'
|
|
146
|
+
type: :runtime
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '0'
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: activerecord
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - ">="
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: 6.0.0
|
|
160
|
+
type: :runtime
|
|
161
|
+
prerelease: false
|
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
+
requirements:
|
|
164
|
+
- - ">="
|
|
165
|
+
- !ruby/object:Gem::Version
|
|
166
|
+
version: 6.0.0
|
|
167
|
+
description: Typed UUIDs 2 bytes are reserved in the UUID for the class enum
|
|
168
|
+
email:
|
|
169
|
+
- jonbracy@gmail.com
|
|
170
|
+
executables: []
|
|
171
|
+
extensions: []
|
|
172
|
+
extra_rdoc_files: []
|
|
173
|
+
files:
|
|
174
|
+
- ".gitignore"
|
|
175
|
+
- ".tm_properties"
|
|
176
|
+
- Gemfile
|
|
177
|
+
- Gemfile.lock
|
|
178
|
+
- LICENSE
|
|
179
|
+
- README.md
|
|
180
|
+
- Rakefile
|
|
181
|
+
- db/migrate/20191222234546_add_typed_uuid_function.rb
|
|
182
|
+
- lib/typed_uuid.rb
|
|
183
|
+
- lib/typed_uuid/active_record.rb
|
|
184
|
+
- lib/typed_uuid/psql_column_methods.rb
|
|
185
|
+
- lib/typed_uuid/railtie.rb
|
|
186
|
+
- lib/typed_uuid/version.rb
|
|
187
|
+
- test/test_helper.rb
|
|
188
|
+
- test/typed_uuid_test.rb
|
|
189
|
+
- typed_uuid.gemspec
|
|
190
|
+
homepage: https://github.com/malomalo/typed_uuid
|
|
191
|
+
licenses: []
|
|
192
|
+
metadata: {}
|
|
193
|
+
post_install_message:
|
|
194
|
+
rdoc_options: []
|
|
195
|
+
require_paths:
|
|
196
|
+
- lib
|
|
197
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
198
|
+
requirements:
|
|
199
|
+
- - ">="
|
|
200
|
+
- !ruby/object:Gem::Version
|
|
201
|
+
version: '0'
|
|
202
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
203
|
+
requirements:
|
|
204
|
+
- - ">="
|
|
205
|
+
- !ruby/object:Gem::Version
|
|
206
|
+
version: '0'
|
|
207
|
+
requirements: []
|
|
208
|
+
rubygems_version: 3.0.3
|
|
209
|
+
signing_key:
|
|
210
|
+
specification_version: 4
|
|
211
|
+
summary: Typed UUIDs for ActiveRecord
|
|
212
|
+
test_files:
|
|
213
|
+
- test/test_helper.rb
|
|
214
|
+
- test/typed_uuid_test.rb
|