mongoid 7.0.4 → 7.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Rakefile +12 -0
- data/lib/mongoid/atomic/paths/embedded.rb +1 -1
- data/lib/mongoid/criteria/modifiable.rb +12 -2
- data/lib/mongoid/criteria/queryable/key.rb +67 -8
- data/lib/mongoid/criteria/queryable/selectable.rb +1 -1
- data/lib/mongoid/criteria/queryable/selector.rb +9 -31
- data/lib/mongoid/extensions/string.rb +2 -2
- data/lib/mongoid/positional.rb +1 -1
- data/lib/mongoid/query_cache.rb +1 -1
- data/lib/mongoid/validatable/macros.rb +1 -1
- data/lib/mongoid/version.rb +1 -1
- data/spec/README.md +18 -0
- data/spec/mongoid/clients/factory_spec.rb +2 -2
- data/spec/mongoid/clients/sessions_spec.rb +12 -3
- data/spec/mongoid/clients/transactions_spec.rb +16 -7
- data/spec/mongoid/contextual/geo_near_spec.rb +1 -0
- data/spec/mongoid/criteria/modifiable_spec.rb +59 -10
- data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +54 -0
- data/spec/mongoid/criteria/queryable/key_spec.rb +48 -6
- data/spec/mongoid/criteria/queryable/selector_spec.rb +37 -0
- data/spec/mongoid/criteria_spec.rb +3 -0
- data/spec/spec_helper.rb +6 -8
- data/spec/support/cluster_config.rb +158 -0
- metadata +435 -428
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d4a5f733ce016f190a456b5801a1e3a1efbe89a30d99a20cd4c73e5696e7004
|
4
|
+
data.tar.gz: a40c8e747c7eeff97d8259bd6b11d35bf25de5434674c24f1c5ebe71ed5d6f3e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 121ace21edf0fec13546294a101b4bb383eed7d7b7ead0d6bd3624ccfad5601a70a9e4b0363e710e687ba237835ea4a61da8d17ebab00a2537751a7fcbf5410f
|
7
|
+
data.tar.gz: d39854dd3981a7c517e6ba00c0d85feb1e9bb6e928dabf233f603bf35f8299706c0981ed3cb9ba3c121e2af58ae42bc0e0e876a3a45f0264ac344d48469e9401
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/Rakefile
CHANGED
@@ -33,3 +33,15 @@ RSpec::Core::RakeTask.new('spec:progress') do |spec|
|
|
33
33
|
end
|
34
34
|
|
35
35
|
task :default => :spec
|
36
|
+
|
37
|
+
desc "Generate all documentation"
|
38
|
+
task :docs => 'docs:yard'
|
39
|
+
|
40
|
+
namespace :docs do
|
41
|
+
desc "Generate yard documention"
|
42
|
+
task :yard do
|
43
|
+
out = File.join('yard-docs', Mongoid::VERSION)
|
44
|
+
FileUtils.rm_rf(out)
|
45
|
+
system "yardoc -o #{out} --title mongoid-#{Mongoid::VERSION}"
|
46
|
+
end
|
47
|
+
end
|
@@ -3,6 +3,10 @@ module Mongoid
|
|
3
3
|
class Criteria
|
4
4
|
module Modifiable
|
5
5
|
|
6
|
+
# @attribute [r] create_attrs Additional attributes to add to the Document upon creation.
|
7
|
+
# @api private
|
8
|
+
attr_reader :create_attrs
|
9
|
+
|
6
10
|
# Build a document given the selector and return it.
|
7
11
|
# Complex criteria, such as $in and $or operations will get ignored.
|
8
12
|
#
|
@@ -57,6 +61,9 @@ module Mongoid
|
|
57
61
|
|
58
62
|
# Define attributes with which new documents will be created.
|
59
63
|
#
|
64
|
+
# Note that if `find_or_create_by` is called after this in a method chain, the attributes in
|
65
|
+
# the query will override those from this method.
|
66
|
+
#
|
60
67
|
# @example Define attributes to be used when a new document is created.
|
61
68
|
# Person.create_with(job: 'Engineer').find_or_create_by(employer: 'MongoDB')
|
62
69
|
#
|
@@ -64,7 +71,9 @@ module Mongoid
|
|
64
71
|
#
|
65
72
|
# @since 5.1.0
|
66
73
|
def create_with(attrs = {})
|
67
|
-
|
74
|
+
tap do
|
75
|
+
(@create_attrs ||= {}).merge!(attrs)
|
76
|
+
end
|
68
77
|
end
|
69
78
|
|
70
79
|
# Find the first +Document+ given the conditions, or creates a new document
|
@@ -172,7 +181,8 @@ module Mongoid
|
|
172
181
|
#
|
173
182
|
# @since 3.0.0
|
174
183
|
def create_document(method, attrs = nil, &block)
|
175
|
-
|
184
|
+
attrs = (create_attrs || {}).merge(attrs || {})
|
185
|
+
attributes = selector.reduce(attrs) do |hash, (key, value)|
|
176
186
|
unless invalid_key?(hash, key) || invalid_embedded_doc?(value)
|
177
187
|
hash[key] = value
|
178
188
|
end
|
@@ -3,16 +3,75 @@ module Mongoid
|
|
3
3
|
class Criteria
|
4
4
|
module Queryable
|
5
5
|
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# Key objects represent specifications for building query expressions
|
7
|
+
# utilizing MongoDB selectors.
|
8
|
+
#
|
9
|
+
# Simple key-value conditions are translated directly into expression
|
10
|
+
# hashes by Mongoid without utilizing Key objects. For example, the
|
11
|
+
# following condition:
|
12
|
+
#
|
13
|
+
# Foo.where(price: 1)
|
14
|
+
#
|
15
|
+
# ... is translated to the following simple expression:
|
16
|
+
#
|
17
|
+
# {price: 1}
|
18
|
+
#
|
19
|
+
# More complex conditions would start involving Key objects. For example:
|
20
|
+
#
|
21
|
+
# Foo.where(:price.gt => 1)
|
22
|
+
#
|
23
|
+
# ... causes a Key instance to be created thusly:
|
24
|
+
#
|
25
|
+
# Key.new(:price, :__override__, '$gt')
|
26
|
+
#
|
27
|
+
# This Key instance utilizes +operator+ but not +expanded+ nor +block+.
|
28
|
+
# The corresponding MongoDB query expression is:
|
29
|
+
#
|
30
|
+
# {price: {'$gt' => 1}}
|
31
|
+
#
|
32
|
+
# A yet more more complex example is the following condition:
|
33
|
+
#
|
34
|
+
# Foo.geo_spacial(:boundary.intersects_point => [1, 10])
|
35
|
+
#
|
36
|
+
# Processing this condition will cause a Key instance to be created as
|
37
|
+
# follows:
|
38
|
+
#
|
39
|
+
# Key.new(:location, :__override__, '$geoIntersects', '$geometry') do |value|
|
40
|
+
# { "type" => POINT, "coordinates" => value }
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# ... eventually producing the following MongoDB query expression:
|
44
|
+
#
|
45
|
+
# {
|
46
|
+
# boundary: {
|
47
|
+
# '$geoIntersects' => {
|
48
|
+
# '$geometry' => {
|
49
|
+
# type: "Point" ,
|
50
|
+
# coordinates: [ 1, 10 ]
|
51
|
+
# }
|
52
|
+
# }
|
53
|
+
# }
|
54
|
+
# }
|
55
|
+
#
|
56
|
+
# Key instances can be thought of as procs that map a value to the
|
57
|
+
# MongoDB query expression required to obtain the key's condition,
|
58
|
+
# given the value.
|
8
59
|
class Key
|
9
60
|
|
10
|
-
# @
|
11
|
-
|
12
|
-
|
13
|
-
# @
|
14
|
-
|
15
|
-
|
61
|
+
# @return [ String | Symbol ] The name of the field.
|
62
|
+
attr_reader :name
|
63
|
+
|
64
|
+
# @return [ String ] The MongoDB query operator.
|
65
|
+
attr_reader :operator
|
66
|
+
|
67
|
+
# @return [ String ] The MongoDB expanded query operator.
|
68
|
+
attr_reader :expanded
|
69
|
+
|
70
|
+
# @return [ Symbol ] The name of the merge strategy.
|
71
|
+
attr_reader :strategy
|
72
|
+
|
73
|
+
# @return [ Proc ] The optional block to transform values.
|
74
|
+
attr_reader :block
|
16
75
|
|
17
76
|
# Does the key equal another object?
|
18
77
|
#
|
@@ -24,7 +24,7 @@ module Mongoid
|
|
24
24
|
# @since 2.0.0
|
25
25
|
POLYGON = "Polygon"
|
26
26
|
|
27
|
-
# @attribute [rw] negating If the next
|
27
|
+
# @attribute [rw] negating If the next expression is negated.
|
28
28
|
# @attribute [rw] selector The query selector.
|
29
29
|
attr_accessor :negating, :selector
|
30
30
|
|
@@ -21,9 +21,10 @@ module Mongoid
|
|
21
21
|
other.each_pair do |key, value|
|
22
22
|
if value.is_a?(Hash) && self[key.to_s].is_a?(Hash)
|
23
23
|
value = self[key.to_s].merge(value) do |_key, old_val, new_val|
|
24
|
-
|
24
|
+
case _key
|
25
|
+
when '$in'
|
25
26
|
new_val & old_val
|
26
|
-
|
27
|
+
when '$nin'
|
27
28
|
(old_val + new_val).uniq
|
28
29
|
else
|
29
30
|
new_val
|
@@ -52,10 +53,13 @@ module Mongoid
|
|
52
53
|
def store(key, value)
|
53
54
|
name, serializer = storage_pair(key)
|
54
55
|
if multi_selection?(name)
|
55
|
-
|
56
|
+
store_name = name
|
57
|
+
store_value = evolve_multi(value)
|
56
58
|
else
|
57
|
-
|
59
|
+
store_name = localized_key(name, serializer)
|
60
|
+
store_value = evolve(serializer, value)
|
58
61
|
end
|
62
|
+
super(store_name, store_value)
|
59
63
|
end
|
60
64
|
alias :[]= :store
|
61
65
|
|
@@ -178,33 +182,7 @@ module Mongoid
|
|
178
182
|
#
|
179
183
|
# @since 1.0.0
|
180
184
|
def multi_selection?(key)
|
181
|
-
|
182
|
-
end
|
183
|
-
|
184
|
-
# Determines if the selection operator takes a list. Returns true for $in and $nin.
|
185
|
-
#
|
186
|
-
# @api private
|
187
|
-
#
|
188
|
-
# @example Does the selection operator take multiple values?
|
189
|
-
# selector.multi_value?("$nin")
|
190
|
-
#
|
191
|
-
# @param [ String ] key The key to check.
|
192
|
-
#
|
193
|
-
# @return [ true, false ] If the key is $in or $nin.
|
194
|
-
#
|
195
|
-
# @since 2.1.1
|
196
|
-
def multi_value?(key)
|
197
|
-
key =~ /\$nin|\$in/
|
198
|
-
end
|
199
|
-
|
200
|
-
private
|
201
|
-
|
202
|
-
def in?(key)
|
203
|
-
key =~ /\$in/
|
204
|
-
end
|
205
|
-
|
206
|
-
def nin?(key)
|
207
|
-
key =~ /\$nin/
|
185
|
+
%w($and $or $nor).include?(key)
|
208
186
|
end
|
209
187
|
end
|
210
188
|
end
|
@@ -69,7 +69,7 @@ module Mongoid
|
|
69
69
|
#
|
70
70
|
# @since 2.3.1
|
71
71
|
def mongoid_id?
|
72
|
-
self =~ /\A(|_)id
|
72
|
+
self =~ /\A(|_)id\z/
|
73
73
|
end
|
74
74
|
|
75
75
|
# Is the string a number? The literals "NaN", "Infinity", and "-Infinity"
|
@@ -96,7 +96,7 @@ module Mongoid
|
|
96
96
|
#
|
97
97
|
# @since 1.0.0
|
98
98
|
def reader
|
99
|
-
delete("=").sub(/\_before\_type\_cast
|
99
|
+
delete("=").sub(/\_before\_type\_cast\z/, '')
|
100
100
|
end
|
101
101
|
|
102
102
|
# Is this string a writer?
|
data/lib/mongoid/positional.rb
CHANGED
data/lib/mongoid/query_cache.rb
CHANGED
@@ -48,7 +48,7 @@ module Mongoid
|
|
48
48
|
# include Mongoid::Document
|
49
49
|
# field :title
|
50
50
|
#
|
51
|
-
# validates_format_of :title, with:
|
51
|
+
# validates_format_of :title, with: /\A[a-z0-9 \-_]*\z/i
|
52
52
|
# end
|
53
53
|
#
|
54
54
|
# @param [ Array ] args The names of the fields to validate.
|
data/lib/mongoid/version.rb
CHANGED
data/spec/README.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Running Mongoid Tests
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
### Quick Start
|
5
|
+
Spin up a MongoDB deployment against which to run the Mongoid specs. Mongoid specs support a variety of MongoDB topologies, but the simplest is a single MongoDB instance:
|
6
|
+
|
7
|
+
# Launch mongod in one terminal
|
8
|
+
mkdir /tmp/mdb
|
9
|
+
mongod --dbpath /tmp/mdb
|
10
|
+
|
11
|
+
Run the test suite in a separate terminal:
|
12
|
+
|
13
|
+
rake
|
14
|
+
|
15
|
+
|
16
|
+
## Caveats
|
17
|
+
### "Too many open files" error
|
18
|
+
On MacOS, you may encounter a "Too many open files" error on the MongoDB server when running the tests. If this happens, stop the server, run the command `ulimit -n 10000` in the same terminal session as the server, and restart the server. This will increase the number of files that can be opened. Then, re-run the tests.
|
@@ -132,8 +132,8 @@ describe Mongoid::Clients::Factory do
|
|
132
132
|
|
133
133
|
let(:config) do
|
134
134
|
{
|
135
|
-
default: { hosts: [ "127.0.0.1:1234" ], database: database_id },
|
136
|
-
secondary: { uri: "mongodb://127.0.0.1:1234,127.0.0.1:5678/mongoid_test" }
|
135
|
+
default: { hosts: [ "127.0.0.1:1234" ], database: database_id, server_selection_timeout: 1 },
|
136
|
+
secondary: { uri: "mongodb://127.0.0.1:1234,127.0.0.1:5678/mongoid_test?serverSelectionTimeoutMS=1000" }
|
137
137
|
}
|
138
138
|
end
|
139
139
|
|
@@ -16,17 +16,26 @@ describe Mongoid::Clients::Sessions do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
let(:subscriber) do
|
19
|
-
Mongoid::Clients.with_name(:other)
|
19
|
+
client = Mongoid::Clients.with_name(:other)
|
20
|
+
monitoring = if client.respond_to?(:monitoring, true)
|
21
|
+
client.send(:monitoring)
|
22
|
+
else
|
23
|
+
# driver 2.5
|
24
|
+
client.instance_variable_get('@monitoring')
|
25
|
+
end
|
26
|
+
monitoring.subscribers['Command'].find do |s|
|
20
27
|
s.is_a?(EventSubscriber)
|
21
28
|
end
|
22
29
|
end
|
23
30
|
|
24
31
|
let(:insert_events) do
|
25
|
-
|
32
|
+
# Driver 2.5 sends command_name as a symbol
|
33
|
+
subscriber.started_events.select { |event| event.command_name.to_s == 'insert' }
|
26
34
|
end
|
27
35
|
|
28
36
|
let(:update_events) do
|
29
|
-
|
37
|
+
# Driver 2.5 sends command_name as a symbol
|
38
|
+
subscriber.started_events.select { |event| event.command_name.to_s == 'update' }
|
30
39
|
end
|
31
40
|
|
32
41
|
context 'when a session is used on a model class' do
|
@@ -1,18 +1,27 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Mongoid::Clients::Sessions do
|
4
|
+
before(:all) do
|
5
|
+
unless Mongo::VERSION >= '2.6'
|
6
|
+
skip 'Driver does not support transactions'
|
7
|
+
end
|
8
|
+
end
|
4
9
|
|
5
10
|
before(:all) do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
+
if Mongo::VERSION >= '2.6'
|
12
|
+
CONFIG[:clients][:other] = CONFIG[:clients][:default].dup
|
13
|
+
CONFIG[:clients][:other][:database] = 'other'
|
14
|
+
Mongoid::Clients.clients.values.each(&:close)
|
15
|
+
Mongoid::Config.send(:clients=, CONFIG[:clients])
|
16
|
+
Mongoid::Clients.with_name(:other).subscribe(Mongo::Monitoring::COMMAND, EventSubscriber.new)
|
17
|
+
end
|
11
18
|
end
|
12
19
|
|
13
20
|
after(:all) do
|
14
|
-
|
15
|
-
|
21
|
+
if Mongo::VERSION >= '2.6'
|
22
|
+
Mongoid::Clients.with_name(:other).close
|
23
|
+
Mongoid::Clients.clients.delete(:other)
|
24
|
+
end
|
16
25
|
end
|
17
26
|
|
18
27
|
let(:subscriber) do
|
@@ -1643,11 +1643,15 @@ describe Mongoid::Criteria::Modifiable do
|
|
1643
1643
|
{ 'username' => 'Turnip' }
|
1644
1644
|
end
|
1645
1645
|
|
1646
|
-
it '
|
1647
|
-
expect(Person.create_with(attrs).selector).to
|
1646
|
+
it 'does not modify the selector' do
|
1647
|
+
expect(Person.create_with(attrs).selector[:username]).to be_nil
|
1648
1648
|
end
|
1649
1649
|
|
1650
|
-
|
1650
|
+
it 'create_attrs is modified' do
|
1651
|
+
expect(Person.create_with(attrs).create_attrs).to eq(attrs)
|
1652
|
+
end
|
1653
|
+
|
1654
|
+
context 'when a create is chained' do
|
1651
1655
|
|
1652
1656
|
context 'when a write method is chained' do
|
1653
1657
|
|
@@ -1671,6 +1675,25 @@ describe Mongoid::Criteria::Modifiable do
|
|
1671
1675
|
expect(new_person.age).to eq(50)
|
1672
1676
|
end
|
1673
1677
|
|
1678
|
+
context 'when a matching document is already in the collection' do
|
1679
|
+
let(:query) do
|
1680
|
+
{ 'username' => 'foo', 'age' => 12 }
|
1681
|
+
end
|
1682
|
+
|
1683
|
+
let(:person) do
|
1684
|
+
Person.create!(query)
|
1685
|
+
end
|
1686
|
+
|
1687
|
+
let(:found_person) do
|
1688
|
+
Person.create_with(attrs).find_or_create_by(query)
|
1689
|
+
end
|
1690
|
+
|
1691
|
+
it 'finds the matching document' do
|
1692
|
+
person
|
1693
|
+
expect(found_person.id).to eq(person.id)
|
1694
|
+
end
|
1695
|
+
end
|
1696
|
+
|
1674
1697
|
context 'when the attributes are shared with the write method args' do
|
1675
1698
|
|
1676
1699
|
let(:query) do
|
@@ -1681,7 +1704,7 @@ describe Mongoid::Criteria::Modifiable do
|
|
1681
1704
|
Person.create_with(attrs).find_or_create_by(query)
|
1682
1705
|
end
|
1683
1706
|
|
1684
|
-
it 'gives the
|
1707
|
+
it 'gives the find method args precedence' do
|
1685
1708
|
expect(new_person.username).to eq('Beet')
|
1686
1709
|
expect(new_person.age).to eq(50)
|
1687
1710
|
end
|
@@ -1708,8 +1731,12 @@ describe Mongoid::Criteria::Modifiable do
|
|
1708
1731
|
{ 'username' => 'Beet', 'age' => 50 }
|
1709
1732
|
end
|
1710
1733
|
|
1734
|
+
it 'does not modify the selector' do
|
1735
|
+
expect(criteria.create_with(attrs).selector).to eq(criteria_selector)
|
1736
|
+
end
|
1737
|
+
|
1711
1738
|
it 'overwrites all the original attributes' do
|
1712
|
-
expect(criteria.create_with(attrs).
|
1739
|
+
expect(criteria.create_with(attrs).create_attrs).to eq(attrs)
|
1713
1740
|
end
|
1714
1741
|
end
|
1715
1742
|
end
|
@@ -1720,8 +1747,12 @@ describe Mongoid::Criteria::Modifiable do
|
|
1720
1747
|
{ 'username' => 'Beet' }
|
1721
1748
|
end
|
1722
1749
|
|
1750
|
+
it 'does not modify the selector' do
|
1751
|
+
expect(criteria.create_with(attrs).selector).to eq(criteria_selector)
|
1752
|
+
end
|
1753
|
+
|
1723
1754
|
it 'only overwrites the shared attributes' do
|
1724
|
-
expect(criteria.create_with(attrs).
|
1755
|
+
expect(criteria.create_with(attrs).create_attrs).to eq(attrs)
|
1725
1756
|
end
|
1726
1757
|
end
|
1727
1758
|
|
@@ -1730,12 +1761,11 @@ describe Mongoid::Criteria::Modifiable do
|
|
1730
1761
|
let(:attrs) do
|
1731
1762
|
{ 'username' => 'Turnip' }
|
1732
1763
|
end
|
1733
|
-
|
1734
1764
|
let(:query) do
|
1735
1765
|
{ 'username' => 'Beet', 'age' => 50 }
|
1736
1766
|
end
|
1737
1767
|
|
1738
|
-
context 'when a
|
1768
|
+
context 'when a create method is chained' do
|
1739
1769
|
|
1740
1770
|
it 'executes the method' do
|
1741
1771
|
expect(criteria.create_with(attrs).new.username).to eq('Turnip')
|
@@ -1749,9 +1779,28 @@ describe Mongoid::Criteria::Modifiable do
|
|
1749
1779
|
criteria.create_with(attrs).find_or_create_by(query)
|
1750
1780
|
end
|
1751
1781
|
|
1752
|
-
it '
|
1782
|
+
it 'gives the find method arg precedence' do
|
1753
1783
|
expect(new_person.username).to eq('Beet')
|
1754
|
-
expect(new_person.age).to
|
1784
|
+
expect(new_person.age).to be(50)
|
1785
|
+
end
|
1786
|
+
|
1787
|
+
context 'when a matching document is already in the collection' do
|
1788
|
+
let(:query) do
|
1789
|
+
{ 'username' => 'foo', 'age' => 12 }
|
1790
|
+
end
|
1791
|
+
|
1792
|
+
let(:person) do
|
1793
|
+
Person.create!(query)
|
1794
|
+
end
|
1795
|
+
|
1796
|
+
let(:found_person) do
|
1797
|
+
criteria.create_with(attrs).find_or_create_by(query)
|
1798
|
+
end
|
1799
|
+
|
1800
|
+
it 'finds the matching document' do
|
1801
|
+
person
|
1802
|
+
expect(found_person.id).to eq(person.id)
|
1803
|
+
end
|
1755
1804
|
end
|
1756
1805
|
end
|
1757
1806
|
end
|