mongodoc 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. data/Rakefile +21 -0
  2. data/TODO +6 -1
  3. data/VERSION +1 -1
  4. data/features/finders.feature +1 -1
  5. data/features/mongodoc_base.feature +11 -2
  6. data/features/{named_scopes.feature → scopes.feature} +0 -0
  7. data/features/step_definitions/document_steps.rb +15 -4
  8. data/features/step_definitions/documents.rb +3 -3
  9. data/features/step_definitions/query_steps.rb +17 -14
  10. data/features/step_definitions/{named_scope_steps.rb → scope_steps.rb} +0 -0
  11. data/features/using_criteria.feature +22 -43
  12. data/lib/mongodoc.rb +1 -1
  13. data/lib/mongodoc/associations/collection_proxy.rb +3 -1
  14. data/lib/mongodoc/associations/document_proxy.rb +4 -1
  15. data/lib/mongodoc/associations/hash_proxy.rb +3 -1
  16. data/lib/mongodoc/associations/proxy_base.rb +6 -4
  17. data/lib/mongodoc/attributes.rb +6 -6
  18. data/lib/mongodoc/contexts.rb +24 -0
  19. data/lib/mongodoc/contexts/enumerable.rb +132 -0
  20. data/lib/mongodoc/contexts/mongo.rb +215 -0
  21. data/lib/mongodoc/criteria.rb +36 -479
  22. data/lib/mongodoc/document.rb +3 -2
  23. data/lib/mongodoc/finders.rb +31 -11
  24. data/lib/mongodoc/matchers.rb +35 -0
  25. data/lib/mongodoc/scope.rb +64 -0
  26. data/lib/mongoid/contexts/paging.rb +42 -0
  27. data/lib/mongoid/criteria.rb +264 -0
  28. data/lib/mongoid/criterion/complex.rb +21 -0
  29. data/lib/mongoid/criterion/exclusion.rb +65 -0
  30. data/lib/mongoid/criterion/inclusion.rb +92 -0
  31. data/lib/mongoid/criterion/optional.rb +136 -0
  32. data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
  33. data/lib/mongoid/extensions/symbol/inflections.rb +36 -0
  34. data/lib/mongoid/matchers/all.rb +11 -0
  35. data/lib/mongoid/matchers/default.rb +26 -0
  36. data/lib/mongoid/matchers/exists.rb +13 -0
  37. data/lib/mongoid/matchers/gt.rb +11 -0
  38. data/lib/mongoid/matchers/gte.rb +11 -0
  39. data/lib/mongoid/matchers/in.rb +11 -0
  40. data/lib/mongoid/matchers/lt.rb +11 -0
  41. data/lib/mongoid/matchers/lte.rb +11 -0
  42. data/lib/mongoid/matchers/ne.rb +11 -0
  43. data/lib/mongoid/matchers/nin.rb +11 -0
  44. data/lib/mongoid/matchers/size.rb +11 -0
  45. data/mongodoc.gemspec +39 -9
  46. data/spec/attributes_spec.rb +16 -2
  47. data/spec/contexts/enumerable_spec.rb +335 -0
  48. data/spec/contexts/mongo_spec.rb +148 -0
  49. data/spec/contexts_spec.rb +28 -0
  50. data/spec/criteria_spec.rb +15 -766
  51. data/spec/finders_spec.rb +28 -36
  52. data/spec/matchers_spec.rb +342 -0
  53. data/spec/scope_spec.rb +79 -0
  54. metadata +40 -10
  55. data/features/step_definitions/criteria_steps.rb +0 -42
  56. data/lib/mongodoc/named_scope.rb +0 -68
  57. data/spec/named_scope_spec.rb +0 -82
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Matchers #:nodoc:
4
+ class In < Default
5
+ # Return true if the attribute is in the values.
6
+ def matches?(value)
7
+ value.values.first.include?(@attribute)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Matchers #:nodoc:
4
+ class Lt < Default
5
+ # Return true if the attribute is less than the value.
6
+ def matches?(value)
7
+ determine(value, :<)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Matchers #:nodoc:
4
+ class Lte < Default
5
+ # Return true if the attribute is less than or equal to the value.
6
+ def matches?(value)
7
+ determine(value, :<=)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Matchers #:nodoc:
4
+ class Ne < Default
5
+ # Return true if the attribute and first value are not equal.
6
+ def matches?(value)
7
+ @attribute != value.values.first
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Matchers #:nodoc:
4
+ class Nin < Default
5
+ # Return true if the attribute is not in the value list.
6
+ def matches?(value)
7
+ !value.values.first.include?(@attribute)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Matchers #:nodoc:
4
+ class Size < Default
5
+ # Return true if the attribute size is equal to the first value.
6
+ def matches?(value)
7
+ @attribute.size == value.values.first
8
+ end
9
+ end
10
+ end
11
+ end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mongodoc}
8
- s.version = "0.2.2"
8
+ s.version = "0.2.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Les Hill"]
12
- s.date = %q{2010-02-16}
12
+ s.date = %q{2010-02-23}
13
13
  s.description = %q{ODM for MongoDB}
