active_mongoid 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.coveralls.yml +1 -0
  4. data/.gitignore +22 -0
  5. data/.ruby_gemset +1 -0
  6. data/.ruby_version +1 -0
  7. data/.travis.yml +11 -0
  8. data/Appraisals +7 -0
  9. data/Gemfile +4 -0
  10. data/LICENSE.txt +22 -0
  11. data/README.md +198 -0
  12. data/Rakefile +7 -0
  13. data/active_mongoid.gemspec +36 -0
  14. data/gemfiles/mongoid_2.8.gemfile +7 -0
  15. data/gemfiles/mongoid_2.8.gemfile.lock +105 -0
  16. data/gemfiles/mongoid_3.1.gemfile +7 -0
  17. data/gemfiles/mongoid_3.1.gemfile.lock +108 -0
  18. data/lib/active_mongoid.rb +8 -0
  19. data/lib/active_mongoid/associations.rb +82 -0
  20. data/lib/active_mongoid/associations/binding.rb +77 -0
  21. data/lib/active_mongoid/associations/builder.rb +26 -0
  22. data/lib/active_mongoid/associations/builders/in.rb +17 -0
  23. data/lib/active_mongoid/associations/builders/many.rb +15 -0
  24. data/lib/active_mongoid/associations/builders/one.rb +15 -0
  25. data/lib/active_mongoid/associations/document_relation/accessors.rb +100 -0
  26. data/lib/active_mongoid/associations/document_relation/associations.rb +33 -0
  27. data/lib/active_mongoid/associations/document_relation/auto_save.rb +31 -0
  28. data/lib/active_mongoid/associations/document_relation/bindings/in.rb +48 -0
  29. data/lib/active_mongoid/associations/document_relation/bindings/many.rb +19 -0
  30. data/lib/active_mongoid/associations/document_relation/bindings/one.rb +19 -0
  31. data/lib/active_mongoid/associations/document_relation/builders.rb +31 -0
  32. data/lib/active_mongoid/associations/document_relation/dependent.rb +26 -0
  33. data/lib/active_mongoid/associations/document_relation/macros.rb +51 -0
  34. data/lib/active_mongoid/associations/document_relation/referenced/in.rb +72 -0
  35. data/lib/active_mongoid/associations/document_relation/referenced/many.rb +125 -0
  36. data/lib/active_mongoid/associations/document_relation/referenced/one.rb +75 -0
  37. data/lib/active_mongoid/associations/many.rb +211 -0
  38. data/lib/active_mongoid/associations/metadata.rb +229 -0
  39. data/lib/active_mongoid/associations/one.rb +21 -0
  40. data/lib/active_mongoid/associations/proxy.rb +38 -0
  41. data/lib/active_mongoid/associations/record_relation/accessors.rb +80 -0
  42. data/lib/active_mongoid/associations/record_relation/associations.rb +33 -0
  43. data/lib/active_mongoid/associations/record_relation/auto_save.rb +43 -0
  44. data/lib/active_mongoid/associations/record_relation/bindings/in.rb +48 -0
  45. data/lib/active_mongoid/associations/record_relation/bindings/many.rb +19 -0
  46. data/lib/active_mongoid/associations/record_relation/bindings/one.rb +19 -0
  47. data/lib/active_mongoid/associations/record_relation/builders.rb +31 -0
  48. data/lib/active_mongoid/associations/record_relation/dependent.rb +26 -0
  49. data/lib/active_mongoid/associations/record_relation/macros.rb +65 -0
  50. data/lib/active_mongoid/associations/record_relation/referenced/in.rb +72 -0
  51. data/lib/active_mongoid/associations/record_relation/referenced/many.rb +128 -0
  52. data/lib/active_mongoid/associations/record_relation/referenced/one.rb +75 -0
  53. data/lib/active_mongoid/associations/targets/enumerable.rb +161 -0
  54. data/lib/active_mongoid/bson_id.rb +44 -0
  55. data/lib/active_mongoid/finder_proxy.rb +55 -0
  56. data/lib/active_mongoid/finders.rb +60 -0
  57. data/lib/active_mongoid/version.rb +3 -0
  58. data/spec/lib/associations/document_relation/accessors_spec.rb +330 -0
  59. data/spec/lib/associations/document_relation/auto_save_spec.rb +157 -0
  60. data/spec/lib/associations/document_relation/bindings/in_spec.rb +39 -0
  61. data/spec/lib/associations/document_relation/bindings/many_spec.rb +36 -0
  62. data/spec/lib/associations/document_relation/bindings/one_spec.rb +39 -0
  63. data/spec/lib/associations/document_relation/builders_spec.rb +117 -0
  64. data/spec/lib/associations/document_relation/dependent_spec.rb +87 -0
  65. data/spec/lib/associations/document_relation/macros_spec.rb +68 -0
  66. data/spec/lib/associations/document_relation/referenced/in_spec.rb +27 -0
  67. data/spec/lib/associations/document_relation/referenced/many_spec.rb +32 -0
  68. data/spec/lib/associations/document_relation/referenced/one_spec.rb +28 -0
  69. data/spec/lib/associations/metadata_spec.rb +157 -0
  70. data/spec/lib/associations/record_relation/accessors_spec.rb +328 -0
  71. data/spec/lib/associations/record_relation/auto_save_spec.rb +157 -0
  72. data/spec/lib/associations/record_relation/bindings/in_spec.rb +39 -0
  73. data/spec/lib/associations/record_relation/bindings/many_spec.rb +39 -0
  74. data/spec/lib/associations/record_relation/bindings/one_spec.rb +57 -0
  75. data/spec/lib/associations/record_relation/builders_spec.rb +118 -0
  76. data/spec/lib/associations/record_relation/dependent_spec.rb +87 -0
  77. data/spec/lib/associations/record_relation/macros_spec.rb +73 -0
  78. data/spec/lib/associations/record_relation/referenced/in_spec.rb +27 -0
  79. data/spec/lib/associations/record_relation/referenced/many_spec.rb +32 -0
  80. data/spec/lib/associations/record_relation/referenced/one_spec.rb +27 -0
  81. data/spec/lib/bson_id_spec.rb +48 -0
  82. data/spec/lib/finders_spec.rb +105 -0
  83. data/spec/spec_helper.rb +89 -0
  84. data/spec/support/models/active_record/address.rb +6 -0
  85. data/spec/support/models/active_record/division.rb +16 -0
  86. data/spec/support/models/active_record/division_setting.rb +9 -0
  87. data/spec/support/models/active_record/player.rb +12 -0
  88. data/spec/support/models/mongoid/league.rb +10 -0
  89. data/spec/support/models/mongoid/person.rb +9 -0
  90. data/spec/support/models/mongoid/post.rb +9 -0
  91. data/spec/support/models/mongoid/stat.rb +8 -0
  92. data/spec/support/models/mongoid/team.rb +9 -0
  93. data/spec/support/shared_examples/shared_many_spec.rb +411 -0
  94. metadata +370 -0
