mongoid 5.4.1 → 6.1.1

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 (260) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +3 -3
  3. data/lib/config/locales/en.yml +19 -0
  4. data/lib/mongoid.rb +4 -4
  5. data/lib/mongoid/atomic.rb +2 -2
  6. data/lib/mongoid/atomic/modifiers.rb +8 -12
  7. data/lib/mongoid/attributes.rb +22 -21
  8. data/lib/mongoid/attributes/readonly.rb +22 -0
  9. data/lib/mongoid/cacheable.rb +36 -0
  10. data/lib/mongoid/changeable.rb +36 -0
  11. data/lib/mongoid/clients.rb +8 -63
  12. data/lib/mongoid/clients/options.rb +55 -250
  13. data/lib/mongoid/clients/storage_options.rb +1 -69
  14. data/lib/mongoid/composable.rb +29 -3
  15. data/lib/mongoid/config.rb +1 -0
  16. data/lib/mongoid/contextual/atomic.rb +5 -8
  17. data/lib/mongoid/contextual/map_reduce.rb +0 -4
  18. data/lib/mongoid/contextual/memory.rb +2 -2
  19. data/lib/mongoid/contextual/mongo.rb +40 -22
  20. data/lib/mongoid/contextual/none.rb +12 -0
  21. data/lib/mongoid/copyable.rb +13 -6
  22. data/lib/mongoid/criteria.rb +5 -2
  23. data/lib/mongoid/criteria/marshalable.rb +2 -2
  24. data/lib/mongoid/criteria/modifiable.rb +17 -1
  25. data/lib/mongoid/criteria/options.rb +25 -0
  26. data/lib/mongoid/criteria/queryable.rb +87 -0
  27. data/lib/mongoid/criteria/queryable/aggregable.rb +120 -0
  28. data/lib/mongoid/criteria/queryable/extensions.rb +28 -0
  29. data/lib/mongoid/criteria/queryable/extensions/array.rb +185 -0
  30. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +37 -0
  31. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +34 -0
  32. data/lib/mongoid/criteria/queryable/extensions/date.rb +63 -0
  33. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +53 -0
  34. data/lib/mongoid/criteria/queryable/extensions/hash.rb +200 -0
  35. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +86 -0
  36. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +90 -0
  37. data/lib/mongoid/criteria/queryable/extensions/object.rb +206 -0
  38. data/lib/mongoid/criteria/queryable/extensions/range.rb +70 -0
  39. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +79 -0
  40. data/lib/mongoid/criteria/queryable/extensions/set.rb +34 -0
  41. data/lib/mongoid/criteria/queryable/extensions/string.rb +137 -0
  42. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +79 -0
  43. data/lib/mongoid/criteria/queryable/extensions/time.rb +60 -0
  44. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +54 -0
  45. data/lib/mongoid/criteria/queryable/forwardable.rb +65 -0
  46. data/lib/mongoid/criteria/queryable/key.rb +103 -0
  47. data/lib/mongoid/criteria/queryable/macroable.rb +27 -0
  48. data/lib/mongoid/criteria/queryable/mergeable.rb +271 -0
  49. data/lib/mongoid/criteria/queryable/optional.rb +429 -0
  50. data/lib/mongoid/criteria/queryable/options.rb +153 -0
  51. data/lib/mongoid/criteria/queryable/pipeline.rb +111 -0
  52. data/lib/mongoid/criteria/queryable/selectable.rb +662 -0
  53. data/lib/mongoid/criteria/queryable/selector.rb +212 -0
  54. data/lib/mongoid/criteria/queryable/smash.rb +104 -0
  55. data/lib/mongoid/document.rb +30 -37
  56. data/lib/mongoid/errors.rb +2 -0
  57. data/lib/mongoid/errors/ambiguous_relationship.rb +1 -1
  58. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +1 -1
  59. data/lib/mongoid/errors/invalid_field.rb +2 -2
  60. data/lib/mongoid/errors/invalid_persistence_option.rb +29 -0
  61. data/lib/mongoid/errors/invalid_relation.rb +66 -0
  62. data/lib/mongoid/evolvable.rb +1 -1
  63. data/lib/mongoid/extensions.rb +0 -4
  64. data/lib/mongoid/extensions/big_decimal.rb +17 -8
  65. data/lib/mongoid/extensions/date.rb +4 -1
  66. data/lib/mongoid/extensions/decimal128.rb +3 -3
  67. data/lib/mongoid/extensions/hash.rb +1 -0
  68. data/lib/mongoid/extensions/string.rb +4 -3
  69. data/lib/mongoid/extensions/time.rb +4 -1
  70. data/lib/mongoid/fields/validators/macro.rb +18 -0
  71. data/lib/mongoid/findable.rb +2 -2
  72. data/lib/mongoid/indexable.rb +15 -13
  73. data/lib/mongoid/interceptable.rb +5 -22
  74. data/lib/mongoid/matchable.rb +13 -7
  75. data/lib/mongoid/matchable/all.rb +2 -2
  76. data/lib/mongoid/matchable/and.rb +3 -3
  77. data/lib/mongoid/matchable/default.rb +2 -2
  78. data/lib/mongoid/matchable/elem_match.rb +28 -0
  79. data/lib/mongoid/matchable/exists.rb +2 -2
  80. data/lib/mongoid/matchable/gt.rb +4 -2
  81. data/lib/mongoid/matchable/gte.rb +4 -2
  82. data/lib/mongoid/matchable/in.rb +2 -2
  83. data/lib/mongoid/matchable/lt.rb +4 -2
  84. data/lib/mongoid/matchable/lte.rb +4 -2
  85. data/lib/mongoid/matchable/ne.rb +2 -2
  86. data/lib/mongoid/matchable/nin.rb +2 -2
  87. data/lib/mongoid/matchable/or.rb +3 -3
  88. data/lib/mongoid/matchable/regexp.rb +3 -3
  89. data/lib/mongoid/matchable/size.rb +2 -2
  90. data/lib/mongoid/persistable.rb +3 -5
  91. data/lib/mongoid/persistable/creatable.rb +2 -2
  92. data/lib/mongoid/persistable/deletable.rb +1 -1
  93. data/lib/mongoid/persistable/settable.rb +1 -1
  94. data/lib/mongoid/persistable/updatable.rb +5 -12
  95. data/lib/mongoid/persistable/upsertable.rb +1 -1
  96. data/lib/mongoid/persistence_context.rb +215 -0
  97. data/lib/mongoid/query_cache.rb +3 -6
  98. data/lib/mongoid/relations/accessors.rb +3 -0
  99. data/lib/mongoid/relations/auto_save.rb +12 -4
  100. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +4 -4
  101. data/lib/mongoid/relations/counter_cache.rb +15 -5
  102. data/lib/mongoid/relations/eager.rb +6 -11
  103. data/lib/mongoid/relations/eager/base.rb +3 -3
  104. data/lib/mongoid/relations/eager/has_and_belongs_to_many.rb +2 -2
  105. data/lib/mongoid/relations/eager/has_many.rb +1 -1
  106. data/lib/mongoid/relations/embedded/batchable.rb +12 -36
  107. data/lib/mongoid/relations/embedded/in.rb +13 -1
  108. data/lib/mongoid/relations/embedded/many.rb +28 -10
  109. data/lib/mongoid/relations/embedded/one.rb +14 -1
  110. data/lib/mongoid/relations/macros.rb +9 -1
  111. data/lib/mongoid/relations/metadata.rb +3 -3
  112. data/lib/mongoid/relations/options.rb +2 -2
  113. data/lib/mongoid/relations/proxy.rb +1 -31
  114. data/lib/mongoid/relations/referenced/in.rb +19 -10
  115. data/lib/mongoid/relations/referenced/many.rb +23 -17
  116. data/lib/mongoid/relations/referenced/many_to_many.rb +20 -13
  117. data/lib/mongoid/relations/referenced/one.rb +15 -1
  118. data/lib/mongoid/relations/synchronization.rb +11 -11
  119. data/lib/mongoid/relations/touchable.rb +6 -3
  120. data/lib/mongoid/reloadable.rb +1 -1
  121. data/lib/mongoid/serializable.rb +1 -1
  122. data/lib/mongoid/traversable.rb +1 -1
  123. data/lib/mongoid/validatable/uniqueness.rb +1 -2
  124. data/lib/mongoid/version.rb +1 -1
  125. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +14 -3
  126. data/spec/app/models/album.rb +5 -1
  127. data/spec/app/models/artist.rb +21 -0
  128. data/spec/app/models/book.rb +2 -1
  129. data/spec/app/models/dokument.rb +1 -0
  130. data/spec/app/models/ordered_post.rb +5 -0
  131. data/spec/app/models/oscar.rb +1 -2
  132. data/spec/app/models/page.rb +1 -1
  133. data/spec/app/models/person.rb +3 -3
  134. data/spec/app/models/princess.rb +2 -0
  135. data/spec/app/models/record.rb +1 -0
  136. data/spec/app/models/subscription.rb +1 -0
  137. data/spec/app/models/thing.rb +1 -1
  138. data/spec/config/mongoid.yml +15 -0
  139. data/spec/mongoid/atomic/modifiers_spec.rb +17 -17
  140. data/spec/mongoid/atomic_spec.rb +17 -17
  141. data/spec/mongoid/attributes/nested_spec.rb +14 -14
  142. data/spec/mongoid/attributes/readonly_spec.rb +87 -44
  143. data/spec/mongoid/attributes_spec.rb +90 -5
  144. data/spec/mongoid/cacheable_spec.rb +112 -0
  145. data/spec/mongoid/changeable_spec.rb +58 -0
  146. data/spec/mongoid/clients/factory_spec.rb +31 -3
  147. data/spec/mongoid/clients/options_spec.rb +382 -96
  148. data/spec/mongoid/clients_spec.rb +243 -101
  149. data/spec/mongoid/composable_spec.rb +7 -0
  150. data/spec/mongoid/config_spec.rb +67 -11
  151. data/spec/mongoid/contextual/atomic_spec.rb +3 -3
  152. data/spec/mongoid/contextual/mongo_spec.rb +165 -20
  153. data/spec/mongoid/contextual/none_spec.rb +15 -0
  154. data/spec/mongoid/copyable_spec.rb +13 -4
  155. data/spec/mongoid/criteria/modifiable_spec.rb +239 -7
  156. data/spec/mongoid/criteria/options_spec.rb +29 -0
  157. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +370 -0
  158. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +523 -0
  159. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +59 -0
  160. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +58 -0
  161. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +213 -0
  162. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +330 -0
  163. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +405 -0
  164. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +58 -0
  165. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +65 -0
  166. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +327 -0
  167. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +65 -0
  168. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +77 -0
  169. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +108 -0
  170. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +309 -0
  171. data/spec/mongoid/{extensions/origin → criteria/queryable/extensions}/regexp_raw_spec.rb +2 -2
  172. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +90 -0
  173. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +39 -0
  174. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +302 -0
  175. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +167 -0
  176. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +376 -0
  177. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +347 -0
  178. data/spec/mongoid/criteria/queryable/forwardable_spec.rb +87 -0
  179. data/spec/mongoid/criteria/queryable/key_spec.rb +52 -0
  180. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +49 -0
  181. data/spec/mongoid/criteria/queryable/optional_spec.rb +1799 -0
  182. data/spec/mongoid/criteria/queryable/options_spec.rb +360 -0
  183. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +200 -0
  184. data/spec/mongoid/criteria/queryable/queryable_spec.rb +137 -0
  185. data/spec/mongoid/criteria/queryable/selectable_spec.rb +4174 -0
  186. data/spec/mongoid/criteria/queryable/selector_spec.rb +844 -0
  187. data/spec/mongoid/criteria/queryable/smash_spec.rb +30 -0
  188. data/spec/mongoid/criteria_spec.rb +152 -21
  189. data/spec/mongoid/document_spec.rb +37 -88
  190. data/spec/mongoid/errors/invalid_relation_spec.rb +37 -0
  191. data/spec/mongoid/errors/mongoid_error_spec.rb +6 -3
  192. data/spec/mongoid/extensions/big_decimal_spec.rb +320 -18
  193. data/spec/mongoid/extensions/boolean_spec.rb +14 -0
  194. data/spec/mongoid/extensions/date_spec.rb +2 -6
  195. data/spec/mongoid/extensions/date_time_spec.rb +2 -6
  196. data/spec/mongoid/extensions/decimal128_spec.rb +1 -1
  197. data/spec/mongoid/extensions/float_spec.rb +8 -1
  198. data/spec/mongoid/extensions/hash_spec.rb +15 -0
  199. data/spec/mongoid/extensions/integer_spec.rb +8 -1
  200. data/spec/mongoid/extensions/object_spec.rb +11 -0
  201. data/spec/mongoid/extensions/string_spec.rb +21 -0
  202. data/spec/mongoid/extensions/time_spec.rb +2 -6
  203. data/spec/mongoid/extensions/time_with_zone_spec.rb +2 -6
  204. data/spec/mongoid/findable_spec.rb +46 -1
  205. data/spec/mongoid/indexable_spec.rb +15 -3
  206. data/spec/mongoid/interceptable_spec.rb +68 -10
  207. data/spec/mongoid/matchable/all_spec.rb +4 -4
  208. data/spec/mongoid/matchable/and_spec.rb +10 -10
  209. data/spec/mongoid/matchable/default_spec.rb +12 -12
  210. data/spec/mongoid/matchable/elem_match_spec.rb +86 -0
  211. data/spec/mongoid/matchable/exists_spec.rb +5 -5
  212. data/spec/mongoid/matchable/gt_spec.rb +18 -7
  213. data/spec/mongoid/matchable/gte_spec.rb +17 -7
  214. data/spec/mongoid/matchable/in_spec.rb +5 -5
  215. data/spec/mongoid/matchable/lt_spec.rb +18 -7
  216. data/spec/mongoid/matchable/lte_spec.rb +18 -7
  217. data/spec/mongoid/matchable/ne_spec.rb +5 -5
  218. data/spec/mongoid/matchable/nin_spec.rb +5 -5
  219. data/spec/mongoid/matchable/or_spec.rb +7 -7
  220. data/spec/mongoid/matchable/regexp_spec.rb +5 -5
  221. data/spec/mongoid/matchable/size_spec.rb +3 -3
  222. data/spec/mongoid/matchable_spec.rb +173 -53
  223. data/spec/mongoid/persistable/creatable_spec.rb +7 -2
  224. data/spec/mongoid/persistable/deletable_spec.rb +16 -1
  225. data/spec/mongoid/persistable/destroyable_spec.rb +6 -2
  226. data/spec/mongoid/persistable/savable_spec.rb +35 -30
  227. data/spec/mongoid/persistable/settable_spec.rb +45 -29
  228. data/spec/mongoid/persistable/updatable_spec.rb +184 -5
  229. data/spec/mongoid/persistence_context_spec.rb +680 -0
  230. data/spec/mongoid/positional_spec.rb +10 -10
  231. data/spec/mongoid/query_cache_spec.rb +89 -0
  232. data/spec/mongoid/relations/accessors_spec.rb +1 -1
  233. data/spec/mongoid/relations/auto_save_spec.rb +39 -6
  234. data/spec/mongoid/relations/bindings/referenced/many_to_many_spec.rb +4 -4
  235. data/spec/mongoid/relations/builders_spec.rb +37 -10
  236. data/spec/mongoid/relations/counter_cache_spec.rb +64 -3
  237. data/spec/mongoid/relations/eager/has_and_belongs_to_many_spec.rb +16 -0
  238. data/spec/mongoid/relations/eager_spec.rb +40 -0
  239. data/spec/mongoid/relations/embedded/many_spec.rb +63 -47
  240. data/spec/mongoid/relations/embedded/one_spec.rb +2 -1
  241. data/spec/mongoid/relations/macros_spec.rb +395 -7
  242. data/spec/mongoid/relations/metadata_spec.rb +15 -1
  243. data/spec/mongoid/relations/proxy_spec.rb +27 -1
  244. data/spec/mongoid/relations/referenced/in_spec.rb +41 -1
  245. data/spec/mongoid/relations/referenced/many_spec.rb +13 -25
  246. data/spec/mongoid/relations/referenced/many_to_many_spec.rb +14 -26
  247. data/spec/mongoid/relations/synchronization_spec.rb +48 -2
  248. data/spec/mongoid/relations/touchable_spec.rb +40 -0
  249. data/spec/mongoid/reloadable_spec.rb +51 -0
  250. data/spec/mongoid/serializable_spec.rb +0 -50
  251. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  252. data/spec/mongoid/validatable/uniqueness_spec.rb +18 -9
  253. data/spec/mongoid/validatable_spec.rb +16 -0
  254. data/spec/spec_helper.rb +20 -11
  255. metadata +524 -469
  256. checksums.yaml.gz.sig +0 -0
  257. data.tar.gz.sig +0 -0
  258. data/lib/mongoid/clients/thread_options.rb +0 -19
  259. data/lib/mongoid/extensions/origin/regexp_raw.rb +0 -43
  260. metadata.gz.sig +0 -0
