dm-mongo-adapter 0.2.0.pre3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/Gemfile +27 -0
  2. data/README.rdoc +16 -35
  3. data/Rakefile +6 -16
  4. data/VERSION.yml +2 -2
  5. data/dm-mongo-adapter.gemspec +100 -121
  6. data/lib/mongo_adapter.rb +19 -62
  7. data/lib/mongo_adapter/adapter.rb +49 -36
  8. data/lib/mongo_adapter/conditions.rb +0 -5
  9. data/lib/mongo_adapter/migrations.rb +17 -23
  10. data/lib/mongo_adapter/model.rb +3 -74
  11. data/lib/mongo_adapter/modifier.rb +1 -1
  12. data/lib/mongo_adapter/property/array.rb +10 -0
  13. data/lib/mongo_adapter/property/db_ref.rb +17 -0
  14. data/lib/mongo_adapter/property/hash.rb +27 -0
  15. data/lib/mongo_adapter/property/object_id.rb +47 -0
  16. data/lib/mongo_adapter/query.rb +42 -45
  17. data/lib/mongo_adapter/rails/storage.rb +15 -0
  18. data/lib/mongo_adapter/resource.rb +0 -130
  19. data/lib/mongo_adapter/support/class.rb +11 -0
  20. data/lib/mongo_adapter/support/date.rb +11 -0
  21. data/lib/mongo_adapter/support/date_time.rb +12 -0
  22. data/lib/mongo_adapter/support/object.rb +9 -0
  23. data/spec/legacy/adapter_spec.rb +9 -6
  24. data/spec/legacy/associations_spec.rb +37 -29
  25. data/spec/legacy/property_spec.rb +4 -3
  26. data/spec/legacy/sti_spec.rb +1 -2
  27. data/spec/lib/cleanup_models.rb +0 -1
  28. data/spec/public/aggregates_spec.rb +171 -0
  29. data/spec/public/model_spec.rb +8 -22
  30. data/spec/public/modifier_spec.rb +109 -0
  31. data/spec/public/properties/db_ref_spec.rb +17 -0
  32. data/spec/public/properties/object_id_spec.rb +15 -0
  33. data/spec/public/resource_spec.rb +2 -383
  34. data/spec/public/shared/object_id_shared_spec.rb +16 -39
  35. data/spec/spec_helper.rb +0 -4
  36. metadata +87 -117
  37. data/.gitignore +0 -9
  38. data/lib/mongo_adapter/embedded_model.rb +0 -187
  39. data/lib/mongo_adapter/embedded_resource.rb +0 -134
  40. data/lib/mongo_adapter/embedments/one_to_many.rb +0 -144
  41. data/lib/mongo_adapter/embedments/one_to_one.rb +0 -57
  42. data/lib/mongo_adapter/embedments/relationship.rb +0 -258
  43. data/lib/mongo_adapter/model/embedment.rb +0 -215
  44. data/lib/mongo_adapter/types/date.rb +0 -24
  45. data/lib/mongo_adapter/types/date_time.rb +0 -28
  46. data/lib/mongo_adapter/types/db_ref.rb +0 -65
  47. data/lib/mongo_adapter/types/discriminator.rb +0 -32
  48. data/lib/mongo_adapter/types/object_id.rb +0 -72
  49. data/lib/mongo_adapter/types/objects.rb +0 -31
  50. data/spec/legacy/embedded_resource_spec.rb +0 -157
  51. data/spec/legacy/embedments_spec.rb +0 -177
  52. data/spec/legacy/modifier_spec.rb +0 -81
  53. data/spec/public/embedded_collection_spec.rb +0 -61
  54. data/spec/public/embedded_resource_spec.rb +0 -220
  55. data/spec/public/model/embedment_spec.rb +0 -186
  56. data/spec/public/shared/model_embedments_spec.rb +0 -338
  57. data/spec/public/types/df_ref_spec.rb +0 -6
  58. data/spec/public/types/discriminator_spec.rb +0 -118
  59. data/spec/public/types/embedded_array_spec.rb +0 -55
  60. data/spec/public/types/embedded_hash_spec.rb +0 -83
  61. data/spec/public/types/object_id_spec.rb +0 -6
  62. data/spec/semipublic/embedded_model_spec.rb +0 -43
  63. data/spec/semipublic/model/embedment_spec.rb +0 -42
  64. data/spec/semipublic/resource_spec.rb +0 -70
