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.
Files changed (77) 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/lib/mongo_mapper.rb +139 -0
  8. data/lib/mongo_mapper/associations.rb +72 -0
  9. data/lib/mongo_mapper/associations/base.rb +113 -0
  10. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +26 -0
  11. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +21 -0
  12. data/lib/mongo_mapper/associations/collection.rb +19 -0
  13. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +26 -0
  14. data/lib/mongo_mapper/associations/many_documents_proxy.rb +115 -0
  15. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +31 -0
  16. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +54 -0
  17. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +11 -0
  18. data/lib/mongo_mapper/associations/one_proxy.rb +61 -0
  19. data/lib/mongo_mapper/associations/proxy.rb +111 -0
  20. data/lib/mongo_mapper/callbacks.rb +61 -0
  21. data/lib/mongo_mapper/dirty.rb +117 -0
  22. data/lib/mongo_mapper/document.rb +496 -0
  23. data/lib/mongo_mapper/dynamic_finder.rb +74 -0
  24. data/lib/mongo_mapper/embedded_document.rb +380 -0
  25. data/lib/mongo_mapper/finder_options.rb +145 -0
  26. data/lib/mongo_mapper/key.rb +36 -0
  27. data/lib/mongo_mapper/mongo_mapper.rb +125 -0
  28. data/lib/mongo_mapper/pagination.rb +66 -0
  29. data/lib/mongo_mapper/rails_compatibility/document.rb +15 -0
  30. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +28 -0
  31. data/lib/mongo_mapper/serialization.rb +54 -0
  32. data/lib/mongo_mapper/serializers/json_serializer.rb +48 -0
  33. data/lib/mongo_mapper/support.rb +192 -0
  34. data/lib/mongo_mapper/validations.rb +39 -0
  35. data/mongo_mapper.gemspec +173 -0
  36. data/specs.watchr +30 -0
  37. data/test/NOTE_ON_TESTING +1 -0
  38. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +55 -0
  39. data/test/functional/associations/test_belongs_to_proxy.rb +91 -0
  40. data/test/functional/associations/test_many_documents_as_proxy.rb +246 -0
  41. data/test/functional/associations/test_many_documents_proxy.rb +477 -0
  42. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +156 -0
  43. data/test/functional/associations/test_many_embedded_proxy.rb +192 -0
  44. data/test/functional/associations/test_many_polymorphic_proxy.rb +339 -0
  45. data/test/functional/associations/test_one_proxy.rb +131 -0
  46. data/test/functional/test_associations.rb +44 -0
  47. data/test/functional/test_binary.rb +33 -0
  48. data/test/functional/test_callbacks.rb +85 -0
  49. data/test/functional/test_dirty.rb +159 -0
  50. data/test/functional/test_document.rb +1198 -0
  51. data/test/functional/test_embedded_document.rb +135 -0
  52. data/test/functional/test_logger.rb +20 -0
  53. data/test/functional/test_modifiers.rb +242 -0
  54. data/test/functional/test_pagination.rb +95 -0
  55. data/test/functional/test_rails_compatibility.rb +25 -0
  56. data/test/functional/test_string_id_compatibility.rb +72 -0
  57. data/test/functional/test_validations.rb +361 -0
  58. data/test/models.rb +271 -0
  59. data/test/support/custom_matchers.rb +55 -0
  60. data/test/support/timing.rb +16 -0
  61. data/test/test_helper.rb +27 -0
  62. data/test/unit/associations/test_base.rb +182 -0
  63. data/test/unit/associations/test_proxy.rb +91 -0
  64. data/test/unit/serializers/test_json_serializer.rb +189 -0
  65. data/test/unit/test_document.rb +236 -0
  66. data/test/unit/test_dynamic_finder.rb +125 -0
  67. data/test/unit/test_embedded_document.rb +709 -0
  68. data/test/unit/test_finder_options.rb +325 -0
  69. data/test/unit/test_key.rb +172 -0
  70. data/test/unit/test_mongo_mapper.rb +65 -0
  71. data/test/unit/test_pagination.rb +119 -0
  72. data/test/unit/test_rails_compatibility.rb +52 -0
  73. data/test/unit/test_serializations.rb +52 -0
  74. data/test/unit/test_support.rb +346 -0
  75. data/test/unit/test_time_zones.rb +40 -0
  76. data/test/unit/test_validations.rb +503 -0
  77. 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,19 @@
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
@@ -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,11 @@
1
+ module MongoMapper
2
+ module Associations
3
+ class ManyPolymorphicProxy < ManyDocumentsProxy
4
+ private
5
+ def apply_scope(doc)
6
+ doc[reflection.type_key_name] = doc.class.name
7
+ super
8
+ end
9
+ end
10
+ end
11
+ 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