mongomodel 0.1.6 → 0.2.0

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 (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