safrano 0.5.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/lib/core_ext/Date/format.rb +47 -0
  3. data/lib/core_ext/DateTime/format.rb +54 -0
  4. data/lib/core_ext/Dir/iter.rb +7 -5
  5. data/lib/core_ext/Hash/transform.rb +14 -6
  6. data/lib/core_ext/Numeric/convert.rb +25 -0
  7. data/lib/core_ext/Time/format.rb +71 -0
  8. data/lib/core_ext/date.rb +5 -0
  9. data/lib/core_ext/datetime.rb +5 -0
  10. data/lib/core_ext/numeric.rb +3 -0
  11. data/lib/core_ext/time.rb +5 -0
  12. data/lib/odata/attribute.rb +8 -6
  13. data/lib/odata/batch.rb +3 -3
  14. data/lib/odata/collection.rb +9 -9
  15. data/lib/odata/collection_filter.rb +3 -1
  16. data/lib/odata/collection_media.rb +4 -27
  17. data/lib/odata/collection_order.rb +1 -1
  18. data/lib/odata/common_logger.rb +5 -27
  19. data/lib/odata/complex_type.rb +61 -67
  20. data/lib/odata/edm/primitive_types.rb +110 -42
  21. data/lib/odata/entity.rb +14 -47
  22. data/lib/odata/error.rb +7 -7
  23. data/lib/odata/expand.rb +2 -2
  24. data/lib/odata/filter/base.rb +10 -1
  25. data/lib/odata/filter/error.rb +2 -2
  26. data/lib/odata/filter/parse.rb +16 -2
  27. data/lib/odata/filter/sequel.rb +31 -4
  28. data/lib/odata/filter/sequel_datetime_adapter.rb +21 -0
  29. data/lib/odata/filter/token.rb +18 -5
  30. data/lib/odata/filter/tree.rb +83 -9
  31. data/lib/odata/function_import.rb +19 -18
  32. data/lib/odata/model_ext.rb +96 -38
  33. data/lib/odata/request/json.rb +171 -0
  34. data/lib/odata/transition.rb +13 -9
  35. data/lib/odata/url_parameters.rb +3 -3
  36. data/lib/odata/walker.rb +9 -9
  37. data/lib/safrano/multipart.rb +1 -3
  38. data/lib/safrano/rack_app.rb +2 -14
  39. data/lib/safrano/rack_builder.rb +0 -15
  40. data/lib/safrano/request.rb +3 -3
  41. data/lib/safrano/response.rb +3 -3
  42. data/lib/safrano/service.rb +43 -12
  43. data/lib/safrano/type_mapping.rb +149 -0
  44. data/lib/safrano/version.rb +1 -2
  45. data/lib/safrano.rb +3 -0
  46. metadata +54 -15
@@ -12,153 +12,148 @@ module Safrano
12
12
  VALUEK = 'value'
13
13
  RESULTSK = 'results'
14
14
  COLLECTION = 'Collection'
15
-
15
+
16
16
  def allowed_transitions
17
17
  [Safrano::TransitionEnd]
18
18
  end
19
-
19
+
20
20
  def transition_end(_match_result)
21
21
  Safrano::Transition::RESULT_END
22
22
  end
23
-
23
+
24
24
  # we will have this on class and instance level for making things simpler first
25
- def self.klassmod
26
- @klassmod
25
+ class << self
26
+ attr_reader :klassmod
27
27
  end
28
-
28
+
29
29
  # return a subclass of ResultAsComplexType
30
30
  def self.asComplexType(klassmod)
31
31
  Class.new(ResultAsComplexType) do
32
32
  @klassmod = klassmod
33
33
  end
34
34
  end
35
-
35
+
36
36
  # return a subclass of ResultAsComplexType
37
37
  def self.asComplexTypeColl(klassmod)
38
38
  Class.new(ResultAsComplexTypeColl) do
39
39
  @klassmod = klassmod
40
40
  end
41
41
  end
42
-
42
+
43
43
  def self.asPrimitiveType(klassmod)
44
44
  Class.new(ResultAsPrimitiveType) do
45
45
  @klassmod = klassmod
46
46
  end
47
47
  end
48
-
48
+
49
49
  def self.asPrimitiveTypeColl(klassmod)
50
50
  Class.new(ResultAsPrimitiveTypeColl) do
51
51
  @klassmod = klassmod
52
52
  end
53
- end
54
-
53
+ end
54
+
55
55
  def self.asEntity(klassmod)
