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.
- data/README.md +6 -0
- data/bin/console +4 -4
- data/lib/mongomodel.rb +4 -4
- data/lib/mongomodel/concerns/associations/base/definition.rb +4 -0
- data/lib/mongomodel/concerns/associations/has_many_by_foreign_key.rb +7 -16
- data/lib/mongomodel/concerns/associations/has_many_by_ids.rb +6 -12
- data/lib/mongomodel/concerns/attributes.rb +1 -7
- data/lib/mongomodel/document.rb +0 -1
- data/lib/mongomodel/document/dynamic_finders.rb +2 -69
- data/lib/mongomodel/document/indexes.rb +0 -6
- data/lib/mongomodel/document/persistence.rb +1 -21
- data/lib/mongomodel/document/scopes.rb +59 -135
- data/lib/mongomodel/document/validations/uniqueness.rb +7 -5
- data/lib/mongomodel/support/dynamic_finder.rb +68 -0
- data/lib/mongomodel/support/mongo_operator.rb +29 -0
- data/lib/mongomodel/support/mongo_options.rb +0 -101
- data/lib/mongomodel/support/mongo_order.rb +78 -0
- data/lib/mongomodel/support/scope.rb +186 -0
- data/lib/mongomodel/support/scope/dynamic_finders.rb +21 -0
- data/lib/mongomodel/support/scope/finder_methods.rb +61 -0
- data/lib/mongomodel/support/scope/query_methods.rb +43 -0
- data/lib/mongomodel/support/scope/spawn_methods.rb +35 -0
- data/lib/mongomodel/version.rb +1 -1
- data/mongomodel.gemspec +20 -3
- data/spec/mongomodel/concerns/associations/has_many_by_foreign_key_spec.rb +1 -1
- data/spec/mongomodel/concerns/associations/has_many_by_ids_spec.rb +1 -1
- data/spec/mongomodel/document/dynamic_finders_spec.rb +0 -1
- data/spec/mongomodel/document/finders_spec.rb +0 -144
- data/spec/mongomodel/document/indexes_spec.rb +2 -2
- data/spec/mongomodel/document/persistence_spec.rb +1 -15
- data/spec/mongomodel/document/scopes_spec.rb +64 -167
- data/spec/mongomodel/support/mongo_operator_spec.rb +29 -0
- data/spec/mongomodel/support/mongo_options_spec.rb +0 -150
- data/spec/mongomodel/support/mongo_order_spec.rb +127 -0
- data/spec/mongomodel/support/scope_spec.rb +932 -0
- data/spec/support/helpers/document_finder_stubs.rb +40 -0
- data/spec/support/matchers/find_with.rb +36 -0
- metadata +22 -5
- 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
|
data/lib/mongomodel/version.rb
CHANGED
data/mongomodel.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mongomodel}
|
8
|
-
s.version = "0.
|
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-
|
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",
|
@@ -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.
|
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.
|
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
|
|