safrano 0.4.1 → 0.4.2

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