safrano 0.3.3 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/odata/attribute.rb +9 -8
- data/lib/odata/batch.rb +8 -8
- data/lib/odata/collection.rb +239 -92
- data/lib/odata/collection_filter.rb +40 -9
- data/lib/odata/collection_media.rb +159 -28
- data/lib/odata/collection_order.rb +46 -36
- data/lib/odata/common_logger.rb +37 -12
- data/lib/odata/entity.rb +188 -99
- data/lib/odata/error.rb +60 -12
- data/lib/odata/expand.rb +123 -0
- data/lib/odata/filter/base.rb +66 -0
- data/lib/odata/filter/error.rb +33 -0
- data/lib/odata/filter/parse.rb +6 -12
- data/lib/odata/filter/sequel.rb +42 -29
- data/lib/odata/filter/sequel_function_adapter.rb +147 -0
- data/lib/odata/filter/token.rb +5 -1
- data/lib/odata/filter/tree.rb +45 -29
- data/lib/odata/navigation_attribute.rb +60 -27
- data/lib/odata/relations.rb +2 -2
- data/lib/odata/select.rb +42 -0
- data/lib/odata/url_parameters.rb +51 -36
- data/lib/odata/walker.rb +6 -6
- data/lib/safrano.rb +23 -13
- data/lib/{safrano_core.rb → safrano/core.rb} +12 -4
- data/lib/{multipart.rb → safrano/multipart.rb} +17 -26
- data/lib/{odata_rack_builder.rb → safrano/odata_rack_builder.rb} +0 -1
- data/lib/{rack_app.rb → safrano/rack_app.rb} +12 -10
- data/lib/{request.rb → safrano/request.rb} +8 -14
- data/lib/{response.rb → safrano/response.rb} +1 -2
- data/lib/{sequel_join_by_paths.rb → safrano/sequel_join_by_paths.rb} +1 -1
- data/lib/{service.rb → safrano/service.rb} +162 -131
- data/lib/safrano/version.rb +3 -0
- data/lib/sequel/plugins/join_by_paths.rb +11 -10
- metadata +33 -16
- data/lib/version.rb +0 -4
@@ -1,6 +1,5 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
1
|
require 'rack'
|
2
|
+
require 'rfc2047'
|
4
3
|
|
5
4
|
module OData
|
6
5
|
# monkey patch deactivate Rack/multipart because it does not work on simple
|
@@ -109,13 +108,6 @@ module OData
|
|
109
108
|
end
|
110
109
|
end
|
111
110
|
|
112
|
-
def uribase
|
113
|
-
return @uribase if @uribase
|
114
|
-
|
115
|
-
@uribase =
|
116
|
-
"#{env['rack.url_scheme']}://#{env['HTTP_HOST']}#{service.xpath_prefix}"
|
117
|
-
end
|
118
|
-
|
119
111
|
def accept?(type)
|
120
112
|
preferred_type(type).to_s.include?(type)
|
121
113
|
end
|
@@ -136,11 +128,13 @@ module OData
|
|
136
128
|
def with_media_data
|
137
129
|
if (filename = @env['HTTP_SLUG'])
|
138
130
|
|
139
|
-
yield @env['rack.input'],
|
131
|
+
yield @env['rack.input'],
|
132
|
+
content_type.split(';').first,
|
133
|
+
Rfc2047.decode(filename)
|
140
134
|
|
141
135
|
else
|
142
136
|
ON_CGST_ERROR.call(self)
|
143
|
-
|
137
|
+
[400, EMPTY_HASH, ['File upload error: Missing SLUG']]
|
144
138
|
end
|
145
139
|
end
|
146
140
|
|
@@ -151,15 +145,15 @@ module OData
|
|
151
145
|
data = JSON.parse(body.read)
|
152
146
|
rescue JSON::ParserError => e
|
153
147
|
ON_CGST_ERROR.call(self)
|
154
|
-
return [400,
|
155
|
-
|
148
|
+
return [400, EMPTY_HASH, ['JSON Parser Error while parsing payload : ',
|
149
|
+
e.message]]
|
156
150
|
end
|
157
151
|
|
158
152
|
yield data
|
159
153
|
|
160
154
|
else # TODO: other formats
|
161
155
|
|
162
|
-
[415,
|
156
|
+
[415, EMPTY_HASH, EMPTY_ARRAY]
|
163
157
|
end
|
164
158
|
end
|
165
159
|
|
@@ -1,4 +1,3 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
1
|
require 'rack'
|
3
2
|
|
4
3
|
# monkey patch deactivate Rack/multipart because it does not work on simple
|
@@ -35,7 +34,7 @@ module OData
|
|
35
34
|
|
36
35
|
if drop_body?
|
37
36
|
close
|
38
|
-
result =
|
37
|
+
result = EMPTY_ARRAY
|
39
38
|
end
|
40
39
|
|
41
40
|
if calculate_content_length?
|
@@ -1,17 +1,19 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
1
|
require 'rexml/document'
|
4
2
|
require 'odata/relations.rb'
|
5
3
|
require 'odata/batch.rb'
|
6
4
|
require 'odata/error.rb'
|
5
|
+
require 'odata/filter/sequel.rb'
|
7
6
|
|
8
7
|
module OData
|
9
8
|
# this module has all methods related to expand/defered output preparation
|
10
9
|
# and will be included in Service class
|
11
10
|
module ExpandHandler
|
12
11
|
PATH_SPLITTER = %r{\A(\w+)\/?(.*)\z}.freeze
|
13
|
-
|
14
|
-
|
12
|
+
DEFERRED = '__deferred'.freeze
|
13
|
+
URI = 'uri'.freeze
|
14
|
+
|
15
|
+
def get_deferred_odata_h(entity_uri:, attrib:)
|
16
|
+
{ DEFERRED => { URI => "#{entity_uri}/#{attrib}" } }
|
15
17
|
end
|
16
18
|
|
17
19
|
# split expand argument into first and rest part
|
@@ -23,109 +25,75 @@ module OData
|
|
23
25
|
# TODO: check errorhandling
|
24
26
|
raise OData::ServerError if cur_exp.nil?
|
25
27
|
|
26
|
-
|
28
|
+
k_s = cur_exp
|
29
|
+
|
27
30
|
else
|
28
|
-
|
31
|
+
k_s = exp_one.strip
|
29
32
|
rest_exp = nil
|
30
33
|
end
|
31
|
-
|
34
|
+
k = k_s.to_sym
|
35
|
+
yield k, k_s, rest_exp
|
32
36
|
end
|
33
37
|
|
34
38
|
# default v2
|
35
39
|
# overriden in ServiceV1
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
40
|
+
RESULTS_K = 'results'.freeze
|
41
|
+
COUNT_K = '__count'.freeze
|
42
|
+
def get_coll_odata_h(array:, template:, icount: nil)
|
43
|
+
array.map! do |w|
|
44
|
+
get_entity_odata_h(entity: w, template: template)
|
41
45
|
end
|
42
46
|
if icount
|
43
|
-
{
|
47
|
+
{ RESULTS_K => array, COUNT_K => icount }
|
44
48
|
else
|
45
|
-
{
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# handle a single expand
|
50
|
-
def handle_entity_expand_one(entity:, exp_one:, nav_values_h:, nav_coll_h:,
|
51
|
-
uribase:)
|
52
|
-
|
53
|
-
split_entity_expand_arg(exp_one) do |first, rest_exp|
|
54
|
-
if (enval = entity.nav_values[first])
|
55
|
-
nav_values_h[first.to_s] = get_entity_odata_h(entity: enval,
|
56
|
-
expand: rest_exp,
|
57
|
-
uribase: uribase)
|
58
|
-
elsif (encoll = entity.nav_coll[first])
|
59
|
-
# nav attributes that are a collection (x..n)
|
60
|
-
nav_coll_h[first.to_s] = get_coll_odata_h(array: encoll,
|
61
|
-
expand: rest_exp,
|
62
|
-
uribase: uribase)
|
63
|
-
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def handle_entity_expand(entity:, expand:, nav_values_h:,
|
69
|
-
nav_coll_h:, uribase:)
|
70
|
-
expand.strip!
|
71
|
-
explist = expand.split(',')
|
72
|
-
# handle multiple expands
|
73
|
-
explist.each do |exp|
|
74
|
-
handle_entity_expand_one(entity: entity, exp_one: exp,
|
75
|
-
nav_values_h: nav_values_h,
|
76
|
-
nav_coll_h: nav_coll_h,
|
77
|
-
uribase: uribase)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def handle_entity_deferred_attribs(entity:, nav_values_h:,
|
82
|
-
nav_coll_h:, uribase:)
|
83
|
-
entity.nav_values.each_key do |ksy|
|
84
|
-
ks = ksy.to_s
|
85
|
-
next if nav_values_h.key?(ks)
|
86
|
-
|
87
|
-
nav_values_h[ks] = get_deferred_odata_h(entity: entity,
|
88
|
-
attrib: ks, uribase: uribase)
|
89
|
-
end
|
90
|
-
entity.nav_coll.each_key do |ksy|
|
91
|
-
ks = ksy.to_s
|
92
|
-
next if nav_coll_h.key?(ks)
|
93
|
-
|
94
|
-
nav_coll_h[ks] = get_deferred_odata_h(entity: entity, attrib: ks,
|
95
|
-
uribase: uribase)
|
49
|
+
{ RESULTS_K => array }
|
96
50
|
end
|
97
51
|
end
|
98
52
|
|
99
53
|
# handle $links ... Note: $expand seems to be ignored when $links
|
100
54
|
# are requested
|
101
|
-
def get_entity_odata_link_h(entity
|
102
|
-
{ uri: entity.uri
|
103
|
-
end
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
55
|
+
def get_entity_odata_link_h(entity:)
|
56
|
+
{ uri: entity.uri }
|
57
|
+
end
|
58
|
+
|
59
|
+
EMPTYH = {}.freeze
|
60
|
+
METADATA_K = '__metadata'.freeze
|
61
|
+
def get_entity_odata_h(entity:, template:)
|
62
|
+
# start with metadata
|
63
|
+
hres = { METADATA_K => entity.metadata_h }
|
64
|
+
|
65
|
+
template.each do |elmt, arg|
|
66
|
+
case elmt
|
67
|
+
when :all_values
|
68
|
+
hres.merge! entity.casted_values
|
69
|
+
when :selected_vals
|
70
|
+
hres.merge! entity.casted_values(arg)
|
71
|
+
when :expand_e
|
72
|
+
|
73
|
+
arg.each do |attr, templ|
|
74
|
+
enval = entity.send(attr)
|
75
|
+
hres[attr] = if enval
|
76
|
+
get_entity_odata_h(entity: enval, template: templ)
|
77
|
+
else
|
78
|
+
# FK is NULL --> nav_value is nil --> return empty json
|
79
|
+
EMPTYH
|
80
|
+
end
|
81
|
+
end
|
82
|
+
when :expand_c
|
83
|
+
arg.each do |attr, templ|
|
84
|
+
next unless (encoll = entity.send(attr))
|
111
85
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
86
|
+
# nav attributes that are a collection (x..n)
|
87
|
+
hres[attr] = get_coll_odata_h(array: encoll, template: templ)
|
88
|
+
# else error ?
|
89
|
+
end
|
90
|
+
when :deferr
|
91
|
+
euri = entity.uri
|
92
|
+
arg.each do |attr|
|
93
|
+
hres[attr] = get_deferred_odata_h(entity_uri: euri, attrib: attr)
|
94
|
+
end
|
95
|
+
end
|
118
96
|
end
|
119
|
-
|
120
|
-
# handle not expanded (deferred) nav attributes
|
121
|
-
handle_entity_deferred_attribs(entity: entity,
|
122
|
-
nav_values_h: nav_values_h,
|
123
|
-
nav_coll_h: nav_coll_h,
|
124
|
-
uribase: uribase)
|
125
|
-
# merge ...
|
126
|
-
hres.merge!(nav_values_h)
|
127
|
-
hres.merge!(nav_coll_h)
|
128
|
-
|
129
97
|
hres
|
130
98
|
end
|
131
99
|
end
|
@@ -175,7 +143,8 @@ module OData
|
|
175
143
|
attr_accessor :xname
|
176
144
|
attr_accessor :xnamespace
|
177
145
|
attr_accessor :xpath_prefix
|
178
|
-
|
146
|
+
attr_accessor :xserver_url
|
147
|
+
attr_accessor :uribase
|
179
148
|
attr_accessor :meta
|
180
149
|
attr_accessor :batch_handler
|
181
150
|
attr_accessor :relman
|
@@ -200,7 +169,8 @@ module OData
|
|
200
169
|
|
201
170
|
DATASERVICEVERSION_RGX = /\A([1234])(?:\.0);*\w*\z/.freeze
|
202
171
|
TRAILING_SLASH = %r{/\z}.freeze
|
203
|
-
DEFAULT_PATH_PREFIX = '/'
|
172
|
+
DEFAULT_PATH_PREFIX = '/'.freeze
|
173
|
+
DEFAULT_SERVER_URL = 'http://localhost:9494'
|
204
174
|
|
205
175
|
# input is the DataServiceVersion request header string, eg.
|
206
176
|
# '2.0;blabla' ---> Version -> 2
|
@@ -243,40 +213,67 @@ module OData
|
|
243
213
|
(@v1.xpath_prefix = @xpath_prefix) if @v1
|
244
214
|
(@v2.xpath_prefix = @xpath_prefix) if @v2
|
245
215
|
end
|
216
|
+
|
217
|
+
def server_url(surl)
|
218
|
+
@xserver_url = surl.sub(TRAILING_SLASH, '')
|
219
|
+
(@v1.xserver_url = @xserver_url) if @v1
|
220
|
+
(@v2.xserver_url = @xserver_url) if @v2
|
221
|
+
end
|
222
|
+
|
246
223
|
# end public API
|
247
224
|
|
225
|
+
def set_uribase
|
226
|
+
@uribase = if @xpath_prefix.empty?
|
227
|
+
@xserver_url
|
228
|
+
else
|
229
|
+
if @xpath_prefix[0] == '/'
|
230
|
+
@xserver_url + @xpath_prefix
|
231
|
+
else
|
232
|
+
@xserver_url + '/' + @xpath_prefix
|
233
|
+
end
|
234
|
+
end
|
235
|
+
(@v1.uribase = @uribase) if @v1
|
236
|
+
(@v2.uribase = @uribase) if @v2
|
237
|
+
end
|
238
|
+
|
248
239
|
def copy_attribs_to(other)
|
249
240
|
other.cmap = @cmap
|
250
241
|
other.collections = @collections
|
242
|
+
other.allowed_transitions = @allowed_transitions
|
251
243
|
other.xtitle = @xtitle
|
252
244
|
other.xname = @xname
|
253
245
|
other.xnamespace = @xnamespace
|
254
246
|
other.xpath_prefix = @xpath_prefix
|
247
|
+
other.xserver_url = @xserver_url
|
248
|
+
other.uribase = @uribase
|
255
249
|
other.meta = ServiceMeta.new(other) # hum ... #todo: versions as well ?
|
256
250
|
other.relman = @relman
|
257
251
|
other.batch_handler = @batch_handler
|
258
252
|
other
|
259
253
|
end
|
260
254
|
|
255
|
+
# this is a central place. We extend Sequel models with OData functionality
|
256
|
+
# The included/extended modules depends on the properties(eg, pks, field types) of the model
|
257
|
+
# we differentiate
|
258
|
+
# * Single/Multi PK
|
259
|
+
# * Media/Non-Media entity
|
260
|
+
# Putting this logic here in modules loaded once on start shall result in less runtime overhead
|
261
261
|
def register_model(modelklass, entity_set_name = nil, is_media = false)
|
262
262
|
# check that the provided klass is a Sequel Model
|
263
|
-
|
264
|
-
|
265
|
-
end
|
263
|
+
|
264
|
+
raise(OData::API::ModelNameError, modelklass) unless modelklass.is_a? Sequel::Model::ClassMethods
|
266
265
|
|
267
266
|
if modelklass.ancestors.include? OData::Entity
|
268
267
|
# modules were already added previously;
|
269
268
|
# cleanup state to avoid having data from previous calls
|
270
269
|
# mostly usefull for testing (eg API)
|
271
270
|
modelklass.reset
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
modelklass.include OData::EntitySinglePK
|
279
|
-
end
|
271
|
+
elsif modelklass.primary_key.is_a?(Array) # first API call... (normal non-testing case)
|
272
|
+
modelklass.extend OData::EntityClassMultiPK
|
273
|
+
modelklass.include OData::EntityMultiPK
|
274
|
+
else
|
275
|
+
modelklass.extend OData::EntityClassSinglePK
|
276
|
+
modelklass.include OData::EntitySinglePK
|
280
277
|
end
|
281
278
|
# Media/Non-media
|
282
279
|
if is_media
|
@@ -326,15 +323,14 @@ module OData
|
|
326
323
|
# example: CrewMember must be matched before Crew otherwise we get error
|
327
324
|
def set_collections_sorted(coll_data)
|
328
325
|
@collections = coll_data
|
329
|
-
if @collections
|
330
|
-
@collections.sort_by! { |klass| klass.entity_set_name.size }.reverse!
|
331
|
-
end
|
326
|
+
@collections.sort_by! { |klass| klass.entity_set_name.size }.reverse! if @collections
|
332
327
|
@collections
|
333
328
|
end
|
334
329
|
|
335
330
|
# to be called at end of publishing block to ensure we get the right names
|
336
331
|
# and additionally build the list of valid attribute path's used
|
337
332
|
# for validation of $orderby or $filter params
|
333
|
+
|
338
334
|
def finalize_publishing
|
339
335
|
# build the cmap
|
340
336
|
@cmap = {}
|
@@ -348,8 +344,36 @@ module OData
|
|
348
344
|
# set default path prefix if path_prefix was not called
|
349
345
|
path_prefix(DEFAULT_PATH_PREFIX) unless @xpath_prefix
|
350
346
|
|
351
|
-
#
|
352
|
-
|
347
|
+
# set default server url if server_url was not called
|
348
|
+
server_url(DEFAULT_SERVER_URL) unless @xserver_url
|
349
|
+
|
350
|
+
set_uribase
|
351
|
+
|
352
|
+
@collections.each(&:finalize_publishing)
|
353
|
+
|
354
|
+
# finalize the uri's and include NoMappingBeforeOutput or MappingBeforeOutput as needed
|
355
|
+
@collections.each { |klass|
|
356
|
+
klass.build_uri(@uribase)
|
357
|
+
if klass.time_cols.empty?
|
358
|
+
klass.include OData::NoMappingBeforeOutput
|
359
|
+
else
|
360
|
+
klass.include OData::MappingBeforeOutput
|
361
|
+
end
|
362
|
+
}
|
363
|
+
|
364
|
+
# build allowed transitions (requires that @collections are filled and sorted for having a
|
365
|
+
# correct base_url_regexp)
|
366
|
+
build_allowed_transitions
|
367
|
+
|
368
|
+
# mixin adapter specific modules where needed
|
369
|
+
case Sequel::Model.db.adapter_scheme
|
370
|
+
when :postgres
|
371
|
+
OData::Filter::FuncTree.include OData::Filter::FuncTreePostgres
|
372
|
+
when :sqlite
|
373
|
+
OData::Filter::FuncTree.include OData::Filter::FuncTreeSqlite
|
374
|
+
else
|
375
|
+
OData::Filter::FuncTree.include OData::Filter::FuncTreeDefault
|
376
|
+
end
|
353
377
|
end
|
354
378
|
|
355
379
|
def execute_deferred_iblocks
|
@@ -374,7 +398,7 @@ module OData
|
|
374
398
|
def service_xml(req)
|
375
399
|
doc = REXML::Document.new
|
376
400
|
# separator required ? ?
|
377
|
-
root = doc.add_element('service', 'xml:base' =>
|
401
|
+
root = doc.add_element('service', 'xml:base' => @uribase)
|
378
402
|
|
379
403
|
root.add_namespace('xmlns:atom', XMLNS::W3_2005_ATOM)
|
380
404
|
root.add_namespace('xmlns:app', XMLNS::W3_2007_APP)
|
@@ -397,7 +421,7 @@ module OData
|
|
397
421
|
def add_metadata_xml_entity_type(schema)
|
398
422
|
@collections.each do |klass|
|
399
423
|
enty = klass.add_metadata_rexml(schema)
|
400
|
-
klass.add_metadata_navs_rexml(enty, @
|
424
|
+
klass.add_metadata_navs_rexml(enty, @relman, @xnamespace)
|
401
425
|
end
|
402
426
|
end
|
403
427
|
|
@@ -485,15 +509,22 @@ module OData
|
|
485
509
|
# methods related to transitions to next state (cf. walker)
|
486
510
|
module Transitions
|
487
511
|
DOLLAR_ID_REGEXP = Regexp.new('\A\/\$').freeze
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
512
|
+
ALLOWED_TRANSITIONS_FIXED = [
|
513
|
+
Safrano::TransitionEnd,
|
514
|
+
Safrano::TransitionMetadata,
|
515
|
+
Safrano::TransitionBatch,
|
516
|
+
Safrano::TransitionContentId
|
517
|
+
].freeze
|
518
|
+
|
519
|
+
def build_allowed_transitions
|
520
|
+
@allowed_transitions = (ALLOWED_TRANSITIONS_FIXED + [
|
494
521
|
Safrano::Transition.new(%r{\A/(#{base_url_regexp})(.*)},
|
495
522
|
trans: 'transition_collection')
|
496
|
-
]
|
523
|
+
]).freeze
|
524
|
+
end
|
525
|
+
|
526
|
+
def allowed_transitions
|
527
|
+
@allowed_transitions
|
497
528
|
end
|
498
529
|
|
499
530
|
def transition_collection(match_result)
|
@@ -540,22 +571,22 @@ module OData
|
|
540
571
|
@data_service_version = '1.0'
|
541
572
|
end
|
542
573
|
|
543
|
-
def get_coll_odata_links_h(array:,
|
574
|
+
def get_coll_odata_links_h(array:, icount: nil)
|
544
575
|
array.map do |w|
|
545
|
-
get_entity_odata_link_h(entity: w
|
576
|
+
get_entity_odata_link_h(entity: w)
|
546
577
|
end
|
547
578
|
end
|
548
579
|
|
549
|
-
def get_coll_odata_h(array:,
|
550
|
-
array.map do |w|
|
580
|
+
def get_coll_odata_h(array:, template:, icount: nil)
|
581
|
+
array.map! do |w|
|
551
582
|
get_entity_odata_h(entity: w,
|
552
|
-
|
553
|
-
uribase: uribase)
|
583
|
+
template: template)
|
554
584
|
end
|
585
|
+
array
|
555
586
|
end
|
556
587
|
|
557
588
|
def get_emptycoll_odata_h
|
558
|
-
|
589
|
+
EMPTY_HASH_IN_ARY
|
559
590
|
end
|
560
591
|
end
|
561
592
|
|
@@ -565,19 +596,19 @@ module OData
|
|
565
596
|
@data_service_version = '2.0'
|
566
597
|
end
|
567
598
|
|
568
|
-
def get_coll_odata_links_h(array:,
|
599
|
+
def get_coll_odata_links_h(array:, icount: nil)
|
569
600
|
res = array.map do |w|
|
570
|
-
get_entity_odata_link_h(entity: w
|
601
|
+
get_entity_odata_link_h(entity: w)
|
571
602
|
end
|
572
603
|
if icount
|
573
|
-
{
|
604
|
+
{ RESULTS_K => res, COUNT_K => icount }
|
574
605
|
else
|
575
|
-
{
|
606
|
+
{ RESULTS_K => res }
|
576
607
|
end
|
577
608
|
end
|
578
609
|
|
579
610
|
def get_emptycoll_odata_h
|
580
|
-
{
|
611
|
+
{ RESULTS_K => EMPTY_HASH_IN_ARY }
|
581
612
|
end
|
582
613
|
end
|
583
614
|
|
@@ -588,9 +619,9 @@ module OData
|
|
588
619
|
@service = service
|
589
620
|
end
|
590
621
|
|
622
|
+
ALLOWED_TRANSITIONS_FIXED = [Safrano::TransitionEnd].freeze
|
591
623
|
def allowed_transitions
|
592
|
-
|
593
|
-
trans: 'transition_end')]
|
624
|
+
ALLOWED_TRANSITIONS_FIXED
|
594
625
|
end
|
595
626
|
|
596
627
|
def transition_end(_match_result)
|