@@ -538,6 +538,135 @@ describe Mongoid::Criteria::Modifiable do
538
538
  it "sets the additional attributes" do
539
539
  expect(document.origin).to eq("Essex")
540
540
  end
541
+
542
+ context 'when attributes contain keys also in the criteria selector' do
543
+
544
+ context 'when the selector has symbol keys' do
545
+
546
+ context 'when the attributes use symbol keys' do
547
+
548
+ let(:document) do
549
+ Band.where(name: 'Tool').first_or_create(name: 'Essex')
550
+ end
551
+
552
+ it 'uses the values from the attributes' do
553
+ expect(document.name).to eq('Essex')
554
+ end
555
+ end
556
+
557
+ context 'when the attributes use string keys' do
558
+
559
+ let(:document) do
560
+ Band.where(name: 'Tool').first_or_create('name' => 'Essex')
561
+ end
562
+
563
+ it 'uses the values from the attributes' do
564
+ expect(document.name).to eq('Essex')
565
+ end
566
+ end
567
+ end
568
+
569
+ context 'when the selector has string keys' do
570
+
571
+ context 'when the attributes use symbol keys' do
572
+
573
+ let(:document) do
574
+ Band.where('name' => 'Tool').first_or_create(name: 'Essex')
575
+ end
576
+
577
+ it 'uses the values from the attributes' do
578
+ expect(document.name).to eq('Essex')
579
+ end
580
+ end
581
+
582
+ context 'when the attributes use string keys' do
583
+
584
+ let(:document) do
585
+ Band.where('name' => 'Tool').first_or_create('name' => 'Essex')
586
+ end
587
+
588
+ it 'uses the values from the attributes' do
589
+ expect(document.name).to eq('Essex')
590
+ end
591
+ end
592
+ end
593
+ end
594
+
595
+ context 'when the query criteria is on a hash attribute' do
596
+
597
+ let(:document) do
598
+ Person.where(map: { foo: :bar }).first_or_create
599
+ end
600
+
601
+ it 'uses the values from the attributes' do
602
+ expect(document.map).to eq({ foo: :bar })
603
+ end
604
+ end
605
+
606
+ context 'when the criteria has a selector with query operators' do
607
+
608
+ let(:document) do
609
+ Band.in(genres: ['Hiphop', 'Soul']).first_or_create(name: 'Smooth')
610
+ end
611
+
612
+ it 'does not create a document with the query operators' do
613
+ expect(document.attributes.keys).not_to include('genres')
614
+ end
615
+ end
616
+
617
+ context 'when the criteria has a nested selector with query operators' do
618
+
619
+ let(:band) do
620
+ record = Record.new(producers: ['testing'])
621
+ band = Band.create(records: [record])
622
+ end
623
+
624
+ let(:document) do
625
+ band.records.in(producers: ['nonexistent']).first_or_create(name: 'new-embedded-doc')
626
+ band.reload
627
+ end
628
+
629
+ it 'creates a new embedded document' do
630
+ expect(document.records.size).to eq(2)
631
+ end
632
+
633
+ it 'does not alter the existing embedded document' do
634
+ expect(document.records[0].producers).to eq(['testing'])
635
+ end
636
+
637
+ it 'does not create a document with the query operators as attributes' do
638
+ expect(document.records[1].producers).to be_nil
639
+ end
640
+
641
+ it 'applies the attribute to the new embedded document' do
642
+ expect(document.records[1].name).to eq('new-embedded-doc')
643
+ end
644
+ end
645
+
646
+ context 'when the criteria has a deeply-nested selector with query operators' do
647
+
648
+ let(:criteria) do
649
+ band = Band.create
650
+ Mongoid::Criteria.new(Record) do |criteria|
651
+ criteria.embedded = true
652
+ criteria.metadata = Band.reflect_on_association(:records)
653
+ criteria.parent_document = band
654
+ criteria.selector = { "records" => { "producers"=>{"$in"=>["nonexistent"] } } }
655
+ end
656
+ end
657
+
658
+ let(:document) do
659
+ criteria.first_or_create(name: 'new-record')
660
+ end
661
+
662
+ it 'does not create a document with the query operators' do
663
+ expect(document.attributes.keys).not_to include('producers')
664
+ end
665
+
666
+ it 'applies the attribute to the new embedded document' do
667
+ expect(document.name).to eq('new-record')
668
+ end
669
+ end
541
670
  end
