mongoid 4.0.0.alpha2 → 4.0.0.beta1

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -0
  3. data/README.md +3 -3
  4. data/lib/config/locales/en.yml +13 -0
  5. data/lib/mongoid.rb +3 -1
  6. data/lib/mongoid/atomic.rb +1 -1
  7. data/lib/mongoid/atomic/paths/embedded/many.rb +1 -1
  8. data/lib/mongoid/atomic/paths/embedded/one.rb +1 -1
  9. data/lib/mongoid/attributes.rb +23 -1
  10. data/lib/mongoid/attributes/processing.rb +1 -1
  11. data/lib/mongoid/composable.rb +3 -2
  12. data/lib/mongoid/contextual/command.rb +0 -26
  13. data/lib/mongoid/contextual/geo_near.rb +1 -1
  14. data/lib/mongoid/contextual/mongo.rb +6 -29
  15. data/lib/mongoid/contextual/text_search.rb +3 -5
  16. data/lib/mongoid/criteria.rb +1 -1
  17. data/lib/mongoid/criteria/modifiable.rb +27 -7
  18. data/lib/mongoid/criteria/permission.rb +70 -0
  19. data/lib/mongoid/document.rb +5 -6
  20. data/lib/mongoid/errors.rb +2 -0
  21. data/lib/mongoid/errors/document_not_destroyed.rb +25 -0
  22. data/lib/mongoid/errors/readonly_document.rb +24 -0
  23. data/lib/mongoid/extensions/boolean.rb +1 -0
  24. data/lib/mongoid/extensions/hash.rb +1 -1
  25. data/lib/mongoid/factory.rb +5 -3
  26. data/lib/mongoid/fields.rb +32 -0
  27. data/lib/mongoid/fields/localized.rb +1 -1
  28. data/lib/mongoid/fields/standard.rb +1 -1
  29. data/lib/mongoid/findable.rb +1 -0
  30. data/lib/mongoid/interceptable.rb +11 -6
  31. data/lib/mongoid/log_subscriber.rb +34 -1
  32. data/lib/mongoid/persistable/deletable.rb +1 -0
  33. data/lib/mongoid/persistable/destroyable.rb +7 -2
  34. data/lib/mongoid/persistable/updatable.rb +27 -26
  35. data/lib/mongoid/query_cache.rb +246 -0
  36. data/lib/mongoid/railties/database.rake +4 -26
  37. data/lib/mongoid/relations.rb +8 -22
  38. data/lib/mongoid/relations/accessors.rb +0 -3
  39. data/lib/mongoid/relations/binding.rb +1 -1
  40. data/lib/mongoid/relations/bindings/embedded/in.rb +1 -1
  41. data/lib/mongoid/relations/eager.rb +5 -6
  42. data/lib/mongoid/relations/eager/base.rb +97 -5
  43. data/lib/mongoid/relations/eager/belongs_to.rb +1 -0
  44. data/lib/mongoid/relations/eager/has_and_belongs_to_many.rb +16 -9
  45. data/lib/mongoid/relations/eager/has_many.rb +1 -0
  46. data/lib/mongoid/relations/eager/has_one.rb +1 -0
  47. data/lib/mongoid/relations/embedded/batchable.rb +1 -1
  48. data/lib/mongoid/relations/embedded/in.rb +4 -4
  49. data/lib/mongoid/relations/embedded/many.rb +7 -5
  50. data/lib/mongoid/relations/embedded/one.rb +1 -1
  51. data/lib/mongoid/relations/macros.rb +1 -0
  52. data/lib/mongoid/relations/marshalable.rb +3 -3
  53. data/lib/mongoid/relations/proxy.rb +12 -10
  54. data/lib/mongoid/relations/referenced/in.rb +2 -2
  55. data/lib/mongoid/relations/referenced/many.rb +9 -9
  56. data/lib/mongoid/relations/referenced/many_to_many.rb +7 -7
  57. data/lib/mongoid/relations/referenced/one.rb +4 -4
  58. data/lib/mongoid/{state.rb → stateful.rb} +13 -1
  59. data/lib/mongoid/tasks/database.rake +31 -0
  60. data/lib/mongoid/tasks/database.rb +107 -0
  61. data/lib/mongoid/threaded.rb +0 -47
  62. data/lib/mongoid/validatable/uniqueness.rb +4 -16
  63. data/lib/mongoid/version.rb +1 -1
  64. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +0 -3
  65. data/lib/rails/mongoid.rb +0 -124
  66. data/spec/app/models/edit.rb +5 -0
  67. data/spec/app/models/even.rb +7 -0
  68. data/spec/app/models/line_item.rb +1 -1
  69. data/spec/app/models/note.rb +2 -0
  70. data/spec/app/models/odd.rb +7 -0
  71. data/spec/app/models/record.rb +5 -0
  72. data/spec/app/models/wiki_page.rb +1 -1
  73. data/spec/mongoid/attributes_spec.rb +76 -1
  74. data/spec/mongoid/changeable_spec.rb +6 -2
  75. data/spec/mongoid/contextual/mongo_spec.rb +3 -1
  76. data/spec/mongoid/contextual/text_search_spec.rb +3 -1
  77. data/spec/mongoid/criteria/modifiable_spec.rb +192 -0
  78. data/spec/mongoid/criteria_spec.rb +6 -2
  79. data/spec/mongoid/errors/document_not_destroyed_spec.rb +33 -0
  80. data/spec/mongoid/errors/readonly_document_spec.rb +29 -0
  81. data/spec/mongoid/fields/localized_spec.rb +15 -0
  82. data/spec/mongoid/fields_spec.rb +88 -2
  83. data/spec/mongoid/log_subscriber_spec.rb +3 -3
  84. data/spec/mongoid/persistable/deletable_spec.rb +14 -1
  85. data/spec/mongoid/persistable/destroyable_spec.rb +45 -1
  86. data/spec/mongoid/persistable/savable_spec.rb +34 -5
  87. data/spec/mongoid/query_cache_spec.rb +197 -0
  88. data/spec/mongoid/relations/bindings/embedded/in_spec.rb +2 -2
  89. data/spec/mongoid/relations/builders/referenced/many_spec.rb +1 -1
  90. data/spec/mongoid/relations/eager/has_and_belongs_to_many_spec.rb +11 -37
  91. data/spec/mongoid/relations/eager/has_one_spec.rb +1 -1
  92. data/spec/mongoid/relations/embedded/in_spec.rb +1 -1
  93. data/spec/mongoid/relations/embedded/many_spec.rb +10 -10
  94. data/spec/mongoid/relations/embedded/one_spec.rb +10 -2
  95. data/spec/mongoid/relations/referenced/in_spec.rb +1 -1
  96. data/spec/mongoid/relations/referenced/many_spec.rb +37 -2
  97. data/spec/mongoid/relations/touchable_spec.rb +20 -0
  98. data/spec/mongoid/{state_spec.rb → stateful_spec.rb} +26 -1
  99. data/spec/mongoid/tasks/database_rake_spec.rb +285 -0
  100. data/spec/mongoid/tasks/database_spec.rb +148 -0
  101. data/spec/mongoid/validatable/uniqueness_spec.rb +7 -0
  102. data/spec/rails/mongoid_spec.rb +0 -316
  103. data/spec/spec_helper.rb +1 -0
  104. metadata +30 -8
