mongo_mapper-unstable 2010.3.8 → 2010.06.23

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 (143) 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/connection.rb +83 -0
  8. data/lib/mongo_mapper/document.rb +11 -329
  9. data/lib/mongo_mapper/embedded_document.rb +9 -38
  10. data/lib/mongo_mapper/exceptions.rb +30 -0
  11. data/lib/mongo_mapper/extensions/array.rb +19 -0
  12. data/lib/mongo_mapper/extensions/binary.rb +22 -0
  13. data/lib/mongo_mapper/extensions/boolean.rb +44 -0
  14. data/lib/mongo_mapper/extensions/date.rb +25 -0
  15. data/lib/mongo_mapper/extensions/float.rb +14 -0
  16. data/lib/mongo_mapper/extensions/hash.rb +14 -0
  17. data/lib/mongo_mapper/extensions/integer.rb +19 -0
  18. data/lib/mongo_mapper/extensions/kernel.rb +9 -0
  19. data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
  20. data/lib/mongo_mapper/extensions/object.rb +27 -0
  21. data/lib/mongo_mapper/extensions/object_id.rb +30 -0
  22. data/lib/mongo_mapper/extensions/set.rb +20 -0
  23. data/lib/mongo_mapper/extensions/string.rb +18 -0
  24. data/lib/mongo_mapper/extensions/time.rb +29 -0
  25. data/lib/mongo_mapper/plugins/accessible.rb +44 -0
  26. data/lib/mongo_mapper/plugins/associations/base.rb +7 -6
  27. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +5 -6
  28. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +5 -6
  29. data/lib/mongo_mapper/plugins/associations/collection.rb +1 -0
  30. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +2 -1
  31. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +25 -39
  32. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +4 -4
  33. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +36 -46
  34. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +1 -0
  35. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +5 -4
  36. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +1 -0
  37. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +40 -0
  38. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +7 -7
  39. data/lib/mongo_mapper/plugins/associations/proxy.rb +16 -8
  40. data/lib/mongo_mapper/plugins/associations.rb +14 -22
  41. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  42. data/lib/mongo_mapper/plugins/callbacks.rb +17 -5
  43. data/lib/mongo_mapper/plugins/clone.rb +10 -4
  44. data/lib/mongo_mapper/plugins/descendants.rb +3 -2
  45. data/lib/mongo_mapper/plugins/dirty.rb +1 -0
  46. data/lib/mongo_mapper/plugins/document.rb +41 -0
  47. data/lib/mongo_mapper/{support/find.rb → plugins/dynamic_querying/dynamic_finder.rb} +3 -36
  48. data/lib/mongo_mapper/plugins/dynamic_querying.rb +43 -0
  49. data/lib/mongo_mapper/plugins/embedded_document.rb +49 -0
  50. data/lib/mongo_mapper/plugins/equality.rb +4 -10
  51. data/lib/mongo_mapper/plugins/identity_map.rb +29 -23
  52. data/lib/mongo_mapper/plugins/indexes.rb +12 -0
  53. data/lib/mongo_mapper/plugins/inspect.rb +1 -0
  54. data/lib/mongo_mapper/plugins/keys/key.rb +55 -0
  55. data/lib/mongo_mapper/plugins/keys.rb +85 -110
  56. data/lib/mongo_mapper/plugins/logger.rb +1 -0
  57. data/lib/mongo_mapper/plugins/modifiers.rb +41 -16
  58. data/lib/mongo_mapper/plugins/pagination.rb +5 -15
  59. data/lib/mongo_mapper/plugins/persistence.rb +69 -0
  60. data/lib/mongo_mapper/plugins/protected.rb +9 -1
  61. data/lib/mongo_mapper/plugins/querying/decorator.rb +46 -0
  62. data/lib/mongo_mapper/plugins/querying/plucky_methods.rb +15 -0
  63. data/lib/mongo_mapper/plugins/querying.rb +176 -0
  64. data/lib/mongo_mapper/plugins/rails.rb +6 -1
  65. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  66. data/lib/mongo_mapper/plugins/sci.rb +32 -0
  67. data/lib/mongo_mapper/plugins/scopes.rb +21 -0
  68. data/lib/mongo_mapper/plugins/serialization.rb +5 -4
  69. data/lib/mongo_mapper/plugins/timestamps.rb +2 -1
  70. data/lib/mongo_mapper/plugins/userstamps.rb +1 -0
  71. data/lib/mongo_mapper/plugins/validations.rb +9 -5
  72. data/lib/mongo_mapper/plugins.rb +1 -20
  73. data/lib/mongo_mapper/support/descendant_appends.rb +5 -6
  74. data/lib/mongo_mapper/version.rb +4 -0
  75. data/lib/mongo_mapper.rb +71 -128
  76. data/test/{NOTE_ON_TESTING → _NOTE_ON_TESTING} +0 -0
  77. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +5 -5
  78. data/test/functional/associations/test_belongs_to_proxy.rb +13 -21
  79. data/test/functional/associations/test_in_array_proxy.rb +7 -9
  80. data/test/functional/associations/test_many_documents_as_proxy.rb +5 -5
  81. data/test/functional/associations/test_many_documents_proxy.rb +186 -64
  82. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +22 -22
  83. data/test/functional/associations/test_many_embedded_proxy.rb +32 -32
  84. data/test/functional/associations/test_many_polymorphic_proxy.rb +47 -47
  85. data/test/functional/associations/test_one_embedded_proxy.rb +67 -0
  86. data/test/functional/associations/test_one_proxy.rb +70 -49
  87. data/test/functional/test_accessible.rb +168 -0
  88. data/test/functional/test_associations.rb +11 -11
  89. data/test/functional/test_binary.rb +5 -5
  90. data/test/functional/test_caching.rb +76 -0
  91. data/test/functional/test_callbacks.rb +104 -34
  92. data/test/functional/test_dirty.rb +16 -16
  93. data/test/functional/test_document.rb +12 -924
  94. data/test/functional/test_dynamic_querying.rb +75 -0
  95. data/test/functional/test_embedded_document.rb +88 -8
  96. data/test/functional/test_identity_map.rb +41 -43
  97. data/test/functional/{test_indexing.rb → test_indexes.rb} +3 -5
  98. data/test/functional/test_logger.rb +1 -1
  99. data/test/functional/test_modifiers.rb +275 -181
  100. data/test/functional/test_pagination.rb +13 -15
  101. data/test/functional/test_protected.rb +25 -11
  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 +11 -11
  107. data/test/functional/test_timestamps.rb +0 -2
  108. data/test/functional/test_userstamps.rb +0 -1
  109. data/test/functional/test_validations.rb +44 -31
  110. data/test/models.rb +18 -17
  111. data/test/{active_model_lint_test.rb → test_active_model_lint.rb} +3 -1
  112. data/test/test_helper.rb +59 -16
  113. data/test/unit/associations/test_base.rb +47 -42
  114. data/test/unit/associations/test_proxy.rb +15 -15
  115. data/test/unit/serializers/test_json_serializer.rb +29 -29
  116. data/test/unit/test_clone.rb +69 -0
  117. data/test/unit/test_descendant_appends.rb +3 -3
  118. data/test/unit/test_document.rb +49 -67
  119. data/test/unit/test_dynamic_finder.rb +53 -51
  120. data/test/unit/test_embedded_document.rb +19 -38
  121. data/test/unit/{test_support.rb → test_extensions.rb} +136 -122
  122. data/test/unit/test_key.rb +185 -0
  123. data/test/unit/test_keys.rb +29 -147
  124. data/test/unit/test_mongo_mapper.rb +3 -48
  125. data/test/unit/test_pagination.rb +1 -150
  126. data/test/unit/test_rails.rb +77 -19
  127. data/test/unit/test_rails_compatibility.rb +12 -12
  128. data/test/unit/test_serialization.rb +5 -5
  129. data/test/unit/test_time_zones.rb +9 -9
  130. data/test/unit/test_validations.rb +46 -46
  131. metadata +157 -155
  132. data/.gitignore +0 -10
  133. data/Rakefile +0 -55
  134. data/VERSION +0 -1
  135. data/lib/mongo_mapper/plugins/pagination/proxy.rb +0 -72
  136. data/lib/mongo_mapper/query.rb +0 -130
  137. data/lib/mongo_mapper/support.rb +0 -215
  138. data/mongo_mapper.gemspec +0 -196
  139. data/performance/read_write.rb +0 -52
  140. data/specs.watchr +0 -51
  141. data/test/support/custom_matchers.rb +0 -55
  142. data/test/support/timing.rb +0 -16
  143. data/test/unit/test_query.rb +0 -340
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Modifiers
@@ -14,7 +15,24 @@ module MongoMapper
14
15
  end
