mongomodel 0.5.5 → 0.5.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +23 -11
- data/gemfiles/rails-3.2.gemfile +2 -2
- data/gemfiles/rails-4-observers.gemfile +1 -1
- data/gemfiles/rails-4.1.gemfile +2 -2
- data/gemfiles/{mongoid.gemfile → rails-4.2.gemfile} +2 -3
- data/gemfiles/{mongo_mapper.gemfile → rails-5.0.gemfile} +2 -3
- data/gemfiles/rails-5.1.gemfile +10 -0
- data/gemfiles/rails-5.2.gemfile +10 -0
- data/lib/mongomodel.rb +15 -15
- data/lib/mongomodel/attributes/mongo.rb +7 -7
- data/lib/mongomodel/attributes/store.rb +4 -4
- data/lib/mongomodel/attributes/typecasting.rb +7 -7
- data/lib/mongomodel/compatibility/mongo_mapper.rb +3 -3
- data/lib/mongomodel/compatibility/mongoid.rb +3 -3
- data/lib/mongomodel/concerns/abstract_class.rb +3 -3
- data/lib/mongomodel/concerns/activemodel.rb +4 -4
- data/lib/mongomodel/concerns/associations.rb +8 -8
- data/lib/mongomodel/concerns/associations/base/association.rb +5 -5
- data/lib/mongomodel/concerns/associations/base/definition.rb +4 -4
- data/lib/mongomodel/concerns/associations/base/proxy.rb +1 -1
- data/lib/mongomodel/concerns/associations/belongs_to.rb +19 -19
- data/lib/mongomodel/concerns/associations/has_many_by_foreign_key.rb +36 -36
- data/lib/mongomodel/concerns/associations/has_many_by_ids.rb +34 -34
- data/lib/mongomodel/concerns/attribute_methods.rb +10 -10
- data/lib/mongomodel/concerns/attribute_methods/before_type_cast.rb +4 -4
- data/lib/mongomodel/concerns/attribute_methods/dirty.rb +95 -13
- data/lib/mongomodel/concerns/attribute_methods/forbidden.rb +1 -1
- data/lib/mongomodel/concerns/attribute_methods/multi_parameter_assignment.rb +6 -6
- data/lib/mongomodel/concerns/attribute_methods/nested.rb +18 -18
- data/lib/mongomodel/concerns/attribute_methods/protected.rb +3 -3
- data/lib/mongomodel/concerns/attribute_methods/query.rb +3 -3
- data/lib/mongomodel/concerns/attribute_methods/read.rb +4 -4
- data/lib/mongomodel/concerns/attribute_methods/write.rb +4 -4
- data/lib/mongomodel/concerns/attributes.rb +18 -18
- data/lib/mongomodel/concerns/callbacks.rb +7 -7
- data/lib/mongomodel/concerns/document_parent.rb +2 -2
- data/lib/mongomodel/concerns/logging.rb +2 -2
- data/lib/mongomodel/concerns/map_reduce.rb +11 -11
- data/lib/mongomodel/concerns/pretty_inspect.rb +3 -3
- data/lib/mongomodel/concerns/properties.rb +18 -18
- data/lib/mongomodel/concerns/record_status.rb +9 -13
- data/lib/mongomodel/concerns/serialization.rb +4 -4
- data/lib/mongomodel/concerns/timestamps.rb +4 -4
- data/lib/mongomodel/concerns/translation.rb +2 -2
- data/lib/mongomodel/concerns/validations.rb +5 -5
- data/lib/mongomodel/concerns/validations/associated.rb +1 -1
- data/lib/mongomodel/document.rb +6 -6
- data/lib/mongomodel/document/callbacks.rb +15 -21
- data/lib/mongomodel/document/collection_modifiers.rb +5 -5
- data/lib/mongomodel/document/dynamic_finders.rb +1 -1
- data/lib/mongomodel/document/indexes.rb +19 -19
- data/lib/mongomodel/document/optimistic_locking.rb +7 -7
- data/lib/mongomodel/document/persistence.rb +23 -23
- data/lib/mongomodel/document/scopes.rb +20 -20
- data/lib/mongomodel/document/validations.rb +6 -6
- data/lib/mongomodel/document/validations/uniqueness.rb +11 -11
- data/lib/mongomodel/embedded_document.rb +11 -11
- data/lib/mongomodel/locale/en.yml +0 -1
- data/lib/mongomodel/log_subscriber.rb +5 -5
- data/lib/mongomodel/railtie.rb +13 -13
- data/lib/mongomodel/support/collection.rb +31 -31
- data/lib/mongomodel/support/configuration.rb +11 -11
- data/lib/mongomodel/support/core_extensions.rb +1 -1
- data/lib/mongomodel/support/dynamic_finder.rb +12 -12
- data/lib/mongomodel/support/exceptions.rb +6 -6
- data/lib/mongomodel/support/instrumented_collection.rb +20 -20
- data/lib/mongomodel/support/map.rb +33 -33
- data/lib/mongomodel/support/mongo_operator.rb +6 -6
- data/lib/mongomodel/support/mongo_options.rb +18 -18
- data/lib/mongomodel/support/mongo_order.rb +16 -16
- data/lib/mongomodel/support/paginator.rb +8 -8
- data/lib/mongomodel/support/reference.rb +10 -10
- data/lib/mongomodel/support/scope.rb +37 -37
- data/lib/mongomodel/support/scope/array_methods.rb +1 -1
- data/lib/mongomodel/support/scope/batches.rb +1 -1
- data/lib/mongomodel/support/scope/dynamic_finders.rb +1 -1
- data/lib/mongomodel/support/scope/finder_methods.rb +7 -7
- data/lib/mongomodel/support/scope/load_methods.rb +1 -1
- data/lib/mongomodel/support/scope/pagination.rb +1 -1
- data/lib/mongomodel/support/scope/query_methods.rb +6 -6
- data/lib/mongomodel/support/scope/spawn_methods.rb +8 -8
- data/lib/mongomodel/support/types.rb +2 -2
- data/lib/mongomodel/support/types/array.rb +1 -1
- data/lib/mongomodel/support/types/boolean.rb +3 -3
- data/lib/mongomodel/support/types/custom.rb +3 -3
- data/lib/mongomodel/support/types/date.rb +2 -2
- data/lib/mongomodel/support/types/date_time.rb +6 -16
- data/lib/mongomodel/support/types/float.rb +1 -1
- data/lib/mongomodel/support/types/hash.rb +1 -1
- data/lib/mongomodel/support/types/integer.rb +13 -10
- data/lib/mongomodel/support/types/object.rb +5 -5
- data/lib/mongomodel/support/types/rational.rb +3 -3
- data/lib/mongomodel/support/types/time.rb +2 -2
- data/lib/mongomodel/version.rb +1 -1
- data/lib/rails/generators/mongo_model/config/templates/mongomodel.yml +3 -4
- data/lib/rails/generators/mongo_model/model/model_generator.rb +3 -3
- data/mongomodel.gemspec +5 -4
- data/spec/mongomodel/attributes/store_spec.rb +21 -21
- data/spec/mongomodel/concerns/activemodel_spec.rb +4 -4
- data/spec/mongomodel/concerns/associations/base/association_spec.rb +12 -12
- data/spec/mongomodel/concerns/associations/belongs_to_spec.rb +34 -21
- data/spec/mongomodel/concerns/associations/has_many_by_foreign_key_spec.rb +53 -53
- data/spec/mongomodel/concerns/associations/has_many_by_ids_spec.rb +30 -30
- data/spec/mongomodel/concerns/attribute_methods/before_type_cast_spec.rb +7 -7
- data/spec/mongomodel/concerns/attribute_methods/dirty_spec.rb +45 -41
- data/spec/mongomodel/concerns/attribute_methods/multi_parameter_assignment_spec.rb +7 -7
- data/spec/mongomodel/concerns/attribute_methods/nested_spec.rb +31 -31
- data/spec/mongomodel/concerns/attribute_methods/protected_spec.rb +15 -15
- data/spec/mongomodel/concerns/attribute_methods/query_spec.rb +19 -19
- data/spec/mongomodel/concerns/attribute_methods/read_spec.rb +9 -9
- data/spec/mongomodel/concerns/attribute_methods/write_spec.rb +6 -6
- data/spec/mongomodel/concerns/attribute_methods_spec.rb +13 -13
- data/spec/mongomodel/concerns/attributes_spec.rb +34 -34
- data/spec/mongomodel/concerns/callbacks_spec.rb +25 -21
- data/spec/mongomodel/concerns/logging_spec.rb +5 -3
- data/spec/mongomodel/concerns/map_reduce_spec.rb +19 -19
- data/spec/mongomodel/concerns/observing_spec.rb +3 -3
- data/spec/mongomodel/concerns/pretty_inspect_spec.rb +10 -10
- data/spec/mongomodel/concerns/properties_spec.rb +11 -11
- data/spec/mongomodel/concerns/serialization/json_serialization_spec.rb +13 -13
- data/spec/mongomodel/concerns/timestamps_spec.rb +39 -39
- data/spec/mongomodel/concerns/validations_spec.rb +41 -38
- data/spec/mongomodel/document/callbacks_spec.rb +20 -16
- data/spec/mongomodel/document/collection_modifiers_spec.rb +16 -16
- data/spec/mongomodel/document/dynamic_finders_spec.rb +46 -46
- data/spec/mongomodel/document/finders_spec.rb +15 -15
- data/spec/mongomodel/document/indexes_spec.rb +29 -29
- data/spec/mongomodel/document/optimistic_locking_spec.rb +16 -16
- data/spec/mongomodel/document/persistence_spec.rb +39 -39
- data/spec/mongomodel/document/scopes_spec.rb +17 -17
- data/spec/mongomodel/document/validations/uniqueness_spec.rb +46 -46
- data/spec/mongomodel/document/validations_spec.rb +35 -35
- data/spec/mongomodel/document_spec.rb +19 -19
- data/spec/mongomodel/embedded_document_spec.rb +19 -19
- data/spec/mongomodel/mongomodel_spec.rb +7 -6
- data/spec/mongomodel/support/collection_spec.rb +54 -54
- data/spec/mongomodel/support/configuration_spec.rb +1 -1
- data/spec/mongomodel/support/map_spec.rb +66 -66
- data/spec/mongomodel/support/mongo_operator_spec.rb +5 -5
- data/spec/mongomodel/support/mongo_options_spec.rb +42 -42
- data/spec/mongomodel/support/mongo_order_spec.rb +24 -24
- data/spec/mongomodel/support/paginator_spec.rb +15 -15
- data/spec/mongomodel/support/property_spec.rb +29 -23
- data/spec/mongomodel/support/scope_spec.rb +205 -204
- data/spec/spec_helper.rb +13 -2
- data/spec/support/callbacks.rb +3 -8
- data/spec/support/helpers/define_class.rb +7 -7
- data/spec/support/helpers/document_finder_stubs.rb +6 -6
- data/spec/support/helpers/specs_for.rb +1 -1
- data/spec/support/helpers/validations.rb +1 -1
- data/spec/support/matchers/find_with.rb +8 -8
- data/spec/support/matchers/respond_to_boolean.rb +3 -3
- data/spec/support/matchers/run_callbacks.rb +6 -9
- data/spec/support/models.rb +5 -5
- metadata +23 -7
@@ -5,66 +5,66 @@ module MongoModel
|
|
5
5
|
def c(field, order)
|
6
6
|
MongoOrder::Clause.new(field, order)
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
subject { MongoOrder.new(c(:name, :ascending), c(:age, :descending)) }
|
10
|
-
|
10
|
+
|
11
11
|
it "converts to string" do
|
12
12
|
subject.to_s.should == "name ascending, age descending"
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
describe "#to_sort" do
|
16
16
|
it "converts to mongo sort array" do
|
17
17
|
model = double('model', :properties => double('properties', :[] => nil))
|
18
18
|
subject.to_sort(model).should == [['name', :ascending], ['age', :descending]]
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
it "is reversable" do
|
23
23
|
subject.reverse.should == MongoOrder.new(c(:name, :descending), c(:age, :ascending))
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
it "equals another order object with identical clauses" do
|
27
27
|
subject.should == MongoOrder.new(c(:name, :ascending), c(:age, :descending))
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
it "equals another order object with different clauses" do
|
31
31
|
subject.should_not == MongoOrder.new(c(:name, :ascending))
|
32
32
|
subject.should_not == MongoOrder.new(c(:age, :ascending), c(:name, :ascending))
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
describe "#parse" do
|
36
36
|
it "does not change a MongoOrder" do
|
37
37
|
MongoOrder.parse(subject).should == subject
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
it "converts individual clause to MongoOrder" do
|
41
41
|
MongoOrder.parse(c(:name, :ascending)).should == MongoOrder.new(c(:name, :ascending))
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
it "converts symbol to MongoOrder" do
|
45
45
|
MongoOrder.parse(:name).should == MongoOrder.new(c(:name, :ascending))
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
it "converts array of clauses to MongoOrder" do
|
49
49
|
MongoOrder.parse([c(:name, :ascending), c(:age, :descending)]).should == MongoOrder.new(c(:name, :ascending), c(:age, :descending))
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
it "converts array of symbols to MongoOrder" do
|
53
53
|
MongoOrder.parse([:name, :age]).should == MongoOrder.new(c(:name, :ascending), c(:age, :ascending))
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
it "converts array of strings to MongoOrder" do
|
57
57
|
MongoOrder.parse(['name ASC', 'age DESC']).should == MongoOrder.new(c(:name, :ascending), c(:age, :descending))
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
it "converts string (no order specified) to MongoOrder" do
|
61
61
|
MongoOrder.parse('name').should == MongoOrder.new(c(:name, :ascending))
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
it "converts string (single order) to MongoOrder" do
|
65
65
|
MongoOrder.parse('name DESC').should == MongoOrder.new(c(:name, :descending))
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
it "converts string (multiple orders) to MongoOrder" do
|
69
69
|
MongoOrder.parse('name DESC, age ASC').should == MongoOrder.new(c(:name, :descending), c(:age, :ascending))
|
70
70
|
end
|
@@ -73,24 +73,24 @@ module MongoModel
|
|
73
73
|
|
74
74
|
describe MongoOrder::Clause do
|
75
75
|
subject { MongoOrder::Clause.new(:name, :ascending) }
|
76
|
-
|
76
|
+
|
77
77
|
it "converts to string" do
|
78
78
|
subject.to_s.should == "name ascending"
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
it "equals another clause with the same field and order" do
|
82
82
|
subject.should == MongoOrder::Clause.new(:name, :ascending)
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
it "equals another clause with a different field or order" do
|
86
86
|
subject.should_not == MongoOrder::Clause.new(:age, :ascending)
|
87
87
|
subject.should_not == MongoOrder::Clause.new(:name, :descending)
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
90
|
it "is reversable" do
|
91
91
|
subject.reverse.should == MongoOrder::Clause.new(:name, :descending)
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
describe "#to_sort" do
|
95
95
|
context "given property" do
|
96
96
|
it "uses property as value to convert to mongo sort" do
|
@@ -98,22 +98,22 @@ module MongoModel
|
|
98
98
|
subject.to_sort(property).should == ['_name', :ascending]
|
99
99
|
end
|
100
100
|
end
|
101
|
-
|
101
|
+
|
102
102
|
context "given nil" do
|
103
103
|
it "converts to mongo sort" do
|
104
104
|
subject.to_sort(nil).should == ['name', :ascending]
|
105
105
|
end
|
106
106
|
end
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
109
|
describe "#parse" do
|
110
110
|
let(:asc) { MongoOrder::Clause.new(:name, :ascending) }
|
111
111
|
let(:desc) { MongoOrder::Clause.new(:name, :descending) }
|
112
|
-
|
112
|
+
|
113
113
|
it "creates Clause from string (no order)" do
|
114
114
|
MongoOrder::Clause.parse('name').should == asc
|
115
115
|
end
|
116
|
-
|
116
|
+
|
117
117
|
it "creates Clause from string (with order)" do
|
118
118
|
MongoOrder::Clause.parse('name ASC').should == asc
|
119
119
|
MongoOrder::Clause.parse('name asc').should == asc
|
@@ -6,50 +6,50 @@ module MongoModel
|
|
6
6
|
let(:scope) { double(:count => 35, :limit => entries).as_null_object }
|
7
7
|
let(:page) { 2 }
|
8
8
|
let(:per_page) { 10 }
|
9
|
-
|
9
|
+
|
10
10
|
subject { Paginator.new(scope, page, per_page) }
|
11
|
-
|
11
|
+
|
12
12
|
it { should be_a_kind_of(Array) }
|
13
|
-
|
13
|
+
|
14
14
|
its(:total_entries) { should == 35 }
|
15
15
|
its(:total_pages) { should == 4 }
|
16
|
-
|
16
|
+
|
17
17
|
its(:current_page) { should == 2 }
|
18
18
|
its(:previous_page) { should == 1 }
|
19
19
|
its(:next_page) { should == 3 }
|
20
20
|
its(:offset) { should == 10 }
|
21
|
-
|
21
|
+
|
22
22
|
its(:size) { should == 10 }
|
23
|
-
|
23
|
+
|
24
24
|
it { should_not be_out_of_bounds }
|
25
|
-
|
25
|
+
|
26
26
|
context "first page" do
|
27
27
|
let(:page) { 1 }
|
28
|
-
|
28
|
+
|
29
29
|
its(:previous_page) { should be_nil }
|
30
30
|
its(:next_page) { should == 2 }
|
31
31
|
its(:offset) { should == 0 }
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
context "last page" do
|
35
35
|
let(:entries) { [double] * 5 }
|
36
36
|
before { scope.stub(:count => nil) }
|
37
|
-
|
37
|
+
|
38
38
|
let(:page) { 4 }
|
39
|
-
|
39
|
+
|
40
40
|
its(:previous_page) { should == 3 }
|
41
41
|
its(:next_page) { should be_nil }
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
context "no entries" do
|
45
45
|
before { scope.stub(:count => 0) }
|
46
|
-
|
46
|
+
|
47
47
|
its(:total_pages) { should == 1 }
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
context "out of bounds" do
|
51
51
|
let(:page) { 5 }
|
52
|
-
|
52
|
+
|
53
53
|
it { should be_out_of_bounds }
|
54
54
|
end
|
55
55
|
end
|
@@ -5,93 +5,99 @@ module MongoModel
|
|
5
5
|
describe Property do
|
6
6
|
context "no options" do
|
7
7
|
subject { Property.new(:name, String) }
|
8
|
-
|
8
|
+
|
9
9
|
it "sets property name" do
|
10
10
|
subject.name.should == :name
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
it "sets property type" do
|
14
14
|
subject.type.should == String
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
it "sets default as value from name" do
|
18
18
|
subject.as.should == 'name'
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
it "defaults to nil" do
|
22
22
|
subject.default(double('document instance')).should be_nil
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
it "equals a property with the same name and type" do
|
26
26
|
subject.should == Property.new(:name, String)
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
it "does not equal properties with different name, type and options" do
|
30
30
|
subject.should_not == Property.new(:address, String)
|
31
31
|
subject.should_not == Property.new(:name, Float)
|
32
32
|
subject.should_not == Property.new(:name, String, :default => 'Anonymous')
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
it { should_not be_internal }
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
context "with options" do
|
39
39
|
subject { Property.new(:age, Integer, :as => '_record_age', :default => 21) }
|
40
|
-
|
40
|
+
|
41
41
|
it "sets property options" do
|
42
42
|
subject.options.should == { :as => '_record_age', :default => 21 }
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
it "sets custom as value" do
|
46
46
|
subject.as.should == '_record_age'
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
it "defaults to custom default" do
|
50
50
|
subject.default(double('document instance')).should == 21
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
it "equals a property with the same name, type and options" do
|
54
54
|
subject.should == Property.new(:age, Integer, :as => '_record_age', :default => 21)
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
it "does not equal properties with different name, type and options" do
|
58
58
|
subject.should_not == Property.new(:address, String)
|
59
59
|
subject.should_not == Property.new(:name, Float)
|
60
60
|
subject.should_not == Property.new(:name, String, :default => 'Anonymous')
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
context "with callable default" do
|
64
64
|
let(:document) { double('document instance', :answer => 42) }
|
65
|
-
|
65
|
+
|
66
66
|
it "calls the proc yielding the instance" do
|
67
67
|
property = Property.new(:age, Integer, :default => lambda { |doc| doc.answer })
|
68
68
|
property.default(document).should == 42
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
it "calls the proc in the context of the instance" do
|
72
72
|
property = Property.new(:age, Integer, :default => proc { answer })
|
73
73
|
property.default(document).should == 42
|
74
74
|
end
|
75
75
|
end
|
76
|
-
|
76
|
+
|
77
77
|
context "with internal option" do
|
78
78
|
subject { Property.new(:age, Integer, :internal => true) }
|
79
79
|
it { should be_internal }
|
80
80
|
end
|
81
|
-
|
81
|
+
|
82
82
|
context "with internal property name" do
|
83
83
|
subject { Property.new(:age, Integer, :as => '_age') }
|
84
84
|
it { should be_internal }
|
85
85
|
end
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
it "does not validate if options[:validate] is false" do
|
89
|
-
Property.new(:age, Integer, :validate => false).validate?.should
|
89
|
+
Property.new(:age, Integer, :validate => false).validate?.should be false
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
it "validates when options[:validate] is true or not provided" do
|
93
|
-
Property.new(:age, Integer, :validate => true).validate?.should
|
94
|
-
Property.new(:age, Integer).validate?.should
|
93
|
+
Property.new(:age, Integer, :validate => true).validate?.should be true
|
94
|
+
Property.new(:age, Integer).validate?.should be true
|
95
|
+
end
|
96
|
+
|
97
|
+
context "with type Integer" do
|
98
|
+
it "correctly converts type from mongo representation" do
|
99
|
+
Property.new(:age, Integer).from_mongo(15.0).should be_a_kind_of(Integer)
|
100
|
+
end
|
95
101
|
end
|
96
102
|
end
|
97
103
|
end
|
@@ -8,68 +8,68 @@ module MongoModel
|
|
8
8
|
property :author, String
|
9
9
|
property :date, Time
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
let(:basic_scope) { Scope.new(Post) }
|
13
13
|
let(:posts) { (1..5).map { Post.new } }
|
14
|
-
|
14
|
+
|
15
15
|
subject { Scope.new(Post) }
|
16
|
-
|
16
|
+
|
17
17
|
MongoModel::Document.extend(DocumentFinderStubs)
|
18
|
-
|
19
|
-
|
18
|
+
|
19
|
+
|
20
20
|
def self.subject_loaded(&block)
|
21
21
|
context "when loaded" do
|
22
22
|
before(:each) { subject.to_a }
|
23
23
|
class_eval(&block)
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
def self.subject_not_loaded(&block)
|
28
28
|
context "when not loaded", &block
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def self.always(&block)
|
32
32
|
subject_loaded(&block)
|
33
33
|
subject_not_loaded(&block)
|
34
34
|
end
|
35
|
-
|
36
|
-
|
35
|
+
|
36
|
+
|
37
37
|
shared_examples_for "all scopes" do
|
38
38
|
def finder_conditions
|
39
39
|
finder_options[:conditions] || {}
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
describe "#to_a" do
|
43
43
|
it "finds and return documents matching conditions" do
|
44
44
|
model.should_find(finder_options, posts) do
|
45
45
|
subject.to_a.should == posts
|
46
46
|
end
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
it "loads the scope" do
|
50
50
|
subject.to_a
|
51
51
|
subject.should be_loaded
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
it "caches the documents" do
|
55
55
|
subject.to_a
|
56
56
|
model.should_not_find { subject.to_a }
|
57
57
|
end
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
describe "#as_json" do
|
61
61
|
it "delegates to #to_a" do
|
62
62
|
subject.as_json.should == subject.to_a.as_json
|
63
63
|
end
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
describe "#count" do
|
67
67
|
it "counts documents matching conditions and return the result" do
|
68
68
|
model.should_count(finder_options, 4) do
|
69
69
|
subject.count
|
70
70
|
end
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
it "does not cache the result" do
|
74
74
|
subject.count
|
75
75
|
model.should_count(finder_options, 4) do
|
@@ -77,25 +77,25 @@ module MongoModel
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
describe "#size" do
|
82
82
|
before(:each) { model.stub_find(posts) }
|
83
|
-
|
83
|
+
|
84
84
|
subject_loaded do
|
85
85
|
it "returns the number of matching documents" do
|
86
86
|
subject.size.should == 5
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
89
|
it "does not perform a count on the collection" do
|
90
90
|
model.should_not_count { subject.size }
|
91
91
|
end
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
subject_not_loaded do
|
95
95
|
it "returns the number of matching documents" do
|
96
96
|
subject.size.should == 5
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
it "performs a count on the collection" do
|
100
100
|
model.should_count(finder_options, 9) do
|
101
101
|
subject.size.should == 9
|
@@ -103,42 +103,42 @@ module MongoModel
|
|
103
103
|
end
|
104
104
|
end
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
describe "#empty?" do
|
108
108
|
context "when no matching documents exist" do
|
109
109
|
before(:each) { model.stub_find([]) }
|
110
|
-
|
110
|
+
|
111
111
|
always do
|
112
112
|
it { should be_empty }
|
113
113
|
end
|
114
114
|
end
|
115
|
-
|
115
|
+
|
116
116
|
context "when matching documents exist" do
|
117
117
|
before(:each) { model.stub_find(posts) }
|
118
|
-
|
118
|
+
|
119
119
|
always do
|
120
120
|
it { should_not be_empty }
|
121
121
|
end
|
122
122
|
end
|
123
|
-
|
123
|
+
|
124
124
|
subject_loaded do
|
125
125
|
it "does not perform a count on the collection" do
|
126
126
|
model.should_not_count { subject.empty? }
|
127
127
|
end
|
128
128
|
end
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
describe "#any?" do
|
132
132
|
context "when no block given" do
|
133
133
|
it "performs a count on the collection" do
|
134
134
|
model.should_count(finder_options, 1) { subject.any? }
|
135
135
|
end
|
136
|
-
|
136
|
+
|
137
137
|
context "when no matching documents exist" do
|
138
138
|
before(:each) { model.stub_find([]) }
|
139
139
|
|
140
140
|
always do
|
141
|
-
specify { subject.any?.should
|
141
|
+
specify { subject.any?.should be false }
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
@@ -146,20 +146,21 @@ module MongoModel
|
|
146
146
|
before(:each) { model.stub_find(posts) }
|
147
147
|
|
148
148
|
always do
|
149
|
-
specify { subject.any?.should
|
149
|
+
specify { subject.any?.should be true }
|
150
150
|
end
|
151
151
|
end
|
152
152
|
end
|
153
|
-
|
153
|
+
|
154
154
|
context "when block given" do
|
155
155
|
it "delegates block to to_a" do
|
156
|
-
|
157
|
-
|
158
|
-
subject.any?(
|
156
|
+
result = double
|
157
|
+
blk = lambda {}
|
158
|
+
subject.to_a.should_receive(:any?).and_return(result)
|
159
|
+
subject.any?(&blk).should == result
|
159
160
|
end
|
160
161
|
end
|
161
162
|
end
|
162
|
-
|
163
|
+
|
163
164
|
describe "#reset" do
|
164
165
|
always do
|
165
166
|
it "returns itself" do
|
@@ -172,7 +173,7 @@ module MongoModel
|
|
172
173
|
end
|
173
174
|
end
|
174
175
|
end
|
175
|
-
|
176
|
+
|
176
177
|
describe "#reload" do
|
177
178
|
always do
|
178
179
|
it "returns itself" do
|
@@ -183,7 +184,7 @@ module MongoModel
|
|
183
184
|
subject.reload
|
184
185
|
subject.should be_loaded
|
185
186
|
end
|
186
|
-
|
187
|
+
|
187
188
|
it "resets its finder options" do
|
188
189
|
old_finder_options = subject.finder_options
|
189
190
|
subject.reload.finder_options.should_not equal(old_finder_options)
|
@@ -195,10 +196,10 @@ module MongoModel
|
|
195
196
|
end
|
196
197
|
end
|
197
198
|
end
|
198
|
-
|
199
|
+
|
199
200
|
describe "#==" do
|
200
201
|
before(:each) { model.stub_find(posts) }
|
201
|
-
|
202
|
+
|
202
203
|
it "is equal to an array with matching results" do
|
203
204
|
subject.should == posts
|
204
205
|
end
|
@@ -207,7 +208,7 @@ module MongoModel
|
|
207
208
|
subject.should_not == []
|
208
209
|
end
|
209
210
|
end
|
210
|
-
|
211
|
+
|
211
212
|
describe "array methods" do
|
212
213
|
it "forwards [] to to_a" do
|
213
214
|
subject.to_a.should_receive(:[]).with(0)
|
@@ -215,181 +216,181 @@ module MongoModel
|
|
215
216
|
end
|
216
217
|
|
217
218
|
it "forwards each to to_a" do
|
218
|
-
blk = lambda {
|
219
|
-
subject.to_a.should_receive(:each).
|
220
|
-
subject.each(&blk)
|
219
|
+
blk = lambda {}
|
220
|
+
subject.to_a.should_receive(:each).and_return([1, 2, 3])
|
221
|
+
subject.each(&blk).should eq [1, 2, 3]
|
221
222
|
end
|
222
223
|
end
|
223
|
-
|
224
|
+
|
224
225
|
describe "#where" do
|
225
226
|
it "returns a new scope" do
|
226
227
|
subject.where(:author => "Sam").should be_an_instance_of(Scope)
|
227
228
|
end
|
228
|
-
|
229
|
+
|
229
230
|
it "is not loaded" do
|
230
231
|
subject.to_a
|
231
232
|
subject.where(:author => "Sam").should_not be_loaded
|
232
233
|
end
|
233
|
-
|
234
|
+
|
234
235
|
it "adds individual where values" do
|
235
236
|
where_scope = subject.where(:author => "Sam")
|
236
237
|
where_scope.where_values.should == subject.where_values + [{ :author => "Sam" }]
|
237
238
|
end
|
238
|
-
|
239
|
+
|
239
240
|
it "adds multiple where values" do
|
240
241
|
where_scope = subject.where({ :author => "Sam" }, { :published => false })
|
241
242
|
where_scope.where_values.should == subject.where_values + [{ :author => "Sam" }, { :published => false }]
|
242
243
|
end
|
243
244
|
end
|
244
|
-
|
245
|
+
|
245
246
|
describe "#where!" do
|
246
247
|
it "overwrites where values" do
|
247
248
|
where_scope = subject.where!(:author => "Sam")
|
248
249
|
where_scope.where_values.should == [{ :author => "Sam" }]
|
249
250
|
end
|
250
251
|
end
|
251
|
-
|
252
|
+
|
252
253
|
describe "#order" do
|
253
254
|
it "returns a new scope" do
|
254
255
|
subject.order(:author.asc).should be_an_instance_of(Scope)
|
255
256
|
end
|
256
|
-
|
257
|
+
|
257
258
|
it "is not loaded" do
|
258
259
|
subject.to_a
|
259
260
|
subject.order(:author.asc).should_not be_loaded
|
260
261
|
end
|
261
|
-
|
262
|
+
|
262
263
|
it "adds individual order values" do
|
263
264
|
order_scope = subject.order(:author.asc)
|
264
265
|
order_scope.order_values.should == subject.order_values + [:author.asc]
|
265
266
|
end
|
266
|
-
|
267
|
+
|
267
268
|
it "adds multiple order values" do
|
268
269
|
order_scope = subject.order(:author.asc, :published.desc)
|
269
270
|
order_scope.order_values.should == subject.order_values + [:author.asc, :published.desc]
|
270
271
|
end
|
271
272
|
end
|
272
|
-
|
273
|
+
|
273
274
|
describe "#order!" do
|
274
275
|
it "overwrites order values" do
|
275
276
|
order_scope = subject.order!(:author.asc)
|
276
277
|
order_scope.order_values.should == [:author.asc]
|
277
278
|
end
|
278
279
|
end
|
279
|
-
|
280
|
+
|
280
281
|
describe "#select" do
|
281
282
|
context "when no block is given" do
|
282
283
|
it "returns a new scope" do
|
283
284
|
subject.select(:author).should be_an_instance_of(Scope)
|
284
285
|
end
|
285
|
-
|
286
|
+
|
286
287
|
it "is not loaded" do
|
287
288
|
subject.to_a
|
288
289
|
subject.select(:author).should_not be_loaded
|
289
290
|
end
|
290
|
-
|
291
|
+
|
291
292
|
it "adds individual select values" do
|
292
293
|
select_scope = subject.select(:author)
|
293
294
|
select_scope.select_values.should == subject.select_values + [:author]
|
294
295
|
end
|
295
|
-
|
296
|
+
|
296
297
|
it "adds multiple select values" do
|
297
298
|
select_scope = subject.select(:author, :published)
|
298
299
|
select_scope.select_values.should == subject.select_values + [:author, :published]
|
299
300
|
end
|
300
301
|
end
|
301
|
-
|
302
|
+
|
302
303
|
context "when a block given" do
|
303
304
|
it "passed block to to_a#select" do
|
304
|
-
blk = lambda {
|
305
|
-
subject.to_a.should_receive(:select).
|
306
|
-
subject.select(&blk)
|
305
|
+
blk = lambda {}
|
306
|
+
subject.to_a.should_receive(:select).and_return([1, 2, 3])
|
307
|
+
subject.select(&blk).should eq [1, 2, 3]
|
307
308
|
end
|
308
309
|
end
|
309
310
|
end
|
310
|
-
|
311
|
+
|
311
312
|
describe "#select!" do
|
312
313
|
it "overwrites select values" do
|
313
314
|
select_scope = subject.select!(:author)
|
314
315
|
select_scope.select_values.should == [:author]
|
315
316
|
end
|
316
317
|
end
|
317
|
-
|
318
|
+
|
318
319
|
describe "#limit" do
|
319
320
|
it "returns a new scope" do
|
320
321
|
subject.limit(10).should be_an_instance_of(Scope)
|
321
322
|
end
|
322
|
-
|
323
|
+
|
323
324
|
it "is not loaded" do
|
324
325
|
subject.limit(10).should_not be_loaded
|
325
326
|
end
|
326
|
-
|
327
|
+
|
327
328
|
it "overrides previous limit value" do
|
328
329
|
subject.limit(10).limit_value.should == 10
|
329
330
|
end
|
330
331
|
end
|
331
|
-
|
332
|
+
|
332
333
|
describe "#offset" do
|
333
334
|
it "returns a new scope" do
|
334
335
|
subject.offset(10).should be_an_instance_of(Scope)
|
335
336
|
end
|
336
|
-
|
337
|
+
|
337
338
|
it "is not loaded" do
|
338
339
|
subject.offset(10).should_not be_loaded
|
339
340
|
end
|
340
|
-
|
341
|
+
|
341
342
|
it "overrides previous offset value" do
|
342
343
|
subject.offset(10).offset_value.should == 10
|
343
344
|
end
|
344
345
|
end
|
345
|
-
|
346
|
+
|
346
347
|
describe "#from" do
|
347
348
|
define_class(:NotAPost, Document)
|
348
|
-
|
349
|
+
|
349
350
|
it "returns a new scope" do
|
350
351
|
subject.from(NotAPost.collection).should be_an_instance_of(Scope)
|
351
352
|
end
|
352
|
-
|
353
|
+
|
353
354
|
it "is not loaded" do
|
354
355
|
subject.from(NotAPost.collection).should_not be_loaded
|
355
356
|
end
|
356
|
-
|
357
|
+
|
357
358
|
it "overrides collection" do
|
358
359
|
subject.from(NotAPost.collection).collection.should == NotAPost.collection
|
359
360
|
end
|
360
|
-
|
361
|
+
|
361
362
|
it "allows collection to be set using string" do
|
362
363
|
subject.from(NotAPost.collection.name).collection.name.should == NotAPost.collection.name
|
363
364
|
end
|
364
365
|
end
|
365
|
-
|
366
|
+
|
366
367
|
describe "#first" do
|
367
368
|
context "with count argument" do
|
368
369
|
context "when no matching documents exist" do
|
369
370
|
before(:each) { model.stub_find([]) }
|
370
|
-
|
371
|
+
|
371
372
|
always do
|
372
373
|
it "returns an empty array" do
|
373
374
|
subject.first(3).should == []
|
374
375
|
end
|
375
376
|
end
|
376
|
-
|
377
|
+
|
377
378
|
subject_loaded do
|
378
379
|
it "does not perform a find" do
|
379
380
|
model.should_not_find { subject.first(3) }
|
380
381
|
end
|
381
382
|
end
|
382
|
-
|
383
|
+
|
383
384
|
subject_not_loaded do
|
384
385
|
it "finds with a limit of 3" do
|
385
386
|
model.should_find(finder_options.merge(:limit => 3), []) { subject.first(3) }
|
386
387
|
end
|
387
388
|
end
|
388
389
|
end
|
389
|
-
|
390
|
+
|
390
391
|
context "when matching documents exist" do
|
391
392
|
before(:each) { model.stub_find([posts[0], posts[1], posts[2]]) }
|
392
|
-
|
393
|
+
|
393
394
|
always do
|
394
395
|
it "returns the first documents in an array" do
|
395
396
|
subject.first(3).should == [posts[0], posts[1], posts[2]]
|
@@ -397,33 +398,33 @@ module MongoModel
|
|
397
398
|
end
|
398
399
|
end
|
399
400
|
end
|
400
|
-
|
401
|
+
|
401
402
|
context "with no argument" do
|
402
403
|
context "when no matching documents exist" do
|
403
404
|
before(:each) { model.stub_find([]) }
|
404
|
-
|
405
|
+
|
405
406
|
always do
|
406
407
|
it "returns nil" do
|
407
408
|
subject.first.should be_nil
|
408
409
|
end
|
409
410
|
end
|
410
|
-
|
411
|
+
|
411
412
|
subject_loaded do
|
412
413
|
it "does not perform a find" do
|
413
414
|
model.should_not_find { subject.first }
|
414
415
|
end
|
415
416
|
end
|
416
|
-
|
417
|
+
|
417
418
|
subject_not_loaded do
|
418
419
|
it "finds with a limit of 1" do
|
419
420
|
model.should_find(finder_options.merge(:limit => 1), []) { subject.first }
|
420
421
|
end
|
421
422
|
end
|
422
423
|
end
|
423
|
-
|
424
|
+
|
424
425
|
context "when matching documents exist" do
|
425
426
|
before(:each) { model.stub_find([posts[0]]) }
|
426
|
-
|
427
|
+
|
427
428
|
always do
|
428
429
|
it "returns the first document" do
|
429
430
|
subject.first.should == posts[0]
|
@@ -432,39 +433,39 @@ module MongoModel
|
|
432
433
|
end
|
433
434
|
end
|
434
435
|
end
|
435
|
-
|
436
|
+
|
436
437
|
describe "#last" do
|
437
438
|
def reversed_finder_options
|
438
439
|
order = MongoModel::MongoOrder.parse(finder_options[:order] || [:id.asc])
|
439
440
|
finder_options.merge(:order => order.reverse.to_a)
|
440
441
|
end
|
441
|
-
|
442
|
+
|
442
443
|
context "with count argument" do
|
443
444
|
context "when no matching documents exist" do
|
444
445
|
before(:each) { model.stub_find([]) }
|
445
|
-
|
446
|
+
|
446
447
|
always do
|
447
448
|
it "returns an empty array" do
|
448
449
|
subject.last(2).should == []
|
449
450
|
end
|
450
451
|
end
|
451
|
-
|
452
|
+
|
452
453
|
subject_loaded do
|
453
454
|
it "does not perform a find" do
|
454
455
|
model.should_not_find { subject.last(2) }
|
455
456
|
end
|
456
457
|
end
|
457
|
-
|
458
|
+
|
458
459
|
subject_not_loaded do
|
459
460
|
it "finds with a limit of 2" do
|
460
461
|
model.should_find(reversed_finder_options.merge(:limit => 2), []) { subject.last(2) }
|
461
462
|
end
|
462
463
|
end
|
463
464
|
end
|
464
|
-
|
465
|
+
|
465
466
|
context "when matching documents exist" do
|
466
467
|
before(:each) { model.stub_find([posts[0], posts[1]]) }
|
467
|
-
|
468
|
+
|
468
469
|
always do
|
469
470
|
it "returns the last documents in an array" do
|
470
471
|
subject.last(2).should == [posts[0], posts[1]]
|
@@ -472,34 +473,34 @@ module MongoModel
|
|
472
473
|
end
|
473
474
|
end
|
474
475
|
end
|
475
|
-
|
476
|
+
|
476
477
|
context "with no argument" do
|
477
478
|
context "when no matching documents exist" do
|
478
479
|
before(:each) { model.stub_find([]) }
|
479
|
-
|
480
|
+
|
480
481
|
always do
|
481
482
|
it "returns nil" do
|
482
483
|
subject.last.should be_nil
|
483
484
|
end
|
484
485
|
end
|
485
|
-
|
486
|
+
|
486
487
|
subject_loaded do
|
487
488
|
it "does not perform a find" do
|
488
489
|
model.should_not_find { subject.last }
|
489
490
|
end
|
490
491
|
end
|
491
|
-
|
492
|
+
|
492
493
|
subject_not_loaded do
|
493
494
|
it "finds with a limit of 1" do
|
494
495
|
model.should_find(reversed_finder_options.merge(:limit => 1), []) { subject.last }
|
495
496
|
end
|
496
497
|
end
|
497
498
|
end
|
498
|
-
|
499
|
+
|
499
500
|
context "when matching documents exist" do
|
500
501
|
let(:post) { posts.last }
|
501
502
|
before(:each) { model.stub_find([post]) }
|
502
|
-
|
503
|
+
|
503
504
|
always do
|
504
505
|
it "returns the last document" do
|
505
506
|
subject.last.should == post
|
@@ -508,7 +509,7 @@ module MongoModel
|
|
508
509
|
end
|
509
510
|
end
|
510
511
|
end
|
511
|
-
|
512
|
+
|
512
513
|
describe "#all" do
|
513
514
|
it "returns all documents" do
|
514
515
|
model.should_find(finder_options, posts) do
|
@@ -516,20 +517,20 @@ module MongoModel
|
|
516
517
|
end
|
517
518
|
end
|
518
519
|
end
|
519
|
-
|
520
|
+
|
520
521
|
describe "#find" do
|
521
522
|
context "with single id" do
|
522
523
|
let(:post) { posts.first }
|
523
|
-
|
524
|
+
|
524
525
|
it "performs find on collection" do
|
525
526
|
model.should_find(finder_options.deep_merge(:conditions => { :id => post.id }, :limit => 1), [post]) do
|
526
527
|
subject.find(post.id)
|
527
528
|
end
|
528
529
|
end
|
529
|
-
|
530
|
+
|
530
531
|
context "when document exists" do
|
531
532
|
before(:each) { model.stub_find([post]) }
|
532
|
-
|
533
|
+
|
533
534
|
it "finds and return document" do
|
534
535
|
subject.find(post.id).should == post
|
535
536
|
end
|
@@ -537,7 +538,7 @@ module MongoModel
|
|
537
538
|
|
538
539
|
context "when document does not exist" do
|
539
540
|
before(:each) { model.stub_find([]) }
|
540
|
-
|
541
|
+
|
541
542
|
it "raises a DocumentNotFound exception" do
|
542
543
|
lambda {
|
543
544
|
subject.find('missing')
|
@@ -549,24 +550,24 @@ module MongoModel
|
|
549
550
|
context "by multiple ids" do
|
550
551
|
let(:post1) { posts.first }
|
551
552
|
let(:post2) { posts.last }
|
552
|
-
|
553
|
+
|
553
554
|
it "performs find on collection" do
|
554
555
|
model.should_find(finder_options.deep_merge(:conditions => { :id.in => [post2.id, post1.id] }), [post1, post2]) do
|
555
556
|
subject.find(post2.id, post1.id)
|
556
557
|
end
|
557
558
|
end
|
558
|
-
|
559
|
+
|
559
560
|
context "when all documents exist" do
|
560
561
|
before(:each) { model.stub_find([post2, post1]) }
|
561
|
-
|
562
|
+
|
562
563
|
it "returns documents in order given" do
|
563
564
|
subject.find(post2.id, post1.id).should == [post2, post1]
|
564
565
|
end
|
565
566
|
end
|
566
|
-
|
567
|
+
|
567
568
|
context "when some documents do not exist" do
|
568
569
|
before(:each) { model.stub_find([post1]) }
|
569
|
-
|
570
|
+
|
570
571
|
it "raises a DocumentNotFound exception" do
|
571
572
|
lambda {
|
572
573
|
subject.find(post1.id, 'missing')
|
@@ -575,7 +576,7 @@ module MongoModel
|
|
575
576
|
end
|
576
577
|
end
|
577
578
|
end
|
578
|
-
|
579
|
+
|
579
580
|
describe "#exists?" do
|
580
581
|
let(:post) { posts.first }
|
581
582
|
|
@@ -587,28 +588,28 @@ module MongoModel
|
|
587
588
|
|
588
589
|
context "when the document exists" do
|
589
590
|
before(:each) { model.stub_find([post])}
|
590
|
-
|
591
|
+
|
591
592
|
it "returns true" do
|
592
|
-
subject.exists?(post.id).should
|
593
|
+
subject.exists?(post.id).should be true
|
593
594
|
end
|
594
595
|
end
|
595
596
|
|
596
597
|
context "when the document does not exist" do
|
597
598
|
before(:each) { model.stub_find([])}
|
598
|
-
|
599
|
+
|
599
600
|
it "returns false" do
|
600
|
-
subject.exists?('missing').should
|
601
|
+
subject.exists?('missing').should be false
|
601
602
|
end
|
602
603
|
end
|
603
604
|
end
|
604
|
-
|
605
|
+
|
605
606
|
describe "#delete_all" do
|
606
607
|
it "removes all matching documents from collection" do
|
607
608
|
model.should_delete(finder_conditions) do
|
608
609
|
subject.delete_all
|
609
610
|
end
|
610
611
|
end
|
611
|
-
|
612
|
+
|
612
613
|
subject_loaded do
|
613
614
|
it "resets the scope" do
|
614
615
|
subject.delete_all
|
@@ -616,7 +617,7 @@ module MongoModel
|
|
616
617
|
end
|
617
618
|
end
|
618
619
|
end
|
619
|
-
|
620
|
+
|
620
621
|
describe "#delete" do
|
621
622
|
context "by single id" do
|
622
623
|
it "removes the document from the collection" do
|
@@ -624,7 +625,7 @@ module MongoModel
|
|
624
625
|
subject.delete("the-id")
|
625
626
|
end
|
626
627
|
end
|
627
|
-
|
628
|
+
|
628
629
|
subject_loaded do
|
629
630
|
it "resets the scope" do
|
630
631
|
subject.delete("the-id")
|
@@ -632,14 +633,14 @@ module MongoModel
|
|
632
633
|
end
|
633
634
|
end
|
634
635
|
end
|
635
|
-
|
636
|
+
|
636
637
|
context "by multiple ids" do
|
637
638
|
it "removes the document from the collection" do
|
638
639
|
model.should_delete(finder_conditions.merge(:id.in => ["first-id", "second-id"])) do
|
639
640
|
subject.delete("first-id", "second-id")
|
640
641
|
end
|
641
642
|
end
|
642
|
-
|
643
|
+
|
643
644
|
subject_loaded do
|
644
645
|
it "resets the scope" do
|
645
646
|
subject.delete("first-id", "second-id")
|
@@ -648,19 +649,19 @@ module MongoModel
|
|
648
649
|
end
|
649
650
|
end
|
650
651
|
end
|
651
|
-
|
652
|
+
|
652
653
|
describe "#destroy_all" do
|
653
654
|
let(:post1) { posts.first }
|
654
655
|
let(:post2) { posts.last }
|
655
|
-
|
656
|
+
|
656
657
|
before(:each) { model.stub_find([post1, post2]) }
|
657
|
-
|
658
|
+
|
658
659
|
it "destroys all matching documents individually" do
|
659
660
|
Post.should_delete(:id => post1.id)
|
660
661
|
Post.should_delete(:id => post2.id)
|
661
662
|
subject.destroy_all
|
662
663
|
end
|
663
|
-
|
664
|
+
|
664
665
|
subject_loaded do
|
665
666
|
it "resets the scope" do
|
666
667
|
subject.destroy_all
|
@@ -668,18 +669,18 @@ module MongoModel
|
|
668
669
|
end
|
669
670
|
end
|
670
671
|
end
|
671
|
-
|
672
|
+
|
672
673
|
describe "#destroy" do
|
673
674
|
context "by single id" do
|
674
675
|
let(:post) { posts.first }
|
675
|
-
|
676
|
+
|
676
677
|
before(:each) { model.stub_find([post]) }
|
677
|
-
|
678
|
+
|
678
679
|
it "destroys the retrieved document" do
|
679
680
|
Post.should_delete(:id => post.id)
|
680
681
|
subject.destroy(post.id)
|
681
682
|
end
|
682
|
-
|
683
|
+
|
683
684
|
subject_loaded do
|
684
685
|
it "resets the scope" do
|
685
686
|
subject.destroy(post.id)
|
@@ -687,19 +688,19 @@ module MongoModel
|
|
687
688
|
end
|
688
689
|
end
|
689
690
|
end
|
690
|
-
|
691
|
+
|
691
692
|
context "by multiple ids" do
|
692
693
|
let(:post1) { posts.first }
|
693
694
|
let(:post2) { posts.last }
|
694
|
-
|
695
|
+
|
695
696
|
before(:each) { model.stub_find([post1, post2]) }
|
696
|
-
|
697
|
+
|
697
698
|
it "destroys the documents individually" do
|
698
699
|
Post.should_delete(:id => post1.id)
|
699
700
|
Post.should_delete(:id => post2.id)
|
700
701
|
subject.destroy(post1.id, post2.id)
|
701
702
|
end
|
702
|
-
|
703
|
+
|
703
704
|
subject_loaded do
|
704
705
|
it "resets the scope" do
|
705
706
|
subject.destroy(post1.id, post2.id)
|
@@ -708,13 +709,13 @@ module MongoModel
|
|
708
709
|
end
|
709
710
|
end
|
710
711
|
end
|
711
|
-
|
712
|
+
|
712
713
|
describe "#update_all" do
|
713
714
|
it "updates all matching documents" do
|
714
715
|
model.should_update(finder_conditions, { :name => "New name" })
|
715
716
|
subject.update_all(:name => "New name")
|
716
717
|
end
|
717
|
-
|
718
|
+
|
718
719
|
subject_loaded do
|
719
720
|
it "resets the scope" do
|
720
721
|
subject.update_all(:name => "New name")
|
@@ -722,16 +723,16 @@ module MongoModel
|
|
722
723
|
end
|
723
724
|
end
|
724
725
|
end
|
725
|
-
|
726
|
+
|
726
727
|
describe "#update" do
|
727
728
|
context "by single id" do
|
728
729
|
let(:post) { posts.first }
|
729
|
-
|
730
|
+
|
730
731
|
it "updates the document with the given id" do
|
731
732
|
model.should_update(finder_conditions.merge(:id => post.id), { :name => "New name" })
|
732
733
|
subject.update(post.id, :name => "New name")
|
733
734
|
end
|
734
|
-
|
735
|
+
|
735
736
|
subject_loaded do
|
736
737
|
it "resets the scope" do
|
737
738
|
subject.update(post.id, {})
|
@@ -739,16 +740,16 @@ module MongoModel
|
|
739
740
|
end
|
740
741
|
end
|
741
742
|
end
|
742
|
-
|
743
|
+
|
743
744
|
context "by multiple ids" do
|
744
745
|
let(:post1) { posts.first }
|
745
746
|
let(:post2) { posts.last }
|
746
|
-
|
747
|
+
|
747
748
|
it "updates the documents with the given ids" do
|
748
749
|
model.should_update(finder_conditions.merge(:id.in => [post1.id, post2.id]), { :name => "New name" })
|
749
750
|
subject.update([post1.id, post2.id], :name => "New name")
|
750
751
|
end
|
751
|
-
|
752
|
+
|
752
753
|
subject_loaded do
|
753
754
|
it "resets the scope" do
|
754
755
|
subject.update([post1.id, post2.id], {})
|
@@ -757,55 +758,55 @@ module MongoModel
|
|
757
758
|
end
|
758
759
|
end
|
759
760
|
end
|
760
|
-
|
761
|
+
|
761
762
|
describe "#paginate" do
|
762
763
|
it "loads the first page of results by default" do
|
763
764
|
model.should_find(finder_options.merge(:offset => 0, :limit => 20), posts) {
|
764
765
|
subject.paginate
|
765
766
|
}
|
766
767
|
end
|
767
|
-
|
768
|
+
|
768
769
|
it "loads a specified page of results" do
|
769
770
|
model.should_find(finder_options.merge(:offset => 40, :limit => 20), posts) {
|
770
771
|
subject.paginate(:page => 3)
|
771
772
|
}
|
772
773
|
end
|
773
|
-
|
774
|
+
|
774
775
|
it "allows the per_page option to be set" do
|
775
776
|
model.should_find(finder_options.merge(:offset => 7, :limit => 7), posts) {
|
776
777
|
subject.paginate(:per_page => 7, :page => 2)
|
777
778
|
}
|
778
779
|
end
|
779
|
-
|
780
|
+
|
780
781
|
it "auto s-detect total entries where possible" do
|
781
782
|
paginator = nil
|
782
|
-
|
783
|
+
|
783
784
|
model.should_find(finder_options.merge(:offset => 0, :limit => 20), posts) {
|
784
785
|
paginator = subject.paginate
|
785
786
|
}
|
786
|
-
|
787
|
+
|
787
788
|
paginator.total_entries.should == 5
|
788
789
|
end
|
789
|
-
|
790
|
+
|
790
791
|
it "loads total entries using count when auto-detection not possible" do
|
791
792
|
paginator = nil
|
792
|
-
|
793
|
+
|
793
794
|
subject.stub(:count).and_return(57)
|
794
795
|
model.should_find(finder_options.merge(:offset => 0, :limit => 5), posts) {
|
795
796
|
paginator = subject.paginate(:per_page => 5)
|
796
797
|
}
|
797
|
-
|
798
|
+
|
798
799
|
paginator.total_entries.should == 57
|
799
800
|
end
|
800
801
|
end
|
801
|
-
|
802
|
+
|
802
803
|
describe "#in_batches" do
|
803
804
|
it "yields documents in groups of given size" do
|
804
805
|
model.should_find(finder_options.merge(:offset => 0, :limit => 3), posts.first(3))
|
805
806
|
model.should_find(finder_options.merge(:offset => 3, :limit => 3), posts.last(2))
|
806
|
-
|
807
|
+
|
807
808
|
expected_size = 3
|
808
|
-
|
809
|
+
|
809
810
|
subject.in_batches(3) do |docs|
|
810
811
|
docs.size.should == expected_size
|
811
812
|
expected_size = 2
|
@@ -813,34 +814,34 @@ module MongoModel
|
|
813
814
|
end
|
814
815
|
end
|
815
816
|
end
|
816
|
-
|
817
|
-
|
817
|
+
|
818
|
+
|
818
819
|
context "without criteria" do
|
819
820
|
subject { basic_scope }
|
820
|
-
|
821
|
+
|
821
822
|
context "when initialized" do
|
822
823
|
it { should_not be_loaded }
|
823
824
|
end
|
824
|
-
|
825
|
+
|
825
826
|
context "when loaded" do
|
826
827
|
before(:each) { subject.to_a }
|
827
828
|
its(:clone) { should_not be_loaded }
|
828
829
|
end
|
829
|
-
|
830
|
+
|
830
831
|
def model
|
831
832
|
Post
|
832
833
|
end
|
833
|
-
|
834
|
+
|
834
835
|
def finder_options
|
835
836
|
{}
|
836
837
|
end
|
837
|
-
|
838
|
+
|
838
839
|
it_should_behave_like "all scopes"
|
839
|
-
|
840
|
+
|
840
841
|
it "uses collection from class" do
|
841
842
|
subject.collection.should == Post.collection
|
842
843
|
end
|
843
|
-
|
844
|
+
|
844
845
|
describe "#inspect" do
|
845
846
|
before(:each) { Post.stub_find(posts) }
|
846
847
|
|
@@ -848,10 +849,10 @@ module MongoModel
|
|
848
849
|
subject.inspect.should == posts.inspect
|
849
850
|
end
|
850
851
|
end
|
851
|
-
|
852
|
+
|
852
853
|
describe "#==" do
|
853
854
|
define_class(:NotAPost, Document)
|
854
|
-
|
855
|
+
|
855
856
|
it "is equal to a new scope for the same class" do
|
856
857
|
subject.should == Scope.new(Post)
|
857
858
|
end
|
@@ -860,69 +861,69 @@ module MongoModel
|
|
860
861
|
subject.should_not == Scope.new(NotAPost)
|
861
862
|
end
|
862
863
|
end
|
863
|
-
|
864
|
+
|
864
865
|
describe "#reverse_order" do
|
865
866
|
subject { basic_scope.reverse_order }
|
866
|
-
|
867
|
+
|
867
868
|
it "returns a new scope" do
|
868
869
|
subject.should be_an_instance_of(Scope)
|
869
870
|
end
|
870
|
-
|
871
|
+
|
871
872
|
it "is not loaded" do
|
872
873
|
basic_scope.to_a # Load parent scope
|
873
874
|
subject.should_not be_loaded
|
874
875
|
end
|
875
|
-
|
876
|
+
|
876
877
|
it "sets the order value to descending by id" do
|
877
878
|
subject.order_values.should == [:id.desc]
|
878
879
|
end
|
879
880
|
end
|
880
|
-
|
881
|
+
|
881
882
|
describe "#build" do
|
882
883
|
it "returns a new document" do
|
883
884
|
subject.build.should be_an_instance_of(Post)
|
884
885
|
end
|
885
|
-
|
886
|
+
|
886
887
|
it "is aliased as #new" do
|
887
888
|
subject.new(:id => '123').should == subject.build(:id => '123')
|
888
889
|
end
|
889
890
|
end
|
890
|
-
|
891
|
+
|
891
892
|
describe "#create" do
|
892
893
|
it "returns a new document" do
|
893
894
|
subject.create.should be_an_instance_of(Post)
|
894
895
|
end
|
895
|
-
|
896
|
+
|
896
897
|
it "saves the document" do
|
897
898
|
subject.create.should_not be_a_new_record
|
898
899
|
end
|
899
900
|
end
|
900
|
-
|
901
|
+
|
901
902
|
describe "#apply_finder_options" do
|
902
903
|
it "returns a new scope" do
|
903
904
|
subject.apply_finder_options({}).should be_an_instance_of(Scope)
|
904
905
|
end
|
905
|
-
|
906
|
+
|
906
907
|
it "sets where values from options" do
|
907
908
|
scope = subject.apply_finder_options({ :conditions => { :author => "John" } })
|
908
909
|
scope.where_values.should == [{ :author => "John" }]
|
909
910
|
end
|
910
|
-
|
911
|
+
|
911
912
|
it "sets order values from options" do
|
912
913
|
scope = subject.apply_finder_options({ :order => :author.desc })
|
913
914
|
scope.order_values.should == [:author.desc]
|
914
915
|
end
|
915
|
-
|
916
|
+
|
916
917
|
it "sets select values from options" do
|
917
918
|
scope = subject.apply_finder_options({ :select => [:id, :author] })
|
918
919
|
scope.select_values.should == [:id, :author]
|
919
920
|
end
|
920
|
-
|
921
|
+
|
921
922
|
it "sets offset value from options" do
|
922
923
|
scope = subject.apply_finder_options({ :offset => 40 })
|
923
924
|
scope.offset_value.should == 40
|
924
925
|
end
|
925
|
-
|
926
|
+
|
926
927
|
it "sets limit value from options" do
|
927
928
|
scope = subject.apply_finder_options({ :limit => 50 })
|
928
929
|
scope.limit_value.should == 50
|
@@ -930,10 +931,10 @@ module MongoModel
|
|
930
931
|
end
|
931
932
|
end
|
932
933
|
|
933
|
-
|
934
|
+
|
934
935
|
context "with criteria" do
|
935
936
|
define_class(:OtherPost, Document)
|
936
|
-
|
937
|
+
|
937
938
|
let(:timestamp) { Time.now }
|
938
939
|
let(:scoped) do
|
939
940
|
basic_scope.where(:author => "Sam").
|
@@ -947,17 +948,17 @@ module MongoModel
|
|
947
948
|
limit(7).
|
948
949
|
from(OtherPost.collection)
|
949
950
|
end
|
950
|
-
|
951
|
+
|
951
952
|
subject { scoped }
|
952
|
-
|
953
|
+
|
953
954
|
def truncate_timestamp(time)
|
954
955
|
time.change(:usec => (time.usec / 1000.0).floor * 1000)
|
955
956
|
end
|
956
|
-
|
957
|
+
|
957
958
|
def model
|
958
959
|
OtherPost
|
959
960
|
end
|
960
|
-
|
961
|
+
|
961
962
|
def finder_options
|
962
963
|
{
|
963
964
|
:conditions => { "author" => "Sam", "published" => true, "date" => { "$lt" => truncate_timestamp(timestamp.utc) } },
|
@@ -967,35 +968,35 @@ module MongoModel
|
|
967
968
|
:limit => 7
|
968
969
|
}
|
969
970
|
end
|
970
|
-
|
971
|
+
|
971
972
|
it_should_behave_like "all scopes"
|
972
|
-
|
973
|
+
|
973
974
|
describe "#build" do
|
974
975
|
it "uses equality where conditions as attributes" do
|
975
976
|
doc = subject.build
|
976
977
|
doc.author.should == "Sam"
|
977
|
-
doc.published.should
|
978
|
+
doc.published.should be true
|
978
979
|
doc.date.should be_nil
|
979
980
|
end
|
980
981
|
end
|
981
|
-
|
982
|
+
|
982
983
|
describe "#create" do
|
983
984
|
it "uses equality where conditions as attributes" do
|
984
985
|
doc = subject.create
|
985
986
|
doc.author.should == "Sam"
|
986
|
-
doc.published.should
|
987
|
+
doc.published.should be true
|
987
988
|
doc.date.should be_nil
|
988
989
|
end
|
989
990
|
end
|
990
|
-
|
991
|
+
|
991
992
|
describe "#reverse_order" do
|
992
993
|
subject { scoped.reverse_order }
|
993
|
-
|
994
|
+
|
994
995
|
it "sets the order values to the reverse order" do
|
995
996
|
subject.order_values.should == MongoOrder.parse([:author.desc, :published.asc]).to_a
|
996
997
|
end
|
997
998
|
end
|
998
|
-
|
999
|
+
|
999
1000
|
describe "#except" do
|
1000
1001
|
context "given :where" do
|
1001
1002
|
it "returns a new scope without where values" do
|
@@ -1069,7 +1070,7 @@ module MongoModel
|
|
1069
1070
|
end
|
1070
1071
|
end
|
1071
1072
|
end
|
1072
|
-
|
1073
|
+
|
1073
1074
|
describe "#merge" do
|
1074
1075
|
let(:on_load_proc) { proc {} }
|
1075
1076
|
let(:merged) do
|
@@ -1079,7 +1080,7 @@ module MongoModel
|
|
1079
1080
|
on_load(&on_load_proc)
|
1080
1081
|
end
|
1081
1082
|
let(:result) { subject.merge(merged) }
|
1082
|
-
|
1083
|
+
|
1083
1084
|
it "combines where values from scopes" do
|
1084
1085
|
result.where_values.should == [
|
1085
1086
|
{ :author => "Sam" },
|
@@ -1088,51 +1089,51 @@ module MongoModel
|
|
1088
1089
|
{ :date.gt => timestamp-1.year }
|
1089
1090
|
]
|
1090
1091
|
end
|
1091
|
-
|
1092
|
+
|
1092
1093
|
it "combines order values from scopes" do
|
1093
1094
|
result.order_values.should == [:author.asc, :published.desc, :date.desc]
|
1094
1095
|
end
|
1095
|
-
|
1096
|
+
|
1096
1097
|
it "combines select values from scopes" do
|
1097
1098
|
result.select_values.should == [:author, :published, :date]
|
1098
1099
|
end
|
1099
|
-
|
1100
|
+
|
1100
1101
|
it "preserves on load proc" do
|
1101
1102
|
result.on_load_proc.should == on_load_proc
|
1102
1103
|
end
|
1103
|
-
|
1104
|
+
|
1104
1105
|
context "merged scope has offset value" do
|
1105
1106
|
let(:merged) { basic_scope.offset(10) }
|
1106
|
-
|
1107
|
+
|
1107
1108
|
it "uses offset value from merged scope" do
|
1108
1109
|
result.offset_value.should == 10
|
1109
1110
|
end
|
1110
1111
|
end
|
1111
|
-
|
1112
|
+
|
1112
1113
|
context "merged scope has no offset value set" do
|
1113
1114
|
let(:merged) { basic_scope }
|
1114
|
-
|
1115
|
+
|
1115
1116
|
it "uses offset value from original scope" do
|
1116
1117
|
result.offset_value.should == 15
|
1117
1118
|
end
|
1118
1119
|
end
|
1119
|
-
|
1120
|
+
|
1120
1121
|
context "merged scope has limit value" do
|
1121
1122
|
let(:merged) { basic_scope.limit(50) }
|
1122
|
-
|
1123
|
+
|
1123
1124
|
it "uses limit value from merged scope" do
|
1124
1125
|
result.limit_value.should == 50
|
1125
1126
|
end
|
1126
1127
|
end
|
1127
|
-
|
1128
|
+
|
1128
1129
|
context "merged scope has no limit value set" do
|
1129
1130
|
let(:merged) { basic_scope }
|
1130
|
-
|
1131
|
+
|
1131
1132
|
it "uses limit value from original scope" do
|
1132
1133
|
result.limit_value.should == 7
|
1133
1134
|
end
|
1134
1135
|
end
|
1135
|
-
|
1136
|
+
|
1136
1137
|
it "uses from value (collection) from merged scope" do
|
1137
1138
|
merged = basic_scope.from(Post.collection)
|
1138
1139
|
subject.merge(merged).collection.should == Post.collection
|