542
671
 
543
672
  context "when attributes are not provided" do
@@ -736,6 +865,59 @@ describe Mongoid::Criteria::Modifiable do
736
865
  end
737
866
  end
738
867
  end
868
+
869
+ context 'when attributes contain keys also in the criteria selector' do
870
+
871
+ context 'when the selector has symbol keys' do
872
+
873
+ context 'when the attributes use symbol keys' do
874
+
875
+ let(:document) do
876
+ Band.where(name: 'Tool').first_or_create!(name: 'Essex')
877
+ end
878
+
879
+ it 'uses the values from the attributes' do
880
+ expect(document.name).to eq('Essex')
881
+ end
882
+ end
883
+
884
+ context 'when the attributes use string keys' do
885
+
886
+ let(:document) do
887
+ Band.where(name: 'Tool').first_or_create!('name' => 'Essex')
888
+ end
889
+
890
+ it 'uses the values from the attributes' do
891
+ expect(document.name).to eq('Essex')
892
+ end
893
+ end
894
+ end
895
+
896
+ context 'when the selector has string keys' do
897
+
898
+ context 'when the attributes use symbol keys' do
899
+
900
+ let(:document) do
901
+ Band.where('name' => 'Tool').first_or_create!(name: 'Essex')
902
+ end
903
+
904
+ it 'uses the values from the attributes' do
905
+ expect(document.name).to eq('Essex')
906
+ end
907
+ end
908
+
909
+ context 'when the attributes use string keys' do
910
+
911
+ let(:document) do
912
+ Band.where('name' => 'Tool').first_or_create!('name' => 'Essex')
913
+ end
914
+
915
+ it 'uses the values from the attributes' do
916
+ expect(document.name).to eq('Essex')
917
+ end
918
+ end
919
+ end
920
+ end
739
921
  end
