mongoid 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/History.txt +2 -0
- data/MIT_LICENSE +20 -0
- data/README.textile +135 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/lib/mongoid.rb +79 -0
- data/lib/mongoid/associations/association_factory.rb +21 -0
- data/lib/mongoid/associations/belongs_to_association.rb +23 -0
- data/lib/mongoid/associations/has_many_association.rb +36 -0
- data/lib/mongoid/associations/has_one_association.rb +35 -0
- data/lib/mongoid/document.rb +208 -0
- data/lib/mongoid/extensions.rb +7 -0
- data/lib/mongoid/extensions/array/conversions.rb +13 -0
- data/lib/mongoid/extensions/object/conversions.rb +13 -0
- data/lib/mongoid/paginator.rb +22 -0
- data/mongoid.gemspec +80 -0
- data/spec/integration/mongoid/document_spec.rb +95 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/unit/mongoid/associations/association_factory_spec.rb +48 -0
- data/spec/unit/mongoid/associations/belongs_to_association_spec.rb +35 -0
- data/spec/unit/mongoid/associations/has_many_association_spec.rb +126 -0
- data/spec/unit/mongoid/associations/has_one_association_spec.rb +35 -0
- data/spec/unit/mongoid/document_spec.rb +680 -0
- data/spec/unit/mongoid/extensions/array/conversions_spec.rb +14 -0
- data/spec/unit/mongoid/extensions/object/conversions_spec.rb +13 -0
- data/spec/unit/mongoid/paginator_spec.rb +74 -0
- metadata +110 -0
data/.gitignore
ADDED
data/History.txt
ADDED
data/MIT_LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Durran Jordan
|
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.
|
data/README.textile
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
<h2>Overview</h2>
|
2
|
+
|
3
|
+
<h3>About Mongoid</h3>
|
4
|
+
|
5
|
+
<p>
|
6
|
+
Mongoid is an ODM (Object-Document-Mapper) framework for MongoDB in Ruby. Mongoid differs from other
|
7
|
+
mapping frameworks in that it constrains the models into behaving in a manner appropriate for a
|
8
|
+
document database. That is to say there are no relationships between documents in the underlying datastore.
|
9
|
+
If a relationship is set up in the Model the child models are automatically embedded within the parent document
|
10
|
+
in the database. The concept of a foreign key relationship to another Document does not exist, as that is
|
11
|
+
design and thinking for a relational database, not a document database. Mongoloid does however provide
|
12
|
+
all the ActiveRecord style functionality you need, with the difference that it stores all associations
|
13
|
+
within the parent document.
|
14
|
+
</p>
|
15
|
+
|
16
|
+
<h3>Project Tracking</h3>
|
17
|
+
|
18
|
+
<a href="http://www.pivotaltracker.com/projects/27482">Mongoid on Pivotal Tracker</a>
|
19
|
+
<a href="http://groups.google.com/group/mongoid">Mongoid Google Group</a>
|
20
|
+
|
21
|
+
<h3>Compatibility</h3>
|
22
|
+
|
23
|
+
<p>
|
24
|
+
Mongoid is developed against Ruby 1.8.6, 1.8.7, 1.9.1
|
25
|
+
</p>
|
26
|
+
|
27
|
+
<h2>Mongoid in Action</h2>
|
28
|
+
|
29
|
+
Initialize Mongoid:
|
30
|
+
|
31
|
+
<pre>
|
32
|
+
Mongoid.connect_to("myapp_database_name")
|
33
|
+
</pre>
|
34
|
+
|
35
|
+
Example of a simple domain model:
|
36
|
+
|
37
|
+
<pre>
|
38
|
+
class Person < Mongoid::Document
|
39
|
+
fields :title
|
40
|
+
has_many :addresses
|
41
|
+
has_one :name
|
42
|
+
end
|
43
|
+
|
44
|
+
class Address < Mongoid::Document
|
45
|
+
fields \
|
46
|
+
:street,
|
47
|
+
:city,
|
48
|
+
:state,
|
49
|
+
:post_code
|
50
|
+
belongs_to :person
|
51
|
+
end
|
52
|
+
|
53
|
+
class Name < Mongoid::Document
|
54
|
+
fields \
|
55
|
+
:first_name,
|
56
|
+
:last_name
|
57
|
+
end
|
58
|
+
</pre>
|
59
|
+
|
60
|
+
Create a new Document:
|
61
|
+
|
62
|
+
<pre>
|
63
|
+
Person.create(:title => "Esquire")
|
64
|
+
</pre>
|
65
|
+
|
66
|
+
Save a Document:
|
67
|
+
|
68
|
+
<pre>
|
69
|
+
person.save
|
70
|
+
</pre>
|
71
|
+
|
72
|
+
Delete a Document:
|
73
|
+
|
74
|
+
<pre>
|
75
|
+
person.destroy
|
76
|
+
</pre>
|
77
|
+
|
78
|
+
Update a Document:
|
79
|
+
|
80
|
+
<pre>
|
81
|
+
person.update_attributes(:title => "Sir")
|
82
|
+
</pre>
|
83
|
+
|
84
|
+
Search for a Document in the database:
|
85
|
+
|
86
|
+
<pre>
|
87
|
+
Person.find(:all, :title => "Esquire")
|
88
|
+
|
89
|
+
Person.find(:first, :title => "Esquire")
|
90
|
+
</pre>
|
91
|
+
|
92
|
+
Paginate Document search results:
|
93
|
+
|
94
|
+
<pre>
|
95
|
+
Person.paginate(:title => "Esquire", :page => 1, :per_page => 20)
|
96
|
+
</pre>
|
97
|
+
|
98
|
+
Validations:
|
99
|
+
|
100
|
+
Mongoid supports all validations provided by Jay Fields' <tt>Validatable</tt> gem.
|
101
|
+
For more information please see the <tt>Validatable</tt> documentation.
|
102
|
+
|
103
|
+
<a href="http://validatable.rubyforge.org/">Validatable on RubyForge</a>
|
104
|
+
|
105
|
+
<h2>License</h2>
|
106
|
+
|
107
|
+
<p>
|
108
|
+
Copyright (c) 2009 Durran Jordan
|
109
|
+
</p>
|
110
|
+
<p>
|
111
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
112
|
+
a copy of this software and associated documentation files (the
|
113
|
+
"Software"), to deal in the Software without restriction, including
|
114
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
115
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
116
|
+
permit persons to whom the Software is furnished to do so, subject to
|
117
|
+
the following conditions:
|
118
|
+
</p>
|
119
|
+
<p>
|
120
|
+
The above copyright notice and this permission notice shall be
|
121
|
+
included in all copies or substantial portions of the Software.
|
122
|
+
</p>
|
123
|
+
<p>
|
124
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
125
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
126
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
127
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
128
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
129
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
130
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
131
|
+
</p>
|
132
|
+
|
133
|
+
<h2>Credits</h2>
|
134
|
+
|
135
|
+
Durran Jordan: durran at gmail dot com
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rake"
|
3
|
+
require "rake/rdoctask"
|
4
|
+
require "spec/rake/spectask"
|
5
|
+
require "metric_fu"
|
6
|
+
|
7
|
+
begin
|
8
|
+
require "jeweler"
|
9
|
+
Jeweler::Tasks.new do |gem|
|
10
|
+
gem.name = "mongoid"
|
11
|
+
gem.summary = %Q{Mongoid}
|
12
|
+
gem.email = "durran@gmail.com"
|
13
|
+
gem.homepage = "http://github.com/durran/mongoid"
|
14
|
+
gem.authors = ["Durran Jordan"]
|
15
|
+
gem.add_dependency "activesupport"
|
16
|
+
gem.add_dependency "mongodb-mongo"
|
17
|
+
end
|
18
|
+
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
21
|
+
end
|
22
|
+
|
23
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
24
|
+
spec.libs << "lib" << "spec"
|
25
|
+
spec.pattern = "spec/**/*_spec.rb"
|
26
|
+
spec.spec_opts = ['--options', "spec/spec.opts"]
|
27
|
+
end
|
28
|
+
|
29
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
30
|
+
spec.libs << "lib" << "spec"
|
31
|
+
spec.pattern = "spec/**/*_spec.rb"
|
32
|
+
spec.spec_opts = ['--options', "spec/spec.opts"]
|
33
|
+
spec.rcov = true
|
34
|
+
end
|
35
|
+
|
36
|
+
Rake::RDocTask.new do |rdoc|
|
37
|
+
if File.exist?("VERSION.yml")
|
38
|
+
config = YAML.load(File.read("VERSION.yml"))
|
39
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
40
|
+
else
|
41
|
+
version = ""
|
42
|
+
end
|
43
|
+
rdoc.rdoc_dir = "rdoc"
|
44
|
+
rdoc.title = "my_emma #{version}"
|
45
|
+
rdoc.rdoc_files.include("README*")
|
46
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
47
|
+
end
|
48
|
+
|
49
|
+
task :default => ["rcov", "metrics:all"]
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.5
|
data/lib/mongoid.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# Copyright (c) 2009 Durran Jordan
|
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
|
+
require "rubygems"
|
22
|
+
|
23
|
+
gem "activesupport", "2.3.4"
|
24
|
+
gem "mongodb-mongo", "0.14.1"
|
25
|
+
gem "durran-validatable", "1.7.5"
|
26
|
+
gem "mislav-will_paginate", "2.3.11"
|
27
|
+
|
28
|
+
require "validatable"
|
29
|
+
require "active_support/callbacks"
|
30
|
+
require "active_support/core_ext"
|
31
|
+
require "delegate"
|
32
|
+
require "will_paginate/collection"
|
33
|
+
require "mongo"
|
34
|
+
require "mongoid/associations/association_factory"
|
35
|
+
require "mongoid/associations/belongs_to_association"
|
36
|
+
require "mongoid/associations/has_many_association"
|
37
|
+
require "mongoid/associations/has_one_association"
|
38
|
+
require "mongoid/extensions/array/conversions"
|
39
|
+
require "mongoid/extensions/object/conversions"
|
40
|
+
require "mongoid/extensions"
|
41
|
+
require "mongoid/document"
|
42
|
+
require "mongoid/paginator"
|
43
|
+
|
44
|
+
module Mongoid
|
45
|
+
|
46
|
+
# Thrown when the database connection has not been set up.
|
47
|
+
class NoConnectionError < RuntimeError
|
48
|
+
end
|
49
|
+
|
50
|
+
# Thrown when :document_class is not provided in the attributes
|
51
|
+
# hash when creating a new Document
|
52
|
+
class ClassNotProvidedError < RuntimeError
|
53
|
+
end
|
54
|
+
|
55
|
+
# Thrown when an association is defined on the class, but the
|
56
|
+
# attribute in the hash is not an Array or Hash.
|
57
|
+
class TypeMismatchError < RuntimeError
|
58
|
+
end
|
59
|
+
|
60
|
+
# Thrown when an association is defined that is not valid. Must
|
61
|
+
# be belongs_to, has_many, has_one
|
62
|
+
class InvalidAssociationError < RuntimeError
|
63
|
+
end
|
64
|
+
|
65
|
+
# Connect to the database name supplied. This should be run
|
66
|
+
# for initial setup, potentially in a rails initializer.
|
67
|
+
def self.connect_to(name)
|
68
|
+
@@connection ||= Mongo::Connection.new
|
69
|
+
@@database ||= @@connection.db(name)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Get the MongoDB database. If initialization via Mongoid.connect_to()
|
73
|
+
# has not happened, an exception will occur.
|
74
|
+
def self.database
|
75
|
+
raise NoConnectionError unless @@database
|
76
|
+
@@database
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Mongoid #:nodoc:
|
2
|
+
module Associations #:nodoc:
|
3
|
+
class AssociationFactory #:nodoc:
|
4
|
+
|
5
|
+
# Creates a new association, based on the type provided and
|
6
|
+
# passes the name and document into the newly instantiated
|
7
|
+
# association.
|
8
|
+
#
|
9
|
+
# If the type is invalid a InvalidAssociationError will be thrown.
|
10
|
+
def self.create(association_type, association_name, document)
|
11
|
+
case association_type
|
12
|
+
when :belongs_to then BelongsToAssociation.new(document)
|
13
|
+
when :has_many then HasManyAssociation.new(association_name, document)
|
14
|
+
when :has_one then HasOneAssociation.new(association_name, document)
|
15
|
+
else raise InvalidAssociationError
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Mongoid #:nodoc:
|
2
|
+
module Associations #:nodoc:
|
3
|
+
class BelongsToAssociation #:nodoc:
|
4
|
+
|
5
|
+
# Creates the new association by setting the internal
|
6
|
+
# document as the passed in Document. This should be the
|
7
|
+
# parent.
|
8
|
+
#
|
9
|
+
# All method calls on this object will then be delegated
|
10
|
+
# to the internal document itself.
|
11
|
+
def initialize(document)
|
12
|
+
@document = document.parent
|
13
|
+
end
|
14
|
+
|
15
|
+
# All calls to this association will be delegated straight
|
16
|
+
# to the encapsulated document.
|
17
|
+
def method_missing(method, *args)
|
18
|
+
@document.send(method, *args)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Mongoid #:nodoc:
|
2
|
+
module Associations #:nodoc:
|
3
|
+
class HasManyAssociation < DelegateClass(Array) #:nodoc:
|
4
|
+
|
5
|
+
# Creates the new association by finding the attributes in
|
6
|
+
# the parent document with its name, and instantiating a
|
7
|
+
# new document for each one found. These will then be put in an
|
8
|
+
# internal array.
|
9
|
+
#
|
10
|
+
# This then delegated all methods to the array class since this is
|
11
|
+
# essentially a proxy to an array itself.
|
12
|
+
def initialize(association_name, document)
|
13
|
+
@klass = association_name.to_s.classify.constantize
|
14
|
+
attributes = document.attributes[association_name]
|
15
|
+
@documents = attributes ? attributes.collect do |attribute|
|
16
|
+
child = @klass.new(attribute)
|
17
|
+
child.parent = document
|
18
|
+
child
|
19
|
+
end : []
|
20
|
+
super(@documents)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Builds a new Document and adds it to the association collection. The
|
24
|
+
# document created will be of the same class as the others in the
|
25
|
+
# association, and the attributes will be passed into the constructor.
|
26
|
+
#
|
27
|
+
# Returns the newly created object.
|
28
|
+
def build(attributes)
|
29
|
+
object = @klass.new(attributes)
|
30
|
+
push(object)
|
31
|
+
object
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Mongoid #:nodoc:
|
2
|
+
module Associations #:nodoc:
|
3
|
+
class HasOneAssociation #:nodoc:
|
4
|
+
|
5
|
+
attr_reader :document
|
6
|
+
delegate :valid?, :to => :document
|
7
|
+
|
8
|
+
# Creates the new association by finding the attributes in
|
9
|
+
# the parent document with its name, and instantiating a
|
10
|
+
# new document for it.
|
11
|
+
#
|
12
|
+
# All method calls on this object will then be delegated
|
13
|
+
# to the internal document itself.
|
14
|
+
def initialize(association_name, document)
|
15
|
+
klass = association_name.to_s.titleize.constantize
|
16
|
+
attributes = document.attributes[association_name]
|
17
|
+
@document = klass.new(attributes)
|
18
|
+
@document.parent = document
|
19
|
+
decorate!
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def decorate!
|
24
|
+
@document.public_methods(false).each do |method|
|
25
|
+
(class << self; self; end).class_eval do
|
26
|
+
define_method method do |*args|
|
27
|
+
@document.send method, *args
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
module Mongoid #:nodoc:
|
2
|
+
class Document #:nodoc:
|
3
|
+
include ActiveSupport::Callbacks
|
4
|
+
include Validatable
|
5
|
+
|
6
|
+
AGGREGATE_REDUCE = "function(obj, prev) { prev.count++; }"
|
7
|
+
GROUP_BY_REDUCE = "function(obj, prev) { prev.group.push(obj); }"
|
8
|
+
|
9
|
+
attr_reader :attributes, :parent
|
10
|
+
|
11
|
+
define_callbacks \
|
12
|
+
:after_create,
|
13
|
+
:after_save,
|
14
|
+
:before_create,
|
15
|
+
:before_save
|
16
|
+
|
17
|
+
class << self
|
18
|
+
|
19
|
+
# Get an aggregate count for the supplied group of fields and the
|
20
|
+
# selector that is provided.
|
21
|
+
def aggregate(fields, selector)
|
22
|
+
collection.group(fields, selector, { :count => 0 }, AGGREGATE_REDUCE)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Create an association to a parent Document.
|
26
|
+
def belongs_to(association_name)
|
27
|
+
add_association(:belongs_to, association_name.to_s.classify, association_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Get the Mongo::Collection associated with this Document.
|
31
|
+
def collection
|
32
|
+
@collection_name = self.to_s.demodulize.tableize
|
33
|
+
@collection ||= Mongoid.database.collection(@collection_name)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Create a new Document with the supplied attribtues, and insert it into the database.
|
37
|
+
def create(attributes = {})
|
38
|
+
new(attributes).save
|
39
|
+
end
|
40
|
+
|
41
|
+
# Defines all the fields that are accessable on the Document
|
42
|
+
# For each field that is defined, a getter and setter will be
|
43
|
+
# added as an instance method to the Document.
|
44
|
+
def fields(*names)
|
45
|
+
@fields = []
|
46
|
+
names.flatten.each do |name|
|
47
|
+
@fields << name
|
48
|
+
define_method(name) { read_attribute(name) }
|
49
|
+
define_method("#{name}=") { |value| write_attribute(name, value) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Find all Documents in several ways.
|
54
|
+
# Model.find(:first, :attribute => "value")
|
55
|
+
# Model.find(:all, :attribute => "value")
|
56
|
+
def find(*args)
|
57
|
+
type, selector = args[0], args[1]
|
58
|
+
case type
|
59
|
+
when :all then find_all(selector[:conditions])
|
60
|
+
when :first then find_first(selector[:conditions])
|
61
|
+
else find_first(Mongo::ObjectID.from_string(type.to_s))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Find a single Document given the passed selector, which is a Hash of attributes that
|
66
|
+
# must match the Document in the database exactly.
|
67
|
+
def find_first(selector = nil)
|
68
|
+
new(collection.find_one(selector))
|
69
|
+
end
|
70
|
+
|
71
|
+
# Find all Documents given the passed selector, which is a Hash of attributes that
|
72
|
+
# must match the Document in the database exactly.
|
73
|
+
def find_all(selector = nil)
|
74
|
+
collection.find(selector).collect { |doc| new(doc) }
|
75
|
+
end
|
76
|
+
|
77
|
+
# Find all Documents given the supplied criteria, grouped by the fields
|
78
|
+
# provided.
|
79
|
+
def group_by(fields, selector)
|
80
|
+
collection.group(fields, selector, { :group => [] }, GROUP_BY_REDUCE).collect do |docs|
|
81
|
+
group!(docs)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Create a one-to-many association between Documents.
|
86
|
+
def has_many(association_name)
|
87
|
+
add_association(:has_many, association_name.to_s.classify, association_name)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Create a one-to-many association between Documents.
|
91
|
+
def has_one(association_name)
|
92
|
+
add_association(:has_one, association_name.to_s.titleize, association_name)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Adds an index on the field specified. Options can be :unique => true or
|
96
|
+
# :unique => false. It will default to the latter.
|
97
|
+
def index(name, options = { :unique => false })
|
98
|
+
collection.create_index(name, options)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Find all documents in paginated fashion given the supplied arguments.
|
102
|
+
# If no parameters are passed just default to offset 0 and limit 20.
|
103
|
+
def paginate(selector = {}, params = {})
|
104
|
+
WillPaginate::Collection.create(
|
105
|
+
params[:page] || 1,
|
106
|
+
params[:per_page] || 20,
|
107
|
+
0) do |pager|
|
108
|
+
results = collection.find(selector[:conditions], { :limit => pager.per_page, :offset => pager.offset })
|
109
|
+
pager.total_entries = results.count
|
110
|
+
pager.replace(results.collect { |doc| new(doc) })
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
# Get the Mongo::Collection associated with this Document.
|
117
|
+
def collection
|
118
|
+
self.class.collection
|
119
|
+
end
|
120
|
+
|
121
|
+
# Delete this Document from the database.
|
122
|
+
def destroy
|
123
|
+
collection.remove(:_id => id)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Get the Mongo::ObjectID associated with this object.
|
127
|
+
# This is in essence the primary key.
|
128
|
+
def id
|
129
|
+
@attributes[:_id]
|
130
|
+
end
|
131
|
+
|
132
|
+
# Instantiate a new Document, setting the Document's attirbutes if given.
|
133
|
+
# If no attributes are provided, they will be initialized with an empty Hash.
|
134
|
+
def initialize(attributes = {})
|
135
|
+
@attributes = attributes.symbolize_keys if attributes
|
136
|
+
@attributes = {} unless attributes
|
137
|
+
end
|
138
|
+
|
139
|
+
# Returns true is the Document has not been persisted to the database, false if it has.
|
140
|
+
def new_record?
|
141
|
+
@attributes[:_id].nil?
|
142
|
+
end
|
143
|
+
|
144
|
+
# Set the parent to this document.
|
145
|
+
def parent=(document)
|
146
|
+
@parent = document
|
147
|
+
end
|
148
|
+
|
149
|
+
# Save this document to the database. If this document is the root document
|
150
|
+
# in the object graph, it will save itself, and return self. If the
|
151
|
+
# document is embedded within another document, or is multiple levels down
|
152
|
+
# the tree, the root object will get saved, and return itself.
|
153
|
+
def save
|
154
|
+
if @parent
|
155
|
+
@parent.save
|
156
|
+
else
|
157
|
+
run_callbacks(:before_save)
|
158
|
+
collection.save(@attributes)
|
159
|
+
run_callbacks(:after_save)
|
160
|
+
return self
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Returns the id of the Document
|
165
|
+
def to_param
|
166
|
+
id.to_s
|
167
|
+
end
|
168
|
+
|
169
|
+
# Update the attributes of this Document and return true
|
170
|
+
def update_attributes(attributes)
|
171
|
+
@attributes = attributes.symbolize_keys!; save; true
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
|
176
|
+
class << self
|
177
|
+
|
178
|
+
# Adds the association to the associations hash with the type as the key,
|
179
|
+
# then adds the accessors for the association.
|
180
|
+
def add_association(type, class_name, name)
|
181
|
+
define_method(name) do
|
182
|
+
Mongoid::Associations::AssociationFactory.create(type, name, self)
|
183
|
+
end
|
184
|
+
define_method("#{name}=") do |object|
|
185
|
+
@attributes[name] = object.mongoidize
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Takes the supplied raw grouping of documents and alters it to a
|
190
|
+
# grouping of actual document objects.
|
191
|
+
def group!(docs)
|
192
|
+
docs["group"] = docs["group"].collect { |attrs| new(attrs) }; docs
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
# Read from the attributes hash.
|
198
|
+
def read_attribute(name)
|
199
|
+
@attributes[name.to_sym]
|
200
|
+
end
|
201
|
+
|
202
|
+
# Write to the attributes hash.
|
203
|
+
def write_attribute(name, value)
|
204
|
+
@attributes[name.to_sym] = value
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
end
|