├── .gitignore ├── CHANGELOG.rdoc ├── Gemfile ├── LICENSE ├── README.rdoc ├── Rakefile ├── lib ├── mongoid_auto_inc.rb └── mongoid_auto_inc │ ├── incrementor.rb │ └── version.rb ├── mongoid_auto_inc.gemspec └── spec └── mongoid_auto_inc_spec.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | .bundle 3 | Gemfile.lock 4 | pkg/* 5 | .rvmrc 6 | *.swp 7 | -------------------------------------------------------------------------------- /CHANGELOG.rdoc: -------------------------------------------------------------------------------- 1 | = Changelog 2 | 3 | Per release changes to mongoid_auto_inc 4 | 5 | == 0.1.0 (2012 March 21) 6 | * Initial stable release. 7 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gem 'activesupport', '>= 3.0.0' 4 | 5 | group :development do 6 | gem 'rspec', '>= 2.0.0.beta.22' 7 | # moving mongoid to be a development dependency 8 | # having it as a gem dependency may cause issues, change the version here to test 9 | gem 'mongoid', '>= 2.4.10' 10 | # to test Mongoid 3 11 | # gem 'mongoid', git: 'git://github.com/mongoid/mongoid.git' 12 | end 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Jeff Smith 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = mongoid_auto_inc 2 | Add SQL like auto-incrementing fields to your Mongoid documents. 3 | 4 | This gem is inspired by http://ihswebdesign.com/blog/autoincrement-in-mongodb-with-ruby/ and the mongomapper_id2[https://github.com/phstc/mongomapper_id2] gem. 5 | == Install 6 | In your Gemfile: 7 | gem 'mongoid_auto_inc' 8 | Followed by running bundle install, or do: 9 | gem install mongoid_auto_inc 10 | == Usage 11 | Just add auto_increment :field to your Mongoid model where :field is the name of the auto-incremented field you want to create. 12 | Example: 13 | class Book 14 | include Mongoid::Document 15 | 16 | field :title 17 | field :author 18 | 19 | auto_increment :sequence 20 | end 21 | auto_increment :sequence will create a field of type Integer named sequence for Book. Whenever an instance of the model is created (intially saved to mongoDB), the auto_increment field will automatically be set to the next number in the sequence. 22 | 23 | You can add more than one auto-incremented field per model. 24 | === Options 25 | auto_increment :sequence, :collection => :some_collection 26 | mongoid_auto_inc keeps track of the current number in the sequence by creating a separate document mongoDB to query and update. By default auto_increment will save this document to a mongoDB collection called sequences. If you wish to save to a different collection use the :collection option to specify its name. 27 | 28 | auto_increment :sequence, :seed => 3333 29 | Use the :seed option to set the initial value of the auto-incremented field. The first number assigned from the sequence will be the next number after the seed value. 30 | 31 | == Contributors 32 | Thanks to these folk for their help: 33 | * davemitchell[https://github.com/davemitchell] 34 | * meltedice[https://github.com/meltedice] 35 | * fedegl[https://github.com/fedegl] -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler' 2 | Bundler::GemHelper.install_tasks 3 | -------------------------------------------------------------------------------- /lib/mongoid_auto_inc.rb: -------------------------------------------------------------------------------- 1 | require "mongoid" 2 | require "mongoid_auto_inc/incrementor" 3 | 4 | module MongoidAutoInc 5 | extend ActiveSupport::Concern 6 | 7 | module ClassMethods 8 | def auto_increment(name, options={}) 9 | field name, :type => Integer 10 | seq_name = "#{self.name.downcase}_#{name}" 11 | incrementor = MongoidAutoInc::Incrementor.new(options) 12 | 13 | before_create { self.send("#{name}=", incrementor[seq_name].inc) unless self[name.to_sym].present? } 14 | end 15 | end 16 | end 17 | 18 | module Mongoid 19 | module Document 20 | include MongoidAutoInc 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/mongoid_auto_inc/incrementor.rb: -------------------------------------------------------------------------------- 1 | # This is a modified version of the code found on this blog post: 2 | # http://ihswebdesign.com/blog/autoincrement-in-mongodb-with-ruby/ 3 | module MongoidAutoInc 4 | class Incrementor 5 | class Sequence 6 | def initialize(sequence, collection_name, seed) 7 | @sequence = sequence.to_s 8 | @collection = collection_name.to_s 9 | exists? || create(seed) 10 | end 11 | 12 | def inc 13 | update_number_with("$inc" => { "number" => 1 }) 14 | end 15 | 16 | def set(number) 17 | update_number_with("$set" => { "number" => number }) 18 | end 19 | 20 | private 21 | 22 | def exists? 23 | collection.find(query).count > 0 24 | end 25 | 26 | def create(number = 0) 27 | collection.insert(query.merge({ "number" => number })) 28 | end 29 | 30 | def collection 31 | if ::Mongoid::VERSION < '3' 32 | Mongoid.database[@collection] 33 | else 34 | Mongoid.default_session[@collection] 35 | end 36 | end 37 | 38 | def query 39 | { "seq_name" => @sequence } 40 | end 41 | 42 | def current 43 | if ::Mongoid::VERSION < '3' 44 | collection.find_one(query)["number"] 45 | else 46 | collection.find(query).one['number'] 47 | end 48 | end 49 | 50 | def update_number_with(mongo_func) 51 | opts = { 52 | "query" => query, 53 | "update" => mongo_func, 54 | "new" => true # return the modified document 55 | } 56 | if ::Mongoid::VERSION < '3' 57 | collection.find_and_modify(opts)["number"] 58 | else 59 | collection.database.command({ 60 | findandmodify: collection.name 61 | }.merge(opts))['value']['number'] 62 | end 63 | end 64 | end 65 | 66 | def initialize(options=nil) 67 | options ||= {} 68 | @collection = options[:collection] || "sequences" 69 | @seed = options[:seed].to_i 70 | end 71 | 72 | def [](sequence) 73 | Sequence.new(sequence, @collection, @seed) 74 | end 75 | 76 | def []=(sequence, number) 77 | Sequence.new(sequence, @collection, @seed).set(number) 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /lib/mongoid_auto_inc/version.rb: -------------------------------------------------------------------------------- 1 | module MongoidAutoInc 2 | VERSION = "0.1.0" 3 | end 4 | -------------------------------------------------------------------------------- /mongoid_auto_inc.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "mongoid_auto_inc/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "mongoid_auto_inc" 7 | s.version = MongoidAutoInc::VERSION 8 | s.platform = Gem::Platform::RUBY 9 | s.authors = ["Jeff Smith"] 10 | s.email = ["jffreyjs@gmail.com"] 11 | s.homepage = "https://github.com/jffjs/mongoid_auto_inc" 12 | s.summary = %q{Adds auto increment capabilities to Mongoid::Document} 13 | s.description = %q{Adds auto increment capabilities to Mongoid::Document} 14 | 15 | s.rubyforge_project = "mongoid_auto_inc" 16 | 17 | s.files = `git ls-files`.split("\n") 18 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 19 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 20 | s.require_paths = ["lib"] 21 | 22 | s.required_ruby_version = '>= 1.8.6' 23 | s.required_rubygems_version = '>= 1.3.5' 24 | s.add_bundler_dependencies 25 | end 26 | -------------------------------------------------------------------------------- /spec/mongoid_auto_inc_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # rspec spec/mongoid_auto_inc_spec.rb 3 | require 'bundler/setup' 4 | Bundler.require(:default, :development) 5 | require 'mongoid_auto_inc' 6 | 7 | describe MongoidAutoInc do 8 | before(:all) do 9 | Mongoid.master = Mongo::Connection.new.db("mongoid_auto_inc_test") 10 | end 11 | 12 | describe "auto increment" do 13 | before(:all) do 14 | class DocumentA 15 | include Mongoid::Document 16 | auto_increment :seq 17 | end 18 | end 19 | 20 | before(:each) do 21 | Mongoid.database["sequences"].remove 22 | end 23 | 24 | it "should be nil" do 25 | DocumentA.new.seq.should be_nil 26 | end 27 | 28 | it "should be 1" do 29 | DocumentA.create!.seq.should == 1 30 | end 31 | 32 | it "should be 2" do 33 | DocumentA.create! 34 | DocumentA.create!.seq.should == 2 35 | end 36 | 37 | it "should not auto increment when value is provided" do 38 | doc = DocumentA.create!(seq: 33) 39 | doc.seq.should == 33 40 | end 41 | end 42 | 43 | describe "auto increment with :collection option" do 44 | before(:all) do 45 | class DocumentB 46 | include Mongoid::Document 47 | auto_increment :seq, :collection => 'other_sequences' 48 | end 49 | end 50 | 51 | before(:each) do 52 | Mongoid.database["sequences"].remove 53 | Mongoid.database["other_sequences"].remove 54 | end 55 | 56 | it "should store sequence data to other_sequences collection" do 57 | DocumentB.create!.seq.should == 1 58 | DocumentB.create!.seq.should == 2 59 | Mongoid.database["sequences"].remove 60 | DocumentB.create!.seq.should == 3 61 | Mongoid.database["other_sequences"].remove 62 | DocumentB.create!.seq.should == 1 63 | end 64 | end 65 | 66 | describe "auto increment with :seed option" do 67 | before(:all) do 68 | class DocumentC 69 | include Mongoid::Document 70 | auto_increment :seq, :seed => 10 71 | end 72 | class DocumentD 73 | include Mongoid::Document 74 | auto_increment :seq 75 | end 76 | end 77 | 78 | before(:each) do 79 | Mongoid.database["sequences"].remove 80 | end 81 | 82 | it "should start with 11 (10 + 1)" do 83 | DocumentC.create!.seq.should == 11 84 | DocumentC.create!.seq.should == 12 85 | DocumentC.create!.seq.should == 13 86 | DocumentD.create!.seq.should == 1 87 | DocumentD.create!.seq.should == 2 88 | end 89 | end 90 | end 91 | --------------------------------------------------------------------------------