safrano 0.8.0 → 0.8.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.
@@ -78,6 +78,10 @@ module Safrano
78
78
  # Represents a named but nil-valued navigation-attribute of an Entity
79
79
  # (usually resulting from a NULL FK db value)
80
80
  class NilNavigationAttribute
81
+ def initialize
82
+ @allowed_transitions = ALLOWED_TRANSITIONS
83
+ end
84
+
81
85
  include Safrano::NavigationInfo
82
86
  def odata_get(req)
83
87
  if req.walker.media_value
@@ -131,6 +135,8 @@ module Safrano
131
135
  def allowed_transitions
132
136
  ALLOWED_TRANSITIONS
133
137
  end
138
+
139
+ include Safrano::Transitions::GetNextTrans::BySimpleDetect
134
140
  end
135
141
  include Transitions
136
142
  end
@@ -35,6 +35,7 @@ module Safrano
35
35
  end
36
36
  end
37
37
  end
38
+
38
39
  # This is used from the Test-suite code !
39
40
  # it does recursive / deep symbolize additionally to inbound casting
40
41
  module XJSON
@@ -4,16 +4,78 @@ require_relative 'error'
4
4
 
5
5
  # our main namespace
6
6
  module Safrano
7
+ module Transitions
8
+ module GetNextTrans
9
+ module BySimpleDetect
10
+ def get_next_transresult(path_remain)
11
+ # current url-parsing context
12
+ # has no ambiguous next match and we dont need to find longest match
13
+ # but it's sufficient to find the one matching (or nil)
14
+ tres_next = nil
15
+ @allowed_transitions.detect { |t| tres_next = t.result(path_remain) }
16
+ tres_next
17
+ end
18
+ end
19
+
20
+ module ForJustTransitionEnd
21
+ def get_next_transresult(path_remain)
22
+ Safrano::TransitionEnd.result(path_remain)
23
+ end
24
+ end
25
+
26
+ # Transitions::GetNextTrans::ByLongestMatch
27
+ module ByLongestMatch
28
+ def get_next_transresult(path_remain)
29
+ # current url-parsing context
30
+ # has ambiguous next match and we need to find longest match
31
+ # example: current context is "the top level service" and we have
32
+ # entity types Race and RaceType
33
+
34
+ match_len = -1
35
+ tres_next = nil
36
+
37
+ @allowed_transitions.each { |t|
38
+ if (res = t.longer_match(path_remain, match_len))
39
+ tres_next = res
40
+ match_len = tres_next.match_length
41
+ end
42
+ }
43
+ tres_next
44
+ end
45
+ end
46
+
47
+ # same as ByLongestMatch but use the getter method allowed_transitions instead of
48
+ # directly @allowed_transitions
49
+ module ByLongestMatchDyn
50
+ def get_next_transresult(path_remain)
51
+ # current url-parsing context
52
+ # has ambiguous next match and we need to find longest match
53
+ # example: current context is "the top level service" and we have
54
+ # entity types Race and RaceType
55
+
56
+ match_len = -1
57
+ tres_next = nil
58
+
59
+ allowed_transitions.each { |t|
60
+ if (res = t.longer_match(path_remain, match_len))
61
+ tres_next = res
62
+ match_len = tres_next.match_length
63
+ end
64
+ }
65
+ tres_next
66
+ end
67
+ end
68
+ end
69
+ end
70
+
7
71
  # represents a state transition when navigating/parsing the url path
8
72
  # from left to right
9
73
  class Transition
10
- attr_accessor :trans
11
- attr_accessor :match_result
12
- attr_accessor :rgx
13
- attr_reader :remain_idx
14
-
15
- EMPTYSTR = ''
16
- SLASH = '/'
74
+ # attr_accessor :trans
75
+ # attr_accessor :match_result
76
+ # attr_accessor :trans_result
77
+ # attr_accessor :rgx
78
+ # attr_reader :remain_idx
17
79
 
