safrano 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fcb0478a7adf2f62f2530ede1bfe1ebee5b0261379a71d4aec54f3007094429f
4
- data.tar.gz: 95a5adbb64d6311d30dad9e4c6c5a2b5a54c4ab0dd788c00743d36a4dbee5cd4
3
+ metadata.gz: a14d6778d6391597537f6747dc2cdd650413bd45d8351af3ba427d349c90e887
4
+ data.tar.gz: f8f899d1d1cffd48701539e85240f7368eec5f85c6d0d1647f0448f55bdfde58
5
5
  SHA512:
6
- metadata.gz: aa50d7338736540e2ef60a2cded37b2993b8a485d4f760c7f06ddf0ff26ba4cbbf1aaaca6a618f6812c6c85cd8ac05f8d93b514799f311997639e1025e7c4da1
7
- data.tar.gz: 967000423228b25f80f070b53ccc2aafdad2e96ab3f6c96bfe17d6845e5d7bfef412dd3c5cd81a7b46c419769a3d0f743e2a74d1e656af983a4ad372e95c05f8
6
+ metadata.gz: dbe8f715a880590d6077f392408a50082e99cfd5f23b9648fd63c64a543c361a155cba6144a63da75a4c1e48f0e2ccb1da95d19729d49cb881b82100bc122b3c
7
+ data.tar.gz: 199026ff4cf9abc042cd547232f8aa9c251c6849f9e954fe6351da2b416b1cc87d3ad974d09bbf7c12122d1bff65ca1699556bffcaae563d329984ffacb5ea53
@@ -25,6 +25,7 @@ module Safrano
25
25
  # 4 55
26
26
  # 5 ,2
27
27
  # 6 2
28
+ DB_TYPE_GUID_RGX = /\A\s*(uuid)\s*\z/i.freeze
28
29
 
29
30
  DB_TYPE_FLOATP_RGX = /\A\s*(FLOAT)\s*(\(\s*(\d+)\s*\))?\s*\z/i.freeze
30
31
 
@@ -96,6 +97,13 @@ module Safrano
96
97
  end
97
98
  return if metadata[:edm_type]
98
99
 
100
+ # try Guid with db_type:
101
+
102
+ metadata[:edm_type] = if (DB_TYPE_GUID_RGX.match(props[:db_type]))
103
+ 'Edm.Guid'
104
+ end
105
+ return if metadata[:edm_type]
106
+
99
107
  # try with Sequel(ruby) type
100
108
  metadata[:edm_type] = case props[:type]
101
109
  when :integer
@@ -157,6 +165,7 @@ module Safrano
157
165
  extend OutputClassMethods
158
166
 
159
167
  def self.convert_from_urlparam(v)
168
+ # TODO this should use base64
160
169
  Contract.valid(v.dup.force_encoding('BINARY'))
161
170
  end
162
171
  end
@@ -247,6 +256,18 @@ module Safrano
247
256
  Contract::NOK
248
257
  end
249
258
  end
259
+
260
+ class Guid < UUIDTools::UUID
261
+ extend OutputClassMethods
262
+
263
+ def self.convert_from_urlparam(v)
264
+ Contract::NOK unless m = Filter::Parser::Token::GUIDRGX.match(v)
265
+
266
+ Contract.valid(UUIDTools::UUID.parse m[1])
267
+ rescue StandardError
268
+ Contract::NOK
269
+ end
270
+ end
250
271
  end
251
272
  end
252
273
  end
data/lib/odata/entity.rb CHANGED
@@ -380,9 +380,20 @@ module Safrano
380
380
  end
381
381
  end
382
382
 
383
- # for a single public key
384
- module EntitySinglePK
385
- include Entity
383
+ module PKUriWithFunc
384
+ def pk_uri
385
+ self.class.pk_castfunc.call(pk)
386
+ end
387
+
388
+ def media_path_id
389
+ pk_uri.to_s
390
+ end
391
+
392
+ def media_path_ids
393
+ [pk_uri]
394
+ end
395
+ end
396
+ module PKUriWithoutFunc
386
397
  def pk_uri
387
398
  pk
388
399
  end
@@ -395,6 +406,11 @@ module Safrano
395
406
  [pk]
396
407
  end
397
408
  end
409
+ # for a single public key
410
+ module EntitySinglePK
411
+ include Entity
412
+ # PKUriWithoutFunc or PKUriWithFunc will be included on startup
413
+ end
398
414
 
399
415
  # for multiple key
400
416
  module EntityMultiPK
@@ -419,7 +435,6 @@ module Safrano
419
435
  module EntityCreateStandardOutput
420
436
  # Json formatter for a create entity POST call / Standard version; return as json object
421
437
  def to_odata_create_json(request:)
422
- # TODO: Perf: reduce method call overhead
423
438
  # we added this redirection for readability and flexibility
424
439
  to_odata_json(request: request)
425
440
  end
@@ -428,7 +443,6 @@ module Safrano
428
443
  module EntityCreateArrayOutput
429
444
  # Json formatter for a create entity POST call Array version
430
445
  def to_odata_create_json(request:)
431
- # TODO: Perf: reduce method call overhead
432
446
  # we added this redirection for readability and flexibility
433
447
  to_odata_array_json(request: request)
434
448
  end
@@ -79,5 +79,9 @@ module Safrano
79
79
  end
80
80
  class DateTimeOffsetLit < Leave
81
81
  end
82
+
83
+ # Edm Guid 16 bytes
84
+ class Guid16 < Leave
85
+ end
82
86
  end
83
87
  end
@@ -174,6 +174,11 @@ module Safrano
174
174
  @cursor.update_state(tok, typ)
175
175
  grow_at_cursor(FPNumber.new(tok))
176
176
  end
177
+ when :GuidLit
178
+ with_accepted(tok, typ) do
179
+ @cursor.update_state(tok, typ)
180
+ grow_at_cursor(Guid16.new(tok))
181
+ end
177
182
  when :DecimalLit
178
183
  with_accepted(tok, typ) do
179
184
  @cursor.update_state(tok, typ)
@@ -15,65 +15,65 @@ module Safrano
15
15
  BINOBOOL = '[eE][qQ]|[LlgGNn][eETt]|[aA][nN][dD]|[oO][rR]'
16
16
  BINOARITHM = '[aA][dD][dD]|[sS][uU][bB]|[mM][uU][lL]|[dD][iI][vV]|[mM][oO][dD]'
17
17
  NOTRGX = 'not|NOT|Not'
18
- FPRGX = '\d+(?:\.\d+)?(?:e[+-]?\d+)?[df]?'
19
- DECIMALRGX = '\d+(?:\.\d+)[mM]'
18
+ FPRGX = '(\d+(?:\.\d+)?(?:e[+-]?\d+)?)[df]?'
19
+ DECIMALRGX = '(\d+(?:\.\d+))[mM]'
20
20
  QUALITRGX = '\w+(?:\/\w+)+'
21
21
  # datetime'yyyy-mm-ddThh:mm[:ss[.fffffff]]' NOTE: Spaces are not allowed between datetime and quoted portion.
22
22
  # datetime is case-insensitive
23
23
  DATIRGX = '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?:\:\d{2})?(?:\.\d{1,7})?'
24
- DATETIMERGX = /datetime'#{DATIRGX}[zZ]?'/i.freeze
25
- DATIOFFRGX = /datetimeoffset'#{DATIRGX}(?:[zZ]|[+-]\d{2}:\d{2})'/.freeze
26
-
27
- RGX = /(#{FUNCRGX})|(#{NULLRGX})|([(),])|(#{BINOBOOL})\s+|(#{BINOARITHM})|(#{NOTRGX})|#{QSTRINGRGX}|(#{DECIMALRGX})|(#{FPRGX})|(#{QUALITRGX})|(#{DATETIMERGX})|(#{DATIOFFRGX})|(\w+)|(')/.freeze
24
+ DATETIMERGX = /datetime'(#{DATIRGX}[zZ]?)'/i.freeze
25
+ DATIOFFRGX = /datetimeoffset'(#{DATIRGX}(?:[zZ]|[+-]\d{2}:\d{2}))'/i.freeze
26
+ GUIDRGX = /guid'([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})'/i.freeze
27
+ RGX = /(#{FUNCRGX})|(#{NULLRGX})|([(),])|(#{BINOBOOL})\s+|(#{BINOARITHM})|(#{NOTRGX})|#{QSTRINGRGX}|#{DECIMALRGX}|#{FPRGX}|(#{QUALITRGX})|#{DATETIMERGX}|#{DATIOFFRGX}|#{GUIDRGX}|(\w+)|(')/.freeze
28
28
 
29
29
  def each_typed_token(inp)
30
30
  typ = nil
31
31
 
32
32
  inp.scan(RGX) do |groups|
33
- idx = nil
34
- found = nil
35
33
  groups.each_with_index do |tok, i|
36
- if (found = tok)
37
- idx = i
34
+ if tok
35
+
36
+ typ = case i
37
+ when 0
38
+ :FuncTree
39
+ when 1
40
+ :NullLiteral
41
+ when 2
42
+ case tok
43
+ when '(', ')'
44
+ :Delimiter
45
+ when ','
46
+ :Separator
47
+ end
48
+ when 3
49
+ :BinopBool
50
+ when 4
51
+ :BinopArithm
52
+ when 5
53
+ :UnopTree
54
+ when 6
55
+ :QString
56
+ when 7
57
+ :DecimalLit
58
+ when 8
59
+ :FPNumber
60
+ when 9
61
+ :Qualit
62
+ when 10
63
+ :DateTimeLit
64
+ when 11
65
+ :DateTimeOffsetLit
66
+ when 12
67
+ :GuidLit
68
+ when 13
69
+ :Literal
70
+ when 14
71
+ :unmatchedQuote
72
+ end
73
+ yield tok, typ
38
74
  break
39
75
  end
40
76
  end
41
- typ = case idx
42
- when 0
43
- :FuncTree
44
- when 1
45
- :NullLiteral
46
- when 2
47
- case found
48
- when '(', ')'
49
- :Delimiter
50
- when ','
51
- :Separator
52
- end
53
- when 3
54
- :BinopBool
55
- when 4
56
- :BinopArithm
57
- when 5
58
- :UnopTree
59
- when 6
60
- :QString
61
- when 7
62
- :DecimalLit
63
- when 8
64
- :FPNumber
65
- when 9
66
- :Qualit
67
- when 10
68
- :DateTimeLit
69
- when 11
70
- :DateTimeOffsetLit
71
- when 12
72
- :Literal
73
- when 13
74
- :unmatchedQuote
75
- end
76
- yield found, typ
77
77
  end
78
78
  end
79
79
  end
@@ -71,7 +71,7 @@ module Safrano
71
71
  def accept?(tok, typ)
72
72
  case typ
73
73
  when :Literal, :NullLiteral, :Qualit, :QString, :FuncTree, :ArgTree,
74
- :UnopTree, :FPNumber, :DecimalLit, :DateTimeLit, :DateTimeOffsetLit
74
+ :UnopTree, :FPNumber, :DecimalLit, :DateTimeLit, :DateTimeOffsetLit, :GuidLit
75
75
  nil
76
76
  when :Delimiter
77
77
  if tok == '('
@@ -238,7 +238,7 @@ module Safrano
238
238
  def update_state(_tok, typ)
239
239
  case typ
240
240
  when :Literal, :NullLiteral, :Qualit, :QString, :FuncTree, :BinopBool, :BinopArithm,
241
- :UnopTree, :FPNumber, :DecimalLit, :DateTimeLit, :DateTimeOffsetLit
241
+ :UnopTree, :FPNumber, :DecimalLit, :DateTimeLit, :DateTimeOffsetLit, :GuidLit
242
242
  @state = :closed
243
243
  end
244
244
  end
@@ -304,7 +304,7 @@ module Safrano
304
304
  when :Separator
305
305
  @state = :sep
306
306
  when :Literal, :NullLiteral, :Qualit, :QString, :FuncTree, :FPNumber, :DecimalLit,
307
- :DateTimeLit, :DateTimeOffsetLit
307
+ :DateTimeLit, :DateTimeOffsetLit, :GuidLit
308
308
  @state = :val
309
309
  end
310
310
  end
@@ -335,7 +335,7 @@ module Safrano
335
335
  Parser::ErrorInvalidToken.new(tok, typ, self)
336
336
  end
337
337
  when :Literal, :NullLiteral, :Qualit, :QString, :FuncTree, :FPNumber, :DecimalLit,
338
- :DateTimeLit, :DateTimeOffsetLit
338
+ :DateTimeLit, :DateTimeOffsetLit, :GuidLit
339
339
  if (@state == :open) || (@state == :sep)
340
340
  Parser::ErrorInvalidArity.new(tok, typ, self) if @parent.arity_full?(@children.size)
341
341
  else
@@ -359,7 +359,9 @@ module Safrano
359
359
  # 1.53f --> value 1.53
360
360
  # 1.53d --> value 1.53
361
361
  # 1.53 --> value 1.53
362
- val[-1] =~ /[fd]/i ? super(val[0..-2]) : super(val)
362
+ # Note: the tokenizer has already dropped the not usefull string parts
363
+ # Note : we dont differentiate between Float and Double here
364
+ super(val)
363
365
  end
364
366
 
365
367
  def accept?(tok, typ)
@@ -376,13 +378,31 @@ module Safrano
376
378
  :number
377
379
  end
378
380
  end
381
+
382
+ # Edm guid
383
+ class Guid16
384
+ def accept?(tok, typ)
385
+ case typ
386
+ when :Delimiter, :Separator, :BinopBool, :BinopArithm
387
+ nil
388
+ else
389
+ Parser::ErrorInvalidToken.new(tok, typ, self)
390
+ end
391
+ end
392
+
393
+ def edm_type
394
+ :guid
395
+ end
396
+ end
397
+
379
398
  class DecimalLit
380
399
  def initialize(val)
381
400
  # 1.53m --> value 1.53
382
401
  # Warning, this assumes that the m|M part in the input is really not optional
402
+ # Note: the tokenizer has already dropped the not usefull string parts
383
403
  # cf. DECIMALRGX in token.rb
384
404
 
385
- super(val[0..-2])
405
+ super(val)
386
406
  end
387
407
 
388
408
  def accept?(tok, typ)
@@ -447,7 +467,8 @@ module Safrano
447
467
  class DateTimeLit
448
468
  def initialize(val)
449
469
  # datetime'2000-12-12T12:00:53' --> value 2000-12-12T12:00:53
450
- super(val[9..-2])
470
+ # Note: the tokenizer has already dropped the not usefull string parts
471
+ super(val)
451
472
  end
452
473
 
453
474
  def accept?(tok, typ)
@@ -467,7 +488,8 @@ module Safrano
467
488
  class DateTimeOffsetLit
468
489
  def initialize(val)
469
490
  # datetimeoffset'2000-12-12T12:00:53+02:00' --> value 2000-12-12T12:00:53+02:00
470
- super(val[15..-2])
491
+ # Note: the tokenizer has already dropped the not usefull string parts
492
+ super(val)
471
493
  end
472
494
 
473
495
  def accept?(tok, typ)
@@ -36,6 +36,9 @@ module Safrano
36
36
  Safrano::Edm::Edm::Double
37
37
  when 'DateTime'
38
38
  Safrano::Edm::Edm::DateTime
39
+ # UUID with uuidtools
40
+ when 'UUIDTools::UUID'
41
+ Safrano::Edm::Edm::Guid
39
42
  else
40
43
  t
41
44
  end
@@ -48,6 +48,11 @@ module Safrano
48
48
  # typically the block should contain the publication of the associations
49
49
  attr_accessor :deferred_iblock
50
50
 
51
+ # allows to override standard types
52
+ attr_accessor :type_mappings
53
+
54
+ attr_accessor :pk_castfunc
55
+
51
56
  # convention: entityType is the namepsaced Ruby Model class --> name is just to_s
52
57
  # Warning: for handling Navigation relations, we use anonymous collection classes
53
58
  # dynamically subtyped from a Model class, and in such an anonymous class
@@ -73,7 +78,6 @@ module Safrano
73
78
  end
74
79
 
75
80
  def reset
76
- # TODO: automatically reset all attributes?
77
81
  @deferred_iblock = nil
78
82
  @entity_set_name = nil
79
83
  @uri = nil
@@ -82,6 +86,8 @@ module Safrano
82
86
  @params = nil
83
87
  @cx = nil
84
88
  @cols_metadata = {}
89
+ @type_mappings = {}
90
+ @pk_castfunc = nil
85
91
  end
86
92
 
87
93
  def build_uri(uribase)
@@ -348,6 +354,13 @@ module Safrano
348
354
  @nav_entity_url_regexp = @nav_entity_attribs_keys.join('|')
349
355
  end
350
356
 
357
+ # allow to override default type settings on attribute level
358
+ # for example use Edm.Guid instead of Binary(Blob) or Edm.DateTimeOffset instead of Edm.DateTime
359
+ def with_attribute(asymb, &proc)
360
+ am = AttributeTypeMapping.builder(asymb, &proc).type_mapping
361
+ @type_mappings[asymb] = am
362
+ end
363
+
351
364
  EMPTYH = {}.freeze
352
365
 
353
366
  def build_default_template
@@ -359,16 +372,26 @@ module Safrano
359
372
  # cols needed catsting before final json output
360
373
  @casted_cols = {}
361
374
  db_schema.each do |col, props|
362
- # first check if we have user-defined type mapping
375
+ # first check if we have user-defined regexp based global type mapping
363
376
  usermap = nil
364
377
  dbtyp = props[:db_type]
365
378
  metadata = @cols_metadata[col]
366
379
  if service.type_mappings.values.find { |map| usermap = map.match(dbtyp) }
367
380
 
368
381
  metadata[:edm_type] = usermap.edm_type
382
+ if usermap.castfunc
383
+ @casted_cols[col] = usermap.castfunc
384
+ next # this will override our rules below !
385
+ end
386
+ end
369
387
 
370
- @casted_cols[col] = usermap.castfunc
371
- next # this will override our rules below !
388
+ # attribute specific type mapping
389
+ if colmap = @type_mappings[col]
390
+ metadata[:edm_type] = colmap.edm_type
391
+ if colmap.castfunc
392
+ @casted_cols[col] = colmap.castfunc
393
+ next # this will override our rules below !
394
+ end
372
395
  end
373
396
 
374
397
  if metadata[:edm_precision] && (metadata[:edm_type] =~ /\AEdm.Decimal\(/i)
@@ -401,14 +424,30 @@ module Safrano
401
424
  @casted_cols[col] = ->(x) { Base64.encode64(x) unless x.nil? } # Base64
402
425
  next
403
426
  end
427
+ # Odata V2 Spec:
428
+ # Literal form of Edm.Guid as used in URIs formatted as a JSON string
429
+ if metadata[:edm_type] == 'Edm.Guid'
430
+
431
+ if props[:type] == :blob # Edm.Guid but as 16 byte binary Blob on DB level, eg in Sqlite
432
+ @casted_cols[col] = ->(x) {
433
+ UUIDTools::UUID.parse_raw(x).to_s unless x.nil?
434
+ } # Base64
435
+ next
436
+ end
437
+ end
404
438
  # TODO: check this more in details
405
439
  # NOTE: here we use :type which is the sequel defined ruby-type
406
440
  if props[:type] == :datetime || props[:type] == :date
407
441
  # @casted_cols[col] = ->(x) { x&.iso8601 }
408
442
  @casted_cols[col] = ->(x) { x&.to_edm_json }
409
443
  end
444
+ end # db_schema.each do |col, props|
445
+
446
+ # check if key needs casting. Important for later entity-uri generation !
447
+ if primary_key.is_a? Symbol # single key field
448
+ @pk_castfunc = @casted_cols[primary_key]
410
449
  end
411
- end
450
+ end # build_casted_cols(service)
412
451
 
413
452
  def finalize_publishing(service)
414
453
  build_type_name
@@ -417,17 +456,17 @@ module Safrano
417
456
  build_default_template
418
457
 
419
458
  # add edm_types into metadata store
420
- @cols_metadata = {}
459
+
421
460
  db_schema.each do |col, props|
422
461
  metadata = @cols_metadata.key?(col) ? @cols_metadata[col] : (@cols_metadata[col] = {})
423
462
  Safrano.add_edm_types(metadata, props)
424
463
  end
425
464
 
426
465
  build_casted_cols(service)
427
- # unless @casted_cols.empty?
428
- # require 'pry'
429
- # binding.pry
430
- # end
466
+
467
+ # build pk regexps
468
+ prepare_pk
469
+
431
470
  # and finally build the path lists and allowed tr's
432
471
  build_attribute_path_list
433
472
  build_expand_path_list
@@ -440,7 +479,8 @@ module Safrano
440
479
  finalize_media if respond_to? :finalize_media
441
480
  end
442
481
 
443
- KEYPRED_URL_REGEXP = /\A\(\s*'?([\w=,'\s]+)'?\s*\)(.*)/.freeze
482
+ KEYPRED_URL_REGEXP = /\A\(\s*((?:guid)?'?[\w=,\-'\s]+'?)\s*\)(.*)/.freeze
483
+ GUIDRGX = /guid'([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})'/i.freeze
444
484
  def prepare_pk
445
485
  if primary_key.is_a? Array
446
486
  @pk_names = []
@@ -479,14 +519,30 @@ module Safrano
479
519
  else
480
520
  @pk_names = [primary_key.to_s]
481
521
  @pk_cast_from_string = nil
522
+
482
523
  kvpredicate = case db_schema[primary_key][:type]
483
524
  when :integer
525
+ # TODO harmonize this with primitive_types.rb convert_from_url
484
526
  @pk_cast_from_string = ->(str) { Integer(str) }
485
- '(\\d+)'
527
+ /(\d+)/.freeze
486
528
  else
487
- "'(\\w+)'"
529
+ metadata = @cols_metadata[primary_key]
530
+ case metadata[:edm_type]
531
+ when 'Edm.Guid'
532
+ if db_schema[primary_key][:type] == :blob # Edm.Guid but as 16byte binary Blob on DB
533
+ @pk_cast_from_string = ->(str) {
534
+ # TODO harmonize this with primitive_types.rb convert_from_url
535
+ # Sequel::SQL::Blob.new([ str.gsub('-', '') ].pack('H*')) }
536
+ Sequel::SQL::Blob.new(UUIDTools::UUID.parse(str).raw)
537
+ }
538
+ end
539
+ GUIDRGX
540
+ else
541
+ /'(\w+)'/.freeze
542
+ end
488
543
  end
489
544
  @iuk_rgx = /\A\s*#{kvpredicate}\s*\z/
545
+ # @entity_id_url_regexp = /\A\(\s*#{kvpredicate}\s*\)(.*)/.freeze
490
546
  @entity_id_url_regexp = KEYPRED_URL_REGEXP
491
547
  end
492
548
  end
@@ -663,7 +719,7 @@ module Safrano
663
719
  end
664
720
 
665
721
  def pk_lookup_expr(id)
666
- id
722
+ { primary_key => id }
667
723
  end
668
724
  end
669
725
 
@@ -262,19 +262,19 @@ module Safrano
262
262
 
263
263
  raise(Safrano::API::ModelNameError, modelklass) unless modelklass.is_a? Sequel::Model::ClassMethods
264
264
 
265
- if modelklass.ancestors.include? Safrano::Entity
266
- # modules were already added previously;
267
- # cleanup state to avoid having data from previous calls
268
- # mostly usefull for testing (eg API)
269
- modelklass.reset
270
- elsif modelklass.primary_key.is_a?(Array) # first API call... (normal non-testing case)
265
+ if modelklass.primary_key.is_a?(Array) # first API call... (normal non-testing case)
271
266
  modelklass.extend Safrano::EntityClassMultiPK
272
267
  modelklass.include Safrano::EntityMultiPK
273
268
  else
269
+
274
270
  modelklass.extend Safrano::EntityClassSinglePK
275
271
  modelklass.include Safrano::EntitySinglePK
272
+
276
273
  end
277
274
 
275
+ # initialize state
276
+ modelklass.reset
277
+
278
278
  # Media/Non-media
279
279
  if is_media
280
280
  modelklass.extend Safrano::EntityClassMedia
@@ -289,8 +289,12 @@ module Safrano
289
289
  modelklass.include Safrano::NonMediaEntity
290
290
  end
291
291
 
292
- modelklass.prepare_pk
292
+ # this needs to be done later as it can depend on overrided attribute specific Edm type
293
+ # eg. Edm-Guid. --> moved to finalize_publishing
294
+ # modelklass.prepare_pk
295
+
293
296
  modelklass.prepare_fields
297
+
294
298
  esname = (entity_set_name || modelklass).to_s.freeze
295
299
  serv_namespace = @xnamespace
296
300
  modelklass.instance_eval do
@@ -337,7 +341,7 @@ module Safrano
337
341
  end
338
342
 
339
343
  def with_db_type(*dbtypnams, &proc)
340
- m = TypeMapping.builder(*dbtypnams, &proc)
344
+ m = RgxTypeMapping.builder(*dbtypnams, &proc)
341
345
  @type_mappings[m.db_types_rgx] = m
342
346
  end
343
347
 
@@ -405,6 +409,17 @@ module Safrano
405
409
  vals
406
410
  end
407
411
  end
412
+ # needed for example if the pk is a guid, saved as binary on DB and the DB
413
+ # does not have a real uuid type but just return binary data...
414
+ # --> we need to convert the pk similarly as for json output
415
+ unless klass.primary_key.is_a?(Array) # we do this only for single PK
416
+ # guid in multi-PK not yet supported
417
+ if klass.pk_castfunc
418
+ klass.include Safrano::PKUriWithFunc
419
+ else
420
+ klass.include Safrano::PKUriWithoutFunc
421
+ end
422
+ end
408
423
  end
409
424
 
410
425
  # build allowed transitions (requires that @collections are filled and sorted for having a
@@ -10,8 +10,45 @@ module Safrano
10
10
  # Base class
11
11
  class TypeMapping
12
12
  attr_reader :castfunc
13
- attr_reader :db_types_rgx
14
13
  attr_reader :edm_type
14
+ end
15
+ # Model attribute (column) specific mapping
16
+ class AttributeTypeMapping < TypeMapping
17
+ attr_reader :attr_name
18
+
19
+ def initialize(builder)
20
+ @edm_type = builder.xedm_type
21
+ @castfunc = builder.castfunc
22
+ end
23
+ # wrapper to handle API
24
+ class Builder
25
+ attr_reader :xedm_type
26
+ attr_reader :castfunc
27
+ attr_reader :attr_name
28
+
29
+ def initialize(atnam)
30
+ @attr_name = atnam
31
+ end
32
+
33
+ def edm_type(input)
34
+ @xedm_type = input
35
+ end
36
+
37
+ def type_mapping
38
+ AttributeTypeMapping.new(self)
39
+ end
40
+ end
41
+
42
+ def self.builder(atnam, &proc)
43
+ builder = Builder.new(atnam)
44
+ builder.instance_eval(&proc)
45
+ builder
46
+ end
47
+ end
48
+
49
+ # Regexp based Global mapping
50
+ class RgxTypeMapping < TypeMapping
51
+ attr_reader :db_types_rgx
15
52
 
16
53
  # wrapper to handle API
17
54
  class Builder
@@ -56,7 +93,7 @@ module Safrano
56
93
 
57
94
  def type_mapping
58
95
  # TODO: perf; return always same object when called multiple times
59
- FixedTypeMapping.new(self)
96
+ RgxFixedTypeMapping.new(self)
60
97
  end
61
98
  end # Builder
62
99
 
@@ -94,7 +131,7 @@ module Safrano
94
131
  p1val = @md[1]
95
132
  instance_exec p1val, &@proc
96
133
 
97
- TypeMapping1Par.new(self)
134
+ RgxTypeMapping1Par.new(self)
98
135
  end
99
136
  end
100
137
  class Builder2Par < Builder
@@ -121,26 +158,26 @@ module Safrano
121
158
  p1val = @md[1]
122
159
  p2val = @md[2]
123
160
  instance_exec p1val, p2val, &@proc
124
- TypeMapping2Par.new(self)
161
+ RgxTypeMapping2Par.new(self)
125
162
  end
126
163
  end
127
164
  end
128
165
 
129
166
  # Fixed type (ie. without variable parts)
130
- class FixedTypeMapping < TypeMapping
167
+ class RgxFixedTypeMapping < RgxTypeMapping
131
168
  def initialize(builder)
132
169
  @edm_type = builder.xedm_type
133
170
  @castfunc = builder.castfunc
134
171
  end
135
172
  end
136
173
 
137
- class TypeMapping1Par < TypeMapping
174
+ class RgxTypeMapping1Par < RgxTypeMapping
138
175
  def initialize(builder)
139
176
  @edm_type = builder.xedm_type
140
177
  @castfunc = builder.castfunc
141
178
  end
142
179
  end
143
- class TypeMapping2Par < TypeMapping
180
+ class RgxTypeMapping2Par < RgxTypeMapping
144
181
  def initialize(builder)
145
182
  @edm_type = builder.xedm_type
146
183
  @castfunc = builder.castfunc
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Safrano
4
- VERSION = '0.6.1'
4
+ VERSION = '0.6.2'
5
5
  end
data/lib/safrano.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'json'
4
4
  require 'rexml/document'
5
+ require 'uuidtools'
5
6
  require_relative 'safrano/version'
6
7
  require_relative 'safrano/deprecation'
7
8
  require_relative 'safrano/core_ext'
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.6.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - oz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-07 00:00:00.000000000 Z
11
+ date: 2022-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '1.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: uuidtools
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2.2'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.2'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: rack-test
99
113
  requirement: !ruby/object:Gem::Requirement