15
16
 
16
17
  def set(*args)
17
- modifier_update('$set', args)
18
+ criteria, updates = criteria_and_keys_from_args(args)
19
+ updates.each do |key, value|
20
+ updates[key] = keys[key].set(value) if key?(key)
21
+ end
22
+ collection.update(criteria, {'$set' => updates}, :multi => true)
23
+ end
24
+
25
+ def unset(*args)
26
+ if args[0].is_a?(Hash)
27
+ criteria, keys = args.shift, args
28
+ else
29
+ keys, ids = args.partition { |arg| arg.is_a?(Symbol) }
30
+ criteria = {:id => ids}
31
+ end
32
+
33
+ criteria = criteria_hash(criteria).to_hash
34
+ modifiers = keys.inject({}) { |hash, key| hash[key] = 1; hash }
35
+ collection.update(criteria, {'$unset' => modifiers}, :multi => true)
18
36
  end
19
37
 
20
38
  def push(*args)
@@ -25,11 +43,10 @@ module MongoMapper
25
43
  modifier_update('$pushAll', args)
26
44
  end
27
45
 
28
- def push_uniq(*args)
29
- criteria, keys = criteria_and_keys_from_args(args)
30
- keys.each { |key, value | criteria[key] = {'$ne' => value} }
31
- collection.update(criteria, {'$push' => keys}, :multi => true)
46
+ def add_to_set(*args)
47
+ modifier_update('$addToSet', args)
32
48
  end