18
80
  RESULT_BAD_REQ_ERR = [nil, :error, ::Safrano::BadRequestError].freeze
19
81
  RESULT_NOT_FOUND_ERR = [nil, :error, ::Safrano::ErrorNotFound].freeze
@@ -25,31 +87,58 @@ module Safrano
25
87
  Regexp.new(arg)
26
88
  else
27
89
  arg
28
- end
90
+ end.freeze
91
+ @trans = trans.freeze
92
+ @remain_idx = remain_idx.freeze
93
+ end
94
+
95
+ def result(str)
96
+ return unless (mres = @rgx.match(str))
97
+
98
+ TransitionResult.new(trans: @trans, match_result: mres, remain_idx: @remain_idx)
99
+ end
100
+
101
+ # return match-result for str, if longer as min_match_length
102
+ def longer_match(str, min_match_length)
103
+ return unless (mres = @rgx.match(str))
104
+ return unless (mres.match_length(1) > min_match_length)
105
+
106
+ TransitionResult.new(trans: @trans, match_result: mres, remain_idx: @remain_idx)
107
+ end
108
+ end
109
+
110
+ class TransitionResult
111
+ attr_reader :match
112
+
113
+ EMPTYSTR = ''
114
+ SLASH = '/'
115
+
116
+ def initialize(trans:, match_result:, remain_idx:)
29
117
  @trans = trans
118
+ @match = match_result
30
119
  @remain_idx = remain_idx
31
120
  end
32
121
 
33
- def do_match(str)
34
- @match_result = @rgx.match(str)
122
+ def match_length
123
+ @match.match_length(1)
35
124
  end
36
125
 
37
126
  # remain_idx is the index of the last match-data. ususally its 2
38
127
  # but can be overidden
39
128
  def path_remain
40
- @match_result[@remain_idx] if @match_result && @match_result[@remain_idx]
129
+ @match[@remain_idx] if @match && @match[@remain_idx]
41
130
  end
42
131
 
43
132
  def path_done
44
- if @match_result
45
- @match_result[1] || EMPTYSTR
133
+ if @match
134
+ @match[1] || EMPTYSTR
46
135
  else
47
136
  EMPTYSTR
48
137
  end
49
138
  end
50
139
 
51
140
  def do_transition(ctx)
52
- ctx.method(@trans).call(@match_result)
141
+ ctx.__send__(@trans, @match)
53
142
  end
54
143
  end
55
144
 
@@ -59,8 +148,30 @@ module Safrano
59
148
  @trans = trans
60
149
  end
61
150
 
62
- def do_match(str)
151
+ def result(str)
152
+ @str = str
153
+ InplaceTransitionResult.new(trans: @trans, match_result: @str)
154
+ end
155
+
156
+ # return match-result for str, if longer as min_match_length
157
+ def longer_match(str, min_match_length)
63
158
  @str = str
159
+ return unless (@str.size > min_match_length)
160
+
161
+ InplaceTransitionResult.new(trans: @trans, match_result: @str)
162
+ end
163
+ end
164
+
165
+ # Transition that does not move/change the input
166
+ class InplaceTransitionResult < TransitionResult
167
+ def initialize(trans:, match_result:)
168
+ @trans = trans
169
+ @match = match_result
170
+ @str = match_result
171
+ end
172
+
173
+ def match_length
174
+ @str.size
64
175
  end
65
176
 
66
177
  def path_remain
@@ -70,26 +181,22 @@ module Safrano
70
181
  def path_done
71
182
  EMPTYSTR
72
183
  end
73
-
74
- def do_transition(ctx)
75
- ctx.method(@trans).call(@str)
76
- end
77
184
  end
78
185
 