14
14
  s.email = %q{leshill@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -31,23 +31,22 @@ Gem::Specification.new do |s|
31
31
  "features/finders.feature",
32
32
  "features/mongodb.yml",
33
33
  "features/mongodoc_base.feature",
34
- "features/named_scopes.feature",
35
34
  "features/new_record.feature",
36
35
  "features/partial_updates.feature",
37
36
  "features/removing_documents.feature",
38
37
  "features/saving_an_object.feature",
38
+ "features/scopes.feature",
39
39
  "features/step_definitions/collection_steps.rb",
40
- "features/step_definitions/criteria_steps.rb",
41
40
  "features/step_definitions/document_steps.rb",
42
41
  "features/step_definitions/documents.rb",
43
42
  "features/step_definitions/finder_steps.rb",
44
43
  "features/step_definitions/json_steps.rb",
45
- "features/step_definitions/named_scope_steps.rb",
46
44
  "features/step_definitions/object_steps.rb",
47
45
  "features/step_definitions/objects.rb",
48
46
  "features/step_definitions/partial_update_steps.rb",
49
47
  "features/step_definitions/query_steps.rb",
50
48
  "features/step_definitions/removing_documents_steps.rb",
49
+ "features/step_definitions/scope_steps.rb",
51
50
  "features/step_definitions/util_steps.rb",
52
51
  "features/support/support.rb",
53
52
  "features/using_criteria.feature",
@@ -60,6 +59,9 @@ Gem::Specification.new do |s|
60
59
  "lib/mongodoc/bson.rb",
61
60
  "lib/mongodoc/collection.rb",
62
61
  "lib/mongodoc/connection.rb",
62
+ "lib/mongodoc/contexts.rb",
63
+ "lib/mongodoc/contexts/enumerable.rb",
64
+ "lib/mongodoc/contexts/mongo.rb",
63
65
  "lib/mongodoc/criteria.rb",
64
66
  "lib/mongodoc/cursor.rb",
65
67
  "lib/mongodoc/document.rb",
@@ -79,10 +81,30 @@ Gem::Specification.new do |s|
79
81
  "lib/mongodoc/ext/symbol.rb",
80
82
  "lib/mongodoc/ext/time.rb",
81
83
  "lib/mongodoc/finders.rb",
82
- "lib/mongodoc/named_scope.rb",
84
+ "lib/mongodoc/matchers.rb",
83
85
  "lib/mongodoc/query.rb",
86
+ "lib/mongodoc/scope.rb",
84
87
  "lib/mongodoc/validations/macros.rb",
85
88
  "lib/mongodoc/validations/validates_embedded.rb",
89
+ "lib/mongoid/contexts/paging.rb",
90
+ "lib/mongoid/criteria.rb",
91
+ "lib/mongoid/criterion/complex.rb",
92
+ "lib/mongoid/criterion/exclusion.rb",
93
+ "lib/mongoid/criterion/inclusion.rb",
94
+ "lib/mongoid/criterion/optional.rb",
95
+ "lib/mongoid/extensions/hash/criteria_helpers.rb",
96
+ "lib/mongoid/extensions/symbol/inflections.rb",
97
+ "lib/mongoid/matchers/all.rb",
98
+ "lib/mongoid/matchers/default.rb",
99
+ "lib/mongoid/matchers/exists.rb",
100
+ "lib/mongoid/matchers/gt.rb",
101
+ "lib/mongoid/matchers/gte.rb",
102
+ "lib/mongoid/matchers/in.rb",
103
+ "lib/mongoid/matchers/lt.rb",
104
+ "lib/mongoid/matchers/lte.rb",
105
+ "lib/mongoid/matchers/ne.rb",
106
+ "lib/mongoid/matchers/nin.rb",
107
+ "lib/mongoid/matchers/size.rb",
86
108
  "mongod.example.yml",
87
109
  "mongodb.example.yml",
88
110
  "mongodoc.gemspec",
@@ -97,6 +119,9 @@ Gem::Specification.new do |s|
97
119
  "spec/bson_spec.rb",
98
120
  "spec/collection_spec.rb",
99
121
  "spec/connection_spec.rb",
122
+ "spec/contexts/enumerable_spec.rb",
123
+ "spec/contexts/mongo_spec.rb",
124
+ "spec/contexts_spec.rb",
100
125
  "spec/criteria_spec.rb",
101
126
  "spec/cursor_spec.rb",
102
127
  "spec/document_ext.rb",
@@ -104,18 +129,19 @@ Gem::Specification.new do |s|
104
129
  "spec/embedded_save_spec.rb",
105
130
  "spec/finders_spec.rb",
106
131
  "spec/hash_matchers.rb",
132
+ "spec/matchers_spec.rb",
107
133
  "spec/mongodb.yml",
108
134
  "spec/mongodb_pairs.yml",
109
- "spec/named_scope_spec.rb",
110
135
  "spec/new_record_spec.rb",
111
136
  "spec/query_spec.rb",
137
+ "spec/scope_spec.rb",
112
138
  "spec/spec.opts",
113
139
  "spec/spec_helper.rb"
114
140
  ]
