mongoo 0.1.2
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/.document +5 -0
- data/.rvmrc +1 -0
- data/Gemfile +20 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/mongoo.rb +49 -0
- data/lib/mongoo/async.rb +41 -0
- data/lib/mongoo/attribute_proxy.rb +47 -0
- data/lib/mongoo/attribute_sanitizer.rb +41 -0
- data/lib/mongoo/base.rb +209 -0
- data/lib/mongoo/changelog.rb +36 -0
- data/lib/mongoo/cursor.rb +55 -0
- data/lib/mongoo/hash_ext.rb +21 -0
- data/lib/mongoo/modifiers.rb +150 -0
- data/lib/mongoo/mongohash.rb +79 -0
- data/lib/mongoo/persistence.rb +256 -0
- data/mongoo.gemspec +91 -0
- data/test/helper.rb +62 -0
- data/test/test_activemodel.rb +14 -0
- data/test/test_mongohash.rb +36 -0
- data/test/test_mongoo.rb +276 -0
- metadata +236 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
module Mongoo
|
2
|
+
module Changelog
|
3
|
+
|
4
|
+
def changelog
|
5
|
+
persisted_mongohash_kv = (self.persisted_mongohash || Mongoo::Mongohash.new).to_key_value
|
6
|
+
curr_mongohash_kv = self.mongohash.to_key_value
|
7
|
+
|
8
|
+
log = []
|
9
|
+
|
10
|
+
persisted_mongohash_kv.each do |k,v|
|
11
|
+
unless curr_mongohash_kv.has_key?(k)
|
12
|
+
found = nil
|
13
|
+
parts = k.split(".")
|
14
|
+
while parts.pop
|
15
|
+
if !self.mongohash.dot_get(parts.join("."))
|
16
|
+
found = [:unset, parts.join("."), 1]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
found ||= [:unset, k, 1]
|
20
|
+
log << found
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
curr_mongohash_kv.each do |k,v|
|
25
|
+
if v != persisted_mongohash_kv[k]
|
26
|
+
unless log.include?([:set, k, v])
|
27
|
+
log << [:set, k, v]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
log.uniq
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Mongoo
|
2
|
+
class Cursor
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_accessor :mongo_cursor
|
6
|
+
|
7
|
+
def initialize(obj_class, mongo_cursor)
|
8
|
+
@obj_class = obj_class
|
9
|
+
@mongo_cursor = mongo_cursor
|
10
|
+
end
|
11
|
+
|
12
|
+
def next_document
|
13
|
+
if doc = @mongo_cursor.next_document
|
14
|
+
@obj_class.new(doc, true)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
alias :next :next_document
|
19
|
+
|
20
|
+
def each
|
21
|
+
@mongo_cursor.each do |doc|
|
22
|
+
yield(@obj_class.new(doc, true))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def sort(key_or_list, direction=nil)
|
27
|
+
@mongo_cursor.sort(key_or_list, direction)
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def limit(number_to_return=nil)
|
32
|
+
@mongo_cursor.limit(number_to_return)
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def skip(number_to_return=nil)
|
37
|
+
@mongo_cursor.skip(number_to_return)
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def batch_size(size=0)
|
42
|
+
@mongo_cursor.batch_size(size)
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def method_missing(name, *args)
|
47
|
+
if @mongo_cursor.respond_to?(name)
|
48
|
+
@mongo_cursor.send name, *args
|
49
|
+
else
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Mongoo
|
2
|
+
module HashExt
|
3
|
+
def deep_stringify_keys
|
4
|
+
Marshal.load(Marshal.dump(self)).deep_stringify_keys!
|
5
|
+
end
|
6
|
+
|
7
|
+
def deep_stringify_keys!
|
8
|
+
keys.each do |key|
|
9
|
+
self[key.to_s] = delete(key)
|
10
|
+
if self[key.to_s].is_a?(Hash)
|
11
|
+
self[key.to_s].stringify_keys!
|
12
|
+
end
|
13
|
+
end
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Hash
|
20
|
+
include Mongoo::HashExt
|
21
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
module Mongoo
|
2
|
+
class ModifierUpdateError < Exception; end
|
3
|
+
class UnknownAttributeError < Exception; end
|
4
|
+
|
5
|
+
class ModifierBuilder
|
6
|
+
def initialize(opts, doc)
|
7
|
+
@opts = opts
|
8
|
+
@doc = doc
|
9
|
+
@queue = {}
|
10
|
+
@key_prefix = opts[:key_prefix] || ""
|
11
|
+
end
|
12
|
+
|
13
|
+
def ensure_valid_field!(k)
|
14
|
+
unless @doc.known_attribute?("#{@key_prefix}#{k}")
|
15
|
+
raise UnknownAttributeError, "#{@key_prefix}#{k}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def sanitize_value(k,v)
|
20
|
+
k = "#{@key_prefix}#{k}"
|
21
|
+
field_type = @doc.class.attributes[k][:type]
|
22
|
+
Mongoo::AttributeSanitizer.sanitize(field_type, v)
|
23
|
+
end
|
24
|
+
|
25
|
+
def inc(k, v=1)
|
26
|
+
ensure_valid_field!(k)
|
27
|
+
v = sanitize_value(k,v)
|
28
|
+
@queue["$inc"] ||= {}
|
29
|
+
@queue["$inc"]["#{@key_prefix}#{k}"] = v
|
30
|
+
end
|
31
|
+
|
32
|
+
def set(k,v)
|
33
|
+
ensure_valid_field!(k)
|
34
|
+
v = sanitize_value(k,v)
|
35
|
+
@queue["$set"] ||= {}
|
36
|
+
@queue["$set"]["#{@key_prefix}#{k}"] = v
|
37
|
+
end
|
38
|
+
|
39
|
+
def unset(k)
|
40
|
+
ensure_valid_field!(k)
|
41
|
+
@queue["$unset"] ||= {}
|
42
|
+
@queue["$unset"]["#{@key_prefix}#{k}"] = 1
|
43
|
+
end
|
44
|
+
|
45
|
+
def push(k, v)
|
46
|
+
ensure_valid_field!(k)
|
47
|
+
@queue["$push"] ||= {}
|
48
|
+
@queue["$push"]["#{@key_prefix}#{k}"] = v
|
49
|
+
end
|
50
|
+
|
51
|
+
def push_all(k, v)
|
52
|
+
ensure_valid_field!(k)
|
53
|
+
@queue["$pushAll"] ||= {}
|
54
|
+
@queue["$pushAll"]["#{@key_prefix}#{k}"] = v
|
55
|
+
end
|
56
|
+
|
57
|
+
def add_to_set(k,v)
|
58
|
+
ensure_valid_field!(k)
|
59
|
+
@queue["$addToSet"] ||= {}
|
60
|
+
@queue["$addToSet"]["#{@key_prefix}#{k}"] = v
|
61
|
+
end
|
62
|
+
|
63
|
+
def pop(k)
|
64
|
+
ensure_valid_field!(k)
|
65
|
+
@queue["$pop"] ||= {}
|
66
|
+
@queue["$pop"]["#{@key_prefix}#{k}"] = 1
|
67
|
+
end
|
68
|
+
|
69
|
+
def pull(k, v)
|
70
|
+
ensure_valid_field!(k)
|
71
|
+
@queue["$pull"] ||= {}
|
72
|
+
@queue["$pull"]["#{@key_prefix}#{k}"] = v
|
73
|
+
end
|
74
|
+
|
75
|
+
def pull_all(k, v)
|
76
|
+
ensure_valid_field!(k)
|
77
|
+
@queue["$pullAll"] ||= {}
|
78
|
+
@queue["$pullAll"]["#{@key_prefix}#{k}"] = v
|
79
|
+
end
|
80
|
+
|
81
|
+
def run!
|
82
|
+
ret = @doc.collection.update({"_id" => @doc.id}, @queue, @opts)
|
83
|
+
if !ret.is_a?(Hash) || (ret["err"] == nil && ret["n"] == 1)
|
84
|
+
@queue.each do |op, op_queue|
|
85
|
+
op_queue.each do |k, v|
|
86
|
+
case op
|
87
|
+
when "$inc" then
|
88
|
+
new_val = @doc.persisted_mongohash.dot_get(k).to_i + v
|
89
|
+
@doc.mongohash.dot_set( k, new_val )
|
90
|
+
@doc.persisted_mongohash.dot_set( k, new_val )
|
91
|
+
when "$set" then
|
92
|
+
@doc.mongohash.dot_set( k, v )
|
93
|
+
@doc.persisted_mongohash.dot_set( k, v )
|
94
|
+
when "$unset" then
|
95
|
+
@doc.mongohash.dot_delete( k )
|
96
|
+
@doc.persisted_mongohash.dot_delete( k )
|
97
|
+
when "$push" then
|
98
|
+
new_val = (@doc.persisted_mongohash.dot_get(k) || []) + [v]
|
99
|
+
@doc.mongohash.dot_set( k, new_val )
|
100
|
+
@doc.persisted_mongohash.dot_set( k, new_val )
|
101
|
+
when "$pushAll" then
|
102
|
+
new_val = (@doc.persisted_mongohash.dot_get(k) || []) + v
|
103
|
+
@doc.mongohash.dot_set( k, new_val )
|
104
|
+
@doc.persisted_mongohash.dot_set( k, new_val )
|
105
|
+
when "$addToSet" then
|
106
|
+
new_val = (@doc.persisted_mongohash.dot_get(k) || [])
|
107
|
+
new_val << v unless new_val.include?(v)
|
108
|
+
@doc.mongohash.dot_set(k, new_val)
|
109
|
+
@doc.persisted_mongohash.dot_set(k, new_val)
|
110
|
+
when "$pop" then
|
111
|
+
new_val = (@doc.persisted_mongohash.dot_get(k) || [])
|
112
|
+
new_val.pop
|
113
|
+
@doc.mongohash.dot_set(k, new_val)
|
114
|
+
@doc.persisted_mongohash.dot_set(k, new_val)
|
115
|
+
when "$pull" then
|
116
|
+
new_val = (@doc.persisted_mongohash.dot_get(k) || [])
|
117
|
+
new_val.delete(v)
|
118
|
+
@doc.mongohash.dot_set(k, new_val)
|
119
|
+
@doc.persisted_mongohash.dot_set(k, new_val)
|
120
|
+
when "$pullAll" then
|
121
|
+
new_val = (@doc.persisted_mongohash.dot_get(k) || [])
|
122
|
+
v.each do |val|
|
123
|
+
new_val.delete(val)
|
124
|
+
end
|
125
|
+
@doc.mongohash.dot_set(k, new_val)
|
126
|
+
@doc.persisted_mongohash.dot_set(k, new_val)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
true
|
131
|
+
else
|
132
|
+
raise ModifierUpdateError, ret.inspect
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
module Modifiers
|
138
|
+
|
139
|
+
def mod(opts={}, &block)
|
140
|
+
builder = ModifierBuilder.new(opts, self)
|
141
|
+
block.call(builder)
|
142
|
+
builder.run!
|
143
|
+
end
|
144
|
+
|
145
|
+
def mod!(opts={}, &block)
|
146
|
+
mod(opts.merge(:safe => true), &block)
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Mongoo
|
2
|
+
class Mongohash
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegators :@raw_hash, :==, :[], :[], :[]=, :clear, :default, :default=, :default_proc, :delete, :delete_if,
|
6
|
+
:each, :each_key, :each_pair, :each_value, :empty?, :fetch, :has_key?, :has_value?, :include?,
|
7
|
+
:index, :indexes, :indices, :initialize_copy, :inspect, :invert, :key?, :keys, :length, :member?,
|
8
|
+
:merge, :merge!, :pretty_print, :pretty_print_cycle, :rehash, :reject, :reject!, :replace, :select,
|
9
|
+
:shift, :size, :sort, :store, :to_a, :to_hash, :to_s, :update, :value?, :values, :values_at
|
10
|
+
|
11
|
+
attr_reader :raw_hash
|
12
|
+
|
13
|
+
def initialize(hash={})
|
14
|
+
hash = hash.to_hash unless hash.class.to_s == "Hash"
|
15
|
+
@raw_hash = hash.deep_stringify_keys
|
16
|
+
end
|
17
|
+
|
18
|
+
def deep_clone
|
19
|
+
Mongoo::Mongohash.new(Marshal.load(Marshal.dump self.raw_hash))
|
20
|
+
end
|
21
|
+
|
22
|
+
def dot_set(k,v)
|
23
|
+
parts = k.to_s.split(".")
|
24
|
+
curr_val = to_hash
|
25
|
+
while !parts.empty?
|
26
|
+
part = parts.shift
|
27
|
+
if parts.empty?
|
28
|
+
curr_val[part] = v
|
29
|
+
else
|
30
|
+
curr_val[part] ||= {}
|
31
|
+
curr_val = curr_val[part]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
def dot_get(k)
|
38
|
+
parts = k.to_s.split(".")
|
39
|
+
curr_val = to_hash
|
40
|
+
while !parts.empty?
|
41
|
+
part = parts.shift
|
42
|
+
curr_val = curr_val[part]
|
43
|
+
return curr_val unless curr_val.is_a?(Hash)
|
44
|
+
end
|
45
|
+
curr_val
|
46
|
+
end
|
47
|
+
|
48
|
+
def dot_delete(k)
|
49
|
+
parts = k.to_s.split(".")
|
50
|
+
curr_val = to_hash
|
51
|
+
while !parts.empty?
|
52
|
+
part = parts.shift
|
53
|
+
if parts.empty?
|
54
|
+
curr_val.delete(part)
|
55
|
+
return true
|
56
|
+
else
|
57
|
+
curr_val = curr_val[part]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
63
|
+
def dot_list(curr_hash=self.to_hash, path=[])
|
64
|
+
list = []
|
65
|
+
curr_hash.each do |k,v|
|
66
|
+
if v.is_a?(Hash)
|
67
|
+
list.concat dot_list(v, (path + [k]))
|
68
|
+
else
|
69
|
+
list << (path + [k]).join(".")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
list
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_key_value
|
76
|
+
kv = {}; dot_list.collect { |k| kv[k] = dot_get(k) }; kv
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,256 @@
|
|
1
|
+
module Mongoo
|
2
|
+
class AlreadyInsertedError < Exception; end
|
3
|
+
class NotInsertedError < Exception; end
|
4
|
+
class InsertError < Exception; end
|
5
|
+
class StaleUpdateError < Exception; end
|
6
|
+
class UpdateError < Exception; end
|
7
|
+
class RemoveError < Exception; end
|
8
|
+
class NotValidError < Exception; end
|
9
|
+
|
10
|
+
module Persistence
|
11
|
+
|
12
|
+
def self.included(base)
|
13
|
+
base.extend(ClassMethods)
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def collection_name
|
18
|
+
@collection_name ||= self.model_name.tableize
|
19
|
+
end
|
20
|
+
|
21
|
+
def collection
|
22
|
+
@collection ||= db.collection(collection_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def conn
|
26
|
+
@conn ||= begin
|
27
|
+
if Mongoo.config == config
|
28
|
+
Mongoo.conn
|
29
|
+
else
|
30
|
+
Mongo::Connection.new(config[:host], config[:port], config[:opts])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def db
|
36
|
+
@db ||= begin
|
37
|
+
if Mongoo.config == config
|
38
|
+
Mongoo.db
|
39
|
+
else
|
40
|
+
conn.db(config[:db])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def config=(cfg)
|
46
|
+
@config = cfg
|
47
|
+
end
|
48
|
+
|
49
|
+
def config
|
50
|
+
@config || Mongoo.config
|
51
|
+
end
|
52
|
+
|
53
|
+
def db=(db)
|
54
|
+
@db = db
|
55
|
+
end
|
56
|
+
|
57
|
+
def find(query={}, opts={})
|
58
|
+
Mongoo::Cursor.new(self, collection.find(query, opts))
|
59
|
+
end
|
60
|
+
|
61
|
+
def find_one(query={}, opts={})
|
62
|
+
return nil unless doc = collection.find_one(query, opts)
|
63
|
+
new(doc, true)
|
64
|
+
end
|
65
|
+
|
66
|
+
def all
|
67
|
+
find
|
68
|
+
end
|
69
|
+
|
70
|
+
def each
|
71
|
+
find.each { |found| yield(found) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def first
|
75
|
+
find.limit(1).next_document
|
76
|
+
end
|
77
|
+
|
78
|
+
def empty?
|
79
|
+
count == 0
|
80
|
+
end
|
81
|
+
|
82
|
+
def count
|
83
|
+
collection.count
|
84
|
+
end
|
85
|
+
|
86
|
+
def drop
|
87
|
+
collection.drop
|
88
|
+
end
|
89
|
+
|
90
|
+
def index_meta
|
91
|
+
Mongoo::INDEX_META[self.collection_name] ||= {}
|
92
|
+
end
|
93
|
+
|
94
|
+
def index(spec, opts={})
|
95
|
+
self.index_meta[spec] = opts
|
96
|
+
end
|
97
|
+
|
98
|
+
def create_indexes
|
99
|
+
self.index_meta.each do |spec, opts|
|
100
|
+
opts[:background] = true if !opts.has_key?(:background)
|
101
|
+
collection.create_index(spec, opts)
|
102
|
+
end; true
|
103
|
+
end
|
104
|
+
end # ClassMethods
|
105
|
+
|
106
|
+
def to_param
|
107
|
+
persisted? ? get("_id").to_s : nil
|
108
|
+
end
|
109
|
+
|
110
|
+
def to_key
|
111
|
+
get("_id")
|
112
|
+
end
|
113
|
+
|
114
|
+
def to_model
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
def persisted?
|
119
|
+
@persisted == true
|
120
|
+
#!get("_id").nil?
|
121
|
+
end
|
122
|
+
|
123
|
+
def collection
|
124
|
+
self.class.collection
|
125
|
+
end
|
126
|
+
|
127
|
+
def insert(opts={})
|
128
|
+
_run_insert_callbacks do
|
129
|
+
if persisted?
|
130
|
+
raise AlreadyInsertedError, "document has already been inserted"
|
131
|
+
end
|
132
|
+
unless valid?
|
133
|
+
if opts[:safe] == true
|
134
|
+
raise Mongoo::NotValidError, "document contains errors"
|
135
|
+
else
|
136
|
+
return false
|
137
|
+
end
|
138
|
+
end
|
139
|
+
ret = self.collection.insert(mongohash.deep_clone, opts)
|
140
|
+
unless ret.is_a?(BSON::ObjectId)
|
141
|
+
raise InsertError, "not an object: #{ret.inspect}"
|
142
|
+
end
|
143
|
+
set("_id", ret)
|
144
|
+
@persisted = true
|
145
|
+
set_persisted_mongohash(mongohash.deep_clone)
|
146
|
+
ret
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def insert!(opts={})
|
151
|
+
insert(opts.merge(:safe => true))
|
152
|
+
end
|
153
|
+
|
154
|
+
def update(opts={})
|
155
|
+
_run_update_callbacks do
|
156
|
+
unless persisted?
|
157
|
+
raise NotInsertedError, "document must be inserted before being updated"
|
158
|
+
end
|
159
|
+
unless valid?
|
160
|
+
if opts[:safe] == true
|
161
|
+
raise Mongoo::NotValidError, "document contains errors"
|
162
|
+
else
|
163
|
+
return false
|
164
|
+
end
|
165
|
+
end
|
166
|
+
opts[:only_if_current] = true unless opts.has_key?(:only_if_current)
|
167
|
+
opts[:safe] = true if !opts.has_key?(:safe) && opts[:only_if_current] == true
|
168
|
+
update_hash = build_update_hash(self.changelog)
|
169
|
+
return true if update_hash.empty?
|
170
|
+
update_query_hash = build_update_query_hash(persisted_mongohash.to_key_value, self.changelog)
|
171
|
+
if Mongoo.verbose_debug
|
172
|
+
puts "\n* update_query_hash: #{update_query_hash.merge({"_id" => get("_id")}).inspect}\n update_hash: #{update_hash.inspect}\n opts: #{opts.inspect}\n"
|
173
|
+
end
|
174
|
+
ret = self.collection.update(update_query_hash.merge({"_id" => get("_id")}), update_hash, opts)
|
175
|
+
if !ret.is_a?(Hash) || (ret["updatedExisting"] && ret["n"] == 1)
|
176
|
+
set_persisted_mongohash(mongohash.deep_clone)
|
177
|
+
@persisted = true
|
178
|
+
true
|
179
|
+
else
|
180
|
+
if opts[:only_if_current]
|
181
|
+
raise StaleUpdateError, ret.inspect
|
182
|
+
else
|
183
|
+
raise UpdateError, ret.inspect
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def update!(opts={})
|
190
|
+
update(opts.merge(:safe => true))
|
191
|
+
end
|
192
|
+
|
193
|
+
def destroyed?
|
194
|
+
@destroyed != nil
|
195
|
+
end
|
196
|
+
|
197
|
+
def new_record?
|
198
|
+
!persisted?
|
199
|
+
end
|
200
|
+
|
201
|
+
def remove(opts={})
|
202
|
+
_run_remove_callbacks do
|
203
|
+
unless persisted?
|
204
|
+
raise NotInsertedError, "document must be inserted before it can be removed"
|
205
|
+
end
|
206
|
+
ret = self.collection.remove({"_id" => get("_id")}, opts)
|
207
|
+
if !ret.is_a?(Hash) || (ret["err"] == nil && ret["n"] == 1)
|
208
|
+
@destroyed = true
|
209
|
+
@persisted = false
|
210
|
+
true
|
211
|
+
else
|
212
|
+
raise RemoveError, ret.inspect
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def remove!(opts={})
|
218
|
+
remove(opts.merge(:safe => true))
|
219
|
+
end
|
220
|
+
|
221
|
+
def reload
|
222
|
+
init_from_hash(collection.find_one(get("_id")))
|
223
|
+
@persisted = true
|
224
|
+
set_persisted_mongohash(mongohash.deep_clone)
|
225
|
+
true
|
226
|
+
end
|
227
|
+
|
228
|
+
def build_update_hash(changelog)
|
229
|
+
update_hash = {}
|
230
|
+
changelog.each do |op, k, v|
|
231
|
+
update_hash["$#{op}"] ||= {}
|
232
|
+
update_hash["$#{op}"][k] = v
|
233
|
+
end
|
234
|
+
update_hash
|
235
|
+
end
|
236
|
+
protected :build_update_hash
|
237
|
+
|
238
|
+
def build_update_query_hash(persisted_mongohash_kv, changelog)
|
239
|
+
update_query_hash = {}
|
240
|
+
changelog.each do |op, k, v|
|
241
|
+
if persisted_val = persisted_mongohash_kv[k]
|
242
|
+
if persisted_val == []
|
243
|
+
# work around a bug where mongo won't find a doc
|
244
|
+
# using an empty array [] if an index is defined
|
245
|
+
# on that field.
|
246
|
+
persisted_val = { "$size" => 0 }
|
247
|
+
end
|
248
|
+
update_query_hash[k] = persisted_val
|
249
|
+
end
|
250
|
+
end
|
251
|
+
update_query_hash
|
252
|
+
end
|
253
|
+
protected :build_update_query_hash
|
254
|
+
|
255
|
+
end
|
256
|
+
end
|