mongo_mapper 0.6.10 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/README.rdoc +5 -14
  2. data/Rakefile +1 -1
  3. data/VERSION +1 -1
  4. data/lib/mongo_mapper.rb +48 -56
  5. data/lib/mongo_mapper/document.rb +136 -164
  6. data/lib/mongo_mapper/embedded_document.rb +29 -354
  7. data/lib/mongo_mapper/plugins.rb +31 -0
  8. data/lib/mongo_mapper/plugins/associations.rb +105 -0
  9. data/lib/mongo_mapper/plugins/associations/base.rb +123 -0
  10. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
  11. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
  12. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  13. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +50 -0
  14. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
  15. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  16. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
  17. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  18. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  19. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  20. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  21. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  22. data/lib/mongo_mapper/plugins/callbacks.rb +65 -0
  23. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  24. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  25. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  26. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  27. data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
  28. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  29. data/lib/mongo_mapper/plugins/keys.rb +324 -0
  30. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  31. data/lib/mongo_mapper/plugins/pagination.rb +24 -0
  32. data/lib/mongo_mapper/plugins/pagination/proxy.rb +68 -0
  33. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  34. data/lib/mongo_mapper/plugins/rails.rb +45 -0
  35. data/lib/mongo_mapper/plugins/serialization.rb +105 -0
  36. data/lib/mongo_mapper/plugins/validations.rb +46 -0
  37. data/lib/mongo_mapper/query.rb +130 -0
  38. data/lib/mongo_mapper/support.rb +40 -17
  39. data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
  40. data/lib/mongo_mapper/support/find.rb +77 -0
  41. data/mongo_mapper.gemspec +55 -38
  42. data/performance/read_write.rb +52 -0
  43. data/specs.watchr +23 -2
  44. data/test/functional/associations/test_belongs_to_proxy.rb +12 -10
  45. data/test/functional/associations/test_many_documents_as_proxy.rb +4 -21
  46. data/test/functional/associations/test_many_documents_proxy.rb +2 -8
  47. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +59 -39
  48. data/test/functional/associations/test_many_embedded_proxy.rb +145 -81
  49. data/test/functional/associations/test_many_polymorphic_proxy.rb +2 -40
  50. data/test/functional/associations/test_one_proxy.rb +25 -10
  51. data/test/functional/test_binary.rb +2 -8
  52. data/test/functional/test_callbacks.rb +1 -5
  53. data/test/functional/test_dirty.rb +27 -23
  54. data/test/functional/test_document.rb +224 -165
  55. data/test/functional/test_embedded_document.rb +72 -82
  56. data/test/functional/test_identity_map.rb +508 -0
  57. data/test/functional/test_modifiers.rb +15 -5
  58. data/test/functional/test_pagination.rb +1 -3
  59. data/test/functional/test_protected.rb +155 -0
  60. data/test/functional/test_string_id_compatibility.rb +7 -12
  61. data/test/functional/test_validations.rb +26 -58
  62. data/test/models.rb +0 -39
  63. data/test/test_helper.rb +37 -3
  64. data/test/unit/associations/test_base.rb +5 -5
  65. data/test/unit/associations/test_proxy.rb +8 -6
  66. data/test/unit/test_descendant_appends.rb +71 -0
  67. data/test/unit/test_document.rb +71 -76
  68. data/test/unit/test_dynamic_finder.rb +27 -29
  69. data/test/unit/test_embedded_document.rb +555 -601
  70. data/test/unit/{test_key.rb → test_keys.rb} +2 -5
  71. data/test/unit/test_mongo_mapper.rb +69 -9
  72. data/test/unit/test_pagination.rb +40 -32
  73. data/test/unit/test_plugins.rb +50 -0
  74. data/test/unit/{test_finder_options.rb → test_query.rb} +74 -65
  75. data/test/unit/test_rails.rb +123 -0
  76. data/test/unit/{test_serializations.rb → test_serialization.rb} +1 -2
  77. data/test/unit/test_support.rb +23 -7
  78. data/test/unit/test_time_zones.rb +3 -4
  79. data/test/unit/test_validations.rb +58 -17
  80. metadata +53 -36
  81. data/lib/mongo_mapper/associations.rb +0 -78
  82. data/lib/mongo_mapper/associations/base.rb +0 -119
  83. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +0 -26
  84. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +0 -21
  85. data/lib/mongo_mapper/associations/collection.rb +0 -19
  86. data/lib/mongo_mapper/associations/in_array_proxy.rb +0 -137
  87. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +0 -26
  88. data/lib/mongo_mapper/associations/many_documents_proxy.rb +0 -115
  89. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +0 -31
  90. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +0 -54
  91. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +0 -11
  92. data/lib/mongo_mapper/associations/one_proxy.rb +0 -64
  93. data/lib/mongo_mapper/associations/proxy.rb +0 -116
  94. data/lib/mongo_mapper/callbacks.rb +0 -61
  95. data/lib/mongo_mapper/dirty.rb +0 -117
  96. data/lib/mongo_mapper/dynamic_finder.rb +0 -74
  97. data/lib/mongo_mapper/finder_options.rb +0 -145
  98. data/lib/mongo_mapper/key.rb +0 -36
  99. data/lib/mongo_mapper/mongo_mapper.rb +0 -125
  100. data/lib/mongo_mapper/pagination.rb +0 -66
  101. data/lib/mongo_mapper/rails_compatibility/document.rb +0 -15
  102. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +0 -28
  103. data/lib/mongo_mapper/serialization.rb +0 -54
  104. data/lib/mongo_mapper/serializers/json_serializer.rb +0 -48
  105. data/lib/mongo_mapper/validations.rb +0 -39
  106. data/test/functional/test_rails_compatibility.rb +0 -25
