ign-mongo_mapper 0.8.6.1

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 (147) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +33 -0
  3. data/UPGRADES +7 -0
  4. data/bin/mmconsole +60 -0
  5. data/examples/attr_accessible.rb +22 -0
  6. data/examples/attr_protected.rb +22 -0
  7. data/examples/cache_key.rb +24 -0
  8. data/examples/custom_types.rb +24 -0
  9. data/examples/identity_map.rb +33 -0
  10. data/examples/identity_map/automatic.rb +8 -0
  11. data/examples/keys.rb +40 -0
  12. data/examples/modifiers/set.rb +25 -0
  13. data/examples/plugins.rb +41 -0
  14. data/examples/querying.rb +35 -0
  15. data/examples/safe.rb +43 -0
  16. data/examples/scopes.rb +52 -0
  17. data/examples/validating/embedded_docs.rb +29 -0
  18. data/lib/mongo_mapper.rb +83 -0
  19. data/lib/mongo_mapper/connection.rb +83 -0
  20. data/lib/mongo_mapper/document.rb +41 -0
  21. data/lib/mongo_mapper/embedded_document.rb +31 -0
  22. data/lib/mongo_mapper/exceptions.rb +27 -0
  23. data/lib/mongo_mapper/extensions/array.rb +19 -0
  24. data/lib/mongo_mapper/extensions/binary.rb +22 -0
  25. data/lib/mongo_mapper/extensions/boolean.rb +44 -0
  26. data/lib/mongo_mapper/extensions/date.rb +25 -0
  27. data/lib/mongo_mapper/extensions/float.rb +14 -0
  28. data/lib/mongo_mapper/extensions/hash.rb +14 -0
  29. data/lib/mongo_mapper/extensions/integer.rb +19 -0
  30. data/lib/mongo_mapper/extensions/kernel.rb +9 -0
  31. data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
  32. data/lib/mongo_mapper/extensions/object.rb +27 -0
  33. data/lib/mongo_mapper/extensions/object_id.rb +30 -0
  34. data/lib/mongo_mapper/extensions/set.rb +20 -0
  35. data/lib/mongo_mapper/extensions/string.rb +18 -0
  36. data/lib/mongo_mapper/extensions/time.rb +29 -0
  37. data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
  38. data/lib/mongo_mapper/plugins.rb +15 -0
  39. data/lib/mongo_mapper/plugins/accessible.rb +44 -0
  40. data/lib/mongo_mapper/plugins/associations.rb +134 -0
  41. data/lib/mongo_mapper/plugins/associations/base.rb +124 -0
  42. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +29 -0
  43. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +24 -0
  44. data/lib/mongo_mapper/plugins/associations/collection.rb +27 -0
  45. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +40 -0
  46. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +151 -0
  47. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  48. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +109 -0
  49. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +32 -0
  50. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +24 -0
  51. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +14 -0
  52. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +41 -0
  53. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  54. data/lib/mongo_mapper/plugins/associations/proxy.rb +139 -0
  55. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  56. data/lib/mongo_mapper/plugins/callbacks.rb +243 -0
  57. data/lib/mongo_mapper/plugins/clone.rb +22 -0
  58. data/lib/mongo_mapper/plugins/descendants.rb +17 -0
  59. data/lib/mongo_mapper/plugins/dirty.rb +124 -0
  60. data/lib/mongo_mapper/plugins/document.rb +41 -0
  61. data/lib/mongo_mapper/plugins/dynamic_querying.rb +43 -0
  62. data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +44 -0
  63. data/lib/mongo_mapper/plugins/embedded_document.rb +48 -0
  64. data/lib/mongo_mapper/plugins/equality.rb +17 -0
  65. data/lib/mongo_mapper/plugins/identity_map.rb +128 -0
  66. data/lib/mongo_mapper/plugins/indexes.rb +12 -0
  67. data/lib/mongo_mapper/plugins/inspect.rb +15 -0
  68. data/lib/mongo_mapper/plugins/keys.rb +311 -0
  69. data/lib/mongo_mapper/plugins/keys/key.rb +65 -0
  70. data/lib/mongo_mapper/plugins/logger.rb +18 -0
  71. data/lib/mongo_mapper/plugins/modifiers.rb +112 -0
  72. data/lib/mongo_mapper/plugins/pagination.rb +14 -0
  73. data/lib/mongo_mapper/plugins/persistence.rb +69 -0
  74. data/lib/mongo_mapper/plugins/protected.rb +53 -0
  75. data/lib/mongo_mapper/plugins/querying.rb +176 -0
  76. data/lib/mongo_mapper/plugins/querying/decorator.rb +46 -0
  77. data/lib/mongo_mapper/plugins/querying/plucky_methods.rb +15 -0
  78. data/lib/mongo_mapper/plugins/rails.rb +58 -0
  79. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  80. data/lib/mongo_mapper/plugins/sci.rb +32 -0
  81. data/lib/mongo_mapper/plugins/scopes.rb +21 -0
  82. data/lib/mongo_mapper/plugins/serialization.rb +76 -0
  83. data/lib/mongo_mapper/plugins/timestamps.rb +22 -0
  84. data/lib/mongo_mapper/plugins/userstamps.rb +15 -0
  85. data/lib/mongo_mapper/plugins/validations.rb +50 -0
  86. data/lib/mongo_mapper/support/descendant_appends.rb +45 -0
  87. data/lib/mongo_mapper/version.rb +4 -0
  88. data/rails/init.rb +15 -0
  89. data/test/_NOTE_ON_TESTING +1 -0
  90. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +64 -0
  91. data/test/functional/associations/test_belongs_to_proxy.rb +117 -0
  92. data/test/functional/associations/test_in_array_proxy.rb +349 -0
  93. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  94. data/test/functional/associations/test_many_documents_proxy.rb +615 -0
  95. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  96. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  97. data/test/functional/associations/test_many_polymorphic_proxy.rb +303 -0
  98. data/test/functional/associations/test_one_embedded_proxy.rb +100 -0
  99. data/test/functional/associations/test_one_proxy.rb +206 -0
  100. data/test/functional/test_accessible.rb +168 -0
  101. data/test/functional/test_associations.rb +46 -0
  102. data/test/functional/test_binary.rb +27 -0
  103. data/test/functional/test_caching.rb +76 -0
  104. data/test/functional/test_callbacks.rb +151 -0
  105. data/test/functional/test_dirty.rb +163 -0
  106. data/test/functional/test_document.rb +272 -0
  107. data/test/functional/test_dynamic_querying.rb +75 -0
  108. data/test/functional/test_embedded_document.rb +210 -0
  109. data/test/functional/test_identity_map.rb +513 -0
  110. data/test/functional/test_indexes.rb +42 -0
  111. data/test/functional/test_logger.rb +20 -0
  112. data/test/functional/test_modifiers.rb +416 -0
  113. data/test/functional/test_pagination.rb +91 -0
  114. data/test/functional/test_protected.rb +175 -0
  115. data/test/functional/test_querying.rb +873 -0
  116. data/test/functional/test_safe.rb +76 -0
  117. data/test/functional/test_sci.rb +230 -0
  118. data/test/functional/test_scopes.rb +171 -0
  119. data/test/functional/test_string_id_compatibility.rb +67 -0
  120. data/test/functional/test_timestamps.rb +62 -0
  121. data/test/functional/test_userstamps.rb +27 -0
  122. data/test/functional/test_validations.rb +342 -0
  123. data/test/models.rb +233 -0
  124. data/test/test_active_model_lint.rb +13 -0
  125. data/test/test_helper.rb +102 -0
  126. data/test/unit/associations/test_base.rb +212 -0
  127. data/test/unit/associations/test_proxy.rb +105 -0
  128. data/test/unit/serializers/test_json_serializer.rb +217 -0
  129. data/test/unit/test_clone.rb +69 -0
  130. data/test/unit/test_descendant_appends.rb +71 -0
  131. data/test/unit/test_document.rb +208 -0
  132. data/test/unit/test_dynamic_finder.rb +125 -0
  133. data/test/unit/test_embedded_document.rb +639 -0
  134. data/test/unit/test_extensions.rb +376 -0
  135. data/test/unit/test_identity_map_middleware.rb +34 -0
  136. data/test/unit/test_inspect.rb +22 -0
  137. data/test/unit/test_key.rb +205 -0
  138. data/test/unit/test_keys.rb +89 -0
  139. data/test/unit/test_mongo_mapper.rb +110 -0
  140. data/test/unit/test_pagination.rb +11 -0
  141. data/test/unit/test_plugins.rb +50 -0
  142. data/test/unit/test_rails.rb +181 -0
  143. data/test/unit/test_rails_compatibility.rb +52 -0
  144. data/test/unit/test_serialization.rb +51 -0
  145. data/test/unit/test_time_zones.rb +39 -0
  146. data/test/unit/test_validations.rb +564 -0
  147. metadata +385 -0