56
56
  Class.new(ResultAsEntity) do
57
57
  @klassmod = klassmod
58
58
  end
59
59
  end
60
-
60
+
61
61
  def self.asEntityColl(klassmod)
62
62
  Class.new(ResultAsEntityColl) do
63
63
  @klassmod = klassmod
64
64
  end
65
65
  end
66
-
66
+
67
67
  def initialize(value)
68
68
  @value = value
69
69
  end
70
-
70
+
71
71
  def odata_get(req)
72
72
  [200, EMPTY_HASH, [to_odata_json(req)]]
73
73
  end
74
+
74
75
  def self.type_metadata
75
76
  @klassmod.type_name
76
77
  end
78
+
77
79
  def type_metadata
78
80
  self.class.type_metadata
79
81
  end
80
-
82
+
81
83
  # needed for ComplexType result
82
84
  def to_odata_json(_req)
83
85
  "#{DJ_OPEN}#{@value.odata_h.to_json}#{DJ_CLOSE}"
84
- end
85
-
86
- # wrapper
86
+ end
87
+
88
+ # wrapper
87
89
  # for OData Entity and Collections, return them directly
88
90
  # for others, ie ComplexType, Prims etc, return the ResultDefinition-subclass wrapped result
89
- def self.do_execute_func_result(result, _req, apply_query_params=false)
90
- self.new(result)
91
+ def self.do_execute_func_result(result, _req, _apply_query_params = false)
92
+ new(result)
91
93
  end
92
-
93
94
  end
94
-
95
+
95
96
  class ResultAsComplexType < ResultDefinition
96
97
  def self.type_metadata
97
98
  @klassmod.type_name
98
99
  end
99
100
  end
100
-
101
+
101
102
  class ResultAsComplexTypeColl < ResultDefinition
102
103
  def self.type_metadata
103
104
  "Collection(#{@klassmod.type_name})"
104
105
  end
105
106
 
106
107
  def to_odata_json(req)
107
- # "#{DJ_OPEN}#{{ RESULTSK => coll.map { |c| c.odata_h } }.to_json}#{DJ_CLOSE}"
108
+ # "#{DJ_OPEN}#{{ RESULTSK => coll.map { |c| c.odata_h } }.to_json}#{DJ_CLOSE}"
108
109
  template = self.class.klassmod.output_template
109
110
  # TODO: Error handling if database contains binary BLOB data that cant be
110
111
  # interpreted as UTF-8 then JSON will fail here
111
112
 
112
113
  innerh = req.service.get_coll_odata_h(array: @value,
113
114
  template: template)
114
-
115
+
115
116
  innerj = innerh.to_json
116
117
 
117
118
  "#{DJ_OPEN}#{innerj}#{DJ_CLOSE}"
118
119
  end
119
120
  end
120
-
121
+
121
122
  class ResultAsEntity < ResultDefinition
122
-
123
123
  def self.type_metadata
124
124
  @klassmod.type_name
125
125
  end
126
126
 
127
-
128
- # wrapper
127
+ # wrapper
129
128
  # for OData Entity return them directly
130
- def self.do_execute_func_result(result, _req, apply_query_params=false)
131
- # note: Sequel entities instances seem to be thread safe, so we can
129
+ def self.do_execute_func_result(result, _req, apply_query_params = false)
130
+ # note: Sequel entities instances seem to be thread safe, so we can
132
131
  # safely add request-dependant data (eg. req.params) there
133
132
  apply_query_params ? result : result.inactive_query_params
134
133
  end
135
-
136
134
  end
137
-
135
+
138
136
  class ResultAsEntityColl < ResultDefinition
139
-
140
137
  def self.type_metadata
141
138
  "Collection(#{@klassmod.type_name})"
142
139
  end
143
-
144
- # wrapper
140
+
141
+ # wrapper
145
142
  # for OData Entity Collection return them directly
146
- def self.do_execute_func_result(result, req, apply_query_params=false)
143
+ def self.do_execute_func_result(result, req, apply_query_params = false)
147
144
  coll = Safrano::OData::Collection.new(@klassmod)
148
145
  # instance_exec has other instance variables; @values would be nil in the block below
149
146
  # need to pass a local copy
150
147
  dtset = result
151
148
  coll.instance_exec do
152
-
153
- @params = apply_query_params ? req.params : EMPTY_HASH
149
+ @params = apply_query_params ? req.params : EMPTY_HASH
154
150
  initialize_dataset(dtset)
155
151
  initialize_uparms
156
152
  end