@@ -178,6 +178,21 @@ describe Mongoid::Fields::Localized do
178
178
  end
179
179
  end
180
180
 
181
+ context "when no type is provided" do
182
+
183
+ let(:field) do
184
+ described_class.new(:description, localize: true)
185
+ end
186
+
187
+ let(:value) do
188
+ field.demongoize({ "en" => false })
189
+ end
190
+
191
+ it "allows booleans to be returned" do
192
+ expect(value).to eq(false)
193
+ end
194
+ end
195
+
181
196
  context "when the type is not a string" do
182
197
 
183
198
  let(:field) do
@@ -309,6 +309,92 @@ describe Mongoid::Fields do
309
309
  end
310
310
  end
311
311
 
312
+ context "when providing a root Boolean type" do
313
+
314
+ let(:klass) do
315
+ Class.new do
316
+ include Mongoid::Document
317
+ end
318
+ end
319
+
320
+ it "converts to Mongoid::Boolean" do
321
+ expect(klass.field(:test, type: Boolean).type).to be(Mongoid::Boolean)
322
+ end
323
+ end
324
+
325
+ context "when using symbol types" do
326
+
327
+ let(:klass) do
328
+ Class.new do
329
+ include Mongoid::Document
330
+ end
331
+ end
332
+
333
+ it "converts :array to Array" do
334
+ expect(klass.field(:test, type: :array).type).to be(Array)
335
+ end
336
+
337
+ it "converts :big_decimal to BigDecimal" do
338
+ expect(klass.field(:test, type: :big_decimal).type).to be(BigDecimal)
339
+ end
340
+
341
+ it "converts :binary to BSON::Binary" do
342
+ expect(klass.field(:test, type: :binary).type).to be(BSON::Binary)
343
+ end
344
+
345
+ it "converts :boolean to Mongoid::Boolean" do
346
+ expect(klass.field(:test, type: :boolean).type).to be(Mongoid::Boolean)
347
+ end
348
+
349
+ it "converts :date to Date" do
350
+ expect(klass.field(:test, type: :date).type).to be(Date)
351
+ end
352
+
353
+ it "converts :date_time to DateTime" do
354
+ expect(klass.field(:test, type: :date_time).type).to be(DateTime)
355
+ end
356
+
357
+ it "converts :float to Float" do
358
+ expect(klass.field(:test, type: :float).type).to be(Float)
359
+ end
360
+
361
+ it "converts :hash to Hash" do
362
+ expect(klass.field(:test, type: :hash).type).to be(Hash)
363
+ end
364
+
365
+ it "converts :integer to Integer" do
366
+ expect(klass.field(:test, type: :integer).type).to be(Integer)
367
+ end
368
+
369
+ it "converts :object_id to BSON::ObjectId" do
370
+ expect(klass.field(:test, type: :object_id).type).to be(BSON::ObjectId)
371
+ end
372
+
373
+ it "converts :range to Range" do
374
+ expect(klass.field(:test, type: :range).type).to be(Range)
375
+ end
376
+
377
+ it "converts :regexp to Rexegp" do
378
+ expect(klass.field(:test, type: :regexp).type).to be(Regexp)
379
+ end
380
+
381
+ it "converts :set to Set" do
382
+ expect(klass.field(:test, type: :set).type).to be(Set)
383
+ end
384
+
385
+ it "converts :string to String" do
386
+ expect(klass.field(:test, type: :string).type).to be(String)
387
+ end
388
+
389
+ it "converts :symbol to Symbol" do
390
+ expect(klass.field(:test, type: :symbol).type).to be(Symbol)
391
+ end
392
+
393
+ it "converts :time to Time" do
394
+ expect(klass.field(:test, type: :time).type).to be(Time)
395
+ end
396
+ end
397
+
312
398
  context "when the options are valid" do