@@ -0,0 +1,75 @@
1
+ module ActiveMongoid
2
+ module Associations
3
+ module DocumentRelation
4
+ module Referenced
5
+ class One < Associations::One
6
+
7
+ def initialize(base, target, metadata)
8
+ init(base, target, metadata) do
9
+ bind_one
10
+ end
11
+ end
12
+
13
+ def substitute(replacement)
14
+ unbind_one
15
+ if base.persisted?
16
+ if __metadata__.destructive?
17
+ send(__metadata__.dependent)
18
+ else
19
+ save if persisted?
20
+ end
21
+ end
22
+ One.new(base, replacement, __metadata__) if replacement
23
+ end
24
+
25
+ private
26
+
27
+ def binding
28
+ Bindings::One.new(base, target, __metadata__)
29
+ end
30
+
31
+ class << self
32
+
33
+ def stores_foreign_key?
34
+ false
35
+ end
36
+
37
+ def foreign_key(name)
38
+ "#{name}#{foreign_key_suffix}"
39
+ end
40
+
41
+ def foreign_key_default
42
+ nil
43
+ end
44
+
45
+ def foreign_key_suffix
46
+ "_id"
47
+ end
48
+
49
+ def primary_key_default
50
+ "id"
51
+ end
52
+
53
+ def macro
54
+ :has_one_document
55
+ end
56
+
57
+ def builder(base, meta, object)
58
+ ActiveMongoid::Associations::Builders::One.new(base, meta, object)
59
+ end
60
+
61
+ def criteria(metadata, object, type = nil)
62
+ crit = metadata.klass.where(metadata.foreign_key => object)
63
+ if metadata.polymorphic?
64
+ crit = crit.where(metadata.type => type.name)
65
+ end
66
+ crit
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,211 @@
1
+ module ActiveMongoid
2
+ module Associations
3
+ class Many < Proxy
4
+ include ::Mongoid::Threaded::Lifecycle
5
+
6
+ delegate :avg, :max, :min, :sum, to: :criteria
7
+ delegate :length, :size, to: :target
8
+ delegate :count, to: :criteria
9
+ delegate :first, :in_memory, :last, :reset, :uniq, to: :target
10
+
11
+ def initialize(base, target, metadata)
12
+ init(base, ActiveMongoid::Associations::Targets::Enumerable.new(target), metadata) do
13
+ end
14
+ end
15
+
16
+ def <<(*args)
17
+ objs = args.flatten
18
+ return concat(objs) if objs.size > 1
19
+ if objs = objs.first
20
+ append(objs)
21
+ objs.save if base.persisted? && !_binding?
22
+ end
23
+ self
24
+ end
25
+ alias :push :<<
26
+
27
+ def build(attributes = {}, type = nil)
28
+ obj = (type || klass).new(attributes)
29
+ append(obj)
30
+ yield(obj) if block_given?
31
+ obj
32
+ end
33
+ alias :new :build
34
+
35
+ def concat(objects)
36
+ objs, inserts = [], []
37
+ objects.each do |obj|
38
+ next unless obj
39
+ append(obj)
40
+ save_or_delay(obj, objs, inserts) if base.persisted?
41
+ end
42
+ persist_delayed(objs, inserts)
43
+ self
44
+ end
45
+
46
+ def purge
47
+ unless __metadata__.destructive?
48
+ nullify
49
+ else
50
+ after_remove_error = nil
51
+ criteria.delete_all
52
+ many = target.clear do |obj|
53
+ unbind_one(obj)
54
+ obj.destroyed = true if obj.respond_to?(:destroyed=)
55
+ end
56
+ many
57
+ end
58
+ end
59
+ alias :clear :purge
60
+
61
+ def delete(object)
62
+ target.delete(object) do |obj|
63
+ unbind_one(obj) if obj
64
+ cascade!(obj) if obj
65
+ end
66
+ end
67
+
68
+ def delete_all(conditions = nil)
69
+ remove_all(conditions, :delete_all)
70
+ end
71
+
72
+ def destroy_all(conditions = nil)
73
+ remove_all(conditions, :destroy_all)
74
+ end
75
+
76
+ def each
77
+ if block_given?
78
+ target.each { |obj| yield(obj) }
79
+ else
80
+ to_enum
81
+ end
82
+ end
83
+
84
+ def exists?
85
+ criteria.exists?
86
+ end
87
+
88
+ def find(*args)
89
+ begin
90
+ matching = criteria.find(*args)
91
+ rescue Exception => e
92
+ end
93
+ Array(matching).each { |obj| target.push(obj) }
94
+ matching
95
+ end
96
+
97
+ def nullify
98
+ criteria.update_all(__metadata__.foreign_key => nil)
99
+ target.clear do |obj|
100
+ unbind_one(obj)
101
+ obj.changed_attributes.delete(__metadata__.foreign_key)
102
+ end
103
+ end
104
+ alias :nullify_all :nullify
105
+
106
+ def blank?
107
+ size == 0
108
+ end
109
+
110
+ def create(attributes = nil, type = nil, &block)
111
+ if attributes.is_a?(::Array)
112
+ attributes.map { |attrs| create(attrs, type, &block) }
113
+ else
114
+ obj = build(attributes, type, &block)
115
+ base.persisted? ? obj.save : raise_unsaved(obj)
116
+ obj
117
+ end
118
+ end
119
+
120
+ def create!(attributes = nil, type = nil, &block)
121
+ if attributes.is_a?(::Array)
122
+ attributes.map { |attrs| create!(attrs, type, &block) }
123
+ else
124
+ obj = build(attributes, type, &block)
125
+ base.persisted? ? obj.save! : raise_unsaved(obj)
126
+ obj
127
+ end
128
+ end
129
+
130
+ def find_or_create_by(attrs = {}, type = nil, &block)
131
+ find_or(:create, attrs, type, &block)
132
+ end
133
+
134
+ def find_or_initialize_by(attrs = {}, type = nil, &block)
135
+ find_or(:build, attrs, type, &block)
136
+ end
137
+
138
+ def nil?
139
+ false
140
+ end
141
+
142
+ def respond_to?(name, include_private = false)
143
+ [].respond_to?(name, include_private) ||
144
+ klass.respond_to?(name, include_private) || super
145
+ end
146
+
147
+ def scoped
148
+ criteria
149
+ end
150
+
151
+ def unscoped
152
+ criteria.unscoped
153
+ end
154
+
155
+ def raise_unsaved(obj)
156
+ # raise new exception
157
+ end
158
+
159
+ def substitute(replacement)
160
+ if replacement
161
+ new_objs, objs = replacement.compact, []
162
+ new_ids = new_objs.map { |obj| obj.id }
163
+ remove_not_in(new_ids)
164
+ new_objs.each do |obj|
165
+ objs.push(obj) if obj.send(__metadata__.foreign_key) != base.id
166
+ end
167
+ concat(objs)
168
+ else
169
+ purge
170
+ end
171
+ self
172
+ end
173
+
174
+ def unscoped
175
+ klass.unscoped.where(__metadata__.foreign_key => base.id)
176
+ end
177
+
178
+ private
179
+
180
+ def find_or(method, attrs = {}, type = nil, &block)
181
+ attrs["_type"] = type.to_s if type
182
+ where(attrs).first || send(method, attrs, type, &block)
183
+ end
184
+
185
+ def append(object)
186
+ target.push(object)
187
+ # characterize_one(object)
188
+ bind_one(object)
189
+ end
190
+
191
+ def cascade!(object)
192
+ if base.persisted?
193
+ if __metadata__.destructive?
194
+ object.send(__metadata__.dependent)
195
+ else
196
+ object.save
197
+ end
198
+ end
199
+ end
200
+
201
+ def with_polymorphic_criterion(criteria, metadata, type = nil)
202
+ if metadata.polymorphic?
203
+ criteria.where(metadata.type => type.name)
204
+ else
205
+ criteria
206
+ end
207
+ end
208
+
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,229 @@
1
+ module ActiveMongoid
2
+ module Associations
3
+ class Metadata < Hash
4
+
5
+ delegate :primary_key_default, :foreign_key_default, :stores_foreign_key?, :macro, to: :relation
6
+
7
+ def as
8
+ self[:as]
9
+ end
10
+
11
+ def as?
12
+ !!as
13
+ end
14
+
15
+ def initialize(properties = {})
16
+ merge!(properties)
17
+ end
18
+
19
+ def autosave
20
+ self[:autosave]
21
+ end
22
+
23
+ def autosave?
24
+ !!autosave
25
+ end
26
+
27
+ def builder(base, object)
28
+ relation.builder(base, self, object)
29
+ end
30
+
31
+ def order
32
+ self[:order]
33
+ end
34
+
35
+ def criteria(object, type = nil)
36
+ query = relation.criteria(self, object, type)
37
+ if order
38
+ query = query.respond_to?(:order_by) ? query.order_by(order) : query.order(order)
39
+ end
40
+ query
41
+ end
42
+
43
+ def key
44
+ relation.stores_foreign_key? ? foreign_key : primary_key
45
+ end
46
+
47
+ def foreign_key
48
+ @foreign_key ||= determine_foreign_key
49
+ end
50
+
51
+ def foreign_key_setter
52
+ @foreign_key_setter ||= "#{foreign_key}="
53
+ end
54
+
55
+ def type_setter
56
+ @type_setter ||= "#{type}="
57
+ end
58
+
59
+ def determine_key
60
+ relation.stores_foreign_key? ? foreign_key : primary_key
61
+ end
62
+
63
+ def primary_key
64
+ @primary_key ||= (self[:primary_key] || primary_key_default)
65
+ end
66
+
67
+ def determine_foreign_key
68
+ return self[:foreign_key].to_s if self[:foreign_key]
69
+
70
+ if relation.stores_foreign_key?
71
+ relation.foreign_key(name)
72
+ else
73
+ inverse_metadata.foreign_key
74
+ end
75
+ end
76
+
77
+ def object_class
78
+ class_name.constantize
79
+ end
80
+ alias_method :klass, :object_class
81
+
82
+ def class_name
83
+ (self[:class_name] || name.to_s.singularize.titleize.delete(' ')).sub(/\A::/,"")
84
+ end
85
+
86
+ def name
87
+ self[:name].to_s
88
+ end
89
+
90
+ def object_name
91
+ name.to_s.singularize
92
+ end
93
+
94
+ def plural_anme
95
+ name.to_s.pluralize
96
+ end
97
+
98
+ def relation
99
+ self[:relation]
100
+ end
101
+
102
+ def inverse_klass
103
+ @inverse_klass ||= inverse_class_name.constantize if inverse_class_name
104
+ end
105
+
106
+ def inverse_class_name
107
+ self[:as] || self[:inverse_class_name]
108
+ end
109
+
110
+ def inverses(other = nil)
111
+ if self[:polymorphic]
112
+ lookup_inverses(other)
113
+ else
114
+ @inverses ||= determine_inverses
115
+ end
116
+ end
117
+
118
+ def polymorphic?
119
+ @polymorphic ||= (!!self[:as] || !!self[:polymorphic])
120
+ end
121
+
122
+ def lookup_inverses(other)
123
+ return [ inverse_of ] if inverse_of
124
+ if other
125
+ matches = []
126
+ other.class.am_relations.values.each do |meta|
127
+ if meta.as.to_s == name && meta.class_name == inverse_class_name
128
+ matches.push(meta.name)
129
+ end
130
+ end
131
+ matches
132
+ end
133
+ end
134
+
135
+ def determine_inverse_for(field)
136
+ relation.stores_foreign_key? && polymorphic? ? "#{name}_#{field}" : nil
137
+ end
138
+
139
+ def inverse_type
140
+ @inverse_type ||= determine_inverse_for(:type)
141
+ end
142
+
143
+ def inverse(other = nil)
144
+ invs = inverses(other)
145
+ invs.first if invs.count == 1
146
+ end
147
+
148
+ def inverse_of
149
+ self[:inverse_of]
150
+ end
151
+
152
+ def inverse_setter(other = nil)
153
+ "#{inverse(other)}="
154
+ end
155
+
156
+ def inverse_metadata(object = nil)
157
+ object = object || object_class
158
+ object.reflect_on_am_association(inverse(object))
159
+ end
160
+
161
+ def determine_inverses
162
+ return [ inverse_of ] if has_key?(:inverse_of)
163
+ return [ as ] if has_key?(:as)
164
+ [ inverse_relation ]
165
+ end
166
+
167
+ def inverse_relation
168
+ @inverse_relation ||= determine_inverse_relation
169
+ end
170
+
171
+ def determine_inverse_relation
172
+ default = foreign_key_match || klass.am_relations[inverse_klass.name.underscore]
173
+ return default.name if default
174
+ klass.am_relations.each_pair do |key, meta|
175
+ next if meta.name == name
176
+ if meta.class_name == inverse_class_name
177
+ return key.to_sym
178
+ end
179
+ end
180
+ return nil
181
+ end
182
+
183
+ def foreign_key_match
184
+ if fk = self[:foreign_key]
185
+ relations_metadata.detect do |meta|
186
+ fk == meta.foreign_key if meta.stores_foreign_key?
187
+ end
188
+ end
189
+ end
190
+
191
+ def relations_metadata
192
+ klass.am_relations.values
193
+ end
194
+
195
+ def dependent
196
+ self[:dependent]
197
+ end
198
+
199
+ def destructive?
200
+ @destructive ||= (dependent == :delete || dependent == :destroy)
201
+ end
202
+
203
+ def polymorphic?
204
+ @polymorphic ||= (!!self[:as] || !!self[:polymorphic])
205
+ end
206
+
207
+ def type
208
+ @type ||= polymorphic? ? "#{as}_type" : nil
209
+ end
210
+
211
+ def type_setter
212
+ @type_setter ||= "#{type}="
213
+ end
214
+
215
+ def determine_inverse_for(field)
216
+ relation.stores_foreign_key? && polymorphic? ? "#{name}_#{field}" : nil
217
+ end
218
+
219
+ def inverse_type
220
+ @inverse_type ||= determine_inverse_for(:type)
221
+ end
222
+
223
+ def inverse_type_setter
224
+ @inverse_type_setter ||= "#{inverse_type}="
225
+ end
226
+
227
+ end
228
+ end
229
+ end