157
153
  coll
158
154
  end
159
-
160
155
  end
161
-
156
+
162
157
  class ResultAsPrimitiveType < ResultDefinition
163
158
  def self.type_metadata
164
159
  @klassmod.type_name
@@ -169,7 +164,7 @@ module Safrano
169
164
  VALUEK => self.class.klassmod.odata_value(@value) } }.to_json
170
165
  end
171
166
  end
172
-
167
+
173
168
  class ResultAsPrimitiveTypeColl < ResultDefinition
174
169
  def self.type_metadata
175
170
  "Collection(#{@klassmod.type_name})"
@@ -179,7 +174,6 @@ module Safrano
179
174
  { D => { METAK => { TYPEK => self.class.type_metadata },
180
175
  RESULTSK => self.class.klassmod.odata_collection(@value) } }.to_json
181
176
  end
182
-
183
177
  end
184
178
  end
185
179
 
@@ -188,51 +182,51 @@ module Safrano
188
182
  # with added OData functionality
189
183
  class ComplexType
190
184
  attr_reader :values
185
+
191
186
  EMPTYH = {}.freeze
192
-
187
+
193
188
  @namespace = nil
194
- def self.namespace
195
- @namespace
189
+ class << self
190
+ attr_reader :namespace
196
191
  end
197
192
 
198
- def self.props
199
- @props
193
+ class << self
194
+ attr_reader :props
200
195
  end
201
-
196
+
202
197
  def type_name
203
198
  self.class.type_name
204
199
  end
205
-
200
+
206
201
  def metadata_h
207
202
  { type: type_name }
208
203
  end
209
-
204
+
210
205
  def casted_values
211
206
  # MVP... TODO: handle time mappings like in Entity models
212
207
  values
213
208
  end
214
-
209
+
215
210
  # needed for nested json output
216
211
  # this is a simpler version of model_ext#output_template
217
212
  def self.default_template
218
213
  template = {}
219
214
  expand_e = {}
220
-
215
+
221
216
  template[:all_values] = EMPTYH
222
- @props.each { |prop, kl|
223
- if kl.respond_to? :default_template
224
- expand_e[prop] = kl.default_template
225
- end
226
- }
217
+ @props.each do |prop, kl|
218
+ expand_e[prop] = kl.default_template if kl.respond_to? :default_template
219
+ end
227
220
  template[:expand_e] = expand_e
228
221
  template
229
222
  end
230
-
223
+
231
224
  def self.output_template
232
225
  default_template
233
226
  end
227
+
234
228
  def self.type_name
235
- @namespace ? "#{@namespace}.#{self.to_s}" : self.to_s
229
+ @namespace ? "#{@namespace}.#{self}" : to_s
236
230
  end
237
231
 
238
232
  def initialize
@@ -244,13 +238,13 @@ module Safrano
244
238
  def odata_h
245
239
  ret = { METAK => { TYPEK => self.class.type_name } }
246
240
 
247
- @values.each { |k, v|
241
+ @values.each do |k, v|
248
242
  ret[k] = if v.respond_to? :odata_h
249
243
  v.odata_h
250
244
  else
251
245
  v
252
246
  end
253
- }
247
+ end
254
248
  ret
255
249
  end
256
250
 
@@ -276,14 +270,14 @@ module Safrano
276
270
  end
277
271
  end
278
272
 
279
- def Safrano.ComplexType(**props)
273
+ def self.ComplexType(**props)
280
274
  Class.new(Safrano::ComplexType) do
281
275
  @props = props
282
- props.each { |a, klassmod|
276
+ props.each do |a, _klassmod|
283
277
  asym = a.to_sym
284
- define_method(asym) do @values[asym] end
285
- define_method("#{a}=") do |val| @values[asym] = val end
286
- }
278
+ define_method(asym) { @values[asym] }
279
+ define_method("#{a}=") { |val| @values[asym] = val }
280
+ end
287
281
  define_method :initialize do |*p, **kwvals|
288
282
  super()
289
283
  p.zip(props.keys).each { |val, a| @values[a] = val } if p
@@ -15,36 +15,108 @@ module Safrano
15
15
  # Classes specifying generic types that Sequel will convert to
16
16
  # database-specific types.
17
17
  DB_TYPE_STRING_RGX = /\ACHAR\s*\(\d+\)\z/.freeze
