mongo_mapper 0.7.6 → 0.8.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 (134) hide show
  1. data/README.rdoc +4 -8
  2. data/bin/mmconsole +1 -1
  3. data/examples/keys.rb +37 -0
  4. data/examples/plugins.rb +41 -0
  5. data/examples/querying.rb +35 -0
  6. data/examples/scopes.rb +52 -0
  7. data/lib/mongo_mapper.rb +77 -97
  8. data/lib/mongo_mapper/connection.rb +83 -0
  9. data/lib/mongo_mapper/document.rb +10 -252
  10. data/lib/mongo_mapper/embedded_document.rb +7 -46
  11. data/lib/mongo_mapper/exceptions.rb +30 -0
  12. data/lib/mongo_mapper/extensions/array.rb +19 -0
  13. data/lib/mongo_mapper/extensions/binary.rb +22 -0
  14. data/lib/mongo_mapper/extensions/boolean.rb +44 -0
  15. data/lib/mongo_mapper/extensions/date.rb +25 -0
  16. data/lib/mongo_mapper/extensions/float.rb +14 -0
  17. data/lib/mongo_mapper/extensions/hash.rb +14 -0
  18. data/lib/mongo_mapper/extensions/integer.rb +19 -0
  19. data/lib/mongo_mapper/extensions/kernel.rb +9 -0
  20. data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
  21. data/lib/mongo_mapper/extensions/object.rb +27 -0
  22. data/lib/mongo_mapper/extensions/object_id.rb +30 -0
  23. data/lib/mongo_mapper/extensions/set.rb +20 -0
  24. data/lib/mongo_mapper/extensions/string.rb +18 -0
  25. data/lib/mongo_mapper/extensions/time.rb +29 -0
  26. data/lib/mongo_mapper/plugins.rb +1 -21
  27. data/lib/mongo_mapper/plugins/accessible.rb +44 -0
  28. data/lib/mongo_mapper/plugins/associations.rb +7 -24
  29. data/lib/mongo_mapper/plugins/associations/base.rb +1 -0
  30. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +5 -6
  31. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +5 -6
  32. data/lib/mongo_mapper/plugins/associations/collection.rb +1 -0
  33. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +2 -1
  34. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +22 -39
  35. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +4 -4
  36. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +22 -23
  37. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +1 -0
  38. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +1 -0
  39. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +1 -0
  40. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +2 -3
  41. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +6 -7
  42. data/lib/mongo_mapper/plugins/associations/proxy.rb +8 -6
  43. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  44. data/lib/mongo_mapper/plugins/callbacks.rb +4 -3
  45. data/lib/mongo_mapper/plugins/clone.rb +10 -4
  46. data/lib/mongo_mapper/plugins/descendants.rb +1 -0
  47. data/lib/mongo_mapper/plugins/dirty.rb +1 -0
  48. data/lib/mongo_mapper/plugins/document.rb +41 -0
  49. data/lib/mongo_mapper/plugins/dynamic_querying.rb +41 -0
  50. data/lib/mongo_mapper/{support/find.rb → plugins/dynamic_querying/dynamic_finder.rb} +3 -36
  51. data/lib/mongo_mapper/plugins/embedded_document.rb +49 -0
  52. data/lib/mongo_mapper/plugins/equality.rb +3 -9
  53. data/lib/mongo_mapper/plugins/identity_map.rb +8 -10
  54. data/lib/mongo_mapper/plugins/indexes.rb +12 -0
  55. data/lib/mongo_mapper/plugins/inspect.rb +1 -0
  56. data/lib/mongo_mapper/plugins/keys.rb +15 -27
  57. data/lib/mongo_mapper/plugins/keys/key.rb +14 -3
  58. data/lib/mongo_mapper/plugins/logger.rb +1 -0
  59. data/lib/mongo_mapper/plugins/modifiers.rb +3 -2
  60. data/lib/mongo_mapper/plugins/pagination.rb +5 -15
  61. data/lib/mongo_mapper/plugins/persistence.rb +12 -11
  62. data/lib/mongo_mapper/plugins/protected.rb +8 -0
  63. data/lib/mongo_mapper/plugins/querying.rb +236 -0
  64. data/lib/mongo_mapper/plugins/querying/decorator.rb +46 -0
  65. data/lib/mongo_mapper/plugins/rails.rb +1 -0
  66. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  67. data/lib/mongo_mapper/plugins/sci.rb +32 -0
  68. data/lib/mongo_mapper/plugins/scopes.rb +21 -0
  69. data/lib/mongo_mapper/plugins/serialization.rb +1 -0
  70. data/lib/mongo_mapper/plugins/timestamps.rb +1 -0
  71. data/lib/mongo_mapper/plugins/userstamps.rb +1 -0
  72. data/lib/mongo_mapper/plugins/validations.rb +5 -1
  73. data/lib/mongo_mapper/support/descendant_appends.rb +5 -6
  74. data/lib/mongo_mapper/version.rb +2 -1
  75. data/test/NOTE_ON_TESTING +1 -0
  76. data/test/active_model_lint_test.rb +13 -0
  77. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
  78. data/test/functional/associations/test_belongs_to_proxy.rb +93 -0
  79. data/test/functional/associations/test_in_array_proxy.rb +319 -0
  80. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  81. data/test/functional/associations/test_many_documents_proxy.rb +536 -0
  82. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  83. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  84. data/test/functional/associations/test_many_polymorphic_proxy.rb +302 -0
  85. data/test/functional/associations/test_one_embedded_proxy.rb +58 -0
  86. data/test/functional/associations/test_one_proxy.rb +182 -0
  87. data/test/functional/test_accessible.rb +168 -0
  88. data/test/functional/test_associations.rb +44 -0
  89. data/test/functional/test_binary.rb +27 -0
  90. data/test/functional/test_caching.rb +76 -0
  91. data/test/functional/test_callbacks.rb +151 -0
  92. data/test/functional/test_dirty.rb +163 -0
  93. data/test/functional/test_document.rb +253 -0
  94. data/test/functional/test_dynamic_querying.rb +75 -0
  95. data/test/functional/test_embedded_document.rb +210 -0
  96. data/test/functional/test_identity_map.rb +506 -0
  97. data/test/functional/test_indexes.rb +42 -0
  98. data/test/functional/test_logger.rb +20 -0
  99. data/test/functional/test_modifiers.rb +416 -0
  100. data/test/functional/test_pagination.rb +91 -0
  101. data/test/functional/test_protected.rb +175 -0
  102. data/test/functional/test_querying.rb +873 -0
  103. data/test/functional/test_safe.rb +76 -0
  104. data/test/functional/test_sci.rb +230 -0
  105. data/test/functional/test_scopes.rb +171 -0
  106. data/test/functional/test_string_id_compatibility.rb +67 -0
  107. data/test/functional/test_timestamps.rb +62 -0
  108. data/test/functional/test_userstamps.rb +27 -0
  109. data/test/functional/test_validations.rb +342 -0
  110. data/test/models.rb +227 -0
  111. data/test/test_helper.rb +98 -0
  112. data/test/unit/associations/test_base.rb +212 -0
  113. data/test/unit/associations/test_proxy.rb +105 -0
  114. data/test/unit/serializers/test_json_serializer.rb +202 -0
  115. data/test/unit/test_clone.rb +69 -0
  116. data/test/unit/test_descendant_appends.rb +71 -0
  117. data/test/unit/test_document.rb +213 -0
  118. data/test/unit/test_dynamic_finder.rb +125 -0
  119. data/test/unit/test_embedded_document.rb +644 -0
  120. data/test/unit/test_extensions.rb +380 -0
  121. data/test/unit/test_key.rb +185 -0
  122. data/test/unit/test_keys.rb +55 -0
  123. data/test/unit/test_mongo_mapper.rb +110 -0
  124. data/test/unit/test_pagination.rb +11 -0
  125. data/test/unit/test_plugins.rb +50 -0
  126. data/test/unit/test_rails.rb +181 -0
  127. data/test/unit/test_rails_compatibility.rb +52 -0
  128. data/test/unit/test_serialization.rb +51 -0
  129. data/test/unit/test_time_zones.rb +39 -0
  130. data/test/unit/test_validations.rb +544 -0
  131. metadata +113 -44
  132. data/lib/mongo_mapper/plugins/pagination/proxy.rb +0 -72
  133. data/lib/mongo_mapper/query.rb +0 -23
  134. data/lib/mongo_mapper/support.rb +0 -196
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
@@ -31,7 +32,7 @@ module MongoMapper
31
32
 
