activeuuid-ps 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.swp
2
+ *.gem
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in activeuuid.gemspec
4
+ gemspec
data/README.mkd ADDED
@@ -0,0 +1,134 @@
1
+ # activeuuid
2
+
3
+ Add `binary(16)` UUIDs to ActiveRecord.
4
+
5
+ ## Example
6
+
7
+ ### Create a Migration
8
+
9
+ `activeuuid` adds the `uuid` type to your migrations. Example:
10
+
11
+ ```ruby
12
+ class CreateEmails < ActiveRecord::Migration
13
+ def self.up
14
+ create_table :emails, :id => false do |t|
15
+ t.uuid :id, :unique => true
16
+ t.uuid :sender_id # belongs_to :sender
17
+
18
+ t.string :subject
19
+ t.text :body
20
+
21
+ t.timestamp :sent_at
22
+ t.timestamps
23
+ end
24
+ add_index :emails, :id
25
+ end
26
+
27
+ def self.down
28
+ drop_table :emails
29
+ end
30
+ end
31
+ ```
32
+
33
+ ### include ActiveUUID::UUID in your model
34
+
35
+ ```ruby
36
+ class Email < ActiveRecord::Base
37
+ include ActiveUUID::UUID
38
+ belongs_to :sender
39
+ end
40
+ ```
41
+
42
+ ### use it:
43
+ Here are some example specs:
44
+
45
+ ```ruby
46
+ require 'spec_helper'
47
+
48
+ describe Email do
49
+
50
+ context "when using uuid's as keys" do
51
+ before(:each) do
52
+ Email.delete_all
53
+ @guid = "1dd74dd0-d116-11e0-99c7-5ac5d975667e"
54
+ @e = Email.new(:subject => "hello", :body => "world") {|e| e.id = UUIDTools::UUID.parse(@guid) }
55
+ @e.save
56
+ end
57
+
58
+ it "the id guid should be equal to the uuid" do
59
+ @e.id.to_s.should eql(@guid)
60
+ end
61
+
62
+ it "should be able to find an email by the uuid" do
63
+ f = Email.find(UUIDTools::UUID.parse(@guid))
64
+ f.id.to_s.should eql(@guid)
65
+ end
66
+
67
+ end
68
+ end
69
+ ```
70
+
71
+ ## Motivation
72
+
73
+ From [2]:
74
+
75
+ > [Here is a] UUID: 1e8ef774-581c-102c-bcfe-f1ab81872213
76
+ >
77
+ > A UUID like the one above is 36 characters long, including dashes. If you store this VARCHAR(36), you're going to decrease compare performance dramatically. This is your primary key, you don't want it to be slow.
78
+ >
79
+ > At its bit level, a UUID is 128 bits, which means it will fit into
80
+ > 16 bytes, note this is not very human readable, but it will keep
81
+ > storage low, and is only 4 times larger than a 32-bit int, or 2
82
+ > times larger than a 64-bit int.
83
+
84
+ Many of the existing examples of how to use UUIDs as primary keys
85
+ in Rails use strings rather than bytes (e.g. [3]).
86
+
87
+ However, this plugin stores the primary keys as bytes. To the
88
+ application the keys are represented by a UUIDTools::UUID object.
89
+
90
+ ## Benefits of UUIDs as primary key
91
+
92
+ * no id conflict during multi-master write
93
+ * no locking due to auto-increment
94
+ * with time-based UUIDs you can store a timestamp within your UUID
95
+ * you can create natural keys (based on the SHA of model attributes)
96
+
97
+ ## Future work
98
+ * more transparent support for natural and composite keys
99
+ * support for MySQLs `INSERT ... ON DUPLICATE KEY UPDATE` syntax
100
+ * support a primary column name other than `id`
101
+ * work on other databases (Postgres, etc)
102
+ * tests
103
+
104
+ ## Inspiration
105
+ James Golick's `friendly` is a great gem for NoSQL on MySQL. It's
106
+ a great gateway drug to systems like Cassandra for teams that are
107
+ already familiar with the ins-and-outs of MySQL.
108
+
109
+ ## Installation
110
+
111
+ Add this to your `Gemfile`
112
+
113
+ gem "activeuuid"
114
+
115
+ Or get the code here: https://github.com/jashmenn/activeuuid
116
+
117
+ ## References
118
+ * [1] http://bret.appspot.com/entry/how-friendfeed-uses-mysql
119
+ * [2] http://kekoav.com/blog/36-computers/58-uuids-as-primary-keys-in-mysql.html
120
+ * [3] https://gist.github.com/937739
121
+ * [4] http://www.codinghorror.com/blog/2007/03/primary-keys-ids-versus-guids.html
122
+ * [5] http://krow.livejournal.com/497839.html
123
+ * [6] https://github.com/jamesgolick/friendly
124
+
125
+ ## Dependencies
126
+ Rails ~> 3.1.0 - It uses the custom column serialization Aaron
127
+ Patterson introduced in Rails 3.1.
128
+
129
+ I'm using JRuby 1.9 (1.6.3) but this should work under MRI (YMMV).
130
+
131
+ ## Author
132
+
133
+ Nate Murray <nate@xcombinator.com>
134
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "activeuuid/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "activeuuid-ps"
7
+ s.version = Activeuuid::VERSION
8
+ s.authors = ["Nate Murray, Ralf S. Bongiolo"]
9
+ s.email = ["nate@natemurray.com, ralfsb2008@gmail.com"]
10
+ s.homepage = "http://www.xcombinator.com"
11
+ s.summary = %q{Add binary UUIDs to ActiveRecord in PostgreSQL}
12
+ s.description = %q{Add binary (not string) UUIDs to ActiveRecord in PostgreSQL}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ # s.add_development_dependency "rspec"
20
+ s.add_runtime_dependency "uuidtools"
21
+ end
data/lib/activeuuid.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "activeuuid/version"
2
+
3
+ module ActiveUUID
4
+ require 'activeuuid/railtie' if defined?(Rails)
5
+ require 'activeuuid/uuid'
6
+ end
@@ -0,0 +1,21 @@
1
+ require 'activeuuid'
2
+ require 'rails'
3
+
4
+ module ActiveUUID
5
+ class Railtie < Rails::Railtie
6
+ railtie_name :activeuuid
7
+ initializer "activeuuid.configure_rails_initialization" do
8
+
9
+ module ActiveRecord::ConnectionAdapters
10
+ class TableDefinition
11
+ def uuid (*args)
12
+ options = args.extract_options!
13
+ column_names = args
14
+ column_names.each { |name| column(name, 'binary(16)', options) }
15
+ end
16
+ end
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,107 @@
1
+ module UUIDTools
2
+ class UUID
3
+ # monkey-patch Friendly::UUID to serialize UUIDs to MySQL
4
+ def quoted_id
5
+ s = raw.unpack("H*")[0]
6
+ "x'#{s}'"
7
+ end
8
+
9
+ # monkey-patch Friendly::UUID to serialize UUIDs to MySQL
10
+ def quoted_id_ps
11
+ s = raw.unpack("H*")[0]
12
+ "\x'#{s}'"
13
+ end
14
+
15
+ def as_json(options = nil)
16
+ hexdigest.upcase
17
+ end
18
+
19
+ def to_param
20
+ hexdigest.upcase
21
+ end
22
+ end
23
+ end
24
+
25
+ module Arel
26
+ module Visitors
27
+ class MySQL < Arel::Visitors::ToSql
28
+ def visit_UUIDTools_UUID(o)
29
+ o.quoted_id
30
+ end
31
+ end
32
+ class PostgreSQL < Arel::Visitors::ToSql
33
+ def visit_UUIDTools_UUID(o)
34
+ o.quoted_id_ps
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ module ActiveUUID
41
+ class UUIDSerializer
42
+ def load(binary)
43
+ case binary
44
+ when UUIDTools::UUID then binary
45
+ when nil then nil
46
+ else UUIDTools::UUID.parse_raw(binary)
47
+ end
48
+ end
49
+ def dump(uuid)
50
+ uuid ? uuid.raw : nil
51
+ end
52
+ end
53
+
54
+ module UUID
55
+ extend ActiveSupport::Concern
56
+
57
+ included do
58
+ before_create :generate_uuid_if_needed
59
+
60
+ set_primary_key "id"
61
+ serialize :id, ActiveUUID::UUIDSerializer.new
62
+
63
+ def generate_uuid_if_needed
64
+ generate_uuid unless self.id
65
+ end
66
+
67
+ def to_param
68
+ id.to_param
69
+ end
70
+
71
+ def generate_uuid
72
+ if nka = self.class.natural_key_attributes
73
+ # TODO if all the attributes return nil you might want to warn about this
74
+ chained = nka.collect{|a| self.send(a).to_s}.join("-")
75
+ self.id = UUIDTools::UUID.sha1_create(UUIDTools::UUID_OID_NAMESPACE, chained)
76
+ else
77
+ self.id = UUIDTools::UUID.timestamp_create
78
+ end
79
+ end
80
+ end
81
+
82
+ module ClassMethods
83
+ def natural_key_attributes
84
+ @_activeuuid_natural_key_attributes
85
+ end
86
+
87
+ def natural_key(*attributes)
88
+ @_activeuuid_natural_key_attributes = attributes
89
+ end
90
+
91
+ def uuids(*attributes)
92
+ attributes.each do |attribute|
93
+ serialize attribute.intern, ActiveUUID::UUIDSerializer.new
94
+ #class_eval <<-eos
95
+ # # def #{@association_name}
96
+ # # @_#{@association_name} ||= self.class.associations[:#{@association_name}].new_proxy(self)
97
+ # # end
98
+ #eos
99
+ end
100
+ end
101
+ end
102
+
103
+ module InstanceMethods
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,3 @@
1
+ module Activeuuid
2
+ VERSION = "0.1.1"
3
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activeuuid-ps
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nate Murray, Ralf S. Bongiolo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-28 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: uuidtools
16
+ requirement: &23679000 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *23679000
25
+ description: Add binary (not string) UUIDs to ActiveRecord in PostgreSQL
26
+ email:
27
+ - nate@natemurray.com, ralfsb2008@gmail.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - .gitignore
33
+ - Gemfile
34
+ - README.mkd
35
+ - Rakefile
36
+ - activeuuid.gemspec
37
+ - lib/activeuuid.rb
38
+ - lib/activeuuid/railtie.rb
39
+ - lib/activeuuid/uuid.rb
40
+ - lib/activeuuid/version.rb
41
+ homepage: http://www.xcombinator.com
42
+ licenses: []
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 1.7.2
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Add binary UUIDs to ActiveRecord in PostgreSQL
65
+ test_files: []