313
399
 
314
400
  context "when the options are all standard" do
@@ -729,11 +815,11 @@ describe Mongoid::Fields do
729
815
 
730
816
  context "when the field name conflicts with mongoid's internals" do
731
817
 
732
- context "when the field is named metadata" do
818
+ context "when the field is named __metadata" do
733
819
 
734
820
  it "raises an error" do
735
821
  expect {
736
- Person.field(:metadata)
822
+ Person.field(:__metadata)
737
823
  }.to raise_error(Mongoid::Errors::InvalidField)
738
824
  end
739
825
  end
@@ -54,15 +54,15 @@ describe Mongoid::LogSubscriber do
54
54
  TestLogSubscriber.log_subscribers.pop
55
55
  end
56
56
 
57
- it "pushes 2 log subscribers" do
58
- expect(Mongoid::LogSubscriber.subscribers.size).to eq(2)
57
+ it "pushes the new log subscriber" do
58
+ expect(Mongoid::LogSubscriber.subscribers.last).to be_a TestLogSubscriber
59
59
  end
60
60
 
61
61
  context "when quering the database" do
62
62
 
63
63
  before do
64
64
  expect(subscribe).to receive(:debug).once
65
- Band.all.to_a
65
+ PetOwner.all.to_a
66
66
  end
67
67
 
68
68
  it "sends operations logs to TestLogSubscriber" do
@@ -4,10 +4,23 @@ describe Mongoid::Persistable::Deletable do
4
4
 
5
5
  describe "#delete" do
6
6
 
7
- let(:person) do
7
+ let!(:person) do
8
8
  Person.create