79
- TransitionEnd = Transition.new('\A(\/?)\z', trans: 'transition_end')
80
- TransitionExecuteFunc = InplaceTransition.new(trans: 'transition_execute_func')
186
+ TransitionEnd = Transition.new('\A(\/?)\z', trans: :transition_end)
187
+ TransitionExecuteFunc = InplaceTransition.new(trans: :transition_execute_func)
81
188
  TransitionMetadata = Transition.new('\A(\/\$metadata)(.*)',
82
- trans: 'transition_metadata')
189
+ trans: :transition_metadata)
83
190
  TransitionBatch = Transition.new('\A(\/\$batch)(.*)',
84
- trans: 'transition_batch')
191
+ trans: :transition_batch)
85
192
  TransitionContentId = Transition.new('\A(\/\$(\d+))(.*)',
86
- trans: 'transition_content_id',
193
+ trans: :transition_content_id,
87
194
  remain_idx: 3)
88
195
  TransitionCount = Transition.new('(\A\/\$count)(.*)\z',
89
- trans: 'transition_count')
196
+ trans: :transition_count)
90
197
  TransitionValue = Transition.new('(\A\/\$value)(.*)\z',
91
- trans: 'transition_value')
198
+ trans: :transition_value)
92
199
  TransitionLinks = Transition.new('(\A\/\$links)(.*)\z',
93
- trans: 'transition_links')
200
+ trans: :transition_links)
94
201
  attr_accessor :allowed_transitions
95
202
  end
data/lib/odata/walker.rb CHANGED
@@ -65,30 +65,10 @@ module Safrano
65
65
  if (prefix == EMPTYSTR) || (prefix == SLASH)
66
66
  path
67
67
  else
68
- # path.sub!(/\A#{prefix}/, '')
69
- # TODO: check
70
68
  path.sub(/\A#{prefix}/, EMPTYSTR)
71
69
  end
72
70
  end
73
71
 
74
- def get_next_transition
75
- # handle multiple valid transitions
76
- # like when we have attributes that are substring of each other
77
- # --> instead of using detect (ie take first transition)
78
- # we need to use select and then find the longest match
79
-
80
- valid_tr = @context.allowed_transitions.map(&:dup).select do |t|
81
- t.do_match(@path_remain)
82
- end
83
-
84
- # HACK: (wanted: a better one) to make attributes that are substrings of each other
85
- # work well
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 }
90
- end
91
-
92
72
  # perform a content-id ($batch changeset ref) transition
93
73
  def do_run_with_content_id
94
74
  if @content_id_refs.is_a? Hash
@@ -137,7 +117,7 @@ module Safrano
137
117
  end
138
118
 
139
119
  def do_next_transition
140
- @context, @status, @error = @tr_next.do_transition(@context)
120
+ @context, @status, @error = @tres_next.do_transition(@context)
141
121
  # little hack's
142
122
  case @status
143
123
  # we dont have the content-id references data on service level
@@ -151,8 +131,8 @@ module Safrano
151
131
  end
152
132
 
153
133
  @contexts << @context
154
- @path_remain = @tr_next.path_remain
155
- @path_done << @tr_next.path_done
134
+ @path_remain = @tres_next.path_remain
135
+ @path_done << @tres_next.path_done
156
136
 
157
137
  # little hack's
158
138
  state_mappings
@@ -160,8 +140,8 @@ module Safrano
160
140
 
161
141
  def eo
162
142
  while @context
163
- get_next_transition
164
- if @tr_next
143
+ @tres_next = @context.get_next_transresult(@path_remain)
144
+ if @tres_next
165
145
  do_next_transition
166
146
  else
167
147
  @context = nil
@@ -22,6 +22,13 @@ module Safrano
22
22
  Safrano::Request.new(env, @service_base).process
23
23
  end
24
24
 
25
+ # needed for testing only ? try to remove this
26
+ def self.copy(other)
27
+ copy = Class.new(Safrano::ServerApp) # <---- !!!
28
+ copy.set_servicebase(other.get_service_base.dup)
29
+ copy
30
+ end
31
+
25
32
  # needed for testing only ? try to remove this
26
33
  def self.enable_batch
27
34
  @service_base.enable_batch
@@ -32,16 +39,22 @@ module Safrano
32
39
  @service_base.path_prefix path_pr
33
40
  end
34
41
 
42
+ # needed for testing only ? try to remove this
43
+
44
+ def self.response_format_options(*args)
45
+ @service_base.response_format_options(*args)
46
+ end
47
+
35
48
  # needed for testing only ? try to remove this
36
49
  def self.get_service_base
37
50
  @service_base
38
51
  end
39
-
40
- # needed for safrano-rack_builder
52
+
53
+ # needed for safrano-rack_builder
41
54
  def get_path_prefix
42
55
  self.class.get_service_base.xpath_prefix
43
56
  end
44
-
57
+
45
58
  def self.set_servicebase(sbase)
46
59
  @service_base = sbase
47
60
  @service_base.enable_v1_service
@@ -7,9 +7,11 @@ module Rack
7
7
  module Safrano
8
8
  # just a Wrapper to ensure (force?) that mandatory middlewares are acutally
9
9
  # used
10
- LOCALHOST_ANY_PORT_RGX = /\A(?:https?:\/\/)?localhost(?::\d+)?\z/
10
+ LOCALHOST_ANY_PORT_RGX = /\A(?:https?:\/\/)?localhost(?::\d+)?\z/.freeze
11
+ CORS_RO_METHODS = %i[get head options].freeze
12
+ CORS_BATCH_METHODS = %i[post head options].freeze
13
+ CORS_RW_METHODS = %i[get post put patch delete head options].freeze
11
14
  class Builder < ::Rack::Builder
12
-
13
15
  def initialize(default_app = nil, &block)
14
16
  super(default_app) {}
15
17
  @middlewares = []
@@ -17,63 +19,61 @@ module Rack
17
19
  instance_eval(&block) if block_given?
18
20
  prepend_rackcors_ifneeded
19
21
  end
20
-
22
+
21
23
  def use(middleware, *args, &block)
22
24
  @middlewares << middleware
23
25
  super(middleware, *args, &block)
24
26
  end
25
-
27
+
26
28
  def prepend_rackcors_ifneeded
27
29
  return if stack_has_rackcors
28
-
30
+
29
31
  # get the safrano app path prefix
30
32
  # normally @run is a Safrano Server app
31
33
  return unless @run.is_a? ::Safrano::ServerApp
32
-
33
-
34
+
34
35
  service_path_prefix = @run.get_path_prefix.dup
35
-
36
- # due to a bug in rack-cors
36
+
37
+ # due to a bug in rack-cors
37
38
  # we cant use the batch ressource path as
38
39
  # a string but need to pass it as a regexp
39
- # ( bug fixed in rack-cors git / new release? but still need to workaround it for
40
- # current/old releases ),
41
- batch_path_regexp = if service_path_prefix.empty?
42
- # Ressource /$batch
43
- /\A\/\$batch\z/
44
- else
45
- # Ressource like /foo/bar/baz/$batch
46
- service_path_prefix.sub!(::Safrano::TRAILING_SLASH_RGX, '')
47
- service_path_prefix.sub!(::Safrano::LEADING_SLASH_RGX, '')
48
- # now is foo/bar/baz
49
- path_prefix_rgx = Regexp.escape("/#{service_path_prefix}/$batch")
50
- # now escaped path regexp /foo/bar/baz/$batch
51
- # finaly just add start / end anchors
52
- /\A#{path_prefix_rgx}\z/
53
- end
40
+ # ( bug fixed in rack-cors git / new release? but still need to workaround it for
41
+ # current/old releases ),
42
+ batch_path_regexp = if service_path_prefix.empty?
43
+ # Ressource /$batch
44
+ /\A\/\$batch\z/
45
+ else
46
+ # Ressource like /foo/bar/baz/$batch
47
+ service_path_prefix.sub!(::Safrano::TRAILING_SLASH_RGX, '')
48
+ service_path_prefix.sub!(::Safrano::LEADING_SLASH_RGX, '')
49
+ # now is foo/bar/baz
50
+ path_prefix_rgx = Regexp.escape("/#{service_path_prefix}/$batch")
51
+ # now escaped path regexp /foo/bar/baz/$batch
52
+ # finaly just add start / end anchors
53
+ /\A#{path_prefix_rgx}\z/
54
+ end
54
55
  # this will append rack-cors mw
