mrkurt-mongo_mapper 0.6.8
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.
- data/.gitignore +10 -0
- data/LICENSE +20 -0
- data/README.rdoc +38 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/bin/mmconsole +60 -0
- data/lib/mongo_mapper.rb +139 -0
- data/lib/mongo_mapper/associations.rb +72 -0
- data/lib/mongo_mapper/associations/base.rb +113 -0
- data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +26 -0
- data/lib/mongo_mapper/associations/belongs_to_proxy.rb +21 -0
- data/lib/mongo_mapper/associations/collection.rb +19 -0
- data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +26 -0
- data/lib/mongo_mapper/associations/many_documents_proxy.rb +115 -0
- data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +31 -0
- data/lib/mongo_mapper/associations/many_embedded_proxy.rb +54 -0
- data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +11 -0
- data/lib/mongo_mapper/associations/one_proxy.rb +61 -0
- data/lib/mongo_mapper/associations/proxy.rb +111 -0
- data/lib/mongo_mapper/callbacks.rb +61 -0
- data/lib/mongo_mapper/dirty.rb +117 -0
- data/lib/mongo_mapper/document.rb +496 -0
- data/lib/mongo_mapper/dynamic_finder.rb +74 -0
- data/lib/mongo_mapper/embedded_document.rb +380 -0
- data/lib/mongo_mapper/finder_options.rb +145 -0
- data/lib/mongo_mapper/key.rb +36 -0
- data/lib/mongo_mapper/mongo_mapper.rb +125 -0
- data/lib/mongo_mapper/pagination.rb +66 -0
- data/lib/mongo_mapper/rails_compatibility/document.rb +15 -0
- data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +28 -0
- data/lib/mongo_mapper/serialization.rb +54 -0
- data/lib/mongo_mapper/serializers/json_serializer.rb +48 -0
- data/lib/mongo_mapper/support.rb +192 -0
- data/lib/mongo_mapper/validations.rb +39 -0
- data/mongo_mapper.gemspec +173 -0
- data/specs.watchr +30 -0
- data/test/NOTE_ON_TESTING +1 -0
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +55 -0
- data/test/functional/associations/test_belongs_to_proxy.rb +91 -0
- data/test/functional/associations/test_many_documents_as_proxy.rb +246 -0
- data/test/functional/associations/test_many_documents_proxy.rb +477 -0
- data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +156 -0
- data/test/functional/associations/test_many_embedded_proxy.rb +192 -0
- data/test/functional/associations/test_many_polymorphic_proxy.rb +339 -0
- data/test/functional/associations/test_one_proxy.rb +131 -0
- data/test/functional/test_associations.rb +44 -0
- data/test/functional/test_binary.rb +33 -0
- data/test/functional/test_callbacks.rb +85 -0
- data/test/functional/test_dirty.rb +159 -0
- data/test/functional/test_document.rb +1198 -0
- data/test/functional/test_embedded_document.rb +135 -0
- data/test/functional/test_logger.rb +20 -0
- data/test/functional/test_modifiers.rb +242 -0
- data/test/functional/test_pagination.rb +95 -0
- data/test/functional/test_rails_compatibility.rb +25 -0
- data/test/functional/test_string_id_compatibility.rb +72 -0
- data/test/functional/test_validations.rb +361 -0
- data/test/models.rb +271 -0
- data/test/support/custom_matchers.rb +55 -0
- data/test/support/timing.rb +16 -0
- data/test/test_helper.rb +27 -0
- data/test/unit/associations/test_base.rb +182 -0
- data/test/unit/associations/test_proxy.rb +91 -0
- data/test/unit/serializers/test_json_serializer.rb +189 -0
- data/test/unit/test_document.rb +236 -0
- data/test/unit/test_dynamic_finder.rb +125 -0
- data/test/unit/test_embedded_document.rb +709 -0
- data/test/unit/test_finder_options.rb +325 -0
- data/test/unit/test_key.rb +172 -0
- data/test/unit/test_mongo_mapper.rb +65 -0
- data/test/unit/test_pagination.rb +119 -0
- data/test/unit/test_rails_compatibility.rb +52 -0
- data/test/unit/test_serializations.rb +52 -0
- data/test/unit/test_support.rb +346 -0
- data/test/unit/test_time_zones.rb +40 -0
- data/test/unit/test_validations.rb +503 -0
- metadata +239 -0
@@ -0,0 +1,26 @@
|
|
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
|
@@ -0,0 +1,21 @@
|
|
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
|
@@ -0,0 +1,26 @@
|
|
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
|
@@ -0,0 +1,115 @@
|
|
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
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Associations
|
3
|
+
class ManyEmbeddedPolymorphicProxy < Collection
|
4
|
+
def replace(values)
|
5
|
+
@_values = values.map do |v|
|
6
|
+
if v.kind_of?(EmbeddedDocument)
|
7
|
+
v.attributes.merge(reflection.type_key_name => v.class.name)
|
8
|
+
else
|
9
|
+
v
|
10
|
+
end
|
11
|
+
end
|
12
|
+
reset
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
def find_target
|
17
|
+
(@_values || []).map do |hash|
|
18
|
+
polymorphic_class(hash).new(hash)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def polymorphic_class(doc)
|
23
|
+
if class_name = doc[reflection.type_key_name]
|
24
|
+
class_name.constantize
|
25
|
+
else
|
26
|
+
klass
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Associations
|
3
|
+
class ManyEmbeddedProxy < Collection
|
4
|
+
def replace(values)
|
5
|
+
@_values = values.map do |v|
|
6
|
+
v.kind_of?(EmbeddedDocument) ? v.attributes : v
|
7
|
+
end
|
8
|
+
reset
|
9
|
+
end
|
10
|
+
|
11
|
+
def build(attributes={})
|
12
|
+
doc = klass.new(attributes)
|
13
|
+
assign_root_document(doc)
|
14
|
+
self << doc
|
15
|
+
doc
|
16
|
+
end
|
17
|
+
|
18
|
+
# TODO: test that both string and oid version work
|
19
|
+
def find(id)
|
20
|
+
load_target
|
21
|
+
target.detect { |item| item.id.to_s == id || item.id == id }
|
22
|
+
end
|
23
|
+
|
24
|
+
def <<(*docs)
|
25
|
+
load_target
|
26
|
+
docs.each do |doc|
|
27
|
+
assign_root_document(doc)
|
28
|
+
target << doc
|
29
|
+
end
|
30
|
+
end
|
31
|
+
alias_method :push, :<<
|
32
|
+
alias_method :concat, :<<
|
33
|
+
|
34
|
+
private
|
35
|
+
def find_target
|
36
|
+
(@_values || []).map do |v|
|
37
|
+
child = klass.new(v)
|
38
|
+
assign_root_document(child)
|
39
|
+
child
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def root_document
|
44
|
+
owner._root_document || owner
|
45
|
+
end
|
46
|
+
|
47
|
+
def assign_root_document(*docs)
|
48
|
+
docs.each do |doc|
|
49
|
+
doc._root_document = root_document
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Associations
|
3
|
+
class OneProxy < Proxy
|
4
|
+
def build(attrs={})
|
5
|
+
instantiate_target(:new, attrs)
|
6
|
+
end
|
7
|
+
|
8
|
+
def create(attrs={})
|
9
|
+
instantiate_target(:create, attrs)
|
10
|
+
end
|
11
|
+
|
12
|
+
def create!(attrs={})
|
13
|
+
instantiate_target(:create!, attrs)
|
14
|
+
end
|
15
|
+
|
16
|
+
def replace(doc)
|
17
|
+
load_target
|
18
|
+
|
19
|
+
if !@target.nil? && @target != doc
|
20
|
+
if options[:dependent] && !@target.new?
|
21
|
+
case options[:dependent]
|
22
|
+
when :delete
|
23
|
+
@target.delete
|
24
|
+
when :destroy
|
25
|
+
@target.destroy
|
26
|
+
when :nullify
|
27
|
+
@target[foreign_key] = nil
|
28
|
+
@target.save
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
if doc
|
34
|
+
owner.save if owner.new?
|
35
|
+
doc[foreign_key] = owner.id
|
36
|
+
doc.save if doc.new?
|
37
|
+
reset
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
def find_target
|
43
|
+
target_class.first(foreign_key => owner.id)
|
44
|
+
end
|
45
|
+
|
46
|
+
def instantiate_target(instantiator, attrs={})
|
47
|
+
@target = target_class.send(instantiator, attrs.update(foreign_key => owner.id))
|
48
|
+
loaded
|
49
|
+
@target
|
50
|
+
end
|
51
|
+
|
52
|
+
def target_class
|
53
|
+
@target_class ||= options[:class] || (options[:class_name] || association.name.to_s.camelize).constantize
|
54
|
+
end
|
55
|
+
|
56
|
+
def foreign_key
|
57
|
+
options[:foreign_key] || owner.class.name.foreign_key
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Associations
|
3
|
+
class Proxy
|
4
|
+
alias :proxy_respond_to? :respond_to?
|
5
|
+
alias :proxy_extend :extend
|
6
|
+
|
7
|
+
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ }
|
8
|
+
|
9
|
+
attr_reader :owner, :reflection, :target
|
10
|
+
|
11
|
+
alias :proxy_owner :owner
|
12
|
+
alias :proxy_target :target
|
13
|
+
alias :proxy_reflection :reflection
|
14
|
+
|
15
|
+
delegate :klass, :to => :proxy_reflection
|
16
|
+
delegate :options, :to => :proxy_reflection
|
17
|
+
delegate :collection, :to => :klass
|
18
|
+
|
19
|
+
def initialize(owner, reflection)
|
20
|
+
@owner, @reflection = owner, reflection
|
21
|
+
Array(reflection.options[:extend]).each { |ext| proxy_extend(ext) }
|
22
|
+
reset
|
23
|
+
end
|
24
|
+
|
25
|
+
def inspect
|
26
|
+
load_target
|
27
|
+
target.inspect
|
28
|
+
end
|
29
|
+
|
30
|
+
def loaded?
|
31
|
+
@loaded
|
32
|
+
end
|
33
|
+
|
34
|
+
def loaded
|
35
|
+
@loaded = true
|
36
|
+
end
|
37
|
+
|
38
|
+
def nil?
|
39
|
+
load_target
|
40
|
+
target.nil?
|
41
|
+
end
|
42
|
+
|
43
|
+
def blank?
|
44
|
+
load_target
|
45
|
+
target.blank?
|
46
|
+
end
|
47
|
+
|
48
|
+
def reload
|
49
|
+
reset
|
50
|
+
load_target
|
51
|
+
self unless target.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
def replace(v)
|
55
|
+
raise NotImplementedError
|
56
|
+
end
|
57
|
+
|
58
|
+
def reset
|
59
|
+
@loaded = false
|
60
|
+
target = nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def respond_to?(*args)
|
64
|
+
proxy_respond_to?(*args) || (load_target && target.respond_to?(*args))
|
65
|
+
end
|
66
|
+
|
67
|
+
def send(method, *args)
|
68
|
+
if proxy_respond_to?(method)
|
69
|
+
super
|
70
|
+
else
|
71
|
+
load_target
|
72
|
+
target.send(method, *args)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def ===(other)
|
77
|
+
load_target
|
78
|
+
other === target
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
def method_missing(method, *args, &block)
|
83
|
+
if load_target
|
84
|
+
if block_given?
|
85
|
+
target.send(method, *args) { |*block_args| block.call(*block_args) }
|
86
|
+
else
|
87
|
+
target.send(method, *args)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def load_target
|
93
|
+
@target = find_target unless loaded?
|
94
|
+
loaded
|
95
|
+
@target
|
96
|
+
rescue MongoMapper::DocumentNotFound
|
97
|
+
reset
|
98
|
+
end
|
99
|
+
|
100
|
+
def find_target
|
101
|
+
raise NotImplementedError
|
102
|
+
end
|
103
|
+
|
104
|
+
def flatten_deeper(array)
|
105
|
+
array.collect do |element|
|
106
|
+
(element.respond_to?(:flatten) && !element.is_a?(Hash)) ? element.flatten : element
|
107
|
+
end.flatten
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|