safrano 0.6.7 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/core_ext/DateTime/format.rb +1 -1
- data/lib/core_ext/Time/format.rb +2 -2
- data/lib/odata/batch.rb +39 -33
- data/lib/odata/collection.rb +2 -3
- data/lib/odata/collection_media.rb +92 -81
- data/lib/odata/common_logger.rb +19 -2
- data/lib/odata/complex_type.rb +5 -9
- data/lib/odata/edm/primitive_types.rb +53 -64
- data/lib/odata/entity.rb +1 -2
- data/lib/odata/error.rb +3 -3
- data/lib/odata/expand.rb +0 -3
- data/lib/odata/function_import.rb +5 -3
- data/lib/odata/model_ext.rb +21 -26
- data/lib/odata/walker.rb +8 -15
- data/lib/safrano/multipart.rb +39 -28
- data/lib/safrano/rack_app.rb +14 -123
- data/lib/safrano/request.rb +127 -8
- data/lib/safrano/service.rb +3 -3
- data/lib/safrano/version.rb +1 -1
- data/lib/sequel/plugins/join_by_paths.rb +48 -7
- metadata +18 -6
@@ -38,6 +38,28 @@ module Safrano
|
|
38
38
|
|
39
39
|
# type mappings are hard, especially between "Standards" like SQL and OData V2 (might be a bit better in V4 ?)
|
40
40
|
# this is all best effort/try to make it work logic
|
41
|
+
|
42
|
+
RUBY_TY_EDM_TY_MAP = { integer: 'Edm.Int32',
|
43
|
+
string: 'Edm.String',
|
44
|
+
date: 'Edm.DateTime',
|
45
|
+
datetime: 'Edm.DateTime',
|
46
|
+
time: 'Edm.Time',
|
47
|
+
boolean: 'Edm.Boolean',
|
48
|
+
float: 'Edm.Double',
|
49
|
+
decimal: 'Edm.Decimal',
|
50
|
+
blob: 'Edm.Binary' }.freeze
|
51
|
+
DB_TY_EDM_TY_MAP = { 'smallint' => 'Edm.Int16',
|
52
|
+
'int2' => 'Edm.Int16',
|
53
|
+
'smallserial' => 'Edm.Int16',
|
54
|
+
'int' => 'Edm.Int32',
|
55
|
+
'integer' => 'Edm.Int32',
|
56
|
+
'serial' => 'Edm.Int32',
|
57
|
+
'mediumint' => 'Edm.Int32',
|
58
|
+
'int4' => 'Edm.Int32',
|
59
|
+
'bigint' => 'Edm.Int64',
|
60
|
+
'bigserial' => 'Edm.Int64',
|
61
|
+
'int8' => 'Edm.Int64',
|
62
|
+
'tinyint' => 'Edm.Byte' }.freeze
|
41
63
|
def self.add_edm_types(metadata, props)
|
42
64
|
# try num/dec with db_type:
|
43
65
|
metadata[:edm_type] = if (md = DB_TYPE_NUMDEC_RGX.match(props[:db_type]))
|
@@ -80,51 +102,24 @@ module Safrano
|
|
80
102
|
|
81
103
|
# try int-like with db_type:
|
82
104
|
# smallint|int|integer|bigint|serial|bigserial
|
83
|
-
metadata[:edm_type] = if (md = DB_TYPE_INTLIKE_RGX.match(props[:db_type]))
|
84
105
|
|
106
|
+
metadata[:edm_type] = if (md = DB_TYPE_INTLIKE_RGX.match(props[:db_type]))
|
85
107
|
if (itype = md[1])
|
86
|
-
|
87
|
-
when 'smallint', 'int2', 'smallserial'
|
88
|
-
'Edm.Int16'
|
89
|
-
when 'int', 'integer', 'serial', 'mediumint', 'int4'
|
90
|
-
'Edm.Int32'
|
91
|
-
when 'bigint', 'bigserial', 'int8'
|
92
|
-
'Edm.Int64'
|
93
|
-
when 'tinyint'
|
94
|
-
'Edm.Byte'
|
95
|
-
end
|
108
|
+
DB_TY_EDM_TY_MAP[itype.downcase]
|
96
109
|
end
|
97
110
|
end
|
98
111
|
return if metadata[:edm_type]
|
99
112
|
|
100
113
|
# try Guid with db_type:
|
101
114
|
|
102
|
-
metadata[:edm_type] = if
|
115
|
+
metadata[:edm_type] = if DB_TYPE_GUID_RGX.match(props[:db_type])
|
103
116
|
'Edm.Guid'
|
104
117
|
end
|
118
|
+
|
105
119
|
return if metadata[:edm_type]
|
106
120
|
|
107
121
|
# try with Sequel(ruby) type
|
108
|
-
metadata[:edm_type] =
|
109
|
-
when :integer
|
110
|
-
'Edm.Int32'
|
111
|
-
when :string
|
112
|
-
'Edm.String'
|
113
|
-
when :date
|
114
|
-
'Edm.DateTime'
|
115
|
-
when :datetime
|
116
|
-
'Edm.DateTime'
|
117
|
-
when :time
|
118
|
-
'Edm.Time'
|
119
|
-
when :boolean
|
120
|
-
'Edm.Boolean'
|
121
|
-
when :float
|
122
|
-
'Edm.Double'
|
123
|
-
when :decimal
|
124
|
-
'Edm.Decimal'
|
125
|
-
when :blob
|
126
|
-
'Edm.Binary'
|
127
|
-
end
|
122
|
+
metadata[:edm_type] = RUBY_TY_EDM_TY_MAP[props[:type]]
|
128
123
|
end
|
129
124
|
|
130
125
|
# use Edm twice so that we can do include Safrano::Edm and then
|
@@ -153,8 +148,8 @@ module Safrano
|
|
153
148
|
nil
|
154
149
|
end
|
155
150
|
|
156
|
-
def self.convert_from_urlparam(
|
157
|
-
return Contract::NOK unless
|
151
|
+
def self.convert_from_urlparam(val)
|
152
|
+
return Contract::NOK unless val == 'null'
|
158
153
|
|
159
154
|
Contract.valid(nil)
|
160
155
|
end
|
@@ -164,9 +159,9 @@ module Safrano
|
|
164
159
|
class Binary < String
|
165
160
|
extend OutputClassMethods
|
166
161
|
|
167
|
-
def self.convert_from_urlparam(
|
168
|
-
# TODO this should use base64
|
169
|
-
Contract.valid(
|
162
|
+
def self.convert_from_urlparam(val)
|
163
|
+
# TODO: this should use base64
|
164
|
+
Contract.valid(val.dup.force_encoding('BINARY'))
|
170
165
|
end
|
171
166
|
end
|
172
167
|
|
@@ -180,13 +175,13 @@ module Safrano
|
|
180
175
|
end
|
181
176
|
|
182
177
|
def self.odata_collection(array)
|
183
|
-
array.map { |
|
178
|
+
array.map { |val| odata_value(val) }
|
184
179
|
end
|
185
180
|
|
186
|
-
def self.convert_from_urlparam(
|
187
|
-
return Contract::NOK unless %w[true false].include?(
|
181
|
+
def self.convert_from_urlparam(val)
|
182
|
+
return Contract::NOK unless %w[true false].include?(val)
|
188
183
|
|
189
|
-
Contract.valid(
|
184
|
+
Contract.valid(val == 'true')
|
190
185
|
end
|
191
186
|
end
|
192
187
|
|
@@ -195,8 +190,8 @@ module Safrano
|
|
195
190
|
class Byte < Integer
|
196
191
|
extend OutputClassMethods
|
197
192
|
|
198
|
-
def self.convert_from_urlparam(
|
199
|
-
return Contract::NOK unless (bytev =
|
193
|
+
def self.convert_from_urlparam(val)
|
194
|
+
return Contract::NOK unless (bytev = val.to_i) < 256
|
200
195
|
|
201
196
|
Contract.valid(bytev)
|
202
197
|
end
|
@@ -209,29 +204,29 @@ module Safrano
|
|
209
204
|
end
|
210
205
|
|
211
206
|
def self.odata_collection(array)
|
212
|
-
array.map { |
|
207
|
+
array.map { |val| odata_value(val) }
|
213
208
|
end
|
214
209
|
|
215
|
-
def self.convert_from_urlparam(
|
216
|
-
Contract.valid(DateTime.parse(
|
210
|
+
def self.convert_from_urlparam(val)
|
211
|
+
Contract.valid(DateTime.parse(val))
|
217
212
|
rescue StandardError
|
218
|
-
convertion_error(
|
213
|
+
convertion_error(val)
|
219
214
|
end
|
220
215
|
end
|
221
216
|
|
222
217
|
class String < ::String
|
223
218
|
extend OutputClassMethods
|
224
219
|
|
225
|
-
def self.convert_from_urlparam(
|
226
|
-
Contract.valid(
|
220
|
+
def self.convert_from_urlparam(val)
|
221
|
+
Contract.valid(val)
|
227
222
|
end
|
228
223
|
end
|
229
224
|
|
230
225
|
class Int32 < Integer
|
231
226
|
extend OutputClassMethods
|
232
227
|
|
233
|
-
def self.convert_from_urlparam(
|
234
|
-
return Contract::NOK unless (ret = number_or_nil(
|
228
|
+
def self.convert_from_urlparam(val)
|
229
|
+
return Contract::NOK unless (ret = number_or_nil(val))
|
235
230
|
|
236
231
|
Contract.valid(ret)
|
237
232
|
end
|
@@ -240,8 +235,8 @@ module Safrano
|
|
240
235
|
class Int64 < Integer
|
241
236
|
extend OutputClassMethods
|
242
237
|
|
243
|
-
def self.convert_from_urlparam(
|
244
|
-
return Contract::NOK unless (ret = number_or_nil(
|
238
|
+
def self.convert_from_urlparam(val)
|
239
|
+
return Contract::NOK unless (ret = number_or_nil(val))
|
245
240
|
|
246
241
|
Contract.valid(ret)
|
247
242
|
end
|
@@ -250,8 +245,8 @@ module Safrano
|
|
250
245
|
class Double < Float
|
251
246
|
extend OutputClassMethods
|
252
247
|
|
253
|
-
def self.convert_from_urlparam(
|
254
|
-
Contract.valid(
|
248
|
+
def self.convert_from_urlparam(val)
|
249
|
+
Contract.valid(val.to_f)
|
255
250
|
rescue StandardError
|
256
251
|
Contract::NOK
|
257
252
|
end
|
@@ -260,10 +255,10 @@ module Safrano
|
|
260
255
|
class Guid < UUIDTools::UUID
|
261
256
|
extend OutputClassMethods
|
262
257
|
|
263
|
-
def self.convert_from_urlparam(
|
264
|
-
Contract::NOK unless m = Filter::Parser::Token::GUIDRGX.match(
|
258
|
+
def self.convert_from_urlparam(val)
|
259
|
+
Contract::NOK unless (m = Filter::Parser::Token::GUIDRGX.match(val))
|
265
260
|
|
266
|
-
Contract.valid(UUIDTools::UUID.parse
|
261
|
+
Contract.valid(UUIDTools::UUID.parse(m[1]))
|
267
262
|
rescue StandardError
|
268
263
|
Contract::NOK
|
269
264
|
end
|
@@ -271,9 +266,3 @@ module Safrano
|
|
271
266
|
end
|
272
267
|
end
|
273
268
|
end
|
274
|
-
|
275
|
-
# include Safrano
|
276
|
-
|
277
|
-
# x = Edm::String.new('xxx')
|
278
|
-
|
279
|
-
# pp x
|
data/lib/odata/entity.rb
CHANGED
data/lib/odata/error.rb
CHANGED
@@ -50,9 +50,9 @@ module Safrano
|
|
50
50
|
|
51
51
|
# used in function import error handling. cf. func import / do_execute_func
|
52
52
|
def self.with_error(result)
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
return unless result.respond_to?(:error) && (err = result.error)
|
54
|
+
|
55
|
+
yield err
|
56
56
|
end
|
57
57
|
|
58
58
|
# base module for HTTP errors, when used as a Error Class
|
data/lib/odata/expand.rb
CHANGED
@@ -196,7 +196,7 @@ module Safrano
|
|
196
196
|
unless (@error = check_url_func_params)
|
197
197
|
begin
|
198
198
|
return yield
|
199
|
-
rescue LocalJumpError
|
199
|
+
rescue LocalJumpError
|
200
200
|
@error = Safrano::ServiceOperationReturnError.new
|
201
201
|
end
|
202
202
|
end
|
@@ -212,13 +212,15 @@ module Safrano
|
|
212
212
|
|
213
213
|
# Note: Sequel::Error exceptions are already
|
214
214
|
# handled on rack app level (cf. the call methode )
|
215
|
-
Safrano
|
215
|
+
Safrano.with_error(result) do |error|
|
216
216
|
@error = error
|
217
217
|
return [nil, :error, @error] # this is return from do_execute_func !
|
218
218
|
end
|
219
219
|
|
220
220
|
# non error case
|
221
|
-
[@returning.do_execute_func_result(result, req,
|
221
|
+
[@returning.do_execute_func_result(result, req,
|
222
|
+
apply_query_params: @auto_query_params),
|
223
|
+
:run]
|
222
224
|
end
|
223
225
|
end
|
224
226
|
|
data/lib/odata/model_ext.rb
CHANGED
@@ -142,11 +142,11 @@ module Safrano
|
|
142
142
|
@attribute_path_list = attribute_path_list
|
143
143
|
end
|
144
144
|
|
145
|
-
MAX_DEPTH =
|
145
|
+
MAX_DEPTH = 4
|
146
146
|
def attribute_path_list(depth = 0)
|
147
147
|
ret = @columns_str.dup
|
148
148
|
# break circles
|
149
|
-
return ret if depth
|
149
|
+
return ret if depth >= MAX_DEPTH
|
150
150
|
|
151
151
|
depth += 1
|
152
152
|
|
@@ -166,7 +166,7 @@ module Safrano
|
|
166
166
|
ret.concat(@nav_collection_attribs_keys) if @nav_collection_attribs
|
167
167
|
|
168
168
|
# break circles
|
169
|
-
return ret if depth
|
169
|
+
return ret if depth >= MAX_DEPTH
|
170
170
|
|
171
171
|
depth += 1
|
172
172
|
|
@@ -387,7 +387,7 @@ module Safrano
|
|
387
387
|
end
|
388
388
|
|
389
389
|
# attribute specific type mapping
|
390
|
-
if colmap = @type_mappings[col]
|
390
|
+
if (colmap = @type_mappings[col])
|
391
391
|
metadata[:edm_type] = colmap.edm_type
|
392
392
|
if colmap.castfunc
|
393
393
|
@casted_cols[col] = colmap.castfunc
|
@@ -430,7 +430,7 @@ module Safrano
|
|
430
430
|
if metadata[:edm_type] == 'Edm.Guid'
|
431
431
|
|
432
432
|
if props[:type] == :blob # Edm.Guid but as 16 byte binary Blob on DB level, eg in Sqlite
|
433
|
-
@casted_cols[col] =
|
433
|
+
@casted_cols[col] = lambda { |x|
|
434
434
|
UUIDTools::UUID.parse_raw(x).to_s unless x.nil?
|
435
435
|
} # Base64
|
436
436
|
next
|
@@ -445,9 +445,9 @@ module Safrano
|
|
445
445
|
end # db_schema.each do |col, props|
|
446
446
|
|
447
447
|
# check if key needs casting. Important for later entity-uri generation !
|
448
|
-
|
449
|
-
|
450
|
-
|
448
|
+
return unless primary_key.is_a? Symbol # single key field
|
449
|
+
|
450
|
+
@pk_castfunc = @casted_cols[primary_key]
|
451
451
|
end # build_casted_cols(service)
|
452
452
|
|
453
453
|
def finalize_publishing(service)
|
@@ -516,14 +516,13 @@ module Safrano
|
|
516
516
|
|
517
517
|
@iuk_rgx_parts.transform_values! { |v| /\A#{v}\z/ }
|
518
518
|
|
519
|
-
@entity_id_url_regexp = KEYPRED_URL_REGEXP
|
520
519
|
else
|
521
520
|
@pk_names = [primary_key.to_s]
|
522
521
|
@pk_cast_from_string = nil
|
523
522
|
|
524
523
|
kvpredicate = case db_schema[primary_key][:type]
|
525
524
|
when :integer
|
526
|
-
# TODO
|
525
|
+
# TODO: Harmonize this with primitive_types.rb convert_from_url
|
527
526
|
@pk_cast_from_string = ->(str) { Integer(str) }
|
528
527
|
/(\d+)/.freeze
|
529
528
|
else
|
@@ -531,9 +530,7 @@ module Safrano
|
|
531
530
|
case metadata[:edm_type]
|
532
531
|
when 'Edm.Guid'
|
533
532
|
if db_schema[primary_key][:type] == :blob # Edm.Guid but as 16byte binary Blob on DB
|
534
|
-
@pk_cast_from_string =
|
535
|
-
# TODO harmonize this with primitive_types.rb convert_from_url
|
536
|
-
# Sequel::SQL::Blob.new([ str.gsub('-', '') ].pack('H*')) }
|
533
|
+
@pk_cast_from_string = lambda { |str|
|
537
534
|
Sequel::SQL::Blob.new(UUIDTools::UUID.parse(str).raw)
|
538
535
|
}
|
539
536
|
end
|
@@ -543,9 +540,9 @@ module Safrano
|
|
543
540
|
end
|
544
541
|
end
|
545
542
|
@iuk_rgx = /\A\s*#{kvpredicate}\s*\z/
|
546
|
-
# @entity_id_url_regexp = /\A\(\s*#{kvpredicate}\s*\)(.*)/.freeze
|
547
|
-
@entity_id_url_regexp = KEYPRED_URL_REGEXP
|
548
543
|
end
|
544
|
+
# @entity_id_url_regexp = /\A\(\s*#{kvpredicate}\s*\)(.*)/.freeze
|
545
|
+
@entity_id_url_regexp = KEYPRED_URL_REGEXP
|
549
546
|
end
|
550
547
|
|
551
548
|
def prepare_fields
|
@@ -673,21 +670,19 @@ module Safrano
|
|
673
670
|
|
674
671
|
mid.split(/\s*,\s*/).each do |midpart|
|
675
672
|
mval = nil
|
676
|
-
mpk,
|
673
|
+
mpk, _mrgx = scan_rgx_parts.find do |_pk, rgx|
|
677
674
|
if (md = rgx.match(midpart))
|
678
675
|
mval = md[1]
|
679
676
|
end
|
680
677
|
end
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
return Contract::NOK
|
690
|
-
end
|
678
|
+
return Contract::NOK unless mpk && mval
|
679
|
+
|
680
|
+
mdch[mpk] = if (pk_cast = @pk_cast_from_string[mpk])
|
681
|
+
pk_cast.call(mval)
|
682
|
+
else
|
683
|
+
mval # no cast needed, eg for string
|
684
|
+
end
|
685
|
+
scan_rgx_parts.delete(mpk)
|
691
686
|
end
|
692
687
|
# normally arriving here we have mdch filled with key values pairs,
|
693
688
|
# but not in the model key ordering. lets just re-order the values
|
data/lib/odata/walker.rb
CHANGED
@@ -66,34 +66,27 @@ module Safrano
|
|
66
66
|
path
|
67
67
|
else
|
68
68
|
# path.sub!(/\A#{prefix}/, '')
|
69
|
-
# TODO check
|
69
|
+
# TODO: check
|
70
70
|
path.sub(/\A#{prefix}/, EMPTYSTR)
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
74
|
def get_next_transition
|
75
|
-
#
|
75
|
+
# handle multiple valid transitions
|
76
76
|
# like when we have attributes that are substring of each other
|
77
77
|
# --> instead of using detect (ie take first transition)
|
78
78
|
# we need to use select and then find the longest match
|
79
|
-
# tr_next = @context.allowed_transitions.detect do |t|
|
80
|
-
# t.do_match(@path_remain)
|
81
|
-
# end
|
82
79
|
|
83
|
-
valid_tr = @context.allowed_transitions.select do |t|
|
80
|
+
valid_tr = @context.allowed_transitions.map(&:dup).select do |t|
|
84
81
|
t.do_match(@path_remain)
|
85
82
|
end
|
86
83
|
|
87
|
-
#
|
88
|
-
# better one) to make attributes that are substrings of each other
|
84
|
+
# HACK: (wanted: a better one) to make attributes that are substrings of each other
|
89
85
|
# work well
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
valid_tr.max_by { |t| t.match_result[1].size }
|
95
|
-
end
|
96
|
-
end
|
86
|
+
return unless valid_tr
|
87
|
+
return (@tr_next = nil) if valid_tr.empty?
|
88
|
+
|
89
|
+
@tr_next = valid_tr.size == 1 ? valid_tr.first : valid_tr.max_by { |t| t.match_result[1].size }
|
97
90
|
end
|
98
91
|
|
99
92
|
# perform a content-id ($batch changeset ref) transition
|
data/lib/safrano/multipart.rb
CHANGED
@@ -45,9 +45,9 @@ module MIME
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def parse_next_part(line)
|
48
|
-
if @target.parser.next_part(line)
|
48
|
+
return if @target.parser.next_part(line)
|
49
49
|
|
50
|
-
|
50
|
+
if @target.parser.last_part(line)
|
51
51
|
@state = :end
|
52
52
|
else
|
53
53
|
@target.parser.addline(line)
|
@@ -113,8 +113,8 @@ module MIME
|
|
113
113
|
MPS = 'multipart/'
|
114
114
|
MP_RGX1 = %r{^(digest|mixed);\s*boundary="(.*)"}.freeze
|
115
115
|
MP_RGX2 = %r{^(digest|mixed);\s*boundary=(.*)}.freeze
|
116
|
-
# APP_HTTP_RGX = %r{^application/http}.freeze
|
117
116
|
APP_HTTP = 'application/http'
|
117
|
+
|
118
118
|
def new_content
|
119
119
|
@target =
|
120
120
|
if @target_ct.start_with?(MPS) &&
|
@@ -138,18 +138,17 @@ module MIME
|
|
138
138
|
|
139
139
|
def parse_str(inpstr, level: 0)
|
140
140
|
# we need to keep the line separators --> use io.readlines
|
141
|
-
if inpstr.respond_to?(:readlines)
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
end
|
141
|
+
@lines = if inpstr.respond_to?(:readlines)
|
142
|
+
inpstr.readlines(@sep)
|
143
|
+
else
|
144
|
+
# rack input wrapper only has gets but not readlines
|
145
|
+
# BUT the rack SPEC says it only supports gets without argument!
|
146
|
+
# --> finally we end up using read and split into lines...
|
147
|
+
# normally should be ok for $batch POST payloads
|
148
|
+
|
149
|
+
# inpstr.read should be a String
|
150
|
+
inpstr.read.lines(@sep)
|
151
|
+
end
|
153
152
|
# tmp hack for test-tools that convert CRLF in payload to LF :-(
|
154
153
|
if @lines.size == 1
|
155
154
|
@sep = LF
|
@@ -319,7 +318,7 @@ module MIME
|
|
319
318
|
def addline(line)
|
320
319
|
@body_lines << line
|
321
320
|
end
|
322
|
-
end
|
321
|
+
end # Parser
|
323
322
|
|
324
323
|
attr_reader :boundary
|
325
324
|
|
@@ -369,12 +368,12 @@ module MIME
|
|
369
368
|
@hd[CTT_TYPE_LC] = "#{Safrano::MP_MIXED}; boundary=#{@boundary}"
|
370
369
|
end
|
371
370
|
|
372
|
-
def
|
373
|
-
get_response(
|
374
|
-
[@response.hd, @response.
|
371
|
+
def get_mult_resp(full_req)
|
372
|
+
get_response(full_req)
|
373
|
+
[202, @response.hd, @response.unparse_bodyonly]
|
375
374
|
end
|
376
375
|
|
377
|
-
def get_response(
|
376
|
+
def get_response(full_req)
|
378
377
|
@response = self.class.new(::SecureRandom.uuid)
|
379
378
|
@response.set_multipart_header
|
380
379
|
if @level == 1 # changeset need their own global transaction
|
@@ -382,9 +381,10 @@ module MIME
|
|
382
381
|
# and will be flagged with in_changeset=true
|
383
382
|
# and this will finally be used to skip the transaction
|
384
383
|
# of the changes
|
385
|
-
|
384
|
+
|
385
|
+
full_req.db.transaction do
|
386
386
|
begin
|
387
|
-
@response.content = @content.map { |part| part.get_response(
|
387
|
+
@response.content = @content.map { |part| part.get_response(full_req) }
|
388
388
|
rescue Sequel::Rollback => e
|
389
389
|
# one of the changes of the changeset has failed
|
390
390
|
# --> provide a dummy empty response for the change-parts
|
@@ -394,7 +394,7 @@ module MIME
|
|
394
394
|
end
|
395
395
|
end
|
396
396
|
else
|
397
|
-
@response.content = @content.map { |
|
397
|
+
@response.content = @content.map { |part| part.get_response(full_req) }
|
398
398
|
end
|
399
399
|
@response
|
400
400
|
end
|
@@ -409,10 +409,20 @@ module MIME
|
|
409
409
|
@response
|
410
410
|
end
|
411
411
|
|
412
|
-
def unparse
|
412
|
+
def unparse
|
413
413
|
b = +String.new
|
414
|
-
b << "#{Safrano::CONTENT_TYPE}: #{@hd[CTT_TYPE_LC]}#{CRLF}"
|
414
|
+
b << "#{Safrano::CONTENT_TYPE}: #{@hd[CTT_TYPE_LC]}#{CRLF}"
|
415
|
+
|
416
|
+
# warning: duplicated code with below
|
417
|
+
b << crbdcr = "#{CRLF}--#{@boundary}#{CRLF}"
|
418
|
+
b << @content.map(&:unparse).join(crbdcr)
|
419
|
+
b << "#{CRLF}--#{@boundary}--#{CRLF}"
|
420
|
+
b
|
421
|
+
end
|
415
422
|
|
423
|
+
def unparse_bodyonly
|
424
|
+
b = +String.new
|
425
|
+
# warning: duplicated code with above
|
416
426
|
b << crbdcr = "#{CRLF}--#{@boundary}#{CRLF}"
|
417
427
|
b << @content.map(&:unparse).join(crbdcr)
|
418
428
|
b << "#{CRLF}--#{@boundary}--#{CRLF}"
|
@@ -450,6 +460,7 @@ module MIME
|
|
450
460
|
class HttpResp < Media
|
451
461
|
attr_accessor :status
|
452
462
|
attr_accessor :content
|
463
|
+
attr_accessor :rack_resp
|
453
464
|
|
454
465
|
APPLICATION_HTTP_11 = ['Content-Type: application/http',
|
455
466
|
"Content-Transfer-Encoding: binary#{CRLF}",
|
@@ -558,9 +569,9 @@ module MIME
|
|
558
569
|
@content = other.content
|
559
570
|
end
|
560
571
|
|
561
|
-
def get_response(
|
562
|
-
# self.content should be the request
|
563
|
-
rack_resp =
|
572
|
+
def get_response(full_req)
|
573
|
+
# self.content should be the part-request
|
574
|
+
rack_resp = full_req.batch_call(@content)
|
564
575
|
@response = MIME::Content::Application::HttpResp.new
|
565
576
|
@response.status = rack_resp[0]
|
566
577
|
@response.hd = rack_resp[1]
|