datamapper-dm-core 0.9.11 → 0.10.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/.autotest +17 -14
- data/.gitignore +3 -1
- data/FAQ +6 -5
- data/History.txt +5 -39
- data/Manifest.txt +67 -76
- data/QUICKLINKS +1 -1
- data/README.txt +21 -15
- data/Rakefile +16 -15
- data/SPECS +2 -29
- data/TODO +1 -1
- data/dm-core.gemspec +11 -15
- data/lib/dm-core/adapters/abstract_adapter.rb +182 -185
- data/lib/dm-core/adapters/data_objects_adapter.rb +482 -534
- data/lib/dm-core/adapters/in_memory_adapter.rb +90 -69
- data/lib/dm-core/adapters/mysql_adapter.rb +22 -115
- data/lib/dm-core/adapters/oracle_adapter.rb +249 -0
- data/lib/dm-core/adapters/postgres_adapter.rb +7 -173
- data/lib/dm-core/adapters/sqlite3_adapter.rb +4 -97
- data/lib/dm-core/adapters/yaml_adapter.rb +116 -0
- data/lib/dm-core/adapters.rb +135 -16
- data/lib/dm-core/associations/many_to_many.rb +372 -90
- data/lib/dm-core/associations/many_to_one.rb +220 -73
- data/lib/dm-core/associations/one_to_many.rb +319 -255
- data/lib/dm-core/associations/one_to_one.rb +66 -53
- data/lib/dm-core/associations/relationship.rb +560 -158
- data/lib/dm-core/collection.rb +1104 -381
- data/lib/dm-core/core_ext/kernel.rb +12 -0
- data/lib/dm-core/core_ext/symbol.rb +10 -0
- data/lib/dm-core/identity_map.rb +4 -34
- data/lib/dm-core/migrations.rb +1283 -0
- data/lib/dm-core/model/descendant_set.rb +81 -0
- data/lib/dm-core/model/hook.rb +45 -0
- data/lib/dm-core/model/is.rb +32 -0
- data/lib/dm-core/model/property.rb +248 -0
- data/lib/dm-core/model/relationship.rb +335 -0
- data/lib/dm-core/model/scope.rb +90 -0
- data/lib/dm-core/model.rb +570 -369
- data/lib/dm-core/property.rb +753 -280
- data/lib/dm-core/property_set.rb +141 -98
- data/lib/dm-core/query/conditions/comparison.rb +814 -0
- data/lib/dm-core/query/conditions/operation.rb +247 -0
- data/lib/dm-core/query/direction.rb +43 -0
- data/lib/dm-core/query/operator.rb +42 -0
- data/lib/dm-core/query/path.rb +102 -0
- data/lib/dm-core/query/sort.rb +45 -0
- data/lib/dm-core/query.rb +974 -492
- data/lib/dm-core/repository.rb +147 -107
- data/lib/dm-core/resource.rb +644 -429
- data/lib/dm-core/spec/adapter_shared_spec.rb +294 -0
- data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +106 -0
- data/lib/dm-core/support/chainable.rb +20 -0
- data/lib/dm-core/support/deprecate.rb +12 -0
- data/lib/dm-core/support/equalizer.rb +23 -0
- data/lib/dm-core/support/logger.rb +13 -0
- data/lib/dm-core/{naming_conventions.rb → support/naming_conventions.rb} +6 -6
- data/lib/dm-core/transaction.rb +333 -92
- data/lib/dm-core/type.rb +98 -60
- data/lib/dm-core/types/boolean.rb +1 -1
- data/lib/dm-core/types/discriminator.rb +34 -20
- data/lib/dm-core/types/object.rb +7 -4
- data/lib/dm-core/types/paranoid_boolean.rb +11 -9
- data/lib/dm-core/types/paranoid_datetime.rb +11 -9
- data/lib/dm-core/types/serial.rb +3 -3
- data/lib/dm-core/types/text.rb +3 -4
- data/lib/dm-core/version.rb +1 -1
- data/lib/dm-core.rb +106 -110
- data/script/performance.rb +102 -109
- data/script/profile.rb +169 -38
- data/spec/lib/adapter_helpers.rb +105 -0
- data/spec/lib/collection_helpers.rb +18 -0
- data/spec/lib/counter_adapter.rb +34 -0
- data/spec/lib/pending_helpers.rb +27 -0
- data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
- data/spec/public/associations/many_to_many_spec.rb +193 -0
- data/spec/public/associations/many_to_one_spec.rb +73 -0
- data/spec/public/associations/one_to_many_spec.rb +77 -0
- data/spec/public/associations/one_to_one_spec.rb +156 -0
- data/spec/public/collection_spec.rb +65 -0
- data/spec/public/model/relationship_spec.rb +924 -0
- data/spec/public/model_spec.rb +159 -0
- data/spec/public/property_spec.rb +829 -0
- data/spec/public/resource_spec.rb +71 -0
- data/spec/public/sel_spec.rb +44 -0
- data/spec/public/setup_spec.rb +145 -0
- data/spec/public/shared/association_collection_shared_spec.rb +317 -0
- data/spec/public/shared/collection_shared_spec.rb +1723 -0
- data/spec/public/shared/finder_shared_spec.rb +1619 -0
- data/spec/public/shared/resource_shared_spec.rb +924 -0
- data/spec/public/shared/sel_shared_spec.rb +112 -0
- data/spec/public/transaction_spec.rb +129 -0
- data/spec/public/types/discriminator_spec.rb +130 -0
- data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
- data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
- data/spec/semipublic/adapters/mysql_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/oracle_adapter_spec.rb +194 -0
- data/spec/semipublic/adapters/postgres_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/yaml_adapter_spec.rb +12 -0
- data/spec/semipublic/associations/many_to_one_spec.rb +53 -0
- data/spec/semipublic/associations/relationship_spec.rb +194 -0
- data/spec/semipublic/associations_spec.rb +177 -0
- data/spec/semipublic/collection_spec.rb +142 -0
- data/spec/semipublic/property_spec.rb +61 -0
- data/spec/semipublic/query/conditions_spec.rb +528 -0
- data/spec/semipublic/query/path_spec.rb +443 -0
- data/spec/semipublic/query_spec.rb +2626 -0
- data/spec/semipublic/resource_spec.rb +47 -0
- data/spec/semipublic/shared/resource_shared_spec.rb +126 -0
- data/spec/spec.opts +3 -1
- data/spec/spec_helper.rb +80 -57
- data/tasks/ci.rb +19 -31
- data/tasks/dm.rb +43 -48
- data/tasks/doc.rb +8 -11
- data/tasks/gemspec.rb +5 -5
- data/tasks/hoe.rb +15 -16
- data/tasks/install.rb +8 -10
- metadata +72 -93
- data/lib/dm-core/associations/relationship_chain.rb +0 -81
- data/lib/dm-core/associations.rb +0 -207
- data/lib/dm-core/auto_migrations.rb +0 -105
- data/lib/dm-core/dependency_queue.rb +0 -32
- data/lib/dm-core/hook.rb +0 -11
- data/lib/dm-core/is.rb +0 -16
- data/lib/dm-core/logger.rb +0 -232
- data/lib/dm-core/migrations/destructive_migrations.rb +0 -17
- data/lib/dm-core/migrator.rb +0 -29
- data/lib/dm-core/scope.rb +0 -58
- data/lib/dm-core/support/array.rb +0 -13
- data/lib/dm-core/support/assertions.rb +0 -8
- data/lib/dm-core/support/errors.rb +0 -23
- data/lib/dm-core/support/kernel.rb +0 -11
- data/lib/dm-core/support/symbol.rb +0 -41
- data/lib/dm-core/support.rb +0 -7
- data/lib/dm-core/type_map.rb +0 -80
- data/lib/dm-core/types.rb +0 -19
- data/script/all +0 -4
- data/spec/integration/association_spec.rb +0 -1382
- data/spec/integration/association_through_spec.rb +0 -203
- data/spec/integration/associations/many_to_many_spec.rb +0 -449
- data/spec/integration/associations/many_to_one_spec.rb +0 -163
- data/spec/integration/associations/one_to_many_spec.rb +0 -188
- data/spec/integration/auto_migrations_spec.rb +0 -413
- data/spec/integration/collection_spec.rb +0 -1073
- data/spec/integration/data_objects_adapter_spec.rb +0 -32
- data/spec/integration/dependency_queue_spec.rb +0 -46
- data/spec/integration/model_spec.rb +0 -197
- data/spec/integration/mysql_adapter_spec.rb +0 -85
- data/spec/integration/postgres_adapter_spec.rb +0 -731
- data/spec/integration/property_spec.rb +0 -253
- data/spec/integration/query_spec.rb +0 -514
- data/spec/integration/repository_spec.rb +0 -61
- data/spec/integration/resource_spec.rb +0 -513
- data/spec/integration/sqlite3_adapter_spec.rb +0 -352
- data/spec/integration/sti_spec.rb +0 -273
- data/spec/integration/strategic_eager_loading_spec.rb +0 -156
- data/spec/integration/transaction_spec.rb +0 -75
- data/spec/integration/type_spec.rb +0 -275
- data/spec/lib/logging_helper.rb +0 -18
- data/spec/lib/mock_adapter.rb +0 -27
- data/spec/lib/model_loader.rb +0 -100
- data/spec/lib/publicize_methods.rb +0 -28
- data/spec/models/content.rb +0 -16
- data/spec/models/vehicles.rb +0 -34
- data/spec/models/zoo.rb +0 -48
- data/spec/unit/adapters/abstract_adapter_spec.rb +0 -133
- data/spec/unit/adapters/adapter_shared_spec.rb +0 -15
- data/spec/unit/adapters/data_objects_adapter_spec.rb +0 -632
- data/spec/unit/adapters/in_memory_adapter_spec.rb +0 -98
- data/spec/unit/adapters/postgres_adapter_spec.rb +0 -133
- data/spec/unit/associations/many_to_many_spec.rb +0 -32
- data/spec/unit/associations/many_to_one_spec.rb +0 -159
- data/spec/unit/associations/one_to_many_spec.rb +0 -393
- data/spec/unit/associations/one_to_one_spec.rb +0 -7
- data/spec/unit/associations/relationship_spec.rb +0 -71
- data/spec/unit/associations_spec.rb +0 -242
- data/spec/unit/auto_migrations_spec.rb +0 -111
- data/spec/unit/collection_spec.rb +0 -182
- data/spec/unit/data_mapper_spec.rb +0 -35
- data/spec/unit/identity_map_spec.rb +0 -126
- data/spec/unit/is_spec.rb +0 -80
- data/spec/unit/migrator_spec.rb +0 -33
- data/spec/unit/model_spec.rb +0 -321
- data/spec/unit/naming_conventions_spec.rb +0 -36
- data/spec/unit/property_set_spec.rb +0 -90
- data/spec/unit/property_spec.rb +0 -753
- data/spec/unit/query_spec.rb +0 -571
- data/spec/unit/repository_spec.rb +0 -93
- data/spec/unit/resource_spec.rb +0 -649
- data/spec/unit/scope_spec.rb +0 -142
- data/spec/unit/transaction_spec.rb +0 -493
- data/spec/unit/type_map_spec.rb +0 -114
- data/spec/unit/type_spec.rb +0 -119
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
module DataMapper
|
|
2
|
+
class Query
|
|
3
|
+
module Conditions
|
|
4
|
+
class InvalidOperation < ArgumentError; end
|
|
5
|
+
|
|
6
|
+
class Operation
|
|
7
|
+
# TODO: document
|
|
8
|
+
# @api semipublic
|
|
9
|
+
def self.new(slug, *operands)
|
|
10
|
+
if klass = operation_class(slug)
|
|
11
|
+
klass.new(*operands)
|
|
12
|
+
else
|
|
13
|
+
raise "No Operation class for `#{slug.inspect}' has been defined"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# TODO: document
|
|
18
|
+
# @api semipublic
|
|
19
|
+
def self.operation_class(slug)
|
|
20
|
+
operation_classes[slug] ||= AbstractOperation.descendants.detect { |operation_class| operation_class.slug == slug }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# TODO: document
|
|
24
|
+
# @api private
|
|
25
|
+
def self.slugs
|
|
26
|
+
@slugs ||= AbstractOperation.descendants.map { |operation_class| operation_class.slug }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class << self
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# TODO: document
|
|
33
|
+
# @api private
|
|
34
|
+
def operation_classes
|
|
35
|
+
@operation_classes ||= {}
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end # class Operation
|
|
39
|
+
|
|
40
|
+
class AbstractOperation
|
|
41
|
+
include Enumerable
|
|
42
|
+
extend Equalizer
|
|
43
|
+
|
|
44
|
+
equalize :slug, :sorted_operands
|
|
45
|
+
|
|
46
|
+
# TODO: document
|
|
47
|
+
# @api semipublic
|
|
48
|
+
attr_reader :operands
|
|
49
|
+
|
|
50
|
+
# TODO: document
|
|
51
|
+
# @api private
|
|
52
|
+
def self.descendants
|
|
53
|
+
@descendants ||= Set.new
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# TODO: document
|
|
57
|
+
# @api private
|
|
58
|
+
def self.inherited(operation_class)
|
|
59
|
+
descendants << operation_class
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# TODO: document
|
|
63
|
+
# @api semipublic
|
|
64
|
+
def self.slug(slug = nil)
|
|
65
|
+
slug ? @slug = slug : @slug
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Return the comparison class slug
|
|
69
|
+
#
|
|
70
|
+
# @return [Symbol]
|
|
71
|
+
# the comparison class slug
|
|
72
|
+
#
|
|
73
|
+
# @api private
|
|
74
|
+
def slug
|
|
75
|
+
self.class.slug
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# TODO: document
|
|
79
|
+
# @api semipublic
|
|
80
|
+
def each
|
|
81
|
+
@operands.each { |*block_args| yield(*block_args) }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# TODO: document
|
|
85
|
+
# @api semipublic
|
|
86
|
+
def valid?
|
|
87
|
+
operands.any? && operands.all? do |operand|
|
|
88
|
+
if operand.respond_to?(:valid?)
|
|
89
|
+
operand.valid?
|
|
90
|
+
else
|
|
91
|
+
true
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# TODO: document
|
|
97
|
+
# @api semipublic
|
|
98
|
+
def <<(operand)
|
|
99
|
+
@operands << operand
|
|
100
|
+
self
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# TODO: document
|
|
104
|
+
# @api semipublic
|
|
105
|
+
def inspect
|
|
106
|
+
"#<#{self.class} @operands=#{@operands.inspect}>"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Return a list of operands in predictable order
|
|
110
|
+
#
|
|
111
|
+
# @return [Array<AbstractOperation>]
|
|
112
|
+
# list of operands sorted in deterministic order
|
|
113
|
+
#
|
|
114
|
+
# @api private
|
|
115
|
+
def sorted_operands
|
|
116
|
+
@operands.sort_by { |operand| operand.hash }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
private
|
|
120
|
+
|
|
121
|
+
# TODO: document
|
|
122
|
+
# @api semipublic
|
|
123
|
+
def initialize(*operands)
|
|
124
|
+
@operands = operands
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# TODO: document
|
|
128
|
+
# @api semipublic
|
|
129
|
+
def initialize_copy(*)
|
|
130
|
+
@operands = @operands.map { |operand| operand.dup }
|
|
131
|
+
end
|
|
132
|
+
end # class AbstractOperation
|
|
133
|
+
|
|
134
|
+
module FlattenOperation
|
|
135
|
+
# TODO: document
|
|
136
|
+
# @api semipublic
|
|
137
|
+
def <<(operand)
|
|
138
|
+
if operand.kind_of?(self.class)
|
|
139
|
+
@operands.concat(operand.operands)
|
|
140
|
+
self
|
|
141
|
+
else
|
|
142
|
+
super
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end # module FlattenOperation
|
|
146
|
+
|
|
147
|
+
class AndOperation < AbstractOperation
|
|
148
|
+
include FlattenOperation
|
|
149
|
+
|
|
150
|
+
slug :and
|
|
151
|
+
|
|
152
|
+
# TODO: document
|
|
153
|
+
# @api semipublic
|
|
154
|
+
def matches?(record)
|
|
155
|
+
@operands.all? { |operand| operand.matches?(record) }
|
|
156
|
+
end
|
|
157
|
+
end # class AndOperation
|
|
158
|
+
|
|
159
|
+
class OrOperation < AbstractOperation
|
|
160
|
+
include FlattenOperation
|
|
161
|
+
|
|
162
|
+
slug :or
|
|
163
|
+
|
|
164
|
+
# TODO: document
|
|
165
|
+
# @api semipublic
|
|
166
|
+
def matches?(record)
|
|
167
|
+
@operands.any? { |operand| operand.matches?(record) }
|
|
168
|
+
end
|
|
169
|
+
end # class OrOperation
|
|
170
|
+
|
|
171
|
+
class NotOperation < AbstractOperation
|
|
172
|
+
slug :not
|
|
173
|
+
|
|
174
|
+
# TODO: document
|
|
175
|
+
# @api semipublic
|
|
176
|
+
def matches?(record)
|
|
177
|
+
not @operands.first.matches?(record)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# TODO: document
|
|
181
|
+
# @api semipublic
|
|
182
|
+
def <<(operand)
|
|
183
|
+
raise ArgumentError, "#{self.class} cannot have more than one operand" if @operands.size > 0
|
|
184
|
+
super
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
private
|
|
188
|
+
|
|
189
|
+
# TODO: document
|
|
190
|
+
# @api semipublic
|
|
191
|
+
def initialize(*operands)
|
|
192
|
+
raise InvalidOperation, "#{self.class} is a unary operator" if operands.size > 1
|
|
193
|
+
super
|
|
194
|
+
end
|
|
195
|
+
end # class NotOperation
|
|
196
|
+
|
|
197
|
+
class NullOperation < AbstractOperation
|
|
198
|
+
undef_method :<<
|
|
199
|
+
|
|
200
|
+
slug :null
|
|
201
|
+
|
|
202
|
+
# Match the record
|
|
203
|
+
#
|
|
204
|
+
# @param [Resource] record
|
|
205
|
+
# the resource to match
|
|
206
|
+
#
|
|
207
|
+
# @return [true]
|
|
208
|
+
# every record matches
|
|
209
|
+
#
|
|
210
|
+
# @api semipublic
|
|
211
|
+
def matches?(record)
|
|
212
|
+
true
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Test validity of the operation
|
|
216
|
+
#
|
|
217
|
+
# @return [true]
|
|
218
|
+
# always valid
|
|
219
|
+
#
|
|
220
|
+
# @api semipublic
|
|
221
|
+
def valid?
|
|
222
|
+
true
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Treat the operation the same as nil
|
|
226
|
+
#
|
|
227
|
+
# @return [true]
|
|
228
|
+
# should be treated as nil
|
|
229
|
+
#
|
|
230
|
+
# @api semipublic
|
|
231
|
+
def nil?
|
|
232
|
+
true
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Inspecting the operation should return the same as nil
|
|
236
|
+
#
|
|
237
|
+
# @return [String]
|
|
238
|
+
# return the string 'nil'
|
|
239
|
+
#
|
|
240
|
+
# @api semipublic
|
|
241
|
+
def inspect
|
|
242
|
+
'nil'
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end # module Conditions
|
|
246
|
+
end # class Query
|
|
247
|
+
end # module DataMapper
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# TODO: rename this DM::Symbol::Direction
|
|
2
|
+
|
|
3
|
+
# TODO: add a method to convert it into a DM::Query::Sort object, eg:
|
|
4
|
+
# operator.sort_for(model)
|
|
5
|
+
|
|
6
|
+
# TODO: rename #target to #property_name
|
|
7
|
+
|
|
8
|
+
# TODO: make sure Query converts this into a DM::Query::Sort object
|
|
9
|
+
# immediately and passes that down to the Adapter
|
|
10
|
+
|
|
11
|
+
# TODO: remove #get method
|
|
12
|
+
|
|
13
|
+
module DataMapper
|
|
14
|
+
class Query
|
|
15
|
+
class Direction < Operator
|
|
16
|
+
extend Deprecate
|
|
17
|
+
|
|
18
|
+
deprecate :property, :target
|
|
19
|
+
deprecate :direction, :operator
|
|
20
|
+
|
|
21
|
+
# TODO: document
|
|
22
|
+
# @api private
|
|
23
|
+
def reverse!
|
|
24
|
+
@operator = @operator == :asc ? :desc : :asc
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# TODO: document
|
|
29
|
+
# @api private
|
|
30
|
+
def get(resource)
|
|
31
|
+
Sort.new(target.get(resource), @operator == :asc)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# TODO: document
|
|
37
|
+
# @api private
|
|
38
|
+
def initialize(target, operator = :asc)
|
|
39
|
+
super
|
|
40
|
+
end
|
|
41
|
+
end # class Direction
|
|
42
|
+
end # class Query
|
|
43
|
+
end # module DataMapper
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# TODO: rename this DM::Symbol::Operator
|
|
2
|
+
|
|
3
|
+
# TODO: add a method to convert it into a DM::Query::AbstractComparison object, eg:
|
|
4
|
+
# operator.comparison_for(repository, model)
|
|
5
|
+
|
|
6
|
+
# TODO: rename #target to #property_name
|
|
7
|
+
|
|
8
|
+
module DataMapper
|
|
9
|
+
class Query
|
|
10
|
+
class Operator
|
|
11
|
+
include Extlib::Assertions
|
|
12
|
+
extend Equalizer
|
|
13
|
+
|
|
14
|
+
equalize :target, :operator
|
|
15
|
+
|
|
16
|
+
# TODO: document
|
|
17
|
+
# @api private
|
|
18
|
+
attr_reader :target
|
|
19
|
+
|
|
20
|
+
# TODO: document
|
|
21
|
+
# @api private
|
|
22
|
+
attr_reader :operator
|
|
23
|
+
|
|
24
|
+
# TODO: document
|
|
25
|
+
# @api private
|
|
26
|
+
def inspect
|
|
27
|
+
"#<#{self.class.name} @target=#{target.inspect} @operator=#{operator.inspect}>"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# TODO: document
|
|
33
|
+
# @api private
|
|
34
|
+
def initialize(target, operator)
|
|
35
|
+
assert_kind_of 'operator', operator, Symbol
|
|
36
|
+
|
|
37
|
+
@target = target
|
|
38
|
+
@operator = operator
|
|
39
|
+
end
|
|
40
|
+
end # class Operator
|
|
41
|
+
end # class Query
|
|
42
|
+
end # module DataMapper
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# TODO: instead of an Array of Path objects, create a Relationship
|
|
2
|
+
# on the fly using :through on the previous relationship, creating a
|
|
3
|
+
# chain. Query::Path could then be a thin wrapper that specifies extra
|
|
4
|
+
# conditions on the Relationships, like the target property o match
|
|
5
|
+
# on.
|
|
6
|
+
|
|
7
|
+
module DataMapper
|
|
8
|
+
class Query
|
|
9
|
+
class Path
|
|
10
|
+
instance_methods.each { |method| undef_method method unless %w[ __id__ __send__ send class dup object_id kind_of? instance_of? respond_to? equal? should should_not instance_variable_set instance_variable_get extend hash inspect ].include?(method.to_s) }
|
|
11
|
+
|
|
12
|
+
include Extlib::Assertions
|
|
13
|
+
extend Equalizer
|
|
14
|
+
|
|
15
|
+
equalize :relationships, :property
|
|
16
|
+
|
|
17
|
+
# TODO: document
|
|
18
|
+
# @api semipublic
|
|
19
|
+
attr_reader :repository_name
|
|
20
|
+
|
|
21
|
+
# TODO: document
|
|
22
|
+
# @api semipublic
|
|
23
|
+
attr_reader :relationships
|
|
24
|
+
|
|
25
|
+
# TODO: document
|
|
26
|
+
# @api semipublic
|
|
27
|
+
attr_reader :model
|
|
28
|
+
|
|
29
|
+
# TODO: document
|
|
30
|
+
# @api semipublic
|
|
31
|
+
attr_reader :property
|
|
32
|
+
|
|
33
|
+
(Conditions::Comparison.slugs | [ :not ]).each do |slug|
|
|
34
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
35
|
+
def #{slug} # def eql
|
|
36
|
+
#{"warn \"explicit use of '#{slug}' operator is deprecated (#{caller[0]})\"" if slug == :eql || slug == :in} # warn "explicit use of 'eql' operator is deprecated (#{caller[0]})"
|
|
37
|
+
Operator.new(self, #{slug.inspect}) # Operator.new(self, :eql)
|
|
38
|
+
end # end
|
|
39
|
+
RUBY
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# TODO: document
|
|
43
|
+
# @api public
|
|
44
|
+
def kind_of?(klass)
|
|
45
|
+
super || (defined?(@property) ? @property.kind_of?(klass) : false)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# TODO: document
|
|
49
|
+
# @api public
|
|
50
|
+
def instance_of?(klass)
|
|
51
|
+
super || (defined?(@property) ? @property.instance_of?(klass) : false)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# TODO: document
|
|
55
|
+
# @api semipublic
|
|
56
|
+
def respond_to?(method, include_private = false)
|
|
57
|
+
super ||
|
|
58
|
+
(defined?(@property) && @property.respond_to?(method, include_private)) ||
|
|
59
|
+
@model.relationships(@repository_name).key?(method) ||
|
|
60
|
+
@model.properties(@repository_name).named?(method)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
# TODO: document
|
|
66
|
+
# @api semipublic
|
|
67
|
+
def initialize(relationships, property_name = nil)
|
|
68
|
+
assert_kind_of 'relationships', relationships, Array
|
|
69
|
+
assert_kind_of 'property_name', property_name, Symbol, NilClass
|
|
70
|
+
|
|
71
|
+
@relationships = relationships.dup
|
|
72
|
+
|
|
73
|
+
last_relationship = @relationships.last
|
|
74
|
+
@repository_name = last_relationship.relative_target_repository_name
|
|
75
|
+
@model = last_relationship.target_model
|
|
76
|
+
|
|
77
|
+
if property_name
|
|
78
|
+
@property = @model.properties(@repository_name)[property_name] ||
|
|
79
|
+
raise(ArgumentError, "Unknown property '#{property_name}' in #{@model}")
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# TODO: document
|
|
84
|
+
# @api semipublic
|
|
85
|
+
def method_missing(method, *args)
|
|
86
|
+
if @property
|
|
87
|
+
return @property.send(method, *args)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
if relationship = @model.relationships(@repository_name)[method]
|
|
91
|
+
return self.class.new(@relationships.dup << relationship)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
if @model.properties(@repository_name).named?(method)
|
|
95
|
+
return self.class.new(@relationships, method)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
raise NoMethodError, "undefined property or relationship '#{method}' on #{@model}"
|
|
99
|
+
end
|
|
100
|
+
end # class Path
|
|
101
|
+
end # class Query
|
|
102
|
+
end # module DataMapper
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# TODO: add #reverse and #reverse! methods
|
|
2
|
+
|
|
3
|
+
module DataMapper
|
|
4
|
+
class Query
|
|
5
|
+
class Sort
|
|
6
|
+
# TODO: document
|
|
7
|
+
# @api semipublic
|
|
8
|
+
attr_reader :value
|
|
9
|
+
|
|
10
|
+
# TODO: document
|
|
11
|
+
# @api semipublic
|
|
12
|
+
def direction
|
|
13
|
+
@ascending ? :ascending : :descending
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# TODO: document
|
|
17
|
+
# @api private
|
|
18
|
+
def <=>(other)
|
|
19
|
+
other_value = other.value
|
|
20
|
+
|
|
21
|
+
cmp = case
|
|
22
|
+
when @value.nil? && other_value.nil?
|
|
23
|
+
0
|
|
24
|
+
when @value.nil?
|
|
25
|
+
1
|
|
26
|
+
when other_value.nil?
|
|
27
|
+
-1
|
|
28
|
+
else
|
|
29
|
+
@value <=> other_value
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
@ascending ? cmp : cmp * -1
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
# TODO: document
|
|
38
|
+
# @api private
|
|
39
|
+
def initialize(value, ascending = true)
|
|
40
|
+
@value = value
|
|
41
|
+
@ascending = ascending
|
|
42
|
+
end
|
|
43
|
+
end # class Sort
|
|
44
|
+
end # class Query
|
|
45
|
+
end # module DataMapper
|