Created
September 26, 2010 15:08
-
-
Save xaviershay/598001 to your computer and use it in GitHub Desktop.
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
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
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) | |
else | |
DataObjects::Transaction.create_for_uri(normalized_uri) | |
end | |
end | |
end | |
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
# 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 that everything is in its right place | |
# before I tidy it up for submission. | |
# | |
# Please read critically the JUSTIFY sections. I have written them as if | |
# I know what I am talking about, which is not an understanding I can claim. | |
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 | |
DataObjects.const_get(uri.scheme.capitalize)::SavePoint.new(uri) | |
end | |
# 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}:#{$$}:#{Time.now.to_f}:#{@@counter += 1}") | |
end | |
def begin | |
run %{SAVEPOINT "#{@id}"} | |
end | |
def commit | |
run %{RELEASE SAVEPOINT "#{@id}"} | |
end | |
def rollback | |
run %{ROLLBACK TO SAVEPOINT "#{@id}"} | |
end | |
private | |
# 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) | |
connection.create_command(cmd).execute_non_query | |
end | |
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
# JUSTIFY: Why just postgres? | |
# | |
# For now, because I don't have other databases set up to test against. | |
# In the future, no reason. | |
module DataObjects | |
module Postgres | |
class SavePoint < DataObjects::SavePoint | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This has been effectively merged in: