Skip to content
This repository was archived by the owner on Jul 20, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,32 @@ s2 = Sequenced.create
s2.id #=> 2 # and so on
```

Subclasses can share their superclass sequenced field(s) and/or have their own sequenced field(s):
```ruby
class Sequenced
include Mongoid::Document
include Mongoid::Sequence

field :my_sequence, :type => Integer
sequence :my_sequence
end

class SubSequenced
use_superclass_sequence

field :my_sub_sequence, :type => Integer
sequence :my_sub_sequence
end

s1 = Sequenced.create
s1.my_sequence #=> 1

s2 = SubSequenced.create
s2.my_sequence #=> 2
s2.my_sub_sequence #=> 1

```

## Consistency

Mongoid::Sequence uses the atomic [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) command, so you shouldn't have to worry about the sequence's consistency.
Expand Down
38 changes: 29 additions & 9 deletions lib/mongoid-sequence.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "mongoid-sequence/version"
require "active_support/concern"
require "set"

module Mongoid
module Sequence
Expand All @@ -11,23 +12,42 @@ module Sequence

module ClassMethods
attr_accessor :sequence_fields
attr_accessor :klazzes

def sequence(field)
self.klazzes ||= Set.new
self.klazzes << self
self.sequence_fields ||= []
self.sequence_fields << field
end

def use_superclass_sequence
self.klazzes ||= self.superclass.klazzes = Set.new
self.klazzes << self.superclass
end

end

def set_sequence
sequences = self.db.collection("__sequences")
self.class.sequence_fields.each do |field|
next_sequence = sequences.find_and_modify(:query => {"_id" => "#{self.class.name.underscore}_#{field}"},
:update => {"$inc" => {"seq" => 1}},
:new => true,
:upsert => true)

self[field] = next_sequence["seq"]
end if self.class.sequence_fields
sequences = get_sequence_collection
self.class.klazzes.each do |klazz|
klazz.sequence_fields.each do |field|
next_sequence = sequences.find_and_modify(:query => {"_id" => "#{klazz.name.underscore}_#{field}"},
:update => {"$inc" => {"seq" => 1}},
:new => true,
:upsert => true)

self[field] = next_sequence["seq"]
end if klazz.sequence_fields
end
end

def get_sequence_collection
if self.embedded?
sequences = self._parent.db.collection("__sequences")
else
sequences = self.db.collection("__sequences")
end
end
end
end
11 changes: 11 additions & 0 deletions test/embedded_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require "test_helper"

class EmbeddedTest < BaseTest
def test_embedded_sequence
parent = ParentSequencedModel.create
child = parent.child_sequenced_models.create

assert_equal parent.auto_increment, 1
assert_equal child.child_auto_increment, 1
end
end
9 changes: 9 additions & 0 deletions test/models/child_sequenced_model.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class ChildSequencedModel
include Mongoid::Document
include Mongoid::Sequence

field :child_auto_increment, :type => Integer
sequence :child_auto_increment

embedded_in :child_sequenced_models, :inverse_of => :child_sequenced_models
end
9 changes: 9 additions & 0 deletions test/models/parent_sequenced_model.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class ParentSequencedModel
include Mongoid::Document
include Mongoid::Sequence

field :auto_increment, :type => Integer
sequence :auto_increment

embeds_many :child_sequenced_models
end
8 changes: 8 additions & 0 deletions test/models/sub_class_multi_sequenced_model.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class SubClassMultiSequencedModel < FirstSequencedModel

field :sequence, :type => Integer
sequence :sequence

use_superclass_sequence

end
6 changes: 6 additions & 0 deletions test/models/sub_class_self_sequenced_model.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class SubClassSelfSequencedModel < FirstSequencedModel

field :sequence, :type => Integer
sequence :sequence

end
5 changes: 5 additions & 0 deletions test/models/sub_class_super_sequenced_model.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class SubClassSuperSequencedModel < FirstSequencedModel

use_superclass_sequence

end
47 changes: 47 additions & 0 deletions test/sub_class_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
require "test_helper"

class SubClassTest < BaseTest
def test_subclass_parent_sequence
parent = FirstSequencedModel.create
child = SubClassSuperSequencedModel.create

assert_equal parent.auto_increment + 1, child.auto_increment

parent2 = FirstSequencedModel.create
child2 = SubClassSuperSequencedModel.create

assert_equal parent2.auto_increment + 1, child2.auto_increment
end

def test_subclass_self_sequence
parent = FirstSequencedModel.create
child = SubClassSelfSequencedModel.create

assert_equal parent.auto_increment, 1
assert_equal child.auto_increment, nil
assert_equal child.sequence, 1

parent2 = FirstSequencedModel.create
child2 = SubClassSelfSequencedModel.create

assert_equal parent2.auto_increment, 2
assert_equal child2.auto_increment, nil
assert_equal child2.sequence, 2
end

def test_subclass_multi_sequence
parent = FirstSequencedModel.create
child = SubClassMultiSequencedModel.create

assert_equal parent.auto_increment, 1
assert_equal child.auto_increment, 2
assert_equal child.sequence, 1

parent2 = FirstSequencedModel.create
child2 = SubClassMultiSequencedModel.create

assert_equal parent2.auto_increment, 3
assert_equal child2.auto_increment, 4
assert_equal child2.sequence, 2
end
end