mongoid 8.0.2 → 8.0.4

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +17 -15
  4. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +4 -0
  5. data/lib/mongoid/association/referenced/has_many/proxy.rb +4 -0
  6. data/lib/mongoid/cacheable.rb +2 -2
  7. data/lib/mongoid/criteria/queryable/extensions/array.rb +1 -1
  8. data/lib/mongoid/criteria/queryable/extensions/hash.rb +1 -1
  9. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +0 -8
  10. data/lib/mongoid/criteria/queryable/extensions/string.rb +1 -11
  11. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +0 -10
  12. data/lib/mongoid/criteria/translator.rb +45 -0
  13. data/lib/mongoid/criteria.rb +1 -0
  14. data/lib/mongoid/document.rb +50 -13
  15. data/lib/mongoid/extensions/big_decimal.rb +4 -0
  16. data/lib/mongoid/extensions/float.rb +6 -2
  17. data/lib/mongoid/extensions/integer.rb +6 -2
  18. data/lib/mongoid/factory.rb +21 -8
  19. data/lib/mongoid/fields/localized.rb +7 -2
  20. data/lib/mongoid/matcher.rb +21 -6
  21. data/lib/mongoid/persistence_context.rb +41 -5
  22. data/lib/mongoid/scopable.rb +9 -7
  23. data/lib/mongoid/shardable.rb +35 -11
  24. data/lib/mongoid/threaded.rb +33 -3
  25. data/lib/mongoid/traversable.rb +1 -1
  26. data/lib/mongoid/version.rb +1 -1
  27. data/spec/integration/i18n_fallbacks_spec.rb +1 -17
  28. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +37 -32
  29. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +143 -197
  30. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +102 -114
  31. data/spec/mongoid/attributes_spec.rb +2 -2
  32. data/spec/mongoid/cacheable_spec.rb +3 -3
  33. data/spec/mongoid/clients_spec.rb +25 -0
  34. data/spec/mongoid/contextual/memory_spec.rb +4 -5
  35. data/spec/mongoid/contextual/mongo_spec.rb +2 -4
  36. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +0 -59
  37. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +0 -59
  38. data/spec/mongoid/criteria/queryable/optional_spec.rb +15 -0
  39. data/spec/mongoid/criteria/translator_spec.rb +132 -0
  40. data/spec/mongoid/criteria_projection_spec.rb +0 -1
  41. data/spec/mongoid/criteria_spec.rb +1 -1
  42. data/spec/mongoid/extensions/big_decimal_spec.rb +15 -0
  43. data/spec/mongoid/extensions/float_spec.rb +10 -3
  44. data/spec/mongoid/extensions/integer_spec.rb +10 -3
  45. data/spec/mongoid/fields/localized_spec.rb +37 -12
  46. data/spec/mongoid/shardable_models.rb +14 -0
  47. data/spec/mongoid/shardable_spec.rb +153 -61
  48. data/spec/mongoid/validatable/uniqueness_spec.rb +0 -1
  49. data/spec/support/macros.rb +16 -0
  50. data.tar.gz.sig +0 -0
  51. metadata +651 -643
  52. metadata.gz.sig +0 -0
@@ -47,18 +47,22 @@ module Mongoid
47
47
  self.class.shard_key_fields
48
48
  end
49
49
 
50
- # Returns the selector that would match the current version of this
51
- # document.
50
+ # Returns the selector that would match the defined shard keys. If
51
+ # `prefer_persisted` is false (the default), it uses the current values
52
+ # of the specified shard keys, otherwise, it will try to use whatever value
53
+ # was most recently persisted.
54
+ #
55
+ # @param [ true | false ] prefer_persisted Whether to use the current
56
+ # value of the shard key fields, or to use their most recently persisted
57
+ # values.
52
58
  #
53
59
  # @return [ Hash ] The shard key selector.
54
60
  #
55
61
  # @api private
56
- def shard_key_selector
57
- selector = {}
58
- shard_key_fields.each do |field|
59
- selector[field.to_s] = send(field)
62
+ def shard_key_selector(prefer_persisted: false)
63
+ shard_key_fields.each_with_object({}) do |field, selector|
64
+ selector[field.to_s] = shard_key_field_value(field.to_s, prefer_persisted: prefer_persisted)
60
65
  end
61
- selector
62
66
  end
63
67
 
64
68
  # Returns the selector that would match the existing version of this
@@ -72,11 +76,31 @@ module Mongoid
72
76
  #
73
77
  # @api private
74
78
  def shard_key_selector_in_db