@@ -1,78 +0,0 @@
1
- module MongoMapper
2
- module Associations
3
- module ClassMethods
4
- def belongs_to(association_id, options={}, &extension)
5
- create_association(:belongs_to, association_id, options, &extension)
6
- end
7
-
8
- def many(association_id, options={}, &extension)
9
- create_association(:many, association_id, options, &extension)
10
- end
11
-
12
- def one(association_id, options={}, &extension)
13
- create_association(:one, association_id, options, &extension)
14
- end
15
-
16
- def associations
17
- @associations ||= HashWithIndifferentAccess.new
18
- end
19
-
20
- def associations=(hash)
21
- @associations = hash
22
- end
23
-
24
- def inherited(subclass)
25
- subclass.associations = associations.dup
26
- super
27
- end
28
-
29
- private
30
- def create_association(type, name, options, &extension)
31
- association = Associations::Base.new(type, name, options, &extension)
32
- associations[association.name] = association
33
-
34
- define_method(association.name) do
35
- get_proxy(association)
36
- end
37
-
38
- define_method("#{association.name}=") do |value|
39
- get_proxy(association).replace(value)
40
- value
41
- end
42
-
43
- if association.one? || association.belongs_to?
44
- define_method("#{association.name}?") do
45
- get_proxy(association).present?
46
- end
47
- end
48
-
49
- if association.options[:dependent] && association.many? && !association.embeddable?
50
- after_destroy do |doc|
51
- case association.options[:dependent]
52
- when :destroy
53
- doc.get_proxy(association).destroy_all
54
- when :delete_all
55
- doc.get_proxy(association).delete_all
56
- when :nullify
57
- doc.get_proxy(association).nullify
58
- end
59
- end
60
- end
61
- end
62
- end
63
-
64
- module InstanceMethods
65
- def associations
66
- self.class.associations
67
- end
68
-
69
- def get_proxy(association)
70
- unless proxy = self.instance_variable_get(association.ivar)
71
- proxy = association.proxy_class.new(self, association)
72
- self.instance_variable_set(association.ivar, proxy)
73
- end
74
- proxy
75
- end
76
- end
77
- end
78
- end
@@ -1,119 +0,0 @@
1
- module MongoMapper
2
- module Associations
3
- class Base
4
- attr_reader :type, :name, :options, :finder_options
5
-
6
- # Options that should not be considered MongoDB query options/criteria
7
- AssociationOptions = [:as, :class, :class_name, :dependent, :extend, :foreign_key, :in, :polymorphic]
8
-
9
- def initialize(type, name, options={}, &extension)
10
- @type, @name, @options, @finder_options = type, name, {}, {}
11
- options.symbolize_keys!
12
-
13
- options[:extend] = modulized_extensions(extension, options[:extend])
14
-
15
- options.each_pair do |key, value|
16
- if AssociationOptions.include?(key)
17
- @options[key] = value
18
- else
19
- @finder_options[key] = value
20
- end
21
- end
22
- end
23
-
24
- def class_name
25
- @class_name ||= begin
26
- if cn = options[:class_name]
27
- cn
28
- elsif many?
29
- name.to_s.singularize.camelize
30
- else
31
- name.to_s.camelize
32
- end
33
- end
34
- end
35
-
36
- def klass
37
- @klass ||= options[:class] || class_name.constantize
38
- end
39
-
40
- def many?
41
- @many_type ||= @type == :many
42
- end
43
-
44
- def belongs_to?
45
- @belongs_to_type ||= @type == :belongs_to
46
- end
47
-
48
- def one?
49
- @one_type ||= @type == :one
50
- end
51
-
52
- def polymorphic?
53
- !!@options[:polymorphic]
54
- end
55
-
56
- def as?
57
- !!@options[:as]
58
- end
59
-
60
- def in_array?
61
- !!@options[:in]
62
- end
63
-
64
- def embeddable?
65
- many? && klass.embeddable?
66
- end
67
-
68
- def type_key_name
69
- @type_key_name ||= many? ? '_type' : "#{as}_type"
70
- end
71
-
72
- def as
73
- @options[:as] || self.name
74
- end
75
-
76
- def foreign_key
77
- @options[:foreign_key] || "#{name}_id"
78
- end
79
-
80
- def ivar
81
- @ivar ||= "@_#{name}"
82
- end
83
-
84
- def proxy_class
85
- @proxy_class ||= begin
86
- if many?
87
- if self.klass.embeddable?
88
- polymorphic? ? ManyEmbeddedPolymorphicProxy : ManyEmbeddedProxy
89
- else
90
- if polymorphic?
91
- ManyPolymorphicProxy
92
- elsif as?
93
- ManyDocumentsAsProxy
94
- elsif in_array?
95
- InArrayProxy
96
- else
97
- ManyDocumentsProxy
98
- end
99
- end
100
- elsif one?
101
- OneProxy
102
- else
103
- polymorphic? ? BelongsToPolymorphicProxy : BelongsToProxy
104
- end
105
- end
106
- end
107
-
108
- private
109
-
110
- # @param [Array<Module, Proc>] extensions a collection of Modules or
111
- # Procs that extend the behaviour of this association.
112
- def modulized_extensions(*extensions)
113
- extensions.flatten.compact.map do |extension|
114
- Proc === extension ? Module.new(&extension) : extension
115
- end
116
- end
117
- end
118
- end
119
- end
@@ -1,26 +0,0 @@
1
- module MongoMapper
2
- module Associations
3
- class BelongsToPolymorphicProxy < Proxy
4
- def replace(doc)
5
- if doc
6
- doc.save if doc.new?
7
- id, type = doc.id, doc.class.name
8
- end
9
-
10
- owner[reflection.foreign_key] = id
11
- owner[reflection.type_key_name] = type
12
- reset
13
- end
14
-
15
- protected
16
- def find_target
17
- return nil if association_class.nil? || owner[reflection.foreign_key].nil?
18
- association_class.first(:id => owner[reflection.foreign_key])
19
- end
20
-
21
- def association_class
22
- proxy_owner[reflection.type_key_name] ? proxy_owner[reflection.type_key_name].constantize : nil
23
- end
24
- end
25
- end
26
- end
@@ -1,21 +0,0 @@
1
- module MongoMapper
2
- module Associations
3
- class BelongsToProxy < Proxy
4
- def replace(doc)
5
- if doc
6
- doc.save if doc.new?
7
- id = doc.id
8
- end
9
-
10
- owner[reflection.foreign_key] = id
11
- reset
12
- end
13
-
14
- protected
15
- def find_target
16
- return nil if owner[reflection.foreign_key].nil?
17
- klass.first(:id => owner[reflection.foreign_key])
18
- end
19
- end
20
- end
21
- end
@@ -1,19 +0,0 @@
1
- module MongoMapper
2
- module Associations
3
- class Collection < Proxy
4
- def to_ary
5
- load_target
6
- if target.is_a?(Array)
7
- target.to_ary
8
- else
9
- Array(target)
10
- end
11
- end
12
-
13
- def reset
14
- super
15
- target = []
16
- end
17
- end
18
- end
19
- end
@@ -1,137 +0,0 @@
1
- module MongoMapper
2
- module Associations
3
- class InArrayProxy < Collection
4
- include ::MongoMapper::Finders
5
-
6
- def find(*args)
7
- options = args.extract_options!
8
-
9
- case args.first
10
- when :first
11
- first(options)
12
- when :last
13
- last(options)
14
- when :all
15
- all(options)
16
- else
17
- klass.find(*scoped_ids(args) << scoped_options(options))
18
- end
19
- end
20
-
21
- def find!(*args)
22
- options = args.extract_options!
23
-
24
- case args.first
25
- when :first
26
- first(options)
27
- when :last
28
- last(options)
29
- when :all
30
- all(options)
31
- else
32
- klass.find!(*scoped_ids(args) << scoped_options(options))
33
- end
34
- end
35
-
36
- def paginate(options)
37
- klass.paginate(scoped_options(options))
38
- end
39
-
40
- def all(options={})
41
- klass.all(scoped_options(options))
42
- end
43
-
44
- def first(options={})
45
- klass.first(scoped_options(options))
46
- end
47
-
48
- def last(options={})
49
- klass.last(scoped_options(options))
50
- end
51
-
52
- def count(options={})
53
- options.blank? ? ids.size : klass.count(scoped_options(options))
54
- end
55
-
56
- def destroy_all(options={})
57
- all(options).each do |doc|
58
- ids.delete(doc.id)
59
- doc.destroy
60
- end
61
- reset
62
- end
63
-
64
- def delete_all(options={})
65
- docs = all(options.merge(:select => ['_id']))
66
- docs.each { |doc| ids.delete(doc.id) }
67
- klass.delete(docs.map(&:id))
68
- reset
69
- end
70
-
71
- def nullify
72
- replace([])
73
- reset
74
- end
75
-
76
- def create(attrs={})
77
- doc = klass.create(attrs)
78
- unless doc.new?
79
- ids << doc.id
80
- owner.save
81
- end
82
- doc
83
- end
84
-
85
- def create!(attrs={})
86
- doc = klass.create!(attrs)
87
- unless doc.new?
88
- ids << doc.id
89
- owner.save
90
- end
91
- doc
92
- end
93
-
94
- def <<(*docs)
95
- flatten_deeper(docs).each do |doc|
96
- doc.save if doc.new?
97
- unless ids.include?(doc.id)
98
- ids << doc.id
99
- end
100
- end
101
- reset
102
- end
103
- alias_method :push, :<<
104
- alias_method :concat, :<<
105
-
106
- def replace(docs)
107
- doc_ids = docs.map do |doc|
108
- doc.save if doc.new?
109
- doc.id
110
- end
111
- ids.replace(doc_ids.uniq)
112
- reset
113
- end
114
-
115
- private
116
- def scoped_conditions
117
- {:_id => ids}
118
- end
119
-
120
- def scoped_options(options)
121
- reflection.finder_options.merge(options).merge(scoped_conditions)
122
- end
123
-
124
- def scoped_ids(args)
125
- args.flatten.reject { |id| !ids.include?(id) }
126
- end
127
-
128
- def find_target
129
- ids.blank? ? [] : all
130
- end
131
-
132
- def ids
133
- owner[options[:in]]
134
- end
135
- end
136
- end
137
- end
@@ -1,26 +0,0 @@
1
- module MongoMapper
2
- module Associations
3
- class ManyDocumentsAsProxy < ManyDocumentsProxy
4
- protected
5
- def scoped_conditions
6
- {type_key_name => owner.class.name, id_key_name => owner.id}
7
- end
8
-
9
- def apply_scope(doc)
10
- ensure_owner_saved
11
- doc[type_key_name] = owner.class.name
12
- doc[id_key_name] = owner.id
13
- doc
14
- end
15
-
16
- private
17
- def type_key_name
18
- "#{options[:as]}_type"
19
- end
20
-
21
- def id_key_name
22
- "#{options[:as]}_id"
23
- end
24
- end
25
- end
26
- end
@@ -1,115 +0,0 @@
1
- module MongoMapper
2
- module Associations
3
- class ManyDocumentsProxy < Collection
4
- include ::MongoMapper::Finders
5
-
6
- def find(*args)
7
- options = args.extract_options!
8
- klass.find(*args << scoped_options(options))
9
- end
10
-
11
- def find!(*args)
12
- options = args.extract_options!
13
- klass.find!(*args << scoped_options(options))
14
- end
15
-
16
- def paginate(options)
17
- klass.paginate(scoped_options(options))
18
- end
19
-
20
- def all(options={})
21
- klass.all(scoped_options(options))
22
- end
23
-
24
- def first(options={})
25
- klass.first(scoped_options(options))
26
- end
27
-
28
- def last(options={})
29
- klass.last(scoped_options(options))
30
- end
31
-
32
- def count(options={})
33
- klass.count(scoped_options(options))
34
- end
35
-
36
- def replace(docs)
37
- load_target
38
- target.map(&:destroy)
39
- docs.each { |doc| apply_scope(doc).save }
40
- reset
41
- end
42
-
43
- def <<(*docs)
44
- ensure_owner_saved
45
- flatten_deeper(docs).each { |doc| apply_scope(doc).save }
46
- reset
47
- end
48
- alias_method :push, :<<
49
- alias_method :concat, :<<
50
-
51
- def build(attrs={})
52
- doc = klass.new(attrs)
53
- apply_scope(doc)
54
- doc
55
- end
56
-
57
- def create(attrs={})
58
- doc = klass.new(attrs)
59
- apply_scope(doc).save
60
- doc
61
- end
62
-
63
- def create!(attrs={})
64
- doc = klass.new(attrs)
65
- apply_scope(doc).save!
66
- doc
67
- end
68
-
69
- def destroy_all(options={})
70
- all(options).map(&:destroy)
71
- reset
72
- end
73
-
74
- def delete_all(options={})
75
- klass.delete_all(options.merge(scoped_conditions))
76
- reset
77
- end
78
-
79
- def nullify
80
- criteria = FinderOptions.new(klass, scoped_conditions).criteria
81
- all(criteria).each do |doc|
82
- doc.update_attributes(self.foreign_key => nil)
83
- end
84
- reset
85
- end
86
-
87
- protected
88
- def scoped_conditions
89
- {self.foreign_key => owner.id}
90
- end
91
-
92
- def scoped_options(options)
93
- reflection.finder_options.merge(options).merge(scoped_conditions)
94
- end
95
-
96
- def find_target
97
- all
98
- end
99
-
100
- def ensure_owner_saved
101
- owner.save if owner.new?
102
- end
103
-
104
- def apply_scope(doc)
105
- ensure_owner_saved
106
- doc[foreign_key] = owner.id
107
- doc
108
- end
109
-
110
- def foreign_key
111
- options[:foreign_key] || owner.class.name.underscore.gsub("/", "_") + "_id"
112
- end
113
- end
114
- end
115
- end