mongomodel 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/README.md +6 -0
  2. data/bin/console +4 -4
  3. data/lib/mongomodel.rb +4 -4
  4. data/lib/mongomodel/concerns/associations/base/definition.rb +4 -0
  5. data/lib/mongomodel/concerns/associations/has_many_by_foreign_key.rb +7 -16
  6. data/lib/mongomodel/concerns/associations/has_many_by_ids.rb +6 -12
  7. data/lib/mongomodel/concerns/attributes.rb +1 -7
  8. data/lib/mongomodel/document.rb +0 -1
  9. data/lib/mongomodel/document/dynamic_finders.rb +2 -69
  10. data/lib/mongomodel/document/indexes.rb +0 -6
  11. data/lib/mongomodel/document/persistence.rb +1 -21
  12. data/lib/mongomodel/document/scopes.rb +59 -135
  13. data/lib/mongomodel/document/validations/uniqueness.rb +7 -5
  14. data/lib/mongomodel/support/dynamic_finder.rb +68 -0
  15. data/lib/mongomodel/support/mongo_operator.rb +29 -0
  16. data/lib/mongomodel/support/mongo_options.rb +0 -101
  17. data/lib/mongomodel/support/mongo_order.rb +78 -0
  18. data/lib/mongomodel/support/scope.rb +186 -0
  19. data/lib/mongomodel/support/scope/dynamic_finders.rb +21 -0
  20. data/lib/mongomodel/support/scope/finder_methods.rb +61 -0
  21. data/lib/mongomodel/support/scope/query_methods.rb +43 -0
  22. data/lib/mongomodel/support/scope/spawn_methods.rb +35 -0
  23. data/lib/mongomodel/version.rb +1 -1
  24. data/mongomodel.gemspec +20 -3
  25. data/spec/mongomodel/concerns/associations/has_many_by_foreign_key_spec.rb +1 -1
  26. data/spec/mongomodel/concerns/associations/has_many_by_ids_spec.rb +1 -1
  27. data/spec/mongomodel/document/dynamic_finders_spec.rb +0 -1
  28. data/spec/mongomodel/document/finders_spec.rb +0 -144
  29. data/spec/mongomodel/document/indexes_spec.rb +2 -2
  30. data/spec/mongomodel/document/persistence_spec.rb +1 -15
  31. data/spec/mongomodel/document/scopes_spec.rb +64 -167
  32. data/spec/mongomodel/support/mongo_operator_spec.rb +29 -0
  33. data/spec/mongomodel/support/mongo_options_spec.rb +0 -150
  34. data/spec/mongomodel/support/mongo_order_spec.rb +127 -0
  35. data/spec/mongomodel/support/scope_spec.rb +932 -0
  36. data/spec/support/helpers/document_finder_stubs.rb +40 -0
  37. data/spec/support/matchers/find_with.rb +36 -0
  38. metadata +22 -5
  39. data/lib/mongomodel/document/finders.rb +0 -82
