dm-mongo-adapter 0.2.0.pre3 → 0.6.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 (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