/
querying.rb
103 lines (92 loc) · 2.92 KB
/
querying.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
module Toy
module Mongo
module Querying
extend ActiveSupport::Concern
PluckyMethods = Plucky::Methods
module ClassMethods
def transformer
@transformer ||= lambda do |doc|
load(doc.delete('_id'), doc)
end
end
def object_id_attributes
attributes.values.select do |attribute|
attribute.type == BSON::ObjectId
end.map do |attribute|
sym = attribute.name.to_sym
sym == :id ? :_id : sym
end
end
def get(id)
super Plucky.to_object_id(id)
end
# Mongo does not guarantee sort order when using $in.
# So we manually sort in ruby for now. Not stoked about
# this, but it gets the job done.
def get_multi(*ids)
ids = ids.flatten
all(:_id => {'$in' => ids}).sort do |a, b|
index_a = ids.index(a.id)
index_b = ids.index(b.id)
if index_a.nil? || index_b.nil?
1
else
index_a <=> index_b
end
end
end
def query
# TODO: add object id keys to convert
Plucky::Query.new(adapter.client, :transformer => transformer).object_ids(object_id_attributes)
end
PluckyMethods.each do |name|
define_method(name) do |*args|
query.send(name, *args)
end
end
end
# Very basic method for determining what has changed locally
# so we can just update changes instead of entire document
#
# Does not work with complex objects (array, hash, set, etc.)
# as it does not attempt to determine what has changed in them,
# just whether or not they have changed at all.
def persistable_changes
attrs = {}
pattrs = persisted_attributes
changed.each do |key|
attribute = self.class.attributes[key.to_s]
next if attribute.virtual?
attrs[attribute.persisted_name] = pattrs[attribute.persisted_name]
end
attrs
end
def atomic_update_attributes(attrs={})
self.attributes = attrs
if valid?
run_callbacks(:save) do
run_callbacks(:update) do
criteria = {'_id' => id}
update = {'$set' => persistable_changes}
adapter.client.update(criteria, update, {:safe => adapter.options[:safe]})
true
end
end
else
false
end
end
def atomic_update(update, opts={})
options = {}
criteria = {'_id' => id}
criteria.update(opts[:criteria]) if opts[:criteria]
options[:safe] = opts.key?(:safe) ? opts[:safe] : adapter.options[:safe]
run_callbacks(:save) do
run_callbacks(:update) do
adapter.client.update(criteria, update, options)
end
end
end
end
end
end