mongoid 7.0.4 → 7.0.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.
- 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
|