mongoid-locomotive 2.0.0.beta9
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/MIT_LICENSE +20 -0
- data/README.rdoc +47 -0
- data/lib/mongoid.rb +141 -0
- data/lib/mongoid/associations.rb +306 -0
- data/lib/mongoid/associations/embedded_in.rb +74 -0
- data/lib/mongoid/associations/embeds_many.rb +280 -0
- data/lib/mongoid/associations/embeds_one.rb +97 -0
- data/lib/mongoid/associations/foreign_key.rb +35 -0
- data/lib/mongoid/associations/meta_data.rb +38 -0
- data/lib/mongoid/associations/options.rb +62 -0
- data/lib/mongoid/associations/proxy.rb +33 -0
- data/lib/mongoid/associations/referenced_in.rb +59 -0
- data/lib/mongoid/associations/references_many.rb +245 -0
- data/lib/mongoid/associations/references_many_as_array.rb +78 -0
- data/lib/mongoid/associations/references_one.rb +99 -0
- data/lib/mongoid/atomicity.rb +55 -0
- data/lib/mongoid/attributes.rb +242 -0
- data/lib/mongoid/callbacks.rb +21 -0
- data/lib/mongoid/collection.rb +120 -0
- data/lib/mongoid/collections.rb +71 -0
- data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
- data/lib/mongoid/collections/master.rb +29 -0
- data/lib/mongoid/collections/operations.rb +41 -0
- data/lib/mongoid/collections/slaves.rb +45 -0
- data/lib/mongoid/components.rb +34 -0
- data/lib/mongoid/config.rb +263 -0
- data/lib/mongoid/contexts.rb +24 -0
- data/lib/mongoid/contexts/enumerable.rb +156 -0
- data/lib/mongoid/contexts/ids.rb +25 -0
- data/lib/mongoid/contexts/mongo.rb +285 -0
- data/lib/mongoid/contexts/paging.rb +50 -0
- data/lib/mongoid/criteria.rb +248 -0
- data/lib/mongoid/criterion/complex.rb +21 -0
- data/lib/mongoid/criterion/exclusion.rb +65 -0
- data/lib/mongoid/criterion/inclusion.rb +110 -0
- data/lib/mongoid/criterion/optional.rb +189 -0
- data/lib/mongoid/cursor.rb +81 -0
- data/lib/mongoid/deprecation.rb +21 -0
- data/lib/mongoid/dirty.rb +252 -0
- data/lib/mongoid/document.rb +210 -0
- data/lib/mongoid/errors.rb +131 -0
- data/lib/mongoid/extensions.rb +115 -0
- data/lib/mongoid/extensions/array/accessors.rb +17 -0
- data/lib/mongoid/extensions/array/assimilation.rb +26 -0
- data/lib/mongoid/extensions/array/conversions.rb +23 -0
- data/lib/mongoid/extensions/array/parentization.rb +13 -0
- data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
- data/lib/mongoid/extensions/binary/conversions.rb +17 -0
- data/lib/mongoid/extensions/boolean/conversions.rb +27 -0
- data/lib/mongoid/extensions/date/conversions.rb +24 -0
- data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
- data/lib/mongoid/extensions/false_class/equality.rb +13 -0
- data/lib/mongoid/extensions/float/conversions.rb +20 -0
- data/lib/mongoid/extensions/hash/accessors.rb +42 -0
- data/lib/mongoid/extensions/hash/assimilation.rb +40 -0
- data/lib/mongoid/extensions/hash/conversions.rb +42 -0
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
- data/lib/mongoid/extensions/hash/scoping.rb +12 -0
- data/lib/mongoid/extensions/integer/conversions.rb +20 -0
- data/lib/mongoid/extensions/nil/assimilation.rb +17 -0
- data/lib/mongoid/extensions/object/conversions.rb +21 -0
- data/lib/mongoid/extensions/objectid/conversions.rb +15 -0
- data/lib/mongoid/extensions/proc/scoping.rb +12 -0
- data/lib/mongoid/extensions/set/conversions.rb +20 -0
- data/lib/mongoid/extensions/string/conversions.rb +15 -0
- data/lib/mongoid/extensions/string/inflections.rb +97 -0
- data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
- data/lib/mongoid/extensions/time_conversions.rb +35 -0
- data/lib/mongoid/extensions/true_class/equality.rb +13 -0
- data/lib/mongoid/extras.rb +61 -0
- data/lib/mongoid/factory.rb +20 -0
- data/lib/mongoid/field.rb +83 -0
- data/lib/mongoid/fields.rb +62 -0
- data/lib/mongoid/finders.rb +145 -0
- data/lib/mongoid/hierarchy.rb +74 -0
- data/lib/mongoid/identity.rb +47 -0
- data/lib/mongoid/indexes.rb +27 -0
- data/lib/mongoid/javascript.rb +21 -0
- data/lib/mongoid/javascript/functions.yml +37 -0
- data/lib/mongoid/logger.rb +19 -0
- data/lib/mongoid/matchers.rb +35 -0
- data/lib/mongoid/matchers/all.rb +11 -0
- data/lib/mongoid/matchers/default.rb +26 -0
- data/lib/mongoid/matchers/exists.rb +13 -0
- data/lib/mongoid/matchers/gt.rb +11 -0
- data/lib/mongoid/matchers/gte.rb +11 -0
- data/lib/mongoid/matchers/in.rb +11 -0
- data/lib/mongoid/matchers/lt.rb +11 -0
- data/lib/mongoid/matchers/lte.rb +11 -0
- data/lib/mongoid/matchers/ne.rb +11 -0
- data/lib/mongoid/matchers/nin.rb +11 -0
- data/lib/mongoid/matchers/size.rb +11 -0
- data/lib/mongoid/memoization.rb +33 -0
- data/lib/mongoid/named_scope.rb +37 -0
- data/lib/mongoid/paranoia.rb +106 -0
- data/lib/mongoid/paths.rb +61 -0
- data/lib/mongoid/persistence.rb +216 -0
- data/lib/mongoid/persistence/command.rb +39 -0
- data/lib/mongoid/persistence/insert.rb +48 -0
- data/lib/mongoid/persistence/insert_embedded.rb +44 -0
- data/lib/mongoid/persistence/remove.rb +39 -0
- data/lib/mongoid/persistence/remove_all.rb +38 -0
- data/lib/mongoid/persistence/remove_embedded.rb +50 -0
- data/lib/mongoid/persistence/update.rb +71 -0
- data/lib/mongoid/railtie.rb +67 -0
- data/lib/mongoid/railties/database.rake +60 -0
- data/lib/mongoid/scope.rb +75 -0
- data/lib/mongoid/state.rb +32 -0
- data/lib/mongoid/timestamps.rb +27 -0
- data/lib/mongoid/validations.rb +51 -0
- data/lib/mongoid/validations/associated.rb +32 -0
- data/lib/mongoid/validations/locale/en.yml +5 -0
- data/lib/mongoid/validations/uniqueness.rb +56 -0
- data/lib/mongoid/version.rb +4 -0
- data/lib/mongoid/versioning.rb +26 -0
- data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +24 -0
- data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
- data/lib/rails/generators/mongoid/model/templates/model.rb +15 -0
- data/lib/rails/generators/mongoid_generator.rb +61 -0
- data/spec/integration/mongoid/association_attributes_spec.rb +71 -0
- data/spec/integration/mongoid/associations_spec.rb +768 -0
- data/spec/integration/mongoid/attributes_spec.rb +59 -0
- data/spec/integration/mongoid/callback_spec.rb +33 -0
- data/spec/integration/mongoid/contexts/enumerable_spec.rb +33 -0
- data/spec/integration/mongoid/criteria_spec.rb +281 -0
- data/spec/integration/mongoid/dirty_spec.rb +85 -0
- data/spec/integration/mongoid/document_spec.rb +741 -0
- data/spec/integration/mongoid/extensions_spec.rb +22 -0
- data/spec/integration/mongoid/finders_spec.rb +119 -0
- data/spec/integration/mongoid/inheritance_spec.rb +171 -0
- data/spec/integration/mongoid/named_scope_spec.rb +58 -0
- data/spec/integration/mongoid/paranoia_spec.rb +44 -0
- data/spec/integration/mongoid/persistence/update_spec.rb +46 -0
- data/spec/integration/mongoid/persistence_spec.rb +311 -0
- data/spec/integration/mongoid/validations/uniqueness_spec.rb +206 -0
- data/spec/models/account.rb +5 -0
- data/spec/models/address.rb +40 -0
- data/spec/models/agent.rb +7 -0
- data/spec/models/animal.rb +15 -0
- data/spec/models/answer.rb +4 -0
- data/spec/models/callbacks.rb +47 -0
- data/spec/models/category.rb +13 -0
- data/spec/models/comment.rb +10 -0
- data/spec/models/country_code.rb +6 -0
- data/spec/models/employer.rb +5 -0
- data/spec/models/favorite.rb +8 -0
- data/spec/models/game.rb +9 -0
- data/spec/models/inheritance.rb +72 -0
- data/spec/models/location.rb +5 -0
- data/spec/models/login.rb +6 -0
- data/spec/models/mixed_drink.rb +4 -0
- data/spec/models/name.rb +13 -0
- data/spec/models/namespacing.rb +11 -0
- data/spec/models/paranoid_post.rb +18 -0
- data/spec/models/parents.rb +32 -0
- data/spec/models/patient.rb +15 -0
- data/spec/models/person.rb +106 -0
- data/spec/models/pet.rb +7 -0
- data/spec/models/pet_owner.rb +6 -0
- data/spec/models/phone.rb +7 -0
- data/spec/models/post.rb +25 -0
- data/spec/models/preference.rb +7 -0
- data/spec/models/question.rb +8 -0
- data/spec/models/survey.rb +6 -0
- data/spec/models/translation.rb +5 -0
- data/spec/models/user.rb +6 -0
- data/spec/models/user_accout.rb +5 -0
- data/spec/models/vet_visit.rb +5 -0
- data/spec/models/video.rb +5 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/unit/mongoid/associations/embedded_in_spec.rb +193 -0
- data/spec/unit/mongoid/associations/embeds_many_spec.rb +626 -0
- data/spec/unit/mongoid/associations/embeds_one_spec.rb +287 -0
- data/spec/unit/mongoid/associations/foreign_key_spec.rb +90 -0
- data/spec/unit/mongoid/associations/meta_data_spec.rb +110 -0
- data/spec/unit/mongoid/associations/options_spec.rb +215 -0
- data/spec/unit/mongoid/associations/referenced_in_spec.rb +145 -0
- data/spec/unit/mongoid/associations/references_many_as_array_spec.rb +424 -0
- data/spec/unit/mongoid/associations/references_many_spec.rb +502 -0
- data/spec/unit/mongoid/associations/references_one_spec.rb +204 -0
- data/spec/unit/mongoid/associations_spec.rb +688 -0
- data/spec/unit/mongoid/atomicity_spec.rb +164 -0
- data/spec/unit/mongoid/attributes_spec.rb +646 -0
- data/spec/unit/mongoid/callbacks_spec.rb +85 -0
- data/spec/unit/mongoid/collection_spec.rb +187 -0
- data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
- data/spec/unit/mongoid/collections/master_spec.rb +41 -0
- data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
- data/spec/unit/mongoid/collections_spec.rb +98 -0
- data/spec/unit/mongoid/config_spec.rb +298 -0
- data/spec/unit/mongoid/contexts/enumerable_spec.rb +447 -0
- data/spec/unit/mongoid/contexts/mongo_spec.rb +703 -0
- data/spec/unit/mongoid/contexts_spec.rb +25 -0
- data/spec/unit/mongoid/criteria_spec.rb +873 -0
- data/spec/unit/mongoid/criterion/complex_spec.rb +17 -0
- data/spec/unit/mongoid/criterion/exclusion_spec.rb +121 -0
- data/spec/unit/mongoid/criterion/inclusion_spec.rb +274 -0
- data/spec/unit/mongoid/criterion/optional_spec.rb +483 -0
- data/spec/unit/mongoid/cursor_spec.rb +80 -0
- data/spec/unit/mongoid/deprecation_spec.rb +24 -0
- data/spec/unit/mongoid/dirty_spec.rb +430 -0
- data/spec/unit/mongoid/document_spec.rb +623 -0
- data/spec/unit/mongoid/errors_spec.rb +154 -0
- data/spec/unit/mongoid/extensions/array/accessors_spec.rb +50 -0
- data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +24 -0
- data/spec/unit/mongoid/extensions/array/conversions_spec.rb +52 -0
- data/spec/unit/mongoid/extensions/array/parentization_spec.rb +20 -0
- data/spec/unit/mongoid/extensions/big_decimal/conversions_spec.rb +36 -0
- data/spec/unit/mongoid/extensions/binary/conversions_spec.rb +22 -0
- data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +49 -0
- data/spec/unit/mongoid/extensions/date/conversions_spec.rb +145 -0
- data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +14 -0
- data/spec/unit/mongoid/extensions/false_class/equality_spec.rb +35 -0
- data/spec/unit/mongoid/extensions/float/conversions_spec.rb +61 -0
- data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +184 -0
- data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +59 -0
- data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +35 -0
- data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +17 -0
- data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +14 -0
- data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +61 -0
- data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +29 -0
- data/spec/unit/mongoid/extensions/object/conversions_spec.rb +44 -0
- data/spec/unit/mongoid/extensions/objectid/conversions_spec.rb +22 -0
- data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +34 -0
- data/spec/unit/mongoid/extensions/set/conversions_spec.rb +21 -0
- data/spec/unit/mongoid/extensions/string/conversions_spec.rb +28 -0
- data/spec/unit/mongoid/extensions/string/inflections_spec.rb +208 -0
- data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +107 -0
- data/spec/unit/mongoid/extensions/time_conversions_spec.rb +186 -0
- data/spec/unit/mongoid/extensions/true_class/equality_spec.rb +35 -0
- data/spec/unit/mongoid/extras_spec.rb +102 -0
- data/spec/unit/mongoid/factory_spec.rb +31 -0
- data/spec/unit/mongoid/field_spec.rb +169 -0
- data/spec/unit/mongoid/fields_spec.rb +181 -0
- data/spec/unit/mongoid/finders_spec.rb +439 -0
- data/spec/unit/mongoid/hierarchy_spec.rb +68 -0
- data/spec/unit/mongoid/identity_spec.rb +109 -0
- data/spec/unit/mongoid/indexes_spec.rb +99 -0
- data/spec/unit/mongoid/javascript_spec.rb +48 -0
- data/spec/unit/mongoid/logger_spec.rb +38 -0
- data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
- data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
- data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
- data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
- data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
- data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
- data/spec/unit/mongoid/matchers_spec.rb +329 -0
- data/spec/unit/mongoid/memoization_spec.rb +75 -0
- data/spec/unit/mongoid/named_scope_spec.rb +123 -0
- data/spec/unit/mongoid/paranoia_spec.rb +108 -0
- data/spec/unit/mongoid/paths_spec.rb +272 -0
- data/spec/unit/mongoid/persistence/insert_embedded_spec.rb +154 -0
- data/spec/unit/mongoid/persistence/insert_spec.rb +144 -0
- data/spec/unit/mongoid/persistence/remove_all_spec.rb +82 -0
- data/spec/unit/mongoid/persistence/remove_embedded_spec.rb +152 -0
- data/spec/unit/mongoid/persistence/remove_spec.rb +89 -0
- data/spec/unit/mongoid/persistence/update_spec.rb +177 -0
- data/spec/unit/mongoid/persistence_spec.rb +452 -0
- data/spec/unit/mongoid/scope_spec.rb +240 -0
- data/spec/unit/mongoid/serialization_spec.rb +43 -0
- data/spec/unit/mongoid/state_spec.rb +94 -0
- data/spec/unit/mongoid/timestamps_spec.rb +30 -0
- data/spec/unit/mongoid/validations/associated_spec.rb +103 -0
- data/spec/unit/mongoid/validations/uniqueness_spec.rb +201 -0
- data/spec/unit/mongoid/validations_spec.rb +43 -0
- data/spec/unit/mongoid/versioning_spec.rb +41 -0
- data/spec/unit/mongoid_spec.rb +46 -0
- metadata +433 -0
|
@@ -0,0 +1,741 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Mongoid::Document do
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
Person.delete_all
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
context "creating anonymous documents" do
|
|
10
|
+
|
|
11
|
+
context "when defining collection" do
|
|
12
|
+
|
|
13
|
+
before do
|
|
14
|
+
@model = Class.new do
|
|
15
|
+
include Mongoid::Document
|
|
16
|
+
store_in :anonymous
|
|
17
|
+
field :gender
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "allows the creation" do
|
|
22
|
+
Object.const_set "Anonymous", @model
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe "#db" do
|
|
28
|
+
|
|
29
|
+
it "returns the mongo database" do
|
|
30
|
+
Person.db.should == Mongoid.master
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "when document contains a hash field" do
|
|
35
|
+
|
|
36
|
+
before do
|
|
37
|
+
@map = { "first" => 10, "second" => "Blah" }
|
|
38
|
+
@person = Person.create(:map => @map)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "properly gets and sets the has attributes" do
|
|
42
|
+
@person.map.should == @map
|
|
43
|
+
@from_db = Person.find(@person.id)
|
|
44
|
+
@from_db.map.should == @map
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe ".collection" do
|
|
50
|
+
|
|
51
|
+
context "on a subclass of a root document" do
|
|
52
|
+
|
|
53
|
+
it "returns the root document collection" do
|
|
54
|
+
Browser.collection.should == Canvas.collection
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
context "on a namespaced document" do
|
|
60
|
+
Medical::Patient.collection.name.should == "medical_patients"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe "#new" do
|
|
66
|
+
|
|
67
|
+
it "gets a new or current database connection" do
|
|
68
|
+
person = Person.new
|
|
69
|
+
person.collection.should be_a_kind_of(Mongoid::Collection)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
describe "#count" do
|
|
75
|
+
|
|
76
|
+
before do
|
|
77
|
+
5.times do |n|
|
|
78
|
+
Person.create(:title => "Sir", :ssn => "#{n}")
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "returns the count" do
|
|
83
|
+
Person.count.should == 5
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe "#create" do
|
|
89
|
+
|
|
90
|
+
it "persists a new record to the database" do
|
|
91
|
+
person = Person.create(:title => "Test")
|
|
92
|
+
person.id.should be_a_kind_of(String)
|
|
93
|
+
person.attributes[:title].should == "Test"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context "when creating a has many" do
|
|
97
|
+
|
|
98
|
+
before do
|
|
99
|
+
@person = Person.new(:title => "Esquire")
|
|
100
|
+
@person.addresses.create(:street => "Nan Jing Dong Lu", :city => "Shanghai")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "should create and save the entire graph" do
|
|
104
|
+
person = Person.find(@person.id)
|
|
105
|
+
person.addresses.first.street.should == "Nan Jing Dong Lu"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
context "chaining criteria scopes" do
|
|
113
|
+
|
|
114
|
+
before do
|
|
115
|
+
@one = Person.create(:title => "Mr", :age => 55, :terms => true, :ssn => "q")
|
|
116
|
+
@two = Person.create(:title => "Sir", :age => 55, :terms => true, :ssn => "w")
|
|
117
|
+
@three = Person.create(:title => "Sir", :age => 35, :terms => true, :ssn => "e")
|
|
118
|
+
@four = Person.create(:title => "Sir", :age => 55, :terms => false, :ssn => "r")
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "finds by the merged criteria" do
|
|
122
|
+
people = Person.old.accepted.knight
|
|
123
|
+
people.count.should == 1
|
|
124
|
+
people.first.should == @two
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
context "#destroy" do
|
|
130
|
+
|
|
131
|
+
context "on a root document" do
|
|
132
|
+
|
|
133
|
+
before do
|
|
134
|
+
@person = Person.create(:title => "Sir")
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it "deletes the document" do
|
|
138
|
+
@person.destroy
|
|
139
|
+
lambda { Person.find(@person.id) }.should raise_error
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "marks the document as destroyed" do
|
|
143
|
+
@person.should_not be_destroyed
|
|
144
|
+
@person.destroy
|
|
145
|
+
@person.should be_destroyed
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
context "on an embedded document" do
|
|
151
|
+
|
|
152
|
+
before do
|
|
153
|
+
@person = Person.create(:title => "Lead")
|
|
154
|
+
address = @person.addresses.create(:street => "1st Street")
|
|
155
|
+
@person.create_name(:first_name => "Emmanuel")
|
|
156
|
+
@person.save
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "deletes the document" do
|
|
160
|
+
@person.addresses.first.destroy
|
|
161
|
+
@person.name.should_not be_nil
|
|
162
|
+
@person.name.destroy
|
|
163
|
+
@person.addresses.first.should be_nil
|
|
164
|
+
@person.name.should be_nil
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
context ".find_or_create_by" do
|
|
172
|
+
|
|
173
|
+
before do
|
|
174
|
+
@person = Person.create(:title => "Senior")
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
context "when the document is found" do
|
|
178
|
+
|
|
179
|
+
it "returns the document" do
|
|
180
|
+
Person.find_or_create_by(:title => "Senior").should == @person
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
context "when the document is not found" do
|
|
186
|
+
|
|
187
|
+
it "creates a new document" do
|
|
188
|
+
person = Person.find_or_create_by(:title => "Senorita", :ssn => "1234567")
|
|
189
|
+
person.title.should == "Senorita"
|
|
190
|
+
person.should_not be_a_new_record
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
context ".find_or_initialize_by" do
|
|
198
|
+
|
|
199
|
+
before do
|
|
200
|
+
@person = Person.create(:title => "Senior")
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
context "when the document is found" do
|
|
204
|
+
|
|
205
|
+
it "returns the document" do
|
|
206
|
+
Person.find_or_initialize_by(:title => "Senior").should == @person
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
context "when the document is not found" do
|
|
212
|
+
|
|
213
|
+
it "returns a new document" do
|
|
214
|
+
person = Person.find_or_initialize_by(:title => "Senorita")
|
|
215
|
+
person.title.should == "Senorita"
|
|
216
|
+
person.should be_a_new_record
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
describe "#find" do
|
|
224
|
+
|
|
225
|
+
before do
|
|
226
|
+
@person = Person.create(:title => "Test")
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
context "finding all documents" do
|
|
230
|
+
|
|
231
|
+
it "returns an array of documents based on the selector provided" do
|
|
232
|
+
documents = Person.find(:all, :conditions => { :title => "Test"})
|
|
233
|
+
documents.first.title.should == "Test"
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
context "finding first document" do
|
|
239
|
+
|
|
240
|
+
it "returns the first document based on the selector provided" do
|
|
241
|
+
person = Person.find(:first, :conditions => { :title => "Test" })
|
|
242
|
+
person.title.should == "Test"
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
context "finding by id" do
|
|
248
|
+
|
|
249
|
+
it "finds the document by the supplied id" do
|
|
250
|
+
person = Person.find(@person.id)
|
|
251
|
+
person.id.should == @person.id
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
context "limiting result fields" do
|
|
257
|
+
|
|
258
|
+
it "adds the type field to the options" do
|
|
259
|
+
people = Person.all(:fields => [ :title ])
|
|
260
|
+
people.first.title.should == "Test"
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
describe "#group" do
|
|
268
|
+
|
|
269
|
+
before do
|
|
270
|
+
5.times do |num|
|
|
271
|
+
Person.create(:title => "Sir", :age => num, :ssn => num)
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
it "returns grouped documents" do
|
|
276
|
+
grouped = Person.only(:title).group
|
|
277
|
+
people = grouped.first["group"]
|
|
278
|
+
person = people.first
|
|
279
|
+
person.should be_a_kind_of(Person)
|
|
280
|
+
person.title.should == "Sir"
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
context "when address is a has one" do
|
|
286
|
+
|
|
287
|
+
before do
|
|
288
|
+
@owner = PetOwner.create(:title => "AKC")
|
|
289
|
+
@address = Address.new(:street => "Fido Street")
|
|
290
|
+
@owner.address = @address
|
|
291
|
+
@address.save
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
after do
|
|
295
|
+
PetOwner.delete_all
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
it "is a single object and not an array" do
|
|
299
|
+
@from_db = PetOwner.find(@owner.id)
|
|
300
|
+
@from_db.address.should == @address
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
describe "#inspect" do
|
|
306
|
+
|
|
307
|
+
context "with allow_dynamic_fields = false" do
|
|
308
|
+
before do
|
|
309
|
+
Mongoid.configure.allow_dynamic_fields = false
|
|
310
|
+
@person = Person.new :title => "CEO"
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
it "returns a pretty string of class name and attributes" do
|
|
314
|
+
attrs = Person.fields.map do |name, field|
|
|
315
|
+
"#{name}: #{@person.attributes[name].nil? ? "nil" : @person.attributes[name].inspect}"
|
|
316
|
+
end * ", "
|
|
317
|
+
@person.inspect.should == "#<Person _id: #{@person.id}, #{attrs}>"
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
context "with allow_dynamic_fields = true" do
|
|
322
|
+
before do
|
|
323
|
+
Mongoid.configure.allow_dynamic_fields = true
|
|
324
|
+
@person = Person.new(:title => "CEO", :some_attribute => "foo")
|
|
325
|
+
@person.addresses << Address.new(:street => "test")
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
it "returns a pretty string of class name, attributes, and dynamic attributes" do
|
|
329
|
+
attrs = Person.fields.map do |name, field|
|
|
330
|
+
"#{name}: #{@person.attributes[name].nil? ? "nil" : @person.attributes[name].inspect}"
|
|
331
|
+
end * ", "
|
|
332
|
+
attrs << ", some_attribute: #{@person.attributes['some_attribute'].inspect}"
|
|
333
|
+
@person.inspect.should == "#<Person _id: #{@person.id}, #{attrs}>"
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
describe "#paginate" do
|
|
339
|
+
|
|
340
|
+
before do
|
|
341
|
+
10.times do |num|
|
|
342
|
+
Person.create(:title => "Test-#{num}", :ssn => "55#{num}")
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
it "returns paginated documents" do
|
|
347
|
+
Person.paginate(:per_page => 5, :page => 2).length.should == 5
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
it "returns a proper count" do
|
|
351
|
+
@criteria = Mongoid::Criteria.translate(Person, { :per_page => 5, :page => 1 })
|
|
352
|
+
@criteria.count.should == 10
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
describe "#reload" do
|
|
358
|
+
|
|
359
|
+
before do
|
|
360
|
+
@person = Person.new(:title => "Sir")
|
|
361
|
+
@person.save
|
|
362
|
+
@from_db = Person.find(@person.id)
|
|
363
|
+
@from_db.age = 35
|
|
364
|
+
@from_db.save
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
it "reloads the object attributes from the db" do
|
|
368
|
+
@person.reload
|
|
369
|
+
@person.age.should == 35
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
it "reload should return self" do
|
|
373
|
+
@person.reload.should == @from_db
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
context "when document not saved" do
|
|
377
|
+
|
|
378
|
+
context "when raising not found error" do
|
|
379
|
+
|
|
380
|
+
it "raises an error" do
|
|
381
|
+
lambda { Person.new.reload }.should raise_error(Mongoid::Errors::DocumentNotFound)
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
context "when embedded documents change" do
|
|
387
|
+
|
|
388
|
+
before do
|
|
389
|
+
@address = @person.addresses.create(:number => 27, :street => "Maiden Lane")
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
it "should reload (unmemoize) the associations" do
|
|
393
|
+
@person.addresses.should == [ @address ]
|
|
394
|
+
Person.collection.update({ "_id" => @person.id }, { "$set" => { "addresses" => [] } })
|
|
395
|
+
@person.reload
|
|
396
|
+
@person.addresses.should == []
|
|
397
|
+
end
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
context "with relational associations" do
|
|
401
|
+
|
|
402
|
+
context "for a references_one" do
|
|
403
|
+
|
|
404
|
+
before do
|
|
405
|
+
@game = @person.game.create(:score => 50)
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
it "should reload the association" do
|
|
409
|
+
@person.game.should == @game
|
|
410
|
+
Game.collection.update({ "_id" => @game.id }, { "$set" => { "score" => 75 } })
|
|
411
|
+
@person.reload
|
|
412
|
+
@person.game.score.should == 75
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
context "for a referenced_in" do
|
|
417
|
+
|
|
418
|
+
before do
|
|
419
|
+
@game = @person.game.create(:score => 50)
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
it "should reload the association" do
|
|
423
|
+
Person.collection.update({ "_id" => @person.id }, { "$set" => { "title" => "Mam" } })
|
|
424
|
+
@game.reload
|
|
425
|
+
@game.person.title.should == "Mam"
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
describe "#save" do
|
|
432
|
+
|
|
433
|
+
context "on a has_one association" do
|
|
434
|
+
|
|
435
|
+
before do
|
|
436
|
+
@person = Person.new(:title => "Sir")
|
|
437
|
+
@name = Name.new(:first_name => "Test")
|
|
438
|
+
@person.name = @name
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
it "saves the parent document" do
|
|
442
|
+
@name.save
|
|
443
|
+
person = Person.find(@person.id)
|
|
444
|
+
person.name.first_name.should == @name.first_name
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
context "without validation" do
|
|
450
|
+
|
|
451
|
+
before do
|
|
452
|
+
@comment = Comment.new
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
it "always persists" do
|
|
456
|
+
@comment.save(false).should be_true
|
|
457
|
+
@from_db = Comment.find(@comment.id)
|
|
458
|
+
@from_db.should == @comment
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
context "with failing validation" do
|
|
464
|
+
|
|
465
|
+
before do
|
|
466
|
+
@comment = Comment.new
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
it "returns false" do
|
|
470
|
+
@comment.should_not be_valid
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
context ".store_in" do
|
|
478
|
+
|
|
479
|
+
after do
|
|
480
|
+
Canvas.store_in(:canvases)
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
it "switches the database collection" do
|
|
484
|
+
Canvas.collection.name.should == "canvases"
|
|
485
|
+
Canvas.store_in(:browsers)
|
|
486
|
+
Canvas.collection.name.should == "browsers"
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
context "when has many exists through a has one" do
|
|
492
|
+
|
|
493
|
+
before do
|
|
494
|
+
@owner = PetOwner.new(:title => "Sir")
|
|
495
|
+
@pet = Pet.new(:name => "Fido")
|
|
496
|
+
@visit = VetVisit.new(:date => Date.today)
|
|
497
|
+
@pet.vet_visits << @visit
|
|
498
|
+
@owner.pet = @pet
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
it "can clear the association" do
|
|
502
|
+
@owner.pet.vet_visits.size.should == 1
|
|
503
|
+
@owner.pet.vet_visits.clear
|
|
504
|
+
@owner.pet.vet_visits.size.should == 0
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
context "the lot" do
|
|
510
|
+
|
|
511
|
+
before do
|
|
512
|
+
@person = Person.new(:title => "Sir")
|
|
513
|
+
@name = Name.new(:first_name => "Syd", :last_name => "Vicious")
|
|
514
|
+
@home = Address.new(:street => "Oxford Street")
|
|
515
|
+
@business = Address.new(:street => "Upper Street")
|
|
516
|
+
@person.name = @name
|
|
517
|
+
@person.addresses << @home
|
|
518
|
+
@person.addresses << @business
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
it "allows adding multiples on an embeds_many in a row" do
|
|
522
|
+
@person.addresses.length.should == 2
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
context "when saving on a has_one" do
|
|
526
|
+
|
|
527
|
+
before do
|
|
528
|
+
@name.save
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
it "saves the entire graph up from the has_one" do
|
|
532
|
+
person = Person.first(:conditions => { :title => "Sir" })
|
|
533
|
+
person.should == @person
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
context "when saving on an embeds_many" do
|
|
539
|
+
|
|
540
|
+
before do
|
|
541
|
+
@home.save
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
it "saves the entire graph up from the embeds_many" do
|
|
545
|
+
person = Person.first(:conditions => { :title => "Sir" })
|
|
546
|
+
person.should == @person
|
|
547
|
+
end
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
context "setting embedded_in" do
|
|
553
|
+
|
|
554
|
+
before do
|
|
555
|
+
@person = Person.new(:title => "Mr")
|
|
556
|
+
@address = Address.new(:street => "Bloomsbury Ave")
|
|
557
|
+
@person.save!
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
it "allows the parent reference to change" do
|
|
561
|
+
@address.addressable = @person
|
|
562
|
+
@address.save!
|
|
563
|
+
@person.addresses.first.should == @address
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
describe "#to_json" do
|
|
569
|
+
|
|
570
|
+
before do
|
|
571
|
+
@person = Person.new(:title => "Sir", :age => 30)
|
|
572
|
+
@address = Address.new(:street => "Nan Jing Dong Lu")
|
|
573
|
+
@person.addresses << @address
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
context "on a new document" do
|
|
577
|
+
|
|
578
|
+
it "returns the json string" do
|
|
579
|
+
@person.to_json.should include('"pets":false')
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
context "on a persisted document" do
|
|
585
|
+
|
|
586
|
+
it "returns the json string" do
|
|
587
|
+
@person.save
|
|
588
|
+
from_db = Person.find(@person.id)
|
|
589
|
+
from_db.to_json.should include('"pets":false')
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
end
|
|
595
|
+
|
|
596
|
+
describe "#as_json" do
|
|
597
|
+
|
|
598
|
+
before do
|
|
599
|
+
@person = Person.new(:title => "Sir", :age => 30)
|
|
600
|
+
@address = Address.new(:street => "Nan Jing Dong Lu")
|
|
601
|
+
@person.addresses << @address
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
context "on a new document" do
|
|
605
|
+
|
|
606
|
+
it "returns the document (not sure why ActiveModel behaves like this)" do
|
|
607
|
+
@person.as_json.should == @person
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
context "on a persisted document" do
|
|
613
|
+
|
|
614
|
+
it "returns the attributes" do
|
|
615
|
+
@person.save
|
|
616
|
+
from_db = Person.find(@person.id)
|
|
617
|
+
from_db.as_json.should == from_db
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
describe "#encode_json" do
|
|
625
|
+
|
|
626
|
+
before do
|
|
627
|
+
@person = Person.new(:title => "Sir", :age => 30)
|
|
628
|
+
@address = Address.new(:street => "Nan Jing Dong Lu")
|
|
629
|
+
@person.addresses << @address
|
|
630
|
+
@encoder = stub(:options => {})
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
context "on a new document" do
|
|
634
|
+
|
|
635
|
+
it "returns the attributes" do
|
|
636
|
+
@person.encode_json(@encoder).should include('"pets":false')
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
context "on a persisted document" do
|
|
642
|
+
|
|
643
|
+
it "returns the attributes" do
|
|
644
|
+
@person.save
|
|
645
|
+
from_db = Person.find(@person.id)
|
|
646
|
+
from_db.encode_json(@encoder).should include('"pets":false')
|
|
647
|
+
end
|
|
648
|
+
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
context "typecasting" do
|
|
654
|
+
|
|
655
|
+
before do
|
|
656
|
+
@date = Date.new(1976, 7, 4)
|
|
657
|
+
@person = Person.new(:dob => @date)
|
|
658
|
+
@person.save
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
it "properly casts dates and times" do
|
|
662
|
+
person = Person.first
|
|
663
|
+
person.dob.should == @date
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
context "versioning" do
|
|
669
|
+
|
|
670
|
+
before do
|
|
671
|
+
@comment = Comment.new(:title => 'Old', :text => "Testing")
|
|
672
|
+
@comment.save
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
after do
|
|
676
|
+
Comment.collection.drop
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
context "first save" do
|
|
680
|
+
|
|
681
|
+
it "creates a new version" do
|
|
682
|
+
@from_db = Comment.find(@comment.id)
|
|
683
|
+
@from_db.title = "New"
|
|
684
|
+
@from_db.save
|
|
685
|
+
@from_db.versions.size.should == 1
|
|
686
|
+
@from_db.version.should == 2
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
context "multiple saves" do
|
|
692
|
+
|
|
693
|
+
before do
|
|
694
|
+
5.times do |n|
|
|
695
|
+
@comment.save
|
|
696
|
+
end
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
it "creates new versions" do
|
|
700
|
+
@from_db = Comment.find(@comment.id)
|
|
701
|
+
@from_db.version.should == 6
|
|
702
|
+
@from_db.versions.size.should == 5
|
|
703
|
+
end
|
|
704
|
+
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
context "executing criteria with date comparisons" do
|
|
710
|
+
|
|
711
|
+
context "handling specific dates" do
|
|
712
|
+
|
|
713
|
+
before do
|
|
714
|
+
@person = Person.create(:dob => Date.new(2000, 10, 31))
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
it "handles comparisons with todays date"do
|
|
718
|
+
people = Person.where("this.dob < new Date()")
|
|
719
|
+
people.first.should == @person
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
it "handles conparisons with a date range" do
|
|
723
|
+
people = Person.where("new Date(1976, 10, 31) < this.dob && this.dob < new Date()")
|
|
724
|
+
people.first.should == @person
|
|
725
|
+
end
|
|
726
|
+
|
|
727
|
+
it "handles false comparisons in a date range" do
|
|
728
|
+
people = Person.where("new Date(2005, 10, 31) < this.dob && this.dob < new Date()")
|
|
729
|
+
people.should be_empty
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
it "handles comparisons with date objects"do
|
|
733
|
+
people = Person.where(:dob => { "$lt" => Date.today.midnight })
|
|
734
|
+
people.first.should == @person
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
end
|