mongo_doc 0.3.0

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 (122) hide show
  1. data/.document +5 -0
  2. data/.gitignore +7 -0
  3. data/LICENSE +20 -0
  4. data/README.textile +174 -0
  5. data/Rakefile +135 -0
  6. data/TODO +31 -0
  7. data/VERSION +1 -0
  8. data/data/.gitignore +2 -0
  9. data/examples/simple_document.rb +35 -0
  10. data/examples/simple_object.rb +30 -0
  11. data/features/finders.feature +76 -0
  12. data/features/mongodb.yml +7 -0
  13. data/features/mongodoc_base.feature +128 -0
  14. data/features/new_record.feature +36 -0
  15. data/features/partial_updates.feature +105 -0
  16. data/features/removing_documents.feature +68 -0
  17. data/features/saving_an_object.feature +15 -0
  18. data/features/scopes.feature +66 -0
  19. data/features/step_definitions/collection_steps.rb +14 -0
  20. data/features/step_definitions/document_steps.rb +149 -0
  21. data/features/step_definitions/documents.rb +30 -0
  22. data/features/step_definitions/finder_steps.rb +15 -0
  23. data/features/step_definitions/json_steps.rb +9 -0
  24. data/features/step_definitions/object_steps.rb +50 -0
  25. data/features/step_definitions/objects.rb +24 -0
  26. data/features/step_definitions/partial_update_steps.rb +32 -0
  27. data/features/step_definitions/query_steps.rb +54 -0
  28. data/features/step_definitions/removing_documents_steps.rb +14 -0
  29. data/features/step_definitions/scope_steps.rb +18 -0
  30. data/features/step_definitions/util_steps.rb +7 -0
  31. data/features/support/support.rb +10 -0
  32. data/features/using_criteria.feature +128 -0
  33. data/lib/mongo_doc/associations/collection_proxy.rb +105 -0
  34. data/lib/mongo_doc/associations/document_proxy.rb +56 -0
  35. data/lib/mongo_doc/associations/hash_proxy.rb +98 -0
  36. data/lib/mongo_doc/associations/proxy_base.rb +53 -0
  37. data/lib/mongo_doc/attributes.rb +140 -0
  38. data/lib/mongo_doc/bson.rb +45 -0
  39. data/lib/mongo_doc/collection.rb +55 -0
  40. data/lib/mongo_doc/connection.rb +88 -0
  41. data/lib/mongo_doc/contexts/enumerable.rb +128 -0
  42. data/lib/mongo_doc/contexts/ids.rb +41 -0
  43. data/lib/mongo_doc/contexts/mongo.rb +232 -0
  44. data/lib/mongo_doc/contexts.rb +25 -0
  45. data/lib/mongo_doc/criteria.rb +38 -0
  46. data/lib/mongo_doc/cursor.rb +32 -0
  47. data/lib/mongo_doc/document.rb +216 -0
  48. data/lib/mongo_doc/ext/array.rb +5 -0
  49. data/lib/mongo_doc/ext/binary.rb +7 -0
  50. data/lib/mongo_doc/ext/boolean_class.rb +11 -0
  51. data/lib/mongo_doc/ext/date.rb +16 -0
  52. data/lib/mongo_doc/ext/date_time.rb +13 -0
  53. data/lib/mongo_doc/ext/dbref.rb +7 -0
  54. data/lib/mongo_doc/ext/hash.rb +7 -0
  55. data/lib/mongo_doc/ext/nil_class.rb +5 -0
  56. data/lib/mongo_doc/ext/numeric.rb +17 -0
  57. data/lib/mongo_doc/ext/object.rb +17 -0
  58. data/lib/mongo_doc/ext/object_id.rb +7 -0
  59. data/lib/mongo_doc/ext/regexp.rb +5 -0
  60. data/lib/mongo_doc/ext/string.rb +5 -0
  61. data/lib/mongo_doc/ext/symbol.rb +5 -0
  62. data/lib/mongo_doc/ext/time.rb +5 -0
  63. data/lib/mongo_doc/finders.rb +49 -0
  64. data/lib/mongo_doc/matchers.rb +35 -0
  65. data/lib/mongo_doc/query.rb +7 -0
  66. data/lib/mongo_doc/scope.rb +64 -0
  67. data/lib/mongo_doc/validations/macros.rb +11 -0
  68. data/lib/mongo_doc/validations/validates_embedded.rb +13 -0
  69. data/lib/mongo_doc.rb +19 -0
  70. data/lib/mongoid/contexts/paging.rb +42 -0
  71. data/lib/mongoid/criteria.rb +247 -0
  72. data/lib/mongoid/criterion/complex.rb +21 -0
  73. data/lib/mongoid/criterion/exclusion.rb +65 -0
  74. data/lib/mongoid/criterion/inclusion.rb +92 -0
  75. data/lib/mongoid/criterion/optional.rb +136 -0
  76. data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
  77. data/lib/mongoid/extensions/symbol/inflections.rb +36 -0
  78. data/lib/mongoid/matchers/all.rb +11 -0
  79. data/lib/mongoid/matchers/default.rb +26 -0
  80. data/lib/mongoid/matchers/exists.rb +13 -0
  81. data/lib/mongoid/matchers/gt.rb +11 -0
  82. data/lib/mongoid/matchers/gte.rb +11 -0
  83. data/lib/mongoid/matchers/in.rb +11 -0
  84. data/lib/mongoid/matchers/lt.rb +11 -0
  85. data/lib/mongoid/matchers/lte.rb +11 -0
  86. data/lib/mongoid/matchers/ne.rb +11 -0
  87. data/lib/mongoid/matchers/nin.rb +11 -0
  88. data/lib/mongoid/matchers/size.rb +11 -0
  89. data/mongo_doc.gemspec +205 -0
  90. data/mongod.example.yml +2 -0
  91. data/mongodb.example.yml +14 -0
  92. data/perf/mongo_doc_runner.rb +90 -0
  93. data/perf/ruby_driver_runner.rb +64 -0
  94. data/script/console +8 -0
  95. data/spec/associations/collection_proxy_spec.rb +200 -0
  96. data/spec/associations/document_proxy_spec.rb +42 -0
  97. data/spec/associations/hash_proxy_spec.rb +163 -0
  98. data/spec/attributes_spec.rb +273 -0
  99. data/spec/bson_matchers.rb +54 -0
  100. data/spec/bson_spec.rb +196 -0
  101. data/spec/collection_spec.rb +161 -0
  102. data/spec/connection_spec.rb +147 -0
  103. data/spec/contexts/enumerable_spec.rb +274 -0
  104. data/spec/contexts/ids_spec.rb +49 -0
  105. data/spec/contexts/mongo_spec.rb +198 -0
  106. data/spec/contexts_spec.rb +28 -0
  107. data/spec/criteria_spec.rb +33 -0
  108. data/spec/cursor_spec.rb +91 -0
  109. data/spec/document_ext.rb +9 -0
  110. data/spec/document_spec.rb +664 -0
  111. data/spec/embedded_save_spec.rb +109 -0
  112. data/spec/finders_spec.rb +73 -0
  113. data/spec/hash_matchers.rb +27 -0
  114. data/spec/matchers_spec.rb +342 -0
  115. data/spec/mongodb.yml +6 -0
  116. data/spec/mongodb_pairs.yml +8 -0
  117. data/spec/new_record_spec.rb +128 -0
  118. data/spec/query_spec.rb +12 -0
  119. data/spec/scope_spec.rb +79 -0
  120. data/spec/spec.opts +2 -0
  121. data/spec/spec_helper.rb +13 -0
  122. metadata +290 -0
