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