740
922
  end
741
923
 
@@ -830,6 +1012,59 @@ describe Mongoid::Criteria::Modifiable do
830
1012
  end
831
1013
  end
832
1014
  end
1015
+
1016
+ context 'when attributes contain keys also in the criteria selector' do
1017
+
1018
+ context 'when the selector has symbol keys' do
1019
+
1020
+ context 'when the attributes use symbol keys' do
1021
+
1022
+ let(:document) do
1023
+ Band.where(name: 'Tool').first_or_initialize(name: 'Essex')
1024
+ end
1025
+
1026
+ it 'uses the values from the attributes' do
1027
+ expect(document.name).to eq('Essex')
1028
+ end
1029
+ end
1030
+
1031
+ context 'when the attributes use string keys' do
1032
+
1033
+ let(:document) do
1034
+ Band.where(name: 'Tool').first_or_initialize('name' => 'Essex')
1035
+ end
1036
+
1037
+ it 'uses the values from the attributes' do
1038
+ expect(document.name).to eq('Essex')
1039
+ end
1040
+ end
1041
+ end
1042
+
1043
+ context 'when the selector has string keys' do
1044
+
1045
+ context 'when the attributes use symbol keys' do
1046
+
1047
+ let(:document) do
1048
+ Band.where('name' => 'Tool').first_or_initialize(name: 'Essex')
1049
+ end
1050
+
1051
+ it 'uses the values from the attributes' do
1052
+ expect(document.name).to eq('Essex')
1053
+ end
1054
+ end
1055
+
1056
+ context 'when the attributes use string keys' do
1057
+
1058
+ let(:document) do
1059
+ Band.where('name' => 'Tool').first_or_initialize('name' => 'Essex')
1060
+ end
1061
+
1062
+ it 'uses the values from the attributes' do
1063
+ expect(document.name).to eq('Essex')
1064
+ end
1065
+ end
1066
+ end
1067
+ end
833
1068
  end
