Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
This is a sample patch for three dm gems - data_objects, do_postgres, and dm-postgres-adapter. It is not ready to be applied, since it is currently unspecced and untested. The purpose of this patch is to solicit feedback as to the architecture, to ensure
require 'dm-transactions/adapters/dm-do-adapter'
module DataMapper
class Transaction
module PostgresAdapter
include DataObjectsAdapter
# Produces a fresh transaction primitive for this Adapter. Fake nested
# transactions by using save points.
# Used by Transaction to perform its various tasks.
# @return [Object]
# a new Object that responds to :close, :begin, :commit,
# and :rollback,
# @api private
def transaction_primitive
if current_transaction
DataObjects::SavePoint.create_for_uri(normalized_uri, current_connection)
require 'digest'
require 'digest/sha2'
# JUSTIFY: Why create a new data object type for save points?
# A save point is analgous to a transaction, and a transaction has its own
# DataObject. Save points are supported by [] do databases, and [are|are
# not] part of the SQL spec.
module DataObjects
# JUSTIFY: Why not inherit from Transaction?
# Even though they share a lot of behaviour, a SavePoint does not satisfy
# LSP for transaction, both because it can't be used in place of a transaction
# (save points require you to be inside a transaction), and as such because
# of the required for the extra connection parameter.
# There is a case to be made for refactoring the common behaviour into a mixin.
class SavePoint
# The host name. Note, this relies on the host name being configured and resolvable using DNS
HOST = "#{Socket::gethostbyname(Socket::gethostname)[0]}" rescue "localhost"
@@counter = 0
# The connection object allocated for this transaction
attr_reader :connection
# A unique ID for this transaction
attr_reader :id
# Instantiate the Transaction subclass that's appropriate for this uri scheme
def self.create_for_uri(uri, connection)
uri = uri.is_a?(String) ? URI::parse(uri) : uri
# JUSTIFY: Why passing in the connection? Transaction doesn't need this...
# Unlike the similar Transaction primitive, which is only created once
# per connection and reused for each transaction, this primitive will
# be created once for each save point, since each save point requires
# its own unique identify. As a result, the extra connection paramater
# is required to allow the existing connection to be reused.
def initialize(uri, connection)
@connection = connection
@id = Digest::SHA256.hexdigest("#{HOST}:#{$$}:#{}:#{@@counter += 1}")
def begin
run %{SAVEPOINT "#{@id}"}
def commit
run %{RELEASE SAVEPOINT "#{@id}"}
def rollback
# JUSTIFY: Transaction doesn't have this extract method refactoring, why here?
# Because I see no reason for this not also to be applied to Transaction
def run(cmd)

jpr5 commented Dec 16, 2010

This has been effectively merged in:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment