safrano 0.8.2 → 0.8.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/core_ext/REXML/Document/output.rb +3 -1
- data/lib/core_ext/rexml.rb +1 -0
- data/lib/odata/collection_order.rb +1 -2
- data/lib/odata/expand.rb +1 -2
- data/lib/safrano/rack_app.rb +0 -66
- data/lib/safrano/service.rb +123 -78
- data/lib/safrano/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c341ac75683820fb122f94d0f45abe31258a48e3366db3ed4547c088a2afdab9
|
4
|
+
data.tar.gz: 7d0ddebfd2b00738235514e5f1544f22d8a20fa6c2b4cde5b9066af4251e50be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 220d3948fc7a80c1c3403fa3d98eab40880c2d80dd7745f003ea93b27581641df1cbcec4d7bf6d471b7c18843c6054addabb9635382f86e60531679aa1738c21
|
7
|
+
data.tar.gz: 4731134f71abd2f5e4b044ac5853d8f30a951c6c434fd2861fd5f59e3f5cdda1916f5ba5c3ff05030572a2f58c4a46d75c5e8289d1d3d96778d0df8a8f6504c8
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Safrano
|
2
4
|
module CoreIncl
|
3
5
|
module REXML
|
@@ -6,7 +8,7 @@ module Safrano
|
|
6
8
|
def to_pretty_xml
|
7
9
|
formatter = ::REXML::Formatters::Pretty.new(2)
|
8
10
|
formatter.compact = true
|
9
|
-
formatter.write(root, strio =
|
11
|
+
formatter.write(root, strio = ::String.new)
|
10
12
|
strio
|
11
13
|
end
|
12
14
|
end
|
data/lib/core_ext/rexml.rb
CHANGED
data/lib/odata/expand.rb
CHANGED
@@ -82,9 +82,8 @@ module Safrano
|
|
82
82
|
# Note: if you change this method, please also update arity_full_monkey?
|
83
83
|
# see below
|
84
84
|
def initialize(expandstr, model)
|
85
|
-
expandstr.strip!
|
86
85
|
@model = model
|
87
|
-
@expandp = expandstr
|
86
|
+
@expandp = expandstr.strip
|
88
87
|
|
89
88
|
@exstrlist = expandstr.split(COMASPLIT)
|
90
89
|
@exlist = @exstrlist.map { |exstr| Expand.new(exstr) }
|
data/lib/safrano/rack_app.rb
CHANGED
@@ -4,69 +4,3 @@ require 'rack'
|
|
4
4
|
require_relative '../odata/walker'
|
5
5
|
require_relative 'request'
|
6
6
|
require_relative 'response'
|
7
|
-
|
8
|
-
module Safrano
|
9
|
-
# Note there is a strong 1 to 1 relation between an app instance
|
10
|
-
# and a published service. --> actually means also
|
11
|
-
# we only support one service per App-class because publishing is
|
12
|
-
# made on app class level
|
13
|
-
class ServerApp
|
14
|
-
def initialize
|
15
|
-
# just get back the service base instance object
|
16
|
-
# that was saved on class level and save it here
|
17
|
-
# so it's not needed to call self.class.service
|
18
|
-
@service_base = self.class.get_service_base
|
19
|
-
end
|
20
|
-
|
21
|
-
def call(env)
|
22
|
-
Safrano::Request.new(env, @service_base).process
|
23
|
-
end
|
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
|
-
|
32
|
-
# needed for testing only ? try to remove this
|
33
|
-
def self.enable_batch
|
34
|
-
@service_base.enable_batch
|
35
|
-
end
|
36
|
-
|
37
|
-
# needed for testing only ? try to remove this
|
38
|
-
def self.path_prefix(path_pr)
|
39
|
-
@service_base.path_prefix path_pr
|
40
|
-
end
|
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
|
-
|
48
|
-
# needed for testing only ? try to remove this
|
49
|
-
def self.get_service_base
|
50
|
-
@service_base
|
51
|
-
end
|
52
|
-
|
53
|
-
# needed for safrano-rack_builder
|
54
|
-
def get_path_prefix
|
55
|
-
self.class.get_service_base.xpath_prefix
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.set_servicebase(sbase)
|
59
|
-
@service_base = sbase
|
60
|
-
@service_base.enable_v1_service
|
61
|
-
@service_base.enable_v2_service
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.publish_service(&block)
|
65
|
-
sbase = Safrano::ServiceBase.new
|
66
|
-
sbase.instance_eval(&block) if block_given?
|
67
|
-
sbase.finalize_publishing
|
68
|
-
# save published service base instance on App-Class level
|
69
|
-
set_servicebase(sbase)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
data/lib/safrano/service.rb
CHANGED
@@ -118,9 +118,10 @@ module Safrano
|
|
118
118
|
LEADING_SLASH_RGX = %r{\A/}.freeze
|
119
119
|
include XMLNS
|
120
120
|
GENERIC_415_RESP = [415, {}, ['']].freeze
|
121
|
-
|
122
|
-
class
|
121
|
+
|
122
|
+
class ServerApp
|
123
123
|
include Safrano
|
124
|
+
include Safrano::Edm
|
124
125
|
include ExpandHandler
|
125
126
|
|
126
127
|
XML_PREAMBLE = %(<?xml version="1.0" encoding="utf-8" standalone="yes"?>\r\n)
|
@@ -132,30 +133,31 @@ module Safrano
|
|
132
133
|
# end
|
133
134
|
# ---> @cmap ends up as {'books' => Book }
|
134
135
|
attr_reader :cmap
|
136
|
+
attr_reader :xbugfix_create_response
|
137
|
+
attr_reader :allowed_transitions
|
135
138
|
|
136
139
|
# this is just the *sorted* list of the entity classes
|
137
140
|
# (ie... @cmap.values.sorted)
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
attr_accessor :response_format_options
|
141
|
+
attr_reader :collections
|
142
|
+
|
143
|
+
attr_reader :xtitle
|
144
|
+
attr_reader :xname
|
145
|
+
attr_reader :xnamespace
|
146
|
+
attr_reader :xpath_prefix
|
147
|
+
attr_reader :xserver_url
|
148
|
+
attr_reader :uribase
|
149
|
+
attr_reader :meta
|
150
|
+
attr_reader :batch_handler
|
151
|
+
attr_reader :complex_types
|
152
|
+
attr_reader :function_imports
|
153
|
+
attr_reader :function_import_keys
|
154
|
+
attr_reader :type_mappings
|
155
|
+
attr_reader :final_template_func
|
156
|
+
attr_reader :response_format_options
|
155
157
|
|
156
158
|
# Instance attributes for specialized Version specific Instances
|
157
|
-
|
158
|
-
|
159
|
+
attr_reader :v1
|
160
|
+
attr_reader :v2
|
159
161
|
|
160
162
|
# TODO: more elegant design
|
161
163
|
attr_reader :data_service_version
|
@@ -166,14 +168,13 @@ module Safrano
|
|
166
168
|
FINAL_TEMPLATE_FUNC_SKIP_DEFERR = ->(template) { template.delete(:deferr) }
|
167
169
|
FINAL_TEMPLATE_FUNC_SKIP_META_DEFERR = ->(template) { template.delete(:meta); template.delete(:deferr) }
|
168
170
|
|
169
|
-
def
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
171
|
+
def self.app_setup_singleton
|
172
|
+
@app_setup_singleton
|
173
|
+
end
|
174
|
+
|
175
|
+
def initialize(template_instance: nil)
|
174
176
|
@meta = ServiceMeta.new(self)
|
175
177
|
@batch_handler = Safrano::Batch::DisabledHandler.new
|
176
|
-
@relman = Safrano::RelationManager.new
|
177
178
|
@complex_types = Set.new
|
178
179
|
@function_imports = {}
|
179
180
|
@function_import_keys = []
|
@@ -182,8 +183,61 @@ module Safrano
|
|
182
183
|
@response_format_options = []
|
183
184
|
@final_template_func = FINAL_TEMPLATE_FUNC_DEFAULT
|
184
185
|
# enabled per default starting from 0.6
|
185
|
-
@
|
186
|
-
|
186
|
+
@xbugfix_create_response = true
|
187
|
+
klass = self.class
|
188
|
+
# TODO better error
|
189
|
+
raise StandardError unless (klass.publish_proc or template_instance)
|
190
|
+
|
191
|
+
tmpli = if template_instance
|
192
|
+
template_instance
|
193
|
+
elsif klass.app_setup_singleton
|
194
|
+
klass.app_setup_singleton
|
195
|
+
end
|
196
|
+
initialize_fork(tmpli) if tmpli
|
197
|
+
end
|
198
|
+
|
199
|
+
def initialize_fork(template_instance)
|
200
|
+
@batch_handler = template_instance.batch_handler.dup
|
201
|
+
@complex_types = template_instance.complex_types.dup
|
202
|
+
@function_imports = template_instance.function_imports.dup
|
203
|
+
@function_import_keys = template_instance.function_import_keys.dup
|
204
|
+
@cmap = template_instance.cmap.dup
|
205
|
+
@type_mappings = template_instance.type_mappings.dup
|
206
|
+
@response_format_options = template_instance.response_format_options.dup
|
207
|
+
@final_template_func = template_instance.final_template_func.dup
|
208
|
+
@xbugfix_create_response = template_instance.xbugfix_create_response.dup
|
209
|
+
@xpath_prefix = template_instance.xpath_prefix.dup
|
210
|
+
@collections = template_instance.collections.dup
|
211
|
+
@xname = template_instance.xname.dup
|
212
|
+
@xserver_url = template_instance.xserver_url.dup
|
213
|
+
@uribase = template_instance.uribase.dup
|
214
|
+
@xtitle = template_instance.xtitle.dup
|
215
|
+
@xnamespace = template_instance.xnamespace.dup
|
216
|
+
@v1 = template_instance.v1.dup
|
217
|
+
@v2 = template_instance.v2.dup
|
218
|
+
@data_service_version = template_instance.data_service_version.dup
|
219
|
+
@allowed_transitions = template_instance.allowed_transitions.dup
|
220
|
+
end
|
221
|
+
|
222
|
+
def call(env)
|
223
|
+
Safrano::Request.new(env, self).process
|
224
|
+
end
|
225
|
+
|
226
|
+
def process_publish_service(&block)
|
227
|
+
instance_eval(&block)
|
228
|
+
finalize_publishing
|
229
|
+
enable_v1_service
|
230
|
+
enable_v2_service
|
231
|
+
end
|
232
|
+
|
233
|
+
def self.publish_service(&block)
|
234
|
+
@publish_proc = block
|
235
|
+
@app_setup_singleton = self.new
|
236
|
+
@app_setup_singleton.process_publish_service(&block)
|
237
|
+
end
|
238
|
+
|
239
|
+
def self.publish_proc
|
240
|
+
@publish_proc
|
187
241
|
end
|
188
242
|
|
189
243
|
DEFAULT_PATH_PREFIX = '/'
|
@@ -191,18 +245,17 @@ module Safrano
|
|
191
245
|
|
192
246
|
def enable_batch
|
193
247
|
@batch_handler = Safrano::Batch::EnabledHandler.new
|
194
|
-
(@v1.
|
195
|
-
(@v2.
|
248
|
+
(@v1.enable_batch) if @v1
|
249
|
+
(@v2.enable_batch) if @v2
|
250
|
+
self
|
196
251
|
end
|
197
252
|
|
198
253
|
def enable_v1_service
|
199
|
-
@v1 = Safrano::ServiceV1.new
|
200
|
-
copy_attribs_to @v1
|
254
|
+
@v1 = Safrano::ServiceV1.new(template_instance: self)
|
201
255
|
end
|
202
256
|
|
203
257
|
def enable_v2_service
|
204
|
-
@v2 = Safrano::ServiceV2.new
|
205
|
-
copy_attribs_to @v2
|
258
|
+
@v2 = Safrano::ServiceV2.new(template_instance: self)
|
206
259
|
end
|
207
260
|
|
208
261
|
# public API
|
@@ -221,14 +274,21 @@ module Safrano
|
|
221
274
|
def path_prefix(path_pr)
|
222
275
|
@xpath_prefix = path_pr.sub(TRAILING_SLASH_RGX, '')
|
223
276
|
@xpath_prefix.freeze
|
224
|
-
(@v1.
|
225
|
-
(@v2.
|
277
|
+
(@v1.path_prefix(path_pr)) if @v1
|
278
|
+
(@v2.path_prefix(path_pr)) if @v2
|
279
|
+
self
|
280
|
+
end
|
281
|
+
|
282
|
+
# needed for safrano-rack_builder
|
283
|
+
def get_path_prefix
|
284
|
+
@xpath_prefix
|
226
285
|
end
|
227
286
|
|
228
287
|
def server_url(surl)
|
229
288
|
@xserver_url = surl.sub(TRAILING_SLASH_RGX, '')
|
230
|
-
|
231
|
-
(@
|
289
|
+
@xserver_url.freeze
|
290
|
+
(@v1.server_url(surl)) if @v1
|
291
|
+
(@v2.server_url(surl)) if @v2
|
232
292
|
end
|
233
293
|
|
234
294
|
VALID_RESP_FORMAT_OPTS = [:skip_deferred, :skip_metadata]
|
@@ -247,11 +307,12 @@ module Safrano
|
|
247
307
|
@v1.response_format_options(*vargs) if @v1
|
248
308
|
@v2.response_format_options(*vargs) if @v2
|
249
309
|
end
|
310
|
+
self
|
250
311
|
end
|
251
312
|
|
252
313
|
# keep the bug active for now, but allow to de-activate the fix
|
253
314
|
def bugfix_create_response(bool)
|
254
|
-
@
|
315
|
+
@xbugfix_create_response = bool
|
255
316
|
end
|
256
317
|
|
257
318
|
# end public API
|
@@ -280,29 +341,6 @@ module Safrano
|
|
280
341
|
(@v2.uribase = @uribase) if @v2
|
281
342
|
end
|
282
343
|
|
283
|
-
def copy_attribs_to(other)
|
284
|
-
other.cmap = @cmap
|
285
|
-
other.collections = @collections
|
286
|
-
other.allowed_transitions = @allowed_transitions
|
287
|
-
other.xtitle = @xtitle
|
288
|
-
other.xname = @xname
|
289
|
-
other.xnamespace = @xnamespace
|
290
|
-
other.xpath_prefix = @xpath_prefix
|
291
|
-
other.xserver_url = @xserver_url
|
292
|
-
other.uribase = @uribase
|
293
|
-
other.meta = ServiceMeta.new(other) # hum ... #todo: versions as well ?
|
294
|
-
other.relman = @relman
|
295
|
-
other.batch_handler = @batch_handler
|
296
|
-
other.complex_types = @complex_types
|
297
|
-
other.function_imports = @function_imports
|
298
|
-
other.function_import_keys = @function_import_keys
|
299
|
-
other.type_mappings = @type_mappings
|
300
|
-
other.response_format_options = @response_format_options
|
301
|
-
other.final_template_func = @final_template_func
|
302
|
-
other.bugfix_create_response(@bugfix_create_response)
|
303
|
-
other
|
304
|
-
end
|
305
|
-
|
306
344
|
# this is a central place. We extend Sequel models with OData functionality
|
307
345
|
# The included/extended modules depends on the properties(eg, pks, field types) of the model
|
308
346
|
# we differentiate
|
@@ -451,7 +489,7 @@ module Safrano
|
|
451
489
|
klass.build_uri(@uribase)
|
452
490
|
|
453
491
|
# Output create (POST) as single entity (Standard) or as array (non-standard buggy)
|
454
|
-
klass.include(@
|
492
|
+
klass.include(@xbugfix_create_response ? Safrano::EntityCreateStandardOutput : Safrano::EntityCreateArrayOutput)
|
455
493
|
|
456
494
|
# define the most optimal casted_values method for the given model(klass)
|
457
495
|
if klass.casted_cols.empty?
|
@@ -557,10 +595,13 @@ module Safrano
|
|
557
595
|
end
|
558
596
|
|
559
597
|
def add_metadata_xml_entity_type(schema)
|
598
|
+
relman = Safrano::RelationManager.new
|
560
599
|
@collections.each do |klass|
|
561
600
|
enty = klass.add_metadata_rexml(schema)
|
562
|
-
klass.add_metadata_navs_rexml(enty,
|
601
|
+
klass.add_metadata_navs_rexml(enty, relman)
|
563
602
|
end
|
603
|
+
# return the collected rels needed later
|
604
|
+
relman
|
564
605
|
end
|
565
606
|
|
566
607
|
def add_metadata_xml_complex_types(schema)
|
@@ -571,8 +612,8 @@ module Safrano
|
|
571
612
|
@function_imports.each_value { |func| func.add_metadata_rexml(ec) }
|
572
613
|
end
|
573
614
|
|
574
|
-
def add_metadata_xml_associations(schema)
|
575
|
-
|
615
|
+
def add_metadata_xml_associations(schema, relman)
|
616
|
+
relman.each_rel do |rel|
|
576
617
|
rel.with_metadata_info(@xnamespace) do |name, bdinfo|
|
577
618
|
assoc = schema.add_element('Association', 'Name' => name)
|
578
619
|
bdinfo.each do |bdi|
|
@@ -585,7 +626,7 @@ module Safrano
|
|
585
626
|
end
|
586
627
|
end
|
587
628
|
|
588
|
-
def add_metadata_xml_entity_container(schema)
|
629
|
+
def add_metadata_xml_entity_container(schema, relman)
|
589
630
|
ec = schema.add_element('EntityContainer',
|
590
631
|
'Name' => @xname,
|
591
632
|
'm:IsDefaultEntityContainer' => 'true')
|
@@ -595,8 +636,9 @@ module Safrano
|
|
595
636
|
'Name' => klass.entity_set_name,
|
596
637
|
'EntityType' => klass.type_name)
|
597
638
|
end
|
639
|
+
|
598
640
|
# 3.b Association set's
|
599
|
-
|
641
|
+
relman.each_rel do |rel|
|
600
642
|
assoc = ec.add_element('AssociationSet',
|
601
643
|
'Name' => rel.name,
|
602
644
|
'Association' => "#{@xnamespace}.#{rel.name}")
|
@@ -645,17 +687,18 @@ module Safrano
|
|
645
687
|
schema = serv.add_element('Schema',
|
646
688
|
'Namespace' => @xnamespace,
|
647
689
|
'xmlns' => XMLNS::MSFT_ADO_2009_EDM)
|
648
|
-
|
649
|
-
|
690
|
+
|
691
|
+
# 1. a. all EntityType (and get the collected rels metadata)
|
692
|
+
relman = add_metadata_xml_entity_type(schema)
|
650
693
|
|
651
694
|
# 1. b. all ComplexType
|
652
695
|
add_metadata_xml_complex_types(schema)
|
653
696
|
|
654
697
|
# 2. Associations
|
655
|
-
add_metadata_xml_associations(schema)
|
698
|
+
add_metadata_xml_associations(schema, relman)
|
656
699
|
|
657
700
|
# 3. Enty container
|
658
|
-
add_metadata_xml_entity_container(schema)
|
701
|
+
add_metadata_xml_entity_container(schema, relman)
|
659
702
|
|
660
703
|
XML_PREAMBLE + doc.to_pretty_xml
|
661
704
|
end
|
@@ -737,8 +780,9 @@ module Safrano
|
|
737
780
|
end
|
738
781
|
|
739
782
|
# for OData V1
|
740
|
-
class ServiceV1 <
|
741
|
-
def initialize
|
783
|
+
class ServiceV1 < ServerApp
|
784
|
+
def initialize(template_instance: nil)
|
785
|
+
super
|
742
786
|
@data_service_version = '1.0'
|
743
787
|
end
|
744
788
|
|
@@ -762,8 +806,9 @@ module Safrano
|
|
762
806
|
end
|
763
807
|
|
764
808
|
# for OData V2
|
765
|
-
class ServiceV2 <
|
766
|
-
def initialize
|
809
|
+
class ServiceV2 < ServerApp
|
810
|
+
def initialize(template_instance: nil)
|
811
|
+
super
|
767
812
|
@data_service_version = '2.0'
|
768
813
|
end
|
769
814
|
|
@@ -785,7 +830,7 @@ module Safrano
|
|
785
830
|
|
786
831
|
# a virtual entity for the service metadata
|
787
832
|
class ServiceMeta
|
788
|
-
|
833
|
+
attr_reader :service
|
789
834
|
|
790
835
|
def initialize(service)
|
791
836
|
@service = service
|
data/lib/safrano/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: safrano
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- oz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|