32
33
  private
33
34
  def assign_references(*docs)
34
- docs.each { |doc| doc._parent_document = owner }
35
+ docs.each { |doc| doc._parent_document = proxy_owner }
35
36
  end
36
37
  end
37
38
  end
@@ -1,57 +1,36 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
4
5
  class InArrayProxy < Collection
5
- include Support::Find
6
+ include MongoMapper::Plugins::DynamicQuerying::ClassMethods
6
7
 
7
8
  def find(*args)
8
- options = args.extract_options!
9
-
10
- case args.first
11
- when :first
12
- first(options)
13
- when :last
14
- last(options)
15
- when :all
16
- all(options)
17
- else
18
- klass.find(*scoped_ids(args) << scoped_options(options))
19
- end
9
+ query.find(*scoped_ids(args))
20
10
  end
21
11
 
22
12
  def find!(*args)
23
- options = args.extract_options!
24
-
25
- case args.first
26
- when :first
27
- first(options)
28
- when :last
29
- last(options)
30
- when :all
31
- all(options)
32
- else
33
- klass.find!(*scoped_ids(args) << scoped_options(options))
34
- end
13
+ query.find!(*scoped_ids(args))
35
14
  end
36
15
 
37
16
  def paginate(options)
38
- klass.paginate(scoped_options(options))
17
+ query.paginate(options)
39
18
  end