55
- # per default allow GET * from everywhere
56
- # allow POST $batch from localhost only
56
+ # per default allow GET * from everywhere
57
+ # allow POST $batch from localhost only
57
58
  use ::Rack::Cors do
58
59
  allow do
59
60
  origins LOCALHOST_ANY_PORT_RGX
60
- resource (batch_path_regexp), headers: :any, methods: [:post, :head, :options]
61
- resource '*', headers: :any, methods: [:get, :post, :put, :patch, :head, :options]
62
- end
61
+ resource batch_path_regexp, headers: :any, methods: CORS_BATCH_METHODS
62
+ resource '*', headers: :any, methods: CORS_RW_METHODS
63
+ end
63
64
  allow do
64
65
  origins '*'
65
- resource '*', headers: :any, methods: [:get, :head, :options]
66
- end
67
-
66
+ resource '*', headers: :any, methods: CORS_RO_METHODS
67
+ end
68
68
  end
69
-
69
+
70
70
  # we need it in first place... move last element to beginin of mw stack
71
- rackcors = @use.delete_at(-1)
72
- @use.insert(0, rackcors)
71
+ rackcors = @use.delete_at(-1)
72
+ @use.insert(0, rackcors)
73
73
  end
74
-
74
+
75
75
  def stack_has_rackcors
76
- @middlewares.find{|mw| mw == Rack::Cors }
76
+ @middlewares.find { |mw| mw == Rack::Cors }
77
77
  end
78
78
  end
79
79
  end
@@ -11,12 +11,12 @@ module Safrano
11
11
  headers.delete('Content-Type')
12
12
  @response.headers.delete('Content-Type')
13
13
  @response.headers['Content-Type'] = ''
14
-
14
+
15
15
  # we only let rack-cors handle Cors OPTIONS .
16
16
  # otherwise dont do it...
17
- # see https://www.mnot.net/blog/2012/10/29/NO_OPTIONS
17
+ # see https://www.mnot.net/blog/2012/10/29/NO_OPTIONS
18
18
  # 501 not implemented
19
- [501, EMPTY_HASH, '']
19
+ [501, EMPTY_HASH, '']
20
20
  end
21
21
 
22
22
  def odata_delete
@@ -41,7 +41,7 @@ module Safrano
41
41
 
42
42
  def odata_post
43
43
  @walker.finalize.tap_error { |err| return err.odata_get(self) }
44
- .if_valid { |context| context.odata_post(self) }
44
+ .if_valid { |context| context.odata_post(self) }
45
45
  end
46
46
 
47
47
  def odata_head
@@ -99,6 +99,7 @@ module Safrano
99
99
  @type
100
100
  end
101
101
  end
102
+
102
103
  ## original coding:
103
104
  # # The set of media-types. Requests that do not indicate
104
105
  # # one of the media types presents in this list will not be eligible
@@ -12,8 +12,12 @@ require 'set'
12
12
  require 'odata/collection'
13
13
 
14
14
  module Safrano
15
- # this module has all methods related to expand/defered output preparation
15
+ # these modules have all methods related to expand/defered output preparation
16
16
  # and will be included in Service class
17
+
18
+ METADATA_K = '__metadata'
19
+ EMPTYH = {}.freeze
20
+
17
21
  module ExpandHandler
18
22
  PATH_SPLITTER = %r{\A(\w+)/?(.*)\z}.freeze
19
23
  DEFERRED = '__deferred'
@@ -40,14 +44,17 @@ module Safrano
40
44
  { uri: entity.uri }
41
45
  end
42
46
 
43
- EMPTYH = {}.freeze
44
- METADATA_K = '__metadata'
45
47
  def get_entity_odata_h(entity:, template:)