49
+ alias push_uniq add_to_set
33
50
 
34
51
  def pull(*args)
35
52
  modifier_update('$pull', args)
@@ -45,41 +62,49 @@ module MongoMapper
45
62
 
46
63
  private
47
64
  def modifier_update(modifier, args)
48
- criteria, keys = criteria_and_keys_from_args(args)
49
- modifiers = {modifier => keys}
50
- collection.update(criteria, modifiers, :multi => true)
65
+ criteria, updates = criteria_and_keys_from_args(args)
66
+ collection.update(criteria, {modifier => updates}, :multi => true)
51
67
  end
52
68
 
53
69
  def criteria_and_keys_from_args(args)
54
70
  keys = args.pop
55
71
  criteria = args[0].is_a?(Hash) ? args[0] : {:id => args}
56
- [to_criteria(criteria), keys]
72
+ [criteria_hash(criteria).to_hash, keys]
57
73
  end
58
74
  end
59
75
 
60
76
  module InstanceMethods
77
+ def unset(*keys)
78
+ self.class.unset(id, *keys)
79
+ end
80
+
61
81
  def increment(hash)
62
- self.class.increment({:_id => id}, hash)
82
+ self.class.increment(id, hash)
63
83
  end
64
84
 
65
85
  def decrement(hash)
66
- self.class.decrement({:_id => id}, hash)
86
+ self.class.decrement(id, hash)
67
87
  end
68
88
 
69
89
  def set(hash)
70
- self.class.set({:_id => id}, hash)
90
+ self.class.set(id, hash)
71
91
  end
72
92
 
73
93
  def push(hash)
74
- self.class.push({:_id => id}, hash)
94
+ self.class.push(id, hash)
75
95
  end
76
96
 
77
97
  def pull(hash)