834
1069
  end
835
1070
 
@@ -1275,8 +1510,7 @@ describe Mongoid::Criteria::Modifiable do
1275
1510
  end
1276
1511
 
1277
1512
  it 'gives the write method args precedence' do
1278
- # @todo: uncomment when MONGOID-4193 is closed
1279
- #expect(new_person.username).to eq('Beet')
1513
+ expect(new_person.username).to eq('Beet')
1280
1514
  expect(new_person.age).to eq(50)
1281
1515
  end
1282
1516
  end
@@ -1332,8 +1566,7 @@ describe Mongoid::Criteria::Modifiable do
1332
1566
  context 'when a write method is chained' do
1333
1567
 
1334
1568
  it 'executes the method' do
1335
- # @todo: uncomment when MONGOID-4193 is closed
1336
- #expect(criteria.create_with(attrs).new.username).to eq('Beet')
1569
+ expect(criteria.create_with(attrs).new.username).to eq('Turnip')
1337
1570
  expect(criteria.create_with(attrs).new.age).to eq(25)
1338
1571
  end
1339
1572
  end
@@ -1345,9 +1578,8 @@ describe Mongoid::Criteria::Modifiable do
1345
1578
  end
1346
1579
 
1347
1580
  it 'executes the query' do
1348
- # @todo: uncomment when MONGOID-4193 is closed
1349
- #expect(new_person.username).to eq('Beet')
1350
- #expect(new_person.age).to eq(50)
1581
+ expect(new_person.username).to eq('Beet')
1582
+ expect(new_person.age).to eq(50)
1351
1583
  end