18
-
18
+ DB_TYPE_NUMDEC_RGX = /\A(NUMERIC|DECIMAL)\s*(\(\s*((\d+)\s*(,\s*(\d+))?)\s*\))?\s*\z/i.freeze
19
+ # thank you rubular
20
+ # Test String: DECIMAL (55,2 )
21
+ # Match groups
22
+ # 1 DECIMAL
23
+ # 2 (55,2 )
24
+ # 3 55,2
25
+ # 4 55
26
+ # 5 ,2
27
+ # 6 2
28
+
29
+ DB_TYPE_FLOATP_RGX = /\A\s*(FLOAT)\s*(\(\s*(\d+)\s*\))?\s*\z/i.freeze
30
+
31
+ # Note: "char" (quoted!) is postgresql's byte type
32
+ DB_TYPE_INTLIKE_RGX = /\A\s*(smallserial|smallint|integer|int2|int4|int8|int|mediumint|bigint|serial|bigserial|tinyint)\s*/i.freeze
19
33
  # used in $metadata
20
34
  # cf. Sequel Database column_schema_default_to_ruby_value
21
35
  # schema_column_type
22
36
  # https://www.odata.org/documentation/odata-version-2-0/overview/
23
- def self.default_edm_type(ruby_type:, db_type: )
24
- case ruby_type
25
- when :integer
26
- 'Edm.Int32'
27
- when :string
28
- 'Edm.String'
29
- when :date
30
- 'Edm.DateTime'
31
- when :datetime
32
- 'Edm.DateTime'
33
- when :time
34
- 'Edm.Time'
35
- when :boolean
36
- 'Edm.Boolean'
37
- when :float
38
- 'Edm.Double'
39
- when :decimal
40
- 'Edm.Decimal'
41
- when :blob
42
- 'Edm.Binary'
43
- else # try with db_type:
44
- if ( db_type =~ /\ANUMERIC/ )
45
- 'Edm.Decimal'
46
- end
47
- end
37
+
38
+ # type mappings are hard, especially between "Standards" like SQL and OData V2 (might be a bit better in V4 ?)
39
+ # this is all best effort/try to make it work logic
40
+ def self.add_edm_types(metadata, props)
41
+ # try num/dec with db_type:
42
+ metadata[:edm_type] = if (md = DB_TYPE_NUMDEC_RGX.match(props[:db_type]))
43
+ prec = md[4]
44
+ scale = md[6]
45
+ if scale && prec
46
+ if scale == '0' # dont force default scale to 0 like SQL standard
47
+ metadata[:edm_precision] = prec
48
+ "Edm.Decimal(#{prec})"
49
+ else
50
+ # we have precision and scale
51
+ metadata[:edm_scale] = scale
52
+ metadata[:edm_precision] = prec
53
+ "Edm.Decimal(#{prec},#{scale})"
54
+ end
55
+ elsif prec
56
+ # we have precision only
57
+ metadata[:edm_precision] = prec
58
+ "Edm.Decimal(#{prec})"
59
+ else
60
+ 'Edm.Decimal'
61
+ end
62
+ end
63
+ return if metadata[:edm_type]
64
+
65
+ # try float(prec) with db_type:
66
+ metadata[:edm_type] = if (md = DB_TYPE_FLOATP_RGX.match(props[:db_type]))
67
+ # FLOAT( 22) match groups
68
+ # 1 FLOAT
69
+ # 2 (22 )
70
+ # 3 22
71
+
72
+ if (prec = md[3])
73
+ # we have precision only
74
+ metadata[:edm_precision] = prec
75
+ 'Edm.Double'
76
+ end
77
+ end
78
+ return if metadata[:edm_type]
79
+
80
+ # try int-like with db_type:
81
+ # smallint|int|integer|bigint|serial|bigserial
82
+ metadata[:edm_type] = if (md = DB_TYPE_INTLIKE_RGX.match(props[:db_type]))
83
+
84
+ if (itype = md[1])
85
+ case itype.downcase
86
+ when 'smallint', 'int2', 'smallserial'
87
+ 'Edm.Int16'
88
+ when 'int', 'integer', 'serial', 'mediumint', 'int4'
89
+ 'Edm.Int32'
90
+ when 'bigint', 'bigserial', 'int8'
91
+ 'Edm.Int64'
92
+ when 'tinyint'
93
+ 'Edm.Byte'
94
+ end
95
+ end
96
+ end
97
+ return if metadata[:edm_type]
98
+
99
+ # try with Sequel(ruby) type
100
+ metadata[:edm_type] = case props[:type]
101
+ when :integer
102
+ 'Edm.Int32'
103
+ when :string
104
+ 'Edm.String'
105
+ when :date
106
+ 'Edm.DateTime'
107
+ when :datetime
108
+ 'Edm.DateTime'
109
+ when :time
110
+ 'Edm.Time'
111
+ when :boolean
112
+ 'Edm.Boolean'
113
+ when :float
114
+ 'Edm.Double'
115
+ when :decimal
116
+ 'Edm.Decimal'
117
+ when :blob
118
+ 'Edm.Binary'
119
+ end
48
120
  end