75
- selector = {}
76
- shard_key_fields.each do |field|
77
- selector[field.to_s] = new_record? ? send(field) : attribute_was(field)
79
+ shard_key_selector(prefer_persisted: true)
80
+ end
81
+
82
+ # Returns the value for the named shard key. If the field identifies
83
+ # an embedded document, the key will be parsed and recursively evaluated.
84
+ # If `prefer_persisted` is true, the value last persisted to the database
85
+ # will be returned, regardless of what the current value of the attribute
86
+ # may be.
87
+ #
88
+ # @param [String] field The name of the field to evaluate
89
+ # @param [ true|false ] prefer_persisted Whether or not to prefer the
90
+ # persisted value over the current value.
91
+ #
92
+ # @return [ Object ] The value of the named field.
93
+ #
94
+ # @api private
95
+ def shard_key_field_value(field, prefer_persisted:)
96
+ if field.include?(".")
97
+ relation, remaining = field.split(".", 2)
98
+ send(relation)&.shard_key_field_value(remaining, prefer_persisted: prefer_persisted)
99
+ elsif prefer_persisted && !new_record?
100
+ attribute_was(field)
101
+ else
102
+ send(field)
78
103
  end
79
- selector
80
104
  end
81
105
 
82
106
  module ClassMethods
@@ -26,6 +26,10 @@ module Mongoid
26
26
  hash[key] = "[mongoid]:#{key}-stack"
27
27
  end
28
28
 
29
+ # The key storing the default value for whether or not callbacks are
30
+ # executed on documents.
31
+ EXECUTE_CALLBACKS = '[mongoid]:execute-callbacks'
32
+
29
33
  extend self
30
34
 
31
35
  # Begin entry into a named thread local stack.
@@ -322,7 +326,7 @@ module Mongoid
322
326
  #
323
327
  # @param [ Mongo::Session ] session The session to save.
324
328
  def set_session(session)
325
- Thread.current[:session] = session
329
+ Thread.current["[mongoid]:session"] = session
326
330
  end
327
331
 
328
332
  # Get the cached session for this thread.
@@ -332,7 +336,7 @@ module Mongoid
332
336
  #
333
337
  # @return [ Mongo::Session | nil ] The session cached on this thread or nil.
334
338
  def get_session
335
- Thread.current[:session]
339
+ Thread.current["[mongoid]:session"]
336
340
  end
337
341
 
338
342
  # Clear the cached session for this thread.
@@ -344,7 +348,33 @@ module Mongoid
344
348
  def clear_session
345
349
  session = get_session
346
350
  session.end_session if session
347
- Thread.current[:session] = nil
351
+ Thread.current["[mongoid]:session"] = nil
352
+ end
353
+
354
+ # Queries whether document callbacks should be executed by default for the
355
+ # current thread.
356
+ #
357
+ # Unless otherwise indicated (by #execute_callbacks=), this will return
358
+ # true.
359
+ #
360
+ # @return [ true | false ] Whether or not document callbacks should be
361
+ # executed by default.
362
+ def execute_callbacks?
363
+ if Thread.current.key?(EXECUTE_CALLBACKS)
364
+ Thread.current[EXECUTE_CALLBACKS]
365
+ else
366
+ true
367
+ end
368
+ end
369
+
370
+ # Indicates whether document callbacks should be invoked by default for
371
+ # the current thread. Individual documents may further override the
372
+ # callback behavior, but this will be used for the default behavior.
373
+ #
374
+ # @param flag [ true | false ] Whether or not document callbacks should be
375
+ # executed by default.
376
+ def execute_callbacks=(flag)
377
+ Thread.current[EXECUTE_CALLBACKS] = flag
348
378
  end
349
379
  end
350
380
  end
@@ -237,7 +237,7 @@ module Mongoid
237
237
  remove_ivar(name)
238
238
  else
239
239
  relation = send(name)
240
- relation.send(:delete_one, child)
240
+ relation._remove(child)
241
241
  end
242
242
  end
243
243
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mongoid
4
- VERSION = "8.0.2"
4
+ VERSION = "8.0.4"
5
5
  end
@@ -3,19 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe 'i18n fallbacks' do
6
- # These tests modify the environment
7
- before(:all) do
8
- unless %w(yes true 1).include?((ENV['TEST_I18N_FALLBACKS'] || '').downcase)
9
- skip 'Set TEST_I18N_FALLBACKS=1 environment variable to run these tests'
10
- end
11
- end
12
-
13
- before(:all) do
14
- puts "I18n version: #{I18n::VERSION}"
15
-
16
- require "i18n/backend/fallbacks"
17
- I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
18
- end
6
+ with_i18n_fallbacks
19
7
 
