mongoid 1.1.4 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|