9
9
  end
10
10
 
11
+ context "when deleting a readonly document" do
12
+
13
+ let(:from_db) do
14
+ Person.only(:_id).first
15
+ end
16
+
17
+ it "raises an error" do
18
+ expect {
19
+ from_db.delete
20
+ }.to raise_error(Mongoid::Errors::ReadonlyDocument)
21
+ end
22
+ end
23
+
11
24
  context "when removing a root document" do
12
25
 
13
26
  let!(:deleted) do
@@ -4,10 +4,23 @@ describe Mongoid::Persistable::Destroyable do
4
4
 
5
5
  describe "#destroy" do
6
6
 
7
- let(:person) do
7
+ let!(:person) do
8
8
  Person.create
9
9
  end
10
10
 
11
+ context "when destroying a readonly document" do
12
+
13
+ let(:from_db) do
14
+ Person.only(:_id).first
15
+ end
16
+
17
+ it "raises an error" do
18
+ expect {
19
+ from_db.destroy
20
+ }.to raise_error(Mongoid::Errors::ReadonlyDocument)
21
+ end
22
+ end
23
+
11
24
  context "when removing a root document" do
12
25
 
13
26
  let!(:destroyd) do
@@ -102,6 +115,37 @@ describe Mongoid::Persistable::Destroyable do
102
115
  end
103
116
  end
104
117
 
118
+ describe "#destroy!" do
119
+
120
+ context "when no validation callback returns false" do
121
+
122
+ let(:person) do
123
+ Person.create
124
+ end
125
+
126
+ it "returns true" do
127
+ expect(person.destroy!).to eq(true)
128
+ end
129
+ end
130
+
131
+ context "when a validation callback returns false" do
132
+
133
+ let(:album) do
134
+ Album.create
135
+ end
136
+
137
+ before do
138
+ expect(album).to receive(:set_parent_name).and_return(false)
139
+ end
140
+
141
+ it "raises an exception" do
142
+ expect {
143
+ album.destroy!
144
+ }.to raise_error(Mongoid::Errors::DocumentNotDestroyed)
145
+ end
146
+ end
147
+ end
148
+
105
149
  describe "#destroy_all" do
106
150
 
107
151
  let!(:person) do
@@ -94,11 +94,6 @@ describe Mongoid::Persistable::Savable do
94
94
  it "does not flag the excluded fields as dirty" do
95
95
  expect(limited.changes).to be_empty
96
96
  end
97
-
98
- it "does not overwrite with the default" do
99
- limited.save
100
- expect(limited.reload.age).to eq(20)
101
- end
102
97
  end
103
98
 
104
99
  context "when iterating over the documents" do
@@ -273,6 +268,23 @@ describe Mongoid::Persistable::Savable do
273
268
  end
274
269
  end
275
270
  end
271
+
272
+ context "when the document is readonly" do
273
+
274
+ let(:person) do
275
+ Person.only(:title).first
276
+ end
277
+
278
+ before do
279
+ Person.create(title: "sir")
280
+ end
281
+
282
+ it "raises an error" do
283
+ expect {
284
+ person.save
285
+ }.to raise_error(Mongoid::Errors::ReadonlyDocument)
286
+ end
287
+ end
276
288
  end
277
289
 
278
290
  describe "save!" do
@@ -428,5 +440,22 @@ describe Mongoid::Persistable::Savable do
428
440
  expect(from_db.shapes.first.canvas).to eq(firefox)
429
441
  end
430
442
  end
443
+
444
+ context "when the document is readonly" do
445
+
446
+ let(:person) do
447
+ Person.only(:title).first
448
+ end
449
+
450
+ before do
451
+ Person.create(title: "sir")
452
+ end
453
+
454
+ it "raises an error" do
455
+ expect {
456
+ person.save!
457
+ }.to raise_error(Mongoid::Errors::ReadonlyDocument)
458
+ end
459
+ end
431
460
  end
432
461
  end