@@ -0,0 +1,21 @@
1
+ module MongoModel
2
+ class Scope
3
+ module DynamicFinders
4
+ def respond_to?(method_id, include_private = false)
5
+ if DynamicFinder.match(self, method_id)
6
+ true
7
+ else
8
+ super
9
+ end
10
+ end
11
+
12
+ def method_missing(method_id, *args, &block)
13
+ if finder = DynamicFinder.match(self, method_id)
14
+ finder.execute(*args)
15
+ else
16
+ super
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,61 @@
1
+ module MongoModel
2
+ class Scope
3
+ module FinderMethods
4
+ def find(*ids, &block)
5
+ if block_given?
6
+ to_a.find(&block)
7
+ else
8
+ ids.flatten!
9
+
10
+ case ids.size
11
+ when 0
12
+ raise ArgumentError, "At least one id must be specified"
13
+ when 1
14
+ id = ids.first.to_s
15
+ where(:id => id).first || raise(DocumentNotFound, "Couldn't find document with id: #{id}")
16
+ else
17
+ docs = where(:id.in => ids.map { |id| id.to_s }).to_a
18
+ raise DocumentNotFound if docs.size != ids.size
19
+ docs.sort_by { |doc| ids.index(doc.id) }
20
+ end
21
+ end
22
+ end
23
+
24
+ def first
25
+ if loaded?
26
+ @documents.first
27
+ else
28
+ @first ||= limit(1).to_a[0]
29
+ end
30
+ end
31
+
32
+ def last
33
+ if loaded?
34
+ @documents.last
35
+ else
36
+ @last ||= reverse_order.limit(1).to_a[0]
37
+ end
38
+ end
39
+
40
+ def all
41
+ to_a
42
+ end
43
+
44
+ def exists?(id)
45
+ where(:id => id).any?
46
+ end
47
+
48
+ def apply_finder_options(options={})
49
+ result = clone
50
+
51
+ result = result.where(options[:conditions]) if options[:conditions]
52
+ result = result.order(options[:order]) if options[:order]
53
+ result = result.select(options[:select]) if options[:select]
54
+ result = result.limit(options[:limit]) if options[:limit]
55
+ result = result.offset(options[:offset]) if options[:offset]
56
+
57
+ result
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,43 @@
1
+ module MongoModel
2
+ class Scope
3
+ module QueryMethods
4
+ def initialize(*)
5
+ SINGLE_VALUE_METHODS.each { |m| instance_variable_set("@#{m}_value", nil) }
6
+ MULTI_VALUE_METHODS.each { |m| instance_variable_set("@#{m}_values", []) }
7
+ end
8
+
9
+ MULTI_VALUE_METHODS.each do |query_method|
10
+ attr_accessor :"#{query_method}_values"
11
+
12
+ class_eval <<-CEVAL, __FILE__
13
+ def #{query_method}(*args, &block)
14
+ new_scope = clone
15
+ value = Array.wrap(args.flatten).reject {|x| x.blank? }
16
+ new_scope.#{query_method}_values += value if value.present?
17
+ new_scope
18
+ end
19
+ CEVAL
20
+ end
21
+
22
+ SINGLE_VALUE_METHODS.each do |query_method|
23
+ attr_accessor :"#{query_method}_value"
24
+
25
+ class_eval <<-CEVAL, __FILE__
26
+ def #{query_method}(value, &block)
27
+ new_scope = clone
28
+ new_scope.#{query_method}_value = value
29
+ new_scope
30
+ end
31
+ CEVAL
32
+ end
33
+
34
+ def reverse_order
35
+ if order_values.empty?
36
+ order(:id.desc)
37
+ else
38
+ except(:order).order(MongoOrder.parse(order_values).reverse.to_a)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,35 @@
1
+ module MongoModel
2
+ class Scope
3
+ module SpawnMethods
4
+ def merge(scope)
5
+ result = clone
6
+
7
+ MULTI_VALUE_METHODS.each do |method|
8
+ values = send(:"#{method}_values") + scope.send(:"#{method}_values")
9
+ result.send(:"#{method}_values=", values.uniq)
10
+ end
11
+
12
+ SINGLE_VALUE_METHODS.each do |method|
13
+ value = scope.send(:"#{method}_value")
14
+ result.send(:"#{method}_value=", value) if value
15
+ end
16
+
17
+ result
18
+ end
19
+
20
+ def except(*exceptions)
21
+ result = self.class.new(klass)
22
+
23
+ MULTI_VALUE_METHODS.each do |method|
24
+ result.send(:"#{method}_values=", send(:"#{method}_values")) unless exceptions.include?(method)
25
+ end
26
+
27
+ SINGLE_VALUE_METHODS.each do |method|
28
+ result.send(:"#{method}_value=", send(:"#{method}_value")) unless exceptions.include?(method)
29
+ end
30
+
31
+ result
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,3 +1,3 @@
1
1
  module MongoModel
