jmonteiro-mongo_mapper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/.gitignore +10 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +38 -0
  4. data/Rakefile +55 -0
  5. data/VERSION +1 -0
  6. data/bin/mmconsole +60 -0
  7. data/jmonteiro-mongo_mapper.gemspec +195 -0
  8. data/lib/mongo_mapper.rb +128 -0
  9. data/lib/mongo_mapper/descendant_appends.rb +44 -0
  10. data/lib/mongo_mapper/document.rb +402 -0
  11. data/lib/mongo_mapper/dynamic_finder.rb +74 -0
  12. data/lib/mongo_mapper/embedded_document.rb +61 -0
  13. data/lib/mongo_mapper/finder_options.rb +127 -0
  14. data/lib/mongo_mapper/plugins.rb +19 -0
  15. data/lib/mongo_mapper/plugins/associations.rb +104 -0
  16. data/lib/mongo_mapper/plugins/associations/base.rb +121 -0
  17. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +28 -0
  18. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +23 -0
  19. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  20. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +49 -0
  21. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
  22. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  23. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
  24. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  25. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  26. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  27. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +66 -0
  28. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  29. data/lib/mongo_mapper/plugins/callbacks.rb +65 -0
  30. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  31. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  32. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  33. data/lib/mongo_mapper/plugins/equality.rb +11 -0
  34. data/lib/mongo_mapper/plugins/identity_map.rb +66 -0
  35. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  36. data/lib/mongo_mapper/plugins/keys.rb +295 -0
  37. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  38. data/lib/mongo_mapper/plugins/pagination.rb +85 -0
  39. data/lib/mongo_mapper/plugins/protected.rb +31 -0
  40. data/lib/mongo_mapper/plugins/rails.rb +80 -0
  41. data/lib/mongo_mapper/plugins/serialization.rb +109 -0
  42. data/lib/mongo_mapper/plugins/validations.rb +48 -0
  43. data/lib/mongo_mapper/support.rb +213 -0
  44. data/performance/read_write.rb +52 -0
  45. data/specs.watchr +51 -0
  46. data/test/NOTE_ON_TESTING +1 -0
  47. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
  48. data/test/functional/associations/test_belongs_to_proxy.rb +93 -0
  49. data/test/functional/associations/test_in_array_proxy.rb +309 -0
  50. data/test/functional/associations/test_many_documents_as_proxy.rb +246 -0
  51. data/test/functional/associations/test_many_documents_proxy.rb +437 -0
  52. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +175 -0
  53. data/test/functional/associations/test_many_embedded_proxy.rb +216 -0
  54. data/test/functional/associations/test_many_polymorphic_proxy.rb +340 -0
  55. data/test/functional/associations/test_one_proxy.rb +149 -0
  56. data/test/functional/test_associations.rb +44 -0
  57. data/test/functional/test_binary.rb +27 -0
  58. data/test/functional/test_callbacks.rb +81 -0
  59. data/test/functional/test_dirty.rb +156 -0
  60. data/test/functional/test_document.rb +1171 -0
  61. data/test/functional/test_embedded_document.rb +125 -0
  62. data/test/functional/test_identity_map.rb +233 -0
  63. data/test/functional/test_logger.rb +20 -0
  64. data/test/functional/test_modifiers.rb +252 -0
  65. data/test/functional/test_pagination.rb +93 -0
  66. data/test/functional/test_protected.rb +41 -0
  67. data/test/functional/test_string_id_compatibility.rb +67 -0
  68. data/test/functional/test_validations.rb +329 -0
  69. data/test/models.rb +232 -0
  70. data/test/support/custom_matchers.rb +55 -0
  71. data/test/support/timing.rb +16 -0
  72. data/test/test_helper.rb +60 -0
  73. data/test/unit/associations/test_base.rb +207 -0
  74. data/test/unit/associations/test_proxy.rb +103 -0
  75. data/test/unit/serializers/test_json_serializer.rb +189 -0
  76. data/test/unit/test_descendant_appends.rb +71 -0
  77. data/test/unit/test_document.rb +203 -0
  78. data/test/unit/test_dynamic_finder.rb +125 -0
  79. data/test/unit/test_embedded_document.rb +628 -0
  80. data/test/unit/test_finder_options.rb +325 -0
  81. data/test/unit/test_keys.rb +169 -0
  82. data/test/unit/test_mongo_mapper.rb +65 -0
  83. data/test/unit/test_pagination.rb +127 -0
  84. data/test/unit/test_plugins.rb +42 -0
  85. data/test/unit/test_rails.rb +139 -0
  86. data/test/unit/test_rails_compatibility.rb +42 -0
  87. data/test/unit/test_serialization.rb +51 -0
  88. data/test/unit/test_support.rb +350 -0
  89. data/test/unit/test_time_zones.rb +39 -0
  90. data/test/unit/test_validations.rb +492 -0
  91. metadata +260 -0
