mongoid 5.4.1 → 6.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (264) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/config/locales/en.yml +23 -16
  5. data/lib/mongoid.rb +4 -9
  6. data/lib/mongoid/atomic.rb +1 -1
  7. data/lib/mongoid/atomic/modifiers.rb +8 -12
  8. data/lib/mongoid/attributes.rb +9 -11
  9. data/lib/mongoid/attributes/dynamic.rb +5 -6
  10. data/lib/mongoid/attributes/nested.rb +1 -1
  11. data/lib/mongoid/attributes/processing.rb +4 -0
  12. data/lib/mongoid/attributes/readonly.rb +22 -0
  13. data/lib/mongoid/cacheable.rb +36 -0
  14. data/lib/mongoid/changeable.rb +37 -1
  15. data/lib/mongoid/clients.rb +0 -63
  16. data/lib/mongoid/clients/factory.rb +0 -2
  17. data/lib/mongoid/clients/options.rb +54 -249
  18. data/lib/mongoid/clients/storage_options.rb +1 -69
  19. data/lib/mongoid/composable.rb +26 -2
  20. data/lib/mongoid/config.rb +1 -1
  21. data/lib/mongoid/config/options.rb +1 -1
  22. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -0
  23. data/lib/mongoid/contextual/atomic.rb +6 -9
  24. data/lib/mongoid/contextual/geo_near.rb +2 -3
  25. data/lib/mongoid/contextual/map_reduce.rb +97 -24
  26. data/lib/mongoid/contextual/memory.rb +7 -4
  27. data/lib/mongoid/contextual/mongo.rb +63 -54
  28. data/lib/mongoid/contextual/none.rb +2 -2
  29. data/lib/mongoid/copyable.rb +19 -19
  30. data/lib/mongoid/criteria.rb +5 -4
  31. data/lib/mongoid/criteria/findable.rb +2 -3
  32. data/lib/mongoid/criteria/includable.rb +63 -16
  33. data/lib/mongoid/criteria/marshalable.rb +2 -2
  34. data/lib/mongoid/criteria/modifiable.rb +17 -1
  35. data/lib/mongoid/criteria/options.rb +25 -0
  36. data/lib/mongoid/criteria/queryable.rb +86 -0
  37. data/lib/mongoid/criteria/queryable/aggregable.rb +120 -0
  38. data/lib/mongoid/criteria/queryable/extensions.rb +28 -0
  39. data/lib/mongoid/criteria/queryable/extensions/array.rb +185 -0
  40. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +37 -0
  41. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +34 -0
  42. data/lib/mongoid/criteria/queryable/extensions/date.rb +63 -0
  43. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +53 -0
  44. data/lib/mongoid/criteria/queryable/extensions/hash.rb +200 -0
  45. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +86 -0
  46. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +90 -0
  47. data/lib/mongoid/criteria/queryable/extensions/object.rb +206 -0
  48. data/lib/mongoid/criteria/queryable/extensions/range.rb +70 -0
  49. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +45 -0
  50. data/lib/mongoid/criteria/queryable/extensions/set.rb +34 -0
  51. data/lib/mongoid/criteria/queryable/extensions/string.rb +137 -0
  52. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +79 -0
  53. data/lib/mongoid/criteria/queryable/extensions/time.rb +60 -0
  54. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +54 -0
  55. data/lib/mongoid/criteria/queryable/forwardable.rb +65 -0
  56. data/lib/mongoid/criteria/queryable/key.rb +103 -0
  57. data/lib/mongoid/criteria/queryable/macroable.rb +27 -0
  58. data/lib/mongoid/criteria/queryable/mergeable.rb +271 -0
  59. data/lib/mongoid/criteria/queryable/optional.rb +411 -0
  60. data/lib/mongoid/criteria/queryable/options.rb +136 -0
  61. data/lib/mongoid/criteria/queryable/pipeline.rb +111 -0
  62. data/lib/mongoid/criteria/queryable/selectable.rb +662 -0
  63. data/lib/mongoid/criteria/queryable/selector.rb +196 -0
  64. data/lib/mongoid/criteria/queryable/smash.rb +103 -0
  65. data/lib/mongoid/document.rb +9 -23
  66. data/lib/mongoid/errors.rb +2 -1
  67. data/lib/mongoid/errors/ambiguous_relationship.rb +1 -1
  68. data/lib/mongoid/errors/delete_restriction.rb +2 -2
  69. data/lib/mongoid/errors/invalid_field.rb +2 -2
  70. data/lib/mongoid/errors/invalid_persistence_option.rb +29 -0
  71. data/lib/mongoid/errors/invalid_relation.rb +66 -0
  72. data/lib/mongoid/errors/inverse_not_found.rb +1 -1
  73. data/lib/mongoid/errors/mongoid_error.rb +1 -1
  74. data/lib/mongoid/evolvable.rb +1 -1
  75. data/lib/mongoid/extensions.rb +0 -5
  76. data/lib/mongoid/extensions/big_decimal.rb +17 -8
  77. data/lib/mongoid/extensions/date.rb +4 -1
  78. data/lib/mongoid/extensions/hash.rb +2 -3
  79. data/lib/mongoid/extensions/object.rb +2 -2
  80. data/lib/mongoid/extensions/string.rb +4 -3
  81. data/lib/mongoid/extensions/time.rb +5 -2
  82. data/lib/mongoid/factory.rb +1 -0
  83. data/lib/mongoid/fields/foreign_key.rb +2 -2
  84. data/lib/mongoid/fields/localized.rb +3 -8
  85. data/lib/mongoid/fields/validators/macro.rb +18 -0
  86. data/lib/mongoid/findable.rb +3 -3
  87. data/lib/mongoid/indexable.rb +17 -16
  88. data/lib/mongoid/indexable/specification.rb +1 -1
  89. data/lib/mongoid/indexable/validators/options.rb +1 -2
  90. data/lib/mongoid/interceptable.rb +6 -17
  91. data/lib/mongoid/loggable.rb +1 -1
  92. data/lib/mongoid/matchable.rb +3 -10
  93. data/lib/mongoid/matchable/gt.rb +2 -0
  94. data/lib/mongoid/matchable/gte.rb +2 -0
  95. data/lib/mongoid/matchable/lt.rb +2 -0
  96. data/lib/mongoid/matchable/lte.rb +2 -0
  97. data/lib/mongoid/persistable.rb +6 -5
  98. data/lib/mongoid/persistable/creatable.rb +2 -0
  99. data/lib/mongoid/persistable/deletable.rb +7 -3
  100. data/lib/mongoid/persistable/settable.rb +3 -16
  101. data/lib/mongoid/persistable/updatable.rb +10 -12
  102. data/lib/mongoid/persistence_context.rb +216 -0
  103. data/lib/mongoid/query_cache.rb +5 -30
  104. data/lib/mongoid/relations/accessors.rb +6 -2
  105. data/lib/mongoid/relations/auto_save.rb +12 -4
  106. data/lib/mongoid/relations/bindings/embedded/in.rb +4 -0
  107. data/lib/mongoid/relations/bindings/embedded/many.rb +8 -1
  108. data/lib/mongoid/relations/bindings/embedded/one.rb +10 -0
  109. data/lib/mongoid/relations/bindings/referenced/many.rb +4 -0
  110. data/lib/mongoid/relations/builders.rb +2 -2
  111. data/lib/mongoid/relations/builders/embedded/one.rb +1 -1
  112. data/lib/mongoid/relations/builders/nested_attributes/many.rb +1 -1
  113. data/lib/mongoid/relations/conversions.rb +1 -1
  114. data/lib/mongoid/relations/counter_cache.rb +28 -18
  115. data/lib/mongoid/relations/eager.rb +19 -7
  116. data/lib/mongoid/relations/eager/base.rb +5 -5
  117. data/lib/mongoid/relations/embedded/batchable.rb +9 -33
  118. data/lib/mongoid/relations/embedded/in.rb +16 -2
  119. data/lib/mongoid/relations/embedded/many.rb +23 -8
  120. data/lib/mongoid/relations/embedded/one.rb +17 -2
  121. data/lib/mongoid/relations/macros.rb +9 -2
  122. data/lib/mongoid/relations/metadata.rb +3 -3
  123. data/lib/mongoid/relations/nested_builder.rb +1 -1
  124. data/lib/mongoid/relations/options.rb +2 -2
  125. data/lib/mongoid/relations/proxy.rb +2 -33
  126. data/lib/mongoid/relations/referenced/in.rb +23 -11
  127. data/lib/mongoid/relations/referenced/many.rb +24 -16
  128. data/lib/mongoid/relations/referenced/many_to_many.rb +20 -13
  129. data/lib/mongoid/relations/referenced/one.rb +17 -1
  130. data/lib/mongoid/relations/reflections.rb +3 -5
  131. data/lib/mongoid/relations/touchable.rb +1 -1
  132. data/lib/mongoid/reloadable.rb +1 -1
  133. data/lib/mongoid/scopable.rb +3 -3
  134. data/lib/mongoid/serializable.rb +2 -3
  135. data/lib/mongoid/tasks/database.rb +1 -2
  136. data/lib/mongoid/threaded.rb +4 -4
  137. data/lib/mongoid/traversable.rb +1 -1
  138. data/lib/mongoid/validatable.rb +1 -1
  139. data/lib/mongoid/validatable/macros.rb +2 -4
  140. data/lib/mongoid/validatable/uniqueness.rb +1 -2
  141. data/lib/mongoid/version.rb +1 -1
  142. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +4 -7
  143. data/spec/app/models/album.rb +5 -1
  144. data/spec/app/models/artist.rb +21 -0
  145. data/spec/app/models/band.rb +0 -1
  146. data/spec/app/models/church.rb +0 -2
  147. data/spec/app/models/ordered_post.rb +5 -0
  148. data/spec/app/models/oscar.rb +1 -2
  149. data/spec/app/models/person.rb +3 -1
  150. data/spec/app/models/post.rb +0 -1
  151. data/spec/app/models/princess.rb +2 -0
  152. data/spec/app/models/record.rb +1 -0
  153. data/spec/app/models/thing.rb +1 -1
  154. data/spec/config/mongoid.yml +1 -5
  155. data/spec/mongoid/atomic/modifiers_spec.rb +17 -17
  156. data/spec/mongoid/atomic_spec.rb +17 -17
  157. data/spec/mongoid/attributes/nested_spec.rb +14 -14
  158. data/spec/mongoid/attributes/readonly_spec.rb +87 -44
  159. data/spec/mongoid/attributes_spec.rb +63 -0
  160. data/spec/mongoid/cacheable_spec.rb +112 -0
  161. data/spec/mongoid/changeable_spec.rb +58 -0
  162. data/spec/mongoid/clients/factory_spec.rb +3 -11
  163. data/spec/mongoid/clients/options_spec.rb +378 -96
  164. data/spec/mongoid/clients_spec.rb +207 -170
  165. data/spec/mongoid/composable_spec.rb +7 -0
  166. data/spec/mongoid/config_spec.rb +41 -21
  167. data/spec/mongoid/contextual/atomic_spec.rb +77 -343
  168. data/spec/mongoid/contextual/map_reduce_spec.rb +119 -111
  169. data/spec/mongoid/contextual/memory_spec.rb +56 -316
  170. data/spec/mongoid/contextual/mongo_spec.rb +104 -378
  171. data/spec/mongoid/copyable_spec.rb +8 -15
  172. data/spec/mongoid/criteria/modifiable_spec.rb +239 -7
  173. data/spec/mongoid/criteria/options_spec.rb +29 -0
  174. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +370 -0
  175. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +523 -0
  176. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +59 -0
  177. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +58 -0
  178. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +213 -0
  179. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +330 -0
  180. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +405 -0
  181. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +58 -0
  182. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +65 -0
  183. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +327 -0
  184. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +65 -0
  185. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +77 -0
  186. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +108 -0
  187. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +309 -0
  188. data/spec/mongoid/{extensions/origin/regexp_raw_spec.rb → criteria/queryable/extensions/regexp_spec.rb} +21 -20
  189. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +39 -0
  190. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +302 -0
  191. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +167 -0
  192. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +376 -0
  193. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +347 -0
  194. data/spec/mongoid/criteria/queryable/forwardable_spec.rb +87 -0
  195. data/spec/mongoid/criteria/queryable/key_spec.rb +52 -0
  196. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +49 -0
  197. data/spec/mongoid/criteria/queryable/optional_spec.rb +1786 -0
  198. data/spec/mongoid/criteria/queryable/options_spec.rb +360 -0
  199. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +200 -0
  200. data/spec/mongoid/criteria/queryable/queryable_spec.rb +137 -0
  201. data/spec/mongoid/criteria/queryable/selectable_spec.rb +4159 -0
  202. data/spec/mongoid/criteria/queryable/selector_spec.rb +778 -0
  203. data/spec/mongoid/criteria/queryable/smash_spec.rb +30 -0
  204. data/spec/mongoid/criteria_spec.rb +45 -63
  205. data/spec/mongoid/document_spec.rb +21 -88
  206. data/spec/mongoid/errors/invalid_relation_spec.rb +37 -0
  207. data/spec/mongoid/errors/mongoid_error_spec.rb +6 -3
  208. data/spec/mongoid/extensions/big_decimal_spec.rb +320 -18
  209. data/spec/mongoid/extensions/date_spec.rb +2 -6
  210. data/spec/mongoid/extensions/date_time_spec.rb +2 -6
  211. data/spec/mongoid/extensions/float_spec.rb +8 -1
  212. data/spec/mongoid/extensions/integer_spec.rb +8 -1
  213. data/spec/mongoid/extensions/object_spec.rb +11 -0
  214. data/spec/mongoid/extensions/string_spec.rb +21 -0
  215. data/spec/mongoid/extensions/time_spec.rb +4 -8
  216. data/spec/mongoid/extensions/time_with_zone_spec.rb +2 -6
  217. data/spec/mongoid/fields/localized_spec.rb +0 -91
  218. data/spec/mongoid/findable_spec.rb +46 -1
  219. data/spec/mongoid/indexable_spec.rb +6 -46
  220. data/spec/mongoid/interceptable_spec.rb +49 -10
  221. data/spec/mongoid/matchable/gt_spec.rb +11 -0
  222. data/spec/mongoid/matchable/gte_spec.rb +10 -0
  223. data/spec/mongoid/matchable/lt_spec.rb +11 -0
  224. data/spec/mongoid/matchable/lte_spec.rb +11 -0
  225. data/spec/mongoid/matchable_spec.rb +1 -51
  226. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  227. data/spec/mongoid/persistable/deletable_spec.rb +1 -1
  228. data/spec/mongoid/persistable/destroyable_spec.rb +6 -2
  229. data/spec/mongoid/persistable/savable_spec.rb +30 -30
  230. data/spec/mongoid/persistable/settable_spec.rb +0 -185
  231. data/spec/mongoid/persistable/updatable_spec.rb +166 -5
  232. data/spec/mongoid/persistence_context_spec.rb +654 -0
  233. data/spec/mongoid/positional_spec.rb +10 -10
  234. data/spec/mongoid/query_cache_spec.rb +89 -65
  235. data/spec/mongoid/relations/accessors_spec.rb +1 -1
  236. data/spec/mongoid/relations/auto_save_spec.rb +39 -6
  237. data/spec/mongoid/relations/builders_spec.rb +37 -10
  238. data/spec/mongoid/relations/counter_cache_spec.rb +64 -15
  239. data/spec/mongoid/relations/cyclic_spec.rb +0 -22
  240. data/spec/mongoid/relations/embedded/many_spec.rb +9 -41
  241. data/spec/mongoid/relations/embedded/one_spec.rb +2 -1
  242. data/spec/mongoid/relations/macros_spec.rb +395 -7
  243. data/spec/mongoid/relations/proxy_spec.rb +3 -1
  244. data/spec/mongoid/relations/referenced/in_spec.rb +41 -1
  245. data/spec/mongoid/relations/referenced/many_spec.rb +6 -29
  246. data/spec/mongoid/relations/referenced/many_to_many_spec.rb +6 -29
  247. data/spec/mongoid/relations/reflections_spec.rb +9 -9
  248. data/spec/mongoid/reloadable_spec.rb +51 -0
  249. data/spec/mongoid/scopable_spec.rb +0 -12
  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 +16 -9
  253. data/spec/mongoid/validatable_spec.rb +16 -0
  254. data/spec/spec_helper.rb +10 -10
  255. metadata +536 -479
  256. metadata.gz.sig +0 -0
  257. data/lib/mongoid/clients/thread_options.rb +0 -19
  258. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +0 -20
  259. data/lib/mongoid/extensions/decimal128.rb +0 -39
  260. data/lib/mongoid/extensions/origin/regexp_raw.rb +0 -43
  261. data/lib/mongoid/matchable/regexp.rb +0 -27
  262. data/spec/app/models/post_genre.rb +0 -6
  263. data/spec/mongoid/extensions/decimal128_spec.rb +0 -44
  264. data/spec/mongoid/matchable/regexp_spec.rb +0 -59