40
19
 
41
20
  def all(options={})
42
- klass.all(scoped_options(options))
21
+ query(options).all
43
22
  end
44
23
 
45
24
  def first(options={})
46
- klass.first(scoped_options(options))
25
+ query(options).first
47
26
  end
48
27
 
49
28
  def last(options={})
50
- klass.last(scoped_options(options))
29
+ query(options).last
51
30
  end
52
31
 
53
32
  def count(options={})
54
- options.blank? ? ids.size : klass.count(scoped_options(options))
33
+ options.blank? ? ids.size : query(options).count
55
34
  end
56
35
 
57
36
  def destroy_all(options={})
@@ -63,7 +42,7 @@ module MongoMapper
63
42
  end
64
43
 
65
44
  def delete_all(options={})
66
- docs = all(options.merge(:select => ['_id']))
45
+ docs = query(options).fields(:_id).all
67
46
  docs.each { |doc| ids.delete(doc.id) }
68
47
  klass.delete(docs.map(&:id))
69
48
  reset
@@ -78,7 +57,7 @@ module MongoMapper
78
57
  doc = klass.create(attrs)
79
58
  unless doc.new?
80
59
  ids << doc.id
81
- owner.save
60
+ proxy_owner.save
82
61
  reset
83
62
  end
84
63
  doc
@@ -88,7 +67,7 @@ module MongoMapper
88
67
  doc = klass.create!(attrs)
89
68
  unless doc.new?
90
69
  ids << doc.id
91
- owner.save
70
+ proxy_owner.save
92
71
  reset
93
72
  end
94
73
  doc
@@ -116,19 +95,23 @@ module MongoMapper
116
95
  end
117
96
 
118
97
  private
119
- def scoped_conditions
120
- {:_id => ids}
98
+ def query(options={})
99
+ klass.
100
+ query(association.query_options).
101
+ update(options).
102
+ update(criteria)
121
103
  end
122
104
 
123
- def scoped_options(options)
124
- association.query_options.merge(options).merge(scoped_conditions)
105
+ def criteria
106
+ {:_id => ids}
125
107
  end
126
108
 
127
109
  def scoped_ids(args)
128
- args.flatten.select do |id|
110
+ valid = args.flatten.select do |id|
129
111
  id = ObjectId.to_mongo(id) if klass.using_object_id?
130
112
  ids.include?(id)
131
113
  end
114
+ valid.empty? ? nil : valid
132
115
  end
133
116
 
134
117
  def find_target
@@ -136,7 +119,7 @@ module MongoMapper
136
119
  end
137
120
 
138
121
  def ids
139
- owner[options[:in]]
122
+ proxy_owner[options[:in]]
140
123
  end
141
124
  end
142
125
  end
@@ -1,16 +1,16 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
4
5
  class ManyDocumentsAsProxy < ManyDocumentsProxy
5
6
  protected
6
- def scoped_conditions
7
- {type_key_name => owner.class.name, id_key_name => owner.id}
7
+ def criteria
8
+ {type_key_name => proxy_owner.class.name, id_key_name => proxy_owner.id}
8
9
  end
9
10
 
10
11
  def apply_scope(doc)
11
12
  ensure_owner_saved
