Skip to content

Instantly share code, notes, and snippets.

@d11wtq
Created May 6, 2011 14:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save d11wtq/959059 to your computer and use it in GitHub Desktop.
Save d11wtq/959059 to your computer and use it in GitHub Desktop.
Sequence Property type for DataMapper
=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