mongoid 5.4.1 → 6.0.0.beta

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 (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
@@ -1105,6 +1105,69 @@ describe Mongoid::Attributes do
1105
1105
  expect(person.delayed_atomic_unsets).to be_empty
1106
1106
  end
1107
1107
  end
1108
+
1109
+ context "when the attribute is aliased" do
1110
+
1111
+ context 'when the database name is used' do
1112
+
1113
+ let(:person) do
1114
+ Person.create(at: Time.now)
1115
+ end
1116
+
1117
+ before do
1118
+ person.remove_attribute(:at)
1119
+ end
1120
+
1121
+ it "removes the attribute" do
1122
+ expect(person.at).to be_nil
1123
+ end
1124
+
1125
+ it "removes the key from the attributes hash" do
1126
+ expect(person.has_attribute?(:at)).to be false
1127
+ end
1128
+
1129
+ context "when saving after the removal" do
1130
+
1131
+ before do
1132
+ person.save
1133
+ end
1134
+
1135
+ it "persists the removal" do
1136
+ expect(person.reload.has_attribute?(:at)).to be false
1137
+ end
1138
+ end
1139
+ end
1140
+
1141
+ context 'when the alias is used' do
1142
+
1143
+ let(:person) do
1144
+ Person.create(aliased_timestamp: Time.now)
1145
+ end
1146
+
1147
+ before do
1148
+ person.remove_attribute(:aliased_timestamp)
1149
+ end
1150
+
1151
+ it "removes the attribute" do
1152
+ expect(person.aliased_timestamp).to be_nil
1153
+ end
1154
+
1155
+ it "removes the key from the attributes hash" do
1156
+ expect(person.has_attribute?(:aliased_timestamp)).to be false
1157
+ end
1158
+
1159
+ context "when saving after the removal" do
1160
+
1161
+ before do
1162
+ person.save
1163
+ end
1164
+
1165
+ it "persists the removal" do
1166
+ expect(person.reload.has_attribute?(:aliased_timestamp)).to be false
1167
+ end
1168
+ end
1169
+ end
1170
+ end
1108
1171
  end
1109
1172
 
1110
1173
  describe "#respond_to?" do
@@ -0,0 +1,112 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Cacheable do
4
+
5
+ describe ".included" do
6
+
7
+ let(:klass) do
8
+ Class.new do
9
+ include Mongoid::Cacheable
10
+ end
11
+ end
12
+
13
+ it "adds an cache_timestamp_format accessor" do
14
+ expect(klass).to respond_to(:cache_timestamp_format)
15
+ end
16
+
17
+ it "defaults cache_timestamp_format to :nsec" do
18
+ expect(klass.cache_timestamp_format).to be(:nsec)
19
+ end
20
+ end
21
+
22
+ describe "#cache_key" do
23
+
24
+ let(:document) do
25
+ Dokument.new
26
+ end
27
+
28
+ context "when the document is new" do
29
+
30
+ it "has a new key name" do
31
+ expect(document.cache_key).to eq("dokuments/new")
32
+ end
33
+ end
34
+
35
+ context "when persisted" do
36
+
37
+ before do
38
+ document.save
39
+ end
40
+
41
+ context "with updated_at" do
42
+
43
+ context "with the default cache_timestamp_format" do
44
+
45
+ let!(:updated_at) do
46
+ document.updated_at.utc.to_s(:nsec)
47
+ end
48
+
49
+ it "has the id and updated_at key name" do
50
+ expect(document.cache_key).to eq("dokuments/#{document.id}-#{updated_at}")
51
+ end
52
+ end
53
+
54
+ context "with a different cache_timestamp_format" do
55
+
56
+ before do
57
+ Dokument.cache_timestamp_format = :number
58
+ end
59
+
60
+ after do
61
+ Dokument.cache_timestamp_format = :nsec
62
+ end
63
+
64
+ let!(:updated_at) do
65
+ document.updated_at.utc.to_s(:number)
66
+ end
67
+
68
+ it "has the id and updated_at key name" do
69
+ expect(document.cache_key).to eq("dokuments/#{document.id}-#{updated_at}")
70
+ end
71
+ end
72
+ end
73
+
74
+ context "without updated_at, with Timestamps" do
75
+
76
+ before do
77
+ document.updated_at = nil
78
+ end
79
+
80
+ it "has the id key name" do
81
+ expect(document.cache_key).to eq("dokuments/#{document.id}")
82
+ end
83
+ end
84
+ end
85
+
86
+ context "when model dont have Timestamps" do
87
+
88
+ let(:artist) do
89
+ Artist.create!
90
+ end
91
+
92
+ it "should have the id key name" do
93
+ expect(artist.cache_key).to eq("artists/#{artist.id}")
94
+ end
95
+ end
96
+
97
+ context "when model has Short Timestamps" do
98
+
99
+ let(:agent) do
100
+ ShortAgent.create!
101
+ end
102
+
103
+ let!(:updated_at) do
104
+ agent.updated_at.utc.to_s(:nsec)
105
+ end
106
+
107
+ it "has the id and updated_at key name" do
108
+ expect(agent.cache_key).to eq("short_agents/#{agent.id}-#{updated_at}")
109
+ end
110
+ end
111
+ end
112
+ end
@@ -1289,6 +1289,64 @@ describe Mongoid::Changeable do
1289
1289
  end
1290
1290
  end
1291
1291
 
1292
+ describe '#previously_changed?' do
1293
+
1294
+ let(:person) do
1295
+ Person.new(title: "Grand Poobah")
1296
+ end
1297
+
1298
+ before do
1299
+ person.title = "Captain Obvious"
1300
+ end
1301
+
1302
+ context "when the document has been saved" do
1303
+
1304
+ before do
1305
+ person.save!
1306
+ end
1307
+
1308
+ it "returns true" do
1309
+ expect(person.title_previously_changed?).to be(true)
1310
+ end
1311
+ end
1312
+
1313
+ context "when the document has not been saved" do
1314
+
1315
+ it "returns false" do
1316
+ expect(person.title_previously_changed?).to be(false)
1317
+ end
1318
+ end
1319
+ end
1320
+
1321
+ describe '#previous_change' do
1322
+
1323
+ let(:person) do
1324
+ Person.new(title: "Grand Poobah")
1325
+ end
1326
+
1327
+ before do
1328
+ person.title = "Captain Obvious"
1329
+ end
1330
+
1331
+ context "when the document has been saved" do
1332
+
1333
+ before do
1334
+ person.save!
1335
+ end
1336
+
1337
+ it "returns the changes" do
1338
+ expect(person.title_previous_change).to eq([ nil, "Captain Obvious" ])
1339
+ end
1340
+ end
1341
+
1342
+ context "when the document has not been saved" do
1343
+
1344
+ it "returns no changes" do
1345
+ expect(person.title_previous_change).to eq(nil)
1346
+ end
1347
+ end
1348
+ end
1349
+
1292
1350
  context "when fields have been defined pre-dirty inclusion" do
1293
1351
 
1294
1352
  let(:document) do
@@ -36,10 +36,6 @@ describe Mongoid::Clients::Factory do
36
36
  it "sets the cluster's seeds" do
37
37
  expect(cluster.addresses.first.to_s).to eq("127.0.0.1:27017")
38
38
  end
39
-
40
- it "sets the platform to Mongoid's platform constant" do
41
- expect(client.options[:platform]).to eq(Mongoid::PLATFORM_DETAILS)
42
- end
43
39
  end
44
40
 
45
41
  context "when the configuration has no ports" do
@@ -120,8 +116,8 @@ describe Mongoid::Clients::Factory do
120
116
 
121
117
  let(:config) do
122
118
  {
123
- default: { hosts: [ "127.0.0.1:30000" ], database: database_id },
124
- secondary: { uri: "mongodb://127.0.0.1:30000,127.0.0.1:30001/mongoid_test" }
119
+ default: { hosts: [ "127.0.0.1:27017" ], database: database_id },
120
+ secondary: { uri: "mongodb://127.0.0.1:27017,127.0.0.1:27018/mongoid_test" }
125
121
  }
126
122
  end
127
123
 
@@ -146,7 +142,7 @@ describe Mongoid::Clients::Factory do
146
142
  end
147
143
 
148
144
  it "sets the cluster's seeds" do
149
- expect(seeds).to eq([ "127.0.0.1:30000", "127.0.0.1:30001" ])
145
+ expect(seeds).to eq([ "127.0.0.1:27017", "127.0.0.1:27018" ])
150
146
  end
151
147
  end
152
148
  end
@@ -284,9 +280,5 @@ describe Mongoid::Clients::Factory do
284
280
  it "sets the write concern" do
285
281
  expect(client.write_concern).to be_a(Mongo::WriteConcern::Acknowledged)
286
282
  end
287
-
288
- it "sets the platform to Mongoid's platform constant" do
289
- expect(client.options[:platform]).to eq(Mongoid::PLATFORM_DETAILS)
290
- end
291
283
  end
292
284
  end
@@ -2,185 +2,467 @@ require "spec_helper"
2
2
 
3
3
  describe Mongoid::Clients::Options do
4
4
 
5
- describe "#with", if: non_legacy_server? do
5
+ describe '#with', if: non_legacy_server? do
6
6
 
7
- context "when passing some options" do
7
+ context 'when passing some options' do
8
8
 
9
- let(:options) { { database: 'test' } }
10
-
11
- let!(:cluster) do
12
- Band.mongo_client.cluster
9
+ let(:persistence_context) do
10
+ Band.with(options) do |klass|
11
+ klass.persistence_context
12
+ end
13
13
  end
14
14
 
15
- let!(:klass) do
16
- Band.with(options)
15
+ let(:options) { { database: 'other' } }
16
+
17
+ it 'sets the options on the client' do
18
+ expect(persistence_context.client.options['database']).to eq(options[:database])
17
19
  end
18
20
 
19
- it "sets the options into the class" do
20
- expect(klass.persistence_options).to eq(options)
21
+ it 'does not set the options on class level' do
22
+ expect(Band.persistence_context.client.options['database']).to eq('mongoid_test')
21
23
  end
22
24
 
23
- it "sets the options into the instance" do
24
- expect(klass.new.persistence_options).to eq(options)
25
+ context 'when the options are not valid mongo client options' do
26
+
27
+ let(:persistence_context) do
28
+ Band.with(invalid_options) do |klass|
29
+ klass.persistence_context
30
+ end
31
+ end
32
+
33
+ let(:invalid_options) { { bad: 'option' } }
34
+
35
+ it 'raises an error' do
36
+ expect {
37
+ persistence_context
38
+ }.to raise_exception(Mongoid::Errors::InvalidPersistenceOption)
39
+ end
40
+
41
+ it 'clears the persistence context' do
42
+ begin; persistence_context; rescue Mongoid::Errors::InvalidPersistenceOption; end
43
+ expect(Band.persistence_context).to eq(Mongoid::PersistenceContext.new(Band))
44
+ end
25
45
  end
26
46
 
27
- it "doesnt set the options on class level" do
28
- expect(Band.new.persistence_options).to be_nil
47
+ context 'when the options include a collection' do
48
+
49
+ let(:options) { { collection: 'another-collection' } }
50
+
51
+ it 'uses the collection' do
52
+ expect(persistence_context.collection_name).to eq(options[:collection].to_sym)
53
+ expect(persistence_context.collection.name).to eq(options[:collection])
54
+ end
55
+
56
+ it 'does not raise an error' do
57
+ expect(persistence_context.client).to be_a(Mongo::Client)
58
+ end
59
+
60
+ it 'does not include the collection option in the client options' do
61
+ expect(persistence_context.client.options[:collection]).to be_nil
62
+ expect(persistence_context.client.options['collection']).to be_nil
63
+ end
29
64
  end
30
65
 
31
- context 'when passed a block', if: testing_locally? do
66
+ context 'when passing a block', if: testing_locally? do
32
67
 
33
68
  let!(:connections_before) do
34
69
  Band.mongo_client.database.command(serverStatus: 1).first['connections']['current']
35
70
  end
36
71
 
37
- it "can return results" do
38
- Band.create(name: 'emily')
39
- result = Band.with(:read => {:mode => :secondary_preferred}) do |klass|
72
+ let!(:connections_and_cluster_during) do
73
+ connections = nil
74
+ cluster = Band.with(options) do |klass|
40
75
  klass.where(name: 'emily').to_a
76
+ connections = Band.mongo_client.database.command(serverStatus: 1).first['connections']['current']
41
77
  end
42
- expect(result.length).to eq(1)
43
- expect(result.first.name).to eq('emily')
78
+ [ connections, cluster ]
44
79
  end
45
80
 
46
- before do
47
- Band.with(options) do |klass|
48
- klass.where(name: 'emily').to_a
49
- end
81
+ let(:connections_during) do
82
+ connections_and_cluster_during[0]
83
+ end
84
+
85
+ let(:cluster_during) do
86
+ connections_and_cluster_during[1]
50
87
  end
51
88
 
52
89
  let(:connections_after) do
53
90
  Band.mongo_client.database.command(serverStatus: 1).first['connections']['current']
54
91
  end
55
92
 
56
- context 'when a new cluster is created by the driver' do
93
+ let!(:cluster_before) do
94
+ Band.persistence_context.cluster
95
+ end
57
96
 
58
- let(:options) { { connect_timeout: 2 } }
97
+ let(:cluster_after) do
98
+ Band.persistence_context.cluster
99
+ end
59
100
 
60
- it 'disconnects the new cluster' do
61
- expect(connections_after).to eq(connections_before)
101
+ context 'when the options create a new cluster' do
102
+
103
+ let(:options) do
104
+ { connect_timeout: 2 }
105
+ end
106
+
107
+ it 'creates a new cluster' do
108
+ expect(connections_before).to be <(connections_during)
109
+ expect(cluster_before).not_to be(cluster_during)
110
+ end
111
+
112
+ it 'disconnects the new cluster when the block exits' do
113
+ expect(connections_before).to eq(connections_after)
62
114
  end
63
115
  end
64
116
 
65
- context 'when the same cluster is used by the new client' do
117
+ context 'when the options do not create a new cluster' do
66
118
 
67
- let(:options) { { database: 'same-cluster' } }
119
+ let(:options) do
120
+ { database: 'same-cluster' }
121
+ end
122
+
123
+ it 'does not create a new cluster' do
124
+ expect(connections_during).to eq(connections_before)
125
+ end
68
126
 
69
127
  it 'does not disconnect the original cluster' do
70
128
  expect(connections_after).to eq(connections_before)
129
+ expect(cluster_before).to be(cluster_after)
130
+ end
131
+ end
132
+
133
+ context 'when the client options were configured using a uri' do
134
+
135
+ let(:config) do
136
+ {
137
+ default: { hosts: [ "127.0.0.1:27017" ], database: database_id },
138
+ secondary: { uri: "mongodb://127.0.0.1:27017/secondary-db?connectTimeoutMS=3000" }
139
+ }
140
+ end
141
+
142
+ before do
143
+ Mongoid::Config.send(:clients=, config)
144
+ end
145
+
146
+ let(:persistence_context) do
147
+ Band.with(client: :secondary) do |klass|
148
+ klass.persistence_context
149
+ end
150
+ end
151
+
152
+ it 'uses the database specified in the uri' do
153
+ expect(persistence_context.database_name).to eq('secondary-db')
154
+ expect(persistence_context.client.database.name).to eq('secondary-db')
155
+ end
156
+
157
+ it 'uses the options specified in the uri' do
158
+ expect(persistence_context.client.options[:connect_timeout]).to eq(3)
71
159
  end
72
160
  end
73
161
  end
74
162
 
75
- context "when calling .collection method" do
163
+ context 'when changing the collection' do
76
164
 
77
- before do
78
- klass.collection
165
+ let(:options) do
166
+ { collection: 'other' }
79
167
  end
80
168
 
81
- it "keeps the options" do
82
- expect(klass.persistence_options).to eq(options)
169
+ it 'uses that collection' do
170
+ expect(persistence_context.collection.name).to eq(options[:collection])
83
171
  end
172
+ end
84
173
 
85
- context 'when changing the collection' do
174
+ context 'when returning a criteria' do
86
175
 
87
- let(:options) do
88
- { collection: 'other' }
176
+ let(:context_and_criteria) do
177
+ collection = nil
178
+ cxt = Band.with(read: :secondary) do |klass|
179
+ collection = klass.all.collection
180
+ klass.persistence_context
89
181
  end
182
+ [ cxt, collection ]
183
+ end
90
184
 
91
- it 'uses that collection' do
92
- expect(klass.collection.name).to eq(options[:collection])
93
- end
185
+ let(:persistence_context) do
186
+ context_and_criteria[0]
187
+ end
188
+
189
+ let(:client) do
190
+ context_and_criteria[1].client
191
+ end
192
+
193
+ it 'applies the options to the criteria client' do
194
+ expect(client.options['read']).to eq(:secondary)
94
195
  end
95
196
  end
96
197
 
97
- context "when returning a criteria" do
198
+ context 'when the object is shared between threads' do
98
199
 
99
- let(:criteria) do
100
- klass.all
200
+ before do
201
+ threads = []
202
+ 100.times do |i|
203
+ threads << Thread.new do
204
+ if i % 2 == 0
205
+ Band.with(collection: 'British') do |klass|
206
+ klass.create(name: 'realised')
207
+ end
208
+ else
209
+ Band.with(collection: 'American') do |klass|
210
+ klass.create(name: 'realized')
211
+ end
212
+ end
213
+ end
214
+ end
215
+ threads.collect { |t| t.value }
101
216
  end
102
217
 
103
- it "sets the options into the criteria object" do
104
- expect(criteria.persistence_options).to eq(options)
218
+ let(:british_count) do
219
+ Band.with(collection: 'British') do |klass|
220
+ klass.all.count
221
+ end
105
222
  end
106
223
 
107
- it "doesnt set the options on class level" do
108
- expect(Band.new.persistence_options).to be_nil
224
+ let(:american_count) do
225
+ Band.with(collection: 'American') do |klass|
226
+ klass.all.count
227
+ end
228
+ end
229
+
230
+ it "does not share the persistence options" do
231
+ expect(british_count).to eq(50)
232
+ expect(american_count).to eq(50)
109
233
  end
110
234
  end
111
235
  end
112
- end
113
236
 
114
- describe ".with", if: non_legacy_server? do
237
+ context 'when passing a persistence context' do
115
238
 
116
- let(:options) { { database: 'test' } }
239
+ let(:instance) do
240
+ Band.new
241
+ end
117
242
 
118
- let(:instance) do
119
- Band.new.with(options)
120
- end
243
+ let(:persistence_context) do
244
+ instance.with(options) do |inst|
245
+ inst.persistence_context
246
+ end
247
+ end
121
248
 
122
- it "sets the options into" do
123
- expect(instance.persistence_options).to eq(options)
124
- end
249
+ let(:options) { { database: 'other' } }
125
250
 
126
- it "passes down the options to collection" do
127
- expect(instance.collection.database.name).to eq('test')
251
+ it 'sets the persistence context on the object' do
252
+ Band.new.with(persistence_context) do |band_instance|
253
+ expect(band_instance.persistence_context.options).to eq(persistence_context.options)
254
+ end
255
+ end
128
256
  end
257
+ end
129
258
 
130
- context "when the object is shared between threads" do
131
-
132
- before do
133
- threads = []
134
- doc = Band.create(name: "Beatles")
135
- 100.times do |i|
136
- threads << Thread.new do
137
- if i % 2 == 0
138
- doc.with(nil).set(name: "Rolling Stones")
139
- else
140
- doc.with(options).set(name: "Beatles")
141
- end
259
+ describe '.with', if: non_legacy_server? do
260
+
261
+ context 'when passing some options' do
262
+
263
+ let(:options) do
264
+ { database: 'other' }
265
+ end
266
+
267
+ let(:band) do
268
+ Band.create
269
+ end
270
+
271
+ let(:persistence_context) do
272
+ band.with(options) do |object|
273
+ object.persistence_context
274
+ end
275
+ end
276
+
277
+ it 'sets the options on the client' do
278
+ expect(persistence_context.client.options['database']).to eq(options[:database])
279
+ end
280
+
281
+ it 'does not set the options on instance level' do
282
+ expect(band.persistence_context.client.database.name).to eq('mongoid_test')
283
+ end
284
+
285
+ context 'when the options are not valid mongo client options' do
286
+
287
+ let(:persistence_context) do
288
+ band.with(invalid_options) do |object|
289
+ object.persistence_context
142
290
  end
143
291
  end
144
- threads.join
292
+
293
+ let(:invalid_options) { { bad: 'option' } }
294
+
295
+ it 'raises an error' do
296
+ expect {
297
+ persistence_context
298
+ }.to raise_exception(Mongoid::Errors::InvalidPersistenceOption)
299
+ end
300
+
301
+ it 'clears the persistence context' do
302
+ begin; persistence_context; rescue Mongoid::Errors::InvalidPersistenceOption; end
303
+ expect(band.persistence_context).to eq(Mongoid::PersistenceContext.new(band))
304
+ end
145
305
  end
146
306
 
147
- it "does not share the persistence options" do
148
- expect(Band.persistence_options).to eq(nil)
307
+ context 'when the client options were configured using a uri' do
308
+
309
+ let(:config) do
310
+ {
311
+ default: { hosts: [ "127.0.0.1:27017" ], database: database_id },
312
+ secondary: { uri: "mongodb://127.0.0.1:27017/secondary-db" }
313
+ }
314
+ end
315
+
316
+ before do
317
+ Mongoid::Config.send(:clients=, config)
318
+ end
319
+
320
+ let(:persistence_context) do
321
+ band.with(client: :secondary) do |object|
322
+ object.persistence_context
323
+ end
324
+ end
325
+
326
+ it 'uses the database specified in the uri' do
327
+ expect(persistence_context.database_name).to eq('secondary-db')
328
+ expect(persistence_context.client.database.name).to eq('secondary-db')
329
+ end
149
330
  end
150
- end
151
- end
152
331
 
153
- describe "#persistence_options" do
332
+ context 'when passing a block', if: testing_locally? do
154
333
 
155
- it "touches the thread local" do
156
- expect(Thread.current).to receive(:[]).with("[mongoid][Band]:persistence-options").and_return({foo: :bar})
157
- expect(Band.persistence_options).to eq({foo: :bar})
158
- end
334
+ let!(:connections_before) do
335
+ band.mongo_client.database.command(serverStatus: 1).first['connections']['current']
336
+ end
159
337
 
160
- it "cannot force a value on thread local" do
161
- expect {
162
- Band.set_persistence_options(Band, {})
163
- }.to raise_error(NoMethodError)
164
- end
165
- end
338
+ let!(:connections_and_cluster_during) do
339
+ connections = nil
340
+ cluster = band.with(options) do |b|
341
+ b.reload
342
+ connections = band.mongo_client.database.command(serverStatus: 1).first['connections']['current']
343
+ b.persistence_context.cluster
344
+ end
345
+ [ connections, cluster ]
346
+ end
166
347
 
167
- describe ".persistence_options" do
348
+ let(:connections_during) do
349
+ connections_and_cluster_during[0]
350
+ end
351
+
352
+ let(:cluster_during) do
353
+ connections_and_cluster_during[1]
354
+ end
355
+
356
+ let(:connections_after) do
357
+ band.mongo_client.database.command(serverStatus: 1).first['connections']['current']
358
+ end
359
+
360
+ let!(:cluster_before) do
361
+ band.persistence_context.cluster
362
+ end
363
+
364
+ let(:cluster_after) do
365
+ band.persistence_context.cluster
366
+ end
168
367
 
169
- context "when options exist on the current thread" do
368
+ context 'when the options create a new cluster' do
170
369
 
171
- let(:klass) do
172
- Band.with(write: { w: 2 })
370
+ let(:options) do
371
+ { connect_timeout: 2 }
372
+ end
373
+
374
+ it 'creates a new cluster' do
375
+ expect(connections_before).to be <(connections_during)
376
+ expect(cluster_before).not_to be(cluster_during)
377
+ end
378
+
379
+ it 'disconnects the new cluster when the block exits' do
380
+ expect(connections_before).to eq(connections_after)
381
+ end
382
+ end
383
+
384
+ context 'when the options do not create a new cluster' do
385
+
386
+ let(:options) { { read: :secondary } }
387
+
388
+ it 'does not create a new cluster' do
389
+ expect(connections_during).to eq(connections_before)
390
+ end
391
+
392
+ it 'does not disconnect the original cluster' do
393
+ expect(connections_after).to eq(connections_before)
394
+ expect(cluster_before).to be(cluster_after)
395
+ end
396
+ end
397
+ end
398
+
399
+ context 'when changing the collection' do
400
+
401
+ let(:options) do
402
+ { collection: 'other' }
403
+ end
404
+
405
+ it 'uses that collection' do
406
+ expect(persistence_context.collection.name).to eq(options[:collection])
407
+ end
173
408
  end
174
409
 
175
- it "returns the options" do
176
- expect(klass.persistence_options).to eq(write: { w: 2 })
410
+ context 'when the object is shared between threads' do
411
+
412
+ before do
413
+ threads = []
414
+ 100.times do |i|
415
+ band = Band.create
416
+ threads << Thread.new do
417
+ if i % 2 == 0
418
+ band.with(collection: 'British') do |b|
419
+ b.name = 'realised'
420
+ b.upsert
421
+ end
422
+ else
423
+ band.with(collection: 'American') do |b|
424
+ b.name = 'realized'
425
+ b.upsert
426
+ end
427
+ end
428
+ end
429
+ end
430
+ threads.collect { |t| t.value }
431
+ end
432
+
433
+ let(:british_count) do
434
+ Band.with(collection: 'British') do |klass|
435
+ klass.all.count
436
+ end
437
+ end
438
+
439
+ let(:american_count) do
440
+ Band.with(collection: 'British') do |klass|
441
+ klass.all.count
442
+ end
443
+ end
444
+
445
+ it 'does not share the persistence options' do
446
+ expect(british_count).to eq(50)
447
+ expect(american_count).to eq(50)
448
+ end
177
449
  end
178
450
  end
179
451
 
180
- context "when there are no options on the current thread" do
452
+ context 'when passing a persistence context' do
181
453
 
182
- it "returns nil" do
183
- expect(Band.persistence_options).to be_nil
454
+ let(:persistence_context) do
455
+ Band.with(options) do |klass|
456
+ klass.persistence_context
457
+ end
458
+ end
459
+
460
+ let(:options) { { database: 'other' } }
461
+
462
+ it 'sets the persistence context on the object' do
463
+ Band.with(persistence_context) do |band_class|
464
+ expect(band_class.persistence_context.options).to eq(persistence_context.options)
465
+ end
184
466
  end
185
467
  end
186
468
  end