78
- self.class.pull({:_id => id}, hash)
98
+ self.class.pull(id, hash)
99
+ end
100
+
101
+ def add_to_set(hash)
102
+ self.class.push_uniq(id, hash)
79
103
  end
104
+ alias push_uniq add_to_set
80
105
 
81
- def push_uniq(hash)
82
- self.class.push_uniq({:_id => id}, hash)
106
+ def pop(hash)
107
+ self.class.pop(id, hash)
83
108
  end
84
109
  end
85
110
  end
@@ -1,24 +1,14 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Pagination
4
5
  module ClassMethods
5
- def per_page
6
- 25
7
- end
8
-
9
- def paginate(options)
10
- per_page = options.delete(:per_page) || self.per_page
11
- page = options.delete(:page)
12
- total_entries = count(options)
13
- pagination = Pagination::Proxy.new(total_entries, page, per_page)
6
+ def per_page; 25 end
14
7
 
15
- options.update(:limit => pagination.limit, :skip => pagination.skip)
16
- pagination.subject = find_many(options)
17
- pagination
8
+ def paginate(opts={})
9
+ query.paginate({:per_page => per_page}.merge(opts))
18
10
  end
19
11
  end
20
12
  end
21
13
  end
22
- end
23
-
24
- require 'mongo_mapper/plugins/pagination/proxy'
14
+ end
@@ -0,0 +1,69 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Persistence
5
+ module ClassMethods
6
+ def connection(mongo_connection=nil)
7
+ assert_supported
8
+ if mongo_connection.nil?
9
+ @connection ||= MongoMapper.connection
10
+ else
11
+ @connection = mongo_connection
12
+ end
13
+ @connection
14
+ end
15
+
16
+ def set_database_name(name)
17
+ assert_supported
18
+ @database_name = name
19
+ end
20
+
21
+ def database_name
22
+ assert_supported
23
+ @database_name
24
+ end
25
+
26
+ def database
27
+ assert_supported
28
+ if database_name.nil?
29
+ MongoMapper.database
30
+ else
31
+ connection.db(database_name)
32
+ end
33
+ end
34
+
35
+ def set_collection_name(name)
36
+ assert_supported
37
+ @collection_name = name
38
+ end
39
+
40
+ def collection_name
41
+ assert_supported
42
+ @collection_name ||= self.to_s.tableize.gsub(/\//, '.')
43
+ end
44
+
45
+ def collection
46
+ assert_supported
47
+ database.collection(collection_name)
48
+ end
49
+
50
+ private
51
+ def assert_supported
52
+ if embeddable?
53
+ raise NotSupported.new('This is not supported for embeddable documents at this time.')
54
+ end
55
+ end
56
+ end
57
+
58
+ module InstanceMethods
59
+ def collection
60
+ _root_document.class.collection
61
+ end
62
+
63
+ def database
64
+ _root_document.class.database
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -1,8 +1,12 @@
1
+ # encoding: UTF-8
2
+ require 'set'
3
+
1
4
  module MongoMapper
2
5
  module Plugins
3
6
  module Protected
4
7
  module ClassMethods
5
8
  def attr_protected(*attrs)
9
+ raise AccessibleOrProtected.new(name) if try(:accessible_attributes?)
6
10
  self.write_inheritable_attribute(:attr_protected, Set.new(attrs) + (protected_attributes || []))
7
11
  end
8
12
 
@@ -10,6 +14,10 @@ module MongoMapper
10
14
  self.read_inheritable_attribute(:attr_protected)
11
15
  end
12
16
 
17
+ def protected_attributes?
18
+ !protected_attributes.nil?
19
+ end
20
+
13
21
  def key(*args)
14
22
  key = super
15
23
  attr_protected key.name.to_sym if key.options[:protected]
@@ -36,7 +44,7 @@ module MongoMapper
36
44
 
37
45
  protected
38
46
  def filter_protected_attrs(attrs)
39
- return attrs if protected_attributes.blank?
47
+ return attrs if protected_attributes.blank? || attrs.blank?
40
48
  attrs.dup.delete_if { |key, val| protected_attributes.include?(key.to_sym) }
41
49
  end
42
50
  end
@@ -0,0 +1,46 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Querying
5
+ module Decorator
6
+ include DynamicQuerying::ClassMethods
7
+
8
+ def model(model=nil)
9
+ return @model if model.nil?
10
+ @model = model
11
+ self
12
+ end
13
+
14
+ def find!(*ids)
15
+ raise DocumentNotFound, "Couldn't find without an ID" if ids.size == 0
16
+
17
+ find(*ids).tap do |result|
18
+ if result.nil? || ids.size != Array(result).size
19
+ raise DocumentNotFound, "Couldn't find all of the ids (#{ids.join(',')}). Found #{Array(result).size}, but was expecting #{ids.size}"
20
+ end
21
+ end
22
+ end
23
+
24
+ def all(opts={})
25
+ super.map { |doc| model.load(doc) }
26
+ end
27
+
28
+ def first(opts={})
29
+ model.load(super)
30
+ end
31
+
32
+ def last(opts={})
33
+ model.load(super)
34
+ end
35
+
36
+ private
37
+ def method_missing(method, *args, &block)
38
+ return super unless model.respond_to?(method)
39
+ result = model.send(method, *args, &block)
40
+ return super unless result.is_a?(Plucky::Query)
41
+ merge(result)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: UTF-8
2
+ require 'forwardable'
3
+
4
+ module MongoMapper
5
+ module Plugins
6
+ module Querying
7
+ module PluckyMethods
8
+ extend Forwardable
9
+ def_delegators :query, :where, :fields, :limit, :skip, :sort,
10
+ :count, :last, :first, :all, :paginate,
11
+ :find, :find!, :exists?, :exist?, :find_each
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,176 @@
1
+ # encoding: UTF-8
2
+ require 'mongo_mapper/plugins/querying/decorator'
3
+ require 'mongo_mapper/plugins/querying/plucky_methods'
4
+
5
+ module MongoMapper
6
+ module Plugins
7
+ module Querying
8
+ module ClassMethods
9
+ include PluckyMethods
10
+
11
+ def find_each(opts={})
12
+ super(opts).each { |doc| yield load(doc) }
13
+ end
14
+
15
+ def find_by_id(id)
16
+ find_one(:_id => id)
17
+ end
18
+
19
+ def first_or_create(args)
20
+ first(args) || create(args.reject { |key, value| !key?(key) })
21
+ end
22
+
23
+ def first_or_new(args)
24
+ first(args) || new(args.reject { |key, value| !key?(key) })
25
+ end
26
+
27
+ def create(*docs)
28
+ initialize_each(*docs) { |doc| doc.save }
29
+ end
30
+
31
+ def create!(*docs)
32
+ initialize_each(*docs) { |doc| doc.save! }
33
+ end
34
+
35
+ def update(*args)
36
+ if args.length == 1
37
+ update_multiple(args[0])
38
+ else
39
+ id, attributes = args
40
+ update_single(id, attributes)
41
+ end
42
+ end
43
+
44
+ def delete(*ids)
45
+ query(:_id => ids.flatten).remove
46
+ end
47
+
48
+ def delete_all(options={})
49
+ query(options).remove
50
+ end
51
+
52
+ def destroy(*ids)
53
+ find_some!(ids.flatten).each(&:destroy)
54
+ end
55
+
56
+ def destroy_all(options={})
57
+ find_each(options) { |document| document.destroy }
58
+ end
59
+
60
+ # @api private for now
61
+ def query(options={})
62
+ Plucky::Query.new(collection).tap do |query|
63
+ query.extend(Decorator)
64
+ query.object_ids(object_id_keys)
65
+ query.update(options)
66
+ query.model(self)
67
+ end
68
+ end
69
+
70
+ # @api private for now
71
+ def criteria_hash(criteria={})
72
+ Plucky::CriteriaHash.new(criteria, :object_ids => object_id_keys)
73
+ end
74
+
75
+ private
76
+ def find_some(ids, options={})
77
+ query = query(options).update(:_id => ids.flatten.compact.uniq)
78
+ find_many(query.to_hash).compact
79
+ end
80
+
81
+ def find_some!(ids, options={})
82
+ ids = ids.flatten.compact.uniq
83
+ docs = find_some(ids, options)
84
+
85
+ if ids.size != docs.size
86
+ raise DocumentNotFound, "Couldn't find all of the ids (#{ids.to_sentence}). Found #{docs.size}, but was expecting #{ids.size}"
87
+ end
88
+
89
+ docs
90
+ end
91
+
92
+ # All query methods that load documents pass through find_one or find_many
93
+ def find_one(options={})
94
+ query(options).first
95
+ end
96
+
97
+ # All query methods that load documents pass through find_one or find_many
98
+ def find_many(options)
99
+ query(options).all
100
+ end
101
+
102
+ def initialize_each(*docs)
103
+ instances = []
104
+ docs = [{}] if docs.blank?
105
+ docs.flatten.each do |attrs|
106
+ doc = new(attrs)
107
+ yield(doc)
108
+ instances << doc
109
+ end
110
+ instances.size == 1 ? instances[0] : instances
111
+ end
112
+
113
+ def update_single(id, attrs)
114
+ if id.blank? || attrs.blank? || !attrs.is_a?(Hash)
115
+ raise ArgumentError, "Updating a single document requires an id and a hash of attributes"
116
+ end
117
+
118
+ find(id).tap do |doc|
119
+ doc.update_attributes(attrs)
120
+ end
121
+ end
122
+
123
+ def update_multiple(docs)
124
+ unless docs.is_a?(Hash)
125
+ raise ArgumentError, "Updating multiple documents takes 1 argument and it must be hash"
126
+ end
127
+
128
+ instances = []
129
+ docs.each_pair { |id, attrs| instances << update(id, attrs) }
130
+ instances
131
+ end
132
+ end
133
+
134
+ module InstanceMethods
135
+ def save(options={})
136
+ options.assert_valid_keys(:validate, :safe)
137
+ options.reverse_merge!(:validate => true)
138
+ !options[:validate] || valid? ? create_or_update(options) : false
139
+ end
140
+
141
+ def save!(options={})
142
+ options.assert_valid_keys(:safe)
143
+ save(options) || raise(DocumentNotValid.new(self))
144
+ end
145
+
146
+ def destroy
147
+ delete
148
+ end
149
+
150
+ def delete
151
+ @_destroyed = true
152
+ self.class.delete(id) unless new?
153
+ end
154
+
155
+ private
156
+ def create_or_update(options={})
157
+ result = new? ? create(options) : update(options)
158
+ result != false
159
+ end
160
+
161
+ def create(options={})
162
+ save_to_collection(options)
163
+ end
164
+
165
+ def update(options={})
166
+ save_to_collection(options)
167
+ end
168
+
169
+ def save_to_collection(options={})
170
+ @_new = false
171
+ collection.save(to_mongo, :safe => options[:safe])
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Rails
@@ -7,13 +8,17 @@ module MongoMapper
7
8
 
8
9
  module InstanceMethods
9
10
  def to_param
10
- id.to_s
11
+ id.to_s if persisted?
11
12
  end
12
13
 
13
14
  def to_model
14
15
  self
15
16
  end
16
17
 
18
+ def to_key
19
+ [id] if persisted?
20
+ end
21
+
17
22
  def new_record?
18
23
  new?
19
24
  end
@@ -0,0 +1,28 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Safe
5
+ module ClassMethods
6
+ def inherited(subclass)
7
+ super
8
+ subclass.safe if safe?
9
+ end
10
+
11
+ def safe
12
+ @safe = true
13
+ end
14
+
15
+ def safe?
16
+ @safe == true
17
+ end
18
+ end
19
+
20
+ module InstanceMethods
21
+ def save_to_collection(options={})
22
+ options[:safe] = self.class.safe? unless options.key?(:safe)
23
+ super
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Sci
5
+ module ClassMethods
6
+ def inherited(subclass)
7
+ key :_type, String unless key?(:_type)
8
+ subclass.instance_variable_set("@single_collection_inherited", true)
9
+ subclass.set_collection_name(collection_name) unless subclass.embeddable?
10
+ super
11
+ end
12
+
13
+ def single_collection_inherited?
14
+ @single_collection_inherited == true
15
+ end
16
+
17
+ def query(options={})
18
+ super.tap do |query|
19
+ query[:_type] = name if single_collection_inherited?
20
+ end
21
+ end
22
+ end
23
+
24
+ module InstanceMethods
25
+ def initialize(*args)
26
+ super
27
+ write_key :_type, self.class.name if self.class.key?(:_type)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Scopes
5
+ module ClassMethods
6
+ def scope(name, scope_options={})
7
+ scopes[name] = lambda do |*args|
8
+ result = scope_options.is_a?(Proc) ? scope_options.call(*args) : scope_options
9
+ result = self.query(result) if result.is_a?(Hash)
10
+ self.query.merge(result)
11
+ end
12
+ singleton_class.send :define_method, name, &scopes[name]
13
+ end
14
+
15
+ def scopes
16
+ read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  require 'active_support/json'
2
3
 
3
4
  module MongoMapper
@@ -6,7 +7,7 @@ module MongoMapper
6
7
  def self.configure(model)
7
8
  model.class_eval { cattr_accessor :include_root_in_json, :instance_writer => true }
8
9
  end
9
-
10
+
10
11
  module InstanceMethods
11
12
  def as_json options={}
12
13
  options ||= {}
@@ -43,7 +44,7 @@ module MongoMapper
43
44
  }
