Created
May 6, 2011 14:41
-
-
Save d11wtq/959059 to your computer and use it in GitHub Desktop.
Sequence Property type for DataMapper
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
=begin | |
@author Chris Corbyn | |
@license None, use at your own risk | |
=end | |
module DataMapper | |
class Property | |
# Adds support for a sequences table to DataMapper, via a Sequence property type. | |
# | |
# class Person | |
# include DataMapper::Resource | |
# | |
# property :id, Sequence | |
# end | |
# | |
# You can optionally specify a sequence name on the propery, if it doesn't match convention. | |
# | |
# class Person | |
# include DataMapper::Resource | |
# | |
# property :id, Sequence, :sequence_name => 'person_personid_seq' | |
# end | |
# | |
# The standard naming convention is "#{table_name}_#{field_name}_seq". | |
class Sequence < Integer | |
Property.accept_options(:sequence_name) | |
key true | |
min 1 | |
default lambda { |resource, property| property.next_sequence } | |
@@sequences_table = 'sequences' | |
@@sequences_name = 'name' | |
@@sequences_id = 'id' | |
@sequence_name = nil | |
@retrying = false | |
def self.table(table) | |
@@sequences_table = table.to_s | |
end | |
def self.name_column(name) | |
@@sequences_name = name.to_s | |
end | |
def self.id_column(name) | |
@@sequences_id = name.to_s | |
end | |
def initialize(model, name, options = {}) | |
field_name = options.fetch(:field, name).to_s | |
@sequence_name = options.fetch(:sequence_name, sequence_name_for(model.storage_name, field_name)) | |
super | |
end | |
def next_sequence | |
adapter = repository.adapter | |
sql = "SELECT #{@@sequences_id} FROM #{@@sequences_table} WHERE #{@@sequences_name} = ? FOR UPDATE" | |
sequence = adapter.select(sql, @sequence_name).first | |
if sequence | |
sql = "UPDATE #{@@sequences_table} SET #{@@sequences_id} = #{@@sequences_id} + 1 WHERE #{@@sequences_name} = ?" | |
else | |
sql = "INSERT INTO #{@@sequences_table} (#{@@sequences_name}, #{@@sequences_id}) VALUES (?, 1)" | |
sequence = 1 | |
end | |
adapter.execute(sql, @sequence_name) | |
@retrying = false | |
sequence | |
rescue ::DataObjects::SQLError | |
unless @retrying | |
@retrying = true | |
retry | |
else | |
@retrying = false | |
raise | |
end | |
end | |
private | |
def sequence_name_for(table, column) | |
"#{table}_#{column}_seq" | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment