mongomodel 0.2.2 → 0.2.3
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/Gemfile +6 -6
- data/Rakefile +22 -11
- data/lib/mongomodel.rb +1 -0
- data/lib/mongomodel/attributes/mongo.rb +2 -1
- data/lib/mongomodel/attributes/typecasting.rb +4 -1
- data/lib/mongomodel/concerns/attribute_methods/dirty.rb +1 -1
- data/lib/mongomodel/concerns/attributes.rb +5 -3
- data/lib/mongomodel/concerns/callbacks.rb +2 -2
- data/lib/mongomodel/concerns/document_parent.rb +13 -0
- data/lib/mongomodel/document/persistence.rb +23 -3
- data/lib/mongomodel/document/scopes.rb +1 -1
- data/lib/mongomodel/embedded_document.rb +2 -0
- data/lib/mongomodel/support/collection.rb +60 -8
- data/lib/mongomodel/support/scope.rb +12 -1
- data/lib/mongomodel/support/types/time.rb +5 -1
- data/lib/mongomodel/version.rb +1 -1
- data/mongomodel.gemspec +8 -6
- data/spec/mongomodel/attributes/store_spec.rb +8 -8
- data/spec/mongomodel/concerns/attribute_methods/dirty_spec.rb +59 -5
- data/spec/mongomodel/concerns/attributes_spec.rb +1 -1
- data/spec/mongomodel/concerns/callbacks_spec.rb +21 -0
- data/spec/mongomodel/concerns/properties_spec.rb +22 -0
- data/spec/mongomodel/concerns/timestamps_spec.rb +2 -2
- data/spec/mongomodel/document/persistence_spec.rb +32 -0
- data/spec/mongomodel/embedded_document_spec.rb +41 -12
- data/spec/mongomodel/support/collection_spec.rb +6 -0
- data/spec/mongomodel/support/scope_spec.rb +49 -0
- data/spec/spec.opts +2 -1
- data/spec/support/helpers/document_finder_stubs.rb +6 -0
- metadata +18 -5
- data/spec/support/time.rb +0 -6
data/Gemfile
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
source "http://
|
1
|
+
source "http://rubygems.org"
|
2
2
|
git "git://github.com/rails/rails.git"
|
3
3
|
|
4
|
-
gem "activemodel"
|
5
|
-
gem "activesupport"
|
4
|
+
gem "activemodel", ">= 3.0.0.beta3"
|
5
|
+
gem "activesupport", ">= 3.0.0.beta3"
|
6
6
|
|
7
|
-
gem "mongo"
|
8
|
-
gem "bson"
|
9
|
-
gem "bson_ext"
|
7
|
+
gem "mongo", '>= 0.20.1'
|
8
|
+
gem "bson", '>= 0.20.1'
|
9
|
+
gem "bson_ext", '>= 0.20.1'
|
10
10
|
|
11
11
|
gem "rspec"
|
data/Rakefile
CHANGED
@@ -1,18 +1,28 @@
|
|
1
|
-
require 'spec/rake/spectask'
|
2
1
|
require 'rake/rdoctask'
|
3
2
|
|
4
3
|
task :default => :spec
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
namespace :spec do
|
12
|
-
desc "Run specs in nested documenting format"
|
13
|
-
Spec::Rake::SpecTask.new(:doc) do |t|
|
5
|
+
begin
|
6
|
+
require 'spec/rake/spectask'
|
7
|
+
desc 'Run the specs'
|
8
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
14
9
|
t.libs << 'lib'
|
15
|
-
t.spec_opts = ['--options', "#{File.expand_path(File.dirname(__FILE__))}/spec/
|
10
|
+
t.spec_opts = ['--options', "#{File.expand_path(File.dirname(__FILE__))}/spec/spec.opts"]
|
11
|
+
end
|
12
|
+
|
13
|
+
namespace :spec do
|
14
|
+
desc "Run specs in nested documenting format"
|
15
|
+
Spec::Rake::SpecTask.new(:doc) do |t|
|
16
|
+
t.libs << 'lib'
|
17
|
+
t.spec_opts = ['--options', "#{File.expand_path(File.dirname(__FILE__))}/spec/specdoc.opts"]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
rescue LoadError
|
21
|
+
task :spec do
|
22
|
+
STDERR.puts "You must have rspec to run the tests"
|
23
|
+
end
|
24
|
+
namespace :spec do
|
25
|
+
task :doc => :spec
|
16
26
|
end
|
17
27
|
end
|
18
28
|
|
@@ -40,9 +50,10 @@ begin
|
|
40
50
|
gem.add_dependency('activemodel', '>= 3.0.0.beta3')
|
41
51
|
gem.add_dependency('mongo', '>= 0.20.1')
|
42
52
|
gem.add_dependency('bson', '>= 0.20.1')
|
53
|
+
gem.add_development_dependency('rspec', '>= 1.3.0')
|
43
54
|
end
|
44
55
|
|
45
56
|
Jeweler::GemcutterTasks.new
|
46
57
|
rescue LoadError
|
47
|
-
puts "Jeweler not available. Install it with: gem install jeweler"
|
58
|
+
STDERR.puts "Jeweler not available. Install it with: gem install jeweler"
|
48
59
|
end
|
data/lib/mongomodel.rb
CHANGED
@@ -26,6 +26,7 @@ module MongoModel
|
|
26
26
|
autoload :PrettyInspect, 'mongomodel/concerns/pretty_inspect'
|
27
27
|
autoload :RecordStatus, 'mongomodel/concerns/record_status'
|
28
28
|
autoload :AbstractClass, 'mongomodel/concerns/abstract_class'
|
29
|
+
autoload :DocumentParent, 'mongomodel/concerns/document_parent'
|
29
30
|
autoload :ActiveModelCompatibility, 'mongomodel/concerns/activemodel'
|
30
31
|
|
31
32
|
autoload :Reference, 'mongomodel/support/reference'
|
@@ -21,7 +21,8 @@ module MongoModel
|
|
21
21
|
property = properties_as[k.to_s]
|
22
22
|
|
23
23
|
if property
|
24
|
-
self[property.name] = property.from_mongo(v)
|
24
|
+
child = self[property.name] = property.from_mongo(v)
|
25
|
+
child.parent_document = instance if child.respond_to?(:parent_document=)
|
25
26
|
else
|
26
27
|
self[k.to_sym] = v
|
27
28
|
end
|
@@ -3,7 +3,10 @@ module MongoModel
|
|
3
3
|
module Typecasting
|
4
4
|
def []=(key, value)
|
5
5
|
values_before_typecast[key] = value
|
6
|
-
|
6
|
+
|
7
|
+
result = super(key, typecast(key, value))
|
8
|
+
result.parent_document = instance if result.respond_to?(:parent_document=)
|
9
|
+
result
|
7
10
|
end
|
8
11
|
|
9
12
|
# Check if key has a value that typecasts to true.
|
@@ -56,9 +56,11 @@ module MongoModel
|
|
56
56
|
|
57
57
|
module ClassMethods
|
58
58
|
def from_mongo(hash)
|
59
|
-
|
60
|
-
|
61
|
-
|
59
|
+
if hash
|
60
|
+
doc = class_for_type(hash['_type']).new
|
61
|
+
doc.attributes.from_mongo!(hash)
|
62
|
+
doc
|
63
|
+
end
|
62
64
|
end
|
63
65
|
|
64
66
|
private
|
@@ -286,8 +286,8 @@ module MongoModel
|
|
286
286
|
|
287
287
|
private
|
288
288
|
def nest_embedded_callbacks(kind, *args, &block)
|
289
|
-
embedded_documents.inject(block) do |
|
290
|
-
Proc.new { doc.run_callbacks(kind, *args, &
|
289
|
+
embedded_documents.inject(block) do |callback, doc|
|
290
|
+
Proc.new { doc.run_callbacks(kind, *args, &callback) }
|
291
291
|
end
|
292
292
|
end
|
293
293
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module MongoModel
|
2
|
+
module DocumentParent
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def parent_document
|
6
|
+
@_parent_document.is_a?(Proc) ? @_parent_document.call(self) : @_parent_document
|
7
|
+
end
|
8
|
+
|
9
|
+
def parent_document=(doc)
|
10
|
+
@_parent_document = doc
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -10,10 +10,27 @@ module MongoModel
|
|
10
10
|
class_inheritable_writer :collection_name
|
11
11
|
end
|
12
12
|
|
13
|
+
# Reload the document from the database. If the document
|
14
|
+
# hasn't been saved, this method will raise an error.
|
15
|
+
def reload
|
16
|
+
reloaded = self.class.unscoped.find(id)
|
17
|
+
|
18
|
+
attributes.clear
|
19
|
+
attributes.from_mongo!(reloaded.attributes.to_mongo)
|
20
|
+
|
21
|
+
associations.values.each do |association|
|
22
|
+
association.proxy.reset
|
23
|
+
end
|
24
|
+
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
# Save the document to the database. Returns +true+ on success.
|
13
29
|
def save
|
14
30
|
create_or_update
|
15
31
|
end
|
16
32
|
|
33
|
+
# Save the document to the database. Raises a DocumentNotSaved exception if it fails.
|
17
34
|
def save!
|
18
35
|
create_or_update || raise(DocumentNotSaved)
|
19
36
|
end
|
@@ -23,7 +40,8 @@ module MongoModel
|
|
23
40
|
set_destroyed(true)
|
24
41
|
freeze
|
25
42
|
end
|
26
|
-
|
43
|
+
|
44
|
+
# Remove the document from the database.
|
27
45
|
def destroy
|
28
46
|
delete
|
29
47
|
end
|
@@ -50,6 +68,8 @@ module MongoModel
|
|
50
68
|
self.class.database
|
51
69
|
end
|
52
70
|
|
71
|
+
# Generate a new BSON::ObjectID for the record.
|
72
|
+
# Override in subclasses for custom ID generation.
|
53
73
|
def generate_id
|
54
74
|
::BSON::ObjectID.new.to_s
|
55
75
|
end
|
@@ -67,7 +87,7 @@ module MongoModel
|
|
67
87
|
|
68
88
|
def from_mongo(document)
|
69
89
|
instance = super
|
70
|
-
instance.send(:instantiate, document)
|
90
|
+
instance.send(:instantiate, document) if instance
|
71
91
|
instance
|
72
92
|
end
|
73
93
|
|
@@ -109,7 +129,7 @@ module MongoModel
|
|
109
129
|
def update
|
110
130
|
save_to_collection
|
111
131
|
end
|
112
|
-
|
132
|
+
|
113
133
|
def save_to_collection
|
114
134
|
collection.save(to_mongo, :safe => self.class.save_safely?)
|
115
135
|
set_new_record(false)
|
@@ -12,7 +12,7 @@ module MongoModel
|
|
12
12
|
|
13
13
|
module ClassMethods
|
14
14
|
delegate :find, :first, :last, :all, :exists?, :count, :to => :scoped
|
15
|
-
delegate :delete, :delete_all, :destroy, :destroy_all, :to => :scoped
|
15
|
+
delegate :update, :update_all, :delete, :delete_all, :destroy, :destroy_all, :to => :scoped
|
16
16
|
delegate :select, :order, :where, :limit, :offset, :from, :to => :scoped
|
17
17
|
|
18
18
|
def unscoped
|
@@ -28,9 +28,11 @@ module MongoModel
|
|
28
28
|
include Timestamps
|
29
29
|
include PrettyInspect
|
30
30
|
include AbstractClass
|
31
|
+
include DocumentParent
|
31
32
|
|
32
33
|
# Allow Collection class to be used in property definitions
|
33
34
|
Collection = MongoModel::Collection
|
35
|
+
extend Collection::PropertyDefaults
|
34
36
|
|
35
37
|
undef_method :type if method_defined?(:type)
|
36
38
|
property :type, String, :as => '_type', :default => lambda { |doc| doc.class.name }, :protected => true
|
@@ -1,20 +1,40 @@
|
|
1
1
|
module MongoModel
|
2
2
|
class Collection < Array
|
3
|
+
module PropertyDefaults
|
4
|
+
def property(name, *args, &block) #:nodoc:
|
5
|
+
property = super(name, *args, &block)
|
6
|
+
|
7
|
+
if property.type <= Collection
|
8
|
+
property.options[:default] ||= property.type.new
|
9
|
+
end
|
10
|
+
|
11
|
+
property
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
3
15
|
ARRAY_CONVERTER = Types.converter_for(Array)
|
4
16
|
|
5
17
|
class_inheritable_accessor :type
|
6
18
|
self.type = Object
|
7
19
|
|
20
|
+
include DocumentParent
|
21
|
+
|
8
22
|
def initialize(array=[])
|
9
|
-
super(array.map { |i|
|
23
|
+
super(array.map { |i| convert_for_add(i) })
|
10
24
|
end
|
11
25
|
|
12
26
|
def []=(index, value)
|
13
|
-
super(index,
|
27
|
+
super(index, convert_for_add(value))
|
14
28
|
end
|
15
29
|
|
16
30
|
def <<(value)
|
17
|
-
super(
|
31
|
+
super(convert_for_add(value))
|
32
|
+
end
|
33
|
+
|
34
|
+
def build (value)
|
35
|
+
value = convert(value)
|
36
|
+
self << value
|
37
|
+
value
|
18
38
|
end
|
19
39
|
|
20
40
|
def +(other)
|
@@ -22,7 +42,7 @@ module MongoModel
|
|
22
42
|
end
|
23
43
|
|
24
44
|
def concat(values)
|
25
|
-
super(values.map { |v|
|
45
|
+
super(values.map { |v| convert_for_add(v) })
|
26
46
|
end
|
27
47
|
|
28
48
|
def delete(value)
|
@@ -38,11 +58,11 @@ module MongoModel
|
|
38
58
|
end
|
39
59
|
|
40
60
|
def insert(index, value)
|
41
|
-
super(index,
|
61
|
+
super(index, convert_for_add(value))
|
42
62
|
end
|
43
63
|
|
44
64
|
def push(*values)
|
45
|
-
super(*values.map { |v|
|
65
|
+
super(*values.map { |v| convert_for_add(v) })
|
46
66
|
end
|
47
67
|
|
48
68
|
def rindex(value)
|
@@ -50,7 +70,7 @@ module MongoModel
|
|
50
70
|
end
|
51
71
|
|
52
72
|
def unshift(*values)
|
53
|
-
super(*values.map { |v|
|
73
|
+
super(*values.map { |v| convert_for_add(v) })
|
54
74
|
end
|
55
75
|
|
56
76
|
def to_mongo
|
@@ -69,7 +89,31 @@ module MongoModel
|
|
69
89
|
"Collection[#{type}]"
|
70
90
|
end
|
71
91
|
end
|
72
|
-
|
92
|
+
|
93
|
+
# Create a new MongoModel::Collection class with the type set to the specified class.
|
94
|
+
# This allows you declare arrays of embedded documents like:
|
95
|
+
#
|
96
|
+
# class Thing < MongoModel::EmbeddedDocument
|
97
|
+
# property :name, String
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
# class MyModel < MongoModel::Document
|
101
|
+
# property :things, Collection[Thing]
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# If you don't declare a default on a property that has a Collection type, the
|
105
|
+
# default will be automatically set to an empty Collection.
|
106
|
+
#
|
107
|
+
# This method is aliased as #of, so you can use the alternative syntax:
|
108
|
+
# property :things, Collection.of(Thing)
|
109
|
+
#
|
110
|
+
# Examples:
|
111
|
+
#
|
112
|
+
# model = MyModel.new
|
113
|
+
# model.things # => []
|
114
|
+
# model.things << {:name => "Thing One"}
|
115
|
+
# model.things # => [#<Thing name: "Thing One">]
|
116
|
+
# model.things = [{:name => "Thing Two"}] # => [#<Thing name: "Thing Two">]
|
73
117
|
def [](type)
|
74
118
|
@collection_class_cache ||= {}
|
75
119
|
@collection_class_cache[type] ||= begin
|
@@ -79,6 +123,8 @@ module MongoModel
|
|
79
123
|
end
|
80
124
|
end
|
81
125
|
|
126
|
+
alias of []
|
127
|
+
|
82
128
|
def from_mongo(array)
|
83
129
|
new(array.map { |i| instantiate(i) })
|
84
130
|
end
|
@@ -102,6 +148,12 @@ module MongoModel
|
|
102
148
|
converter.cast(value)
|
103
149
|
end
|
104
150
|
|
151
|
+
def convert_for_add(value)
|
152
|
+
result = convert(value)
|
153
|
+
result.parent_document = lambda { parent_document } if result.respond_to?(:parent_document=)
|
154
|
+
result
|
155
|
+
end
|
156
|
+
|
105
157
|
def converter
|
106
158
|
self.class.converter
|
107
159
|
end
|
@@ -83,6 +83,17 @@ module MongoModel
|
|
83
83
|
reset
|
84
84
|
end
|
85
85
|
|
86
|
+
def update_all(updates)
|
87
|
+
selector = MongoOptions.new(klass, :conditions => finder_conditions).selector
|
88
|
+
collection.update(selector, { "$set" => updates }, { :multi => true })
|
89
|
+
reset
|
90
|
+
end
|
91
|
+
|
92
|
+
def update(ids, updates)
|
93
|
+
where(ids_to_conditions(ids)).update_all(updates)
|
94
|
+
reset
|
95
|
+
end
|
96
|
+
|
86
97
|
def loaded?
|
87
98
|
@loaded
|
88
99
|
end
|
@@ -174,7 +185,7 @@ module MongoModel
|
|
174
185
|
end
|
175
186
|
|
176
187
|
def ids_to_conditions(ids)
|
177
|
-
ids.flatten
|
188
|
+
ids = Array.wrap(ids).flatten
|
178
189
|
|
179
190
|
if ids.size == 1
|
180
191
|
{ :id => ids.first.to_s }
|
@@ -5,7 +5,11 @@ module MongoModel
|
|
5
5
|
module Types
|
6
6
|
class Time < Object
|
7
7
|
def cast(value)
|
8
|
-
value.to_time.utc
|
8
|
+
time = value.to_time.utc
|
9
|
+
# BSON only stores time accurate to the millisecond
|
10
|
+
::Time.at((time.to_f * 1000).floor / 1000.0)
|
11
|
+
rescue
|
12
|
+
nil
|
9
13
|
end
|
10
14
|
end
|
11
15
|
end
|
data/lib/mongomodel/version.rb
CHANGED
data/mongomodel.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mongomodel}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Sam Pohlenz"]
|
12
|
-
s.date = %q{2010-04-
|
12
|
+
s.date = %q{2010-04-30}
|
13
13
|
s.default_executable = %q{console}
|
14
14
|
s.description = %q{MongoModel is a MongoDB ORM for Ruby/Rails similar to ActiveRecord and DataMapper.}
|
15
15
|
s.email = %q{sam@sampohlenz.com}
|
@@ -47,6 +47,7 @@ Gem::Specification.new do |s|
|
|
47
47
|
"lib/mongomodel/concerns/attribute_methods/write.rb",
|
48
48
|
"lib/mongomodel/concerns/attributes.rb",
|
49
49
|
"lib/mongomodel/concerns/callbacks.rb",
|
50
|
+
"lib/mongomodel/concerns/document_parent.rb",
|
50
51
|
"lib/mongomodel/concerns/logging.rb",
|
51
52
|
"lib/mongomodel/concerns/pretty_inspect.rb",
|
52
53
|
"lib/mongomodel/concerns/properties.rb",
|
@@ -145,8 +146,7 @@ Gem::Specification.new do |s|
|
|
145
146
|
"spec/support/matchers/find_with.rb",
|
146
147
|
"spec/support/matchers/respond_to_boolean.rb",
|
147
148
|
"spec/support/matchers/run_callbacks.rb",
|
148
|
-
"spec/support/models.rb"
|
149
|
-
"spec/support/time.rb"
|
149
|
+
"spec/support/models.rb"
|
150
150
|
]
|
151
151
|
s.homepage = %q{http://github.com/spohlenz/mongomodel}
|
152
152
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -202,8 +202,7 @@ Gem::Specification.new do |s|
|
|
202
202
|
"spec/support/matchers/find_with.rb",
|
203
203
|
"spec/support/matchers/respond_to_boolean.rb",
|
204
204
|
"spec/support/matchers/run_callbacks.rb",
|
205
|
-
"spec/support/models.rb"
|
206
|
-
"spec/support/time.rb"
|
205
|
+
"spec/support/models.rb"
|
207
206
|
]
|
208
207
|
|
209
208
|
if s.respond_to? :specification_version then
|
@@ -215,17 +214,20 @@ Gem::Specification.new do |s|
|
|
215
214
|
s.add_runtime_dependency(%q<activemodel>, [">= 3.0.0.beta3"])
|
216
215
|
s.add_runtime_dependency(%q<mongo>, [">= 0.20.1"])
|
217
216
|
s.add_runtime_dependency(%q<bson>, [">= 0.20.1"])
|
217
|
+
s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
|
218
218
|
else
|
219
219
|
s.add_dependency(%q<activesupport>, [">= 3.0.0.beta3"])
|
220
220
|
s.add_dependency(%q<activemodel>, [">= 3.0.0.beta3"])
|
221
221
|
s.add_dependency(%q<mongo>, [">= 0.20.1"])
|
222
222
|
s.add_dependency(%q<bson>, [">= 0.20.1"])
|
223
|
+
s.add_dependency(%q<rspec>, [">= 1.3.0"])
|
223
224
|
end
|
224
225
|
else
|
225
226
|
s.add_dependency(%q<activesupport>, [">= 3.0.0.beta3"])
|
226
227
|
s.add_dependency(%q<activemodel>, [">= 3.0.0.beta3"])
|
227
228
|
s.add_dependency(%q<mongo>, [">= 0.20.1"])
|
228
229
|
s.add_dependency(%q<bson>, [">= 0.20.1"])
|
230
|
+
s.add_dependency(%q<rspec>, [">= 1.3.0"])
|
229
231
|
end
|
230
232
|
end
|
231
233
|
|
@@ -96,10 +96,10 @@ module MongoModel
|
|
96
96
|
},
|
97
97
|
:time =>
|
98
98
|
{
|
99
|
-
Time.local(2008, 5, 14, 1, 2, 3, 4) => Time.local(2008, 5, 14, 1, 2, 3, 4),
|
100
|
-
Date.civil(2009, 11, 15) => Time.local(2009, 11, 15, 0, 0, 0, 0),
|
101
|
-
"Sat Jan 01 20:15:01 UTC 2000" => Time.utc(2000, 1, 1, 20, 15, 1, 0),
|
102
|
-
"2009/3/4" => Time.utc(2009, 3, 4, 0, 0, 0, 0)
|
99
|
+
Time.local(2008, 5, 14, 1, 2, 3, 4) => Time.local(2008, 5, 14, 1, 2, 3, 4, 0),
|
100
|
+
Date.civil(2009, 11, 15) => Time.local(2009, 11, 15, 0, 0, 0, 0, 0),
|
101
|
+
"Sat Jan 01 20:15:01 UTC 2000" => Time.utc(2000, 1, 1, 20, 15, 1, 0, 0),
|
102
|
+
"2009/3/4" => Time.utc(2009, 3, 4, 0, 0, 0, 0, 0)
|
103
103
|
}
|
104
104
|
}
|
105
105
|
|
@@ -216,7 +216,7 @@ module MongoModel
|
|
216
216
|
subject[:hash] = { :foo => 'bar', :custom => CustomClass.new('custom in hash') }
|
217
217
|
subject[:array] = [ 123, 'abc', 45.67, true, :bar, CustomClass.new('custom in array') ]
|
218
218
|
subject[:date] = Date.civil(2009, 11, 15)
|
219
|
-
subject[:time] = Time.local(2008, 5, 14, 1, 2, 3, 4)
|
219
|
+
subject[:time] = Time.local(2008, 5, 14, 1, 2, 3, 4, 0.5)
|
220
220
|
subject[:custom] = CustomClass.new('custom')
|
221
221
|
subject[:as] = "As property"
|
222
222
|
subject[:non_property] = "Hello World"
|
@@ -231,7 +231,7 @@ module MongoModel
|
|
231
231
|
'hash' => { :foo => 'bar', :custom => { :name => 'custom in hash' } },
|
232
232
|
'array' => [ 123, 'abc', 45.67, true, :bar, { :name => 'custom in array' } ],
|
233
233
|
'date' => "2009/11/15",
|
234
|
-
'time' => Time.local(2008, 5, 14, 1, 2, 3, 4),
|
234
|
+
'time' => Time.local(2008, 5, 14, 1, 2, 3, 4, 0),
|
235
235
|
'custom' => { :name => 'custom' },
|
236
236
|
'_custom_as' => "As property",
|
237
237
|
'non_property' => "Hello World",
|
@@ -249,7 +249,7 @@ module MongoModel
|
|
249
249
|
'hash' => { :foo => 'bar' },
|
250
250
|
'array' => [ 123, 'abc', 45.67, true, :bar ],
|
251
251
|
'date' => Time.utc(2009, 11, 15),
|
252
|
-
'time' => Time.local(2008, 5, 14, 1, 2, 3, 4),
|
252
|
+
'time' => Time.local(2008, 5, 14, 1, 2, 3, 4, 0.5),
|
253
253
|
'custom' => { :name => 'custom' },
|
254
254
|
'_custom_as' => "As property",
|
255
255
|
'custom_non_property' => { :name => 'custom non property' }
|
@@ -263,7 +263,7 @@ module MongoModel
|
|
263
263
|
subject[:hash].should == { :foo => 'bar' }.with_indifferent_access
|
264
264
|
subject[:array].should == [ 123, 'abc', 45.67, true, :bar ]
|
265
265
|
subject[:date].should == Date.civil(2009, 11, 15)
|
266
|
-
subject[:time].should == Time.local(2008, 5, 14, 1, 2, 3, 4)
|
266
|
+
subject[:time].should == Time.local(2008, 5, 14, 1, 2, 3, 4, 0)
|
267
267
|
subject[:custom].should == CustomClass.new('custom')
|
268
268
|
subject[:as].should == "As property"
|
269
269
|
subject[:custom_non_property].should == { :name => 'custom non property' }
|
@@ -31,15 +31,15 @@ module MongoModel
|
|
31
31
|
end
|
32
32
|
|
33
33
|
it "should add the old attribute name to the changed attributes" do
|
34
|
-
subject.changed.should include(
|
34
|
+
subject.changed.should include("foo")
|
35
35
|
end
|
36
36
|
|
37
37
|
it "should not add other attributes to the changed attributes" do
|
38
|
-
subject.changed.should_not include(
|
38
|
+
subject.changed.should_not include("bar")
|
39
39
|
end
|
40
40
|
|
41
41
|
it "should add the changed attribute value to the changes hash" do
|
42
|
-
subject.changes[
|
42
|
+
subject.changes["foo"].should == ['original foo', 'new foo']
|
43
43
|
end
|
44
44
|
|
45
45
|
context "when called twice" do
|
@@ -48,7 +48,7 @@ module MongoModel
|
|
48
48
|
end
|
49
49
|
|
50
50
|
it "should keep the original value as the old value in the changes hash" do
|
51
|
-
subject.changes[
|
51
|
+
subject.changes["foo"].should == ['original foo', 'new foo #2']
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -60,6 +60,24 @@ module MongoModel
|
|
60
60
|
end
|
61
61
|
|
62
62
|
it { should be_changed }
|
63
|
+
|
64
|
+
it "should have a changed attribute" do
|
65
|
+
subject.foo_changed?.should == true
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should tell what the attribute was" do
|
69
|
+
subject.foo_was.should == "original foo"
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should have an attribute change" do
|
73
|
+
subject.foo_change.should == ["original foo", "foo changed"]
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should be able to reset an attribute" do
|
77
|
+
subject.reset_foo!
|
78
|
+
subject.foo.should == "original foo"
|
79
|
+
subject.changed?.should == false
|
80
|
+
end
|
63
81
|
end
|
64
82
|
|
65
83
|
context "attribute set to the original value" do
|
@@ -68,11 +86,47 @@ module MongoModel
|
|
68
86
|
end
|
69
87
|
|
70
88
|
it { should_not be_changed }
|
89
|
+
|
90
|
+
it "should not have a changed attribute" do
|
91
|
+
subject.foo_changed?.should == false
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should tell what the attribute was" do
|
95
|
+
subject.foo_was.should == "original foo"
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should not have an attribute change" do
|
99
|
+
subject.foo_change.should == nil
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should be able to reset an attribute" do
|
103
|
+
subject.reset_foo!
|
104
|
+
subject.foo.should == "original foo"
|
105
|
+
subject.changed?.should == false
|
106
|
+
end
|
71
107
|
end
|
72
108
|
end
|
73
109
|
|
74
110
|
context "without changed attributes" do
|
75
111
|
it { should_not be_changed }
|
112
|
+
|
113
|
+
it "should not have a changed attribute" do
|
114
|
+
subject.foo_changed?.should == false
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should tell what the attribute was" do
|
118
|
+
subject.foo_was.should == "original foo"
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should not have an attribute change" do
|
122
|
+
subject.foo_change.should == nil
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should be able to reset an attribute" do
|
126
|
+
subject.reset_foo!
|
127
|
+
subject.foo.should == "original foo"
|
128
|
+
subject.changed?.should == false
|
129
|
+
end
|
76
130
|
end
|
77
131
|
|
78
132
|
context "#original_attributes" do
|
@@ -82,7 +136,7 @@ module MongoModel
|
|
82
136
|
end
|
83
137
|
|
84
138
|
it "should return the attributes before changes" do
|
85
|
-
subject.original_attributes[
|
139
|
+
subject.original_attributes['foo'].should == 'original foo'
|
86
140
|
end
|
87
141
|
end
|
88
142
|
|
@@ -11,7 +11,7 @@ module MongoModel
|
|
11
11
|
Array => [ 1, 2, 3, "hello", :world, [99, 100] ],
|
12
12
|
Hash => { :rabbit => 'hat', 'hello' => 12345 }.with_indifferent_access,
|
13
13
|
Date => Date.today,
|
14
|
-
Time => Time.now,
|
14
|
+
Time => Types::Time.new.cast(Time.now),
|
15
15
|
CustomClass => CustomClass.new('hello')
|
16
16
|
}
|
17
17
|
|
@@ -2,6 +2,27 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module MongoModel
|
4
4
|
specs_for(EmbeddedDocument) do
|
5
|
+
describe "callbacks on many embedded documents" do
|
6
|
+
define_class(:ChildThingDocument, EmbeddedDocument) do
|
7
|
+
include MongoModel::CallbackHelpers
|
8
|
+
property :name, String
|
9
|
+
end
|
10
|
+
|
11
|
+
define_class(:ParentDocument, Document) do
|
12
|
+
property :things, Collection[ChildThingDocument]
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should call callbacks on all embedded documents when adding a new one" do
|
16
|
+
parent = ParentDocument.create!
|
17
|
+
parent.things = Collection[ChildThingDocument].new
|
18
|
+
parent.things << ChildThingDocument.new(:name => "Thing One")
|
19
|
+
parent.save!
|
20
|
+
parent = ParentDocument.find(parent.id)
|
21
|
+
parent.things << ChildThingDocument.new(:name => "Thing Two")
|
22
|
+
parent.save!
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
5
26
|
describe "callbacks" do
|
6
27
|
define_class(:ChildDocument, EmbeddedDocument) do
|
7
28
|
include MongoModel::CallbackHelpers
|
@@ -30,5 +30,27 @@ module MongoModel
|
|
30
30
|
Person.internal_properties.should include(Person.properties[:type])
|
31
31
|
Person.internal_properties.should include(Person.properties[:id]) if described_class == Document
|
32
32
|
end
|
33
|
+
|
34
|
+
describe "when used as a property inside a document" do
|
35
|
+
define_class(:Factory, Document) do
|
36
|
+
property :manager, Person
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:person) { SkilledPerson.new(:name => "Joe", :age => 44, :skill => "Management") }
|
40
|
+
let(:with_manager) { Factory.create!(:manager => person) }
|
41
|
+
let(:without_manager) { Factory.create! }
|
42
|
+
|
43
|
+
it "should load correctly when property is set" do
|
44
|
+
factory = Factory.find(with_manager.id)
|
45
|
+
factory.manager.should be_an_instance_of(SkilledPerson)
|
46
|
+
factory.manager.name.should == "Joe"
|
47
|
+
factory.manager.skill.should == "Management"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should load correctly when property is nil" do
|
51
|
+
factory = Factory.find(without_manager.id)
|
52
|
+
factory.manager.should be_nil
|
53
|
+
end
|
54
|
+
end
|
33
55
|
end
|
34
56
|
end
|
@@ -38,7 +38,7 @@ module MongoModel
|
|
38
38
|
subject { TestDocument.new }
|
39
39
|
|
40
40
|
before(:each) do
|
41
|
-
@now = Time.now
|
41
|
+
@now = Types::Time.new.cast(Time.now)
|
42
42
|
Time.stub!(:now).and_return(@now)
|
43
43
|
end
|
44
44
|
|
@@ -91,7 +91,7 @@ module MongoModel
|
|
91
91
|
subject { TestDocument.new }
|
92
92
|
|
93
93
|
before(:each) do
|
94
|
-
@now = Time.now
|
94
|
+
@now = Types::Time.new.cast(Time.now)
|
95
95
|
Time.stub!(:now).and_return(@now)
|
96
96
|
end
|
97
97
|
|
@@ -300,6 +300,38 @@ module MongoModel
|
|
300
300
|
user.should_not be_a_new_record
|
301
301
|
end
|
302
302
|
end
|
303
|
+
|
304
|
+
describe "#reload" do
|
305
|
+
define_class(:UserComment, Document) do
|
306
|
+
property :title, String
|
307
|
+
property :body, String
|
308
|
+
|
309
|
+
belongs_to :user
|
310
|
+
end
|
311
|
+
|
312
|
+
let(:user) { User.create!(:name => "Bob") }
|
313
|
+
|
314
|
+
subject { UserComment.create!(:title => "Test", :user => user) }
|
315
|
+
|
316
|
+
it "should return itself" do
|
317
|
+
subject.reload.should == subject
|
318
|
+
end
|
319
|
+
|
320
|
+
it "should reset the attributes" do
|
321
|
+
subject.title = "New Value"
|
322
|
+
subject.body = "Blah blah blah"
|
323
|
+
subject.reload
|
324
|
+
subject.title.should == "Test"
|
325
|
+
subject.body.should == nil
|
326
|
+
end
|
327
|
+
|
328
|
+
it "should reset the associations" do
|
329
|
+
subject.user.should == user
|
330
|
+
subject.user = User.new(:name => "Bill")
|
331
|
+
subject.reload
|
332
|
+
subject.user.should == user
|
333
|
+
end
|
334
|
+
end
|
303
335
|
end
|
304
336
|
end
|
305
337
|
end
|
@@ -41,19 +41,20 @@ module MongoModel
|
|
41
41
|
end
|
42
42
|
|
43
43
|
specs_for(EmbeddedDocument) do
|
44
|
+
define_class(:Event, EmbeddedDocument)
|
45
|
+
define_class(:SpecialEvent, :Event)
|
46
|
+
|
47
|
+
define_class(:Parent, Document) do
|
48
|
+
property :event, Event
|
49
|
+
property :events, Collection[Event], :default => []
|
50
|
+
end
|
51
|
+
|
52
|
+
let(:event) { Event.new }
|
53
|
+
let(:special) { SpecialEvent.new }
|
54
|
+
let(:parent) { Parent.new(:event => special) }
|
55
|
+
let(:reloaded) { parent.save!; Parent.find(parent.id) }
|
56
|
+
|
44
57
|
describe "single collection inheritance" do
|
45
|
-
define_class(:Event, EmbeddedDocument)
|
46
|
-
define_class(:SpecialEvent, :Event)
|
47
|
-
|
48
|
-
define_class(:Parent, Document) do
|
49
|
-
property :event, Event
|
50
|
-
end
|
51
|
-
|
52
|
-
let(:event) { Event.new }
|
53
|
-
let(:special) { SpecialEvent.new }
|
54
|
-
let(:parent) { Parent.new(:event => special) }
|
55
|
-
let(:reloaded) { parent.save!; Parent.find(parent.id) }
|
56
|
-
|
57
58
|
it "should not typecast to parent type when assigning to property" do
|
58
59
|
parent.event.should be_an_instance_of(SpecialEvent)
|
59
60
|
end
|
@@ -62,5 +63,33 @@ module MongoModel
|
|
62
63
|
reloaded.event.should be_an_instance_of(SpecialEvent)
|
63
64
|
end
|
64
65
|
end
|
66
|
+
|
67
|
+
describe "parent document" do
|
68
|
+
context "on an embedded document" do
|
69
|
+
it "should set the parent document on the embedded document" do
|
70
|
+
parent.event.parent_document.should == parent
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should set the parent document on the embedded document when loaded from database" do
|
74
|
+
reloaded.event.parent_document.should == reloaded
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "on a collection" do
|
79
|
+
it "should set the parent document on the collection" do
|
80
|
+
parent.events.parent_document.should == parent
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should set the parent document on each item added to a collection" do
|
84
|
+
parent.events << special
|
85
|
+
parent.events.first.parent_document.should == parent
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should set the parent document on each item in a collection when loaded from database" do
|
89
|
+
parent.events << special
|
90
|
+
reloaded.events.first.parent_document.should == parent
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
65
94
|
end
|
66
95
|
end
|
@@ -234,8 +234,14 @@ module MongoModel
|
|
234
234
|
let(:embedded2) { Embedded.new(:number => 2) }
|
235
235
|
let(:embedded3) { Embedded.new(:number => 3) }
|
236
236
|
|
237
|
+
let(:empty) { TestDocument.new }
|
237
238
|
subject { TestDocument.new(:embedded => embedded1, :embedded_collection => [embedded2, embedded3]) }
|
238
239
|
|
240
|
+
it "should default to an empty collection" do
|
241
|
+
empty.embedded_collection.should be_an_instance_of(Collection[Embedded])
|
242
|
+
empty.embedded_collection.should be_empty
|
243
|
+
end
|
244
|
+
|
239
245
|
it "should include the embedded properties in the embedded documents list" do
|
240
246
|
subject.embedded_documents.should include(embedded1)
|
241
247
|
end
|
@@ -611,6 +611,55 @@ module MongoModel
|
|
611
611
|
end
|
612
612
|
end
|
613
613
|
end
|
614
|
+
|
615
|
+
describe "#update_all" do
|
616
|
+
it "should update all matching documents" do
|
617
|
+
model.should_update(finder_conditions, { :name => "New name" })
|
618
|
+
subject.update_all(:name => "New name")
|
619
|
+
end
|
620
|
+
|
621
|
+
subject_loaded do
|
622
|
+
it "should reset the scope" do
|
623
|
+
subject.update_all(:name => "New name")
|
624
|
+
subject.should_not be_loaded
|
625
|
+
end
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
describe "#update" do
|
630
|
+
context "by single id" do
|
631
|
+
let(:post) { posts.first }
|
632
|
+
|
633
|
+
it "should update the document with the given id" do
|
634
|
+
model.should_update(finder_conditions.merge(:id => post.id), { :name => "New name" })
|
635
|
+
subject.update(post.id, :name => "New name")
|
636
|
+
end
|
637
|
+
|
638
|
+
subject_loaded do
|
639
|
+
it "should reset the scope" do
|
640
|
+
subject.update(post.id, {})
|
641
|
+
subject.should_not be_loaded
|
642
|
+
end
|
643
|
+
end
|
644
|
+
end
|
645
|
+
|
646
|
+
context "by multiple ids" do
|
647
|
+
let(:post1) { posts.first }
|
648
|
+
let(:post2) { posts.last }
|
649
|
+
|
650
|
+
it "should update the documents with the given ids" do
|
651
|
+
model.should_update(finder_conditions.merge(:id.in => [post1.id, post2.id]), { :name => "New name" })
|
652
|
+
subject.update([post1.id, post2.id], :name => "New name")
|
653
|
+
end
|
654
|
+
|
655
|
+
subject_loaded do
|
656
|
+
it "should reset the scope" do
|
657
|
+
subject.update([post1.id, post2.id], {})
|
658
|
+
subject.should_not be_loaded
|
659
|
+
end
|
660
|
+
end
|
661
|
+
end
|
662
|
+
end
|
614
663
|
end
|
615
664
|
|
616
665
|
|
data/spec/spec.opts
CHANGED
@@ -41,4 +41,10 @@ module DocumentFinderStubs
|
|
41
41
|
collection.should_receive(:remove).once.with(selector)
|
42
42
|
yield if block_given?
|
43
43
|
end
|
44
|
+
|
45
|
+
def should_update(conditions={}, updates={})
|
46
|
+
selector, options = MongoModel::MongoOptions.new(self, :conditions => conditions).to_a
|
47
|
+
collection.should_receive(:update).once.with(selector, { "$set" => updates }, { :multi => true })
|
48
|
+
yield if block_given?
|
49
|
+
end
|
44
50
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 3
|
9
|
+
version: 0.2.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Sam Pohlenz
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-04-
|
17
|
+
date: 2010-04-30 00:00:00 +09:30
|
18
18
|
default_executable: console
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -75,6 +75,20 @@ dependencies:
|
|
75
75
|
version: 0.20.1
|
76
76
|
type: :runtime
|
77
77
|
version_requirements: *id004
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rspec
|
80
|
+
prerelease: false
|
81
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
segments:
|
86
|
+
- 1
|
87
|
+
- 3
|
88
|
+
- 0
|
89
|
+
version: 1.3.0
|
90
|
+
type: :development
|
91
|
+
version_requirements: *id005
|
78
92
|
description: MongoModel is a MongoDB ORM for Ruby/Rails similar to ActiveRecord and DataMapper.
|
79
93
|
email: sam@sampohlenz.com
|
80
94
|
executables:
|
@@ -113,6 +127,7 @@ files:
|
|
113
127
|
- lib/mongomodel/concerns/attribute_methods/write.rb
|
114
128
|
- lib/mongomodel/concerns/attributes.rb
|
115
129
|
- lib/mongomodel/concerns/callbacks.rb
|
130
|
+
- lib/mongomodel/concerns/document_parent.rb
|
116
131
|
- lib/mongomodel/concerns/logging.rb
|
117
132
|
- lib/mongomodel/concerns/pretty_inspect.rb
|
118
133
|
- lib/mongomodel/concerns/properties.rb
|
@@ -212,7 +227,6 @@ files:
|
|
212
227
|
- spec/support/matchers/respond_to_boolean.rb
|
213
228
|
- spec/support/matchers/run_callbacks.rb
|
214
229
|
- spec/support/models.rb
|
215
|
-
- spec/support/time.rb
|
216
230
|
has_rdoc: true
|
217
231
|
homepage: http://github.com/spohlenz/mongomodel
|
218
232
|
licenses: []
|
@@ -293,4 +307,3 @@ test_files:
|
|
293
307
|
- spec/support/matchers/respond_to_boolean.rb
|
294
308
|
- spec/support/matchers/run_callbacks.rb
|
295
309
|
- spec/support/models.rb
|
296
|
-
- spec/support/time.rb
|