mongoid 1.1.3 → 1.1.4

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 (60) hide show
  1. data/.watchr +20 -2
  2. data/VERSION +1 -1
  3. data/caliper.yml +4 -0
  4. data/lib/mongoid.rb +0 -1
  5. data/lib/mongoid/associations.rb +25 -13
  6. data/lib/mongoid/associations/belongs_to.rb +15 -17
  7. data/lib/mongoid/associations/belongs_to_related.rb +12 -14
  8. data/lib/mongoid/associations/has_many.rb +53 -35
  9. data/lib/mongoid/associations/has_many_related.rb +10 -15
  10. data/lib/mongoid/associations/has_one.rb +31 -30
  11. data/lib/mongoid/associations/has_one_related.rb +18 -20
  12. data/lib/mongoid/associations/options.rb +10 -0
  13. data/lib/mongoid/associations/proxy.rb +18 -1
  14. data/lib/mongoid/criteria.rb +9 -233
  15. data/lib/mongoid/criterion/complex.rb +21 -0
  16. data/lib/mongoid/criterion/exclusion.rb +63 -0
  17. data/lib/mongoid/criterion/inclusion.rb +91 -0
  18. data/lib/mongoid/criterion/optional.rb +96 -0
  19. data/lib/mongoid/document.rb +2 -2
  20. data/lib/mongoid/extensions/hash/accessors.rb +6 -0
  21. data/lib/mongoid/extensions/hash/criteria_helpers.rb +2 -2
  22. data/lib/mongoid/extensions/symbol/inflections.rb +1 -1
  23. data/mongoid.gemspec +53 -3
  24. data/spec/integration/mongoid/associations_spec.rb +41 -0
  25. data/spec/models/address.rb +39 -0
  26. data/spec/models/animal.rb +6 -0
  27. data/spec/models/comment.rb +8 -0
  28. data/spec/models/country_code.rb +6 -0
  29. data/spec/models/employer.rb +5 -0
  30. data/spec/models/game.rb +6 -0
  31. data/spec/models/inheritance.rb +56 -0
  32. data/spec/models/location.rb +5 -0
  33. data/spec/models/mixed_drink.rb +4 -0
  34. data/spec/models/name.rb +13 -0
  35. data/spec/models/namespacing.rb +11 -0
  36. data/spec/models/patient.rb +4 -0
  37. data/spec/models/person.rb +97 -0
  38. data/spec/models/pet.rb +7 -0
  39. data/spec/models/pet_owner.rb +6 -0
  40. data/spec/models/phone.rb +7 -0
  41. data/spec/models/post.rb +15 -0
  42. data/spec/models/translation.rb +5 -0
  43. data/spec/models/vet_visit.rb +5 -0
  44. data/spec/spec_helper.rb +9 -326
  45. data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +26 -5
  46. data/spec/unit/mongoid/associations/belongs_to_spec.rb +96 -30
  47. data/spec/unit/mongoid/associations/has_many_related_spec.rb +32 -12
  48. data/spec/unit/mongoid/associations/has_many_spec.rb +48 -12
  49. data/spec/unit/mongoid/associations/has_one_related_spec.rb +29 -4
  50. data/spec/unit/mongoid/associations/has_one_spec.rb +46 -1
  51. data/spec/unit/mongoid/associations/options_spec.rb +58 -0
  52. data/spec/unit/mongoid/associations_spec.rb +58 -1
  53. data/spec/unit/mongoid/criteria_spec.rb +71 -735
  54. data/spec/unit/mongoid/criterion/complex_spec.rb +19 -0
  55. data/spec/unit/mongoid/criterion/exclusion_spec.rb +75 -0
  56. data/spec/unit/mongoid/criterion/inclusion_spec.rb +213 -0
  57. data/spec/unit/mongoid/criterion/optional_spec.rb +244 -0
  58. data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +20 -0
  59. metadata +53 -3
  60. data/lib/mongoid/complex_criterion.rb +0 -10
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+ # Complex criterion are used when performing operations on symbols to get
5
+ # get a shorthand syntax for where clauses.
6
+ #
7
+ # Example:
8
+ #
9
+ # <tt>{ :field => { "$lt" => "value" } }</tt>
10
+ # becomes:
11
+ # <tt> { :field.lt => "value }</tt>
12
+ class Complex
13
+ attr_accessor :key, :operator
14
+
15
+ # Create the new complex criterion.
16
+ def initialize(opts = {})
17
+ @key, @operator = opts[:key], opts[:operator]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,63 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+ module Exclusion
5
+ # Adds a criterion to the +Criteria+ that specifies values that are not allowed
6
+ # to match any document in the database. The MongoDB conditional operator that
7
+ # will be used is "$ne".
8
+ #
9
+ # Options:
10
+ #
11
+ # attributes: A +Hash+ where the key is the field name and the value is a
12
+ # value that must not be equal to the corresponding field value in the database.
13
+ #
14
+ # Example:
15
+ #
16
+ # <tt>criteria.excludes(:field => "value1")</tt>
17
+ #
18
+ # <tt>criteria.excludes(:field1 => "value1", :field2 => "value1")</tt>
19
+ #
20
+ # Returns: <tt>self</tt>
21
+ def excludes(attributes = {})
22
+ update_selector(attributes, "$ne")
23
+ end
24
+
25
+ # Adds a criterion to the +Criteria+ that specifies values where none
26
+ # should match in order to return results. This is similar to an SQL "NOT IN"
27
+ # clause. The MongoDB conditional operator that will be used is "$nin".
28
+ #
29
+ # Options:
30
+ #
31
+ # exclusions: A +Hash+ where the key is the field name and the value is an
32
+ # +Array+ of values that none can match.
33
+ #
34
+ # Example:
35
+ #
36
+ # <tt>criteria.not_in(:field => ["value1", "value2"])</tt>
37
+ #
38
+ # <tt>criteria.not_in(:field1 => ["value1", "value2"], :field2 => ["value1"])</tt>
39
+ #
40
+ # Returns: <tt>self</tt>
41
+ def not_in(exclusions)
42
+ exclusions.each { |key, value| @selector[key] = { "$nin" => value } }; self
43
+ end
44
+
45
+ # Adds a criterion to the +Criteria+ that specifies the fields that will
46
+ # get returned from the Document. Used mainly for list views that do not
47
+ # require all fields to be present. This is similar to SQL "SELECT" values.
48
+ #
49
+ # Options:
50
+ #
51
+ # args: A list of field names to retrict the returned fields to.
52
+ #
53
+ # Example:
54
+ #
55
+ # <tt>criteria.only(:field1, :field2, :field3)</tt>
56
+ #
57
+ # Returns: <tt>self</tt>
58
+ def only(*args)
59
+ @options[:fields] = args.flatten if args.any?; self
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,91 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+ module Inclusion
5
+ # Adds a criterion to the +Criteria+ that specifies values that must all
6
+ # be matched in order to return results. Similar to an "in" clause but the
7
+ # underlying conditional logic is an "AND" and not an "OR". The MongoDB
8
+ # conditional operator that will be used is "$all".
9
+ #
10
+ # Options:
11
+ #
12
+ # attributes: A +Hash+ where the key is the field name and the value is an
13
+ # +Array+ of values that must all match.
14
+ #
15
+ # Example:
16
+ #
17
+ # <tt>criteria.all(:field => ["value1", "value2"])</tt>
18
+ #
19
+ # <tt>criteria.all(:field1 => ["value1", "value2"], :field2 => ["value1"])</tt>
20
+ #
21
+ # Returns: <tt>self</tt>
22
+ def all(attributes = {})
23
+ update_selector(attributes, "$all")
24
+ end
25
+
26
+ # Adds a criterion to the +Criteria+ that specifies values that must
27
+ # be matched in order to return results. This is similar to a SQL "WHERE"
28
+ # clause. This is the actual selector that will be provided to MongoDB,
29
+ # similar to the Javascript object that is used when performing a find()
30
+ # in the MongoDB console.
31
+ #
32
+ # Options:
33
+ #
34
+ # selectior: A +Hash+ that must match the attributes of the +Document+.
35
+ #
36
+ # Example:
37
+ #
38
+ # <tt>criteria.and(:field1 => "value1", :field2 => 15)</tt>
39
+ #
40
+ # Returns: <tt>self</tt>
41
+ def and(selector = nil)
42
+ where(selector)
43
+ end
44
+
45
+ # Adds a criterion to the +Criteria+ that specifies values where any can
46
+ # be matched in order to return results. This is similar to an SQL "IN"
47
+ # clause. The MongoDB conditional operator that will be used is "$in".
48
+ #
49
+ # Options:
50
+ #
51
+ # attributes: A +Hash+ where the key is the field name and the value is an
52
+ # +Array+ of values that any can match.
53
+ #
54
+ # Example:
55
+ #
56
+ # <tt>criteria.in(:field => ["value1", "value2"])</tt>
57
+ #
58
+ # <tt>criteria.in(:field1 => ["value1", "value2"], :field2 => ["value1"])</tt>
59
+ #
60
+ # Returns: <tt>self</tt>
61
+ def in(attributes = {})
62
+ update_selector(attributes, "$in")
63
+ end
64
+
65
+ # Adds a criterion to the +Criteria+ that specifies values that must
66
+ # be matched in order to return results. This is similar to a SQL "WHERE"
67
+ # clause. This is the actual selector that will be provided to MongoDB,
68
+ # similar to the Javascript object that is used when performing a find()
69
+ # in the MongoDB console.
70
+ #
71
+ # Options:
72
+ #
73
+ # selectior: A +Hash+ that must match the attributes of the +Document+.
74
+ #
75
+ # Example:
76
+ #
77
+ # <tt>criteria.where(:field1 => "value1", :field2 => 15)</tt>
78
+ #
79
+ # Returns: <tt>self</tt>
80
+ def where(selector = nil)
81
+ case selector
82
+ when String
83
+ @selector.update("$where" => selector)
84
+ else
85
+ @selector.update(selector ? selector.expand_complex_criteria : {})
86
+ end
87
+ self
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,96 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+ module Optional
5
+ # Adds a criterion to the +Criteria+ that specifies additional options
6
+ # to be passed to the Ruby driver, in the exact format for the driver.
7
+ #
8
+ # Options:
9
+ #
10
+ # extras: A +Hash+ that gets set to the driver options.
11
+ #
12
+ # Example:
13
+ #
14
+ # <tt>criteria.extras(:limit => 20, :skip => 40)</tt>
15
+ #
16
+ # Returns: <tt>self</tt>
17
+ def extras(extras)
18
+ @options.merge!(extras); filter_options; self
19
+ end
20
+
21
+ # Adds a criterion to the +Criteria+ that specifies an id that must be matched.
22
+ #
23
+ # Options:
24
+ #
25
+ # object_id: A +String+ representation of a <tt>Mongo::ObjectID</tt>
26
+ #
27
+ # Example:
28
+ #
29
+ # <tt>criteria.id("4ab2bc4b8ad548971900005c")</tt>
30
+ #
31
+ # Returns: <tt>self</tt>
32
+ def id(*args)
33
+ (args.flatten.size > 1) ? self.in(:_id => args.flatten) : (@selector[:_id] = args.first)
34
+ self
35
+ end
36
+
37
+ # Adds a criterion to the +Criteria+ that specifies the maximum number of
38
+ # results to return. This is mostly used in conjunction with <tt>skip()</tt>
39
+ # to handle paginated results.
40
+ #
41
+ # Options:
42
+ #
43
+ # value: An +Integer+ specifying the max number of results. Defaults to 20.
44
+ #
45
+ # Example:
46
+ #
47
+ # <tt>criteria.limit(100)</tt>
48
+ #
49
+ # Returns: <tt>self</tt>
50
+ def limit(value = 20)
51
+ @options[:limit] = value; self
52
+ end
53
+
54
+ # Returns the offset option. If a per_page option is in the list then it
55
+ # will replace it with a skip parameter and return the same value. Defaults
56
+ # to 20 if nothing was provided.
57
+ def offset
58
+ @options[:skip]
59
+ end
60
+
61
+ # Adds a criterion to the +Criteria+ that specifies the sort order of
62
+ # the returned documents in the database. Similar to a SQL "ORDER BY".
63
+ #
64
+ # Options:
65
+ #
66
+ # params: An +Array+ of [field, direction] sorting pairs.
67
+ #
68
+ # Example:
69
+ #
70
+ # <tt>criteria.order_by([[:field1, :asc], [:field2, :desc]])</tt>
71
+ #
72
+ # Returns: <tt>self</tt>
73
+ def order_by(params = [])
74
+ @options[:sort] = params; self
75
+ end
76
+
77
+ # Adds a criterion to the +Criteria+ that specifies how many results to skip
78
+ # when returning Documents. This is mostly used in conjunction with
79
+ # <tt>limit()</tt> to handle paginated results, and is similar to the
80
+ # traditional "offset" parameter.
81
+ #
82
+ # Options:
83
+ #
84
+ # value: An +Integer+ specifying the number of results to skip. Defaults to 0.
85
+ #
86
+ # Example:
87
+ #
88
+ # <tt>criteria.skip(20)</tt>
89
+ #
90
+ # Returns: <tt>self</tt>
91
+ def skip(value = 0)
92
+ @options[:skip] = value; self
93
+ end
94
+ end
95
+ end
96
+ end
@@ -262,8 +262,8 @@ module Mongoid #:nodoc:
262
262
  # Example:
263
263
  #
264
264
  # <tt>person.to_json</tt>
265
- def to_json
266
- attributes.to_json
265
+ def to_json(options=nil)
266
+ attributes.to_json(options)
267
267
  end
268
268
 
269
269
  # Returns the id of the Document, used in Rails compatibility.
@@ -26,6 +26,12 @@ module Mongoid #:nodoc:
26
26
  self[key] = key.singular? ? attrs : [attrs]
27
27
  end
28
28
  end
29
+
30
+ # If a _type key exists in the hash, return the class for the value.
31
+ def klass
32
+ class_name = self["_type"]
33
+ class_name ? class_name.constantize : nil
34
+ end
29
35
  end
30
36
  end
31
37
  end
@@ -6,7 +6,7 @@ module Mongoid #:nodoc:
6
6
  def expand_complex_criteria
7
7
  hsh = {}
8
8
  self.each_pair do |k,v|
9
- if k.class == Mongoid::ComplexCriterion
9
+ if k.class == Mongoid::Criterion::Complex
10
10
  hsh[k.key] = {"$#{k.operator}" => v}
11
11
  else
12
12
  hsh[k] = v
@@ -17,4 +17,4 @@ module Mongoid #:nodoc:
17
17
  end
18
18
  end
19
19
  end
20
- end
20
+ end
@@ -26,7 +26,7 @@ module Mongoid #:nodoc:
26
26
  ["gt", "lt", "gte", "lte", "ne", "in", "nin", "mod", "all", "size", "exists"].each do |oper|