2
- VERSION = "0.1.6"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mongomodel}
8
- s.version = "0.1.6"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Sam Pohlenz"]
12
- s.date = %q{2010-04-16}
12
+ s.date = %q{2010-04-21}
13
13
  s.default_executable = %q{console}
14
14
  s.description = %q{MongoModel is a MongoDB ORM for Ruby/Rails similar to ActiveRecord and DataMapper.}
15
15
  s.email = %q{sam@sampohlenz.com}
@@ -59,7 +59,6 @@ Gem::Specification.new do |s|
59
59
  "lib/mongomodel/document.rb",
60
60
  "lib/mongomodel/document/callbacks.rb",
61
61
  "lib/mongomodel/document/dynamic_finders.rb",
62
- "lib/mongomodel/document/finders.rb",
63
62
  "lib/mongomodel/document/indexes.rb",
64
63
  "lib/mongomodel/document/optimistic_locking.rb",
65
64
  "lib/mongomodel/document/persistence.rb",
@@ -71,8 +70,16 @@ Gem::Specification.new do |s|
71
70
  "lib/mongomodel/support/collection.rb",
72
71
  "lib/mongomodel/support/configuration.rb",
73
72
  "lib/mongomodel/support/core_extensions.rb",
73
+ "lib/mongomodel/support/dynamic_finder.rb",
74
74
  "lib/mongomodel/support/exceptions.rb",
75
+ "lib/mongomodel/support/mongo_operator.rb",
75
76
  "lib/mongomodel/support/mongo_options.rb",
77
+ "lib/mongomodel/support/mongo_order.rb",
78
+ "lib/mongomodel/support/scope.rb",
79
+ "lib/mongomodel/support/scope/dynamic_finders.rb",
80
+ "lib/mongomodel/support/scope/finder_methods.rb",
81
+ "lib/mongomodel/support/scope/query_methods.rb",
82
+ "lib/mongomodel/support/scope/spawn_methods.rb",
76
83
  "lib/mongomodel/support/types.rb",
77
84
  "lib/mongomodel/support/types/array.rb",
78
85
  "lib/mongomodel/support/types/boolean.rb",
@@ -120,16 +127,21 @@ Gem::Specification.new do |s|
120
127
  "spec/mongomodel/embedded_document_spec.rb",
121
128
  "spec/mongomodel/mongomodel_spec.rb",
122
129
  "spec/mongomodel/support/collection_spec.rb",
130
+ "spec/mongomodel/support/mongo_operator_spec.rb",
123
131
  "spec/mongomodel/support/mongo_options_spec.rb",
132
+ "spec/mongomodel/support/mongo_order_spec.rb",
124
133
  "spec/mongomodel/support/property_spec.rb",
134
+ "spec/mongomodel/support/scope_spec.rb",
125
135
  "spec/spec.opts",
126
136
  "spec/spec_helper.rb",
127
137
  "spec/specdoc.opts",
128
138
  "spec/support/callbacks.rb",
129
139
  "spec/support/helpers/define_class.rb",
140
+ "spec/support/helpers/document_finder_stubs.rb",
130
141
  "spec/support/helpers/specs_for.rb",
131
142
  "spec/support/matchers/be_a_subclass_of.rb",
132
143
  "spec/support/matchers/be_truthy.rb",
144
+ "spec/support/matchers/find_with.rb",
133
145
  "spec/support/matchers/respond_to_boolean.rb",
134
146
  "spec/support/matchers/run_callbacks.rb",
135
147
  "spec/support/models.rb",
@@ -174,14 +186,19 @@ Gem::Specification.new do |s|
174
186
  "spec/mongomodel/embedded_document_spec.rb",
175
187
  "spec/mongomodel/mongomodel_spec.rb",
176
188
  "spec/mongomodel/support/collection_spec.rb",