@@ -0,0 +1,55 @@
1
+ require 'mongo_doc/cursor'
2
+
3
+ module MongoDoc
4
+ class Collection
5
+ attr_accessor :_collection
6
+
7
+ delegate :[], :clear, :count, :create_index, :db, :distinct, :drop, :drop_index, :drop_indexes, :group, :hint, :index_information, :map_reduce, :mapreduce, :name, :options, :pk_factory, :remove, :rename, :size, :to => :_collection
8
+
9
+ def initialize(name)
10
+ self._collection = self.class.mongo_collection(name)
11
+ end
12
+
13
+ def find(query = {}, options = {})
14
+ cursor = wrapped_cursor(query, options)
15
+ if block_given?
16
+ yield cursor
17
+ cursor.close
18
+ else
19
+ cursor
20
+ end
21
+ end
22
+
23
+ def find_one(spec_or_object_id = nil, options = {})
24
+ MongoDoc::BSON.decode(_collection.find_one(spec_or_object_id, options))
25
+ end
26
+
27
+ def insert(doc_or_docs, options = {})
28
+ _collection.insert(doc_or_docs.to_bson, options)
29
+ end
30
+ alias :<< :insert
31
+
32
+ def save(doc, options = {})
33
+ _collection.save(doc.to_bson, options)
34
+ end
35
+
36
+ def update(spec, doc, options = {})
37
+ _collection.update(spec, doc.to_bson, options)
38
+ (last_error || {})['updatedExisting'] || false
39
+ end
40
+
41
+ protected
42
+
43
+ def last_error
44
+ MongoDoc::Connection.database.command({'getlasterror' => 1})
45
+ end
46
+
47
+ def wrapped_cursor(query = {}, options = {})
48
+ MongoDoc::Cursor.new(self, _collection.find(query, options))
49
+ end
50
+
51
+ def self.mongo_collection(name)
52
+ MongoDoc::Connection.database.collection(name)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,88 @@
1
+ module MongoDoc
2
+ class NoConnectionError < RuntimeError; end
3
+ class UnsupportedServerVersionError < RuntimeError; end
4
+
5
+ module Connection
6
+
7
+ extend self
8
+
9
+ attr_writer :config_path, :env, :host, :name, :options, :port, :strict
10
+
11
+ def config_path
12
+ @config_path || default_path
13
+ end
14
+
15
+ def configuration
16
+ @configuration ||= File.exists?(config_path) ? YAML.load_file(config_path)[env] : {}
17
+ end
18
+
19
+ def connection
20
+ @connection ||= connect
21
+ end
22
+
23
+ def database
24
+ @database ||= connection.db(name, :strict => strict)
25
+ end
26
+
27
+ def env
28
+ if rails?
29
+ Rails.env
30
+ else
31
+ @env ||= 'development'
32
+ end
33
+ end
34
+
35
+ def host
36
+ @host ||= configuration['host']
37
+ end
38
+
39
+ def name
40
+ @name ||= configuration['name'] || default_name
41
+ end
42
+
43
+ def options
44
+ @options ||= configuration['options'] || {}
45
+ end
46
+
47
+ def port
48
+ @port ||= configuration['port']
49
+ end
50
+
51
+ def strict
52
+ @strict ||= configuration['strict'] || false
53
+ end
54
+
55
+ private
56
+
57
+ def connect
58
+ connection = Mongo::Connection.new(host, port, options)
59
+ raise NoConnectionError unless connection
60
+ verify_server_version(connection)
61
+ connection
62
+ end
63
+
64
+ def default_name
65
+ if rails?
66
+ "#{Rails.root.basename}_#{Rails.env}"
67
+ else
68
+ "mongo_doc"
69
+ end
70
+ end
71
+
72
+ def default_path
73
+ if rails?
74
+ Rails.root + 'config/mongodb.yml'
75
+ else
76
+ './mongodb.yml'
77
+ end
78
+ end
79
+
80
+ def rails?
81
+ Object.const_defined?("Rails")
82
+ end
83
+
84
+ def verify_server_version(connection)
85
+ raise UnsupportedServerVersionError.new('MongoDoc requires at least mongoDB version 1.3.2') unless connection.server_version >= "1.3.2"
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,128 @@
1
+ # encoding: utf-8
2
+ module MongoDoc #:nodoc:
3
+ module Contexts #:nodoc:
4
+ class Enumerable
5
+ include Mongoid::Contexts::Paging
6
+ include MongoDoc::Contexts::Ids
7
+
8
+ attr_reader :criteria
9
+
10
+ delegate :first, :last, :to => :execute
11
+ delegate :documents, :options, :selector, :to => :criteria
12
+
13
+ # Return aggregation counts of the grouped documents. This will count by
14
+ # the first field provided in the fields array.
15
+ #
16
+ # Returns:
17
+ #
18
+ # A +Hash+ with field values as keys, count as values
19
+ def aggregate
20
+ counts = {}
21
+ group.each_pair { |key, value| counts[key] = value.size }
22
+ counts
23
+ end
24
+
25
+ # Gets the number of documents in the array. Delegates to size.
26
+ def count
27
+ @count ||= documents.size
28
+ end
29
+
30
+ # Groups the documents by the first field supplied in the field options.
31
+ #
32
+ # Returns:
33
+ #
34
+ # A +Hash+ with field values as keys, arrays of documents as values.
35
+ def group
36
+ field = options[:fields].first
37
+ documents.group_by { |doc| doc.send(field) }
38
+ end
39
+
40
+ # Enumerable implementation of execute. Returns matching documents for
41
+ # the selector, and adds options if supplied.
42
+ #
43
+ # Returns:
44
+ #
45
+ # An +Array+ of documents that matched the selector.
46
+ def execute(paginating = false)
47
+ limit(documents.select { |document| document.matches?(selector) })
48
+ end
49
+
50
+ # Create the new enumerable context. This will need the selector and
51
+ # options from a +Criteria+ and a documents array that is the underlying
52
+ # array of embedded documents from a has many association.
53
+ #
54
+ # Example:
55
+ #
56
+ # <tt>MongoDoc::Contexts::Enumerable.new(criteria)</tt>
57
+ def initialize(criteria)
58
+ @criteria = criteria
59
+ end
60
+
61
+ # Iterate over each +Document+ in the results. This can take an optional
62
+ # block to pass to each argument in the results.
63
+ #
64
+ # Example:
65
+ #
66
+ # <tt>context.iterate { |doc| p doc }</tt>
67
+ def iterate(&block)
68
+ execute.each(&block)
69
+ end
70
+
71
+ # Get the largest value for the field in all the documents.
72
+ #
73
+ # Returns:
74
+ #
75
+ # The numerical largest value.
76
+ def max(field)
77
+ determine(field, :>=)
78
+ end
79
+
80
+ # Get the smallest value for the field in all the documents.
81
+ #
82
+ # Returns:
83
+ #
84
+ # The numerical smallest value.
85
+ def min(field)
86
+ determine(field, :<=)
87
+ end
88
+
89
+ # Get one document.
90
+ #
91
+ # Returns:
92
+ #
93
+ # The first document in the +Array+
94
+ alias :one :first
95
+
96
+ # Get the sum of the field values for all the documents.
97
+ #
98
+ # Returns:
99
+ #
100
+ # The numerical sum of all the document field values.
101
+ def sum(field)
102
+ sum = documents.inject(nil) do |memo, doc|
103
+ value = doc.send(field)
104
+ memo ? memo += value : value
105
+ end
106
+ end
107
+
108
+ protected
109
+ # If the field exists, perform the comparison and set if true.
110
+ def determine(field, operator)
111
+ matching = documents.inject(nil) do |memo, doc|
112
+ value = doc.send(field)
113
+ (memo && memo.send(operator, value)) ? memo : value
114
+ end
115
+ end
116
+
117
+ # Limits the result set if skip and limit options.
118
+ def limit(documents)
119
+ skip, limit = options[:skip], options[:limit]
120
+ if skip && limit
121
+ return documents.slice(skip, limit)
122
+ end
123
+ documents
124
+ end
125
+ end
126
+ end
127
+ end
128
+
@@ -0,0 +1,41 @@
1
+ module MongoDoc
2
+ module Contexts
3
+ module Ids
4
+ # Return documents based on an id search. Will handle if a single id has
5
+ # been passed or mulitple ids.
6
+ #
7
+ # Example:
8
+ #
9
+ # context.id_criteria([1, 2, 3])
10
+ #
11
+ # Returns:
12
+ #
13
+ # The single or multiple documents.
14
+ def id_criteria(params)
15
+ criteria.id(strings_to_object_ids(params))
16
+ params.is_a?(Array) ? criteria.entries : one
17
+ end
18
+
19
+ protected
20
+
21
+ # Convert ids from strings to +Mongo::ObjectID+s
22
+ def strings_to_object_ids(ids)
23
+ if Array === ids
24
+ ids.map {|id| string_to_object_id(id) }
25
+ else
26
+ string_to_object_id(ids)
27
+ end
28
+
29
+ end
30
+
31
+ # Convert ids from strings to +Mongo::ObjectID+s
32
+ def string_to_object_id(id)
33
+ if String === id
34
+ ::Mongo::ObjectID.from_string(id)
35
+ else
36
+ id
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,232 @@
1
+ module MongoDoc
2
+ module Contexts
3
+ class Mongo
4
+ include Mongoid::Contexts::Paging
5
+ include MongoDoc::Contexts::Ids
6
+
7
+ attr_reader :criteria, :cache
8
+
9
+ delegate :klass, :options, :selector, :to => :criteria
10
+ delegate :collection, :to => :klass
11
+
12
+ AGGREGATE_REDUCE = "function(obj, prev) { prev.count++; }"
13
+ # Aggregate the context. This will take the internally built selector and options
14
+ # and pass them on to the Ruby driver's +group()+ method on the collection. The
15
+ # collection itself will be retrieved from the class provided, and once the
16
+ # query has returned it will provided a grouping of keys with counts.
17
+ #
18
+ # Example:
19
+ #
20
+ # <tt>context.aggregate</tt>
21
+ #
22
+ # Returns:
23
+ #
24
+ # A +Hash+ with field values as keys, counts as values
25
+ def aggregate
26
+ collection.group(options[:fields], selector, { :count => 0 }, AGGREGATE_REDUCE, true)
27
+ end
28
+
29
+ # Get the count of matching documents in the database for the context.
30
+ #
31
+ # Example:
32
+ #
33
+ # <tt>context.count</tt>
34
+ #
35
+ # Returns:
36
+ #
37
+ # An +Integer+ count of documents.
38
+ def count
39
+ @count ||= collection.find(selector, options).count
40
+ end
41
+
42
+ # Execute the context. This will take the selector and options
43
+ # and pass them on to the Ruby driver's +find()+ method on the collection. The
44
+ # collection itself will be retrieved from the class provided, and once the
45
+ # query has returned new documents of the type of class provided will be instantiated.
46
+ #
47
+ # Example:
48
+ #
49
+ # <tt>mongo.execute</tt>
50
+ #
51
+ # Returns:
52
+ #
53
+ # An enumerable +Cursor+.
54
+ def execute(paginating = false)
55
+ cursor = collection.find(selector, options)
56
+ if cursor
57
+ @count = cursor.count if paginating
58
+ cursor
59
+ else
60
+ []
61
+ end
62
+ end
63
+
64
+ GROUP_REDUCE = "function(obj, prev) { prev.group.push(obj); }"
65
+ # Groups the context. This will take the internally built selector and options
66
+ # and pass them on to the Ruby driver's +group()+ method on the collection. The
67
+ # collection itself will be retrieved from the class provided, and once the
68
+ # query has returned it will provided a grouping of keys with objects.
69
+ #
70
+ # Example:
71
+ #
72
+ # <tt>context.group</tt>
73
+ #
74
+ # Returns:
75
+ #
76
+ # A +Hash+ with field values as keys, arrays of documents as values.
77
+ def group
78
+ collection.group(
79
+ options[:fields],
80
+ selector,
81
+ { :group => [] },
82
+ GROUP_REDUCE,
83
+ true
84
+ ).collect {|docs| docs["group"] = MongoDoc::BSON.decode(docs["group"]); docs }
85
+ end
86
+
87
+ # Create the new mongo context. This will execute the queries given the
88
+ # selector and options against the database.
89
+ #
90
+ # Example:
91
+ #
92
+ # <tt>Mongoid::Contexts::Mongo.new(criteria)</tt>
93
+ def initialize(criteria)
94
+ @criteria = criteria
95
+ end
96
+
97
+ # Iterate over each +Document+ in the results. This can take an optional
98
+ # block to pass to each argument in the results.
99
+ #
100
+ # Example:
101
+ #
102
+ # <tt>context.iterate { |doc| p doc }</tt>
103
+ def iterate(&block)
104
+ return caching(&block) if criteria.cached?
105
+ if block_given?
106
+ execute.each do |doc|
107
+ yield doc
108
+ end
109
+ end
110
+ end
111
+
112
+ # Return the last result for the +Context+. Essentially does a find_one on
113
+ # the collection with the sorting reversed. If no sorting parameters have
114
+ # been provided it will default to ids.
115
+ #
116
+ # Example:
117
+ #
118
+ # <tt>context.last</tt>
119
+ #
120
+ # Returns:
121
+ #
122
+ # The last document in the collection.
123
+ def last
124
+ sorting = options[:sort] || [[:_id, :asc]]
125
+ options[:sort] = sorting.collect { |option| [ option[0], option[1].invert ] }
126
+ collection.find_one(selector, options)
127
+ end
128
+
129
+ MAX_REDUCE = "function(obj, prev) { if (prev.max == 'start') { prev.max = obj.[field]; } " +
130
+ "if (prev.max < obj.[field]) { prev.max = obj.[field]; } }"
131
+ # Return the max value for a field.
132
+ #
133
+ # This will take the internally built selector and options
134
+ # and pass them on to the Ruby driver's +group()+ method on the collection. The
135
+ # collection itself will be retrieved from the class provided, and once the
136
+ # query has returned it will provided a grouping of keys with sums.
137
+ #
138
+ # Example:
139
+ #
140
+ # <tt>context.max(:age)</tt>
141
+ #
142
+ # Returns:
143
+ #
144
+ # A numeric max value.
145
+ def max(field)
146
+ grouped(:max, field.to_s, MAX_REDUCE)
147
+ end
148
+
149
+ MIN_REDUCE = "function(obj, prev) { if (prev.min == 'start') { prev.min = obj.[field]; } " +
150
+ "if (prev.min > obj.[field]) { prev.min = obj.[field]; } }"
151
+ # Return the min value for a field.
152
+ #
153
+ # This will take the internally built selector and options
154
+ # and pass them on to the Ruby driver's +group()+ method on the collection. The
155
+ # collection itself will be retrieved from the class provided, and once the
156
+ # query has returned it will provided a grouping of keys with sums.
157
+ #
158
+ # Example:
159
+ #
160
+ # <tt>context.min(:age)</tt>
161
+ #
162
+ # Returns:
163
+ #
164
+ # A numeric minimum value.
165
+ def min(field)
166
+ grouped(:min, field.to_s, MIN_REDUCE)
167
+ end
168
+
169
+ # Return the first result for the +Context+.
170
+ #
171
+ # Example:
172
+ #
173
+ # <tt>context.one</tt>
174
+ #
175
+ # Return:
176
+ #
177
+ # The first document in the collection.
178
+ def one
179
+ collection.find_one(selector, options)
180
+ end
181
+
182
+ alias :first :one
183
+
184
+ SUM_REDUCE = "function(obj, prev) { if (prev.sum == 'start') { prev.sum = 0; } prev.sum += obj.[field]; }"
185
+ # Sum the context.
186
+ #
187
+ # This will take the internally built selector and options
188
+ # and pass them on to the Ruby driver's +group()+ method on the collection. The
189
+ # collection itself will be retrieved from the class provided, and once the
190
+ # query has returned it will provided a grouping of keys with sums.
191
+ #
192
+ # Example:
193
+ #
194
+ # <tt>context.sum(:age)</tt>
195
+ #
196
+ # Returns:
197
+ #
198
+ # A numeric value that is the sum.
199
+ def sum(field)
200
+ grouped(:sum, field.to_s, SUM_REDUCE)
201
+ end
202
+
203
+ # Common functionality for grouping operations. Currently used by min, max
204
+ # and sum. Will gsub the field name in the supplied reduce function.
205
+ def grouped(start, field, reduce)
206
+ result = collection.group(
207
+ nil,
208
+ selector,
209
+ { start => "start" },
210
+ reduce.gsub("[field]", field),
211
+ true
212
+ )
213
+ result.empty? ? nil : result.first[start.to_s]
214
+ end
215
+
216
+ protected
217
+
218
+ # Iterate and cache results from execute
219
+ def caching(&block)
220
+ if cache
221
+ cache.each(&block)
222
+ else
223
+ @cache = []
224
+ execute.each do |doc|
225
+ @cache << doc
226
+ yield doc if block_given?
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ require "mongoid/contexts/paging"
3
+ require "mongo_doc/contexts/ids"
4
+ require "mongo_doc/contexts/enumerable"
5
+ require "mongo_doc/contexts/mongo"
6
+
7
+ module Mongoid
8
+ module Contexts
9
+ # Determines the context to be used for this criteria. If the class is an
10
+ # embedded document, then the context will be the array in the has_many
11
+ # association it is in. If the class is a root, then the database itself
12
+ # will be the context.
13
+ #
14
+ # Example:
15
+ #
16
+ # <tt>Contexts.context_for(criteria)</tt>
17
+ def self.context_for(criteria)
18
+ if criteria.klass.respond_to?(:collection)
19
+ return MongoDoc::Contexts::Mongo.new(criteria)
20
+ end
21
+ return MongoDoc::Contexts::Enumerable.new(criteria)
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,38 @@
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
+ Mongoid::Criteria.new(self)
14
+ end
15
+
16
+ delegate \
17
+ :and,
18
+ :any_in,
19
+ :cache,
20
+ :enslave,
21
+ :excludes,
22
+ :extras,
23
+ :id,
24
+ :in,
25
+ :limit,
26
+ :not_in,
27
+ :offset,
28
+ :only,
29
+ :order_by,
30
+ :page,
31
+ :per_page,
32
+ :skip,
33
+ :where, :to => :criteria
34
+ end
35
+ end
36
+
37
+ Hash.send(:include, Mongoid::Extensions::Hash::CriteriaHelpers)
38
+ 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