12
- doc[type_key_name] = owner.class.name
13
- doc[id_key_name] = owner.id
13
+ criteria.each { |key, value| doc[key] = value }
14
14
  doc
15
15
  end
16
16
 
@@ -1,37 +1,36 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
4
5
  class ManyDocumentsProxy < Collection
5
- include Support::Find
6
+ include MongoMapper::Plugins::DynamicQuerying::ClassMethods
6
7
 
7
8
  def find(*args)
8
- options = args.extract_options!
9
- klass.find(*args << scoped_options(options))
9
+ query.find(*args)
10
10
  end
11
11
 
12
12
  def find!(*args)
13
- options = args.extract_options!
14
- klass.find!(*args << scoped_options(options))
13
+ query.find!(*args)
15
14
  end
16
15
 
17
16
  def paginate(options)
18
- klass.paginate(scoped_options(options))
17
+ query.paginate(options)
19
18
  end
20
19
 
21
20
  def all(options={})
22
- klass.all(scoped_options(options))
21
+ query(options).all
23
22
  end
24
23
 
25
24
  def first(options={})
26
- klass.first(scoped_options(options))
25
+ query(options).first
27
26
  end
28
27
 
29
28
  def last(options={})
30
- klass.last(scoped_options(options))
29
+ query(options).last
31
30
  end
32
31
 
33
32
  def count(options={})
34
- klass.count(scoped_options(options))
33
+ query(options).count
35
34
  end
36
35
 
37
36
  def replace(docs)
@@ -77,29 +76,29 @@ module MongoMapper
77
76
  end
78
77
 
79
78
  def delete_all(options={})
80
- klass.delete_all(options.merge(scoped_conditions))
79
+ query(options).remove
81
80
  reset
82
81
  end
83
82
 
84
83
  def nullify
85
- criteria = Query.new(klass, scoped_conditions).criteria
86
- all(criteria).each do |doc|
87
- doc.update_attributes(self.foreign_key => nil)
88
- end
84
+ all.each { |doc| doc.update_attributes(self.foreign_key => nil) }
89
85
  reset
90
86
  end
91
87
 
92
- def save_to_collection(options = {})
88
+ def save_to_collection(options={})
93
89
  @target.each { |doc| doc.save(options) } if @target
94
90
  end
95
91
 
96
92
  protected
97
- def scoped_conditions
98
- {self.foreign_key => owner.id}
93
+ def query(options={})
94
+ klass.
95
+ query(association.query_options).
96
+ update(options).
97
+ update(criteria)
99
98
  end
100
99
 
101
- def scoped_options(options)
102
- association.query_options.merge(options).merge(scoped_conditions)
100
+ def criteria
101
+ {self.foreign_key => proxy_owner.id}
103
102
  end
104
103
 
105
104
  def find_target
@@ -107,7 +106,7 @@ module MongoMapper
107
106
  end
108
107
 
109
108
  def ensure_owner_saved
110
- owner.save if owner.new?
109
+ proxy_owner.save if proxy_owner.new?
111
110
  end
112
111
 
113
112
  def prepare(doc)
@@ -116,12 +115,12 @@ module MongoMapper
116
115
 
117
116
  def apply_scope(doc)
118
117
  ensure_owner_saved
119
- doc[foreign_key] = owner.id
118
+ criteria.each { |key, value| doc[key] = value }
120
119
  doc
121
120
  end
122
121
 
123
122
  def foreign_key
124
- options[:foreign_key] || owner.class.name.to_s.underscore.gsub("/", "_") + "_id"
123
+ options[:foreign_key] || proxy_owner.class.name.to_s.underscore.gsub("/", "_") + "_id"
125
124
  end
126
125
  end
127
126
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
@@ -1,9 +1,8 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
4
5
  class OneEmbeddedProxy < Proxy
5
- undef_method :object_id
6
-
7
6
  def build(attributes={})
8
7
  @target = klass.new(attributes)
9
8
  assign_references(@target)
@@ -33,7 +32,7 @@ module MongoMapper
33
32
  end
34
33
 
35
34
  def assign_references(doc)
36
- doc._parent_document = owner
35
+ doc._parent_document = proxy_owner
37
36
  end
38
37
  end
39
38
  end
@@ -1,9 +1,8 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
4
5
  class OneProxy < Proxy
5
- undef_method :object_id
6
-
7
6
  def build(attrs={})
8
7
  instantiate_target(:new, attrs)
9
8
  end
