mongoid 1.1.4 → 1.2.0
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/HISTORY +69 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/mongoid.rb +39 -13
- data/lib/mongoid/associations.rb +1 -0
- data/lib/mongoid/associations/has_many.rb +19 -3
- data/lib/mongoid/attributes.rb +6 -1
- data/lib/mongoid/collection.rb +106 -0
- data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
- data/lib/mongoid/collections/master.rb +28 -0
- data/lib/mongoid/collections/mimic.rb +46 -0
- data/lib/mongoid/collections/operations.rb +39 -0
- data/lib/mongoid/collections/slaves.rb +44 -0
- data/lib/mongoid/commands.rb +1 -0
- data/lib/mongoid/config.rb +61 -9
- data/lib/mongoid/contexts/enumerable.rb +24 -15
- data/lib/mongoid/contexts/mongo.rb +25 -31
- data/lib/mongoid/contexts/paging.rb +2 -2
- data/lib/mongoid/criteria.rb +48 -7
- data/lib/mongoid/criterion/exclusion.rb +2 -0
- data/lib/mongoid/criterion/optional.rb +2 -2
- data/lib/mongoid/cursor.rb +82 -0
- data/lib/mongoid/document.rb +12 -13
- data/lib/mongoid/errors.rb +35 -4
- data/lib/mongoid/extensions.rb +1 -0
- data/lib/mongoid/extensions/array/aliasing.rb +4 -0
- data/lib/mongoid/extensions/string/inflections.rb +44 -1
- data/lib/mongoid/factory.rb +17 -0
- data/lib/mongoid/finders.rb +7 -2
- data/lib/mongoid/matchers/default.rb +6 -0
- data/lib/mongoid/matchers/gt.rb +1 -1
- data/lib/mongoid/matchers/gte.rb +1 -1
- data/lib/mongoid/matchers/lt.rb +1 -1
- data/lib/mongoid/matchers/lte.rb +1 -1
- data/mongoid.gemspec +30 -5
- data/perf/benchmark.rb +5 -3
- data/spec/integration/mongoid/associations_spec.rb +12 -0
- data/spec/integration/mongoid/contexts/enumerable_spec.rb +20 -0
- data/spec/integration/mongoid/criteria_spec.rb +28 -0
- data/spec/integration/mongoid/document_spec.rb +1 -1
- data/spec/integration/mongoid/inheritance_spec.rb +2 -2
- data/spec/models/person.rb +1 -1
- data/spec/spec_helper.rb +9 -4
- data/spec/unit/mongoid/associations/has_many_spec.rb +19 -0
- data/spec/unit/mongoid/associations_spec.rb +9 -0
- data/spec/unit/mongoid/attributes_spec.rb +4 -4
- data/spec/unit/mongoid/collection_spec.rb +113 -0
- data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
- data/spec/unit/mongoid/collections/master_spec.rb +41 -0
- data/spec/unit/mongoid/collections/mimic_spec.rb +43 -0
- data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
- data/spec/unit/mongoid/commands_spec.rb +7 -0
- data/spec/unit/mongoid/config_spec.rb +52 -1
- data/spec/unit/mongoid/contexts/enumerable_spec.rb +38 -12
- data/spec/unit/mongoid/contexts/mongo_spec.rb +38 -31
- data/spec/unit/mongoid/criteria_spec.rb +20 -12
- data/spec/unit/mongoid/criterion/exclusion_spec.rb +26 -0
- data/spec/unit/mongoid/criterion/optional_spec.rb +13 -0
- data/spec/unit/mongoid/cursor_spec.rb +74 -0
- data/spec/unit/mongoid/document_spec.rb +4 -5
- data/spec/unit/mongoid/errors_spec.rb +5 -9
- data/spec/unit/mongoid/extensions/string/inflections_spec.rb +21 -2
- data/spec/unit/mongoid/factory_spec.rb +16 -0
- data/spec/unit/mongoid_spec.rb +4 -4
- metadata +28 -3
data/HISTORY
CHANGED
@@ -1,4 +1,72 @@
|
|
1
|
-
=== 1.0
|
1
|
+
=== 1.2.0
|
2
|
+
- Fixed composite key generation not to replace all
|
3
|
+
special chars with dashes.
|
4
|
+
|
5
|
+
- Memory optimizations, now wrapping the mongo cursor.
|
6
|
+
|
7
|
+
- Fixed memoization on has_many_related assocations.
|
8
|
+
|
9
|
+
- Fixed pagination on embedded associations
|
10
|
+
|
11
|
+
- Fixed after_update callback not getting fired.
|
12
|
+
|
13
|
+
- When a connection failure occurs, Mongoid tried to
|
14
|
+
retry the operation up to a configurable time.
|
15
|
+
|
16
|
+
- Mongoid now supports a configuration with a master
|
17
|
+
and multiple read slaves. It will direct all writes
|
18
|
+
to the master and all reads to the slaves. In the case
|
19
|
+
of a write, subsequent reads will be directed to the
|
20
|
+
master up to configurable number to try and counter
|
21
|
+
the 2 second slave sync delay.
|
22
|
+
|
23
|
+
- Fixed issue with criteria exclusion queries with ids.
|
24
|
+
|
25
|
+
- Mongoid only executes a count when explicitly paginating.
|
26
|
+
|
27
|
+
- Fixed Criteria offset to be a getter or setter
|
28
|
+
|
29
|
+
- Added indexes to foreign keys on belongs_to_related
|
30
|
+
associations.
|
31
|
+
|
32
|
+
- General code refactorings/cleanup
|
33
|
+
|
34
|
+
=== 1.1.4
|
35
|
+
- Refactorings in preparation for next feature push.
|
36
|
+
|
37
|
+
- Associations may now have anonymous extensions.
|
38
|
+
|
39
|
+
- Ruby 1.9 compatibility updates. (brainopia)
|
40
|
+
|
41
|
+
- Document.to_json accepts options. (jsmestad)
|
42
|
+
|
43
|
+
=== 1.1.3
|
44
|
+
- Nil can be passed into methods that set attributes.
|
45
|
+
|
46
|
+
- Mongoid.config can now take a block.
|
47
|
+
|
48
|
+
- Allow named_scopes and criteria class methods on
|
49
|
+
has_many_related if related is a Mongoid document.
|
50
|
+
|
51
|
+
- Document.find can now take an array of ids.
|
52
|
+
|
53
|
+
=== 1.1.2
|
54
|
+
- Fixing issues with updates to parents.
|
55
|
+
|
56
|
+
=== 1.1.1
|
57
|
+
- Document.create raises validations error, not no
|
58
|
+
method error on self.errors (Rick Frankel)
|
59
|
+
|
60
|
+
- Support default values that respond_to?(:call)
|
61
|
+
(procs/lambda) (ahoward)
|
62
|
+
|
63
|
+
- Added Mongoid.persist_in_safe_mode global config
|
64
|
+
option.
|
65
|
+
|
66
|
+
- Minor optimization: don't evaluate default procs
|
67
|
+
if it's not needed (brainopia)
|
68
|
+
|
69
|
+
=== 1.1.0
|
2
70
|
- Nil attributes no longer persist nil values to the
|
3
71
|
database - the field will just not exist.
|
4
72
|
|
data/Rakefile
CHANGED
@@ -15,7 +15,7 @@ begin
|
|
15
15
|
gem.add_dependency("activesupport", "<= 2.3.5")
|
16
16
|
gem.add_dependency("mongo", ">= 0.18.2")
|
17
17
|
gem.add_dependency("durran-validatable", ">= 2.0.1")
|
18
|
-
gem.add_dependency("
|
18
|
+
gem.add_dependency("will_paginate", ">= 2.3.11")
|
19
19
|
|
20
20
|
gem.add_development_dependency("rspec", ">= 1.2.9")
|
21
21
|
gem.add_development_dependency("mocha", ">= 0.9.8")
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.0
|
data/lib/mongoid.rb
CHANGED
@@ -24,7 +24,7 @@ require "rubygems"
|
|
24
24
|
gem "activesupport", ">= 2.2.2", "<3.0.pre"
|
25
25
|
gem "mongo", ">= 0.18.2"
|
26
26
|
gem "durran-validatable", ">= 2.0.1"
|
27
|
-
gem "
|
27
|
+
gem "will_paginate", ">= 2.3.11"
|
28
28
|
|
29
29
|
require "delegate"
|
30
30
|
require "observer"
|
@@ -41,12 +41,15 @@ require "mongoid/associations"
|
|
41
41
|
require "mongoid/associations/options"
|
42
42
|
require "mongoid/attributes"
|
43
43
|
require "mongoid/callbacks"
|
44
|
+
require "mongoid/collection"
|
44
45
|
require "mongoid/commands"
|
45
46
|
require "mongoid/config"
|
46
47
|
require "mongoid/contexts"
|
47
48
|
require "mongoid/criteria"
|
49
|
+
require "mongoid/cursor"
|
48
50
|
require "mongoid/extensions"
|
49
51
|
require "mongoid/errors"
|
52
|
+
require "mongoid/factory"
|
50
53
|
require "mongoid/field"
|
51
54
|
require "mongoid/fields"
|
52
55
|
require "mongoid/finders"
|
@@ -65,20 +68,43 @@ module Mongoid #:nodoc
|
|
65
68
|
|
66
69
|
class << self
|
67
70
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
71
|
+
# Sets the Mongoid configuration options. Best used by passing a block.
|
72
|
+
#
|
73
|
+
# Example:
|
74
|
+
#
|
75
|
+
# Mongoid.configure do |config|
|
76
|
+
# name = "mongoid_test"
|
77
|
+
# host = "localhost"
|
78
|
+
# config.allow_dynamic_fields = false
|
79
|
+
# config.master = Mongo::Connection.new.db(name)
|
80
|
+
# config.slaves = [
|
81
|
+
# Mongo::Connection.new(host, 27018, :slave_ok => true).db(name),
|
82
|
+
# Mongo::Connection.new(host, 27019, :slave_ok => true).db(name)
|
83
|
+
# ]
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# Returns:
|
87
|
+
#
|
88
|
+
# The Mongoid +Config+ singleton instance.
|
89
|
+
def configure
|
90
|
+
config = Config.instance
|
91
|
+
block_given? ? yield(config) : config
|
80
92
|
end
|
81
93
|
|
94
|
+
alias :config :configure
|
82
95
|
end
|
83
96
|
|
97
|
+
# Take all the public instance methods from the Config singleton and allow
|
98
|
+
# them to be accessed through the Mongoid module directly.
|
99
|
+
#
|
100
|
+
# Example:
|
101
|
+
#
|
102
|
+
# <tt>Mongoid.database = Mongo::Connection.new.db("test")</tt>
|
103
|
+
Config.public_instance_methods(false).each do |name|
|
104
|
+
(class << self; self; end).class_eval <<-EOT
|
105
|
+
def #{name}(*args)
|
106
|
+
configure.send("#{name}", *args)
|
107
|
+
end
|
108
|
+
EOT
|
109
|
+
end
|
84
110
|
end
|
data/lib/mongoid/associations.rb
CHANGED
@@ -97,9 +97,9 @@ module Mongoid #:nodoc:
|
|
97
97
|
# If the method exists on the array, use the default proxy behavior.
|
98
98
|
def method_missing(name, *args, &block)
|
99
99
|
unless @target.respond_to?(name)
|
100
|
-
|
101
|
-
|
102
|
-
return
|
100
|
+
object = @klass.send(name, *args)
|
101
|
+
object.documents = @target
|
102
|
+
return object
|
103
103
|
end
|
104
104
|
super
|
105
105
|
end
|
@@ -120,6 +120,22 @@ module Mongoid #:nodoc:
|
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
|
+
# Paginate the association. Will create a new criteria, set the documents
|
124
|
+
# on it and execute in an enumerable context.
|
125
|
+
#
|
126
|
+
# Options:
|
127
|
+
#
|
128
|
+
# options: A +Hash+ of pagination options.
|
129
|
+
#
|
130
|
+
# Returns:
|
131
|
+
#
|
132
|
+
# A +WillPaginate::Collection+.
|
133
|
+
def paginate(options)
|
134
|
+
criteria = Mongoid::Criteria.translate(@klass, options)
|
135
|
+
criteria.documents = @target
|
136
|
+
criteria.paginate
|
137
|
+
end
|
138
|
+
|
123
139
|
protected
|
124
140
|
# Initializes each of the attributes in the hash.
|
125
141
|
def initialize_each(attributes)
|
data/lib/mongoid/attributes.rb
CHANGED
@@ -40,7 +40,7 @@ module Mongoid #:nodoc:
|
|
40
40
|
# put into the document's attributes.
|
41
41
|
def process(attrs = nil)
|
42
42
|
(attrs || {}).each_pair do |key, value|
|
43
|
-
if
|
43
|
+
if set_allowed?(key)
|
44
44
|
@attributes[key.to_s] = value
|
45
45
|
else
|
46
46
|
send("#{key}=", value) if value
|
@@ -131,6 +131,11 @@ module Mongoid #:nodoc:
|
|
131
131
|
end
|
132
132
|
|
133
133
|
protected
|
134
|
+
# Return true is dynamic field setting is enabled.
|
135
|
+
def set_allowed?(key)
|
136
|
+
Mongoid.allow_dynamic_fields && !respond_to?("#{key}=")
|
137
|
+
end
|
138
|
+
|
134
139
|
# Used when supplying a :reject_if block as an option to
|
135
140
|
# accepts_nested_attributes_for
|
136
141
|
def reject(attributes, options)
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "mongoid/collections/operations"
|
3
|
+
require "mongoid/collections/cyclic_iterator"
|
4
|
+
require "mongoid/collections/mimic"
|
5
|
+
require "mongoid/collections/master"
|
6
|
+
require "mongoid/collections/slaves"
|
7
|
+
|
8
|
+
module Mongoid #:nodoc
|
9
|
+
class Collection
|
10
|
+
include Collections::Mimic
|
11
|
+
attr_reader :counter, :name
|
12
|
+
|
13
|
+
# All write operations should delegate to the master connection. These
|
14
|
+
# operations mimic the methods on a Mongo:Collection.
|
15
|
+
#
|
16
|
+
# Example:
|
17
|
+
#
|
18
|
+
# <tt>collection.save({ :name => "Al" })</tt>
|
19
|
+
proxy(:master, Collections::Operations::WRITE)
|
20
|
+
|
21
|
+
# All read operations should be intelligently directed to either the master
|
22
|
+
# or the slave, depending on where the read counter is and what it's
|
23
|
+
# maximum was configured at.
|
24
|
+
#
|
25
|
+
# Example:
|
26
|
+
#
|
27
|
+
# <tt>collection.find({ :name => "Al" })</tt>
|
28
|
+
proxy(:directed, (Collections::Operations::READ - [:find]))
|
29
|
+
|
30
|
+
# Determines where to send the next read query. If the slaves are not
|
31
|
+
# defined then send to master. If the read counter is under the configured
|
32
|
+
# maximum then return the master. In any other case return the slaves.
|
33
|
+
#
|
34
|
+
# Example:
|
35
|
+
#
|
36
|
+
# <tt>collection.directed</tt>
|
37
|
+
#
|
38
|
+
# Return:
|
39
|
+
#
|
40
|
+
# Either a +Master+ or +Slaves+ collection.
|
41
|
+
def directed
|
42
|
+
if under_max_counter? || slaves.empty?
|
43
|
+
@counter = @counter + 1
|
44
|
+
master
|
45
|
+
else
|
46
|
+
@counter = 0
|
47
|
+
slaves
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Find documents from the database given a selector and options.
|
52
|
+
#
|
53
|
+
# Options:
|
54
|
+
#
|
55
|
+
# selector: A +Hash+ selector that is the query.
|
56
|
+
# options: The options to pass to the db.
|
57
|
+
#
|
58
|
+
# Example:
|
59
|
+
#
|
60
|
+
# <tt>collection.find({ :test => "value" })</tt>
|
61
|
+
def find(selector = {}, options = {})
|
62
|
+
cursor = Mongoid::Cursor.new(self, directed.find(selector, options))
|
63
|
+
if block_given?
|
64
|
+
yield cursor; cursor.close
|
65
|
+
else
|
66
|
+
cursor
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Initialize a new Mongoid::Collection, setting up the master, slave, and
|
71
|
+
# name attributes. Masters will be used for writes, slaves for reads.
|
72
|
+
#
|
73
|
+
# Example:
|
74
|
+
#
|
75
|
+
# <tt>Mongoid::Collection.new(masters, slaves, "test")</tt>
|
76
|
+
def initialize(name)
|
77
|
+
@name, @counter = name, 0
|
78
|
+
end
|
79
|
+
|
80
|
+
# Return the object responsible for reading documents from the database.
|
81
|
+
# This is usually the slave databases, but in their absence the master will
|
82
|
+
# handle the task.
|
83
|
+
#
|
84
|
+
# Example:
|
85
|
+
#
|
86
|
+
# <tt>collection.reader</tt>
|
87
|
+
def slaves
|
88
|
+
@slaves ||= Collections::Slaves.new(Mongoid.slaves, @name)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Return the object responsible for writes to the database. This will
|
92
|
+
# always return a collection associated with the Master DB.
|
93
|
+
#
|
94
|
+
# Example:
|
95
|
+
#
|
96
|
+
# <tt>collection.writer</tt>
|
97
|
+
def master
|
98
|
+
@master ||= Collections::Master.new(Mongoid.master, @name)
|
99
|
+
end
|
100
|
+
|
101
|
+
protected
|
102
|
+
def under_max_counter?
|
103
|
+
@counter < Mongoid.max_successive_reads
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Collections #:nodoc:
|
4
|
+
class CyclicIterator
|
5
|
+
|
6
|
+
attr_reader :counter
|
7
|
+
|
8
|
+
# Performs iteration over an array, if the array gets to the end then loop
|
9
|
+
# back to the first.
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
#
|
13
|
+
# <tt>CyclicIterator.new([ first, second ])</tt>
|
14
|
+
def initialize(array)
|
15
|
+
@array, @counter = array, -1
|
16
|
+
end
|
17
|
+
|
18
|
+
# Get the next element in the array. If the element is the last in the
|
19
|
+
# array then return the first.
|
20
|
+
#
|
21
|
+
# Example:
|
22
|
+
#
|
23
|
+
# <tt>iterator.next</tt>
|
24
|
+
#
|
25
|
+
# Returns:
|
26
|
+
#
|
27
|
+
# The next element in the array.
|
28
|
+
def next
|
29
|
+
(@counter == @array.size - 1) ? @counter = 0 : @counter = @counter + 1
|
30
|
+
@array[@counter]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Collections #:nodoc:
|
4
|
+
class Master
|
5
|
+
include Mimic
|
6
|
+
|
7
|
+
attr_reader :collection
|
8
|
+
|
9
|
+
# All read and write operations should delegate to the master connection.
|
10
|
+
# These operations mimic the methods on a Mongo:Collection.
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
#
|
14
|
+
# <tt>collection.save({ :name => "Al" })</tt>
|
15
|
+
proxy(:collection, Operations::ALL)
|
16
|
+
|
17
|
+
# Create the new database writer. Will create a collection from the
|
18
|
+
# master database.
|
19
|
+
#
|
20
|
+
# Example:
|
21
|
+
#
|
22
|
+
# <tt>Master.new(master, "mongoid_people")</tt>
|
23
|
+
def initialize(master, name)
|
24
|
+
@collection = master.collection(name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid #:nodoc:
|
3
|
+
module Collections #:nodoc:
|
4
|
+
module Mimic #:nodoc:
|
5
|
+
def self.included(base)
|
6
|
+
base.class_eval do
|
7
|
+
include InstanceMethods
|
8
|
+
extend ClassMethods
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module InstanceMethods #:nodoc:
|
13
|
+
# Retry the supplied operation until the reconnect time has expired,
|
14
|
+
# defined in the mongoid Config module.
|
15
|
+
#
|
16
|
+
# Example:
|
17
|
+
#
|
18
|
+
# <tt>master.attempt(operation)</tt>
|
19
|
+
def attempt(operation, start)
|
20
|
+
begin
|
21
|
+
elapsed = (Time.now - start)
|
22
|
+
operation.call
|
23
|
+
rescue Mongo::ConnectionFailure => error
|
24
|
+
(elapsed < Mongoid.reconnect_time) ? retry : (raise error)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module ClassMethods #:nodoc:
|
30
|
+
# Proxy all the supplied operations to the internal collection or target.
|
31
|
+
#
|
32
|
+
# Example:
|
33
|
+
#
|
34
|
+
# <tt>proxy Operations::ALL, :collection</tt>
|
35
|
+
def proxy(target, operations)
|
36
|
+
operations.each do |name|
|
37
|
+
define_method(name) do |*args|
|
38
|
+
operation = lambda { send(target).send(name, *args) }
|
39
|
+
attempt(operation, Time.now)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|