safrano 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,6 +2,15 @@
2
2
 
3
3
  # our main namespace
4
4
  module OData
5
+ # frozen empty Array/Hash to reduce unncecessary object creation
6
+ EMPTY_ARRAY = [].freeze
7
+ EMPTY_HASH = {}.freeze
8
+ EMPTY_HASH_IN_ARY = [EMPTY_HASH].freeze
9
+ EMPTY_STRING = ''.freeze
10
+ ARY_204_EMPTY_HASH_ARY = [204, EMPTY_HASH, EMPTY_ARRAY].freeze
11
+ SPACE = ' '.freeze
12
+ COMMA = ','.freeze
13
+
5
14
  # some prominent constants... probably already defined elsewhere eg in Rack
6
15
  # but lets KISS
7
16
  CONTENT_TYPE = 'Content-Type'.freeze
@@ -32,7 +41,7 @@ module OData
32
41
  # database-specific types.
33
42
  DB_TYPE_STRING_RGX = /\ACHAR\s*\(\d+\)\z/.freeze
34
43
 
35
- # TODO... complete; used in $metadata
44
+ # TODO... complete; used in $metadata
36
45
  def self.get_edm_type(db_type:)
37
46
  case db_type.upcase
38
47
  when 'INTEGER'
@@ -6,6 +6,9 @@ require 'webrick/httpstatus'
6
6
 
7
7
  # Simple multipart support for OData $batch purpose
8
8
  module MIME
9
+ CTT_TYPE_LC = 'content-type'.freeze
10
+ TEXT_PLAIN = 'text/plain'.freeze
11
+
9
12
  # a mime object has a header(with content-type etc) and a content(aka body)
10
13
  class Media
11
14
  # Parser for MIME::Media
@@ -56,7 +59,7 @@ module MIME
56
59
 
57
60
  # elsif CRLF_LINE_RGX =~ line
58
61
  elsif CRLF == line
59
- @target_ct = @target_hd['content-type'] || 'text/plain'
62
+ @target_ct = @target_hd[CTT_TYPE_LC] || TEXT_PLAIN
60
63
  @state = new_content
61
64
 
62
65
  end
@@ -100,8 +103,8 @@ module MIME
100
103
  end
101
104
 
102
105
  def hook_multipart(content_type, boundary)
103
- @target_hd['content-type'] = content_type
104
- @target_ct = @target_hd['content-type']
106
+ @target_hd[CTT_TYPE_LC] = content_type
107
+ @target_ct = @target_hd[CTT_TYPE_LC]
105
108
  @target = multipart_content(boundary)
106
109
  @target.hd = @target_hd
107
110
  @target.ct = @target_ct
@@ -114,10 +117,8 @@ module MIME
114
117
  APP_HTTP = 'application/http'.freeze
115
118
  def new_content
116
119
  @target =
117
- if @target_ct.start_with?(MPS) and
118
- (md = ((MP_RGX1.match(@target_ct[10..-1])) ||
119
- (MP_RGX2.match(@target_ct[10..-1])))
120
- )
120
+ if @target_ct.start_with?(MPS) &&
121
+ (md = (MP_RGX1.match(@target_ct[10..-1]) || MP_RGX2.match(@target_ct[10..-1])))
121
122
  multipart_content(md[2].strip)
122
123
  elsif @target_ct.start_with?(APP_HTTP)
123
124
  MIME::Content::Application::Http.new
@@ -243,8 +244,8 @@ module MIME
243
244
  @hd = {}
244
245
  @content = ''
245
246
  # set default values. Can be overwritten by parser
246
- @hd['content-type'] = 'text/plain'
247
- @ct = 'text/plain'
247
+ @hd[CTT_TYPE_LC] = TEXT_PLAIN
248
+ @ct = TEXT_PLAIN
248
249
  @parser = Parser.new(self)
249
250
  end
250
251
 
@@ -364,7 +365,7 @@ module MIME
364
365
  end
365
366
 
366
367
  def set_multipart_header
367
- @hd['content-type'] = "#{OData::MP_MIXED}; boundary=#{@boundary}"
368
+ @hd[CTT_TYPE_LC] = "#{OData::MP_MIXED}; boundary=#{@boundary}"
368
369
  end
369
370
 
370
371
  def get_http_resp(batcha)
@@ -382,9 +383,7 @@ module MIME
382
383
  # of the changes
383
384
  batcha.db.transaction do
384
385
  begin
385
- @response.content = @content.map { |part|
386
- part.get_response(batcha)
387
- }
386
+ @response.content = @content.map { |part| part.get_response(batcha) }
388
387
  rescue Sequel::Rollback => e
389
388
  # one of the changes of the changeset has failed