49
121
 
50
122
  # use Edm twice so that we can do include Safrano::Edm and then
@@ -69,12 +141,12 @@ module Safrano
69
141
  class Null < NilClass
70
142
  extend OutputClassMethods
71
143
  # nil --> null convertion is done by to_json
72
- def self.odata_value(instance)
144
+ def self.odata_value(_instance)
73
145
  nil
74
146
  end
75
147
 
76
148
  def self.convert_from_urlparam(v)
77
- return Contract::NOK unless (v == 'null')
149
+ return Contract::NOK unless v == 'null'
78
150
 
79
151
  Contract.valid(nil)
80
152
  end
@@ -94,7 +166,7 @@ module Safrano
94
166
  # or false([nil, false])
95
167
  class Boolean < Object
96
168
  extend OutputClassMethods
97
- def Boolean.odata_value(instance)
169
+ def self.odata_value(instance)
98
170
  instance ? true : false
99
171
  end
100
172
 
@@ -103,7 +175,7 @@ module Safrano
103
175
  end
104
176
 
105
177
  def self.convert_from_urlparam(v)
106
- return Contract::NOK unless ['true', 'false'].include?(v)
178
+ return Contract::NOK unless %w[true false].include?(v)
107
179
 
108
180
  Contract.valid(v == 'true')
109
181
  end
@@ -115,7 +187,7 @@ module Safrano
115
187
  extend OutputClassMethods
116
188
 
117
189
  def self.convert_from_urlparam(v)
118
- return Contract::NOK unless ((bytev = v.to_i) < 256)
190
+ return Contract::NOK unless (bytev = v.to_i) < 256
119
191
 
120
192
  Contract.valid(bytev)
121
193
  end
@@ -123,7 +195,7 @@ module Safrano
123
195
 
124
196
  class DateTime < ::DateTime
125
197
  extend OutputClassMethods
126
- def DateTime.odata_value(instance)
198
+ def self.odata_value(instance)
127
199
  instance.to_datetime
128
200
  end
129
201
 
@@ -132,11 +204,9 @@ module Safrano
132
204
  end
133
205
 
134
206
  def self.convert_from_urlparam(v)
135
- begin
136
- Contract.valid(DateTime.parse(v))
137
- rescue
138
- return convertion_error(v)
139
- end
207
+ Contract.valid(DateTime.parse(v))
208
+ rescue StandardError
209
+ convertion_error(v)
140
210
  end
141
211
  end
142
212
 
@@ -172,11 +242,9 @@ module Safrano
172
242
  extend OutputClassMethods
173
243
 
174
244
  def self.convert_from_urlparam(v)
175
- begin
176
- Contract.valid(v.to_f)
177
- rescue
178
- return Contract::NOK
179
- end
245
+ Contract.valid(v.to_f)
246
+ rescue StandardError
247
+ Contract::NOK
180
248
  end
181
249
  end
182
250
  end
data/lib/odata/entity.rb CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  require 'json'
4
4
  require 'rexml/document'
5
- require 'safrano.rb'
6
- require 'odata/model_ext.rb' # required for self.class.entity_type_name ??
5
+ require 'safrano'
6
+ require 'odata/model_ext' # required for self.class.entity_type_name ??
7
7
  require_relative 'navigation_attribute'
8
8
 
9
9
  module Safrano
@@ -86,9 +86,9 @@ module Safrano
86
86
  "#{self.class.uri}#{@odata_pk}"
87
87
  end
88
88
 
89
- D = 'd'.freeze
90
- DJ_OPEN = '{"d":'.freeze
91
- DJ_CLOSE = '}'.freeze
89
+ D = 'd'
90
+ DJ_OPEN = '{"d":'
91
+ DJ_CLOSE = '}'
92
92
 
93
93
  # Json formatter for a single entity (probably OData V1/V2 like)
94
94
  def to_odata_json(request:)
@@ -151,11 +151,12 @@ module Safrano
151
151
  @uparms.check_all.tap_valid { return odata_get_output(req) }
