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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97ae228df96e11fe59977a8d1af1bb0e86597fe5ee31d8cbe257a077d6e87d4f
4
- data.tar.gz: b8face8e682359ca47c26c0dc168ab1a99762769176fd2f8796ae472a341cd76
3
+ metadata.gz: 1d4a5f733ce016f190a456b5801a1e3a1efbe89a30d99a20cd4c73e5696e7004
4
+ data.tar.gz: a40c8e747c7eeff97d8259bd6b11d35bf25de5434674c24f1c5ebe71ed5d6f3e
5
5
  SHA512:
6
- metadata.gz: 1aafc53e49a0576a7bfb081bca208629ba7323c1a52468e0279644b0b9c2a9d4015c63d35cdf1f16b0967056ed976d015638fab512bce7a221acfeda75c867ed
7
- data.tar.gz: 0c3e7557c424ccd5a95d3e5c4249e4a45a31f74577be2ba7cfac70d67d3226cd00b0b655e7f9d576086a0fc18c7b9d7bf37c57e8a06fb07131a3bec99e85fe8a
6
+ metadata.gz: 121ace21edf0fec13546294a101b4bb383eed7d7b7ead0d6bd3624ccfad5601a70a9e4b0363e710e687ba237835ea4a61da8d17ebab00a2537751a7fcbf5410f
7
+ data.tar.gz: d39854dd3981a7c517e6ba00c0d85feb1e9bb6e928dabf233f603bf35f8299706c0981ed3cb9ba3c121e2af58ae42bc0e0e876a3a45f0264ac344d48469e9401
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
@@ -20,7 +20,7 @@ module Mongoid
20
20
  #
21
21
  # @since 2.1.0
22
22
  def path
23
- @path ||= position.sub(/\.\d+$/, "")
23
+ @path ||= position.sub(/\.\d+\z/, "")
24
24
  end
25
25
  end
26
26
  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
- where(selector.merge(attrs))
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
- attributes = selector.reduce(attrs ? attrs.dup : {}) do |hash, (key, value)|
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
- # The key is a representation of a field in a queryable, that can be
7
- # expanded to special MongoDB selectors.
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
- # @attribute [r] name The name of the field.
11
- # @attribute [r] block The optional block to transform values.
12
- # @attribute [r] operator The MongoDB query operator.
13
- # @attribute [r] expanded The MongoDB expanded query operator.
14
- # @attribute [r] strategy The name of the merge strategy.
15
- attr_reader :block, :name, :operator, :expanded, :strategy
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 spression is negated.
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
- if in?(_key)
24
+ case _key
25
+ when '$in'
25
26
  new_val & old_val
26
- elsif nin?(_key)
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
- super(name, evolve_multi(value))
56
+ store_name = name
57
+ store_value = evolve_multi(value)
56
58
  else
57
- super(localized_key(name, serializer), evolve(serializer, value))
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
- key =~ /\$and|\$or|\$nor/
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?
@@ -64,7 +64,7 @@ module Mongoid
64
64
  matches = position.scan(/\.\d+\./)
65
65
  if matches.size == 1
66
66
  keys.each do |kk|
67
- if position =~ /^#{kk}\.\d+\.(.*)/
67
+ if position =~ /\A#{kk}\.\d+\.(.*)\z/
68
68
  return "#{kk}.$.#{$1}"
69
69
  end
70
70
  end
@@ -258,7 +258,7 @@ module Mongoid
258
258
  end
259
259
 
260
260
  def system_collection?
261
- collection.namespace =~ /^system./
261
+ collection.namespace =~ /\Asystem./
262
262
  end
263
263
  end
264
264
 
@@ -48,7 +48,7 @@ module Mongoid
48
48
  # include Mongoid::Document
49
49
  # field :title
50
50
  #
51
- # validates_format_of :title, with: /^[a-z0-9 \-_]*$/i
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.
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid
3
- VERSION = "7.0.4"
3
+ VERSION = "7.0.5"
4
4
  end
@@ -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).send(:monitoring).subscribers['Command'].find do |s|
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
- subscriber.started_events.select { |event| event.command_name == 'insert' }
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
- subscriber.started_events.select { |event| event.command_name == 'update' }
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
- CONFIG[:clients][:other] = CONFIG[:clients][:default].dup
7
- CONFIG[:clients][:other][:database] = 'other'
8
- Mongoid::Clients.clients.values.each(&:close)
9
- Mongoid::Config.send(:clients=, CONFIG[:clients])
10
- Mongoid::Clients.with_name(:other).subscribe(Mongo::Monitoring::COMMAND, EventSubscriber.new)
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
- Mongoid::Clients.with_name(:other).close
15
- Mongoid::Clients.clients.delete(:other)
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
@@ -1,6 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Mongoid::Contextual::GeoNear do
4
+ max_server_version '4.0'
4
5
 
5
6
  describe "#average_distance" do
6
7
 
@@ -1643,11 +1643,15 @@ describe Mongoid::Criteria::Modifiable do
1643
1643
  { 'username' => 'Turnip' }
1644
1644
  end
1645
1645
 
1646
- it 'returns a criteria with the defined attributes' do
1647
- expect(Person.create_with(attrs).selector).to eq(attrs)
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
- context 'when a method is chained' do
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 write method args precedence' do
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).selector).to eq(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).selector).to eq(criteria_selector.merge!(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 write method is chained' do
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 'executes the query' do
1782
+ it 'gives the find method arg precedence' do
1753
1783
  expect(new_person.username).to eq('Beet')
1754
- expect(new_person.age).to eq(50)
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