spiderfw 0.6.23 → 0.6.24
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +10 -1
- data/README.rdoc +1 -1
- data/VERSION +1 -1
- data/apps/config_editor/_init.rb +1 -2
- data/apps/config_editor/controllers/config_editor_controller.rb +1 -7
- data/apps/core/admin/controllers/admin_controller.rb +1 -1
- data/apps/core/admin/public/css/sass/admin.css +35 -31
- data/apps/core/admin/public/sass/admin.scss +6 -1
- data/apps/core/components/widgets/crud/crud.shtml +2 -2
- data/apps/core/components/widgets/table/table.rb +5 -5
- data/apps/core/forms/tags/element_row.erb +15 -10
- data/apps/core/forms/widgets/form/form.rb +35 -22
- data/apps/core/forms/widgets/inputs/checkbox/checkbox.shtml +2 -2
- data/apps/core/forms/widgets/inputs/date_time/date_time.shtml +2 -2
- data/apps/core/forms/widgets/inputs/file_input/file_input.shtml +2 -2
- data/apps/core/forms/widgets/inputs/html_area/html_area.shtml +2 -2
- data/apps/core/forms/widgets/inputs/input/input.shtml +2 -2
- data/apps/core/forms/widgets/inputs/password/password.shtml +2 -2
- data/apps/core/forms/widgets/inputs/search_select/search_select.shtml +1 -1
- data/apps/core/forms/widgets/inputs/select/select.shtml +2 -2
- data/apps/core/forms/widgets/inputs/text/text.shtml +2 -2
- data/apps/core/forms/widgets/inputs/text_area/text_area.shtml +2 -2
- data/apps/core/forms/widgets/inputs/time_span/time_span.shtml +1 -1
- data/blueprints/home/config.ru +8 -0
- data/lib/spiderfw/app.rb +416 -224
- data/lib/spiderfw/cmd/commands/app.rb +243 -239
- data/lib/spiderfw/cmd/commands/cert.rb +421 -417
- data/lib/spiderfw/cmd/commands/config.rb +85 -82
- data/lib/spiderfw/cmd/commands/console.rb +64 -40
- data/lib/spiderfw/cmd/commands/content.rb +29 -25
- data/lib/spiderfw/cmd/commands/create.rb +58 -54
- data/lib/spiderfw/cmd/commands/model.rb +118 -114
- data/lib/spiderfw/cmd/commands/setup.rb +55 -51
- data/lib/spiderfw/cmd/commands/test.rb +63 -59
- data/lib/spiderfw/cmd/commands/webserver.rb +56 -51
- data/lib/spiderfw/config/options/spider.rb +4 -3
- data/lib/spiderfw/controller/controller.rb +2 -0
- data/lib/spiderfw/controller/http_controller.rb +1 -2
- data/lib/spiderfw/controller/mixins/static_content.rb +3 -3
- data/lib/spiderfw/controller/mixins/visual.rb +30 -15
- data/lib/spiderfw/controller/response.rb +84 -0
- data/lib/spiderfw/controller/session/file_session.rb +2 -2
- data/lib/spiderfw/http/adapters/rack.rb +12 -13
- data/lib/spiderfw/http/server.rb +80 -46
- data/lib/spiderfw/i18n/cldr.rb +6 -9
- data/lib/spiderfw/model/base_model.rb +103 -23
- data/lib/spiderfw/model/condition.rb +110 -25
- data/lib/spiderfw/model/mappers/db_mapper.rb +14 -6
- data/lib/spiderfw/model/mappers/mapper.rb +440 -197
- data/lib/spiderfw/model/model.rb +105 -21
- data/lib/spiderfw/model/model_hash.rb +9 -1
- data/lib/spiderfw/model/query.rb +50 -9
- data/lib/spiderfw/model/query_set.rb +211 -44
- data/lib/spiderfw/model/request.rb +28 -21
- data/lib/spiderfw/model/storage/base_storage.rb +125 -10
- data/lib/spiderfw/model/storage/db/db_storage.rb +7 -4
- data/lib/spiderfw/model/storage.rb +8 -1
- data/lib/spiderfw/setup/spider_setup_wizard.rb +9 -7
- data/lib/spiderfw/spider.rb +270 -43
- data/lib/spiderfw/templates/layout.rb +9 -4
- data/lib/spiderfw/templates/resources/sass.rb +3 -2
- data/lib/spiderfw/templates/template.rb +1 -0
- data/lib/spiderfw/utils/annotations.rb +3 -1
- data/lib/spiderfw/utils/logger.rb +1 -1
- data/lib/spiderfw/utils/monkey/symbol.rb +4 -2
- data/lib/spiderfw/utils/shared_store/file_shared_store.rb +2 -2
- data/lib/spiderfw/utils/thread_out.rb +3 -1
- data/public/css/error_page.css +83 -0
- data/public/js/error_page.js +5 -0
- data/spider.gemspec +4 -1
- data/templates/email/error.erb +9 -0
- metadata +28 -12
- data/apps/config_editor/widgets/edit_bool/edit_bool.rb +0 -8
- data/apps/config_editor/widgets/edit_bool/edit_bool.shtml +0 -5
@@ -2,32 +2,46 @@ require 'spiderfw/model/model_hash'
|
|
2
2
|
|
3
3
|
module Spider; module Model
|
4
4
|
|
5
|
-
# The Condition behaves like a ModelHash, and as such contains key-value pairs:
|
5
|
+
# The Condition behaves like a {ModelHash}, and as such contains key-value pairs:
|
6
6
|
# a simple equality condition can be set with
|
7
7
|
# condition[:element_name] = value
|
8
8
|
# The Condition object also holds comparisons: a comparison different from equality can be set with
|
9
9
|
# condition.set(:element_name, '>', value)
|
10
10
|
# Finally, it contains subconditions, which can be added with
|
11
11
|
# conditions << subcondition
|
12
|
-
# Subconditions will be created automatically when using #set twice on the same element.
|
13
|
-
# If you want to change the condition, use #delete and set it again.
|
12
|
+
# Subconditions will be created automatically when using {#set} twice on the same element.
|
13
|
+
# If you want to change the condition, use {#delete} and set it again.
|
14
|
+
#
|
15
|
+
# Conditions also support an SQL-like block syntax for setting conditions:
|
16
|
+
# books_condition = Condition.new{ |book|
|
17
|
+
# ((book.year < 1970) | (book.price > 1000)) & (book.author.name .like 'John')
|
18
|
+
# }
|
14
19
|
#
|
15
20
|
# The Condition object, like the Request, doesn't hold a reference to a model; so no check will be made
|
16
21
|
# that the conditions elements are meaningful.
|
17
22
|
|
18
23
|
class Condition < Hash
|
19
24
|
# The top level conjunction for the Condition (:or or :and; new Conditions are initialized with :or)
|
25
|
+
# @return [Symbol] :and | :or
|
20
26
|
attr_accessor :conjunction
|
21
27
|
# Polymorph model: used to tell the mapper the condition is on a subclass of the queried model.
|
28
|
+
# @return [Class<BaseModel]
|
22
29
|
attr_accessor :polymorph
|
23
30
|
# An hash of comparisons for each element name
|
31
|
+
# @return [Hash]
|
24
32
|
attr_reader :comparisons
|
25
33
|
# An Array of subconditions
|
34
|
+
# @return [Array]
|
26
35
|
attr_reader :subconditions
|
27
|
-
|
36
|
+
# @private
|
37
|
+
# A pointer to the last Condition used in condition blocks
|
38
|
+
# @return [Condition]
|
39
|
+
attr_accessor :conjunct
|
40
|
+
# Original hash value assignment
|
28
41
|
alias :hash_set :[]= # :nodoc:
|
29
42
|
|
30
43
|
# See #ModelHash.get_deep_obj
|
44
|
+
# @return [Condition]
|
31
45
|
def get_deep_obj # :nodoc:
|
32
46
|
c = self.class.new
|
33
47
|
c.conjunction = @conjunction
|
@@ -40,12 +54,18 @@ module Spider; module Model
|
|
40
54
|
str += Regexp.quote(op)
|
41
55
|
end
|
42
56
|
|
57
|
+
# @private
|
43
58
|
# Regexp to parse comparison operators
|
44
|
-
|
59
|
+
# @return [Regexp]
|
60
|
+
def self.comparison_operators_regexp
|
45
61
|
@comparison_operators_regexp
|
46
62
|
end
|
47
63
|
|
48
|
-
#
|
64
|
+
# @private
|
65
|
+
# Used by {Condition.and} and {Condition.or} methods
|
66
|
+
# @param [Symbol] conjunction
|
67
|
+
# @param [Condition] a
|
68
|
+
# @param [Condition] b
|
49
69
|
def self.conj(conjunction, a, b) # :nodoc:
|
50
70
|
c = Condition.new
|
51
71
|
c.conjunction = conjunction
|
@@ -54,7 +74,8 @@ module Spider; module Model
|
|
54
74
|
end
|
55
75
|
|
56
76
|
# Instantiates a Condition with :and conjunction.
|
57
|
-
# See
|
77
|
+
# See {Condition.new} for arguments.
|
78
|
+
# @return [Condition]
|
58
79
|
def self.and(*params, &proc)
|
59
80
|
c = self.new(*params, &proc)
|
60
81
|
c.conjunction = :and
|
@@ -62,7 +83,8 @@ module Spider; module Model
|
|
62
83
|
end
|
63
84
|
|
64
85
|
# Instantiates a Condition with :or conjunction.
|
65
|
-
# See
|
86
|
+
# See {Condition.new} for arguments.
|
87
|
+
# @return [Condition]
|
66
88
|
def self.or(*params, &proc)
|
67
89
|
c = self.new(*params, &proc)
|
68
90
|
c.conjunction = :or
|
@@ -70,7 +92,9 @@ module Spider; module Model
|
|
70
92
|
end
|
71
93
|
|
72
94
|
# Instantiates a Condition with no conjunction.
|
73
|
-
|
95
|
+
# See {Condition.new} for arguments.
|
96
|
+
# @return [Condition]
|
97
|
+
def self.no_conjunction(*params, &proc)
|
74
98
|
c = self.new(*params, &proc)
|
75
99
|
c.conjunction = nil
|
76
100
|
return c
|
@@ -101,12 +125,14 @@ module Spider; module Model
|
|
101
125
|
#
|
102
126
|
# Example:
|
103
127
|
# condition.parse_block{ (element1 == val1) & ( (element2 > 'some string') | (element3 .not nil) ) }
|
128
|
+
#
|
104
129
|
# All comparisons must be parenthesized; and/or conjunctions are expressed with a single &/|.
|
105
130
|
#
|
106
131
|
# Available comparisions are: ==, >, <, >=, <=, .not, .like, .ilike (case insensitive like).
|
107
132
|
#
|
108
133
|
# _Note:_ for .like and .ilike comparisons, the SQL '%' syntax must be used.
|
109
134
|
#
|
135
|
+
# @param [Proc] proc The condition block
|
110
136
|
def parse_block(&proc)
|
111
137
|
res = nil
|
112
138
|
if proc.arity == 1
|
@@ -122,6 +148,7 @@ module Spider; module Model
|
|
122
148
|
@polymorph = res.polymorph
|
123
149
|
end
|
124
150
|
|
151
|
+
# @return [Array] An array of all conditions, expressed as [key, value, comparison]
|
125
152
|
def conditions_array
|
126
153
|
self.hash_clone.map do |k, v|
|
127
154
|
k = k.to_sym if k.respond_to?(:to_sym)
|
@@ -130,6 +157,7 @@ module Spider; module Model
|
|
130
157
|
end
|
131
158
|
|
132
159
|
# Yields each key, value and comparison.
|
160
|
+
# @return void
|
133
161
|
def each_with_comparison
|
134
162
|
self.each do |k, v|
|
135
163
|
k = k.to_sym if k.respond_to?(:to_sym)
|
@@ -138,6 +166,7 @@ module Spider; module Model
|
|
138
166
|
end
|
139
167
|
|
140
168
|
# Yields each key, value and comparison, for this condition and its subconditions
|
169
|
+
# @return [void]
|
141
170
|
def all_each_with_comparison
|
142
171
|
self.each_with_comparison{ |k, v, c| yield k, v, c }
|
143
172
|
@subconditions.each do |sub|
|
@@ -145,11 +174,15 @@ module Spider; module Model
|
|
145
174
|
end
|
146
175
|
end
|
147
176
|
|
177
|
+
# @param [Class<BaseModel] The model on which the Condition is based on.
|
178
|
+
# @return [bool] True if the condition has only primary keys for the given model
|
148
179
|
def primary_keys_only?(model)
|
149
180
|
self.select{ |key, value| !model.elements[key] || !model.elements[key].primary_key? }.empty?
|
150
181
|
end
|
151
182
|
|
152
183
|
# Returns the result of merging the condition with another one (does not modify the original condition).
|
184
|
+
# @param [Condition] Condition to merge with
|
185
|
+
# @return [Condition] The resulting Condition
|
153
186
|
def +(condition)
|
154
187
|
res = self.clone
|
155
188
|
@subconditions += condition.subconditions
|
@@ -160,6 +193,8 @@ module Spider; module Model
|
|
160
193
|
end
|
161
194
|
|
162
195
|
# Adds a subcondtion.
|
196
|
+
# @param [Condition] condition
|
197
|
+
# @return [void]
|
163
198
|
def <<(condition)
|
164
199
|
if (condition.class == self.class)
|
165
200
|
@subconditions << condition
|
@@ -171,7 +206,11 @@ module Spider; module Model
|
|
171
206
|
end
|
172
207
|
end
|
173
208
|
|
174
|
-
#
|
209
|
+
# Adds a single condition for an element
|
210
|
+
# @param [Symbol|String|QueryFuncs::Function] field to add the condition to
|
211
|
+
# @param [String] comparison: can be =, <, >, <=, >=, 'between'
|
212
|
+
# @param [QuerySet|Array|Range|Object] the value of the condition
|
213
|
+
# @return [self]
|
175
214
|
def set(field, comparison, value)
|
176
215
|
if value.is_a?(QuerySet)
|
177
216
|
value = value.to_a
|
@@ -188,6 +227,7 @@ module Spider; module Model
|
|
188
227
|
unless field.is_a?(Spider::QueryFuncs::Function)
|
189
228
|
field = field.to_s
|
190
229
|
parts = field.split('.', 2)
|
230
|
+
debugger if parts[0].blank?
|
191
231
|
parts[0] = parts[0].to_sym
|
192
232
|
field = field.to_sym unless parts[1]
|
193
233
|
end
|
@@ -206,10 +246,18 @@ module Spider; module Model
|
|
206
246
|
end
|
207
247
|
|
208
248
|
# Sets an equality comparison.
|
249
|
+
#
|
250
|
+
# Equivalent to {#set}(key, '=', value)
|
251
|
+
# @param [String|Symbol|QueryFuncs::Function] key
|
252
|
+
# @param [Object] value
|
253
|
+
# @return [self]
|
209
254
|
def []=(key, value)
|
210
255
|
set(key, '=', value)
|
211
256
|
end
|
212
257
|
|
258
|
+
# Gets the value of a condition
|
259
|
+
# @param [String|Symbol|QueryFuncs::Function] key
|
260
|
+
# @return [Object] value
|
213
261
|
def [](key)
|
214
262
|
# TODO: deep
|
215
263
|
key = key.name if key.is_a?(Element)
|
@@ -218,6 +266,10 @@ module Spider; module Model
|
|
218
266
|
end
|
219
267
|
|
220
268
|
# Adds a range condition. This creates a subcondition with >= and <= conditions.
|
269
|
+
# @param [String|Symbol|QueryFuncs::Function] key
|
270
|
+
# @param [Object] lower
|
271
|
+
# @param [Object] upper
|
272
|
+
# @return [self]
|
221
273
|
def range(field, lower, upper)
|
222
274
|
c = self.class.and
|
223
275
|
c.set(field, '>=', lower)
|
@@ -226,6 +278,8 @@ module Spider; module Model
|
|
226
278
|
end
|
227
279
|
|
228
280
|
# Deletes a field from the Condition.
|
281
|
+
# @param [String|Symbol|QueryFuncs::Function] key
|
282
|
+
# @return [Array] A pair containing the deleted value and comparison
|
229
283
|
def delete(field)
|
230
284
|
field = field.to_sym
|
231
285
|
return nil unless self[field] || @comparisons[field]
|
@@ -235,17 +289,7 @@ module Spider; module Model
|
|
235
289
|
cur
|
236
290
|
end
|
237
291
|
|
238
|
-
#
|
239
|
-
# TODO: remove?
|
240
|
-
def parse_comparison(comparison) # :nodoc:
|
241
|
-
if (comparison =~ Regexp.new("(.+)(#{self.class.comparison_operators_regexp})(.+)"))
|
242
|
-
val = $3.strip
|
243
|
-
# strip single and double quotes
|
244
|
-
val = val[1..-2] if ((val[0] == ?' && val[-1] == ?') || (val[0] == ?" && val[-1] == ?") )
|
245
|
-
return [$1.strip, $2.strip, val]
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
292
|
+
# @return [String] A String representation of the condition
|
249
293
|
def inspect
|
250
294
|
str = ""
|
251
295
|
cnt = 0
|
@@ -269,6 +313,10 @@ module Spider; module Model
|
|
269
313
|
# Returns the conjunction with another condition.
|
270
314
|
# If this condition already has the required conjunction, the other will be added as a subcondition;
|
271
315
|
# otherwise, a new condition will be created and both will be added to it.
|
316
|
+
# @param [Symbol] conjunction :and | :or
|
317
|
+
# @param [Condition] other Condition to conjuct to this
|
318
|
+
# @param [Proc] proc Block to create the other condition
|
319
|
+
# @return [Condition] The resulting Condition (self, or the new Condition created)
|
272
320
|
def conj(conjunction, other=nil, &proc)
|
273
321
|
self.conjunction = conjunction if (!self.conjunction)
|
274
322
|
if (self.conjunction == conjunction)
|
@@ -287,14 +335,20 @@ module Spider; module Model
|
|
287
335
|
end
|
288
336
|
|
289
337
|
|
290
|
-
# Joins the condition to another with an "or" conjunction. See #conj.
|
338
|
+
# Joins the condition to another with an "or" conjunction. See {#conj}.
|
339
|
+
# @param [Condition] other Condition to conjuct to this
|
340
|
+
# @param [Proc] proc Block to create the other condition
|
341
|
+
# @return [Condition] The resulting Condition (self, or the new Condition created)
|
291
342
|
def or(other=nil, &proc)
|
292
343
|
return conj(:or, other, &proc)
|
293
344
|
end
|
294
345
|
alias :| :or
|
295
346
|
alias :OR :or
|
296
347
|
|
297
|
-
# Joins the condition to another with an "and" conjunction. See #conj.
|
348
|
+
# Joins the condition to another with an "and" conjunction. See {#conj}.
|
349
|
+
# @param [Condition] other Condition to conjuct to this
|
350
|
+
# @param [Proc] proc Block to create the other condition
|
351
|
+
# @return [Condition] The resulting Condition (self, or the new Condition created)
|
298
352
|
def and(other=nil, &proc)
|
299
353
|
return conj(:and, other, &proc)
|
300
354
|
end
|
@@ -304,6 +358,7 @@ module Spider; module Model
|
|
304
358
|
alias :hash_empty? :empty? # :nodoc:
|
305
359
|
|
306
360
|
# True if there are no comparisons and no subconditions.
|
361
|
+
# @return [bool] True if the Condition is empty, false otherwise
|
307
362
|
def empty?
|
308
363
|
return false unless super
|
309
364
|
@subconditions.each do |sub|
|
@@ -312,17 +367,23 @@ module Spider; module Model
|
|
312
367
|
return true
|
313
368
|
end
|
314
369
|
|
315
|
-
|
370
|
+
# Alias to the original Hash#replace
|
371
|
+
alias :hash_replace :replace
|
316
372
|
|
317
|
-
# Replace the content of this Condition with another one.
|
373
|
+
# Replace all the content of this Condition with another one.
|
374
|
+
# @param [Condition] other The other condition
|
375
|
+
# @return [self]
|
318
376
|
def replace(other)
|
319
377
|
hash_replace(other)
|
320
378
|
@subconditions = other.subconditions
|
321
379
|
@conjunction = other.conjunction
|
322
380
|
@polymorph = other.polymorph
|
323
381
|
@comparisons = other.comparisons
|
382
|
+
self
|
324
383
|
end
|
325
384
|
|
385
|
+
# @param [Condition] other
|
386
|
+
# @return [bool] True if the two conditions have the same comparisions and conjunction
|
326
387
|
def ==(other)
|
327
388
|
return false unless other.class == self.class
|
328
389
|
return false unless super
|
@@ -333,22 +394,28 @@ module Spider; module Model
|
|
333
394
|
return true
|
334
395
|
end
|
335
396
|
|
397
|
+
# @return [bool] See {#==}
|
336
398
|
def eql?(other)
|
337
399
|
self == other
|
338
400
|
end
|
339
401
|
|
402
|
+
# @return [String] Keying hash
|
340
403
|
def hash
|
341
404
|
([self.keys, self.values, @comparisons.values, @polymorph] + @subconditions.map{ |s| s.hash}).hash
|
342
405
|
end
|
343
406
|
|
344
407
|
# Removes duplicate subcondtions.
|
408
|
+
# @return self
|
345
409
|
def uniq!
|
346
410
|
@subconditions.uniq!
|
411
|
+
self
|
347
412
|
end
|
348
413
|
|
414
|
+
# Alias for Hash#clone
|
349
415
|
alias :hash_clone :clone
|
350
416
|
|
351
417
|
# Returns a deep copy.
|
418
|
+
# @return [Condition] A copy of this Condition
|
352
419
|
def clone
|
353
420
|
c = self.class.new
|
354
421
|
c.conjunction = @conjunction
|
@@ -363,6 +430,7 @@ module Spider; module Model
|
|
363
430
|
end
|
364
431
|
|
365
432
|
# Traverses the tree removing useless conditions.
|
433
|
+
# @return [self]
|
366
434
|
def simplify
|
367
435
|
@subconditions.each{ |sub| sub.simplify }
|
368
436
|
if (hash_empty? && @subconditions.length == 1)
|
@@ -372,6 +440,7 @@ module Spider; module Model
|
|
372
440
|
return self
|
373
441
|
end
|
374
442
|
|
443
|
+
# @return [Array] An array of polymorphic conditions
|
375
444
|
def polymorphs
|
376
445
|
pol = []
|
377
446
|
pol << @polymorph if @polymorph
|
@@ -379,6 +448,8 @@ module Spider; module Model
|
|
379
448
|
end
|
380
449
|
|
381
450
|
# Returns, from self and subconditions, all those who define a condition for one of the given element names.
|
451
|
+
# @param [*Symbol] element_names A list of element names
|
452
|
+
# @return [Array] An array of matching conditions
|
382
453
|
def conditions_for(*element_names)
|
383
454
|
conds = []
|
384
455
|
element_names.each do |el|
|
@@ -390,9 +461,23 @@ module Spider; module Model
|
|
390
461
|
@subconditions.map{ |s| s.conditions_for(*element_names) }.each{ |c| conds += c }
|
391
462
|
conds
|
392
463
|
end
|
464
|
+
|
465
|
+
private
|
466
|
+
|
467
|
+
# Parses a string comparison.
|
468
|
+
# TODO: remove?
|
469
|
+
def parse_comparison(comparison) # :nodoc:
|
470
|
+
if (comparison =~ Regexp.new("(.+)(#{self.class.comparison_operators_regexp})(.+)"))
|
471
|
+
val = $3.strip
|
472
|
+
# strip single and double quotes
|
473
|
+
val = val[1..-2] if ((val[0] == ?' && val[-1] == ?') || (val[0] == ?" && val[-1] == ?") )
|
474
|
+
return [$1.strip, $2.strip, val]
|
475
|
+
end
|
476
|
+
end
|
393
477
|
|
394
478
|
end
|
395
479
|
|
480
|
+
# Helper module used for Condition block syntax
|
396
481
|
module ConditionMixin # :nodoc:
|
397
482
|
|
398
483
|
def __el(meth)
|
@@ -4,15 +4,20 @@ require 'fileutils'
|
|
4
4
|
|
5
5
|
module Spider; module Model; module Mappers
|
6
6
|
|
7
|
+
# This is the Mapper subclass for interacting with databases.
|
7
8
|
class DbMapper < Spider::Model::Mapper
|
8
9
|
include Spider::Model::Storage::Db
|
9
10
|
|
11
|
+
# @param [BaseModel] model
|
12
|
+
# @param [Storage]
|
10
13
|
def initialize(model, storage)
|
11
14
|
super
|
12
15
|
@type = :db
|
13
16
|
end
|
14
17
|
|
15
|
-
|
18
|
+
# Is this mapper writable?
|
19
|
+
# @return [true]
|
20
|
+
def self.write?
|
16
21
|
true
|
17
22
|
end
|
18
23
|
|
@@ -797,7 +802,10 @@ module Spider; module Model; module Mappers
|
|
797
802
|
# * joins
|
798
803
|
# * final model called
|
799
804
|
# * final element called
|
800
|
-
|
805
|
+
# @param [String] dotted_element: the element to get joins for
|
806
|
+
# @param [Symbol] join_type (nil, :inner, :left, :right, :outer): force a join type for all elements
|
807
|
+
# @return [Array] [joins, final_model, final_element]
|
808
|
+
def get_deep_join(dotted_element, join_type=nil)
|
801
809
|
#return [[], @model, @model.elements[dotted_element]] unless dotted_element.is_a?(String)
|
802
810
|
parts = dotted_element.to_s.split('.').map{ |el| el.to_sym }
|
803
811
|
current_model = @model
|
@@ -811,17 +819,17 @@ module Spider; module Model; module Mappers
|
|
811
819
|
raise "Can't find element #{part} in model #{current_model}" unless el
|
812
820
|
next if have_references?(el) && cnt == parts.length
|
813
821
|
if el.integrated?
|
814
|
-
joins << current_model.mapper.get_join(el.integrated_from)
|
822
|
+
joins << current_model.mapper.get_join(el.integrated_from, join_type)
|
815
823
|
current_model = el.integrated_from.type
|
816
824
|
el = current_model.elements[el.integrated_from_element]
|
817
825
|
end
|
818
826
|
if el.model? && can_join?(el)
|
819
|
-
joins << current_model.mapper.get_join(el)
|
827
|
+
joins << current_model.mapper.get_join(el, join_type)
|
820
828
|
current_model = el.model
|
821
829
|
end
|
822
830
|
end
|
823
831
|
while el.integrated? && !have_references?(el)
|
824
|
-
joins << current_model.mapper.get_join(el.integrated_from)
|
832
|
+
joins << current_model.mapper.get_join(el.integrated_from, join_type)
|
825
833
|
# joins << current_model.integrated_from.mapper.get_join(el.integrated_from_element)
|
826
834
|
current_model = el.integrated_from.type
|
827
835
|
el = current_model.elements[el.integrated_from_element]
|
@@ -871,7 +879,7 @@ module Spider; module Model; module Mappers
|
|
871
879
|
joins += field.joins
|
872
880
|
fields << [field, direction]
|
873
881
|
else
|
874
|
-
el_joins, el_model, el = get_deep_join(order_element)
|
882
|
+
el_joins, el_model, el = get_deep_join(order_element, :left)
|
875
883
|
if el.model?
|
876
884
|
if el_model.mapper.have_references?(el) || el.model.storage != storage
|
877
885
|
el.model.primary_keys.each do |pk|
|