27
27
  class_eval <<-OPERATORS
28
28
  def #{oper}
29
- ComplexCriterion.new(:key => self, :operator => "#{oper}")
29
+ Criterion::Complex.new(:key => self, :operator => "#{oper}")
30
30
  end
31
31
  OPERATORS
32
32
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mongoid}
8
- s.version = "1.1.3"
8
+ s.version = "1.1.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Durran Jordan"]
12
- s.date = %q{2010-01-24}
12
+ s.date = %q{2010-01-26}
13
13
  s.email = %q{durran@gmail.com}
14
14
  s.extra_rdoc_files = [
15
15
  "README.rdoc"
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
22
22
  "README.rdoc",
23
23
  "Rakefile",
24
24
  "VERSION",
25
+ "caliper.yml",
25
26
  "lib/mongoid.rb",
26
27
  "lib/mongoid/associations.rb",
27
28
  "lib/mongoid/associations/belongs_to.rb",
@@ -42,7 +43,6 @@ Gem::Specification.new do |s|
42
43
  "lib/mongoid/commands/destroy.rb",
43
44
  "lib/mongoid/commands/destroy_all.rb",
44
45
  "lib/mongoid/commands/save.rb",
45
- "lib/mongoid/complex_criterion.rb",
46
46
  "lib/mongoid/components.rb",
47
47
  "lib/mongoid/config.rb",
48
48
  "lib/mongoid/contexts.rb",
@@ -50,6 +50,10 @@ Gem::Specification.new do |s|
50
50
  "lib/mongoid/contexts/mongo.rb",
51
51
  "lib/mongoid/contexts/paging.rb",
52
52
  "lib/mongoid/criteria.rb",
53
+ "lib/mongoid/criterion/complex.rb",
54
+ "lib/mongoid/criterion/exclusion.rb",
55
+ "lib/mongoid/criterion/inclusion.rb",
56
+ "lib/mongoid/criterion/optional.rb",
53
57
  "lib/mongoid/document.rb",
54
58
  "lib/mongoid/errors.rb",
55
59
  "lib/mongoid/extensions.rb",
@@ -107,6 +111,25 @@ Gem::Specification.new do |s|
107
111
  "spec/integration/mongoid/finders_spec.rb",
108
112
  "spec/integration/mongoid/inheritance_spec.rb",
109
113
  "spec/integration/mongoid/named_scope_spec.rb",
114
+ "spec/models/address.rb",
115
+ "spec/models/animal.rb",
116
+ "spec/models/comment.rb",
117
+ "spec/models/country_code.rb",
118
+ "spec/models/employer.rb",
119
+ "spec/models/game.rb",
120
+ "spec/models/inheritance.rb",
121
+ "spec/models/location.rb",
122
+ "spec/models/mixed_drink.rb",
123
+ "spec/models/name.rb",
124
+ "spec/models/namespacing.rb",
125
+ "spec/models/patient.rb",
126
+ "spec/models/person.rb",
127
+ "spec/models/pet.rb",
128
+ "spec/models/pet_owner.rb",
129
+ "spec/models/phone.rb",
130
+ "spec/models/post.rb",
131
+ "spec/models/translation.rb",
132
+ "spec/models/vet_visit.rb",
110
133
  "spec/spec.opts",
111
134
  "spec/spec_helper.rb",
112
135
  "spec/unit/mongoid/associations/belongs_to_related_spec.rb",
@@ -130,6 +153,10 @@ Gem::Specification.new do |s|
130
153
  "spec/unit/mongoid/contexts/enumerable_spec.rb",
131
154
  "spec/unit/mongoid/contexts/mongo_spec.rb",
132
155
  "spec/unit/mongoid/criteria_spec.rb",
156
+ "spec/unit/mongoid/criterion/complex_spec.rb",
157
+ "spec/unit/mongoid/criterion/exclusion_spec.rb",
158
+ "spec/unit/mongoid/criterion/inclusion_spec.rb",
159
+ "spec/unit/mongoid/criterion/optional_spec.rb",
133
160
  "spec/unit/mongoid/document_spec.rb",
134
161
  "spec/unit/mongoid/errors_spec.rb",
135
162
  "spec/unit/mongoid/extensions/array/accessors_spec.rb",
@@ -192,6 +219,25 @@ Gem::Specification.new do |s|
192
219
  "spec/integration/mongoid/finders_spec.rb",
193
220
  "spec/integration/mongoid/inheritance_spec.rb",
194
221
  "spec/integration/mongoid/named_scope_spec.rb",
222
+ "spec/models/address.rb",
223
+ "spec/models/animal.rb",
224
+ "spec/models/comment.rb",
225
+ "spec/models/country_code.rb",
226
+ "spec/models/employer.rb",
227
+ "spec/models/game.rb",
228
+ "spec/models/inheritance.rb",
229
+ "spec/models/location.rb",
230
+ "spec/models/mixed_drink.rb",
231
+ "spec/models/name.rb",
232
+ "spec/models/namespacing.rb",
233
+ "spec/models/patient.rb",
234
+ "spec/models/person.rb",
235
+ "spec/models/pet.rb",
236
+ "spec/models/pet_owner.rb",
237
+ "spec/models/phone.rb",
238
+ "spec/models/post.rb",
239
+ "spec/models/translation.rb",
240
+ "spec/models/vet_visit.rb",
195
241
  "spec/spec_helper.rb",
196
242
  "spec/unit/mongoid/associations/belongs_to_related_spec.rb",
197
243
  "spec/unit/mongoid/associations/belongs_to_spec.rb",
@@ -214,6 +260,10 @@ Gem::Specification.new do |s|
214
260
  "spec/unit/mongoid/contexts/enumerable_spec.rb",
215
261
  "spec/unit/mongoid/contexts/mongo_spec.rb",
216
262
  "spec/unit/mongoid/criteria_spec.rb",
263
+ "spec/unit/mongoid/criterion/complex_spec.rb",
264
+ "spec/unit/mongoid/criterion/exclusion_spec.rb",
265
+ "spec/unit/mongoid/criterion/inclusion_spec.rb",
266
+ "spec/unit/mongoid/criterion/optional_spec.rb",
217
267
  "spec/unit/mongoid/document_spec.rb",
218
268
  "spec/unit/mongoid/errors_spec.rb",
219
269
  "spec/unit/mongoid/extensions/array/accessors_spec.rb",
@@ -8,6 +8,47 @@ describe Mongoid::Associations do
8
8
  Post.delete_all
9
9
  end
10
10
 
11
+ context "anonymous extensions" do
12
+
13
+ before do
14
+ @person = Person.new(:title => "Dr")
15
+ @address_one = Address.new(:street => "Oxford")
16
+ @address_two = Address.new(:street => "Bond")
17
+ @name = Name.new(:first_name => "Richard", :last_name => "Dawkins")
18
+ @person.addresses << [ @address_one, @address_two ]
19
+ @person.name = @name
20
+ @person.save
21
+ end
22
+
23
+ context "when defined on a has_many" do
24
+
25
+ it "applies the extension" do
26
+ addresses = @person.addresses.find_by_street("Oxford")
27
+ addresses.size.should == 1
28
+ addresses.first.should == @address_one
29
+ end
30
+
31
+ end
32
+
33
+ context "when defined on a has_one" do
34
+
35
+ it "applies the extension" do
36
+ name = @person.name
37
+ name.dawkins?.should be_true
38
+ end
39
+
40
+ end
41
+
42
+ context "when defined on a belongs_to" do
43
+
44
+ it "applies the extension" do
45
+ @address_two.addressable.doctor?.should be_true
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+
11
52
  context "criteria on has many embedded associations" do
12
53
 
13
54
  before do