mongodoc 0.2.2 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
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