@@ -36,9 +35,9 @@ module MongoMapper
36
35
  reset
37
36
 
38
37
  unless doc.nil?
39
- owner.save if owner.new?
38
+ proxy_owner.save if proxy_owner.new?
40
39
  doc = klass.new(doc) unless klass === doc
41
- doc[foreign_key] = owner.id
40
+ doc[foreign_key] = proxy_owner.id
42
41
  doc.save if doc.new?
43
42
  loaded
44
43
  @target = doc
@@ -47,11 +46,11 @@ module MongoMapper
47
46
 
48
47
  protected
49
48
  def find_target
50
- target_class.first(association.query_options.merge(foreign_key => owner.id))
49
+ target_class.first(association.query_options.merge(foreign_key => proxy_owner.id))
51
50
  end
52
51
 
53
52
  def instantiate_target(instantiator, attrs={})
54
- @target = target_class.send(instantiator, attrs.update(foreign_key => owner.id))
53
+ @target = target_class.send(instantiator, attrs.update(foreign_key => proxy_owner.id))
55
54
  loaded
56
55
  @target
57
56
  end
@@ -61,7 +60,7 @@ module MongoMapper
61
60
  end
62
61
 
63
62
  def foreign_key
64
- options[:foreign_key] || owner.class.name.foreign_key
63
+ options[:foreign_key] || proxy_owner.class.name.foreign_key
65
64
  end
66
65
  end
67
66
  end
@@ -1,24 +1,26 @@
1
+ # encoding: UTF-8
2
+ require 'forwardable'
1
3
  module MongoMapper
2
4
  module Plugins
3
5
  module Associations
4
6
  class Proxy
7
+ extend Forwardable
8
+
5
9
  alias :proxy_respond_to? :respond_to?
6
10
  alias :proxy_extend :extend
7
11
 
8
12
  instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ }
9
13
 
10
- attr_reader :owner, :association, :target
14
+ attr_reader :proxy_owner, :association, :target
11
15
 
12
- alias :proxy_owner :owner
13
16
  alias :proxy_target :target
14
17
  alias :proxy_association :association
15
18
 
16
- delegate :klass, :to => :proxy_association
17
- delegate :options, :to => :proxy_association
18
- delegate :collection, :to => :klass
19
+ def_delegators :proxy_association, :klass, :options
20
+ def_delegator :klass, :collection
19
21
 
20
22
  def initialize(owner, association)
21
- @owner, @association, @loaded = owner, association, false
23
+ @proxy_owner, @association, @loaded = owner, association, false
22
24
  Array(association.options[:extend]).each { |ext| proxy_extend(ext) }
23
25
  reset
24
26
  end
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Caching
5
+ module InstanceMethods
6
+ def cache_key(*suffixes)
7
+ cache_key = case
8
+ when new?
9
+ "#{self.class.name}/new"
10
+ when timestamp = self[:updated_at]
11
+ "#{self.class.name}/#{id}-#{timestamp.to_s(:number)}"
12
+ else
13
+ "#{self.class.name}/#{id}"
14
+ end
15
+ cache_key += "/#{suffixes.join('/')}" unless suffixes.empty?
16
+ cache_key
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  # Almost all of this callback stuff is pulled directly from ActiveSupport
2
3
  # in the interest of support rails 2 and 3 at the same time and is the
3
4
  # same copyright as rails.
@@ -76,7 +77,7 @@ module MongoMapper
76
77
  result
77
78
  end
78
79
 
79
- def run_callbacks(kind, options = {}, &block)
80
+ def run_callbacks(kind, options={}, &block)
80
81
  callback_chain_method = "#{kind}_callback_chain"
81
82
  return unless self.class.respond_to?(callback_chain_method)
82
83
  self.class.send(callback_chain_method).run(self, options, &block)
@@ -122,7 +123,7 @@ module MongoMapper
122
123
  new(methods)
123
124
  end
124
125
 
125
- def run(object, options = {}, &terminator)
126
+ def run(object, options={}, &terminator)
126
127
  enumerator = options[:enumerator] || :each
127
128
 
128
129
  unless block_given?
@@ -169,7 +170,7 @@ module MongoMapper
169
170
  class Callback
170
171
  attr_reader :kind, :method, :identifier, :options
171
172
 
172
- def initialize(kind, method, options = {})
173
+ def initialize(kind, method, options={})
173
174
  @kind = kind
174
175
  @method = method
175
176
  @identifier = options[:identifier]