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.
- data/Gemfile +27 -0
- data/README.rdoc +16 -35
- data/Rakefile +6 -16
- data/VERSION.yml +2 -2
- data/dm-mongo-adapter.gemspec +100 -121
- data/lib/mongo_adapter.rb +19 -62
- data/lib/mongo_adapter/adapter.rb +49 -36
- data/lib/mongo_adapter/conditions.rb +0 -5
- data/lib/mongo_adapter/migrations.rb +17 -23
- data/lib/mongo_adapter/model.rb +3 -74
- data/lib/mongo_adapter/modifier.rb +1 -1
- data/lib/mongo_adapter/property/array.rb +10 -0
- data/lib/mongo_adapter/property/db_ref.rb +17 -0
- data/lib/mongo_adapter/property/hash.rb +27 -0
- data/lib/mongo_adapter/property/object_id.rb +47 -0
- data/lib/mongo_adapter/query.rb +42 -45
- data/lib/mongo_adapter/rails/storage.rb +15 -0
- data/lib/mongo_adapter/resource.rb +0 -130
- data/lib/mongo_adapter/support/class.rb +11 -0
- data/lib/mongo_adapter/support/date.rb +11 -0
- data/lib/mongo_adapter/support/date_time.rb +12 -0
- data/lib/mongo_adapter/support/object.rb +9 -0
- data/spec/legacy/adapter_spec.rb +9 -6
- data/spec/legacy/associations_spec.rb +37 -29
- data/spec/legacy/property_spec.rb +4 -3
- data/spec/legacy/sti_spec.rb +1 -2
- data/spec/lib/cleanup_models.rb +0 -1
- data/spec/public/aggregates_spec.rb +171 -0
- data/spec/public/model_spec.rb +8 -22
- data/spec/public/modifier_spec.rb +109 -0
- data/spec/public/properties/db_ref_spec.rb +17 -0
- data/spec/public/properties/object_id_spec.rb +15 -0
- data/spec/public/resource_spec.rb +2 -383
- data/spec/public/shared/object_id_shared_spec.rb +16 -39
- data/spec/spec_helper.rb +0 -4
- metadata +87 -117
- data/.gitignore +0 -9
- data/lib/mongo_adapter/embedded_model.rb +0 -187
- data/lib/mongo_adapter/embedded_resource.rb +0 -134
- data/lib/mongo_adapter/embedments/one_to_many.rb +0 -144
- data/lib/mongo_adapter/embedments/one_to_one.rb +0 -57
- data/lib/mongo_adapter/embedments/relationship.rb +0 -258
- data/lib/mongo_adapter/model/embedment.rb +0 -215
- data/lib/mongo_adapter/types/date.rb +0 -24
- data/lib/mongo_adapter/types/date_time.rb +0 -28
- data/lib/mongo_adapter/types/db_ref.rb +0 -65
- data/lib/mongo_adapter/types/discriminator.rb +0 -32
- data/lib/mongo_adapter/types/object_id.rb +0 -72
- data/lib/mongo_adapter/types/objects.rb +0 -31
- data/spec/legacy/embedded_resource_spec.rb +0 -157
- data/spec/legacy/embedments_spec.rb +0 -177
- data/spec/legacy/modifier_spec.rb +0 -81
- data/spec/public/embedded_collection_spec.rb +0 -61
- data/spec/public/embedded_resource_spec.rb +0 -220
- data/spec/public/model/embedment_spec.rb +0 -186
- data/spec/public/shared/model_embedments_spec.rb +0 -338
- data/spec/public/types/df_ref_spec.rb +0 -6
- data/spec/public/types/discriminator_spec.rb +0 -118
- data/spec/public/types/embedded_array_spec.rb +0 -55
- data/spec/public/types/embedded_hash_spec.rb +0 -83
- data/spec/public/types/object_id_spec.rb +0 -6
- data/spec/semipublic/embedded_model_spec.rb +0 -43
- data/spec/semipublic/model/embedment_spec.rb +0 -42
- data/spec/semipublic/resource_spec.rb +0 -70
@@ -1,215 +0,0 @@
|
|
1
|
-
module DataMapper
|
2
|
-
module Mongo
|
3
|
-
module Model
|
4
|
-
# Embedment extends Mongo-based resources to allow resources to be
|
5
|
-
# embedded within a document, while providing relationship-like `has 1`
|
6
|
-
# and `has n` functionality.
|
7
|
-
#
|
8
|
-
# @example
|
9
|
-
# class User
|
10
|
-
# include DataMapper::Mongo::Resource
|
11
|
-
#
|
12
|
-
# property :id, ObjectID
|
13
|
-
# property :name, String
|
14
|
-
#
|
15
|
-
# embeds n, :addresses, :model => Address
|
16
|
-
# end
|
17
|
-
#
|
18
|
-
# class Address
|
19
|
-
# include DataMapper::Mongo::EmbeddedResource
|
20
|
-
#
|
21
|
-
# property :street, String
|
22
|
-
# property :post_code, String
|
23
|
-
# end
|
24
|
-
#
|
25
|
-
module Embedment
|
26
|
-
extend Chainable
|
27
|
-
|
28
|
-
# Options which cannot be used on Embedments.
|
29
|
-
ILLEGAL_OPTS = [:through, :remote_name, :via, :inverse, :parent_key]
|
30
|
-
|
31
|
-
# @api private
|
32
|
-
def self.extended(model)
|
33
|
-
model.instance_variable_set(:@embedments, {})
|
34
|
-
end
|
35
|
-
|
36
|
-
chainable do
|
37
|
-
# @api private
|
38
|
-
def inherited(model)
|
39
|
-
model.instance_variable_set(:@embedments, {})
|
40
|
-
|
41
|
-
@embedments.each { |name, embedment| model.embedments[name] ||= embedment }
|
42
|
-
|
43
|
-
super
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
chainable do
|
48
|
-
# @api public
|
49
|
-
def method_missing(method, *args, &block)
|
50
|
-
if respond_to?(:embedments) && embedment = embedments[method]
|
51
|
-
return embedment
|
52
|
-
end
|
53
|
-
|
54
|
-
super
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# Returns the embedments on this model
|
59
|
-
#
|
60
|
-
# @return [Hash]
|
61
|
-
# Embedments on this model, where each hash key is the embedment
|
62
|
-
# name, and each value is the Embedments::Relationship instance.
|
63
|
-
#
|
64
|
-
# @api semipublic
|
65
|
-
def embedments
|
66
|
-
@embedments ||= {}
|
67
|
-
end
|
68
|
-
|
69
|
-
# A short-hand, clear syntax for defining one-to-one and one-to-many
|
70
|
-
# embedments -- where an embedded resource is held within the parent
|
71
|
-
# document in the database.
|
72
|
-
#
|
73
|
-
# @example
|
74
|
-
# embed 1, :friend # one friend
|
75
|
-
# embed n, :friends # many friends
|
76
|
-
# embed 1..3, :friends # many friends (at least 1, at most 3)
|
77
|
-
# embed 3, :friends # many friends (exactly 3)
|
78
|
-
# embed 1, :friend, 'User' # one friend with the class User
|
79
|
-
#
|
80
|
-
# @param cardinality [Integer, Range, Infinity]
|
81
|
-
# Cardinality that defines the embedment type and constraints
|
82
|
-
# @param name [Symbol]
|
83
|
-
# The name that the embedment will be referenced by
|
84
|
-
# @param model [Model, #to_str]
|
85
|
-
# The target model of the embedment
|
86
|
-
# @param opts [Hash]
|
87
|
-
# An options hash
|
88
|
-
#
|
89
|
-
# @option :model[Model, String] The name of the class to associate
|
90
|
-
# with, if omitted then the model class name is assumed to match the
|
91
|
-
# (optional) third parameter, or the embedment name.
|
92
|
-
#
|
93
|
-
# @return [Embedment::Relationship]
|
94
|
-
# The embedment that was created to reflect either a one-to-one or
|
95
|
-
# one-to-many embedment.
|
96
|
-
#
|
97
|
-
# @raise [ArgumentError]
|
98
|
-
# If the cardinality was not understood. Should be a Integer, Range
|
99
|
-
# or Infinity(n)
|
100
|
-
#
|
101
|
-
# @api public
|
102
|
-
def embeds(cardinality, name, *args)
|
103
|
-
assert_kind_of 'cardinality', cardinality, Integer, Range, Infinity.class
|
104
|
-
assert_kind_of 'name', name, Symbol
|
105
|
-
|
106
|
-
model = extract_model(args)
|
107
|
-
options = extract_options(args)
|
108
|
-
|
109
|
-
min, max = extract_min_max(cardinality)
|
110
|
-
options.update(:min => min, :max => max)
|
111
|
-
|
112
|
-
assert_valid_options(options)
|
113
|
-
|
114
|
-
if options.key?(:model) && model
|
115
|
-
raise ArgumentError, 'should not specify options[:model] if passing the model in the third argument'
|
116
|
-
end
|
117
|
-
|
118
|
-
model ||= options.delete(:model)
|
119
|
-
|
120
|
-
klass = if max > 1
|
121
|
-
Embedments::OneToMany::Relationship
|
122
|
-
else
|
123
|
-
Embedments::OneToOne::Relationship
|
124
|
-
end
|
125
|
-
|
126
|
-
embedment = embedments[name] = klass.new(name, model, self, options)
|
127
|
-
|
128
|
-
descendants.each do |descendant|
|
129
|
-
descendant.embedments[name] ||= embedment
|
130
|
-
end
|
131
|
-
|
132
|
-
create_embedment_reader(embedment)
|
133
|
-
create_embedment_writer(embedment)
|
134
|
-
|
135
|
-
embedment
|
136
|
-
end
|
137
|
-
|
138
|
-
# @todo Investigate as a candidate for removal.
|
139
|
-
# Added 26ae98e1 as an equivelent of belongs_to but _probably_ isn't
|
140
|
-
# of much use in embedded resources (since it would be perfectly
|
141
|
-
# acceptable for an embedment to be used in multiple models). My
|
142
|
-
# opinion is that embedments should always be declared from the
|
143
|
-
# parent side (DM::M::Resource), rather the child side
|
144
|
-
# (DM::M::EmbeddedResource).
|
145
|
-
#
|
146
|
-
# ~antw
|
147
|
-
#
|
148
|
-
# @api public
|
149
|
-
def embedded_in(name, *args)
|
150
|
-
return NotImplementedError
|
151
|
-
end
|
152
|
-
|
153
|
-
def assert_valid_options(options)
|
154
|
-
ILLEGAL_OPTS.each do |option|
|
155
|
-
raise ArgumentError, "+options[:#{option}]+ should not be " \
|
156
|
-
"specified on a relationship" if options.key?(option)
|
157
|
-
end
|
158
|
-
|
159
|
-
super
|
160
|
-
end
|
161
|
-
|
162
|
-
# Dynamically defines a reader method
|
163
|
-
#
|
164
|
-
# Creates a public method matching the name of the embedment which can
|
165
|
-
# be used to access the embedded resource(s).
|
166
|
-
#
|
167
|
-
# @param [Embedment::Relationship] embedment
|
168
|
-
# The embedment for which a reader should be created
|
169
|
-
#
|
170
|
-
# @api private
|
171
|
-
def create_embedment_reader(embedment)
|
172
|
-
name = embedment.name
|
173
|
-
reader_name = name.to_s
|
174
|
-
|
175
|
-
return if resource_method_defined?(reader_name)
|
176
|
-
|
177
|
-
reader_visibility = embedment.reader_visibility
|
178
|
-
|
179
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
180
|
-
#{reader_visibility} # public
|
181
|
-
def #{reader_name}(query = nil) # def author(query = nil)
|
182
|
-
embedments[#{name.inspect}].get(self, query) # embedment[:author].get(self, query)
|
183
|
-
end # end
|
184
|
-
RUBY
|
185
|
-
end
|
186
|
-
|
187
|
-
# Dynamically defines a writer method
|
188
|
-
#
|
189
|
-
# Creates a public method matching the name of the embedment which can
|
190
|
-
# be used to set the embedded resource(s).
|
191
|
-
#
|
192
|
-
# @param [Embedment::Relationship] embedment
|
193
|
-
# The embedment for which a writer should be created
|
194
|
-
#
|
195
|
-
# @api private
|
196
|
-
def create_embedment_writer(embedment)
|
197
|
-
name = embedment.name
|
198
|
-
writer_name = "#{name}="
|
199
|
-
|
200
|
-
return if resource_method_defined?(writer_name)
|
201
|
-
|
202
|
-
writer_visibility = embedment.writer_visibility
|
203
|
-
|
204
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
205
|
-
#{writer_visibility} # public
|
206
|
-
def #{writer_name}(target) # def author=(target)
|
207
|
-
embedments[#{name.inspect}].set(self, target) # embedment[:author].set(self, target)
|
208
|
-
end # end
|
209
|
-
RUBY
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
end # Model
|
214
|
-
end # Mongo
|
215
|
-
end # DataMapper
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module DataMapper
|
2
|
-
module Mongo
|
3
|
-
module Types
|
4
|
-
class Date < DataMapper::Type
|
5
|
-
primitive ::Time
|
6
|
-
|
7
|
-
def self.load(value, property)
|
8
|
-
self.typecast(value, property)
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.typecast(value, property)
|
12
|
-
case value
|
13
|
-
when ::Date
|
14
|
-
Time.utc(value.year, value.month, value.day)
|
15
|
-
when ::Time
|
16
|
-
::Date.new(value.year, value.month, value.day)
|
17
|
-
when NilClass, Range
|
18
|
-
value
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end # Types
|
23
|
-
end # Mongo
|
24
|
-
end # DataMapper
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module DataMapper
|
2
|
-
module Mongo
|
3
|
-
module Types
|
4
|
-
class DateTime < DataMapper::Type
|
5
|
-
primitive Time
|
6
|
-
|
7
|
-
def self.load(value, property)
|
8
|
-
self.typecast(value, property)
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.dump(value, property)
|
12
|
-
self.typecast(value, property)
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.typecast(value, property)
|
16
|
-
case value
|
17
|
-
when Time
|
18
|
-
value.to_datetime
|
19
|
-
when ::DateTime
|
20
|
-
value.to_time.utc
|
21
|
-
when NilClass, Range
|
22
|
-
value
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end # Types
|
27
|
-
end # Mongo
|
28
|
-
end # DataMapper
|
@@ -1,65 +0,0 @@
|
|
1
|
-
module DataMapper
|
2
|
-
module Mongo
|
3
|
-
module Types
|
4
|
-
# Database references are references from one document (object) to
|
5
|
-
# another within a database. A database reference is a standard embedded
|
6
|
-
# object: this is a MongoDB convention, not a special type.
|
7
|
-
#
|
8
|
-
# The DBRef is made available via your model as a String.
|
9
|
-
#
|
10
|
-
# @see http://www.mongodb.org/display/DOCS/DB+Ref
|
11
|
-
#
|
12
|
-
# @api public
|
13
|
-
class DBRef < DataMapper::Type
|
14
|
-
primitive ::Object
|
15
|
-
|
16
|
-
# Returns the DBRef as a string; suitable for use in a Resource
|
17
|
-
#
|
18
|
-
# @return [String]
|
19
|
-
#
|
20
|
-
# @api public
|
21
|
-
def self.load(value, property)
|
22
|
-
typecast(value, property)
|
23
|
-
end
|
24
|
-
|
25
|
-
# Returns the DBRef as a Mongo ObjectID; suitable to be passed to the
|
26
|
-
# Mongo library
|
27
|
-
#
|
28
|
-
# @return [Mongo::ObjectID] The dumped ID.
|
29
|
-
#
|
30
|
-
# @api public
|
31
|
-
def self.dump(value, property)
|
32
|
-
case value
|
33
|
-
when NilClass
|
34
|
-
nil
|
35
|
-
when String
|
36
|
-
::Mongo::ObjectID.from_string(value)
|
37
|
-
when ::Mongo::ObjectID
|
38
|
-
value
|
39
|
-
else
|
40
|
-
raise ArgumentError.new('+value+ must be nil, String, ObjectID')
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# Returns the DBRef as a string
|
45
|
-
#
|
46
|
-
# @return [String]
|
47
|
-
#
|
48
|
-
# @api semipublic
|
49
|
-
def self.typecast(value, property)
|
50
|
-
case value
|
51
|
-
when NilClass
|
52
|
-
nil
|
53
|
-
when String
|
54
|
-
value
|
55
|
-
when ::Mongo::ObjectID
|
56
|
-
value.to_s
|
57
|
-
else
|
58
|
-
raise ArgumentError.new('+value+ must be nil, String, ObjectID')
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
end # DBRef
|
63
|
-
end # Types
|
64
|
-
end # Mongo
|
65
|
-
end # DataMapper
|
@@ -1,32 +0,0 @@
|
|
1
|
-
module DataMapper
|
2
|
-
module Mongo
|
3
|
-
module Types
|
4
|
-
class Discriminator < DataMapper::Types::Discriminator
|
5
|
-
primitive String
|
6
|
-
default lambda { |resource, property| resource.model.to_s }
|
7
|
-
|
8
|
-
def self.load(value, property)
|
9
|
-
typecast(value, property)
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.dump(value, property)
|
13
|
-
value.name
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.typecast(value, property)
|
17
|
-
if value
|
18
|
-
if value.is_a?(String)
|
19
|
-
Extlib::Inflection.constantize(value)
|
20
|
-
else
|
21
|
-
value
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.==(other)
|
27
|
-
other == DataMapper::Types::Discriminator || super
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,72 +0,0 @@
|
|
1
|
-
module DataMapper
|
2
|
-
module Mongo
|
3
|
-
module Types
|
4
|
-
# Each object (document) stored in Mongo DB has an _id field as its
|
5
|
-
# first attribute. This is an object id. It must be unique for each
|
6
|
-
# member of a collection (this is enforced if the collection has an _id
|
7
|
-
# index, which is the case by default).
|
8
|
-
#
|
9
|
-
# The database will assign an _id if an object being inserted into a
|
10
|
-
# collection does not have one.
|
11
|
-
#
|
12
|
-
# The _id may be of any type as long as it is a unique value.
|
13
|
-
#
|
14
|
-
# @see http://www.mongodb.org/display/DOCS/Object+IDs
|
15
|
-
#
|
16
|
-
# @api public
|
17
|
-
class ObjectID < DataMapper::Type
|
18
|
-
primitive ::Object
|
19
|
-
key true
|
20
|
-
field "_id"
|
21
|
-
required false
|
22
|
-
|
23
|
-
# Returns the ObjectID as a string; suitable for use in a Resource
|
24
|
-
#
|
25
|
-
# @return [String]
|
26
|
-
#
|
27
|
-
# @api public
|
28
|
-
def self.load(value, property)
|
29
|
-
typecast(value, property)
|
30
|
-
end
|
31
|
-
|
32
|
-
# Returns the ObjectID as a Mongo::ObjectID; suitable to be passed to
|
33
|
-
# the Mongo library
|
34
|
-
#
|
35
|
-
# @return [Mongo::ObjectID] The dumped ID.
|
36
|
-
#
|
37
|
-
# @api public
|
38
|
-
def self.dump(value, property)
|
39
|
-
case value
|
40
|
-
when NilClass
|
41
|
-
nil
|
42
|
-
when String
|
43
|
-
::Mongo::ObjectID.from_string(value)
|
44
|
-
when ::Mongo::ObjectID
|
45
|
-
value
|
46
|
-
else
|
47
|
-
raise ArgumentError.new('+value+ must be nil, String or ObjectID')
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Returns the ObjectID as a string
|
52
|
-
#
|
53
|
-
# @return [String]
|
54
|
-
#
|
55
|
-
# @api semipublic
|
56
|
-
def self.typecast(value, property)
|
57
|
-
case value
|
58
|
-
when NilClass
|
59
|
-
nil
|
60
|
-
when String
|
61
|
-
value
|
62
|
-
when ::Mongo::ObjectID
|
63
|
-
value.to_s
|
64
|
-
else
|
65
|
-
raise ArgumentError.new('+value+ must be nil, String or ObjectID')
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
end # ObjectID
|
70
|
-
end # Types
|
71
|
-
end # Mongo
|
72
|
-
end # DataMapper
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module DataMapper
|
2
|
-
module Mongo
|
3
|
-
module Types
|
4
|
-
class EmbeddedArray < DataMapper::Type
|
5
|
-
primitive Object
|
6
|
-
end
|
7
|
-
|
8
|
-
class EmbeddedHash < DataMapper::Type
|
9
|
-
primitive Object
|
10
|
-
|
11
|
-
# @api public
|
12
|
-
def self.load(value, property)
|
13
|
-
typecast(value, property)
|
14
|
-
end
|
15
|
-
|
16
|
-
# @api semipublic
|
17
|
-
def self.typecast(value, property)
|
18
|
-
case value
|
19
|
-
when NilClass
|
20
|
-
nil
|
21
|
-
when Hash
|
22
|
-
value.to_mash.symbolize_keys
|
23
|
-
when Array
|
24
|
-
value.empty? ? Mash.new : [value].to_mash.symbolize_keys
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end #EmbeddedHash
|
28
|
-
|
29
|
-
end # Types
|
30
|
-
end # Mongo
|
31
|
-
end # DataMapper
|