mongo_mapper 0.6.10 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +5 -14
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/mongo_mapper.rb +48 -56
- data/lib/mongo_mapper/document.rb +136 -164
- data/lib/mongo_mapper/embedded_document.rb +29 -354
- data/lib/mongo_mapper/plugins.rb +31 -0
- data/lib/mongo_mapper/plugins/associations.rb +105 -0
- data/lib/mongo_mapper/plugins/associations/base.rb +123 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
- data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +50 -0
- data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
- data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
- data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
- data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
- data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
- data/lib/mongo_mapper/plugins/callbacks.rb +65 -0
- data/lib/mongo_mapper/plugins/clone.rb +13 -0
- data/lib/mongo_mapper/plugins/descendants.rb +16 -0
- data/lib/mongo_mapper/plugins/dirty.rb +119 -0
- data/lib/mongo_mapper/plugins/equality.rb +23 -0
- data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
- data/lib/mongo_mapper/plugins/inspect.rb +14 -0
- data/lib/mongo_mapper/plugins/keys.rb +324 -0
- data/lib/mongo_mapper/plugins/logger.rb +17 -0
- data/lib/mongo_mapper/plugins/pagination.rb +24 -0
- data/lib/mongo_mapper/plugins/pagination/proxy.rb +68 -0
- data/lib/mongo_mapper/plugins/protected.rb +45 -0
- data/lib/mongo_mapper/plugins/rails.rb +45 -0
- data/lib/mongo_mapper/plugins/serialization.rb +105 -0
- data/lib/mongo_mapper/plugins/validations.rb +46 -0
- data/lib/mongo_mapper/query.rb +130 -0
- data/lib/mongo_mapper/support.rb +40 -17
- data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
- data/lib/mongo_mapper/support/find.rb +77 -0
- data/mongo_mapper.gemspec +55 -38
- data/performance/read_write.rb +52 -0
- data/specs.watchr +23 -2
- data/test/functional/associations/test_belongs_to_proxy.rb +12 -10
- data/test/functional/associations/test_many_documents_as_proxy.rb +4 -21
- data/test/functional/associations/test_many_documents_proxy.rb +2 -8
- data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +59 -39
- data/test/functional/associations/test_many_embedded_proxy.rb +145 -81
- data/test/functional/associations/test_many_polymorphic_proxy.rb +2 -40
- data/test/functional/associations/test_one_proxy.rb +25 -10
- data/test/functional/test_binary.rb +2 -8
- data/test/functional/test_callbacks.rb +1 -5
- data/test/functional/test_dirty.rb +27 -23
- data/test/functional/test_document.rb +224 -165
- data/test/functional/test_embedded_document.rb +72 -82
- data/test/functional/test_identity_map.rb +508 -0
- data/test/functional/test_modifiers.rb +15 -5
- data/test/functional/test_pagination.rb +1 -3
- data/test/functional/test_protected.rb +155 -0
- data/test/functional/test_string_id_compatibility.rb +7 -12
- data/test/functional/test_validations.rb +26 -58
- data/test/models.rb +0 -39
- data/test/test_helper.rb +37 -3
- data/test/unit/associations/test_base.rb +5 -5
- data/test/unit/associations/test_proxy.rb +8 -6
- data/test/unit/test_descendant_appends.rb +71 -0
- data/test/unit/test_document.rb +71 -76
- data/test/unit/test_dynamic_finder.rb +27 -29
- data/test/unit/test_embedded_document.rb +555 -601
- data/test/unit/{test_key.rb → test_keys.rb} +2 -5
- data/test/unit/test_mongo_mapper.rb +69 -9
- data/test/unit/test_pagination.rb +40 -32
- data/test/unit/test_plugins.rb +50 -0
- data/test/unit/{test_finder_options.rb → test_query.rb} +74 -65
- data/test/unit/test_rails.rb +123 -0
- data/test/unit/{test_serializations.rb → test_serialization.rb} +1 -2
- data/test/unit/test_support.rb +23 -7
- data/test/unit/test_time_zones.rb +3 -4
- data/test/unit/test_validations.rb +58 -17
- metadata +53 -36
- data/lib/mongo_mapper/associations.rb +0 -78
- data/lib/mongo_mapper/associations/base.rb +0 -119
- data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +0 -26
- data/lib/mongo_mapper/associations/belongs_to_proxy.rb +0 -21
- data/lib/mongo_mapper/associations/collection.rb +0 -19
- data/lib/mongo_mapper/associations/in_array_proxy.rb +0 -137
- data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +0 -26
- data/lib/mongo_mapper/associations/many_documents_proxy.rb +0 -115
- data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +0 -31
- data/lib/mongo_mapper/associations/many_embedded_proxy.rb +0 -54
- data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +0 -11
- data/lib/mongo_mapper/associations/one_proxy.rb +0 -64
- data/lib/mongo_mapper/associations/proxy.rb +0 -116
- data/lib/mongo_mapper/callbacks.rb +0 -61
- data/lib/mongo_mapper/dirty.rb +0 -117
- data/lib/mongo_mapper/dynamic_finder.rb +0 -74
- data/lib/mongo_mapper/finder_options.rb +0 -145
- data/lib/mongo_mapper/key.rb +0 -36
- data/lib/mongo_mapper/mongo_mapper.rb +0 -125
- data/lib/mongo_mapper/pagination.rb +0 -66
- data/lib/mongo_mapper/rails_compatibility/document.rb +0 -15
- data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +0 -28
- data/lib/mongo_mapper/serialization.rb +0 -54
- data/lib/mongo_mapper/serializers/json_serializer.rb +0 -48
- data/lib/mongo_mapper/validations.rb +0 -39
- data/test/functional/test_rails_compatibility.rb +0 -25
data/README.rdoc
CHANGED
@@ -13,25 +13,16 @@ Releases are tagged on github and released on gemcutter. Master is pushed to whe
|
|
13
13
|
* Send me a pull request. Bonus points for topic branches.
|
14
14
|
|
15
15
|
== Install
|
16
|
-
|
17
|
-
$ gem install mongo_mapper
|
18
|
-
|
19
|
-
== Dependencies
|
20
|
-
|
21
|
-
* ActiveSupport (typically the latest version)
|
22
|
-
* Mongo Ruby Driver (mongo)
|
23
|
-
* My fork of the validatable gem (jnunemaker-validatable)
|
24
16
|
|
25
|
-
|
17
|
+
$ gem install mongo_mapper
|
26
18
|
|
27
|
-
|
19
|
+
== Problems or Questions?
|
28
20
|
|
21
|
+
Hit up the google group.
|
29
22
|
http://groups.google.com/group/mongomapper
|
30
23
|
|
31
|
-
|
32
|
-
|
33
|
-
* http://www.mongodb.org/
|
34
|
-
* http://github.com/mongodb/mongo-ruby-driver/
|
24
|
+
To see if the problem you are having is a verified issue, you can see the MM pivotal tracker project:
|
25
|
+
http://www.pivotaltracker.com/projects/33576
|
35
26
|
|
36
27
|
== Copyright
|
37
28
|
|
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ Jeweler::Tasks.new do |gem|
|
|
12
12
|
gem.authors = ["John Nunemaker"]
|
13
13
|
|
14
14
|
gem.add_dependency('activesupport', '>= 2.3')
|
15
|
-
gem.add_dependency('mongo', '0.18.
|
15
|
+
gem.add_dependency('mongo', '0.18.3')
|
16
16
|
gem.add_dependency('jnunemaker-validatable', '1.8.1')
|
17
17
|
|
18
18
|
gem.add_development_dependency('jnunemaker-matchy', '0.4.0')
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0
|
data/lib/mongo_mapper.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
1
3
|
# if Gem is defined i'll assume you are using rubygems and lock specific versions
|
2
4
|
# call me crazy but a plain old require will just get the latest version you have installed
|
3
5
|
# so i want to make sure that if you are using gems you do in fact have the correct versions
|
4
6
|
# if there is a better way to do this, please enlighten me!
|
5
7
|
if self.class.const_defined?(:Gem)
|
6
8
|
gem 'activesupport', '>= 2.3'
|
7
|
-
gem 'mongo', '0.18.
|
9
|
+
gem 'mongo', '0.18.3'
|
8
10
|
gem 'jnunemaker-validatable', '1.8.1'
|
9
11
|
end
|
10
12
|
|
@@ -15,112 +17,102 @@ require 'validatable'
|
|
15
17
|
module MongoMapper
|
16
18
|
# generic MM error
|
17
19
|
class MongoMapperError < StandardError; end
|
18
|
-
|
20
|
+
|
19
21
|
# raised when key expected to exist but not found
|
20
22
|
class KeyNotFound < MongoMapperError; end
|
21
|
-
|
23
|
+
|
22
24
|
# raised when document expected but not found
|
23
25
|
class DocumentNotFound < MongoMapperError; end
|
24
|
-
|
26
|
+
|
25
27
|
# raised when document not valid and using !
|
26
28
|
class DocumentNotValid < MongoMapperError
|
27
29
|
def initialize(document)
|
28
30
|
super("Validation failed: #{document.errors.full_messages.join(", ")}")
|
29
31
|
end
|
30
32
|
end
|
31
|
-
|
33
|
+
|
32
34
|
# @api public
|
33
35
|
def self.connection
|
34
36
|
@@connection ||= Mongo::Connection.new
|
35
37
|
end
|
36
|
-
|
38
|
+
|
37
39
|
# @api public
|
38
40
|
def self.connection=(new_connection)
|
39
41
|
@@connection = new_connection
|
40
42
|
end
|
41
|
-
|
43
|
+
|
42
44
|
# @api public
|
43
45
|
def self.logger
|
44
46
|
connection.logger
|
45
47
|
end
|
46
|
-
|
48
|
+
|
47
49
|
# @api public
|
48
50
|
def self.database=(name)
|
49
51
|
@@database = nil
|
50
52
|
@@database_name = name
|
51
53
|
end
|
52
|
-
|
54
|
+
|
53
55
|
# @api public
|
54
56
|
def self.database
|
55
57
|
if @@database_name.blank?
|
56
58
|
raise 'You forgot to set the default database name: MongoMapper.database = "foobar"'
|
57
59
|
end
|
58
|
-
|
60
|
+
|
59
61
|
@@database ||= MongoMapper.connection.db(@@database_name)
|
60
62
|
end
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
@@ensured_indexes ||= []
|
63
|
+
|
64
|
+
def self.config=(hash)
|
65
|
+
@@config = hash
|
65
66
|
end
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
@@
|
67
|
+
|
68
|
+
def self.config
|
69
|
+
raise 'Set config before connecting. MongoMapper.config = {...}' unless defined?(@@config)
|
70
|
+
@@config
|
70
71
|
end
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
|
73
|
+
def self.connect(environment, options={})
|
74
|
+
raise 'Set config before connecting. MongoMapper.config = {...}' if config.blank?
|
75
|
+
MongoMapper.connection = Mongo::Connection.new(config[environment]['host'], config[environment]['port'], options)
|
76
|
+
MongoMapper.database = config[environment]['database']
|
77
|
+
if config[environment]['username'].present? && config[environment]['password'].present?
|
78
|
+
MongoMapper.database.authenticate(config[environment]['username'], config[environment]['password'])
|
79
|
+
end
|
75
80
|
end
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
|
82
|
+
def self.setup(config, environment, options={})
|
83
|
+
using_passenger = options.delete(:passenger)
|
84
|
+
handle_passenger_forking if using_passenger
|
85
|
+
self.config = config
|
86
|
+
connect(environment, options)
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.handle_passenger_forking
|
90
|
+
if defined?(PhusionPassenger)
|
91
|
+
PhusionPassenger.on_event(:starting_worker_process) do |forked|
|
92
|
+
connection.connect_to_master if forked
|
93
|
+
end
|
82
94
|
end
|
83
95
|
end
|
84
|
-
|
96
|
+
|
85
97
|
# @api private
|
86
98
|
def self.use_time_zone?
|
87
99
|
Time.respond_to?(:zone) && Time.zone ? true : false
|
88
100
|
end
|
89
|
-
|
101
|
+
|
90
102
|
# @api private
|
91
103
|
def self.time_class
|
92
104
|
use_time_zone? ? Time.zone : Time
|
93
105
|
end
|
94
|
-
|
106
|
+
|
95
107
|
# @api private
|
96
108
|
def self.normalize_object_id(value)
|
97
109
|
value.is_a?(String) ? Mongo::ObjectID.from_string(value) : value
|
98
110
|
end
|
111
|
+
|
112
|
+
autoload :Query, 'mongo_mapper/query'
|
113
|
+
autoload :Document, 'mongo_mapper/document'
|
114
|
+
autoload :EmbeddedDocument, 'mongo_mapper/embedded_document'
|
99
115
|
end
|
100
116
|
|
101
117
|
require 'mongo_mapper/support'
|
102
|
-
require 'mongo_mapper/
|
103
|
-
require 'mongo_mapper/finder_options'
|
104
|
-
require 'mongo_mapper/dirty'
|
105
|
-
require 'mongo_mapper/dynamic_finder'
|
106
|
-
require 'mongo_mapper/key'
|
107
|
-
require 'mongo_mapper/pagination'
|
108
|
-
require 'mongo_mapper/serialization'
|
109
|
-
require 'mongo_mapper/validations'
|
110
|
-
require 'mongo_mapper/rails_compatibility/document'
|
111
|
-
require 'mongo_mapper/rails_compatibility/embedded_document'
|
112
|
-
require 'mongo_mapper/embedded_document'
|
113
|
-
require 'mongo_mapper/document'
|
114
|
-
require 'mongo_mapper/associations'
|
115
|
-
require 'mongo_mapper/associations/base'
|
116
|
-
require 'mongo_mapper/associations/proxy'
|
117
|
-
require 'mongo_mapper/associations/collection'
|
118
|
-
require 'mongo_mapper/associations/many_documents_proxy'
|
119
|
-
require 'mongo_mapper/associations/belongs_to_proxy'
|
120
|
-
require 'mongo_mapper/associations/belongs_to_polymorphic_proxy'
|
121
|
-
require 'mongo_mapper/associations/many_polymorphic_proxy'
|
122
|
-
require 'mongo_mapper/associations/many_embedded_proxy'
|
123
|
-
require 'mongo_mapper/associations/many_embedded_polymorphic_proxy'
|
124
|
-
require 'mongo_mapper/associations/many_documents_as_proxy'
|
125
|
-
require 'mongo_mapper/associations/one_proxy'
|
126
|
-
require 'mongo_mapper/associations/in_array_proxy'
|
118
|
+
require 'mongo_mapper/plugins'
|
@@ -1,66 +1,39 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
1
|
module MongoMapper
|
4
2
|
module Document
|
3
|
+
extend Support::DescendantAppends
|
4
|
+
|
5
5
|
def self.included(model)
|
6
6
|
model.class_eval do
|
7
|
-
include EmbeddedDocument
|
8
7
|
include InstanceMethods
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
extra_extensions.concat extensions
|
33
|
-
|
34
|
-
# Add the extension to existing descendants
|
35
|
-
descendants.each do |model|
|
36
|
-
extensions.each { |extension| model.extend(extension) }
|
37
|
-
end
|
8
|
+
extend Support::Find
|
9
|
+
extend ClassMethods
|
10
|
+
extend Plugins
|
11
|
+
|
12
|
+
plugin Plugins::Associations
|
13
|
+
plugin Plugins::Clone
|
14
|
+
plugin Plugins::Descendants
|
15
|
+
plugin Plugins::Equality
|
16
|
+
plugin Plugins::Inspect
|
17
|
+
plugin Plugins::Keys
|
18
|
+
plugin Plugins::Dirty # for now dirty needs to be after keys
|
19
|
+
plugin Plugins::Logger
|
20
|
+
plugin Plugins::Pagination
|
21
|
+
plugin Plugins::Protected
|
22
|
+
plugin Plugins::Rails
|
23
|
+
plugin Plugins::Serialization
|
24
|
+
plugin Plugins::Validations
|
25
|
+
plugin Plugins::Callbacks # for now callbacks needs to be after validations
|
26
|
+
|
27
|
+
extend Plugins::Validations::DocumentMacros
|
28
|
+
end
|
29
|
+
|
30
|
+
super
|
38
31
|
end
|
39
32
|
|
40
|
-
# @api private
|
41
|
-
def self.extra_extensions
|
42
|
-
@extra_extensions ||= []
|
43
|
-
end
|
44
|
-
|
45
|
-
def self.append_inclusions(*inclusions)
|
46
|
-
extra_inclusions.concat inclusions
|
47
|
-
|
48
|
-
# Add the inclusion to existing descendants
|
49
|
-
descendants.each do |model|
|
50
|
-
inclusions.each { |inclusion| model.send :include, inclusion }
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
# @api private
|
55
|
-
def self.extra_inclusions
|
56
|
-
@extra_inclusions ||= []
|
57
|
-
end
|
58
|
-
|
59
33
|
module ClassMethods
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
key
|
34
|
+
def inherited(subclass)
|
35
|
+
subclass.set_collection_name(collection_name)
|
36
|
+
super
|
64
37
|
end
|
65
38
|
|
66
39
|
def ensure_index(name_or_array, options={})
|
@@ -70,43 +43,50 @@ module MongoMapper
|
|
70
43
|
name_or_array
|
71
44
|
end
|
72
45
|
|
73
|
-
|
46
|
+
collection.create_index(keys_to_index, options[:unique])
|
47
|
+
end
|
48
|
+
|
49
|
+
def find(*args)
|
50
|
+
assert_no_first_last_or_all(args)
|
51
|
+
options = args.extract_options!
|
52
|
+
return nil if args.size == 0
|
53
|
+
|
54
|
+
if args.first.is_a?(Array) || args.size > 1
|
55
|
+
find_some(args, options)
|
56
|
+
else
|
57
|
+
find_one(options.merge({:_id => args[0]}))
|
58
|
+
end
|
74
59
|
end
|
75
60
|
|
76
61
|
def find!(*args)
|
62
|
+
assert_no_first_last_or_all(args)
|
77
63
|
options = args.extract_options!
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
case args.size
|
85
|
-
when 0
|
86
|
-
raise DocumentNotFound, "Couldn't find without an ID"
|
87
|
-
when 1
|
88
|
-
find_one!(options.merge({:_id => args[0]}))
|
89
|
-
else
|
90
|
-
find_some(args, options)
|
91
|
-
end
|
64
|
+
raise DocumentNotFound, "Couldn't find without an ID" if args.size == 0
|
65
|
+
|
66
|
+
if args.first.is_a?(Array) || args.size > 1
|
67
|
+
find_some!(args, options)
|
68
|
+
else
|
69
|
+
find_one(options.merge({:_id => args[0]})) || raise(DocumentNotFound, "Document match #{options.inspect} does not exist in #{collection.name} collection")
|
92
70
|
end
|
93
71
|
end
|
94
|
-
|
95
|
-
def
|
96
|
-
|
97
|
-
|
98
|
-
|
72
|
+
|
73
|
+
def find_each(options={})
|
74
|
+
criteria, options = to_query(options)
|
75
|
+
collection.find(criteria, options).each do |doc|
|
76
|
+
yield load(doc)
|
77
|
+
end
|
99
78
|
end
|
100
79
|
|
101
|
-
def
|
102
|
-
|
103
|
-
|
104
|
-
total_entries = count(options)
|
105
|
-
pagination = Pagination::PaginationProxy.new(total_entries, page, per_page)
|
80
|
+
def find_by_id(id)
|
81
|
+
find(id)
|
82
|
+
end
|
106
83
|
|
107
|
-
|
108
|
-
|
109
|
-
|
84
|
+
def first_or_create(arg)
|
85
|
+
first(arg) || create(arg)
|
86
|
+
end
|
87
|
+
|
88
|
+
def first_or_new(arg)
|
89
|
+
first(arg) || new(arg)
|
110
90
|
end
|
111
91
|
|
112
92
|
def first(options={})
|
@@ -119,11 +99,7 @@ module MongoMapper
|
|
119
99
|
end
|
120
100
|
|
121
101
|
def all(options={})
|
122
|
-
|
123
|
-
end
|
124
|
-
|
125
|
-
def find_by_id(id)
|
126
|
-
find(id)
|
102
|
+
find_many(options)
|
127
103
|
end
|
128
104
|
|
129
105
|
def count(options={})
|
@@ -160,63 +136,57 @@ module MongoMapper
|
|
160
136
|
end
|
161
137
|
|
162
138
|
def destroy(*ids)
|
163
|
-
find_some(ids.flatten).each(&:destroy)
|
139
|
+
find_some!(ids.flatten).each(&:destroy)
|
164
140
|
end
|
165
141
|
|
166
142
|
def destroy_all(options={})
|
167
|
-
|
143
|
+
find_each(options) { |document| document.destroy }
|
168
144
|
end
|
169
|
-
|
145
|
+
|
170
146
|
def increment(*args)
|
171
147
|
modifier_update('$inc', args)
|
172
148
|
end
|
173
|
-
|
149
|
+
|
174
150
|
def decrement(*args)
|
175
151
|
criteria, keys = criteria_and_keys_from_args(args)
|
176
152
|
values, to_decrement = keys.values, {}
|
177
153
|
keys.keys.each_with_index { |k, i| to_decrement[k] = -values[i].abs }
|
178
154
|
collection.update(criteria, {'$inc' => to_decrement}, :multi => true)
|
179
155
|
end
|
180
|
-
|
156
|
+
|
181
157
|
def set(*args)
|
182
158
|
modifier_update('$set', args)
|
183
159
|
end
|
184
|
-
|
160
|
+
|
185
161
|
def push(*args)
|
186
162
|
modifier_update('$push', args)
|
187
163
|
end
|
188
|
-
|
164
|
+
|
189
165
|
def push_all(*args)
|
190
166
|
modifier_update('$pushAll', args)
|
191
167
|
end
|
192
|
-
|
168
|
+
|
193
169
|
def push_uniq(*args)
|
194
170
|
criteria, keys = criteria_and_keys_from_args(args)
|
195
171
|
keys.each { |key, value | criteria[key] = {'$ne' => value} }
|
196
172
|
collection.update(criteria, {'$push' => keys}, :multi => true)
|
197
173
|
end
|
198
|
-
|
174
|
+
|
199
175
|
def pull(*args)
|
200
176
|
modifier_update('$pull', args)
|
201
177
|
end
|
202
|
-
|
178
|
+
|
203
179
|
def pull_all(*args)
|
204
180
|
modifier_update('$pullAll', args)
|
205
181
|
end
|
206
|
-
|
207
|
-
def
|
208
|
-
|
209
|
-
modifiers = {modifier => keys}
|
210
|
-
collection.update(criteria, modifiers, :multi => true)
|
182
|
+
|
183
|
+
def pop(*args)
|
184
|
+
modifier_update('$pop', args)
|
211
185
|
end
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
keys = args.pop
|
216
|
-
criteria = args[0].is_a?(Hash) ? args[0] : {:id => args}
|
217
|
-
[to_criteria(criteria), keys]
|
186
|
+
|
187
|
+
def embeddable?
|
188
|
+
false
|
218
189
|
end
|
219
|
-
private :criteria_and_keys_from_args
|
220
190
|
|
221
191
|
def connection(mongo_connection=nil)
|
222
192
|
if mongo_connection.nil?
|
@@ -269,39 +239,51 @@ module MongoMapper
|
|
269
239
|
end
|
270
240
|
|
271
241
|
def single_collection_inherited?
|
272
|
-
keys.
|
242
|
+
keys.key?(:_type) && single_collection_inherited_superclass?
|
273
243
|
end
|
274
244
|
|
275
245
|
def single_collection_inherited_superclass?
|
276
|
-
superclass.respond_to?(:keys) && superclass.keys.
|
246
|
+
superclass.respond_to?(:keys) && superclass.keys.key?(:_type)
|
277
247
|
end
|
278
248
|
|
279
249
|
private
|
280
|
-
def create_indexes_for(key)
|
281
|
-
ensure_index key.name if key.options[:index]
|
282
|
-
end
|
283
|
-
|
284
250
|
def initialize_each(*docs)
|
285
251
|
instances = []
|
286
252
|
docs = [{}] if docs.blank?
|
287
253
|
docs.flatten.each do |attrs|
|
288
|
-
doc =
|
254
|
+
doc = new(attrs)
|
289
255
|
yield(doc)
|
290
256
|
instances << doc
|
291
257
|
end
|
292
258
|
instances.size == 1 ? instances[0] : instances
|
293
259
|
end
|
294
260
|
|
295
|
-
def
|
296
|
-
criteria,
|
297
|
-
|
298
|
-
|
261
|
+
def modifier_update(modifier, args)
|
262
|
+
criteria, keys = criteria_and_keys_from_args(args)
|
263
|
+
modifiers = {modifier => keys}
|
264
|
+
collection.update(criteria, modifiers, :multi => true)
|
265
|
+
end
|
266
|
+
|
267
|
+
def criteria_and_keys_from_args(args)
|
268
|
+
keys = args.pop
|
269
|
+
criteria = args[0].is_a?(Hash) ? args[0] : {:id => args}
|
270
|
+
[to_criteria(criteria), keys]
|
271
|
+
end
|
272
|
+
|
273
|
+
def assert_no_first_last_or_all(args)
|
274
|
+
if args[0] == :first || args[0] == :last || args[0] == :all
|
275
|
+
raise ArgumentError, "#{self}.find(:#{args}) is no longer supported, use #{self}.#{args} instead."
|
299
276
|
end
|
300
277
|
end
|
301
278
|
|
302
279
|
def find_some(ids, options={})
|
303
|
-
ids
|
304
|
-
|
280
|
+
ids = ids.flatten.compact.uniq
|
281
|
+
find_many(options.merge(:_id => ids)).compact
|
282
|
+
end
|
283
|
+
|
284
|
+
def find_some!(ids, options={})
|
285
|
+
ids = ids.flatten.compact.uniq
|
286
|
+
documents = find_some(ids, options)
|
305
287
|
|
306
288
|
if ids.size == documents.size
|
307
289
|
documents
|
@@ -310,15 +292,20 @@ module MongoMapper
|
|
310
292
|
end
|
311
293
|
end
|
312
294
|
|
295
|
+
# All query methods that load documents pass through find_one or find_many
|
313
296
|
def find_one(options={})
|
314
|
-
criteria, options =
|
297
|
+
criteria, options = to_query(options)
|
315
298
|
if doc = collection.find_one(criteria, options)
|
316
|
-
|
299
|
+
load(doc)
|
317
300
|
end
|
318
301
|
end
|
319
302
|
|
320
|
-
|
321
|
-
|
303
|
+
# All query methods that load documents pass through find_one or find_many
|
304
|
+
def find_many(options)
|
305
|
+
criteria, options = to_query(options)
|
306
|
+
collection.find(criteria, options).to_a.map do |doc|
|
307
|
+
load(doc)
|
308
|
+
end
|
322
309
|
end
|
323
310
|
|
324
311
|
def invert_order_clause(order)
|
@@ -354,11 +341,11 @@ module MongoMapper
|
|
354
341
|
end
|
355
342
|
|
356
343
|
def to_criteria(options={})
|
357
|
-
|
344
|
+
Query.new(self, options).criteria
|
358
345
|
end
|
359
346
|
|
360
|
-
def
|
361
|
-
|
347
|
+
def to_query(options={})
|
348
|
+
Query.new(self, options).to_a
|
362
349
|
end
|
363
350
|
end
|
364
351
|
|
@@ -366,42 +353,38 @@ module MongoMapper
|
|
366
353
|
def collection
|
367
354
|
self.class.collection
|
368
355
|
end
|
369
|
-
|
356
|
+
|
370
357
|
def database
|
371
358
|
self.class.database
|
372
359
|
end
|
373
360
|
|
374
|
-
def new?
|
375
|
-
read_attribute('_id').blank? || using_custom_id?
|
376
|
-
end
|
377
|
-
|
378
361
|
def save(options={})
|
379
|
-
|
380
|
-
ActiveSupport::Deprecation.warn "save with true/false is deprecated. You should now use :validate => true/false."
|
381
|
-
options = {:validate => false}
|
382
|
-
end
|
362
|
+
options.assert_valid_keys(:validate, :safe)
|
383
363
|
options.reverse_merge!(:validate => true)
|
384
|
-
|
385
|
-
!perform_validations || valid? ? create_or_update(options) : false
|
364
|
+
!options[:validate] || valid? ? create_or_update(options) : false
|
386
365
|
end
|
387
366
|
|
388
|
-
def save!
|
389
|
-
|
367
|
+
def save!(options={})
|
368
|
+
options.assert_valid_keys(:safe)
|
369
|
+
save(options) || raise(DocumentNotValid.new(self))
|
390
370
|
end
|
391
371
|
|
392
372
|
def destroy
|
393
|
-
|
373
|
+
delete
|
394
374
|
end
|
395
|
-
|
375
|
+
|
396
376
|
def delete
|
397
377
|
self.class.delete(id) unless new?
|
398
378
|
end
|
399
379
|
|
400
380
|
def reload
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
381
|
+
if attrs = collection.find_one({:_id => _id})
|
382
|
+
self.class.associations.each { |name, assoc| send(name).reset if respond_to?(name) }
|
383
|
+
self.attributes = attrs
|
384
|
+
self
|
385
|
+
else
|
386
|
+
raise DocumentNotFound, "Document match #{_id.inspect} does not exist in #{collection.name} collection"
|
387
|
+
end
|
405
388
|
end
|
406
389
|
|
407
390
|
private
|
@@ -411,34 +394,23 @@ module MongoMapper
|
|
411
394
|
end
|
412
395
|
|
413
396
|
def create(options={})
|
414
|
-
assign_id
|
415
397
|
save_to_collection(options)
|
416
398
|
end
|
417
399
|
|
418
|
-
def assign_id
|
419
|
-
if read_attribute(:_id).blank?
|
420
|
-
write_attribute :_id, Mongo::ObjectID.new
|
421
|
-
end
|
422
|
-
end
|
423
|
-
|
424
400
|
def update(options={})
|
425
401
|
save_to_collection(options)
|
426
402
|
end
|
427
403
|
|
428
404
|
def save_to_collection(options={})
|
429
|
-
|
430
|
-
|
405
|
+
safe = options[:safe] || false
|
406
|
+
@new = false
|
431
407
|
collection.save(to_mongo, :safe => safe)
|
432
408
|
end
|
433
409
|
|
434
410
|
def update_timestamps
|
435
411
|
now = Time.now.utc
|
436
|
-
|
437
|
-
|
438
|
-
end
|
439
|
-
|
440
|
-
def clear_custom_id_flag
|
441
|
-
@using_custom_id = nil
|
412
|
+
self[:created_at] = now if new? && !created_at?
|
413
|
+
self[:updated_at] = now
|
442
414
|
end
|
443
415
|
end
|
444
416
|
end # Document
|