mongo_mapper 0.7.5 → 0.7.6
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/lib/mongo_mapper.rb +3 -5
- data/lib/mongo_mapper/document.rb +23 -53
- data/lib/mongo_mapper/plugins/associations.rb +1 -1
- data/lib/mongo_mapper/plugins/associations/base.rb +4 -4
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +1 -1
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +1 -1
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +1 -1
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +1 -1
- data/lib/mongo_mapper/plugins/equality.rb +3 -3
- data/lib/mongo_mapper/plugins/identity_map.rb +8 -7
- data/lib/mongo_mapper/plugins/keys.rb +49 -73
- data/lib/mongo_mapper/plugins/keys/key.rb +44 -0
- data/lib/mongo_mapper/plugins/modifiers.rb +9 -5
- data/lib/mongo_mapper/plugins/pagination/proxy.rb +3 -3
- data/lib/mongo_mapper/plugins/serialization.rb +3 -3
- data/lib/mongo_mapper/plugins/timestamps.rb +1 -1
- data/lib/mongo_mapper/plugins/validations.rb +2 -2
- data/lib/mongo_mapper/query.rb +9 -129
- data/lib/mongo_mapper/support.rb +17 -39
- data/lib/mongo_mapper/version.rb +1 -1
- metadata +54 -140
- data/.gitignore +0 -10
- data/Rakefile +0 -37
- data/mongo_mapper.gemspec +0 -214
- data/performance/read_write.rb +0 -52
- data/specs.watchr +0 -51
- data/test/NOTE_ON_TESTING +0 -1
- data/test/active_model_lint_test.rb +0 -13
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +0 -63
- data/test/functional/associations/test_belongs_to_proxy.rb +0 -101
- data/test/functional/associations/test_in_array_proxy.rb +0 -325
- data/test/functional/associations/test_many_documents_as_proxy.rb +0 -229
- data/test/functional/associations/test_many_documents_proxy.rb +0 -536
- data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +0 -176
- data/test/functional/associations/test_many_embedded_proxy.rb +0 -256
- data/test/functional/associations/test_many_polymorphic_proxy.rb +0 -302
- data/test/functional/associations/test_one_embedded_proxy.rb +0 -68
- data/test/functional/associations/test_one_proxy.rb +0 -196
- data/test/functional/test_associations.rb +0 -44
- data/test/functional/test_binary.rb +0 -27
- data/test/functional/test_callbacks.rb +0 -151
- data/test/functional/test_dirty.rb +0 -163
- data/test/functional/test_document.rb +0 -1219
- data/test/functional/test_embedded_document.rb +0 -210
- data/test/functional/test_identity_map.rb +0 -507
- data/test/functional/test_indexing.rb +0 -44
- data/test/functional/test_logger.rb +0 -20
- data/test/functional/test_modifiers.rb +0 -394
- data/test/functional/test_pagination.rb +0 -93
- data/test/functional/test_protected.rb +0 -163
- data/test/functional/test_string_id_compatibility.rb +0 -67
- data/test/functional/test_timestamps.rb +0 -64
- data/test/functional/test_userstamps.rb +0 -28
- data/test/functional/test_validations.rb +0 -342
- data/test/models.rb +0 -227
- data/test/support/custom_matchers.rb +0 -37
- data/test/support/timing.rb +0 -16
- data/test/test_helper.rb +0 -64
- data/test/unit/associations/test_base.rb +0 -212
- data/test/unit/associations/test_proxy.rb +0 -105
- data/test/unit/serializers/test_json_serializer.rb +0 -202
- data/test/unit/test_descendant_appends.rb +0 -71
- data/test/unit/test_document.rb +0 -225
- data/test/unit/test_dynamic_finder.rb +0 -123
- data/test/unit/test_embedded_document.rb +0 -657
- data/test/unit/test_keys.rb +0 -185
- data/test/unit/test_mongo_mapper.rb +0 -118
- data/test/unit/test_pagination.rb +0 -160
- data/test/unit/test_plugins.rb +0 -50
- data/test/unit/test_query.rb +0 -374
- data/test/unit/test_rails.rb +0 -181
- data/test/unit/test_rails_compatibility.rb +0 -52
- data/test/unit/test_serialization.rb +0 -51
- data/test/unit/test_support.rb +0 -382
- data/test/unit/test_time_zones.rb +0 -39
- data/test/unit/test_validations.rb +0 -544
@@ -0,0 +1,44 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Keys
|
4
|
+
class Key
|
5
|
+
attr_accessor :name, :type, :options, :default_value
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
options = args.extract_options!
|
9
|
+
@name, @type = args.shift.to_s, args.shift
|
10
|
+
self.options = (options || {}).symbolize_keys
|
11
|
+
self.default_value = self.options.delete(:default)
|
12
|
+
end
|
13
|
+
|
14
|
+
def ==(other)
|
15
|
+
@name == other.name && @type == other.type
|
16
|
+
end
|
17
|
+
|
18
|
+
def embeddable?
|
19
|
+
type.respond_to?(:embeddable?) && type.embeddable? ? true : false
|
20
|
+
end
|
21
|
+
|
22
|
+
def number?
|
23
|
+
[Integer, Float].include?(type)
|
24
|
+
end
|
25
|
+
|
26
|
+
def get(value)
|
27
|
+
if value.nil? && !default_value.nil?
|
28
|
+
if default_value.respond_to?(:call)
|
29
|
+
return default_value.call
|
30
|
+
else
|
31
|
+
return default_value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
type.from_mongo(value)
|
36
|
+
end
|
37
|
+
|
38
|
+
def set(value)
|
39
|
+
type.to_mongo(value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -14,7 +14,11 @@ module MongoMapper
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def set(*args)
|
17
|
-
|
17
|
+
criteria, updates = criteria_and_keys_from_args(args)
|
18
|
+
updates.each do |key, value|
|
19
|
+
updates[key] = keys[key].set(value) if key?(key)
|
20
|
+
end
|
21
|
+
collection.update(criteria, {'$set' => updates}, :multi => true)
|
18
22
|
end
|
19
23
|
|
20
24
|
def unset(*args)
|
@@ -25,7 +29,7 @@ module MongoMapper
|
|
25
29
|
criteria = {:id => ids}
|
26
30
|
end
|
27
31
|
|
28
|
-
criteria =
|
32
|
+
criteria = query(criteria).criteria.to_hash
|
29
33
|
modifiers = keys.inject({}) { |hash, key| hash[key] = 1; hash }
|
30
34
|
collection.update(criteria, {'$unset' => modifiers}, :multi => true)
|
31
35
|
end
|
@@ -57,14 +61,14 @@ module MongoMapper
|
|
57
61
|
|
58
62
|
private
|
59
63
|
def modifier_update(modifier, args)
|
60
|
-
criteria,
|
61
|
-
collection.update(criteria, {modifier =>
|
64
|
+
criteria, updates = criteria_and_keys_from_args(args)
|
65
|
+
collection.update(criteria, {modifier => updates}, :multi => true)
|
62
66
|
end
|
63
67
|
|
64
68
|
def criteria_and_keys_from_args(args)
|
65
69
|
keys = args.pop
|
66
70
|
criteria = args[0].is_a?(Hash) ? args[0] : {:id => args}
|
67
|
-
[
|
71
|
+
[query(criteria).criteria.to_hash, keys]
|
68
72
|
end
|
69
73
|
end
|
70
74
|
|
@@ -3,7 +3,7 @@ module MongoMapper
|
|
3
3
|
module Pagination
|
4
4
|
class Proxy
|
5
5
|
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|respond_to\?|proxy_|^object_id$)/ }
|
6
|
-
|
6
|
+
|
7
7
|
attr_accessor :subject
|
8
8
|
attr_reader :total_entries, :per_page, :current_page
|
9
9
|
alias limit per_page
|
@@ -50,11 +50,11 @@ module MongoMapper
|
|
50
50
|
def method_missing(name, *args, &block)
|
51
51
|
@subject.send(name, *args, &block)
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
def respond_to?(name, *args, &block)
|
55
55
|
super || @subject.respond_to?(name, *args, &block)
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
private
|
59
59
|
def per_page=(value)
|
60
60
|
value = 25 if value.blank?
|
@@ -6,7 +6,7 @@ module MongoMapper
|
|
6
6
|
def self.configure(model)
|
7
7
|
model.class_eval { cattr_accessor :include_root_in_json, :instance_writer => true }
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
module InstanceMethods
|
11
11
|
def as_json options={}
|
12
12
|
options ||= {}
|
@@ -43,7 +43,7 @@ module MongoMapper
|
|
43
43
|
}
|
44
44
|
end
|
45
45
|
# End rip
|
46
|
-
|
46
|
+
|
47
47
|
options.delete(:only) if options[:only].nil? or options[:only].empty?
|
48
48
|
|
49
49
|
hash.each do |key, value|
|
@@ -57,7 +57,7 @@ module MongoMapper
|
|
57
57
|
hash[key] = value.as_json(options)
|
58
58
|
end
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
# Replicate Rails 3 naming - and also bin anytihng after : for use in our dynamic classes from unit tests
|
62
62
|
hash = { ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)).gsub(/:.*/,'') => hash } if include_root_in_json
|
63
63
|
hash
|
@@ -4,13 +4,13 @@ module MongoMapper
|
|
4
4
|
def self.configure(model)
|
5
5
|
model.class_eval { include Validatable }
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
module DocumentMacros
|
9
9
|
def validates_uniqueness_of(*args)
|
10
10
|
add_validations(args, MongoMapper::Plugins::Validations::ValidatesUniquenessOf)
|
11
11
|
end
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
class ValidatesUniquenessOf < Validatable::ValidationBase
|
15
15
|
option :scope, :case_sensitive
|
16
16
|
default :case_sensitive => true
|
data/lib/mongo_mapper/query.rb
CHANGED
@@ -1,143 +1,23 @@
|
|
1
1
|
module MongoMapper
|
2
|
-
# IMPORTANT
|
3
|
-
# This class is private to MongoMapper and should not be considered part of MongoMapper's public API.
|
4
|
-
#
|
5
2
|
class Query
|
6
|
-
|
7
|
-
|
8
|
-
attr_reader :model
|
9
|
-
|
10
|
-
def initialize(model, options)
|
3
|
+
def initialize(model, options={})
|
11
4
|
raise ArgumentError, "Options must be a hash" unless options.is_a?(Hash)
|
12
|
-
@model, @options, @conditions
|
13
|
-
|
5
|
+
@model, @options, @conditions = model, {}, {}
|
6
|
+
query.update(options)
|
14
7
|
add_sci_condition
|
15
8
|
end
|
16
9
|
|
17
|
-
def criteria
|
18
|
-
to_criteria(@conditions)
|
19
|
-
end
|
20
|
-
|
21
|
-
def options
|
22
|
-
fields = @options[:fields] || @options[:select]
|
23
|
-
skip = @options[:skip] || @options[:offset] || 0
|
24
|
-
limit = @options[:limit] || 0
|
25
|
-
sort = @options[:sort] || normalized_sort(@options[:order])
|
26
|
-
|
27
|
-
{:fields => to_fields(fields), :skip => skip.to_i, :limit => limit.to_i, :sort => sort}
|
28
|
-
end
|
29
|
-
|
30
|
-
def to_a
|
31
|
-
[criteria, options]
|
32
|
-
end
|
33
|
-
|
34
10
|
private
|
35
|
-
def
|
36
|
-
|
37
|
-
key = key.respond_to?(:to_sym) ? key.to_sym : key
|
38
|
-
|
39
|
-
if OptionKeys.include?(key)
|
40
|
-
@options[key] = value
|
41
|
-
elsif key == :conditions
|
42
|
-
@conditions.update(value)
|
43
|
-
else
|
44
|
-
@conditions[key] = value
|
45
|
-
end
|
46
|
-
end
|
11
|
+
def method_missing(method, *args, &block)
|
12
|
+
query.send(method, *args, &block)
|
47
13
|
end
|
48
14
|
|
49
|
-
|
50
|
-
|
51
|
-
@conditions[:_type] = model.to_s if model.single_collection_inherited?
|
15
|
+
def query
|
16
|
+
@query ||= Plucky::Query.new(@model.collection).object_ids(@model.object_id_keys)
|
52
17
|
end
|
53
18
|
|
54
|
-
def
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
def symbol_operator?(object)
|
59
|
-
object.respond_to?(:field, :operator)
|
60
|
-
end
|
61
|
-
|
62
|
-
def to_criteria(conditions, parent_key=nil)
|
63
|
-
criteria = {}
|
64
|
-
|
65
|
-
conditions.each_pair do |key, value|
|
66
|
-
key = normalized_key(key)
|
67
|
-
|
68
|
-
if model.object_id_key?(key)
|
69
|
-
case value
|
70
|
-
when String
|
71
|
-
value = ObjectId.to_mongo(value)
|
72
|
-
when Array
|
73
|
-
value.map! { |id| ObjectId.to_mongo(id) }
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
if symbol_operator?(key)
|
78
|
-
key, value = normalized_key(key.field), {"$#{key.operator}" => value}
|
79
|
-
end
|
80
|
-
|
81
|
-
criteria[key] = normalized_value(criteria, key, value)
|
82
|
-
end
|
83
|
-
|
84
|
-
criteria
|
85
|
-
end
|
86
|
-
|
87
|
-
def to_fields(keys)
|
88
|
-
return keys if keys.is_a?(Hash)
|
89
|
-
return nil if keys.blank?
|
90
|
-
|
91
|
-
if keys.respond_to?(:flatten, :compact)
|
92
|
-
keys.flatten.compact
|
93
|
-
else
|
94
|
-
keys.split(',').map { |key| key.strip }
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def to_order(key, direction=nil)
|
99
|
-
[normalized_key(key).to_s, normalized_direction(direction)]
|
100
|
-
end
|
101
|
-
|
102
|
-
def normalized_key(key)
|
103
|
-
key.to_s == 'id' ? :_id : key
|
104
|
-
end
|
105
|
-
|
106
|
-
# TODO: this is getting heavy enough to move to a class
|
107
|
-
def normalized_value(criteria, key, value)
|
108
|
-
case value
|
109
|
-
when Array, Set
|
110
|
-
modifier?(key) ? value.to_a : {'$in' => value.to_a}
|
111
|
-
when Hash
|
112
|
-
if criteria[key].kind_of?(Hash)
|
113
|
-
criteria[key].dup.merge(to_criteria(value, key))
|
114
|
-
else
|
115
|
-
to_criteria(value, key)
|
116
|
-
end
|
117
|
-
when Time
|
118
|
-
value.utc
|
119
|
-
else
|
120
|
-
value
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def normalized_direction(direction)
|
125
|
-
direction ||= 'asc'
|
126
|
-
direction.downcase == 'asc' ? Mongo::ASCENDING : Mongo::DESCENDING
|
127
|
-
end
|
128
|
-
|
129
|
-
def normalized_sort(sort)
|
130
|
-
return if sort.blank?
|
131
|
-
|
132
|
-
if sort.respond_to?(:all?) && sort.all? { |s| symbol_operator?(s) }
|
133
|
-
sort.map { |s| to_order(s.field, s.operator) }
|
134
|
-
elsif symbol_operator?(sort)
|
135
|
-
[to_order(sort.field, sort.operator)]
|
136
|
-
else
|
137
|
-
sort.split(',').map do |str|
|
138
|
-
to_order(*str.strip.split(' '))
|
139
|
-
end
|
140
|
-
end
|
19
|
+
def add_sci_condition
|
20
|
+
query[:_type] = @model.to_s if @model.single_collection_inherited?
|
141
21
|
end
|
142
22
|
end
|
143
23
|
end
|
data/lib/mongo_mapper/support.rb
CHANGED
@@ -3,7 +3,7 @@ class Array
|
|
3
3
|
value = value.respond_to?(:lines) ? value.lines : value
|
4
4
|
value.to_a
|
5
5
|
end
|
6
|
-
|
6
|
+
|
7
7
|
def self.from_mongo(value)
|
8
8
|
value || []
|
9
9
|
end
|
@@ -28,7 +28,7 @@ class Boolean
|
|
28
28
|
true => true, 'true' => true, 'TRUE' => true, 'True' => true, 't' => true, 'T' => true, '1' => true, 1 => true, 1.0 => true,
|
29
29
|
false => false, 'false' => false, 'FALSE' => false, 'False' => false, 'f' => false, 'F' => false, '0' => false, 0 => false, 0.0 => false, nil => nil
|
30
30
|
}
|
31
|
-
|
31
|
+
|
32
32
|
def self.to_mongo(value)
|
33
33
|
if value.is_a?(Boolean)
|
34
34
|
value
|
@@ -53,7 +53,7 @@ class Date
|
|
53
53
|
rescue
|
54
54
|
nil
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
def self.from_mongo(value)
|
58
58
|
value.to_date if value.present?
|
59
59
|
end
|
@@ -61,7 +61,7 @@ end
|
|
61
61
|
|
62
62
|
class Float
|
63
63
|
def self.to_mongo(value)
|
64
|
-
value.to_f
|
64
|
+
value.nil? ? nil : value.to_f
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
@@ -69,7 +69,7 @@ class Hash
|
|
69
69
|
def self.from_mongo(value)
|
70
70
|
HashWithIndifferentAccess.new(value || {})
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
def to_mongo
|
74
74
|
self
|
75
75
|
end
|
@@ -90,7 +90,7 @@ class NilClass
|
|
90
90
|
def to_mongo(value)
|
91
91
|
value
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
def from_mongo(value)
|
95
95
|
value
|
96
96
|
end
|
@@ -115,11 +115,11 @@ class Object
|
|
115
115
|
def class_def(name, &blk)
|
116
116
|
class_eval { define_method(name, &blk) }
|
117
117
|
end
|
118
|
-
|
118
|
+
|
119
119
|
def self.to_mongo(value)
|
120
120
|
value
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
def self.from_mongo(value)
|
124
124
|
value
|
125
125
|
end
|
@@ -127,15 +127,9 @@ end
|
|
127
127
|
|
128
128
|
class ObjectId
|
129
129
|
def self.to_mongo(value)
|
130
|
-
|
131
|
-
nil
|
132
|
-
elsif value.is_a?(BSON::ObjectID)
|
133
|
-
value
|
134
|
-
else
|
135
|
-
BSON::ObjectID.from_string(value.to_s)
|
136
|
-
end
|
130
|
+
Plucky.to_object_id(value)
|
137
131
|
end
|
138
|
-
|
132
|
+
|
139
133
|
def self.from_mongo(value)
|
140
134
|
value
|
141
135
|
end
|
@@ -145,7 +139,7 @@ class Set
|
|
145
139
|
def self.to_mongo(value)
|
146
140
|
value.to_a
|
147
141
|
end
|
148
|
-
|
142
|
+
|
149
143
|
def self.from_mongo(value)
|
150
144
|
Set.new(value || [])
|
151
145
|
end
|
@@ -155,28 +149,12 @@ class String
|
|
155
149
|
def self.to_mongo(value)
|
156
150
|
value.nil? ? nil : value.to_s
|
157
151
|
end
|
158
|
-
|
152
|
+
|
159
153
|
def self.from_mongo(value)
|
160
154
|
value.nil? ? nil : value.to_s
|
161
155
|
end
|
162
156
|
end
|
163
157
|
|
164
|
-
class SymbolOperator
|
165
|
-
attr_reader :field, :operator
|
166
|
-
|
167
|
-
def initialize(field, operator, options={})
|
168
|
-
@field, @operator = field, operator
|
169
|
-
end unless method_defined?(:initialize)
|
170
|
-
end
|
171
|
-
|
172
|
-
class Symbol
|
173
|
-
%w(gt lt gte lte ne in nin mod all size where exists asc desc).each do |operator|
|
174
|
-
define_method(operator) do
|
175
|
-
SymbolOperator.new(self, operator)
|
176
|
-
end unless method_defined?(operator)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
158
|
class Time
|
181
159
|
def self.to_mongo(value)
|
182
160
|
if value.nil? || value == ''
|
@@ -184,11 +162,11 @@ class Time
|
|
184
162
|
else
|
185
163
|
time_class = Time.try(:zone).present? ? Time.zone : Time
|
186
164
|
time = value.is_a?(Time) ? value : time_class.parse(value.to_s)
|
187
|
-
#
|
188
|
-
|
165
|
+
# strip milliseconds as Ruby does micro and bson does milli and rounding rounded wrong
|
166
|
+
at(time.to_i).utc if time
|
189
167
|
end
|
190
168
|
end
|
191
|
-
|
169
|
+
|
192
170
|
def self.from_mongo(value)
|
193
171
|
if Time.try(:zone).present? && value.present?
|
194
172
|
value.in_time_zone(Time.zone)
|
@@ -200,11 +178,11 @@ end
|
|
200
178
|
|
201
179
|
class BSON::ObjectID
|
202
180
|
alias_method :original_to_json, :to_json
|
203
|
-
|
181
|
+
|
204
182
|
def as_json(options=nil)
|
205
183
|
to_s
|
206
184
|
end
|
207
|
-
|
185
|
+
|
208
186
|
def to_json(options = nil)
|
209
187
|
as_json.to_json
|
210
188
|
end
|