1352
1584
  end
1353
1585
  end
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Criteria::Options do
4
+
5
+
6
+ context 'when a persistence context with options is set on the class of the criteria' do
7
+
8
+ let(:context) do
9
+ Band.with(connect_timeout: 10) do |klass|
10
+ klass.where(name: 'FKA Twigs').persistence_context
11
+ end
12
+ end
13
+
14
+ it 'uses the persistence context of the class of the criteria' do
15
+ expect(context.options).to eq({ connect_timeout: 10 })
16
+ end
17
+ end
18
+
19
+ context 'when a persistence context with options is not set on the class of the criteria' do
20
+
21
+ let(:context) do
22
+ Band.where(name: 'FKA Twigs').persistence_context
23
+ end
24
+
25
+ it 'uses the persistence context of the class of the criteria' do
26
+ expect(context.options).to eq({ })
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,370 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Criteria::Queryable::Aggregable do
4
+
5
+ let(:query) do
6
+ Mongoid::Query.new("id" => "_id", "alias" => "a")
7
+ end
8
+
9
+ shared_examples_for "an aggregable object" do
10
+
11
+ it "clones the queryable" do
12
+ expect(aggregation).to_not equal(query)
13
+ end
14
+
15
+ it "sets the aggrating flag" do
16
+ expect(aggregation).to be_aggregating
17
+ end
18
+ end
19
+
20
+ describe "#project" do
21
+
22
+ context "when no selection or options exist" do
23
+
24
+ let(:aggregation) do
25
+ query.project(author: 1, title: 0)
26
+ end
27
+
28
+ let!(:pipeline) do
29
+ aggregation.pipeline
30
+ end
31
+
32
+ it "sets the projection" do
33
+ expect(pipeline).to eq([
34
+ { "$project" => { "author" => 1, "title" => 0 }}
35
+ ])
36
+ end
37
+
38
+ it_behaves_like "an aggregable object"
39
+ end
40
+
41
+ context "when the field is aliased" do
42
+
43
+ let(:aggregation) do
44
+ query.project(id: 1, title: "$docTitle")
45
+ end
46
+
47
+ let!(:pipeline) do
48
+ aggregation.pipeline
49
+ end
50
+
51
+ it "sets the aliased projection" do
52
+ expect(pipeline).to eq([
53
+ { "$project" => { "_id" => 1, "title" => "$docTitle" }}
54
+ ])
55
+ end
56
+
57
+ it_behaves_like "an aggregable object"
58
+ end
59
+
60
+ context "when selection exists" do
61
+
62
+ let(:aggregation) do
63
+ query.where(name: "test").project(author: 1, title: 0)
64
+ end
65
+
66
+ let!(:pipeline) do
67
+ aggregation.pipeline
68
+ end
69
+
70
+ it "converts the selection to a $match" do
71
+ expect(pipeline).to eq([
72
+ { "$match" => { "name" => "test" }},
73
+ { "$project" => { "author" => 1, "title" => 0 }}
74
+ ])
75
+ end
76
+
77
+ it_behaves_like "an aggregable object"
78
+ end
79
+
80
+ context "when options exist" do
81
+
82
+ context "when the option is a sort" do
83
+
84
+ let(:aggregation) do
85
+ query.asc(:name).project(author: 1, title: 0)
86
+ end
87
+
88
+ let!(:pipeline) do
89
+ aggregation.pipeline
90
+ end
91
+
92
+ it "converts the option to a $sort" do
93
+ expect(pipeline).to eq([
94
+ { "$sort" => { "name" => 1 }},
95
+ { "$project" => { "author" => 1, "title" => 0 }}
96
+ ])
97
+ end
98
+
99
+ it_behaves_like "an aggregable object"
100
+ end
101
+
102
+ context "when the option is a limit" do
103
+
104
+ let(:aggregation) do
105
+ query.limit(10).project(author: 1, title: 0)
106
+ end
107
+
108
+ let!(:pipeline) do
109
+ aggregation.pipeline
110
+ end
111
+
112
+ it "converts the option to a $sort" do
113
+ expect(pipeline).to eq([
114
+ { "$limit" => 10 },
115
+ { "$project" => { "author" => 1, "title" => 0 }}
116
+ ])
117
+ end
118
+
119
+ it_behaves_like "an aggregable object"
120
+ end
121
+
122
+ context "when the option is a skip" do
123
+
124
+ let(:aggregation) do
125
+ query.skip(10).project(author: 1, title: 0)
126
+ end
127
+
128
+ let!(:pipeline) do
129
+ aggregation.pipeline
130
+ end
131
+
132
+ it "converts the option to a $sort" do
133
+ expect(pipeline).to eq([
134
+ { "$skip" => 10 },
135
+ { "$project" => { "author" => 1, "title" => 0 }}
136
+ ])
137
+ end
138
+
139
+ it_behaves_like "an aggregable object"
140
+ end
141
+ end
142
+
143
+ context "when selection and options exist" do
144
+
145
+ let(:aggregation) do
146
+ query.skip(10).where(name: "test").project(author: 1, title: 0)
147
+ end
148
+
149
+ let!(:pipeline) do
150
+ aggregation.pipeline
151
+ end
152
+
153
+ it "converts the option to a $sort" do
154
+ expect(pipeline).to eq([
155
+ { "$match" => { "name" => "test" }},
156
+ { "$skip" => 10 },
157
+ { "$project" => { "author" => 1, "title" => 0 }}
158
+ ])
159
+ end
160
+
161
+ it_behaves_like "an aggregable object"
162
+ end
163
+ end
164
+
165
+ describe "#unwind" do
166
+
167
+ context "when another pipeline operation exists" do
168
+
169
+ let(:aggregation) do
170
+ query.project(name: 1).unwind(:author)
171
+ end
172
+
173
+ let!(:pipeline) do
174
+ aggregation.pipeline
175
+ end
176
+
177
+ it "adds the unwind to the pipeline" do
178
+ expect(pipeline).to eq([
179
+ { "$project" => { "name" => 1 }},
180
+ { "$unwind" => "$author" }
181
+ ])
182
+ end
183
+
184
+ it_behaves_like "an aggregable object"
185
+ end
186
+
187
+ context "when provided a symbol" do
188
+
189
+ context "when the symbol begins with $" do
190
+
191
+ let(:aggregation) do
192
+ query.unwind(:$author)
193
+ end
194
+
195
+ let!(:pipeline) do
196
+ aggregation.pipeline
197
+ end
198
+
199
+ it "converts the symbol to a string" do
200
+ expect(pipeline).to eq([{ "$unwind" => "$author" }])
201
+ end
202
+
203
+ it_behaves_like "an aggregable object"
204
+ end
205
+
206
+ context "when the symbol does not begin with $" do
207
+
208
+ let(:aggregation) do
209
+ query.unwind(:author)
210
+ end
211
+
212
+ let!(:pipeline) do
213
+ aggregation.pipeline
214
+ end
215
+
216
+ it "converts the symbol to a string and prepends $" do
217
+ expect(pipeline).to eq([{ "$unwind" => "$author" }])
218
+ end
219
+
220
+ it_behaves_like "an aggregable object"
221
+ end
222
+ end
223
+
224
+ context "when provided a string" do
225
+
226
+ context "when the string begins with $" do
227
+
228
+ let(:aggregation) do
229
+ query.unwind("$author")
230
+ end
231
+
232
+ let!(:pipeline) do
233
+ aggregation.pipeline
234
+ end
235
+
236
+ it "sets the string" do
237
+ expect(pipeline).to eq([{ "$unwind" => "$author" }])
238
+ end
239
+
240
+ it_behaves_like "an aggregable object"
241
+ end
242
+
243
+ context "when the string does not begin with $" do
244
+
245
+ let(:aggregation) do
246
+ query.unwind(:author)
247
+ end
248
+
249
+ let!(:pipeline) do
250
+ aggregation.pipeline
251
+ end
252
+
253
+ it "prepends $ to the string" do
254
+ expect(pipeline).to eq([{ "$unwind" => "$author" }])
255
+ end
256
+
257
+ it_behaves_like "an aggregable object"
258
+ end
259
+ end
260
+
261
+ context "when provided a string alias" do
262
+
263
+ context "when the string does not begin with $" do
264
+
265
+ let(:aggregation) do
266
+ query.unwind(:alias)
267
+ end
268
+
269
+ let!(:pipeline) do
270
+ aggregation.pipeline
271
+ end
272
+
273
+ it "prepends $ to the string" do
274
+ expect(pipeline).to eq([{ "$unwind" => "$a" }])
275
+ end
276
+
277
+ it_behaves_like "an aggregable object"
278
+ end
279
+ end
280
+ end
281
+
282
+ describe "#group" do
283
+
284
+ context "when the expression fields are not aliased" do
285
+
286
+ context "when using full notation" do
287
+
288
+ let(:aggregation) do
289
+ query.group(count: { "$sum" => 1 }, max: { "$max" => "likes" })
290
+ end
291
+
292
+ let!(:pipeline) do
293
+ aggregation.pipeline
294
+ end
295
+
296
+ it "adds the group operation to the pipeline" do
297
+ expect(pipeline).to eq([
298
+ { "$group" => { "count" => { "$sum" => 1 }, "max" => { "$max" => "likes" }}}
299
+ ])
300
+ end
301
+
302
+ it_behaves_like "an aggregable object"
303
+ end
304
+
305
+ context "when using symbol shortcuts" do
306
+
307
+ let(:aggregation) do
308
+ query.group(:count.sum => 1, :max.max => "likes")
309
+ end
310
+
311
+ let!(:pipeline) do
312
+ aggregation.pipeline
313
+ end
314
+
315
+ it "adds the group operation to the pipeline" do
316
+ expect(pipeline).to eq([
317
+ { "$group" => { "count" => { "$sum" => 1 }, "max" => { "$max" => "likes" }}}
318
+ ])
319
+ end
320
+
321
+ it_behaves_like "an aggregable object"
322
+ end
323
+ end
324
+
325
+ context "when the expression fields are aliased" do
326
+
327
+ context "when using full notation" do
328
+
329
+ let(:aggregation) do
330
+ query.group(count: { "$sum" => 1 }, max: { "$max" => "alias" })
331
+ end
332
+
333
+ let!(:pipeline) do
334
+ aggregation.pipeline
335
+ end
336
+
337
+ it "adds the group operation to the pipeline" do
338
+ pending
339
+ fail
340
+ expect(pipeline).to eq([
341
+ { "$group" => { "count" => { "$sum" => 1 }, "max" => { "$max" => "a" }}}
342
+ ])
343
+ end
344
+
345
+ it_behaves_like "an aggregable object"
346
+ end
347
+
348
+ context "when using symbol shortcuts" do
349
+
350
+ let(:aggregation) do
351
+ query.group(:count.sum => 1, :max.max => "alias")
352
+ end
353
+
354
+ let!(:pipeline) do
355
+ aggregation.pipeline
356
+ end
357
+
358
+ it "adds the group operation to the pipeline" do
359
+ pending
360
+ fail
361
+ expect(pipeline).to eq([
362
+ { "$group" => { "count" => { "$sum" => 1 }, "max" => { "$max" => "a" }}}
363
+ ])
364
+ end
365
+
366
+ it_behaves_like "an aggregable object"
367
+ end
368
+ end
369
+ end
370
+ end