46
- # start with metadata
47
- hres = { METADATA_K => entity.metadata_h }
48
+ hres = {}
49
+ # finalise the template according to options
50
+ # (eg. skip metadata and or deferred...)
51
+ @final_template_func.call(template)
48
52
 
49
53
  template.each do |elmt, arg|
50
54
  case elmt
55
+ when :meta
56
+ hres[METADATA_K] = entity.metadata_h
57
+
51
58
  when :all_values
52
59
  hres.merge! entity.casted_values
53
60
 
@@ -110,6 +117,7 @@ module Safrano
110
117
  TRAILING_SLASH_RGX = %r{/\z}.freeze
111
118
  LEADING_SLASH_RGX = %r{\A/}.freeze
112
119
  include XMLNS
120
+ GENERIC_415_RESP = [415, {}, ['']].freeze
113
121
  # Base class for service. Subclass will be for V1, V2 etc...
114
122
  class ServiceBase
115
123
  include Safrano
@@ -142,6 +150,8 @@ module Safrano
142
150
  attr_accessor :function_imports
143
151
  attr_accessor :function_import_keys
144
152
  attr_accessor :type_mappings
153
+ attr_accessor :final_template_func
154
+ attr_accessor :response_format_options
145
155
 
146
156
  # Instance attributes for specialized Version specific Instances
147
157
  attr_accessor :v1
@@ -150,6 +160,12 @@ module Safrano
150
160
  # TODO: more elegant design
151
161
  attr_reader :data_service_version
152
162
 
163
+ # for response format options
164
+ FINAL_TEMPLATE_FUNC_DEFAULT = ->(_template) {}
165
+ FINAL_TEMPLATE_FUNC_SKIP_META = ->(template) { template.delete(:meta) }
166
+ FINAL_TEMPLATE_FUNC_SKIP_DEFERR = ->(template) { template.delete(:deferr) }
167
+ FINAL_TEMPLATE_FUNC_SKIP_META_DEFERR = ->(template) { template.delete(:meta); template.delete(:deferr) }
168
+
153
169
  def initialize(&block)
154
170
  # Warning: if you add attributes here, you shall need add them
155
171
  # in copy_attribs_to as well
@@ -163,6 +179,8 @@ module Safrano
163
179
  @function_import_keys = []
164
180
  @cmap = {}
165
181
  @type_mappings = {}
182
+ @response_format_options = []
183
+ @final_template_func = FINAL_TEMPLATE_FUNC_DEFAULT
166
184
  # enabled per default starting from 0.6
167
185
  @bugfix_create_response = true
168
186
  instance_eval(&block) if block_given?
@@ -213,12 +231,42 @@ module Safrano
213
231
  (@v2.xserver_url = @xserver_url) if @v2
214
232
  end
215
233
 
234
+ VALID_RESP_FORMAT_OPTS = [:skip_deferred, :skip_metadata]
235
+ def valid_resp_format_options(*args)
236
+ args.map!(&:to_sym)
237
+ args.each { |arg|
238
+ raise API::InvalidRespFormatOption.new(arg) unless VALID_RESP_FORMAT_OPTS.include?(arg)
239
+ }
240
+ yield(args)
241
+ end
242
+
243
+ def response_format_options(*args)
244
+ valid_resp_format_options(*args) do |vargs|
245
+ @response_format_options = vargs.dup
246
+ process_response_format_options
247
+ @v1.response_format_options(*vargs) if @v1
248
+ @v2.response_format_options(*vargs) if @v2
249
+ end
250
+ end
251
+
216
252
  # keep the bug active for now, but allow to de-activate the fix
217
253
  def bugfix_create_response(bool)
218
254
  @bugfix_create_response = bool
219
255
  end
220
256
 
221
257
  # end public API
