mongo_mapper 0.7.6 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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]