mongo_doc_rails2 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +8 -0
- data/HISTORY.md +11 -0
- data/LICENSE +20 -0
- data/README.textile +185 -0
- data/Rakefile +188 -0
- data/TODO +40 -0
- data/VERSION +1 -0
- data/data/.gitignore +2 -0
- data/examples/simple_document.rb +46 -0
- data/examples/simple_object.rb +34 -0
- data/features/collections.feature +9 -0
- data/features/embed_hash.feature +16 -0
- data/features/finders.feature +76 -0
- data/features/indexes.feature +28 -0
- data/features/mongodb.yml +7 -0
- data/features/mongodoc_base.feature +128 -0
- data/features/new_record.feature +36 -0
- data/features/partial_updates.feature +95 -0
- data/features/removing_documents.feature +68 -0
- data/features/saving_an_object.feature +15 -0
- data/features/scopes.feature +66 -0
- data/features/step_definitions/collection_steps.rb +17 -0
- data/features/step_definitions/document_steps.rb +149 -0
- data/features/step_definitions/documents.rb +40 -0
- data/features/step_definitions/embed_hash_steps.rb +6 -0
- data/features/step_definitions/finder_steps.rb +15 -0
- data/features/step_definitions/index_steps.rb +10 -0
- data/features/step_definitions/json_steps.rb +9 -0
- data/features/step_definitions/object_steps.rb +50 -0
- data/features/step_definitions/objects.rb +24 -0
- data/features/step_definitions/partial_update_steps.rb +31 -0
- data/features/step_definitions/query_steps.rb +66 -0
- data/features/step_definitions/removing_documents_steps.rb +14 -0
- data/features/step_definitions/scope_steps.rb +18 -0
- data/features/step_definitions/string_casting_steps.rb +29 -0
- data/features/step_definitions/util_steps.rb +7 -0
- data/features/string_casting.feature +10 -0
- data/features/support/support.rb +10 -0
- data/features/using_criteria.feature +142 -0
- data/lib/mongo_doc.rb +12 -0
- data/lib/mongo_doc/associations.rb +109 -0
- data/lib/mongo_doc/associations/collection_proxy.rb +121 -0
- data/lib/mongo_doc/associations/document_proxy.rb +65 -0
- data/lib/mongo_doc/associations/hash_proxy.rb +102 -0
- data/lib/mongo_doc/associations/proxy_base.rb +48 -0
- data/lib/mongo_doc/attributes.rb +84 -0
- data/lib/mongo_doc/bson.rb +31 -0
- data/lib/mongo_doc/collection.rb +82 -0
- data/lib/mongo_doc/connection.rb +88 -0
- data/lib/mongo_doc/contexts.rb +31 -0
- data/lib/mongo_doc/contexts/ids.rb +41 -0
- data/lib/mongo_doc/contexts/mongo.rb +272 -0
- data/lib/mongo_doc/criteria.rb +70 -0
- data/lib/mongo_doc/cursor.rb +32 -0
- data/lib/mongo_doc/document.rb +205 -0
- data/lib/mongo_doc/ext.rb +16 -0
- data/lib/mongo_doc/ext/array.rb +5 -0
- data/lib/mongo_doc/ext/binary.rb +7 -0
- data/lib/mongo_doc/ext/boolean_class.rb +17 -0
- data/lib/mongo_doc/ext/date.rb +19 -0
- data/lib/mongo_doc/ext/date_time.rb +17 -0
- data/lib/mongo_doc/ext/dbref.rb +7 -0
- data/lib/mongo_doc/ext/hash.rb +7 -0
- data/lib/mongo_doc/ext/min_max_keys.rb +13 -0
- data/lib/mongo_doc/ext/nil_class.rb +5 -0
- data/lib/mongo_doc/ext/numeric.rb +17 -0
- data/lib/mongo_doc/ext/object.rb +19 -0
- data/lib/mongo_doc/ext/object_id.rb +7 -0
- data/lib/mongo_doc/ext/regexp.rb +5 -0
- data/lib/mongo_doc/ext/string.rb +5 -0
- data/lib/mongo_doc/ext/symbol.rb +5 -0
- data/lib/mongo_doc/ext/time.rb +9 -0
- data/lib/mongo_doc/finders.rb +38 -0
- data/lib/mongo_doc/index.rb +46 -0
- data/lib/mongo_doc/matchers.rb +35 -0
- data/lib/mongo_doc/root.rb +26 -0
- data/lib/mongo_doc/scope.rb +64 -0
- data/lib/mongo_doc/validations.rb +12 -0
- data/lib/mongo_doc/validations/macros.rb +11 -0
- data/lib/mongo_doc/validations/validates_embedded.rb +13 -0
- data/lib/mongoid/contexts/enumerable.rb +151 -0
- data/lib/mongoid/contexts/paging.rb +42 -0
- data/lib/mongoid/criteria.rb +239 -0
- data/lib/mongoid/criterion/complex.rb +21 -0
- data/lib/mongoid/criterion/exclusion.rb +65 -0
- data/lib/mongoid/criterion/inclusion.rb +93 -0
- data/lib/mongoid/criterion/optional.rb +136 -0
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
- data/lib/mongoid/extensions/symbol/inflections.rb +36 -0
- data/lib/mongoid/matchers/all.rb +11 -0
- data/lib/mongoid/matchers/default.rb +26 -0
- data/lib/mongoid/matchers/exists.rb +13 -0
- data/lib/mongoid/matchers/gt.rb +11 -0
- data/lib/mongoid/matchers/gte.rb +11 -0
- data/lib/mongoid/matchers/in.rb +11 -0
- data/lib/mongoid/matchers/lt.rb +11 -0
- data/lib/mongoid/matchers/lte.rb +11 -0
- data/lib/mongoid/matchers/ne.rb +11 -0
- data/lib/mongoid/matchers/nin.rb +11 -0
- data/lib/mongoid/matchers/size.rb +11 -0
- data/mongo_doc_rails2.gemspec +237 -0
- data/mongod.example.yml +2 -0
- data/mongodb.example.yml +14 -0
- data/perf/mongo_doc_object.rb +83 -0
- data/perf/mongo_document.rb +84 -0
- data/perf/ruby_driver.rb +49 -0
- data/script/console +8 -0
- data/spec/array_including_argument_matcher.rb +62 -0
- data/spec/associations/collection_proxy_spec.rb +233 -0
- data/spec/associations/document_proxy_spec.rb +45 -0
- data/spec/associations/hash_proxy_spec.rb +181 -0
- data/spec/associations/proxy_base_spec.rb +92 -0
- data/spec/associations_spec.rb +218 -0
- data/spec/attributes_accessor_spec.rb +33 -0
- data/spec/attributes_spec.rb +145 -0
- data/spec/bson_matchers.rb +54 -0
- data/spec/bson_spec.rb +196 -0
- data/spec/collection_spec.rb +169 -0
- data/spec/connection_spec.rb +147 -0
- data/spec/contexts/ids_spec.rb +49 -0
- data/spec/contexts/mongo_spec.rb +235 -0
- data/spec/contexts_spec.rb +56 -0
- data/spec/criteria_spec.rb +69 -0
- data/spec/cursor_spec.rb +91 -0
- data/spec/document_ext.rb +9 -0
- data/spec/document_spec.rb +553 -0
- data/spec/embedded_save_spec.rb +73 -0
- data/spec/ext_spec.rb +89 -0
- data/spec/finders_spec.rb +61 -0
- data/spec/hash_matchers.rb +27 -0
- data/spec/index_spec.rb +79 -0
- data/spec/matchers_spec.rb +342 -0
- data/spec/mongodb.yml +6 -0
- data/spec/mongodb_pairs.yml +8 -0
- data/spec/new_record_spec.rb +128 -0
- data/spec/root_spec.rb +41 -0
- data/spec/scope_spec.rb +79 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/validations_spec.rb +30 -0
- metadata +346 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'mongoid/extensions/hash/criteria_helpers'
|
2
|
+
require 'mongoid/extensions/symbol/inflections'
|
3
|
+
require 'mongo_doc/matchers'
|
4
|
+
require 'mongo_doc/contexts'
|
5
|
+
require 'mongoid/criteria'
|
6
|
+
|
7
|
+
module MongoDoc
|
8
|
+
module Criteria
|
9
|
+
# Create a criteria for this +Document+ class
|
10
|
+
#
|
11
|
+
# <tt>Person.criteria</tt>
|
12
|
+
def criteria
|
13
|
+
CriteriaWrapper.new(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
delegate \
|
17
|
+
:aggregate,
|
18
|
+
:all,
|
19
|
+
:and,
|
20
|
+
:any_in,
|
21
|
+
:blank?,
|
22
|
+
:count,
|
23
|
+
:empty?,
|
24
|
+
:excludes,
|
25
|
+
:extras,
|
26
|
+
:first,
|
27
|
+
:group,
|
28
|
+
:id,
|
29
|
+
:in,
|
30
|
+
:last,
|
31
|
+
:limit,
|
32
|
+
:max,
|
33
|
+
:min,
|
34
|
+
:not_in,
|
35
|
+
:offset,
|
36
|
+
:one,
|
37
|
+
:only,
|
38
|
+
:order_by,
|
39
|
+
:page,
|
40
|
+
:paginate,
|
41
|
+
:per_page,
|
42
|
+
:skip,
|
43
|
+
:sum,
|
44
|
+
:where, :to => :criteria
|
45
|
+
|
46
|
+
class CriteriaWrapper < Mongoid::Criteria
|
47
|
+
%w(all and any_in cache enslave excludes extras fuse in limit not_in offset only order_by skip where).each do |method|
|
48
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
49
|
+
def #{method}_with_wrapping(*args, &block) # def and(*args, &block)
|
50
|
+
new_criteria = CriteriaWrapper.new(klass) # new_criteria = CriteriaWrapper.new(klass)
|
51
|
+
new_criteria.merge(self) # new_criteria.merge(criteria)
|
52
|
+
new_criteria.#{method}_without_wrapping(*args, &block) # new_criteria.and_without_wrapping(*args, &block)
|
53
|
+
new_criteria # new_criteria
|
54
|
+
end # end
|
55
|
+
|
56
|
+
alias_method_chain :#{method}, :wrapping
|
57
|
+
protected :#{method}_without_wrapping
|
58
|
+
RUBY
|
59
|
+
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
|
63
|
+
attr_accessor :criteria
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
Hash.send(:include, Mongoid::Extensions::Hash::CriteriaHelpers)
|
70
|
+
Symbol.send(:include, Mongoid::Extensions::Symbol::Inflections)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module MongoDoc
|
2
|
+
class Cursor
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_accessor :_collection, :_cursor
|
6
|
+
|
7
|
+
delegate :admin, :close, :closed?, :count, :explain, :fields, :full_collection_name, :hint, :limit, :order, :query_options_hash, :query_opts, :selector, :skip, :snapshot, :sort, :timeout, :to => :_cursor
|
8
|
+
|
9
|
+
def initialize(mongo_doc_collection, cursor)
|
10
|
+
self._collection = mongo_doc_collection
|
11
|
+
self._cursor = cursor
|
12
|
+
end
|
13
|
+
|
14
|
+
def collection
|
15
|
+
_collection
|
16
|
+
end
|
17
|
+
|
18
|
+
def each
|
19
|
+
_cursor.each do |next_document|
|
20
|
+
yield MongoDoc::BSON.decode(next_document)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def next_document
|
25
|
+
MongoDoc::BSON.decode(_cursor.next_document)
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_a
|
29
|
+
MongoDoc::BSON.decode(_cursor.to_a)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'mongo_doc/bson'
|
2
|
+
require 'mongo_doc/attributes'
|
3
|
+
require 'mongo_doc/root'
|
4
|
+
require 'mongo_doc/associations'
|
5
|
+
require 'mongo_doc/criteria'
|
6
|
+
require 'mongo_doc/finders'
|
7
|
+
require 'mongo_doc/index'
|
8
|
+
require 'mongo_doc/scope'
|
9
|
+
require 'mongo_doc/validations'
|
10
|
+
|
11
|
+
module MongoDoc
|
12
|
+
class UnsupportedOperation < RuntimeError; end
|
13
|
+
class DocumentInvalidError < RuntimeError; end
|
14
|
+
class NotADocumentError < RuntimeError; end
|
15
|
+
|
16
|
+
module Document
|
17
|
+
|
18
|
+
def self.included(klass)
|
19
|
+
klass.class_eval do
|
20
|
+
include Attributes
|
21
|
+
include Root
|
22
|
+
extend Associations
|
23
|
+
extend ClassMethods
|
24
|
+
extend Criteria
|
25
|
+
extend Finders
|
26
|
+
extend Index
|
27
|
+
extend Scope
|
28
|
+
include Validations
|
29
|
+
|
30
|
+
alias id _id
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def _collection
|
35
|
+
_root and _root._collection or self.class.collection
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(attrs = {})
|
39
|
+
self.attributes = attrs
|
40
|
+
end
|
41
|
+
|
42
|
+
def ==(other)
|
43
|
+
return false unless self.class === other
|
44
|
+
self.class._attributes.all? {|var| self.send(var) == other.send(var)}
|
45
|
+
end
|
46
|
+
|
47
|
+
def new_record?
|
48
|
+
_id.nil?
|
49
|
+
end
|
50
|
+
|
51
|
+
def remove
|
52
|
+
raise UnsupportedOperation.new('Document#remove is not supported for embedded documents') if _root
|
53
|
+
remove_document
|
54
|
+
end
|
55
|
+
|
56
|
+
def remove_document
|
57
|
+
return _root.remove_document if _root
|
58
|
+
_remove
|
59
|
+
end
|
60
|
+
|
61
|
+
def save(validate = true)
|
62
|
+
return _root.save(validate) if _root
|
63
|
+
return _save(false) unless validate and not valid?
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
def save!
|
68
|
+
return _root.save! if _root
|
69
|
+
raise DocumentInvalidError unless valid?
|
70
|
+
_save(true)
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_bson(*args)
|
74
|
+
{MongoDoc::BSON::CLASS_KEY => self.class.name}.tap do |bson_hash|
|
75
|
+
bson_hash['_id'] = _id unless new_record?
|
76
|
+
self.class._attributes.each do |name|
|
77
|
+
bson_hash[name.to_s] = send(name).to_bson(args)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_param
|
83
|
+
_id.to_s
|
84
|
+
end
|
85
|
+
|
86
|
+
def update_attributes(attrs)
|
87
|
+
self.attributes = attrs
|
88
|
+
return save if new_record?
|
89
|
+
return false unless valid?
|
90
|
+
_update({}, attrs, false)
|
91
|
+
end
|
92
|
+
|
93
|
+
def update_attributes!(attrs)
|
94
|
+
strict = attrs.delete(:__strict__)
|
95
|
+
self.attributes = attrs
|
96
|
+
return save! if new_record?
|
97
|
+
raise DocumentInvalidError unless valid?
|
98
|
+
_update({}, attrs, true)
|
99
|
+
end
|
100
|
+
|
101
|
+
module ClassMethods
|
102
|
+
def bson_create(bson_hash, options = {})
|
103
|
+
allocate.tap do |obj|
|
104
|
+
bson_hash.each do |name, value|
|
105
|
+
obj.send("#{name}=", MongoDoc::BSON.decode(value, options))
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def collection
|
111
|
+
@collection ||= MongoDoc::Collection.new(collection_name)
|
112
|
+
end
|
113
|
+
|
114
|
+
def collection_name
|
115
|
+
self.to_s.tableize.gsub('/', '.')
|
116
|
+
end
|
117
|
+
|
118
|
+
def create(attrs = {})
|
119
|
+
instance = new(attrs)
|
120
|
+
instance.save(true)
|
121
|
+
instance
|
122
|
+
end
|
123
|
+
|
124
|
+
def create!(attrs = {})
|
125
|
+
instance = new(attrs)
|
126
|
+
instance.save!
|
127
|
+
instance
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
protected
|
132
|
+
|
133
|
+
def _remove
|
134
|
+
_collection.remove({'_id' => _id})
|
135
|
+
end
|
136
|
+
|
137
|
+
def _update(selector, data, safe)
|
138
|
+
return _root.send(:_update, {_selector_path + '._id' => _id}, hash_with_modifier_path_keys(data), safe) if _root
|
139
|
+
_collection.update({'_id' => _id}.merge(selector), {'$set' => data}, :safe => safe)
|
140
|
+
end
|
141
|
+
|
142
|
+
def _save(safe)
|
143
|
+
notify_before_save_observers
|
144
|
+
self._id = _collection.save(self, :safe => safe)
|
145
|
+
notify_save_success_observers
|
146
|
+
self._id
|
147
|
+
rescue Mongo::MongoDBError => e
|
148
|
+
notify_save_failed_observers
|
149
|
+
raise e
|
150
|
+
end
|
151
|
+
|
152
|
+
def hash_with_modifier_path_keys(hash)
|
153
|
+
hash.stringify_keys!
|
154
|
+
{}.tap do |dup|
|
155
|
+
hash.each do |key, value|
|
156
|
+
dup[_modifier_path + '.' + key] = value
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def path(parent_path, child_path)
|
162
|
+
if parent_path.blank?
|
163
|
+
child_path
|
164
|
+
else
|
165
|
+
parent_path + '.' + child_path
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def before_save_callback(root)
|
170
|
+
self._id = ::BSON::ObjectID.new if new_record?
|
171
|
+
end
|
172
|
+
|
173
|
+
def save_failed_callback(root)
|
174
|
+
self._id = nil
|
175
|
+
end
|
176
|
+
|
177
|
+
def save_success_callback(root)
|
178
|
+
root.unregister_save_observer(self)
|
179
|
+
end
|
180
|
+
|
181
|
+
def save_observers
|
182
|
+
@save_observers ||= []
|
183
|
+
end
|
184
|
+
|
185
|
+
def register_save_observer(child)
|
186
|
+
save_observers << child
|
187
|
+
end
|
188
|
+
|
189
|
+
def unregister_save_observer(child)
|
190
|
+
save_observers.delete(child)
|
191
|
+
end
|
192
|
+
|
193
|
+
def notify_before_save_observers
|
194
|
+
save_observers.each {|obs| obs.before_save_callback(self) }
|
195
|
+
end
|
196
|
+
|
197
|
+
def notify_save_success_observers
|
198
|
+
save_observers.each {|obs| obs.save_success_callback(self) }
|
199
|
+
end
|
200
|
+
|
201
|
+
def notify_save_failed_observers
|
202
|
+
save_observers.each {|obs| obs.save_failed_callback(self) }
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'mongo_doc/ext/array'
|
2
|
+
require 'mongo_doc/ext/binary'
|
3
|
+
require 'mongo_doc/ext/boolean_class'
|
4
|
+
require 'mongo_doc/ext/date'
|
5
|
+
require 'mongo_doc/ext/date_time'
|
6
|
+
require 'mongo_doc/ext/dbref'
|
7
|
+
require 'mongo_doc/ext/hash'
|
8
|
+
require 'mongo_doc/ext/min_max_keys'
|
9
|
+
require 'mongo_doc/ext/nil_class'
|
10
|
+
require 'mongo_doc/ext/numeric'
|
11
|
+
require 'mongo_doc/ext/object'
|
12
|
+
require 'mongo_doc/ext/object_id'
|
13
|
+
require 'mongo_doc/ext/regexp'
|
14
|
+
require 'mongo_doc/ext/string'
|
15
|
+
require 'mongo_doc/ext/symbol'
|
16
|
+
require 'mongo_doc/ext/time'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Date
|
2
|
+
def to_bson(*args)
|
3
|
+
{
|
4
|
+
MongoDoc::BSON::CLASS_KEY => self.class.name,
|
5
|
+
'dt' => strftime,
|
6
|
+
'sg' => start
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
alias start sg unless method_defined?(:start)
|
11
|
+
|
12
|
+
def self.bson_create(bson_hash, options = nil)
|
13
|
+
Date.parse(*bson_hash.values_at('dt', 'sg'))
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.cast_from_string(value)
|
17
|
+
Date.parse(value) unless value.blank?
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class DateTime
|
2
|
+
def to_bson(*args)
|
3
|
+
{
|
4
|
+
MongoDoc::BSON::CLASS_KEY => self.class.name,
|
5
|
+
'dt' => strftime,
|
6
|
+
'sg' => start
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.bson_create(bson_hash, options = nil)
|
11
|
+
DateTime.parse(*bson_hash.values_at('dt', 'sg'))
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.cast_from_string(string)
|
15
|
+
DateTime.parse(string) unless string.blank?
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Numeric
|
2
|
+
def to_bson(*args)
|
3
|
+
self
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
class BigDecimal
|
8
|
+
def self.cast_from_string(string)
|
9
|
+
BigDecimal.new(string) unless string.blank?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Integer
|
14
|
+
def self.cast_from_string(string)
|
15
|
+
string.to_i unless string.blank?
|
16
|
+
end
|
17
|
+
end
|