258
+ def process_response_format_options
259
+ @final_template_func = if (@response_format_options.include?(:skip_metadata) &&
260
+ @response_format_options.include?(:skip_deferred))
261
+ FINAL_TEMPLATE_FUNC_SKIP_META_DEFERR
262
+ elsif @response_format_options.include?(:skip_metadata)
263
+ FINAL_TEMPLATE_FUNC_SKIP_META
264
+ elsif @response_format_options.include?(:skip_deferred)
265
+ FINAL_TEMPLATE_FUNC_SKIP_DEFERR
266
+ else
267
+ FINAL_TEMPLATE_FUNC_DEFAULT
268
+ end
269
+ end
222
270
 
223
271
  def set_uribase
224
272
  @uribase = if @xpath_prefix.empty?
@@ -249,6 +297,8 @@ module Safrano
249
297
  other.function_imports = @function_imports
250
298
  other.function_import_keys = @function_import_keys
251
299
  other.type_mappings = @type_mappings
300
+ other.response_format_options = @response_format_options
301
+ other.final_template_func = @final_template_func
252
302
  other.bugfix_create_response(@bugfix_create_response)
253
303
  other
254
304
  end
@@ -620,6 +670,8 @@ module Safrano
620
670
  Safrano::TransitionContentId
621
671
  ].freeze
622
672
 
673
+ include Safrano::Transitions::GetNextTrans::ByLongestMatch
674
+
623
675
  def build_allowed_transitions
624
676
  @allowed_transitions = if @function_imports.empty?
625
677
  (ALLOWED_TRANSITIONS_FIXED + [
@@ -679,7 +731,7 @@ module Safrano
679
731
  [200, CT_APPXML, [service_xml(req)]]
680
732
  else
681
733
  # this is returned by http://services.odata.org/V2/OData/Safrano.svc
682
- 415
734
+ GENERIC_415_RESP
683
735
  end
684
736
  end
685
737
  end
@@ -748,11 +800,13 @@ module Safrano
748
800
  Safrano::Transition::RESULT_END
749
801
  end
750
802
 
803
+ include Safrano::Transitions::GetNextTrans::ForJustTransitionEnd
804
+
751
805
  def odata_get(req)
752
806
  if req.accept?(APPXML)
753
807
  [200, CT_APPXML, [@service.metadata_xml(req)]]
754
808
  else
755
- 415
809
+ GENERIC_415_RESP
756
810
  end
757
811
  end
758
812
  end
@@ -12,6 +12,7 @@ module Safrano
12
12
  attr_reader :castfunc
13
13
  attr_reader :edm_type
14
14
  end
15
+
15
16
  # Model attribute (column) specific mapping
16
17
  class AttributeTypeMapping < TypeMapping
17
18
  attr_reader :attr_name
@@ -20,6 +21,7 @@ module Safrano
20
21
  @edm_type = builder.xedm_type
21
22
  @castfunc = builder.castfunc
22
23
  end
24
+
23
25
  # wrapper to handle API
24
26
  class Builder
25
27
  attr_reader :xedm_type
@@ -82,9 +84,8 @@ module Safrano
82
84
  end
83
85
 
84
86
  def match(curtyp)
85
- if @bui2 && (m = @bui2.match(curtyp))
86
- m
87
- elsif @bui1 && (m = @bui1.match(curtyp))
87
+ if (@bui2 && (m = @bui2.match(curtyp))) ||
88
+ (@bui1 && (m = @bui1.match(curtyp)))
88
89
  m
89
90
  elsif @rgx.match(curtyp)
90
91
  type_mapping
@@ -134,6 +135,7 @@ module Safrano
134
135
  RgxTypeMapping1Par.new(self)
135
136
  end
136
137
  end
138
+
137
139
  class Builder2Par < Builder
138
140
  def initialize(db_ty_rgx, proc)
139
141
  @db_types_rgx = db_ty_rgx
@@ -177,6 +179,7 @@ module Safrano
177
179
  @castfunc = builder.castfunc
178
180
  end
179
181
  end
182
+
180
183
  class RgxTypeMapping2Par < RgxTypeMapping
181
184
  def initialize(builder)
182
185
  @edm_type = builder.xedm_type