44
45
  end
45
46
  # End rip
46
-
47
+
47
48
  options.delete(:only) if options[:only].nil? or options[:only].empty?
48
49
 
49
50
  hash.each do |key, value|
@@ -51,13 +52,13 @@ module MongoMapper
51
52
  hash[key] = value.map do |item|
52
53
  item.respond_to?(:as_json) ? item.as_json(options) : item
53
54
  end
54
- elsif value.is_a? Mongo::ObjectID
55
+ elsif value.is_a? BSON::ObjectID
55
56
  hash[key] = value.to_s
56
57
  elsif value.respond_to?(:as_json)
57
58
  hash[key] = value.as_json(options)
58
59
  end
59
60
  end
60
-
61
+
61
62
  # Replicate Rails 3 naming - and also bin anytihng after : for use in our dynamic classes from unit tests
62
63
  hash = { ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)).gsub(/:.*/,'') => hash } if include_root_in_json
63
64
  hash
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Timestamps
@@ -8,7 +9,7 @@ module MongoMapper
8
9
  class_eval { before_save :update_timestamps }
9
10
  end
10
11
  end
11
-
12
+
12
13
  module InstanceMethods
13
14
  def update_timestamps
14
15
  now = Time.now.utc
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Userstamps
@@ -1,16 +1,20 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Validations
4
5
  def self.configure(model)
5
- model.class_eval { include Validatable }
6
+ model.class_eval do
7
+ include Validatable
8
+ extend Validations::DocumentMacros
9
+ end
6
10
  end
7
-
11
+
8
12
  module DocumentMacros
9
13
  def validates_uniqueness_of(*args)
10
- add_validations(args, MongoMapper::Plugins::Validations::ValidatesUniquenessOf)
14
+ add_validations(args, Validations::ValidatesUniquenessOf)
11
15
  end
12
16
  end
13
-
17
+
14
18
  class ValidatesUniquenessOf < Validatable::ValidationBase
15
19
  option :scope, :case_sensitive
16
20
  default :case_sensitive => true
@@ -37,7 +41,7 @@ module MongoMapper
37
41
 
38
42
  def where_conditions(instance)
39
43
  conditions = {}
40
- conditions[attribute] = /#{instance[attribute].to_s}/i unless case_sensitive
44
+ conditions[attribute] = /^#{Regexp.escape(instance[attribute].to_s)}$/i unless case_sensitive
41
45
  conditions
42
46
  end
43
47
  end