390
389
  # --> provide a dummy empty response for the change-parts
@@ -413,10 +412,11 @@ module MIME
413
412
  b = ''
414
413
  unless bodyonly
415
414
  # b << OData::CONTENT_TYPE << ': ' << @hd[OData::CTT_TYPE_LC] << CRLF
416
- b << "#{OData::CONTENT_TYPE}: #{@hd[OData::CTT_TYPE_LC]}#{CRLF}"
415
+ b << "#{OData::CONTENT_TYPE}: #{@hd[CTT_TYPE_LC]}#{CRLF}"
417
416
  end
418
- b << "#{CRLF}--#{@boundary}#{CRLF}"
419
- b << @content.map(&:unparse).join("#{CRLF}--#{@boundary}#{CRLF}")
417
+
418
+ b << crbdcr = "#{CRLF}--#{@boundary}#{CRLF}"
419
+ b << @content.map(&:unparse).join(crbdcr)
420
420
  b << "#{CRLF}--#{@boundary}--#{CRLF}"
421
421
  b
422
422
  end
@@ -14,7 +14,7 @@ module OData
14
14
  x = if @walker.status == :end
15
15
  headers.delete('Content-Type')
16
16
  @response.headers.delete('Content-Type')
17
- [200, {}, '']
17
+ [200, EMPTY_HASH, '']
18
18
  else
19
19
  odata_error
20
20
  end
@@ -70,7 +70,7 @@ module OData
70
70
  end
71
71
 
72
72
  def odata_head
73
- [200, {}, ['']]
73
+ [200, EMPTY_HASH, [EMPTY_STRING]]
74
74
  end
75
75
  end
76
76
 
@@ -119,7 +119,7 @@ module OData
119
119
 
120
120
  def dispatch
121
121
  req_ret = if @request.request_method !~ METHODS_REGEXP
122
- [404, {}, ['Did you get lost?']]
122
+ [404, EMPTY_HASH, ['Did you get lost?']]
123
123
  elsif @request.request_method == 'HEAD'
124
124
  odata_head
125
125
  else
@@ -134,14 +134,14 @@ module OData
134
134
 
135
135
  def with_media_data
136
136
  if (filename = @env['HTTP_SLUG'])
137
-
138
- yield @env['rack.input'],
137
+
138
+ yield @env['rack.input'],
139
139
  content_type.split(';').first,
140
140
  Rfc2047.decode(filename)
141
141
 
142
142
  else
143
143
  ON_CGST_ERROR.call(self)
144
- return [400, {}, ['File upload error: Missing SLUG']]
144
+ [400, EMPTY_HASH, ['File upload error: Missing SLUG']]
145
145
  end
146
146
  end
147
147
 
@@ -152,15 +152,15 @@ module OData
152
152
  data = JSON.parse(body.read)
153
153
  rescue JSON::ParserError => e
154
154
  ON_CGST_ERROR.call(self)
155
- return [400, {}, ['JSON Parser Error while parsing payload : ',
156
- e.message]]
155
+ return [400, EMPTY_HASH, ['JSON Parser Error while parsing payload : ',
156
+ e.message]]
157
157
  end
158
158
 
159
159
  yield data
160
160
 
161
161
  else # TODO: other formats
162
162
 
163
- [415, {}, []]
163
+ [415, EMPTY_HASH, EMPTY_ARRAY]
164
164
  end
165
165
  end
166
166
 
@@ -34,7 +34,7 @@ module OData
34
34
 
35
35
  if drop_body?
36
36
  close
37
- result = []
37
+ result = EMPTY_ARRAY
38
38
  end
39
39
 
40
40
  if calculate_content_length?
@@ -21,20 +21,22 @@ module OData
21
21
  # TODO: check errorhandling
22
22
  raise OData::ServerError if cur_exp.nil?
23
23
 
24
- k = cur_exp.to_sym
24
+ k_s = cur_exp
25
+
25
26
  else
26
- k = exp_one.strip.to_sym
27
+ k_s = exp_one.strip
27
28
  rest_exp = nil
28
29
  end
29
- yield k, rest_exp
30
+ k = k_s.to_sym
31
+ yield k, k_s, rest_exp
30
32
  end
31
33
 
32
34
  # default v2
33
35
  # overriden in ServiceV1
34
- def get_coll_odata_h(array:, expand: nil, uribase:, icount: nil)
36
+ def get_coll_odata_h(array:, template:, uribase:, icount: nil)
35
37
  res = array.map do |w|
36
38
  get_entity_odata_h(entity: w,
37
- expand: expand,
39
+ template: template,
38
40
  uribase: uribase)
39
41
  end
40
42
  if icount
@@ -44,107 +46,55 @@ module OData
44
46
  end