@@ -1,134 +0,0 @@
1
- module DataMapper
2
- module Mongo
3
- module EmbeddedResource
4
- # Raised when trying to save an EmbeddedResource which doesn't have a
5
- # parent set.
6
- class MissingParentError < StandardError; end
7
-
8
- include Types
9
- include DataMapper::Resource
10
-
11
- def self.included(base)
12
- base.extend(DataMapper::Mongo::EmbeddedModel)
13
- end
14
-
15
- # @api public
16
- alias_method :model, :class
17
-
18
- # Returns the resource to which this EmbeddedResource belongs.
19
- #
20
- # @return [DataMapper::Mongo::Resource]
21
- # The parent
22
- #
23
- # @api public
24
- attr_reader :parent
25
-
26
- # Gets all the attributes of the EmbeddedResource instance
27
- #
28
- # @param [Symbol] key_on
29
- # Use this attribute of the Property as keys.
30
- # defaults to :name. :field is useful for adapters
31
- # :property or nil use the actual Property object.
32
- #
33
- # @return [Hash]
34
- # All the attributes
35
- #
36
- # @overrides DataMapper::Resource#attributes
37
- #
38
- # @api public
39
- def attributes(key_on=:name)
40
- attributes = {}
41
-
42
- fields.each do |property|
43
- if model.public_method_defined?(name = property.name)
44
- key = case key_on
45
- when :name then name
46
- when :field then property.field
47
- else property
48
- end
49
-
50
- attributes[key] = __send__(name)
51
- end
52
- end
53
-
54
- attributes
55
- end
56
-
57
- # Sets the resource to which this EmbeddedResource belongs
58
- #
59
- # @param [DataMapper::Mongo::Resource] resource
60
- # The new parent resource
61
- #
62
- # @api public
63
- def parent=(resource)
64
- @parent = resource
65
- end
66
-
67
- # Returns whether this resource (or rather, it's parent) has been saved
68
- #
69
- # @return [Boolean]
70
- #
71
- # @api public
72
- def saved?
73
- parent && parent.saved?
74
- end
75
-
76
- # Returns whether this resource (or rather, it's parent) is unsaved
77
- #
78
- # @return [Boolean]
79
- #
80
- # @api public
81
- def new?
82
- !parent? || parent.new?
83
- end
84
-
85
- # Returns if the EmbeddedResource has a parent set
86
- #
87
- # @return [Boolean]
88
- #
89
- # @api public
90
- def parent?
91
- !parent.nil?
92
- end
93
-
94
- # Saves the EmbeddedResource by saving the parent
95
- #
96
- # @return [Boolean]
97
- # Returns true if the resource was successfully saved, false
98
- # otherwise
99
- #
100
- # @raise [MissingParentError]
101
- # Raises a MissingParentError if a parent has not been set
102
- #
103
- # @api public
104
- def save
105
- if parent?
106
- if parent.save
107
- original_attributes.clear
108
- true
109
- end
110
- else
111
- raise MissingParentError, 'EmbeddedResource needs a parent to be ' \
112
- 'set before it can be saved'
113
- end
114
- end
115
-
116
- # Checks if the resource has unsaved changes
117
- #
118
- # @return [Boolean]
119
- # True if resource may be persisted
120
- #
121
- # @api public
122
- def dirty_self?
123
- if original_attributes.any?
124
- true
125
- elsif new?
126
- properties.any? { |property| property.default? }
127
- else
128
- false
129
- end
130
- end
131
-
132
- end # EmbeddedResource
133
- end # Mongo
134
- end # DataMapper
@@ -1,144 +0,0 @@
1
- module DataMapper
2
- module Mongo
3
- module Embedments
4
- module OneToMany
5
- class Relationship < Embedments::Relationship
6
- # Loads and returns embedment target for given source
7
- #
8
- # @param [DataMapper::Mongo::Resource] source
9
- # The resource whose relationship value is to be retrieved.
10
- #
11
- # @return [DataMapper::Collection]
12
- #
13
- # @api semipublic
14
- def get(source, other_query = nil)
15
- assert_kind_of 'source', source, source_model
16
-
17
- unless loaded?(source)
18
- set!(source, collection_for(source, other_query))
19
- end
20
-
21
- get!(source)
22
- end
23
-
24
- # Sets and returns association target for given source
25
- #
26
- # @param [DataMapper::Mongo::Resource] source
27
- # The parent resource whose target is to be set.
28
- # @param [DataMapper::Mongo::EmbeddedResource] targets
29
- # The embedded resources to be set to the relationship
30
- # @param [Boolean] loading
31
- # Do the attributes have to be loaded before being set? Setting
32
- # this to true will typecase the attributes, and set the
33
- # original_values on the resource.
34
- #
35
- # @api semipublic
36
- def set(source, targets, loading=false)
37
- assert_kind_of 'source', source, source_model
38
- assert_kind_of 'targets', targets, Array
39
-
40
- targets = targets.map do |target|
41
- case target
42
- when Hash
43
- load_target(source, target)
44
- when DataMapper::Mongo::EmbeddedResource
45
- target.parent = source
46
- target
47
- else
48
- raise ArgumentError, 'one-to-many embedment requires an ' \
49
- 'EmbeddedResource or a hash'
50
- end
51
- end
52
-
53
- set_original_attributes(source, targets) unless loading
54
-
55
- unless loaded?(source)
56
- set!(source, collection_for(source))
57
- end
58
-
59
- get!(source).replace(targets)
60
- end
61
-
62
- # @api public
63
- def storage_name
64
- @storage_name ||= target_model.storage_name
65
- end
66
-
67
- private
68
-
69
- # Creates a new collection instance for the source resources.
70
- #
71
- # @param [DataMapper::Mongo::Resource] source
72
- # The resources to be wrapped in a Collection.
73
- #
74
- # @return [DataMapper::Collection]
75
- #
76
- # @api private
77
- def collection_for(source, other_query=nil)
78
- Collection.new(source, target_model)
79
- end
80
- end
81
-
82
- # Extends Array to ensure that each EmbeddedResource has it's +parent+
83
- # attribute set.
84
- class Collection < Array
85
- # Returns the resource to which this collection belongs
86
- #
87
- # @return [DataMapper::Mongo::Resource]
88
- # The resource to which the contained EmbeddedResource instances
89
- # belong.
90
- #
91
- # @api semipublic
92
- attr_reader :source
93
-
94
- # @api semipublic
95
- attr_reader :target_model
96
-
97
- # Creates a new Collection instance
98
- #
99
- # @param [DataMapper::Mongo::Resource] source
100
- # The resource to which the contained EmbeddedResource instances
101
- # belong.
102
- #
103
- # @api semipublic
104
- def initialize(source, target_model)
105
- @source = source
106
- @target_model = target_model
107
- end
108
-
109
- # Adds a new embedded resource to the collection
110
- #
111
- # @param [DataMapper::Mongo::EmbeddedResource] resource
112
- # The embedded resource to be added.
113
- #
114
- # @api public
115
- def <<(resource)
116
- resource.parent = source
117
- super(resource)
118
- end
119
-
120
- # TODO: document
121
- # @api public
122
- def dirty?
123
- any? { |resource| resource.dirty? }
124
- end
125
-
126
- # TODO: document
127
- # @api public
128
- def save
129
- source.save
130
- end
131
-
132
- # TODO: document
133
- # @api public
134
- def new(attributes={})
135
- resource = target_model.new(attributes)
136
- self. << resource
137
- resource
138
- end
139
- end
140
-
141
- end # OneToMany
142
- end # Embedments
143
- end # Mongo
144
- end # DataMapper
@@ -1,57 +0,0 @@
1
- module DataMapper
2
- module Mongo
3
- module Embedments
4
- module OneToOne
5
- class Relationship < Embedments::Relationship
6
- # Loads and returns embedment target for given source
7
- #
8
- # Returns a new instance of the target model if there isn't one set.
9
- #
10
- # @param [DataMapper::Mongo::Resource] source
11
- # The resource whose relationship value is to be retrieved.
12
- #
13
- # @return [DataMapper::Mongo::Resource]
14
- #
15
- # @api semipublic
16
- def get(source, other_query = nil)
17
- get!(source)
18
- end
19
-
20
- # Sets and returns association target for given source
21
- #
22
- # @param [DataMapper::Mongo::Resource] source
23
- # The resource whose target is to be set.
24
- # @param [DataMapper::Mongo::EmbeddedResource] target
25
- # The value to be set to the target
26
- # @param [Boolean] loading
27
- # Do the attributes have to be loaded before being set? Setting
28
- # this to true will typecase the attributes, and set the
29
- # original_values on the resource.
30
- #
31
- # @api semipublic
32
- def set(source, target, loading=false)
33
- assert_kind_of 'source', source, source_model
34
- assert_kind_of 'target', target, target_model, Hash, NilClass
35
-
36
- unless target.nil?
37
- if target.kind_of?(Hash)
38
- target = load_target(source, target, loading)
39
- else
40
- target.parent = source
41
- end
42
-
43
- set_original_attributes(source, target) unless loading
44
- end
45
-
46
- set!(source, target)
47
- end
48
-
49
- # @api public
50
- def storage_name
51
- @storage_name ||= target_model.storage_name.singular
52
- end
53
- end # Relationship
54
- end # OneToOne
55
- end # Embedments
56
- end # Mongo
57
- end # DataMapper
@@ -1,258 +0,0 @@
1
- module DataMapper
2
- module Mongo
3
- module Embedments
4
- # Base class for embedment relationships. Each type of relationship
5
- # (1 to 1, 1 to n) implements a subclass of this class with methods like
6
- # get and set overridden.
7
- class Relationship
8
- include Extlib::Assertions
9
-
10
- # Relationship name
11
- #
12
- # @example for :parent relationship in
13
- #
14
- # class VersionControl::Commit
15
- # # ...
16
- # belongs_to :parent
17
- # end
18
- #
19
- # name is :parent
20
- #
21
- # @api semipublic
22
- attr_reader :name
23
-
24
- # Returns the model class used by the parent side of the relationship
25
- #
26
- # @return [Resource]
27
- # Model for relationship parent
28
- #
29
- # @api semipublic
30
- attr_reader :source_model
31
-
32
- # Options used to set up this relationship
33
- #
34
- # @example for :author relationship in
35
- #
36
- # class VersionControl::Commit
37
- # # ...
38
- #
39
- # belongs_to :author, :model => 'Person'
40
- # end
41
- #
42
- # options is a hash with a single key, :model
43
- #
44
- # @api semipublic
45
- attr_reader :options
46
-
47
- # The name of the variable used to store the relationship
48
- #
49
- # @example for :commits relationship in
50
- #
51
- # class VersionControl::Branch
52
- # # ...
53
- #
54
- # has n, :commits
55
- # end
56
- #
57
- # instance variable name for source will be @commits
58
- #
59
- # @api semipublic
60
- attr_reader :instance_variable_name
61
-
62
- # Returns query options for relationship.
63
- #
64
- # For this base class, always returns query options has been
65
- # initialized with. Overridden in subclasses.
66
- #
67
- # @api private
68
- attr_reader :query
69
-
70
- # Returns the visibility for the source accessor
71
- #
72
- # @return [Symbol]
73
- # the visibility for the accessor added to the source
74
- #
75
- # @api semipublic
76
- attr_reader :reader_visibility
77
-
78
- # Returns the visibility for the source accessor
79
- #
80
- # @return [Symbol]
81
- # the visibility for the accessor added to the source
82
- #
83
- # @api semipublic
84
- attr_reader :writer_visibility
85
-
86
- # Loads and returns "other end" of the embedment
87
- #
88
- # Must be implemented in subclasses.
89
- #
90
- # @api semipublic
91
- def get(resource, other_query = nil)
92
- raise NotImplementedError, "#{self.class}#get not implemented"
93
- end
94
-
95
- # Gets "other end" of the embedment directly
96
- #
97
- # @api semipublic
98
- def get!(resource)
99
- resource.instance_variable_get(instance_variable_name)
100
- end
101
-
102
- # Sets value of the "other end" of the embedment on given resource
103
- #
104
- # Must be implemented in subclasses.
105
- #
106
- # @api semipublic
107
- def set(resource, association)
108
- raise NotImplementedError, "#{self.class}#set not implemented"
109
- end
110
-
111
- # Sets "other end" of the embedment directly.
112
- #
113
- # @api semipublic
114
- def set!(resource, association)
115
- resource.instance_variable_set(instance_variable_name, association)
116
- end
117
-
118
- # Returns the model class used by the child side of the relationship
119
- #
120
- # @return [Resource]
121
- # Model for relationship child
122
- #
123
- # @api semipublic
124
- def target_model
125
- if defined?(@target_model)
126
- @target_model
127
- elsif @target_model_name
128
- @target_model = (@source_model || Object).find_const(@target_model_name)
129
- else
130
- raise "No model type defined for relationship #{@name}"
131
- end
132
- end
133
-
134
- # @api semipublic
135
- def set_original_attributes(resource, association)
136
- Array(association).each do |association|
137
- resource.original_attributes[self] = association.original_attributes if association.dirty?
138
- end
139
- end
140
-
141
- # Checks if "other end" of the embedment is loaded on given resource
142
- #
143
- # @api semipublic
144
- def loaded?(resource)
145
- assert_kind_of 'resource', resource, source_model
146
-
147
- resource.instance_variable_defined?(instance_variable_name)
148
- end
149
-
150
- # Creates an instance of the target model with its attributes
151
- #
152
- # @param [DataMapper::Mongo::Resource] source
153
- # The source model to which the target belongs.
154
- # @param [Hash, #to_mash] attributes
155
- # The attributes to be set on the embedded resource.
156
- # @param [Boolean] loading
157
- # Do the attributes have to be loaded before being set? Setting
158
- # this to true will typecase the attributes, and set the
159
- # original_values on the resource.
160
- #
161
- # @return [DataMapper::Mongo::EmbeddedResource]
162
- # The initialized embedded resource instance.
163
- #
164
- # @api semipublic
165
- def load_target(source, attributes, loading=false)
166
- target = target_model.allocate
167
- target.parent = source
168
-
169
- attributes = attributes.to_mash
170
-
171
- target_model.properties.each do |property|
172
- property.send(loading ? :set! : :set, target, attributes[property.field])
173
- end
174
-
175
- target
176
- end
177
-
178
- # Creates and returns Query instance that represents the embedment
179
- #
180
- # The returned query can be used to fetch target resource(s)
181
- # (ex.: articles) for given target resource (ex.: author).
182
- #
183
- # @return [DataMapper::Mongo::Query]
184
- #
185
- # @api semipublic
186
- def query_for(source, other_query = nil)
187
- Query.new
188
- end
189
-
190
- # Creates a hash of attributes for the relationship.
191
- #
192
- # @api semipublic
193
- def value(relationship)
194
- relationship.model.properties.map { |property| [property, property.get(relationship)] }.to_hash
195
- end
196
-
197
- # Test the resource to see if it is a valid target
198
- #
199
- # @param [Object] relationship
200
- # The resource or collection to be tested
201
- #
202
- # @return [Boolean]
203
- # True if the resource is valid
204
- #
205
- # @api semipublic
206
- def valid?(relationship)
207
- relationship.kind_of?(target_model)
208
- end
209
-
210
- # @api public
211
- def method_missing(method, *args, &block)
212
- target_model.send(method, args, &block)
213
- end
214
-
215
- private
216
-
217
- # Creates a new Relationship instance
218
- #
219
- # @param [DataMapper::Mongo::EmbeddedModel, String] target_model
220
- # The child side of the relationship.
221
- # @param [DataMapper::Mongo::Model] source_model
222
- # The parent side of the relationship.
223
- # @param [Hash] options
224
- # Options for customising the relationship.
225
- #
226
- # @option options [Symbol] :reader_visibility
227
- # The visibility of the reader method created on the source model;
228
- # one of public, protected or private.
229
- # @option options [Symbol] :writer_visibility
230
- # The visibility of the writer method created on the source model;
231
- # one of public, protected or private.
232
- #
233
- def initialize(name, target_model, source_model, options={})
234
- if target_model.kind_of?(EmbeddedModel)
235
- @target_model = target_model
236
- elsif target_model.nil?
237
- # No model given, infer it from the name.
238
- @target_model_name =
239
- Extlib::Inflection.camelize(name.to_s.singular).freeze
240
- else
241
- # We were likely given a string as the target model -- perhaps
242
- # because the user's app hasn't loaded yet; get the constant
243
- # later in Relationship#target_model.
244
- @target_model_name = target_model.to_str.dup.freeze
245
- end
246
-
247
- @name = name
248
- @source_model = source_model
249
- @instance_variable_name = "@#{@name}".freeze
250
- @options = options.dup.freeze
251
- @reader_visibility = @options.fetch(:reader_visibility, :public)
252
- @writer_visibility = @options.fetch(:writer_visibility, :public)
253
- end
254
-
255
- end # Relationship
256
- end # Embedments
257
- end # Mongo
258
- end # DataMapper