safrano 0.3.3 → 0.4.3
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.
- checksums.yaml +4 -4
- data/lib/odata/attribute.rb +9 -8
- data/lib/odata/batch.rb +8 -8
- data/lib/odata/collection.rb +239 -92
- data/lib/odata/collection_filter.rb +40 -9
- data/lib/odata/collection_media.rb +159 -28
- data/lib/odata/collection_order.rb +46 -36
- data/lib/odata/common_logger.rb +37 -12
- data/lib/odata/entity.rb +188 -99
- data/lib/odata/error.rb +60 -12
- data/lib/odata/expand.rb +123 -0
- data/lib/odata/filter/base.rb +66 -0
- data/lib/odata/filter/error.rb +33 -0
- data/lib/odata/filter/parse.rb +6 -12
- data/lib/odata/filter/sequel.rb +42 -29
- data/lib/odata/filter/sequel_function_adapter.rb +147 -0
- data/lib/odata/filter/token.rb +5 -1
- data/lib/odata/filter/tree.rb +45 -29
- data/lib/odata/navigation_attribute.rb +60 -27
- data/lib/odata/relations.rb +2 -2
- data/lib/odata/select.rb +42 -0
- data/lib/odata/url_parameters.rb +51 -36
- data/lib/odata/walker.rb +6 -6
- data/lib/safrano.rb +23 -13
- data/lib/{safrano_core.rb → safrano/core.rb} +12 -4
- data/lib/{multipart.rb → safrano/multipart.rb} +17 -26
- data/lib/{odata_rack_builder.rb → safrano/odata_rack_builder.rb} +0 -1
- data/lib/{rack_app.rb → safrano/rack_app.rb} +12 -10
- data/lib/{request.rb → safrano/request.rb} +8 -14
- data/lib/{response.rb → safrano/response.rb} +1 -2
- data/lib/{sequel_join_by_paths.rb → safrano/sequel_join_by_paths.rb} +1 -1
- data/lib/{service.rb → safrano/service.rb} +162 -131
- data/lib/safrano/version.rb +3 -0
- data/lib/sequel/plugins/join_by_paths.rb +11 -10
- metadata +33 -16
- data/lib/version.rb +0 -4
data/lib/odata/relations.rb
CHANGED
@@ -85,7 +85,7 @@ module OData
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
-
def get_metadata_xml_attribs(from, to, assoc_type, xnamespace)
|
88
|
+
def get_metadata_xml_attribs(from, to, assoc_type, xnamespace, attrname)
|
89
89
|
rel = get([from, to])
|
90
90
|
# use Sequel reflection to get multiplicity (will be used later
|
91
91
|
# in 2. Associations below)
|
@@ -107,7 +107,7 @@ module OData
|
|
107
107
|
# <NavigationProperty Name="Supplier"
|
108
108
|
# Relationship="ODataDemo.Product_Supplier_Supplier_Products"
|
109
109
|
# FromRole="Product_Supplier" ToRole="Supplier_Products"/>
|
110
|
-
{ 'Name' =>
|
110
|
+
{ 'Name' => attrname, 'Relationship' => "#{xnamespace}.#{rel.name}",
|
111
111
|
'FromRole' => from, 'ToRole' => to }
|
112
112
|
end
|
113
113
|
end
|
data/lib/odata/select.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'odata/error.rb'
|
2
|
+
|
3
|
+
# all dataset selecting related classes in our OData module
|
4
|
+
# ie do eager loading
|
5
|
+
module OData
|
6
|
+
# base class for selecting. We have to distinguish between
|
7
|
+
# fields of the current entity, and the navigation properties
|
8
|
+
# we can have one special case
|
9
|
+
# empty, ie no $select specified --> return all fields and all nav props
|
10
|
+
# ==> SelectAll
|
11
|
+
|
12
|
+
class SelectBase
|
13
|
+
ALL = new # re-useable selecting-all handler
|
14
|
+
|
15
|
+
def self.factory(selectstr)
|
16
|
+
case selectstr&.strip
|
17
|
+
when nil, '', '*'
|
18
|
+
ALL
|
19
|
+
else
|
20
|
+
Select.new(selectstr)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def all_props?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def ALL.all_props?
|
29
|
+
true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# single select
|
34
|
+
class Select < SelectBase
|
35
|
+
COMASPLIT = /\s*,\s*/.freeze
|
36
|
+
attr_reader :props
|
37
|
+
def initialize(selstr)
|
38
|
+
@selectp = selstr.strip
|
39
|
+
@props = @selectp.split(COMASPLIT)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/odata/url_parameters.rb
CHANGED
@@ -3,57 +3,72 @@ require 'odata/error.rb'
|
|
3
3
|
# url parameters processing . Mostly delegates to specialised classes
|
4
4
|
# (filter, order...) to convert into Sequel exprs.
|
5
5
|
module OData
|
6
|
-
class
|
6
|
+
class UrlParametersBase
|
7
|
+
attr_reader :expand
|
8
|
+
attr_reader :select
|
9
|
+
|
10
|
+
def check_expand
|
11
|
+
return BadRequestExpandParseError if @expand.parse_error?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# url parameters for a single entity expand/select
|
16
|
+
class UrlParameters4Single < UrlParametersBase
|
17
|
+
def initialize(params)
|
18
|
+
@params = params
|
19
|
+
@expand = ExpandBase.factory(@params['$expand'])
|
20
|
+
@select = SelectBase.factory(@params['$select'])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# url parameters for a collection expand/select + filter/order
|
25
|
+
class UrlParameters4Coll < UrlParametersBase
|
7
26
|
attr_reader :filt
|
8
27
|
attr_reader :ordby
|
9
|
-
|
10
|
-
|
28
|
+
|
29
|
+
def initialize(model, params)
|
30
|
+
# join helper is only needed for odering or filtering
|
31
|
+
@jh = model.join_by_paths_helper if params['$orderby'] || params['$filter']
|
11
32
|
@params = params
|
33
|
+
@ordby = OrderBase.factory(@params['$orderby'], @jh)
|
34
|
+
@filt = FilterBase.factory(@params['$filter'])
|
35
|
+
@expand = ExpandBase.factory(@params['$expand'])
|
36
|
+
@select = SelectBase.factory(@params['$select'])
|
12
37
|
end
|
13
38
|
|
14
39
|
def check_filter
|
15
|
-
return unless @params['$filter']
|
16
|
-
|
17
|
-
@filt = FilterByParse.new(@params['$filter'], @jh)
|
18
40
|
return BadRequestFilterParseError if @filt.parse_error?
|
19
|
-
|
20
|
-
# nil is the expected return for no errors
|
21
|
-
nil
|
22
41
|
end
|
23
42
|
|
24
43
|
def check_order
|
25
|
-
return
|
44
|
+
return BadRequestOrderParseError if @ordby.parse_error?
|
45
|
+
end
|
26
46
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
qualfn.strip!
|
32
|
-
dir.strip! if dir
|
33
|
-
return BadRequestError unless @jh.start_model.attrib_path_valid? qualfn
|
34
|
-
return BadRequestError unless [nil, 'asc', 'desc'].include? dir
|
35
|
-
end
|
47
|
+
def apply_to_dataset(dtcx)
|
48
|
+
dtcx = apply_expand_to_dataset(dtcx)
|
49
|
+
apply_filter_order_to_dataset(dtcx)
|
50
|
+
end
|
36
51
|
|
37
|
-
|
52
|
+
def apply_expand_to_dataset(dtcx)
|
53
|
+
return dtcx if @expand.empty?
|
38
54
|
|
39
|
-
|
40
|
-
nil
|
55
|
+
@expand.apply_to_dataset(dtcx)
|
41
56
|
end
|
42
57
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
58
|
+
# Warning, the @ordby and @filt objects are coupled by way of the join helper
|
59
|
+
def apply_filter_order_to_dataset(dtcx)
|
60
|
+
return dtcx if @filt.empty? && @ordby.empty?
|
61
|
+
|
62
|
+
# filter object and join-helper need to be finalized after filter has been parsed and checked
|
63
|
+
@filt.finalize(@jh)
|
64
|
+
|
65
|
+
# start with the join
|
66
|
+
dtcx = @jh.dataset(dtcx)
|
67
|
+
|
68
|
+
dtcx = @filt.apply_to_dataset(dtcx)
|
69
|
+
dtcx = @ordby.apply_to_dataset(dtcx)
|
70
|
+
|
71
|
+
dtcx.select_all(@jh.start_model.table_name)
|
57
72
|
end
|
58
73
|
end
|
59
74
|
end
|
data/lib/odata/walker.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
1
|
require 'json'
|
4
2
|
require 'rexml/document'
|
5
3
|
require 'safrano.rb'
|
@@ -29,9 +27,11 @@ module OData
|
|
29
27
|
|
30
28
|
# are $links requested ?
|
31
29
|
attr_reader :do_links
|
32
|
-
|
30
|
+
NIL_SERVICE_FATAL = 'Walker is called with a nil service'.freeze
|
31
|
+
EMPTYSTR = ''.freeze
|
32
|
+
SLASH = '/'.freeze
|
33
33
|
def initialize(service, path, content_id_refs = nil)
|
34
|
-
raise
|
34
|
+
raise NIL_SERVICE_FATAL unless service
|
35
35
|
|
36
36
|
path = URI.decode_www_form_component(path)
|
37
37
|
@context = service
|
@@ -53,12 +53,12 @@ module OData
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def unprefixed(prefix, path)
|
56
|
-
if (prefix ==
|
56
|
+
if (prefix == EMPTYSTR) || (prefix == SLASH)
|
57
57
|
path
|
58
58
|
else
|
59
59
|
# path.sub!(/\A#{prefix}/, '')
|
60
60
|
# TODO check
|
61
|
-
path.sub(/\A#{prefix}/,
|
61
|
+
path.sub(/\A#{prefix}/, EMPTYSTR)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
data/lib/safrano.rb
CHANGED
@@ -1,19 +1,18 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
1
|
require 'json'
|
4
2
|
require 'rexml/document'
|
5
|
-
require_relative '
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
3
|
+
require_relative 'safrano/multipart.rb'
|
4
|
+
require_relative 'safrano/core.rb'
|
5
|
+
require_relative 'odata/entity.rb'
|
6
|
+
require_relative 'odata/attribute.rb'
|
7
|
+
require_relative 'odata/navigation_attribute.rb'
|
8
|
+
require_relative 'odata/collection.rb'
|
9
|
+
require_relative 'safrano/service.rb'
|
10
|
+
require_relative 'odata/walker.rb'
|
13
11
|
require 'sequel'
|
14
|
-
require_relative '
|
15
|
-
|
16
|
-
|
12
|
+
require_relative 'safrano/sequel_join_by_paths.rb'
|
13
|
+
require_relative 'safrano/rack_app'
|
14
|
+
require_relative 'safrano/odata_rack_builder'
|
15
|
+
require_relative 'safrano/version'
|
17
16
|
|
18
17
|
# picked from activsupport; needed for ruby < 2.5
|
19
18
|
# Destructively converts all keys using the +block+ operations.
|
@@ -30,3 +29,14 @@ class Hash
|
|
30
29
|
transform_keys! { |key| key.to_sym rescue key }
|
31
30
|
end
|
32
31
|
end
|
32
|
+
|
33
|
+
# needed for ruby < 2.5
|
34
|
+
class Dir
|
35
|
+
def self.each_child(dir)
|
36
|
+
Dir.foreach(dir) do |x|
|
37
|
+
next if (x == '.') || (x == '..')
|
38
|
+
|
39
|
+
yield x
|
40
|
+
end
|
41
|
+
end unless respond_to? :each_child
|
42
|
+
end
|
@@ -1,7 +1,14 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
1
|
# our main namespace
|
4
2
|
module OData
|
3
|
+
# frozen empty Array/Hash to reduce unncecessary object creation
|
4
|
+
EMPTY_ARRAY = [].freeze
|
5
|
+
EMPTY_HASH = {}.freeze
|
6
|
+
EMPTY_HASH_IN_ARY = [EMPTY_HASH].freeze
|
7
|
+
EMPTY_STRING = ''.freeze
|
8
|
+
ARY_204_EMPTY_HASH_ARY = [204, EMPTY_HASH, EMPTY_ARRAY].freeze
|
9
|
+
SPACE = ' '.freeze
|
10
|
+
COMMA = ','.freeze
|
11
|
+
|
5
12
|
# some prominent constants... probably already defined elsewhere eg in Rack
|
6
13
|
# but lets KISS
|
7
14
|
CONTENT_TYPE = 'Content-Type'.freeze
|
@@ -32,14 +39,15 @@ module OData
|
|
32
39
|
# database-specific types.
|
33
40
|
DB_TYPE_STRING_RGX = /\ACHAR\s*\(\d+\)\z/.freeze
|
34
41
|
|
42
|
+
# TODO... complete; used in $metadata
|
35
43
|
def self.get_edm_type(db_type:)
|
36
|
-
case db_type
|
44
|
+
case db_type.upcase
|
37
45
|
when 'INTEGER'
|
38
46
|
'Edm.Int32'
|
39
47
|
when 'TEXT', 'STRING'
|
40
48
|
'Edm.String'
|
41
49
|
else
|
42
|
-
'Edm.String' if DB_TYPE_STRING_RGX =~ db_type
|
50
|
+
'Edm.String' if DB_TYPE_STRING_RGX =~ db_type.upcase
|
43
51
|
end
|
44
52
|
end
|
45
53
|
end
|
@@ -6,14 +6,15 @@ 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
|
12
15
|
class Parser
|
13
16
|
HMD_RGX = /^([\w-]+)\s*:\s*(.*)/.freeze
|
14
17
|
|
15
|
-
CRLF_LINE_RGX = /^#{CRLF}$/.freeze
|
16
|
-
|
17
18
|
attr_accessor :lines
|
18
19
|
attr_accessor :target
|
19
20
|
def initialize
|
@@ -54,9 +55,8 @@ module MIME
|
|
54
55
|
if (hmd = HMD_RGX.match(line))
|
55
56
|
@target_hd[hmd[1].downcase] = hmd[2].strip
|
56
57
|
|
57
|
-
# elsif CRLF_LINE_RGX =~ line
|
58
58
|
elsif CRLF == line
|
59
|
-
@target_ct = @target_hd[
|
59
|
+
@target_ct = @target_hd[CTT_TYPE_LC] || TEXT_PLAIN
|
60
60
|
@state = new_content
|
61
61
|
|
62
62
|
end
|
@@ -100,8 +100,8 @@ module MIME
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def hook_multipart(content_type, boundary)
|
103
|
-
@target_hd[
|
104
|
-
@target_ct = @target_hd[
|
103
|
+
@target_hd[CTT_TYPE_LC] = content_type
|
104
|
+
@target_ct = @target_hd[CTT_TYPE_LC]
|
105
105
|
@target = multipart_content(boundary)
|
106
106
|
@target.hd = @target_hd
|
107
107
|
@target.ct = @target_ct
|
@@ -114,10 +114,8 @@ module MIME
|
|
114
114
|
APP_HTTP = 'application/http'.freeze
|
115
115
|
def new_content
|
116
116
|
@target =
|
117
|
-
if @target_ct.start_with?(MPS)
|
118
|
-
(md = (
|
119
|
-
(MP_RGX2.match(@target_ct[10..-1])))
|
120
|
-
)
|
117
|
+
if @target_ct.start_with?(MPS) &&
|
118
|
+
(md = (MP_RGX1.match(@target_ct[10..-1]) || MP_RGX2.match(@target_ct[10..-1])))
|
121
119
|
multipart_content(md[2].strip)
|
122
120
|
elsif @target_ct.start_with?(APP_HTTP)
|
123
121
|
MIME::Content::Application::Http.new
|
@@ -198,7 +196,6 @@ module MIME
|
|
198
196
|
# Parser for Text::Plain
|
199
197
|
class Parser
|
200
198
|
HMD_RGX = /^([\w-]+)\s*:\s*(.*)/.freeze
|
201
|
-
CRLF_LINE_RGX = /^#{CRLF}$/.freeze
|
202
199
|
def initialize(target)
|
203
200
|
@state = :h
|
204
201
|
@lines = []
|
@@ -212,7 +209,6 @@ module MIME
|
|
212
209
|
def parse_head(line)
|
213
210
|
if (hmd = HMD_RGX.match(line))
|
214
211
|
@target.hd[hmd[1].downcase] = hmd[2].strip
|
215
|
-
# elsif CRLF_LINE_RGX =~ line
|
216
212
|
elsif CRLF == line
|
217
213
|
@state = :b
|
218
214
|
else
|
@@ -243,8 +239,8 @@ module MIME
|
|
243
239
|
@hd = {}
|
244
240
|
@content = ''
|
245
241
|
# set default values. Can be overwritten by parser
|
246
|
-
@hd[
|
247
|
-
@ct =
|
242
|
+
@hd[CTT_TYPE_LC] = TEXT_PLAIN
|
243
|
+
@ct = TEXT_PLAIN
|
248
244
|
@parser = Parser.new(self)
|
249
245
|
end
|
250
246
|
|
@@ -364,7 +360,7 @@ module MIME
|
|
364
360
|
end
|
365
361
|
|
366
362
|
def set_multipart_header
|
367
|
-
@hd[
|
363
|
+
@hd[CTT_TYPE_LC] = "#{OData::MP_MIXED}; boundary=#{@boundary}"
|
368
364
|
end
|
369
365
|
|
370
366
|
def get_http_resp(batcha)
|
@@ -382,9 +378,7 @@ module MIME
|
|
382
378
|
# of the changes
|
383
379
|
batcha.db.transaction do
|
384
380
|
begin
|
385
|
-
@response.content = @content.map { |part|
|
386
|
-
part.get_response(batcha)
|
387
|
-
}
|
381
|
+
@response.content = @content.map { |part| part.get_response(batcha) }
|
388
382
|
rescue Sequel::Rollback => e
|
389
383
|
# one of the changes of the changeset has failed
|
390
384
|
# --> provide a dummy empty response for the change-parts
|
@@ -413,10 +407,11 @@ module MIME
|
|
413
407
|
b = ''
|
414
408
|
unless bodyonly
|
415
409
|
# b << OData::CONTENT_TYPE << ': ' << @hd[OData::CTT_TYPE_LC] << CRLF
|
416
|
-
b << "#{OData::CONTENT_TYPE}: #{@hd[
|
410
|
+
b << "#{OData::CONTENT_TYPE}: #{@hd[CTT_TYPE_LC]}#{CRLF}"
|
417
411
|
end
|
418
|
-
|
419
|
-
b <<
|
412
|
+
|
413
|
+
b << crbdcr = "#{CRLF}--#{@boundary}#{CRLF}"
|
414
|
+
b << @content.map(&:unparse).join(crbdcr)
|
420
415
|
b << "#{CRLF}--#{@boundary}--#{CRLF}"
|
421
416
|
b
|
422
417
|
end
|
@@ -442,7 +437,6 @@ module MIME
|
|
442
437
|
def unparse
|
443
438
|
b = "#{@http_method} #{@uri} HTTP/1.1#{CRLF}"
|
444
439
|
@hd.each { |k, v| b << "#{k}: #{v}#{CRLF}" }
|
445
|
-
# @hd.each { |k, v| b << k.to_s << ': ' << v.to_s << CRLF }
|
446
440
|
b << CRLF
|
447
441
|
b << @content if @content != ''
|
448
442
|
b
|
@@ -473,7 +467,6 @@ module MIME
|
|
473
467
|
b = String.new(APPLICATION_HTTP_11)
|
474
468
|
b << "#{@status} #{StatusMessage[@status]} #{CRLF}"
|
475
469
|
@hd.each { |k, v| b << "#{k}: #{v}#{CRLF}" }
|
476
|
-
# @hd.each { |k, v| b << k.to_s << ': ' << v.to_s << CRLF }
|
477
470
|
b << CRLF
|
478
471
|
b << @content.join if @content
|
479
472
|
b
|
@@ -482,7 +475,7 @@ module MIME
|
|
482
475
|
|
483
476
|
# For application/http . Content is either a Request or a Response
|
484
477
|
class Http < Media
|
485
|
-
HTTP_MTHS_RGX = 'POST|GET|PUT|MERGE|PATCH'.freeze
|
478
|
+
HTTP_MTHS_RGX = 'POST|GET|PUT|MERGE|PATCH|DELETE'.freeze
|
486
479
|
HTTP_R_RGX = %r{^(#{HTTP_MTHS_RGX})\s+(\S*)\s?(HTTP/1\.1)\s*$}.freeze
|
487
480
|
HEADER_RGX = %r{^([a-zA-Z\-]+):\s*([0-9a-zA-Z\-\/,\s]+;?\S*)\s*$}.freeze
|
488
481
|
HTTP_RESP_RGX = %r{^HTTP/1\.1\s(\d+)\s}.freeze
|
@@ -490,7 +483,6 @@ module MIME
|
|
490
483
|
# Parser for Http Media
|
491
484
|
class Parser
|
492
485
|
HMD_RGX = /^([\w-]+)\s*:\s*(.*)/.freeze
|
493
|
-
CRLF_LINE_RGX = /^#{CRLF}$/.freeze
|
494
486
|
|
495
487
|
def initialize(target)
|
496
488
|
@state = :http
|
@@ -523,7 +515,6 @@ module MIME
|
|
523
515
|
if (hmd = HMD_RGX.match(line))
|
524
516
|
@target.content.hd[hmd[1].downcase] = hmd[2].strip
|
525
517
|
elsif CRLF == line
|
526
|
-
# elsif CRLF_LINE_RGX =~ line
|
527
518
|
@state = :b
|
528
519
|
else
|
529
520
|
@body_lines << line
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'rack'
|
4
|
-
require_relative 'odata/walker.rb'
|
4
|
+
require_relative '../odata/walker.rb'
|
5
5
|
require_relative 'request.rb'
|
6
6
|
require_relative 'response.rb'
|
7
7
|
|
@@ -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,20 +70,20 @@ 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
|
|
77
77
|
# the main Rack server app. Source: the Rack docu/examples and partly
|
78
78
|
# inspired from Sinatra
|
79
79
|
class ServerApp
|
80
|
-
METHODS_REGEXP = Regexp.new('HEAD|OPTIONS|GET|POST|PATCH|MERGE|PUT|DELETE')
|
80
|
+
METHODS_REGEXP = Regexp.new('HEAD|OPTIONS|GET|POST|PATCH|MERGE|PUT|DELETE').freeze
|
81
|
+
NOCACHE_HDRS = { 'Cache-Control' => 'no-cache',
|
82
|
+
'Expires' => '-1',
|
83
|
+
'Pragma' => 'no-cache' }.freeze
|
84
|
+
DATASERVICEVERSION = 'DataServiceVersion'.freeze
|
81
85
|
include MethodHandlers
|
82
86
|
def before
|
83
|
-
headers 'Cache-Control' => 'no-cache'
|
84
|
-
headers 'Expires' => '-1'
|
85
|
-
headers 'Pragma' => 'no-cache'
|
86
|
-
|
87
87
|
@request.service_base = self.class.get_service_base
|
88
88
|
|
89
89
|
neg_error = @request.negotiate_service_version
|
@@ -92,7 +92,9 @@ module OData
|
|
92
92
|
|
93
93
|
return false unless @request.service
|
94
94
|
|
95
|
-
|
95
|
+
myhdrs = NOCACHE_HDRS.dup
|
96
|
+
myhdrs[DATASERVICEVERSION] = @request.service.data_service_version
|
97
|
+
headers myhdrs
|
96
98
|
end
|
97
99
|
|
98
100
|
# dispatch for all methods requiring parsing of the path
|
@@ -119,7 +121,7 @@ module OData
|
|
119
121
|
|
120
122
|
def dispatch
|
121
123
|
req_ret = if @request.request_method !~ METHODS_REGEXP
|
122
|
-
[404,
|
124
|
+
[404, EMPTY_HASH, ['Did you get lost?']]
|
123
125
|
elsif @request.request_method == 'HEAD'
|
124
126
|
odata_head
|
125
127
|
else
|