45
47
  end
46
48
 
47
- # for expand 1..n nav attributes
48
- # actually same as v1 get_coll_odata_h
49
- # def get_expandcoll_odata_h(array:, expand: nil, uribase:, icount: nil)
50
- # array.map do |w|
51
- # get_entity_odata_h(entity: w,
52
- # expand: expand,
53
- # uribase: uribase)
54
- # end
55
- # end
56
-
57
- # handle a single expand
58
- def handle_entity_expand_one(entity:, exp_one:, nav_values_h:, nav_coll_h:,
59
- uribase:)
60
-
61
-
62
- split_entity_expand_arg(exp_one) do |first, rest_exp|
63
- if ( entity.nav_values.has_key?(first) )
64
- if (enval = entity.nav_values[first])
65
- nav_values_h[first.to_s] = get_entity_odata_h(entity: enval,
66
- expand: rest_exp,
67
- uribase: uribase)
68
- else
69
- # FK is NULL --> nav_value is nil --> return empty json
70
- nav_values_h[first.to_s] = {}
71
- end
72
- elsif (encoll = entity.nav_coll[first])
73
- # nav attributes that are a collection (x..n)
74
- nav_coll_h[first.to_s] = get_coll_odata_h(array: encoll,
75
- expand: rest_exp,
76
- uribase: uribase)
77
- # nav_coll_h[first.to_s] = get_expandcoll_odata_h(array: encoll,
78
- # expand: rest_exp,
79
- # uribase: uribase)
80
-
81
-
82
- end
83
- end
84
- end
85
-
86
- def handle_entity_expand(entity:, expand:, nav_values_h:,
87
- nav_coll_h:, uribase:)
88
- expand.strip!
89
- explist = expand.split(',')
90
- # handle multiple expands
91
- explist.each do |exp|
92
- handle_entity_expand_one(entity: entity,
93
- exp_one: exp,
94
- nav_values_h: nav_values_h,
95
- nav_coll_h: nav_coll_h,
96
- uribase: uribase)
97
- end
98
- end
99
-
100
- def handle_entity_deferred_attribs(entity:, nav_values_h:,
101
- nav_coll_h:, uribase:)
102
- entity.nav_values.each_key do |ksy|
103
- ks = ksy.to_s
104
- next if nav_values_h.key?(ks)
105
-
106
- nav_values_h[ks] = get_deferred_odata_h(entity: entity,
107
- attrib: ks, uribase: uribase)
108
- end
109
- entity.nav_coll.each_key do |ksy|
110
- ks = ksy.to_s
111
- next if nav_coll_h.key?(ks)
112
-
113
- nav_coll_h[ks] = get_deferred_odata_h(entity: entity, attrib: ks,
114
- uribase: uribase)
115
- end
116
- end
117
-
118
49
  # handle $links ... Note: $expand seems to be ignored when $links
119
50
  # are requested
120
51
  def get_entity_odata_link_h(entity:, uribase:)
121
52
  { uri: entity.uri(uribase) }
122
53
  end
123
54
 
124
- def get_entity_odata_h(entity:, expand: nil, uribase:)
125
- hres = entity.casted_values
126
- hres['__metadata'] = entity.metadata_h(uribase: uribase)
127
-
128
- nav_values_h = {}
129
- nav_coll_h = {}
55
+ EMPTYH = {}.freeze
56
+ def get_entity_odata_h(entity:, template:, uribase:)
57
+ # start with metadata
58
+ hres = { '__metadata' => entity.metadata_h(uribase: uribase) }
130
59
 
131
- # handle expanded nav attributes
132
- unless expand.nil?
133
- handle_entity_expand(entity: entity, expand: expand,
134
- nav_values_h: nav_values_h,
135
- nav_coll_h: nav_coll_h,
136
- uribase: uribase)
137
- end
60
+ template.each do |elmt, arg|
61
+ case elmt
62
+ when :all_values
63
+ hres.merge! entity.casted_values
64
+ when :selected_vals
65
+ hres.merge! entity.casted_values(arg)
66
+ when :expand_e
138
67
 
139
- # handle not expanded (deferred) nav attributes
140
- handle_entity_deferred_attribs(entity: entity,
141
- nav_values_h: nav_values_h,
142
- nav_coll_h: nav_coll_h,
143
- uribase: uribase)
144
- # merge ...
145
- hres.merge!(nav_values_h)
146
- hres.merge!(nav_coll_h)
68
+ arg.each do |attr, templ|
69
+ enval = entity.send(attr)
70
+ hres[attr] = if enval
147
71
 
