trax_model 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +16 -6
- data/lib/trax/model.rb +1 -0
- data/lib/trax/model/config.rb +3 -4
- data/lib/trax/model/errors.rb +27 -0
- data/lib/trax/model/mti/entity.rb +14 -15
- data/lib/trax/model/unique_id.rb +7 -8
- data/lib/trax/model/uuid.rb +20 -0
- data/lib/trax/model/uuid_prefix.rb +6 -50
- data/lib/trax_model/version.rb +1 -1
- data/spec/support/schema.rb +14 -1
- data/spec/trax/model/errors_spec.rb +10 -0
- data/spec/trax/model/uuid_prefix_spec.rb +4 -26
- data/spec/trax/model/uuid_spec.rb +12 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7872fe10e5e8fcbe93b6897dd20c4b7da7890d1c
|
4
|
+
data.tar.gz: a3844a50a55a3a4d73699e5bddd8551539433e65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c4010865a9e93b936268e272cc554e1f45fd6082688c165855d5472f7f08bd4ac114cd9aa589e0ac1c08de4936c86b8bc6f187cea7f2412e9683c4c046ec2e1
|
7
|
+
data.tar.gz: 6f33aa0545ab904bee6517f1b58216bbe9b37ef18afa0a46d8ea871d4ea11e6d99d93fbf53fe671ce5332492b2583eb61272fe75473efdbc41415afb25d1e5d4
|
data/README.md
CHANGED
@@ -58,6 +58,16 @@ bx rails c
|
|
58
58
|
=> "1a"
|
59
59
|
```
|
60
60
|
|
61
|
+
### Or, register prefixes using dsl rather than in each individual class
|
62
|
+
|
63
|
+
``` ruby
|
64
|
+
|
65
|
+
Trax::Model::UUID.register do
|
66
|
+
prefix "1a", Product
|
67
|
+
prefix "1b", Category
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
61
71
|
But wait theires more!
|
62
72
|
|
63
73
|
### UUID utility methods
|
@@ -140,18 +150,18 @@ end
|
|
140
150
|
|
141
151
|
The main advantages of Multiple Table Inheritance versus Single Table inheritance I see are:
|
142
152
|
|
143
|
-
1
|
153
|
+
1. Table size. As databases grow, vertically adding more length to traverse the table will continue to get slower. One way to mitigate this issue would be to split up your table into multiple horizontal tables, if it makes sense for your data structure to do so (i.e. like above)
|
144
154
|
|
145
|
-
2
|
155
|
+
2. STI will get out of proportion likely. I.e. if 90% of your posts are text posts, then when you are looking for a video post, you are to some degree being slowed down by the video posts in your table. (or at least at some point when you reach past xxxxxx number of records)
|
146
156
|
|
147
|
-
3
|
157
|
+
3. Further on that note, only storing what you need for each individual subset of your data, on that particular subset. I.e. if video post has a video_url attribute, but none of the other post types have that, it will keep holes out of your data tables since video_url is only on the video_posts table.
|
148
158
|
|
149
|
-
4
|
159
|
+
4. Real separation at the data level of non common attributes, so you dont have to write safeguards in child classes to make sure that a value didnt slip into a field or whatever, because each child class has its own individual interpretation of the schema.
|
150
160
|
|
151
161
|
The main disadvantages are:
|
152
162
|
|
153
|
-
1
|
154
|
-
2
|
163
|
+
1. No shared view between child types. I.E. thats what the MTI entity is for. (want to find all blog posts? You cant unless you select a type first, or are using this gem, or a postgres view or something else)
|
164
|
+
2. More difficult to setup since each child table needs its own table.
|
155
165
|
|
156
166
|
|
157
167
|
## Installation
|
data/lib/trax/model.rb
CHANGED
data/lib/trax/model/config.rb
CHANGED
@@ -4,8 +4,7 @@ module Trax
|
|
4
4
|
ERROR_MESSAGES = {
|
5
5
|
:invalid_uuid_prefix => [
|
6
6
|
"UUID prefix must be 2 characters long",
|
7
|
-
"
|
8
|
-
"Second character must be a letter a-f",
|
7
|
+
"and be 0-9 or a-f",
|
9
8
|
"for hexadecimal id compatibility"
|
10
9
|
].join("\n")
|
11
10
|
}.freeze
|
@@ -14,8 +13,8 @@ module Trax
|
|
14
13
|
property :uuid_column, :default => :id
|
15
14
|
|
16
15
|
def uuid_prefix=(prefix)
|
17
|
-
if prefix.length != 2 || prefix.chars.
|
18
|
-
raise
|
16
|
+
if prefix.length != 2 || prefix.chars.any?{|char| char !~ /[0-9a-f]/ }
|
17
|
+
raise ::Trax::Model::Errors::InvalidPrefixForUUID.new(prefix)
|
19
18
|
end
|
20
19
|
|
21
20
|
self[:uuid_prefix] = ::Trax::Model::UUIDPrefix.new(prefix)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Trax
|
2
|
+
module Model
|
3
|
+
module Errors
|
4
|
+
class Base < StandardError
|
5
|
+
def initialize(*args)
|
6
|
+
message = (self.class::MESSAGE + args).join("\n")
|
7
|
+
super(message)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class InvalidPrefix < Trax::Model::Errors::Base
|
12
|
+
MESSAGE = [
|
13
|
+
"UUID prefix must be 2 characters long",
|
14
|
+
"and be 0-9 or a-f",
|
15
|
+
"for hexadecimal id compatibility"
|
16
|
+
]
|
17
|
+
end
|
18
|
+
|
19
|
+
class DuplicatePrefixRegistered < Trax::Model::Errors::Base
|
20
|
+
MESSAGE = [
|
21
|
+
"UUID prefix must be unique, the",
|
22
|
+
"following prefix was already registered"
|
23
|
+
]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -10,6 +10,20 @@ module Trax
|
|
10
10
|
scope :records, lambda{
|
11
11
|
map(&:entity)
|
12
12
|
}
|
13
|
+
|
14
|
+
scope :fully_loaded, lambda{
|
15
|
+
relation = current_scope.dup
|
16
|
+
entity_ids = relation.pluck(:id)
|
17
|
+
entity_types = entity_ids.map { |id| ::Trax::Model::UUID.new(id[0..1]) }
|
18
|
+
.map(&:record_type)
|
19
|
+
.flatten
|
20
|
+
.compact
|
21
|
+
.uniq
|
22
|
+
|
23
|
+
relation_names = entity_types.map{ |type| :"#{type.name.demodulize.underscore}_entity" }
|
24
|
+
|
25
|
+
current_scope.includes(relation_names).references(relation_names)
|
26
|
+
}
|
13
27
|
end
|
14
28
|
|
15
29
|
def model_type
|
@@ -29,20 +43,6 @@ module Trax
|
|
29
43
|
end
|
30
44
|
|
31
45
|
module ClassMethods
|
32
|
-
def all
|
33
|
-
relation = super
|
34
|
-
entity_ids = relation.pluck(:id)
|
35
|
-
entity_types = entity_ids.map { |id| ::Trax::Model::UUID.new(id[0..1]) }
|
36
|
-
.map(&:record_type)
|
37
|
-
.flatten
|
38
|
-
.compact
|
39
|
-
.uniq
|
40
|
-
|
41
|
-
relation_names = entity_types.map{ |type| :"#{type.name.demodulize.underscore}_entity" }
|
42
|
-
|
43
|
-
relation.includes(relation_names).references(relation_names)
|
44
|
-
end
|
45
|
-
|
46
46
|
def mti_namespace(namespace)
|
47
47
|
_mti_namespace = (namespace.is_a?(String)) ? namespace.constantize : namespace
|
48
48
|
|
@@ -55,7 +55,6 @@ module Trax
|
|
55
55
|
def multiple_table_inheritance_namespace(namespace)
|
56
56
|
mti_namespace(namespace)
|
57
57
|
end
|
58
|
-
|
59
58
|
end
|
60
59
|
end
|
61
60
|
end
|
data/lib/trax/model/unique_id.rb
CHANGED
@@ -3,17 +3,16 @@ module Trax
|
|
3
3
|
module UniqueId
|
4
4
|
extend ::ActiveSupport::Concern
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
}.freeze
|
6
|
+
included do
|
7
|
+
#grab prefix from uuid registry if using that
|
8
|
+
if ::Trax::Model::UUID.klass_prefix_map.has_key?(self.name)
|
9
|
+
self.trax_defaults.uuid_prefix = ::Trax::Model::UUIDPrefix.new(klass_prefix_map[self.name])
|
10
|
+
end
|
11
|
+
end
|
13
12
|
|
14
13
|
def uuid
|
15
14
|
uuid_column = self.class.trax_defaults.uuid_column
|
16
|
-
uuid_value = (uuid_column ==
|
15
|
+
uuid_value = (uuid_column == "uuid") ? super : __send__(uuid_column)
|
17
16
|
|
18
17
|
::Trax::Model::UUID.new(uuid_value)
|
19
18
|
end
|
data/lib/trax/model/uuid.rb
CHANGED
@@ -1,12 +1,32 @@
|
|
1
1
|
module Trax
|
2
2
|
module Model
|
3
3
|
class UUID < String
|
4
|
+
class_attribute :prefix_map
|
5
|
+
|
6
|
+
self.prefix_map = ::Hashie::Mash.new
|
7
|
+
|
8
|
+
def self.klass_prefix_map
|
9
|
+
prefix_map.invert
|
10
|
+
end
|
11
|
+
|
4
12
|
def self.generate(prefix = nil)
|
5
13
|
uuid = ::SecureRandom.uuid
|
6
14
|
uuid[0..1] = prefix if prefix
|
7
15
|
uuid
|
8
16
|
end
|
9
17
|
|
18
|
+
def self.prefix(prefix_value, klass)
|
19
|
+
if prefix_map.has_key(:"#{prefix_value}") && prefix_map[:"#{prefix_value}"] == klass
|
20
|
+
raise ::Trax::Model::Errors::DuplicatePrefix.new(prefix_value)
|
21
|
+
end
|
22
|
+
|
23
|
+
prefix_map[:"#{prefix_value}"] = klass
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.register(&block)
|
27
|
+
instance_exec(&block)
|
28
|
+
end
|
29
|
+
|
10
30
|
def record
|
11
31
|
@record ||= record_type ? record_type.find_by(:"#{record_type.uuid_column}" => self) : nil
|
12
32
|
end
|
@@ -3,50 +3,19 @@ module Trax
|
|
3
3
|
class UUIDPrefix < String
|
4
4
|
HEX_LETTER_RANGE = ('a'..'f').to_a.freeze
|
5
5
|
HEX_DIGIT_RANGE = (0..9).to_a.freeze
|
6
|
-
|
7
|
-
|
6
|
+
CHARACTER_RANGE = (HEX_DIGIT_RANGE + HEX_LETTER_RANGE).freeze
|
7
|
+
PREFIX_LENGTH = 2
|
8
8
|
|
9
9
|
def self.all
|
10
10
|
@all ||= begin
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
values
|
11
|
+
CHARACTER_RANGE.repeated_permutation(PREFIX_LENGTH).to_a.reject! do |permutation|
|
12
|
+
(HEX_LETTER_RANGE.include?(permutation[0]) && HEX_LETTER_RANGE.include?(permutation[1]) || HEX_DIGIT_RANGE.include?(permutation[0]) && HEX_DIGIT_RANGE.include?(permutation[1]))
|
13
|
+
end.uniq.map do |character_array|
|
14
|
+
new(character_array.join)
|
18
15
|
end
|
19
|
-
|
20
|
-
higher_value_prefixes = HEX_LETTER_RANGE.map do |digit|
|
21
|
-
values = HEX_DIGIT_RANGE.map do |character|
|
22
|
-
prefix = [digit, character].join
|
23
|
-
new(prefix)
|
24
|
-
end
|
25
|
-
|
26
|
-
values
|
27
|
-
end
|
28
|
-
|
29
|
-
[lower_value_prefixes, higher_value_prefixes].flatten!.sort!
|
30
16
|
end
|
31
17
|
end
|
32
18
|
|
33
|
-
def self.build_from_integer(value)
|
34
|
-
value_str = "#{value}"
|
35
|
-
return new([value_str.chars.first.to_i, HEX_LETTER_RANGE[value_str.chars.last.to_i]].join)
|
36
|
-
end
|
37
|
-
|
38
|
-
def <=>(comparison_prefix)
|
39
|
-
self.to_i <=> comparison_prefix.to_i
|
40
|
-
end
|
41
|
-
|
42
|
-
def in_higher_partition?
|
43
|
-
"#{self}"[0] =~ /[a-f]/
|
44
|
-
end
|
45
|
-
|
46
|
-
def in_lower_partition?
|
47
|
-
!in_higher_partition?
|
48
|
-
end
|
49
|
-
|
50
19
|
def index
|
51
20
|
self.class.all.index(self)
|
52
21
|
end
|
@@ -59,19 +28,6 @@ module Trax
|
|
59
28
|
self.class.all.at(index - 1)
|
60
29
|
end
|
61
30
|
|
62
|
-
def to_digits
|
63
|
-
digits = self.chars.map do |character|
|
64
|
-
(character.downcase =~ /[a-f]/ ? HEX_LETTER_RANGE.index(character.downcase) : character)
|
65
|
-
end
|
66
|
-
|
67
|
-
#kind of wonky but multiply by 2 will ensure the letter prefixes begin with a higher value
|
68
|
-
in_higher_partition? ? "#{((digits.join.to_i + DIVIDING_VALUE * 2))}".chars : digits
|
69
|
-
end
|
70
|
-
|
71
|
-
def to_i
|
72
|
-
return self.to_digits.join.to_i
|
73
|
-
end
|
74
|
-
|
75
31
|
def to_s
|
76
32
|
"#{self}"
|
77
33
|
end
|
data/lib/trax_model/version.rb
CHANGED
data/spec/support/schema.rb
CHANGED
@@ -48,6 +48,13 @@ ActiveRecord::Schema.define(:version => 1) do
|
|
48
48
|
t.datetime "created_at", :null => false
|
49
49
|
t.datetime "updated_at", :null => false
|
50
50
|
end
|
51
|
+
|
52
|
+
create_table "people", :force => true do |t|
|
53
|
+
t.string "name"
|
54
|
+
t.string "uuid"
|
55
|
+
t.datetime "created_at", :null => false
|
56
|
+
t.datetime "updated_at", :null => false
|
57
|
+
end
|
51
58
|
end
|
52
59
|
|
53
60
|
class Product < ::ActiveRecord::Base
|
@@ -87,5 +94,11 @@ end
|
|
87
94
|
class Thing < ::ActiveRecord::Base
|
88
95
|
include ::Trax::Model
|
89
96
|
|
90
|
-
defaults :uuid_prefix => "
|
97
|
+
defaults :uuid_prefix => "4a", :uuid_column => "uuid"
|
98
|
+
end
|
99
|
+
|
100
|
+
class Person < ::ActiveRecord::Base
|
101
|
+
include ::Trax::Model
|
102
|
+
|
103
|
+
defaults :uuid_column => "uuid"
|
91
104
|
end
|
@@ -1,26 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
describe ::Trax::Model::UUIDPrefix do
|
3
|
-
subject{
|
4
|
-
|
5
|
-
describe "#to_i" do
|
6
|
-
{"1a" => 10, "2a" => 20, "9e" => 94, "8d" => 83, "0a" => 0, "0b" => 1, "f9" => 251}.each_pair do |prefix_string, assertion|
|
7
|
-
it "#{prefix_string} should eq #{assertion}" do
|
8
|
-
prefix = ::Trax::Model::UUIDPrefix.new(prefix_string)
|
9
|
-
|
10
|
-
prefix.to_i.should eq assertion
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
3
|
+
subject{ described_class.new('1a') }
|
14
4
|
|
15
5
|
describe ".all" do
|
16
|
-
it { described_class.all.should include("
|
17
|
-
it { described_class.all.
|
18
|
-
|
19
|
-
|
20
|
-
describe ".build_from_integer" do
|
21
|
-
it { described_class.build_from_integer(10).should eq "1a" }
|
6
|
+
it { described_class.all.should include("a1") }
|
7
|
+
it { described_class.all.first.should eq "0a" }
|
8
|
+
it { described_class.all.last.should eq "f9" }
|
22
9
|
end
|
23
|
-
|
24
10
|
describe "#next" do
|
25
11
|
let(:test_subject) { Product.uuid_prefix }
|
26
12
|
|
@@ -37,12 +23,4 @@ describe ::Trax::Model::UUIDPrefix do
|
|
37
23
|
|
38
24
|
it { test_subject.previous.should eq '0f' }
|
39
25
|
end
|
40
|
-
|
41
|
-
describe "#to_i" do
|
42
|
-
context "when prefix in {int,str} order" do
|
43
|
-
let(:test_subject) { Product.uuid_prefix }
|
44
|
-
|
45
|
-
it { test_subject.to_i.should eq 10 }
|
46
|
-
end
|
47
|
-
end
|
48
26
|
end
|
@@ -4,9 +4,20 @@ describe ::Trax::Model::UUID do
|
|
4
4
|
let(:product) { ::Product.create(:name => "iMac") }
|
5
5
|
subject{ product.uuid }
|
6
6
|
|
7
|
+
context "dsl register methods" do
|
8
|
+
before do
|
9
|
+
::Trax::Model::UUID.register do
|
10
|
+
prefix "9a", ::Person
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it { described_class.prefix_map.should have_key("9a") }
|
15
|
+
it { described_class.klass_prefix_map.should have_key(Person) }
|
16
|
+
end
|
17
|
+
|
7
18
|
its(:record_type) { should eq ::Product }
|
8
19
|
its(:record) { should eq product }
|
9
|
-
|
20
|
+
|
10
21
|
describe ".generate" do
|
11
22
|
context "with prefix" do
|
12
23
|
let(:prefixed_uuid) { described_class.generate("1a") }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trax_model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Ayre
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: trax_core
|
@@ -266,6 +266,7 @@ files:
|
|
266
266
|
- lib/trax.rb
|
267
267
|
- lib/trax/model.rb
|
268
268
|
- lib/trax/model/config.rb
|
269
|
+
- lib/trax/model/errors.rb
|
269
270
|
- lib/trax/model/freezable.rb
|
270
271
|
- lib/trax/model/matchable.rb
|
271
272
|
- lib/trax/model/mti.rb
|
@@ -288,6 +289,7 @@ files:
|
|
288
289
|
- spec/spec_helper.rb
|
289
290
|
- spec/support/schema.rb
|
290
291
|
- spec/trax/model/config_spec.rb
|
292
|
+
- spec/trax/model/errors_spec.rb
|
291
293
|
- spec/trax/model/freezable_spec.rb
|
292
294
|
- spec/trax/model/matchable_spec.rb
|
293
295
|
- spec/trax/model/registry_spec.rb
|
@@ -329,6 +331,7 @@ test_files:
|
|
329
331
|
- spec/spec_helper.rb
|
330
332
|
- spec/support/schema.rb
|
331
333
|
- spec/trax/model/config_spec.rb
|
334
|
+
- spec/trax/model/errors_spec.rb
|
332
335
|
- spec/trax/model/freezable_spec.rb
|
333
336
|
- spec/trax/model/matchable_spec.rb
|
334
337
|
- spec/trax/model/registry_spec.rb
|