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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3a86c5949b3cd7f7ac7767f1dbf1a5b19dbc34d5
4
- data.tar.gz: 98c3b79365a9481776921ccda2fa84de42e79627
3
+ metadata.gz: 7872fe10e5e8fcbe93b6897dd20c4b7da7890d1c
4
+ data.tar.gz: a3844a50a55a3a4d73699e5bddd8551539433e65
5
5
  SHA512:
6
- metadata.gz: 98dad576741bcaad00821fe586117bf9259ca23c39c198e06d9a2ecf86b523a48d5dbe9a904257947dd9e4207451205d658acbe745cdf4b7c3e68279c640a2ae
7
- data.tar.gz: 6f9ead4ee3ce3e17909e53d88c560542300cf65896c265bb58f9e3112b0e0fc3a7014406eb88c039bd000995e2c050167f3b7da283f0c8bfa04003efdee536c8
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) 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)
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) 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)
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) 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.
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) 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.
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) 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)
154
- 2) More difficult to setup since each child table needs its own table.
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
@@ -15,6 +15,7 @@ module Trax
15
15
  extend ::ActiveSupport::Autoload
16
16
 
17
17
  autoload :Config
18
+ autoload :Errors
18
19
  autoload :Freezable
19
20
  autoload :Registry
20
21
  autoload :UUID
@@ -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
- "First Character must be an integer 0-9",
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.first !~ /[0-9]/ || prefix.chars.last !~ /[a-f]/
18
- raise ERROR_MESSAGES[:invalid_uuid_prefix]
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
@@ -3,17 +3,16 @@ module Trax
3
3
  module UniqueId
4
4
  extend ::ActiveSupport::Concern
5
5
 
6
- ERROR_MESSAGES = {
7
- :invalid_uuid_prefix => [
8
- "UUID prefix must be 2 characters long",
9
- "and can only include a-f0-9",
10
- "for hexadecimal id compatibility"
11
- ].join("\n")
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 == :uuid) ? super : __send__(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
@@ -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
- #9f = 96 so we need to begin at 96 when mapping back down [str,int]
7
- DIVIDING_VALUE = 96
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
- lower_value_prefixes = HEX_DIGIT_RANGE.map do |digit|
12
- values = HEX_LETTER_RANGE.map do |character|
13
- prefix = [digit, character].join
14
- new(prefix)
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
@@ -1,3 +1,3 @@
1
1
  module TraxModel
2
- VERSION = '0.0.5'
2
+ VERSION = '0.0.6'
3
3
  end
@@ -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 => "0a", :uuid_column => "uuid"
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
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::Trax::Model::Errors do
4
+ subject{ Trax::Model::Errors::InvalidPrefix }
5
+
6
+ it do
7
+ expect{raise subject.new("blah")}.to raise_error(subject, /blah/)
8
+ end
9
+
10
+ end
@@ -1,26 +1,12 @@
1
1
  require 'spec_helper'
2
2
  describe ::Trax::Model::UUIDPrefix do
3
- subject{ Trax::Model::UUIDPrefix.new('1a') }
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("9a") }
17
- it { described_class.all.length.should eq 120 }
18
- end
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.5
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-08 00:00:00.000000000 Z
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