115
141
  s.homepage = %q{http://github.com/leshill/mongodoc}
116
142
  s.rdoc_options = ["--charset=UTF-8"]
117
143
  s.require_paths = ["lib"]
118
- s.rubygems_version = %q{1.3.6.pre.3}
144
+ s.rubygems_version = %q{1.3.6}
119
145
  s.summary = %q{ODM for MongoDB}
120
146
  s.test_files = [
121
147
  "spec/associations/collection_proxy_spec.rb",
@@ -126,6 +152,9 @@ Gem::Specification.new do |s|
126
152
  "spec/bson_spec.rb",
127
153
  "spec/collection_spec.rb",
128
154
  "spec/connection_spec.rb",
155
+ "spec/contexts/enumerable_spec.rb",
156
+ "spec/contexts/mongo_spec.rb",
157
+ "spec/contexts_spec.rb",
129
158
  "spec/criteria_spec.rb",
130
159
  "spec/cursor_spec.rb",
131
160
  "spec/document_ext.rb",
@@ -133,9 +162,10 @@ Gem::Specification.new do |s|
133
162
  "spec/embedded_save_spec.rb",
134
163
  "spec/finders_spec.rb",
135
164
  "spec/hash_matchers.rb",
136
- "spec/named_scope_spec.rb",
165
+ "spec/matchers_spec.rb",
137
166
  "spec/new_record_spec.rb",
138
167
  "spec/query_spec.rb",
168
+ "spec/scope_spec.rb",
139
169
  "spec/spec_helper.rb",
140
170
  "examples/simple_document.rb",
141
171
  "examples/simple_object.rb"
@@ -132,6 +132,12 @@ describe "MongoDoc::Attributes" do
132
132
  has_many :sub_docs, :class_name => 'SubHasManyDoc'
133
133
  end
134
134
 
135
+ class TestHasManyDoc2
136
+ include MongoDoc::Document
137
+
138
+ has_many :sub_docs, :class_name => :sub_has_many_doc
139
+ end
140
+
135
141
  class TestImplicitHasManyDoc
136
142
  include MongoDoc::Document
137
143
 
@@ -157,6 +163,14 @@ describe "MongoDoc::Attributes" do
157
163
  TestImplicitHasManyDoc.new.sub_has_many_docs.assoc_class.should == SubHasManyDoc
158
164
  end
159
165
 
166
+ it "uses class_name attribute for the children's class name" do
167
+ TestHasManyDoc.new.sub_docs.assoc_class.should == SubHasManyDoc
168
+ end
169
+
170
+ it "uses class_name attribute for the children's class name" do
171
+ TestHasManyDoc2.new.sub_docs.assoc_class.should == SubHasManyDoc
172
+ end
173
+
160
174
  context "validations" do
161
175
  class HasManyValidationChild
162
176
  include MongoDoc::Document
@@ -171,8 +185,8 @@ describe "MongoDoc::Attributes" do
171
185
  has_many :subdocs, :class_name => 'HasManyValidationChild'
172
186
  end
173
187
 
174
- let(:invalid_child) { HasHashValidationChild.new }
175
- let(:doc) { HasHashValidationTest.new(:subdocs => {:key => invalid_child}) }
188
+ let(:invalid_child) { HasManyValidationChild.new }
189
+ let(:doc) { HasManyValidationTest.new(:subdocs => [invalid_child]) }
176
190
 
177
191
  it "cascades validations and marks it in the parent" do
178
192
  doc.should have(1).error_on(:subdocs)
@@ -0,0 +1,335 @@
1
+ require "spec_helper"
2
+
3
+ describe MongoDoc::Contexts::Enumerable do
4
+
5
+ class Address
6
+ include MongoDoc::Document
7
+ include MongoDoc::Matchers
8
+
9
+ key :number
10
+ key :street
11
+ end
12
+
13
+ before do
14
+ @london = Address.new(:number => 1, :street => "Bond Street")
15
+ @shanghai = Address.new(:number => 10, :street => "Nan Jing Dong Lu")
16
+ @melbourne = Address.new(:number => 20, :street => "Bourke Street")
17
+ @new_york = Address.new(:number => 20, :street => "Broadway")
18
+ @docs = [ @london, @shanghai, @melbourne, @new_york ]
19
+ @criteria = Mongoid::Criteria.new(Address)
20
+ @criteria.documents = @docs
21
+ @criteria.where(:street => "Bourke Street").only(:number)
22
+ @context = MongoDoc::Contexts::Enumerable.new(@criteria)
23
+ end
24
+
25
+ describe "#aggregate" do
26
+
27
+ before do
28
+ @counts = @context.aggregate
29
+ end
30
+
31
+ it "groups by the fields provided in the options" do
32
+ @counts.size.should == 3
33
+ end
34
+
35
+ it "stores the counts in proper groups" do
36
+ @counts[1].should == 1
37
+ @counts[10].should == 1
38
+ @counts[20].should == 2
39
+ end
40
+ end
41
+
42
+ describe "#count" do
43
+
44
+ it "returns the size of the enumerable" do
45
+ @context.count.should == 4
46
+ end
47
+
48
+ end
49
+
50
+ describe "#execute" do
51
+
52
+ before do
53
+ @criteria = Mongoid::Criteria.new(Address)
54
+ @criteria.documents = @docs
55
+ end
56
+
57
+ it "returns the matching documents from the array" do
58
+ @context.execute.should == [ @melbourne ]
59
+ end
60
+
61
+ context "when selector is empty" do
62
+
63
+ before do
64
+ @criteria.only(:number)
65
+ @context = MongoDoc::Contexts::Enumerable.new(@criteria)
66
+ end
67
+
68
+ it "returns all the documents" do
69
+ @context.execute.should == @docs
70
+ end
71
+ end
72
+
73
+ context "when skip and limit are in the options" do
74
+
75
+ before do
76
+ @criteria.skip(2).limit(2)
77
+ @context = MongoDoc::Contexts::Enumerable.new(@criteria)
78
+ end
79
+
80
+ it "properly narrows down the matching results" do
81
+ @context.execute.should == [ @melbourne, @new_york ]
82
+ end
83
+ end
84
+
85
+ end
86
+
87
+ describe "#first" do
88
+
89
+ context "when a selector is present" do
90
+
91
+ it "returns the first that matches the selector" do
92
+ @context.first.should == @melbourne
93
+ end
94
+ end
95
+
96
+ end
97
+
98
+ describe "#group" do
99
+
100
+ before do
101
+ @group = @context.group
102
+ end
103
+
104
+ it "groups by the fields provided in the options" do
105
+ @group.size.should == 3
106
+ end
107
+
108
+ it "stores the documents in proper groups" do
109
+ @group[1].should == [ @london ]
110
+ @group[10].should == [ @shanghai ]
111
+ @group[20].should == [ @melbourne, @new_york ]
112
+ end
113
+
114
+ end
115
+
116
+ describe ".initialize" do
117
+
118
+ let(:selector) { { :field => "value" } }
119
+ let(:options) { { :skip => 20 } }
120
+ let(:documents) { [stub] }
121
+
122
+ before do
123
+ @criteria = Mongoid::Criteria.new(Address)
124
+ @criteria.documents = documents
125
+ @criteria.where(selector).skip(20)
126
+ @context = MongoDoc::Contexts::Enumerable.new(@criteria)
127
+ end
128
+
129
+ it "sets the selector" do
130
+ @context.selector.should == selector
131
+ end
132
+
133
+ it "sets the options" do
134
+ @context.options.should == options
135
+ end
136
+
137
+ it "sets the documents" do
138
+ @context.documents.should == documents
139
+ end
140
+
141
+ end
142
+
143
+ describe "#last" do
144
+
145
+ it "returns the last matching in the enumerable" do
146
+ @context.last.should == @melbourne
147
+ end
148
+
149
+ end
150
+
151
+ describe "#max" do
152
+
153
+ it "returns the max value for the supplied field" do
154
+ @context.max(:number).should == 20
155
+ end
156
+
157
+ end
158
+
159
+ describe "#min" do
160
+
161
+ it "returns the min value for the supplied field" do
162
+ @context.min(:number).should == 1
163
+ end
164
+
165
+ end
166
+
167
+ describe "#one" do
168
+
169
+ it "returns the first matching in the enumerable" do
170
+ @context.one.should == @melbourne
171
+ end
172
+
173
+ end
174
+
175
+ describe "#page" do
176
+
177
+ context "when the page option exists" do
178
+
179
+ before do
180
+ @criteria = Mongoid::Criteria.new(Address).extras({ :page => 5 })
181
+ @criteria.documents = []
182
+ @context = MongoDoc::Contexts::Enumerable.new(@criteria)
183
+ end
184
+
185
+ it "returns the page option" do
186
+ @context.page.should == 5
187
+ end
188
+
189
+ end
190
+
191
+ context "when the page option does not exist" do
192
+
193
+ before do
194
+ @criteria = Mongoid::Criteria.new(Address)
195
+ @criteria.documents = []
196
+ @context = MongoDoc::Contexts::Enumerable.new(@criteria)
197
+ end
198
+
199
+ it "returns 1" do
200
+ @context.page.should == 1
201
+ end
202
+
203
+ end
204
+
205
+ end
206
+
207
+ describe "#paginate" do
208
+
209
+ before do
210
+ @criteria = Mongoid::Criteria.new(Address).skip(2).limit(2)
211
+ @context = MongoDoc::Contexts::Enumerable.new(@criteria)
212
+ @results = @context.paginate
213
+ end
214
+
215
+ it "executes and paginates the results" do
216
+ @results.current_page.should == 2
217
+ @results.per_page.should == 2
218
+ end
219
+
220
+ end
221
+
222
+ describe "#per_page" do
223
+
224
+ context "when a limit option exists" do
225
+
226
+ it "returns 20" do
227
+ @context.per_page.should == 20
228
+ end
229
+
230
+ end
231
+
232
+ context "when a limit option does not exist" do
233
+
234
+ before do
235
+ @criteria = Mongoid::Criteria.new(Address).limit(50)
236
+ @criteria.documents = []
237
+ @context = MongoDoc::Contexts::Enumerable.new(@criteria)
238
+ end
239
+
240
+ it "returns the limit" do
241
+ @context.per_page.should == 50
242
+ end
243
+
244
+ end
245
+
246
+ end
247
+
248
+ describe "#sum" do
249
+
250
+ it "returns the sum of all the field values" do
251
+ @context.sum(:number).should == 51
252
+ end
253
+
254
+ end
255
+
256
+ context "#id_criteria" do
257
+
258
+ let(:criteria) do
259
+ criteria = Mongoid::Criteria.new(Address)
260
+ criteria.documents = []
261
+ criteria
262
+ end
263
+ let(:context) { criteria.context }
264
+
265
+ context "with a single argument" do
266
+
267
+ let(:id) { Mongo::ObjectID.new.to_s }
268
+
269
+ before do
270
+ criteria.should_receive(:id).with(id).and_return(criteria)
271
+ end
272
+
273
+ context "when the document is found" do
274
+
275
+ let(:document) { stub }
276
+
277
+ it "returns a matching document" do
278
+ context.should_receive(:one).and_return(document)
279
+ context.id_criteria(id).should == document
280
+ end
281
+
282
+ end
283
+
284
+ context "when the document is not found" do
285
+
286
+ it "returns nil" do
287
+ context.should_receive(:one).and_return(nil)
288
+ context.id_criteria(id).should be_nil
289
+ end
290
+
291
+ end
292
+
293
+ end
294
+
295
+ context "multiple arguments" do
296
+
297
+ context "when an array of ids" do
298
+
299
+ let(:ids) do
300
+ (0..2).inject([]) { |ary, i| ary << Mongo::ObjectID.new.to_s }
301
+ end
302
+
303
+ context "when documents are found" do
304
+
305
+ let(:docs) do
306
+ (0..2).inject([]) { |ary, i| ary << stub }
307
+ end
308
+
309
+ before do
310
+ criteria.should_receive(:id).with(ids).and_return(criteria)
311
+ end
312
+
313
+ it "returns matching documents" do
314
+ context.should_receive(:execute).and_return(docs)
315
+ context.id_criteria(ids).should == docs
316
+ end
317
+
318
+ end
319
+
320
+ context "when documents are not found" do
321
+
322
+ it "returns an empty array" do
323
+ context.should_receive(:execute).and_return([])
324
+ context.id_criteria(ids).should be_empty
325
+ end
326
+
327
+ end
328
+
329
+ end
330
+
331
+ end
332
+
333
+ end
334
+
335
+ end