Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Brian Morearty
committed
Jan 3, 2009
1 parent
54ef8f0
commit 2dc1e95
Showing
5 changed files
with
719 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Copyright (c) 2005 Assembla, Inc. | ||
# Portions Copyright (c) 2008 Intuit | ||
# | ||
# This plugin for ActiveRecord makes the "ID" field into a URL-safe GUID | ||
# It is a mashup by Andy Singleton <andy@assembla.com> that includes | ||
# * the UUID class from Bob Aman. | ||
# * the plugin skeleton from Demetrius Nunes | ||
# * the 22 character URL-safe format from Andy Singleton | ||
# You can get standard 36 char UUID formats instead | ||
# TODO: Auto-detect a character ID field and use a GUID in this case (DRY principle) | ||
# | ||
# It has been extended by Brian Morearty with: | ||
# * the addition of a mysql_create function (configurable with a guid_generator accessor) | ||
# for much better performance | ||
# * id assignment is now done before_create instead of after_initialize, to more closely | ||
# mimic the default Rails behavior of assigning an id upon save. | ||
# | ||
# This library is free software; you can redistribute it and/or modify it | ||
# under the terms of the MIT license. | ||
# | ||
# TO USE | ||
# Install as a plugin in the rails directory vendor/plugin/guid | ||
# define ID as char(22) | ||
# call "usesguid" in ActiveRecord class declaration, like | ||
# class Mymodel < ActiveRecord::Base | ||
# usesguid | ||
# | ||
# if your ID field is not called "ID", call "usesguid :column =>'IdColumnName' " | ||
# | ||
# If you use MySQL as your database, you can make guid generation much faster | ||
# by putting this in config/environment.rb: | ||
# ActiveRecord::Base.guid_generator = :mysql | ||
|
||
require 'usesguid' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# from Demetrio Nunes | ||
# Modified by Andy Singleton to use different GUID generator | ||
# Further modified by Brian Morearty to: | ||
# 1. optionally use the MySQL GUID generator | ||
# 2. respect the "column" option | ||
# 3. set the id before create instead of after initialize | ||
# | ||
# MIT License | ||
|
||
require 'uuid22' | ||
require 'uuid_mysql' | ||
|
||
module ActiveRecord | ||
module Usesguid #:nodoc: | ||
|
||
def self.append_features(base) | ||
super | ||
base.extend(ClassMethods) | ||
end | ||
|
||
|
||
module ClassMethods | ||
|
||
# guid_generator can be :timestamp or :mysql | ||
def guid_generator=(generator); class_eval { @guid_generator = generator } end | ||
def guid_generator; class_eval { @guid_generator || :timestamp } end | ||
|
||
def usesguid(options = {}) | ||
|
||
class_eval do | ||
set_primary_key options[:column] if options[:column] | ||
|
||
before_create :assign_guid | ||
|
||
# Give this record a guid id. Public method so people can call it before save if necessary. | ||
def assign_guid | ||
self[self.class.primary_key] ||= case ActiveRecord::Base.guid_generator | ||
when :mysql then UUID.mysql_create(self.connection) | ||
when :timestamp then UUID.timestamp_create() | ||
else raise "Unrecognized guid generator '#{ActiveRecord::Base.guid_generator.to_s}'" | ||
end.to_s22 | ||
end | ||
|
||
end | ||
|
||
end | ||
|
||
end | ||
end | ||
end | ||
|
||
ActiveRecord::Base.class_eval do | ||
include ActiveRecord::Usesguid | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Copyright (c) 2005 Assembla, Inc. | ||
# MIT License | ||
|
||
require 'uuidtools' | ||
|
||
class UUID | ||
|
||
# Make an array of 64 URL-safe characters | ||
@@chars64=('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + ['-','_'] | ||
#return a 22 byte URL-safe string, encoded six bits at a time using 64 characters | ||
def to_s22 | ||
integer=self.to_i | ||
rval='' | ||
22.times do | ||
c=(integer & 0x3F) | ||
rval+=@@chars64[c] | ||
integer =integer >> 6 | ||
end | ||
return rval.reverse | ||
end | ||
# Create a new UUID from a 22char string | ||
def self.parse22(s) | ||
# get the integer representation | ||
integer=0 | ||
s.each_byte {|c| | ||
integer = integer << 6 | ||
pos=@@chars64.index(c.chr) | ||
integer+=pos | ||
} | ||
|
||
time_low = (integer >> 96) & 0xFFFFFFFF | ||
time_mid = (integer >> 80) & 0xFFFF | ||
time_hi_and_version = (integer >> 64) & 0xFFFF | ||
clock_seq_hi_and_reserved = (integer >> 56) & 0xFF | ||
clock_seq_low = (integer >> 48) & 0xFF | ||
nodes = [] | ||
for i in 0..5 do | ||
nodes << ((integer >> (40 - (i * 8))) & 0xFF) | ||
end | ||
return new(time_low, time_mid, time_hi_and_version, | ||
clock_seq_hi_and_reserved, clock_seq_low, nodes) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Copyright (c) 2008 Intuit | ||
# Written by Brian Morearty | ||
# MIT License | ||
|
||
require 'uuidtools' | ||
|
||
class UUID | ||
|
||
BUCKET_SIZE = 50 | ||
@@guid_bucket_mutex = Mutex.new | ||
@@guid_bucket = nil | ||
|
||
# We'll retrieve a bunch of guids at a time to reduce the # of DB round-trips. | ||
# If the guid bucket is empty, re-fill it by calling MySQL. Then return a guid. | ||
def UUID.mysql_create(connection=ActiveRecord::Base.connection) | ||
raise "UUID.mysql_create only works with MySQL" unless connection.adapter_name.downcase =~ /mysql/ | ||
@@guid_bucket_mutex.synchronize do | ||
if @@guid_bucket.blank? | ||
uuid_functions = Array.new(BUCKET_SIZE, "UUID()") | ||
@@guid_bucket = connection.execute("SELECT #{uuid_functions.join(',')}").fetch_row | ||
end | ||
# My tests show shift is much faster than slice!(0), pop, or delete_at(0) | ||
parse @@guid_bucket.shift | ||
end | ||
end | ||
|
||
end |
Oops, something went wrong.