@@ -0,0 +1,124 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Associations
5
+ class Base
6
+ attr_reader :type, :name, :options, :query_options
7
+
8
+ # Options that should not be considered MongoDB query options/criteria
9
+ AssociationOptions = [:as, :class, :class_name, :dependent, :extend, :foreign_key, :in, :polymorphic]
10
+
11
+ def initialize(type, name, options={}, &extension)
12
+ @type, @name, @options, @query_options, @original_options = type, name, {}, {}, options
13
+ options.symbolize_keys!
14
+ options[:extend] = modularized_extensions(extension, options[:extend])
15
+ separate_options_and_conditions
16
+ end
17
+
18
+ def class_name
19
+ return @class_name if defined?(@class_name)
20
+
21
+ @class_name =
22
+ if cn = options[:class_name]
23
+ cn
24
+ elsif many?
25
+ name.to_s.singularize.camelize
26
+ else
27
+ name.to_s.camelize
28
+ end
29
+ end
30
+
31
+ def klass
32
+ @klass ||= options[:class] || class_name.constantize
33
+ end
34
+
35
+ def many?
36
+ @type == :many
37
+ end
38
+
39
+ def belongs_to?
40
+ @type == :belongs_to
41
+ end
42
+
43
+ def one?
44
+ @type == :one
45
+ end
46
+
47
+ def polymorphic?
48
+ !!@options[:polymorphic]
49
+ end
50
+
51
+ def as?
52
+ !!@options[:as]
53
+ end
54
+
55
+ def in_array?
56
+ !!@options[:in]
57
+ end
58
+
59
+ def embeddable?
60
+ (one? || many?) && klass.embeddable?
61
+ end
62
+
63
+ def type_key_name
64
+ many? ? '_type' : "#{as}_type"
65
+ end
66
+
67
+ def as
68
+ @options[:as] || self.name
69
+ end
70
+
71
+ def foreign_key
72
+ @options[:foreign_key] || "#{name}_id"
73
+ end
74
+
75
+ def ivar
76
+ @ivar ||= "@_#{name}"
77
+ end
78
+
79
+ # hate this, need to revisit
80
+ def proxy_class
81
+ return @proxy_class if defined?(@proxy_class)
82
+
83
+ @proxy_class =
84
+ if many?
85
+ if klass.embeddable?
86
+ polymorphic? ? ManyEmbeddedPolymorphicProxy : ManyEmbeddedProxy
87
+ else
88
+ if polymorphic?
89
+ ManyPolymorphicProxy
90
+ elsif as?
91
+ ManyDocumentsAsProxy
92
+ elsif in_array?
93
+ InArrayProxy
94
+ else
95
+ ManyDocumentsProxy
96
+ end
97
+ end
98
+ elsif one?
99
+ klass.embeddable? ? OneEmbeddedProxy : OneProxy
100
+ else
101
+ polymorphic? ? BelongsToPolymorphicProxy : BelongsToProxy
102
+ end
103
+ end
104
+
105
+ private
106
+ def separate_options_and_conditions
107
+ @original_options.each_pair do |key, value|
108
+ if AssociationOptions.include?(key)
109
+ @options[key] = value
110
+ else
111
+ @query_options[key] = value
112
+ end
113
+ end
114
+ end
115
+
116
+ def modularized_extensions(*extensions)
117
+ extensions.flatten.compact.map do |extension|
118
+ Proc === extension ? Module.new(&extension) : extension
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Associations
5
+ class BelongsToPolymorphicProxy < Proxy
6
+ def replace(doc)
7
+ if doc
8
+ doc.save if doc.new?
9
+ id, type = doc.id, doc.class.name
10
+ end
11
+
12
+ proxy_owner[association.foreign_key] = id
13
+ proxy_owner[association.type_key_name] = type
14
+ reset
15
+ end
16
+
17
+ protected
18
+ def find_target
19
+ return nil if association_class.nil? || proxy_owner[association.foreign_key].nil?
20
+ association_class.find_by_id(proxy_owner[association.foreign_key])
21
+ end
22
+
23
+ def association_class
24
+ proxy_owner[association.type_key_name] ? proxy_owner[association.type_key_name].constantize : nil
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Associations
5
+ class BelongsToProxy < Proxy
6
+ def replace(doc)
7
+ if doc
8
+ doc.save if doc.new?
9
+ id = doc.id
10
+ end
11
+
12
+ proxy_owner[association.foreign_key] = id
13
+ reload
14
+ end
15
+
16
+ protected
17
+ def find_target
18
+ return nil if proxy_owner[association.foreign_key].nil?
19
+ klass.find_by_id(proxy_owner[association.foreign_key])
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Associations
5
+ class Collection < Proxy
6
+ def to_ary
7
+ load_target
8
+ if target.is_a?(Array)
9
+ target.to_ary
10
+ else
11
+ Array(target)
12
+ end
13
+ end
14
+
15
+ def include?(*args)
16
+ load_target
17
+ target.include?(*args)
18
+ end
19
+
20
+ def reset
21
+ super
22
+ target = []
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Associations
5
+ class EmbeddedCollection < Collection
6
+ def build(attributes={})
7
+ doc = klass.new(attributes)
8
+ assign_references(doc)
9
+ self << doc
10
+ doc
11
+ end
12
+
13
+ def find(id)
14
+ load_target
15
+ target.detect { |item| item.id.to_s == id || item.id == id }
16
+ end
17
+
18
+ def count
19
+ load_target
20
+ target.size
21
+ end
22
+
23
+ def <<(*docs)
24
+ load_target
25
+ docs.each do |doc|
26
+ assign_references(doc)
27
+ target << doc
28
+ end
29
+ end
30
+ alias_method :push, :<<
31
+ alias_method :concat, :<<
32
+
33
+ private
34
+ def assign_references(*docs)
35
+ docs.each { |doc| doc._parent_document = proxy_owner }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,151 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Associations
5
+ class InArrayProxy < Collection
6
+ include DynamicQuerying::ClassMethods
7
+
8
+ def find(*args)
9
+ query.find(*scoped_ids(args))
10
+ end
11
+
12
+ def find!(*args)
13
+ query.find!(*scoped_ids(args))
14
+ end
15
+
16
+ def paginate(options)
17
+ return [] if ids.blank?
18
+ query.paginate(options)
19
+ end
20
+
21
+ def all(options={})
22
+
23
+ return [] if ids.blank?
24
+
25
+ # preserve order if options[:preserve_order]
26
+ random_order = query(options).all
27
+ if options[:preserve_order]
28
+ preserve_order = Array.new
29
+ criteria[:_id].each do |id|
30
+ random_order.each do |element|
31
+ if (id.eql?(element._id))
32
+ preserve_order << element
33
+ break
34
+ end
35
+ end
36
+ end
37
+ preserve_order
38
+ else
39
+ random_order
40
+ end
41
+
42
+ end
43
+
44
+ def first(options={})
45
+ return nil if ids.blank?
46
+ query(options).first
47
+ end
48
+
49
+ def last(options={})
50
+ return nil if ids.blank?
51
+ query(options).last
52
+ end
53
+
54
+ def count(options={})
55
+ return 0 if ids.blank?
56
+ options.blank? ? ids.size : query(options).count
57
+ end
58
+
59
+ def destroy_all(options={})
60
+ all(options).each do |doc|
61
+ ids.delete(doc.id)
62
+ doc.destroy
63
+ end
64
+ reset
65
+ end
66
+
67
+ def delete_all(options={})
68
+ docs = query(options).fields(:_id).all
69
+ docs.each { |doc| ids.delete(doc.id) }
70
+ klass.delete(docs.map(&:id))
71
+ reset
72
+ end
73
+
74
+ def nullify
75
+ replace([])
76
+ reset
77
+ end
78
+
79
+ def create(attrs={})
80
+ doc = klass.create(attrs)
81
+ unless doc.new?
82
+ ids << doc.id
83
+ proxy_owner.save
84
+ reset
85
+ end
86
+ doc
87
+ end
88
+
89
+ def create!(attrs={})
90
+ doc = klass.create!(attrs)
91
+ unless doc.new?
92
+ ids << doc.id
93
+ proxy_owner.save
94
+ reset
95
+ end
96
+ doc
97
+ end
98
+
99
+ def <<(*docs)
100
+ flatten_deeper(docs).each do |doc|
101
+ doc.save if doc.new?
102
+ unless ids.include?(doc.id)
103
+ ids << doc.id
104
+ end
105
+ end
106
+ reset
107
+ end
108
+ alias_method :push, :<<
109
+ alias_method :concat, :<<
110
+
111
+ def replace(docs)
112
+ doc_ids = docs.map do |doc|
113
+ doc.save if doc.new?
114
+ doc.id
115
+ end
116
+ ids.replace(doc_ids.uniq)
117
+ reset
118
+ end
119
+
120
+ private
121
+ def query(options={})
122
+ klass.
123
+ query(association.query_options).
124
+ update(options).
125
+ update(criteria)
126
+ end
127
+
128
+ def criteria
129
+ {:_id => ids}
130
+ end
131
+
132
+ def scoped_ids(args)
133
+ valid = args.flatten.select do |id|
134
+ id = ObjectId.to_mongo(id) if klass.using_object_id?
135
+ ids.include?(id)
136
+ end
137
+ valid.empty? ? nil : valid
138
+ end
139
+
140
+ def find_target
141
+ return [] if ids.blank?
142
+ all
143
+ end
144
+
145
+ def ids
146
+ proxy_owner[options[:in]]
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Associations
5
+ class ManyDocumentsAsProxy < ManyDocumentsProxy
6
+ protected
7
+ def criteria
8
+ {type_key_name => proxy_owner.class.name, id_key_name => proxy_owner.id}
9
+ end
10
+
11
+ def apply_scope(doc)
12
+ ensure_owner_saved
13
+ criteria.each { |key, value| doc[key] = value }
14
+ doc
15
+ end
16
+
17
+ private
18
+ def type_key_name
19
+ "#{options[:as]}_type"
20
+ end
21
+
22
+ def id_key_name
23
+ "#{options[:as]}_id"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,109 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Associations
5
+ class ManyDocumentsProxy < Collection
6
+ include DynamicQuerying::ClassMethods
7
+ include Querying::PluckyMethods
8
+
9
+ def replace(docs)
10
+ load_target
11
+ target.map(&:destroy)
12
+ docs.each { |doc| prepare(doc).save }
13
+ reset
14
+ end
15
+
16
+ def <<(*docs)
17
+ ensure_owner_saved
18
+ flatten_deeper(docs).each { |doc| prepare(doc).save }
19
+ reset
20
+ end
21
+ alias_method :push, :<<
22
+ alias_method :concat, :<<
23
+
24
+ def build(attrs={})
25
+ doc = klass.new(attrs)
26
+ apply_scope(doc)
27
+ @target ||= [] unless loaded?
28
+ @target << doc
29
+ doc
30
+ end
31
+
32
+ def create(attrs={})
33
+ doc = klass.new(attrs)
34
+ apply_scope(doc).save
35
+ reset
36
+ doc
37
+ end
38
+
39
+ def create!(attrs={})
40
+ doc = klass.new(attrs)
41
+ apply_scope(doc).save!
42
+ reset
43
+ doc
44
+ end
45
+
46
+ def destroy_all(options={})
47
+ all(options).map(&:destroy)
48
+ reset
49
+ end
50
+
51
+ def delete_all(options={})
52
+ query(options).remove
53
+ reset
54
+ end
55
+
56
+ def nullify
57
+ all.each { |doc| doc.update_attributes(self.foreign_key => nil) }
58
+ reset
59
+ end
60
+
61
+ def save_to_collection(options={})
62
+ @target.each { |doc| doc.save(options) } if @target
63
+ end
64
+
65
+ protected
66
+ def query(options={})
67
+ klass.
68
+ query(association.query_options).
69
+ update(options).update(criteria)
70
+ end
71
+
72
+ def method_missing(method, *args, &block)
73
+ if klass.respond_to?(method)
74
+ result = klass.send(method, *args, &block)
75
+ result.is_a?(Plucky::Query) ?
76
+ query.merge(result) : super
77
+ else
78
+ super
79
+ end
80
+ end
81
+
82
+ def criteria
83
+ {self.foreign_key => proxy_owner.id}
84
+ end
85
+
86
+ def find_target
87
+ all
88
+ end
89
+
90
+ def ensure_owner_saved
91
+ proxy_owner.save if proxy_owner.new?
92
+ end
93
+
94
+ def prepare(doc)
95
+ klass === doc ? apply_scope(doc) : build(doc)
96
+ end
97
+
98
+ def apply_scope(doc)
99
+ criteria.each { |key, value| doc[key] = value }
100
+ doc
101
+ end
102
+
103
+ def foreign_key
104
+ options[:foreign_key] || proxy_owner.class.name.to_s.underscore.gsub("/", "_") + "_id"
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end