20
8
  context 'when fallbacks are enabled with a locale list' do
21
9
  before do
@@ -36,7 +24,6 @@ describe 'i18n fallbacks' do
36
24
  end
37
25
 
38
26
  context 'when translation is missing in active locale and present in fallback locale' do
39
-
40
27
  it 'falls back on default locale' do
41
28
  product = Product.new
42
29
  I18n.locale = :en
@@ -44,7 +31,6 @@ describe 'i18n fallbacks' do
44
31
  I18n.locale = :de
45
32
  product.description.should == 'Marvelous!'
46
33
  end
47
-
48
34
  end
49
35
 
50
36
  context 'when translation is missing in all locales' do
@@ -64,7 +50,6 @@ describe 'i18n fallbacks' do
64
50
  I18n.locale = :ru
65
51
  product.description.should be nil
66
52
  end
67
-
68
53
  end
69
54
 
70
55
  context 'i18n 1.0' do
@@ -82,7 +67,6 @@ describe 'i18n fallbacks' do
82
67
  I18n.locale = :ru
83
68
  product.description.should == 'Marvelous!'
84
69
  end
85
-
86
70
  end
87
71
  end
88
72
  end
@@ -1862,51 +1862,56 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
1862
1862
  end
1863
1863
  end
1864
1864
 
1865
- describe "#delete" do
1865
+ %i[ delete delete_one ].each do |method|
1866
+ describe "\##{method}" do
1867
+ let(:address_one) { Address.new(street: "first") }
1868
+ let(:address_two) { Address.new(street: "second") }
1866
1869
 
1867
- let(:person) do
1868
- Person.new
1869
- end
1870
-
1871
- let(:address_one) do
1872
- Address.new(street: "first")
1873
- end
1870
+ before do
1871
+ person.addresses << [ address_one, address_two ]
1872
+ end
1874
1873
 
1875
- let(:address_two) do
1876
- Address.new(street: "second")
1877
- end
1874
+ shared_examples_for 'deleting from the collection' do
1875
+ context 'when the document exists in the relation' do
1876
+ let!(:deleted) do
1877
+ person.addresses.send(method, address_one)
1878
+ end
1878
1879
 
1879
- before do
1880
- person.addresses << [ address_one, address_two ]
1881
- end
1880
+ it 'deletes the document' do
1881
+ expect(person.addresses).to eq([ address_two ])
1882
+ expect(person.reload.addresses).to eq([ address_two ]) if person.persisted?
1883
+ end
1882
1884
 
1883
- context "when the document exists in the relation" do
1885
+ it 'deletes the document from the unscoped' do
1886
+ expect(person.addresses.send(:_unscoped)).to eq([ address_two ])
1887
+ end
1884
1888
 
1885
- let!(:deleted) do
1886
- person.addresses.delete(address_one)
1887
- end
1889
+ it 'reindexes the relation' do
1890
+ expect(address_two._index).to eq(0)
1891
+ end
1888
1892
 
1889
- it "deletes the document" do
1890
- expect(person.addresses).to eq([ address_two ])
1891
- end
1893
+ it 'returns the document' do
1894
+ expect(deleted).to eq(address_one)
1895
+ end
1896
+ end
1892
1897
 
1893
- it "deletes the document from the unscoped" do
1894
- expect(person.addresses.send(:_unscoped)).to eq([ address_two ])
1898
+ context 'when the document does not exist' do
1899
+ it 'returns nil' do
1900
+ expect(person.addresses.send(method, Address.new)).to be_nil
1901
+ end
1902
+ end
1895
1903
  end
1896
1904
 
1897
- it "reindexes the relation" do
1898
- expect(address_two._index).to eq(0)
1899
- end
1905
+ context 'when the root document is unpersisted' do
1906
+ let(:person) { Person.new }
1900
1907
 
1901
- it "returns the document" do
1902
- expect(deleted).to eq(address_one)
1908
+ it_behaves_like 'deleting from the collection'
1903
1909
  end
1904
- end
1905
1910
 
1906
- context "when the document does not exist" do
1911
+ context 'when the root document is persisted' do
1912
+ let(:person) { Person.create }
1907
1913
 
1908
- it "returns nil" do
1909
- expect(person.addresses.delete(Address.new)).to be_nil
1914
+ it_behaves_like 'deleting from the collection'
1910
1915
  end
1911
1916
  end
1912
1917
  end