72
+ get_entity_odata_h(entity: enval,
73
+ template: templ,
74
+ uribase: uribase)
75
+ else
76
+ # FK is NULL --> nav_value is nil --> return empty json
77
+ EMPTYH
78
+ end
79
+ end
80
+ when :expand_c
81
+ arg.each do |attr, templ|
82
+ next unless (encoll = entity.send(attr))
83
+
84
+ # nav attributes that are a collection (x..n)
85
+ hres[attr] = get_coll_odata_h(array: encoll,
86
+ template: templ,
87
+ uribase: uribase)
88
+ # else error ?
89
+ end
90
+ when :deferr
91
+ arg.each do |attr|
92
+ hres[attr] = get_deferred_odata_h(entity: entity,
93
+ attrib: attr,
94
+ uribase: uribase)
95
+ end
96
+ end
97
+ end
148
98
  hres
149
99
  end
150
100
  end
@@ -219,7 +169,7 @@ module OData
219
169
 
220
170
  DATASERVICEVERSION_RGX = /\A([1234])(?:\.0);*\w*\z/.freeze
221
171
  TRAILING_SLASH = %r{/\z}.freeze
222
- DEFAULT_PATH_PREFIX = '/'
172
+ DEFAULT_PATH_PREFIX = '/'.freeze
223
173
 
224
174
  # input is the DataServiceVersion request header string, eg.
225
175
  # '2.0;blabla' ---> Version -> 2
@@ -279,23 +229,20 @@ module OData
279
229
 
280
230
  def register_model(modelklass, entity_set_name = nil, is_media = false)
281
231
  # check that the provided klass is a Sequel Model
282
- unless modelklass.is_a? Sequel::Model::ClassMethods
283
- raise OData::API::ModelNameError, modelklass
284
- end
232
+
233
+ raise(OData::API::ModelNameError, modelklass) unless modelklass.is_a? Sequel::Model::ClassMethods
285
234
 
286
235
  if modelklass.ancestors.include? OData::Entity
287
236
  # modules were already added previously;
288
237
  # cleanup state to avoid having data from previous calls
289
238
  # mostly usefull for testing (eg API)
290
239
  modelklass.reset
291
- else # first API call... (normal non-testing case)
292
- if modelklass.primary_key.is_a?(Array)
293
- modelklass.extend OData::EntityClassMultiPK
294
- modelklass.include OData::EntityMultiPK
295
- else
296
- modelklass.extend OData::EntityClassSinglePK
297
- modelklass.include OData::EntitySinglePK
298
- end
240
+ elsif modelklass.primary_key.is_a?(Array) # first API call... (normal non-testing case)
241
+ modelklass.extend OData::EntityClassMultiPK
242
+ modelklass.include OData::EntityMultiPK
243
+ else
244
+ modelklass.extend OData::EntityClassSinglePK
245
+ modelklass.include OData::EntitySinglePK
299
246
  end
300
247
  # Media/Non-media
301
248
  if is_media
@@ -345,9 +292,7 @@ module OData
345
292
  # example: CrewMember must be matched before Crew otherwise we get error
346
293
  def set_collections_sorted(coll_data)
347
294
  @collections = coll_data
348
- if @collections
349
- @collections.sort_by! { |klass| klass.entity_set_name.size }.reverse!
350
- end
295
+ @collections.sort_by! { |klass| klass.entity_set_name.size }.reverse! if @collections
351
296
  @collections
352
297
  end
353
298
 
@@ -369,9 +314,9 @@ module OData
369
314
  path_prefix(DEFAULT_PATH_PREFIX) unless @xpath_prefix
370
315
 
371
316
  @collections.each(&:finalize_publishing)
372
-
373
- #finalize the media handlers
374
- @collections.each{|klass| }
317
+
318
+ # finalize the media handlers
319
+ @collections.each { |klass| }
375
320
  end
376
321
 
377
322
  def execute_deferred_iblocks
@@ -568,16 +513,16 @@ module OData
568
513
  end
569
514
  end
570
515
 
571
- def get_coll_odata_h(array:, expand: nil, uribase:, icount: nil)
516
+ def get_coll_odata_h(array:, template:, uribase:, icount: nil)
572
517
  array.map do |w|
573
518
  get_entity_odata_h(entity: w,
574
- expand: expand,
519
+ template: template,
575
520
  uribase: uribase)
576
521
  end
577
522
  end
578
523
 
579
524
  def get_emptycoll_odata_h
580
- [{}]
525
+ EMPTY_HASH_IN_ARY
581
526
  end
582
527
  end
583
528
 
@@ -599,7 +544,7 @@ module OData
599
544
  end
600
545
 
601
546
  def get_emptycoll_odata_h
602
- { 'results' => [{}] }
547
+ { 'results' => EMPTY_HASH_IN_ARY }
603
548
  end
604
549
  end
605
550