@@ -0,0 +1,197 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::QueryCache do
4
+
5
+ around do |spec|
6
+ Mongoid::QueryCache.clear_cache
7
+ Mongoid::QueryCache.cache { spec.run }
8
+ end
9
+
10
+ context "when querying for a single document" do
11
+
12
+ [ :first, :one ].each do |method|
13
+
14
+ before do
15
+ Band.all.send(method)
16
+ end
17
+
18
+ context "when query cache disable" do
19
+
20
+ before do
21
+ Mongoid::QueryCache.enabled = false
22
+ end
23
+
24
+ it "queries again" do
25
+ expect_query(1) do
26
+ Band.all.send(method)
27
+ end
28
+ end
29
+ end
30
+
31
+ context "with same selector" do
32
+
33
+ it "does not query again" do
34
+ expect_no_queries do
35
+ Band.all.send(method)
36
+ end
37
+ end
38
+ end
39
+
40
+ context "with different selector" do
41
+
42
+ it "queries again" do
43
+ expect_query(1) do
44
+ Band.where(id: 1).send(method)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ context "when querying in the same collection" do
52
+
53
+ before do
54
+ Band.all.to_a
55
+ end
56
+
57
+ context "when query cache disable" do
58
+
59
+ before do
60
+ Mongoid::QueryCache.enabled = false
61
+ end
62
+
63
+ it "queries again" do
64
+ expect_query(1) do
65
+ Band.all.to_a
66
+ end
67
+ end
68
+ end
69
+
70
+ context "with same selector" do
71
+
72
+ it "does not query again" do
73
+ expect_no_queries do
74
+ Band.all.to_a
75
+ end
76
+ end
77
+ end
78
+
79
+ context "with different selector" do
80
+
81
+ it "queries again" do
82
+ expect_query(1) do
83
+ Band.where(id: 1).to_a
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ context "when querying in different collection" do
90
+
91
+ before do
92
+ Person.all.to_a
93
+ end
94
+
95
+ it "queries again" do
96
+ expect_query(1) do
97
+ Band.all.to_a
98
+ end
99
+ end
100
+ end
101
+
102
+ context "when inserting a new document" do
103
+
104
+ before do
105
+ Band.all.to_a
106
+ Band.create!
107
+ end
108
+
109
+ it "queries again" do
110
+ expect_query(1) do
111
+ Band.all.to_a
112
+ end
113
+ end
114
+ end
115
+
116
+ context "when deleting all documents" do
117
+
118
+ before do
119
+ Band.create!
120
+ Band.all.to_a
121
+ Band.delete_all
122
+ end
123
+
124
+ it "queries again" do
125
+ expect_query(1) do
126
+ Band.all.to_a
127
+ end
128
+ end
129
+ end
130
+
131
+ context "when destroying all documents" do
132
+
133
+ before do
134
+ Band.create!
135
+ Band.all.to_a
136
+ Band.destroy_all
137
+ end
138
+
139
+ it "queries again" do
140
+ expect_query(1) do
141
+ Band.all.to_a
142
+ end
143
+ end
144
+ end
145
+
146
+ context "when inserting an index" do
147
+
148
+ it "does not cache the query" do
149
+ expect(Mongoid::QueryCache).to receive(:cache_table).never
150
+ Band.collection.indexes.create(name: 1)
151
+ end
152
+ end
153
+ end
154
+
155
+ describe Mongoid::QueryCache::Middleware do
156
+
157
+ let :middleware do
158
+ Mongoid::QueryCache::Middleware.new(app)
159
+ end
160
+
161
+ context "when not touching mongoid on the app" do
162
+
163
+ let(:app) do
164
+ ->(env) { @enabled = Mongoid::QueryCache.enabled?; [200, env, "app"] }
165
+ end
166
+
167
+ it "returns success" do
168
+ code, _ = middleware.call({})
169
+ expect(code).to eq(200)
170
+ end
171
+
172
+ it "enableds the query cache" do
173
+ middleware.call({})
174
+ expect(@enabled).to be true
175
+ end
176
+ end
177
+
178
+ context "when querying on the app" do
179
+
180
+ let(:app) do
181
+ ->(env) {
182
+ Band.all.to_a
183
+ [200, env, "app"]
184
+ }
185
+ end
186
+
187
+ it "returns success" do
188
+ code, _ = middleware.call({})
189
+ expect(code).to eq(200)
190
+ end
191
+
192
+ it "cleans the query cache after reponds" do
193
+ middleware.call({})
194
+ expect(Mongoid::QueryCache.cache_table).to be_empty
195
+ end
196
+ end
197
+ end