152
152
  .tap_error { |e| return e.odata_get(req) }
153
153
  end
154
+
154
155
  def inactive_query_params
155
156
  @inactive_query_params = true
156
157
  self # chaining
157
158
  end
158
-
159
+
159
160
  DELETE_REL_AND_ENTY = lambda do |entity, assoc, parent|
160
161
  Safrano.remove_nav_relation(assoc, parent)
161
162
  entity.destroy(transaction: false)
@@ -175,7 +176,7 @@ module Safrano
175
176
  destroy(transaction: false)
176
177
  end
177
178
  rescue StandardError => e
178
- raise SequelAdapterError.new(e)
179
+ raise SequelAdapterError, e
179
180
  end
180
181
 
181
182
  # TODO: differentiate between POST/PUT/PATCH/MERGE
@@ -202,7 +203,7 @@ module Safrano
202
203
  if req.walker.media_value
203
204
  odata_media_value_put(req)
204
205
  elsif req.accept?(APPJSON)
205
- data = JSON.parse(req.body.read)
206
+ data = Safrano::OData::JSON.parse_one(req.body.read, self.class)
206
207
  data.delete('__metadata')
207
208
 
208
209
  if req.in_changeset
@@ -219,7 +220,7 @@ module Safrano
219
220
  end
220
221
 
221
222
  def odata_patch(req)
222
- req.with_parsed_data do |data|
223
+ req.with_parsed_data(self.class) do |data|
223
224
  data.delete('__metadata')
224
225
 
225
226
  # validate payload column names
@@ -310,40 +311,6 @@ module Safrano
310
311
  end
311
312
  end
312
313
 
313
- module MappingBeforeOutput
314
- # needed for proper datetime or Decimal output
315
- def casted_values(cols = nil)
316
- vals = case cols
317
- when nil
318
- # we need to dup the model values as we need to change it before passing to_json,
319
- # but we dont want to interfere with Sequel's owned data
320
- # (eg because then in worst case it could happen that we write back changed values to DB)
321
- values_for_odata.dup
322
- else
323
- selected_values_for_odata(cols)
324
- end
325
- # TODO better design (perf/ do more during startup and less during request runtime )
326
- # TODO replace the quick and dirty BigDecimal hack with something better
327
- self.class.decimal_cols.each { |dc| vals[dc] = BigDecimal(vals[dc].to_s).to_s('F') if vals.key?(dc) }
328
-
329
- self.class.time_cols.each { |tc| vals[tc] = vals[tc]&.iso8601 if vals.key?(tc) }
330
- vals
331
- end
332
- end
333
- module NoMappingBeforeOutput
334
- # current model does not have eg. Time fields--> no special mapping, just to_json is fine
335
- # --> we can use directly the model.values (values_for_odata) withoud dup'ing it as we dont
336
- # need to change it, just output as is
337
- def casted_values(cols = nil)
338
- case cols
339
- when nil
340
- values_for_odata
341
- else
342
- selected_values_for_odata(cols)
343
- end
344
- end
345
- end
346
-
347
314
  module MediaEntity
348
315
  # media entity metadata for json h
349
316
  def metadata_h
@@ -434,9 +401,9 @@ module Safrano
434
401
  include Entity
435
402
  def pk_uri
436
403
  pku = +''
437
- self.class.odata_upk_parts.each_with_index { |upart, i|
404
+ self.class.odata_upk_parts.each_with_index do |upart, i|
438
405
  pku = "#{pku}#{upart}#{pk[i]}"
439
- }
406
+ end
440
407
  pku
441
408
  end
442
409
 
@@ -452,7 +419,7 @@ module Safrano
452
419
  module EntityCreateStandardOutput
453
420
  # Json formatter for a create entity POST call / Standard version; return as json object
454
421
  def to_odata_create_json(request:)
455
- # TODO Perf: reduce method call overhead
422
+ # TODO: Perf: reduce method call overhead
456
423
  # we added this redirection for readability and flexibility
457
424
  to_odata_json(request: request)
458
425
  end
@@ -461,7 +428,7 @@ module Safrano
461
428
  module EntityCreateArrayOutput
462
429
  # Json formatter for a create entity POST call Array version
463
430
  def to_odata_create_json(request:)
464
- # TODO Perf: reduce method call overhead
431
+ # TODO: Perf: reduce method call overhead
465
432
  # we added this redirection for readability and flexibility
466
433
  to_odata_array_json(request: request)
467
434
  end