@@ -0,0 +1,23 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class BelongsToProxy < Proxy
5
+ def replace(doc)
6
+ if doc
7
+ doc.save if doc.new?
8
+ id = doc.id
9
+ end
10
+
11
+ owner[reflection.foreign_key] = id
12
+ reset
13
+ end
14
+
15
+ protected
16
+ def find_target
17
+ return nil if owner[reflection.foreign_key].nil?
18
+ klass.first(:id => owner[reflection.foreign_key])
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class Collection < Proxy
5
+ def to_ary
6
+ load_target
7
+ if target.is_a?(Array)
8
+ target.to_ary
9
+ else
10
+ Array(target)
11
+ end
12
+ end
13
+
14
+ def reset
15
+ super
16
+ target = []
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,49 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class EmbeddedCollection < Collection
5
+ def build(attributes={})
6
+ doc = klass.new(attributes)
7
+ assign_root_document(doc)
8
+ self << doc
9
+ doc
10
+ end
11
+
12
+ def find(id)
13
+ load_target
14
+ target.detect { |item| item.id.to_s == id || item.id == id }
15
+ end
16
+
17
+ def count
18
+ load_target
19
+ target.size
20
+ end
21
+
22
+ def <<(*docs)
23
+ load_target
24
+ docs.each do |doc|
25
+ assign_root_document(doc)
26
+ target << doc
27
+ end
28
+ end
29
+ alias_method :push, :<<
30
+ alias_method :concat, :<<
31
+
32
+ private
33
+ def _root_document
34
+ if owner.respond_to?(:_root_document)
35
+ owner._root_document
36
+ else
37
+ owner
38
+ end
39
+ end
40
+
41
+ def assign_root_document(*docs)
42
+ docs.each do |doc|
43
+ doc._root_document = _root_document
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,139 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class InArrayProxy < Collection
5
+ include ::MongoMapper::Finders
6
+
7
+ 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
20
+ end
21
+
22
+ 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
35
+ end
36
+
37
+ def paginate(options)
38
+ klass.paginate(scoped_options(options))
39
+ end
40
+
41
+ def all(options={})
42
+ klass.all(scoped_options(options))
43
+ end
44
+
45
+ def first(options={})
46
+ klass.first(scoped_options(options))
47
+ end
48
+
49
+ def last(options={})
50
+ klass.last(scoped_options(options))
51
+ end
52
+
53
+ def count(options={})
54
+ options.blank? ? ids.size : klass.count(scoped_options(options))
55
+ end
56
+
57
+ def destroy_all(options={})
58
+ all(options).each do |doc|
59
+ ids.delete(doc.id)
60
+ doc.destroy
61
+ end
62
+ reset
63
+ end
64
+
65
+ def delete_all(options={})
66
+ docs = all(options.merge(:select => ['_id']))
67
+ docs.each { |doc| ids.delete(doc.id) }
68
+ klass.delete(docs.map(&:id))
69
+ reset
70
+ end
71
+
72
+ def nullify
73
+ replace([])
74
+ reset
75
+ end
76
+
77
+ def create(attrs={})
78
+ doc = klass.create(attrs)
79
+ unless doc.new?
80
+ ids << doc.id
81
+ owner.save
82
+ end
83
+ doc
84
+ end
85
+
86
+ def create!(attrs={})
87
+ doc = klass.create!(attrs)
88
+ unless doc.new?
89
+ ids << doc.id
90
+ owner.save
91
+ end
92
+ doc
93
+ end
94
+
95
+ def <<(*docs)
96
+ flatten_deeper(docs).each do |doc|
97
+ doc.save if doc.new?
98
+ unless ids.include?(doc.id)
99
+ ids << doc.id
100
+ end
101
+ end
102
+ reset
103
+ end
104
+ alias_method :push, :<<
105
+ alias_method :concat, :<<
106
+
107
+ def replace(docs)
108
+ doc_ids = docs.map do |doc|
109
+ doc.save if doc.new?
110
+ doc.id
111
+ end
112
+ ids.replace(doc_ids.uniq)
113
+ reset
114
+ end
115
+
116
+ private
117
+ def scoped_conditions
118
+ {:_id => ids}
119
+ end
120
+
121
+ def scoped_options(options)
122
+ reflection.finder_options.merge(options).merge(scoped_conditions)
123
+ end
124
+
125
+ def scoped_ids(args)
126
+ args.flatten.reject { |id| !ids.include?(id) }
127
+ end
128
+
129
+ def find_target
130
+ ids.blank? ? [] : all
131
+ end
132
+
133
+ def ids
134
+ owner[options[:in]]
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,28 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyDocumentsAsProxy < ManyDocumentsProxy
5
+ protected
6
+ def scoped_conditions
7
+ {type_key_name => owner.class.name, id_key_name => owner.id}
8
+ end
9
+
10
+ def apply_scope(doc)
11
+ ensure_owner_saved
12
+ doc[type_key_name] = owner.class.name
13
+ doc[id_key_name] = owner.id
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,117 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyDocumentsProxy < Collection
5
+ include ::MongoMapper::Finders
6
+
7
+ def find(*args)
8
+ options = args.extract_options!
9
+ klass.find(*args << scoped_options(options))
10
+ end
11
+
12
+ def find!(*args)
13
+ options = args.extract_options!
14
+ klass.find!(*args << scoped_options(options))
15
+ end
16
+
17
+ def paginate(options)
18
+ klass.paginate(scoped_options(options))
19
+ end
20
+
21
+ def all(options={})
22
+ klass.all(scoped_options(options))
23
+ end
24
+
25
+ def first(options={})
26
+ klass.first(scoped_options(options))
27
+ end
28
+
29
+ def last(options={})
30
+ klass.last(scoped_options(options))
31
+ end
32
+
33
+ def count(options={})
34
+ klass.count(scoped_options(options))
35
+ end
36
+
37
+ def replace(docs)
38
+ load_target
39
+ target.map(&:destroy)
40
+ docs.each { |doc| apply_scope(doc).save }
41
+ reset
42
+ end
43
+
44
+ def <<(*docs)
45
+ ensure_owner_saved
46
+ flatten_deeper(docs).each { |doc| apply_scope(doc).save }
47
+ reset
48
+ end
49
+ alias_method :push, :<<
50
+ alias_method :concat, :<<
51
+
52
+ def build(attrs={})
53
+ doc = klass.new(attrs)
54
+ apply_scope(doc)
55
+ doc
56
+ end
57
+
58
+ def create(attrs={})
59
+ doc = klass.new(attrs)
60
+ apply_scope(doc).save
61
+ doc
62
+ end
63
+
64
+ def create!(attrs={})
65
+ doc = klass.new(attrs)
66
+ apply_scope(doc).save!
67
+ doc
68
+ end
69
+
70
+ def destroy_all(options={})
71
+ all(options).map(&:destroy)
72
+ reset
73
+ end
74
+
75
+ def delete_all(options={})
76
+ klass.delete_all(options.merge(scoped_conditions))
77
+ reset
78
+ end
79
+
80
+ def nullify
81
+ criteria = FinderOptions.new(klass, scoped_conditions).criteria
82
+ all(criteria).each do |doc|
83
+ doc.update_attributes(self.foreign_key => nil)
84
+ end
85
+ reset
86
+ end
87
+
88
+ protected
89
+ def scoped_conditions
90
+ {self.foreign_key => owner.id}
91
+ end
92
+
93
+ def scoped_options(options)
94
+ reflection.finder_options.merge(options).merge(scoped_conditions)
95
+ end
96
+
97
+ def find_target
98
+ all
99
+ end
100
+
101
+ def ensure_owner_saved
102
+ owner.save if owner.new?
103
+ end
104
+
105
+ def apply_scope(doc)
106
+ ensure_owner_saved
107
+ doc[foreign_key] = owner.id
108
+ doc
109
+ end
110
+
111
+ def foreign_key
112
+ options[:foreign_key] || owner.class.name.underscore.gsub("/", "_") + "_id"
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,31 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyEmbeddedPolymorphicProxy < EmbeddedCollection
5
+ def replace(values)
6
+ @_values = values.map do |v|
7
+ v.respond_to?(:attributes) ? v.attributes.merge(reflection.type_key_name => v.class.name) : v
8
+ end
9
+ reset
10
+ end
11
+
12
+ protected
13
+ def find_target
14
+ (@_values || []).map do |hash|
15
+ child = polymorphic_class(hash).new(hash)
16
+ assign_root_document(child)
17
+ child
18
+ end
19
+ end
20
+
21
+ def polymorphic_class(doc)
22
+ if class_name = doc[reflection.type_key_name]
23
+ class_name.constantize
24
+ else
25
+ klass
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyEmbeddedProxy < EmbeddedCollection
5
+ def replace(values)
6
+ @_values = values.map do |v|
7
+ v.respond_to?(:attributes) ? v.attributes : v
8
+ end
9
+ reset
10
+ end
11
+
12
+ private
13
+ def find_target
14
+ (@_values || []).map do |v|
15
+ child = klass.new(v)
16
+ assign_root_document(child)
17
+ child
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyPolymorphicProxy < ManyDocumentsProxy
5
+ private
6
+ def apply_scope(doc)
7
+ doc[reflection.type_key_name] = doc.class.name
8
+ super
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end