active_mongoid 0.1.0

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 (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