189
+ "spec/mongomodel/support/mongo_operator_spec.rb",
177
190
  "spec/mongomodel/support/mongo_options_spec.rb",
191
+ "spec/mongomodel/support/mongo_order_spec.rb",
178
192
  "spec/mongomodel/support/property_spec.rb",
193
+ "spec/mongomodel/support/scope_spec.rb",
179
194
  "spec/spec_helper.rb",
180
195
  "spec/support/callbacks.rb",
181
196
  "spec/support/helpers/define_class.rb",
197
+ "spec/support/helpers/document_finder_stubs.rb",
182
198
  "spec/support/helpers/specs_for.rb",
183
199
  "spec/support/matchers/be_a_subclass_of.rb",
184
200
  "spec/support/matchers/be_truthy.rb",
201
+ "spec/support/matchers/find_with.rb",
185
202
  "spec/support/matchers/respond_to_boolean.rb",
186
203
  "spec/support/matchers/run_callbacks.rb",
187
204
  "spec/support/models.rb",
@@ -142,7 +142,7 @@ module MongoModel
142
142
  Chapter.create!(:id => '999')
143
143
  Chapter.create!(:id => '998')
144
144
 
145
- result = subject.chapters.find(:all, :order => :id.desc)
145
+ result = subject.chapters.order(:id.desc)
146
146
  result.should == [chapter2, chapter1]
147
147
  end
148
148
 
@@ -141,7 +141,7 @@ module MongoModel
141
141
  Chapter.create!(:id => '999')
142
142
  Chapter.create!(:id => '998')
143
143
 
144
- result = subject.chapters.find(:all, :order => :id.desc)
144
+ result = subject.chapters.order(:id.desc)
145
145
  result.should == [chapter2, chapter1]
146
146
  end
147
147
 
@@ -66,7 +66,6 @@ module MongoModel
66
66
  it_should_behave_like "a dynamic finder"
67
67
 
68
68
  should_find("John") { @john }
69
- should_find("John", :conditions => { :age.lt => 20 }) { @young_john }
70
69
  should_find("Jane") { nil }
71
70
  end
72
71
 
@@ -82,150 +82,6 @@ module MongoModel
82
82
  end
83
83
  end
84
84
  end
