126 lines
2.3 KiB
Ruby
126 lines
2.3 KiB
Ruby
|
require 'mongoid'
|
||
|
|
||
|
module Mongoid
|
||
|
module Sequence
|
||
|
def Sequence.version
|
||
|
'1.0.0'
|
||
|
end
|
||
|
|
||
|
ClassMethods = proc do
|
||
|
def sequence(fieldname, *args, &block)
|
||
|
options = args.extract_options!.to_options!
|
||
|
|
||
|
sequence_name = (
|
||
|
options.delete(:sequence) || sequence_name_for(fieldname)
|
||
|
)
|
||
|
|
||
|
args.push(options)
|
||
|
|
||
|
before_create do |doc|
|
||
|
doc[fieldname] = SequenceGenerator.for(sequence_name).next
|
||
|
end
|
||
|
|
||
|
field(fieldname, *args, &block)
|
||
|
|
||
|
SequenceGenerator.for(sequence_name)
|
||
|
end
|
||
|
|
||
|
def sequence_for(fieldname)
|
||
|
SequenceGenerator.for(sequence_name_for(fieldname))
|
||
|
end
|
||
|
|
||
|
def sequence_name_for(fieldname)
|
||
|
SequenceGenerator.sequence_name_for(self, fieldname)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
InstanceMethods = proc do
|
||
|
def sequence_for(fieldname)
|
||
|
self.class.sequence_for(fieldname)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def Sequence.included(other)
|
||
|
other.send(:instance_eval, &ClassMethods)
|
||
|
other.send(:class_eval, &InstanceMethods)
|
||
|
super
|
||
|
end
|
||
|
end
|
||
|
|
||
|
class SequenceGenerator
|
||
|
include Mongoid::Document
|
||
|
|
||
|
field(:name, :type => String)
|
||
|
|
||
|
field(:value, :default => 0, :type => Integer)
|
||
|
|
||
|
validates_presence_of(:name)
|
||
|
validates_uniqueness_of(:name)
|
||
|
|
||
|
validates_presence_of(:value)
|
||
|
|
||
|
index({:name => 1}, {:unique => true})
|
||
|
|
||
|
Cache = Hash.new
|
||
|
|
||
|
class << self
|
||
|
def for(name)
|
||
|
name = name.to_s
|
||
|
|
||
|
Cache[name] ||= (
|
||
|
begin
|
||
|
create!(:name => name)
|
||
|
rescue
|
||
|
where(:name => name).first || create!(:name => name)
|
||
|
end
|
||
|
)
|
||
|
end
|
||
|
|
||
|
alias_method('[]', 'for')
|
||
|
|
||
|
def sequence_name_for(klass, fieldname)
|
||
|
"#{ klass.name.underscore }-#{ fieldname }"
|
||
|
end
|
||
|
end
|
||
|
|
||
|
after_destroy do |sequence|
|
||
|
Cache.delete(sequence.name)
|
||
|
end
|
||
|
|
||
|
def next
|
||
|
inc(:value, 1)
|
||
|
end
|
||
|
|
||
|
def current_value
|
||
|
reload.value
|
||
|
end
|
||
|
|
||
|
def reset!
|
||
|
update_attributes!(:value => 0)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
if $0 == __FILE__
|
||
|
|
||
|
Mongoid.configure do |config|
|
||
|
config.connect_to('mongoid-sequence')
|
||
|
end
|
||
|
|
||
|
class A
|
||
|
include Mongoid::Document
|
||
|
include Mongoid::Sequence
|
||
|
|
||
|
p sequence(:number)
|
||
|
end
|
||
|
|
||
|
A.sequence_for(:number).destroy
|
||
|
|
||
|
a = A.create!
|
||
|
p a
|
||
|
|
||
|
end
|