mongo_doc_rails2 0.6.1

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.
Files changed (142) hide show
  1. data/.document +5 -0
  2. data/.gitignore +8 -0
  3. data/HISTORY.md +11 -0
  4. data/LICENSE +20 -0
  5. data/README.textile +185 -0
  6. data/Rakefile +188 -0
  7. data/TODO +40 -0
  8. data/VERSION +1 -0
  9. data/data/.gitignore +2 -0
  10. data/examples/simple_document.rb +46 -0
  11. data/examples/simple_object.rb +34 -0
  12. data/features/collections.feature +9 -0
  13. data/features/embed_hash.feature +16 -0
  14. data/features/finders.feature +76 -0
  15. data/features/indexes.feature +28 -0
  16. data/features/mongodb.yml +7 -0
  17. data/features/mongodoc_base.feature +128 -0
  18. data/features/new_record.feature +36 -0
  19. data/features/partial_updates.feature +95 -0
  20. data/features/removing_documents.feature +68 -0
  21. data/features/saving_an_object.feature +15 -0
  22. data/features/scopes.feature +66 -0
  23. data/features/step_definitions/collection_steps.rb +17 -0
  24. data/features/step_definitions/document_steps.rb +149 -0
  25. data/features/step_definitions/documents.rb +40 -0
  26. data/features/step_definitions/embed_hash_steps.rb +6 -0
  27. data/features/step_definitions/finder_steps.rb +15 -0
  28. data/features/step_definitions/index_steps.rb +10 -0
  29. data/features/step_definitions/json_steps.rb +9 -0
  30. data/features/step_definitions/object_steps.rb +50 -0
  31. data/features/step_definitions/objects.rb +24 -0
  32. data/features/step_definitions/partial_update_steps.rb +31 -0
  33. data/features/step_definitions/query_steps.rb +66 -0
  34. data/features/step_definitions/removing_documents_steps.rb +14 -0
  35. data/features/step_definitions/scope_steps.rb +18 -0
  36. data/features/step_definitions/string_casting_steps.rb +29 -0
  37. data/features/step_definitions/util_steps.rb +7 -0
  38. data/features/string_casting.feature +10 -0
  39. data/features/support/support.rb +10 -0
  40. data/features/using_criteria.feature +142 -0
  41. data/lib/mongo_doc.rb +12 -0
  42. data/lib/mongo_doc/associations.rb +109 -0
  43. data/lib/mongo_doc/associations/collection_proxy.rb +121 -0
  44. data/lib/mongo_doc/associations/document_proxy.rb +65 -0
  45. data/lib/mongo_doc/associations/hash_proxy.rb +102 -0
  46. data/lib/mongo_doc/associations/proxy_base.rb +48 -0
  47. data/lib/mongo_doc/attributes.rb +84 -0
  48. data/lib/mongo_doc/bson.rb +31 -0
  49. data/lib/mongo_doc/collection.rb +82 -0
  50. data/lib/mongo_doc/connection.rb +88 -0
  51. data/lib/mongo_doc/contexts.rb +31 -0
  52. data/lib/mongo_doc/contexts/ids.rb +41 -0
  53. data/lib/mongo_doc/contexts/mongo.rb +272 -0
  54. data/lib/mongo_doc/criteria.rb +70 -0
  55. data/lib/mongo_doc/cursor.rb +32 -0
  56. data/lib/mongo_doc/document.rb +205 -0
  57. data/lib/mongo_doc/ext.rb +16 -0
  58. data/lib/mongo_doc/ext/array.rb +5 -0
  59. data/lib/mongo_doc/ext/binary.rb +7 -0
  60. data/lib/mongo_doc/ext/boolean_class.rb +17 -0
  61. data/lib/mongo_doc/ext/date.rb +19 -0
  62. data/lib/mongo_doc/ext/date_time.rb +17 -0
  63. data/lib/mongo_doc/ext/dbref.rb +7 -0
  64. data/lib/mongo_doc/ext/hash.rb +7 -0
  65. data/lib/mongo_doc/ext/min_max_keys.rb +13 -0
  66. data/lib/mongo_doc/ext/nil_class.rb +5 -0
  67. data/lib/mongo_doc/ext/numeric.rb +17 -0
  68. data/lib/mongo_doc/ext/object.rb +19 -0
  69. data/lib/mongo_doc/ext/object_id.rb +7 -0
  70. data/lib/mongo_doc/ext/regexp.rb +5 -0
  71. data/lib/mongo_doc/ext/string.rb +5 -0
  72. data/lib/mongo_doc/ext/symbol.rb +5 -0
  73. data/lib/mongo_doc/ext/time.rb +9 -0
  74. data/lib/mongo_doc/finders.rb +38 -0
  75. data/lib/mongo_doc/index.rb +46 -0
  76. data/lib/mongo_doc/matchers.rb +35 -0
  77. data/lib/mongo_doc/root.rb +26 -0
  78. data/lib/mongo_doc/scope.rb +64 -0
  79. data/lib/mongo_doc/validations.rb +12 -0
  80. data/lib/mongo_doc/validations/macros.rb +11 -0
  81. data/lib/mongo_doc/validations/validates_embedded.rb +13 -0
  82. data/lib/mongoid/contexts/enumerable.rb +151 -0
  83. data/lib/mongoid/contexts/paging.rb +42 -0
  84. data/lib/mongoid/criteria.rb +239 -0
  85. data/lib/mongoid/criterion/complex.rb +21 -0
  86. data/lib/mongoid/criterion/exclusion.rb +65 -0
  87. data/lib/mongoid/criterion/inclusion.rb +93 -0
  88. data/lib/mongoid/criterion/optional.rb +136 -0
  89. data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
  90. data/lib/mongoid/extensions/symbol/inflections.rb +36 -0
  91. data/lib/mongoid/matchers/all.rb +11 -0
  92. data/lib/mongoid/matchers/default.rb +26 -0
  93. data/lib/mongoid/matchers/exists.rb +13 -0
  94. data/lib/mongoid/matchers/gt.rb +11 -0
  95. data/lib/mongoid/matchers/gte.rb +11 -0
  96. data/lib/mongoid/matchers/in.rb +11 -0
  97. data/lib/mongoid/matchers/lt.rb +11 -0
  98. data/lib/mongoid/matchers/lte.rb +11 -0
  99. data/lib/mongoid/matchers/ne.rb +11 -0
  100. data/lib/mongoid/matchers/nin.rb +11 -0
  101. data/lib/mongoid/matchers/size.rb +11 -0
  102. data/mongo_doc_rails2.gemspec +237 -0
  103. data/mongod.example.yml +2 -0
  104. data/mongodb.example.yml +14 -0
  105. data/perf/mongo_doc_object.rb +83 -0
  106. data/perf/mongo_document.rb +84 -0
  107. data/perf/ruby_driver.rb +49 -0
  108. data/script/console +8 -0
  109. data/spec/array_including_argument_matcher.rb +62 -0
  110. data/spec/associations/collection_proxy_spec.rb +233 -0
  111. data/spec/associations/document_proxy_spec.rb +45 -0
  112. data/spec/associations/hash_proxy_spec.rb +181 -0
  113. data/spec/associations/proxy_base_spec.rb +92 -0
  114. data/spec/associations_spec.rb +218 -0
  115. data/spec/attributes_accessor_spec.rb +33 -0
  116. data/spec/attributes_spec.rb +145 -0
  117. data/spec/bson_matchers.rb +54 -0
  118. data/spec/bson_spec.rb +196 -0
  119. data/spec/collection_spec.rb +169 -0
  120. data/spec/connection_spec.rb +147 -0
  121. data/spec/contexts/ids_spec.rb +49 -0
  122. data/spec/contexts/mongo_spec.rb +235 -0
  123. data/spec/contexts_spec.rb +56 -0
  124. data/spec/criteria_spec.rb +69 -0
  125. data/spec/cursor_spec.rb +91 -0
  126. data/spec/document_ext.rb +9 -0
  127. data/spec/document_spec.rb +553 -0
  128. data/spec/embedded_save_spec.rb +73 -0
  129. data/spec/ext_spec.rb +89 -0
  130. data/spec/finders_spec.rb +61 -0
  131. data/spec/hash_matchers.rb +27 -0
  132. data/spec/index_spec.rb +79 -0
  133. data/spec/matchers_spec.rb +342 -0
  134. data/spec/mongodb.yml +6 -0
  135. data/spec/mongodb_pairs.yml +8 -0
  136. data/spec/new_record_spec.rb +128 -0
  137. data/spec/root_spec.rb +41 -0
  138. data/spec/scope_spec.rb +79 -0
  139. data/spec/spec.opts +2 -0
  140. data/spec/spec_helper.rb +14 -0
  141. data/spec/validations_spec.rb +30 -0
  142. 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,5 @@
1
+ class Array
2
+ def to_bson(*args)
3
+ map {|item| item.to_bson(args)}
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ module BSON
2
+ class Binary
3
+ def to_bson(*args)
4
+ self
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ class Boolean
2
+ def self.cast_from_string(value)
3
+ value == '1' || value.downcase == 'true'
4
+ end
5
+ end
6
+
7
+ class FalseClass
8
+ def to_bson(*args)
9
+ self
10
+ end
11
+ end
12
+
13
+ class TrueClass
14
+ def to_bson(*args)
15
+ self
16
+ end
17
+ end
@@ -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,7 @@
1
+ module BSON
2
+ class DBRef
3
+ def to_bson(*args)
4
+ self
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class Hash
2
+ def to_bson(*args)
3
+ {}.tap do |hash|
4
+ each {|key, value| hash[key.to_s] = value.to_bson}
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ module BSON
2
+ class MaxKey
3
+ def to_bson(*args)
4
+ self
5
+ end
6
+ end
7
+
8
+ class MinKey
9
+ def to_bson(*args)
10
+ self
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ class NilClass
2
+ def to_bson(*args)
3
+ self
4
+ end
5
+ 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