@@ -20,7 +20,7 @@ describe Mongoid::Copyable do
20
20
  end
21
21
 
22
22
  let!(:address) do
23
- person.addresses.build(street: "Bond", name: "Bond")
23
+ person.addresses.build(street: "Bond")
24
24
  end
25
25
 
26
26
  let!(:name) do
@@ -54,7 +54,7 @@ describe Mongoid::Copyable do
54
54
  end
55
55
  end
56
56
 
57
- context "when a document has old renamed fields" do
57
+ context "when a document has fields from a legacy schema" do
58
58
 
59
59
  let!(:actor) do
60
60
  Actor.create(name: "test")
@@ -68,8 +68,12 @@ describe Mongoid::Copyable do
68
68
  actor.reload.send(method)
69
69
  end
70
70
 
71
- it "copies the document without error" do
72
- expect(cloned.this_is_not_a_field).to eq(1)
71
+ it "sets the legacy attribute" do
72
+ expect(cloned.attributes['this_is_not_a_field']).to eq(1)
73
+ end
74
+
75
+ it "copies the known attriutes" do
76
+ expect(cloned.name).to eq('test')
73
77
  end
74
78
  end
75
79
 
@@ -93,7 +97,6 @@ describe Mongoid::Copyable do
93
97
  I18n.enforce_available_locales = false
94
98
  I18n.locale = 'pt_BR'
95
99
  person.desc = "descrição"
96
- person.addresses.first.name = "descrição"
97
100
  person.save
98
101
  end
99
102
 
@@ -123,16 +126,6 @@ describe Mongoid::Copyable do
123
126
  I18n.locale = :fr
124
127
  expect(copy.desc).to be_nil
125
128
  end
126
-
127
- it 'sets embedded translations' do
128
- I18n.locale = 'pt_BR'
129
- expect(copy.addresses.first.name).to eq("descrição")
130
- end
131
-
132
- it 'sets embedded english version' do
133
- I18n.locale = :en
134
- expect(copy.addresses.first.name).to eq("Bond")
135
- end
136
129
  end
137
130
 
138
131
  context "when cloning a loaded document" do
@@ -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