85
-
86
- describe "first" do
87
- context "documents exist" do
88
- subject { User.find(:first) }
89
-
90
- it "should return the first document" do
91
- subject.id.should == '1'
92
- subject.name.should == 'Fred'
93
- end
94
-
95
- it "should be aliased as #first" do
96
- User.first.should == subject
97
- end
98
-
99
- context "with order" do
100
- it "should find first document by order" do
101
- User.find(:first, :order => :name.asc).name.should == 'Alistair'
102
- end
103
- end
104
- end
105
-
106
- context "no documents" do
107
- before(:each) { User.collection.remove }
108
-
109
- it "should return nil" do
110
- User.find(:first).should be_nil
111
- end
112
- end
113
- end
114
-
115
- describe "last" do
116
- context "documents exist" do
117
- subject { User.find(:last) }
118
-
119
- it "should return the last document (by id)" do
120
- subject.id.should == '3'
121
- subject.name.should == 'Barney'
122
- end
123
-
124
- it "should be aliased as #last" do
125
- User.last.should == subject
126
- end
127
-
128
- context "with order" do
129
- it "should find last document by order" do
130
- User.find(:last, :order => :name.asc).name.should == 'Fred'
131
- end
132
- end
133
- end
134
-
135
- context "no documents" do
136
- before(:each) { User.collection.remove }
137
-
138
- it "should return nil" do
139
- User.find(:last).should be_nil
140
- end
141
- end
142
- end
143
-
144
- describe "all" do
145
- subject { User.find(:all, :order => 'id ASC') }
146
-
147
- it "should return all documents as User instances" do
148
- subject.should have(3).users
149
- subject.each { |d| d.should be_a(User) }
150
- end
151
-
152
- it "should load attributes for each document" do
153
- subject[0].name.should == 'Fred'
154
- subject[1].name.should == 'Alistair'
155
- subject[2].name.should == 'Barney'
156
- end
157
-
158
- it "should be aliased as #all" do
159
- User.all.should == subject
160
- end
161
-
162
- context "with exact-match conditions" do
163
- subject { User.find(:all, :conditions => { :name => 'Alistair' }) }
164
-
165
- it "should only return documents matching conditions" do
166
- subject.should have(1).user
167
- subject[0].name.should == 'Alistair'
168
- end
169
- end
170
-
171
- context "with inequality conditions" do
172
- subject { User.find(:all, :conditions => { :age.lt => 21 }) }
173
-
174
- it "should only return documents matching conditions" do
175
- subject.should have(2).users
176
- subject[0].name.should == 'Alistair'
177
- subject[1].name.should == 'Barney'
178
- end
179
- end
180
- end
181
- end
182
-
183
- describe "#count" do
184
- before(:each) do
185
- 5.times { User.create(:age => 18) }
186
- 7.times { User.create(:age => 42) }
187
- 3.times { NonUser.create }
188
- end
189
-
190
- context "without arguments" do
191
- it "should return the count for that particular model" do
192
- User.count.should == 12
193
- NonUser.count.should == 3
194
- end
195
- end
196
-
197
- context "with conditions" do
198
- it "should return the count for the model that match the conditions" do
199
- User.count(:age => 18).should == 5
200
- User.count(:age.gte => 18).should == 12
201
- end
202
- end
203
- end
204
-
205
- describe "#exists?" do
206
- before(:each) do
207
- User.create(:id => 'user-1', :name => 'Test', :age => 10)
208
- end
209
-
210
- context "by id" do
211
- it "should return true if the document exists" do
212
- User.exists?('user-1').should == true
213
- end
214
-
215
- it "should return false if the document does not exist" do
216
- User.exists?('user-2').should == false
217
- end
218
- end
219
-
220
- context "by conditions" do
221
- it "should return true if the document exists" do
222
- User.exists?(:name => 'Test').should == true
223
- end
224
-
225
- it "should return false if the document does not exist" do
226
- User.exists?(:name => 'Nonexistant').should == false
227
- end
228
- end
229
85
  end
230
86
  end
231
87
  end
@@ -60,13 +60,13 @@ module MongoModel
60
60
  describe "#_find" do
61
61
  it "should run ensure_indexes!" do
62
62
  Article.should_receive(:ensure_indexes!)
63
- Article.find(:first)
63
+ Article.first
64
64
  end
65
65
 
66
66
  it "should rerun ensure_indexes! if indexes are initialized" do
67
67
  Article.ensure_indexes!
68
68
  Article.should_not_receive(:ensure_indexes!)
69
- Article.find(:first)
69
+ Article.first
70
70
  end
71
71
  end
72
72
  end
@@ -183,14 +183,7 @@ module MongoModel
183
183
  User.exists?('user-1').should be_false
184
184
  User.exists?('user-2').should be_true
185
185
  end
186
-
187
- it "should delete by conditions" do
188
- User.delete(:age.gt => 15)
189
-
190
- User.exists?('user-2').should be_false
191
- User.exists?('user-1').should be_true
192
- end
193
-
186
+
194
187
  it "should delete by multiple ids in array" do
195
188
  User.delete(['user-1', 'user-2'])
196
189
 
@@ -270,13 +263,6 @@ module MongoModel
270
263
  User.exists?('user-2').should be_true
271
264
  end
272
265
 
273
- it "should destroy by conditions" do
274
- User.destroy(:age.gt => 15)
275
-
276
- User.exists?('user-2').should be_false
277
- User.exists?('user-1').should be_true
278
- end
279
-
280
266
  it "should destroy by multiple ids in array" do
281
267
  User.destroy(['user-1', 'user-2'])
282
268