pg_space_cadet
Summary
for space cadet augmented ActiveRecord::Base's, ruby ObjectSpace like object_id's as default ActiveRecord id's based on UUID's
Description
pg_space_cadet is a simple hack for postgreSQL and ActiveRecord which provides a uuids table of distributable identities of space cadets -- ActiveRecord::Base instances which use the SpaceCadetWrapper. Each space cadet has a default ActiveRecord id unique in the set of all local space cadets; a space cadet's id is derived from its uuid - UUID's are by design universally distributable.
Usage
Note that the version 0.7.2 gem is tested but experimental -- a proof of concept. (It does not use the postgres native uuid type yet. It has not been established whether or not the dependence on the postgreSQL setval function is practical for a production database.)
require 'space_cadet_wrapper'
class ChessGame < ActiveRecord::Base
before_create SpaceCadetWrapper.new
before_destroy SpaceCadetWrapper.new # optional
...
end # ChessGame
class MySpaceCadet < ActiveRecord::Base
before_create SpaceCadetWrapper.new
before_destroy SpaceCadetWrapper.new # optional
...
end # MySpaceCadet
ChessGame instances are space cadets.
Before ActiveRecord creates a ChessGame space cadet, it uses postgreSQL's uuid_generate_v4 to create a UUID. The lowest 31 bits of the UUID are used to make a shared ActiveRecord default id.
The uuids table gains a chess_games row as in:
id source_name uuid
746042992 my_space_cadets 7770a54c-7f08-4817-877e-43e1ac77b670
569967860 chess_games 274ead56-7c8f-4c8d-ad21-35d4a1f904f4
The chess_games table gains a row like:
id moves ambiguities move_number ...
569967860 e2e4 1 ...
569967860 == 0x21f904f4 # the 31 low order bits of the UUID
The (setval) hack, used to force the id's to be the same, uses postgreSQL's setval on the uuids_id_seq and the chess_games_id_seq sequences so that ActiveRecord uses (is tricked into using) the 569967860 value as the next id in both tables.
The result is that id 569967860 is guaranteed to be unique for all space cadets i.e. ChessGame instances, MySpaceCadet instances and other space cadets. Note in the rare event that there is a duplicate id conflict in uuids, a new UUID is tried.
my_space_cadet = ... # created MySpaceCadet instance
uuid = SpaceCadet::Uuid.find(my_space_cadet.id) # my_space_cadet's uuid
space_cadet_ref = SpaceCadet::Uuid.find_by_uuid(
'274ead56-7c8f-4c8d-ad21-35d4a1f904f4')
space_cadet_id = space_cadet_ref.id # 569967860
space_cadet_source_name = space_cadet_ref.source_name # 'chess_games'
chess_game_class = <some function> space_cadet_source_name
chess_game = chess_game_class.find(space_cadet_id)
'e2e4' == chess_game.moves # true
Requirements
Most likely any recent version of 1.9 ruby works.
Most likely any version of the pg gem that understands setval for sequences and uuid_generate_v4 (after create extension "uuid-ossp") works.
Most likely any version of the activerecord gem which can use the given pg gem and can be used with require "active_record" works.
TODO: JRuby postgreSQL space_cadets - should be simple
Test with rspec ~> 2.11, rspec -fd
The specs assume that the connection url in spec/support/space_cadet.rb works.
The specs assume that the uuids table exists in the postgreSQL database.
The specs assume that the chess_games table exists in the postgreSQL database.
The specs do not update the database (transactions with rollback).
Note, to prepare the database for testing:
irb prompt> load 'spec/support/space_cadet.rb'
irb prompt> up
irb prompt> exit
The author uses DbVisualizer 9.0.5 and irb to try out the space cadets.
Note, to find the gem installation directory:
irb prompt> require 'space_cadet_wrapper'
irb prompt> $".grep(/pg_space_cadet/)[0]
irb prompt> exit
License
Copyright (c) 2013 Bardi Einarsson. Released under the MIT License. See the LICENSE file for further details.