safrano 0.0.6 → 0.0.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a69035d5b1015e36842490919163234c4ae55591657fb7d3b4b730b871c0035b
4
- data.tar.gz: 5c0024539a67f37cbf397975315066b1df803dd826b242b873147bbd1da60062
3
+ metadata.gz: cd0dda1e8d7fc80e01fc15b50b0893a31b189bb95e0138c8c1e49f4d3cdb11d5
4
+ data.tar.gz: 4155a3d6ca1dcd2817aab51bc85208ada311b8a120d4ed90e5a8fcd6c05d23b7
5
5
  SHA512:
6
- metadata.gz: 7538b83433db7381e77a34415e9cd4887cd2db20bfe8ba05db66e6d3703a0358e9f3024f137bddfca3b9b490caf3afbc2262b6b26514a36efeae792c8983a670
7
- data.tar.gz: b12e002bdbdeb826678d9cd1f8c1c9dce8bd11791adf8205464d12b115551bebbc59ddf4635d4406e93c4f5cee955f5356fea3d373857bac662ddbe5dd098ef7
6
+ metadata.gz: e1b61fcb3776b7435821121eb41b21afcf5fba422cb7665182ca7dc4d5e11155c3ba92a41eee7c9dc20730728c838033aa4b30367fd0e518d108547b7fbb7bf5
7
+ data.tar.gz: 270e6f1942254b239aed16b0bdb4ba8c5f48eba6fa676f9e9da9758e984c1cdd37a72cd355ed30326881013342538bf59b4de7b9143aabd2104d4c3fdf7faa0d
@@ -50,6 +50,7 @@ module OData
50
50
  attr_reader :nav_collection_attribs
51
51
  attr_reader :nav_entity_attribs
52
52
  attr_reader :data_fields
53
+ attr_reader :inlinecount
53
54
 
54
55
  attr_accessor :namespace
55
56
 
@@ -131,12 +132,25 @@ module OData
131
132
  @cx = @cx.select_all(entity_set_name.to_sym)
132
133
  end
133
134
 
135
+ def odata_get_inlinecount_w_sequel
136
+ return unless (icp = @params['$inlinecount'])
137
+
138
+ @inlinecount = if icp == 'allpages'
139
+ if is_a? Sequel::Model::ClassMethods
140
+ @cx.count
141
+ else
142
+ @cx.dataset.count
143
+ end
144
+ end
145
+ end
146
+
134
147
  def odata_get_apply_params_w_sequel
135
148
  @left_assocs = Set.new
136
149
  @right_assocs = Set.new
137
150
  odata_get_apply_filter_w_sequel
138
151
  odata_get_apply_order_w_sequel
139
152
  odata_get_do_assoc_joins_w_sequel
153
+ odata_get_inlinecount_w_sequel
140
154
 
141
155
  @cx = @cx.offset(@params['$skip']) if @params['$skip']
142
156
  @cx = @cx.limit(@params['$top']) if @params['$top']
@@ -169,6 +183,16 @@ module OData
169
183
  return BadRequestError if iskip.nil? || (iskip < 0)
170
184
  end
171
185
 
186
+ def check_u_p_inlinecount
187
+ return unless (icp = @params['$inlinecount'])
188
+
189
+ unless (icp == 'allpages') || (icp == 'none')
190
+ return BadRequestInlineCountParamError
191
+ end
192
+
193
+ nil
194
+ end
195
+
172
196
  def check_u_p_filter
173
197
  return unless @params['$filter']
174
198
 
@@ -182,7 +206,8 @@ module OData
182
206
  end
183
207
 
184
208
  def check_u_p_orderby
185
- # TODO: this should be moved into OData::Order somehow, at least partly
209
+ # TODO: this should be moved into OData::Order somehow,
210
+ # at least partly
186
211
  return unless (pordlist = @params['$orderby'].dup)
187
212
 
188
213
  pordlist.split(',').each do |pord|
@@ -224,7 +249,7 @@ module OData
224
249
  def check_url_params
225
250
  return nil unless @params
226
251
 
227
- check_u_p_top || check_u_p_skip || check_u_p_orderby || check_u_p_filter
252
+ check_u_p_top || check_u_p_skip || check_u_p_orderby || check_u_p_filter || check_u_p_inlinecount
228
253
  end
229
254
 
230
255
  def initialize_dataset
@@ -248,19 +273,29 @@ module OData
248
273
  [200, { 'Content-Type' => 'text/plain;charset=utf-8' },
249
274
  @cx.count.to_s]
250
275
  elsif req.accept?('application/json')
251
- [200, { 'Content-Type' => 'application/json;charset=utf-8' },
252
- to_odata_json(service: req.service)]
276
+ if req.walker.do_links
277
+ [200, { 'Content-Type' => 'application/json;charset=utf-8' },
278
+ to_odata_links_json(service: req.service)]
279
+ else
280
+ [200, { 'Content-Type' => 'application/json;charset=utf-8' },
281
+ to_odata_json(service: req.service)]
282
+ end
253
283
  else # TODO: other formats
254
284
  406
255
285
  end
256
286
  end
257
287
  end
258
288
 
289
+ def to_odata_links_json(service:)
290
+ { 'd' => service.get_coll_odata_links_h(array: get_a,
291
+ uribase: @uribase) }.to_json
292
+ end
293
+
259
294
  def to_odata_json(service:)
260
- expand = @params['$expand']
261
295
  { 'd' => service.get_coll_odata_h(array: get_a,
262
- expand: expand,
263
- uribase: @uribase) }.to_json
296
+ expand: @params['$expand'],
297
+ uribase: @uribase,
298
+ icount: @inlinecount) }.to_json
264
299
  end
265
300
 
266
301
  def get_a
@@ -40,32 +40,6 @@ class String
40
40
  end
41
41
  end
42
42
 
43
- # Handles filtering with ruby expressions
44
- # (eval and DB full scan used --> better avoid using this)
45
- module FilterWithRuby
46
- # this module requires the @fn attribute to exist where it is used
47
- def fn=(farg)
48
- @fn = farg
49
- @fn_tab = farg.split('/').map(&:to_sym)
50
- end
51
-
52
- # returns the attribute named "@fn" of object inp. This version assumes that
53
- # @fn can be a path like "address/city"
54
- def get_value(inp, colescev = '')
55
- obj = inp
56
- @fn_tab.each do |csymb|
57
- tmp = obj.send(csymb)
58
- if tmp.nil?
59
- obj = colescev
60
- break
61
- else
62
- obj = tmp
63
- end
64
- end
65
- obj
66
- end
67
- end
68
-
69
43
  # filter base class and subclass in our OData namespace
70
44
  module OData
71
45
  # handles associations in filter arguments
@@ -120,11 +94,6 @@ module OData
120
94
  new(matx)
121
95
  end
122
96
 
123
- # handle complex deep (relations) expressions with Ruby
124
- def self.new_full_match_complexpr_by_ruby(filterstr)
125
- ComplexFilterByRuby.new(filterstr)
126
- end
127
-
128
97
  def apply_to_dataset(dtcx)
129
98
  dtcx
130
99
  end
@@ -137,7 +106,6 @@ module OData
137
106
 
138
107
  # well...
139
108
  class EqualFilter < Filter
140
- include FilterWithRuby
141
109
  include FilterWithAssoc
142
110
  EQL = '[eE][qQ]|[LlgGNn][eETt]'.freeze
143
111
 
@@ -147,7 +115,7 @@ module OData
147
115
 
148
116
  def initialize(matx)
149
117
  super(matx)
150
- self.fn = matx[1]
118
+ @fn = matx[1]
151
119
  get_assoc if @fn
152
120
 
153
121
  @val = matx[3] ? matx[3].gsub("''", "'") : matx[4]
@@ -172,29 +140,34 @@ module OData
172
140
  y
173
141
  end
174
142
 
175
- def apply_to_dataset(dtcx)
176
- seqfn = get_qualified_fn(dtcx)
177
- # using @val in Procs below does not work reliably. Using a local var
178
- # seems to work better
179
- argval = @val
143
+ def apply_op_to_dataset(dtcx, lefval, rightval)
180
144
  case @op
181
145
  when 'eq'
182
- dtcx.where(seqfn => @val)
146
+ dtcx.where(lefval => rightval)
183
147
  when 'ne'
184
- dtcx.exclude(seqfn => @val)
148
+ dtcx.exclude(lefval => rightval)
185
149
  when 'le'
186
- dtcx.where { seqfn <= argval }
150
+ dtcx.where { lefval <= rightval }
187
151
  when 'ge'
188
- dtcx.where { seqfn >= argval }
152
+ dtcx.where { lefval >= rightval }
189
153
  when 'lt'
190
- dtcx.where { seqfn < argval }
154
+ dtcx.where { lefval < rightval }
191
155
  when 'gt'
192
- dtcx.where { seqfn > argval }
156
+ dtcx.where { lefval > rightval }
193
157
  else
194
158
  raise OData::FilterParseError
195
159
  end
196
160
  end
197
161
 
162
+ def apply_to_dataset(dtcx)
163
+ seqfn = get_qualified_fn(dtcx)
164
+ # using @val in Procs below does not work reliably. Using a local var
165
+ # seems to work better
166
+ argval = @val
167
+
168
+ apply_op_to_dataset(dtcx, seqfn, argval)
169
+ end
170
+
198
171
  def apply_to_object(inp)
199
172
  case @op
200
173
  when 'eq'
@@ -207,7 +180,132 @@ module OData
207
180
  end
208
181
  end
209
182
 
210
- # equality expressions with functions ... length(name) eq 2
183
+ class Func2a_EqualFilter < EqualFilter
184
+ FUNC = 'concat'.freeze
185
+ attr_reader :funcname
186
+
187
+ # like for concat(Name, 'xyz') EQ 'blablux'
188
+ def self.qualified_regexp(pathsrx)
189
+ /\s*(#{FUNC})\((#{pathsrx}),\s*(?:#{QUO})\)\s+(#{EQL})\s+(?:#{QUO})\s*/
190
+ end
191
+
192
+ def initialize(matx)
193
+ # super(matx)
194
+ @funcname = matx[1]
195
+ @fn = matx[2]
196
+ get_assoc if @fn
197
+ @farg = matx[3].gsub("''", "'")
198
+ @op = matx[4].downcase
199
+
200
+ @val = matx[5].gsub("''", "'")
201
+ end
202
+
203
+ def apply_to_dataset(dtcx)
204
+ seqfn = get_qualified_fn(dtcx)
205
+ # using @val in Procs below does not work reliably. Using a local var
206
+ # seems to work better
207
+ argval = @val
208
+ seqfunc = case @funcname
209
+ when 'concat'
210
+ Sequel.join([seqfn, @farg])
211
+ else
212
+ raise OData::FilterParseError
213
+ end
214
+ apply_op_to_dataset(dtcx, seqfunc, argval)
215
+ end
216
+ end
217
+ class Func2b_EqualFilter < EqualFilter
218
+ FUNC = 'concat'.freeze
219
+ attr_reader :funcname
220
+
221
+ # like for concat('xyz', Name) EQ 'blablux'
222
+ def self.qualified_regexp(pathsrx)
223
+ /\s*(#{FUNC})\((?:#{QUO}),\s*(#{pathsrx})\)\s+(#{EQL})\s+(?:#{QUO})\s*/
224
+ end
225
+
226
+ def initialize(matx)
227
+ # super(matx)
228
+ @funcname = matx[1]
229
+ @fn = matx[3]
230
+ get_assoc if @fn
231
+ @farg = matx[2].gsub("''", "'")
232
+ @op = matx[4].downcase
233
+
234
+ @val = matx[5].gsub("''", "'")
235
+ end
236
+
237
+ def apply_to_dataset(dtcx)
238
+ seqfn = get_qualified_fn(dtcx)
239
+ # using @val in Procs below does not work reliably. Using a local var
240
+ # seems to work better
241
+ argval = @val
242
+ seqfunc = case @funcname
243
+ when 'concat'
244
+ Sequel.join([@farg, seqfn])
245
+ else
246
+ raise OData::FilterParseError
247
+ end
248
+ apply_op_to_dataset(dtcx, seqfunc, argval)
249
+ end
250
+ end
251
+
252
+ class Func2c_EqualFilter < EqualFilter
253
+ FUNC = 'concat'.freeze
254
+ attr_reader :funcname
255
+
256
+ # like for concat(first_ame, last_name) EQ 'blablux'
257
+ def self.qualified_regexp(pathsrx)
258
+ /\s*(#{FUNC})\((#{pathsrx}),\s*(#{pathsrx})\)\s+(#{EQL})\s+(?:#{QUO})\s*/
259
+ end
260
+
261
+ def get_assoc
262
+ @assoc, @fn = @fn.split('/') if @fn.include?('/')
263
+ assoc1, @fn1 = @fn1.split('/') if @fn1.include?('/')
264
+ if assoc1 != @assoc
265
+ # TODO... handle this
266
+ raise OData::ServerError
267
+ end
268
+ end
269
+
270
+ def get_qualified_fn1(dtcx)
271
+ seqtn = if dtcx.respond_to? :table_name
272
+ @assoc ? @assoc.to_sym : dtcx.table_name
273
+ else
274
+ @assoc ? @assoc.to_sym : dtcx.model.table_name
275
+ end
276
+ Sequel[seqtn][@fn1.to_sym]
277
+ end
278
+
279
+ def initialize(matx)
280
+ # super(matx)
281
+ @funcname = matx[1]
282
+ @fn = matx[2]
283
+ @fn1 = matx[3]
284
+ get_assoc if @fn
285
+
286
+ @op = matx[4].downcase
287
+
288
+ @val = matx[5].gsub("''", "'")
289
+ end
290
+
291
+ def apply_to_dataset(dtcx)
292
+ seqfn = get_qualified_fn(dtcx)
293
+ seqfn1 = get_qualified_fn1(dtcx)
294
+ # using @val in Procs below does not work reliably. Using a local var
295
+ # seems to work better
296
+ argval = @val
297
+ seqfunc = case @funcname
298
+ when 'concat'
299
+ Sequel.join([seqfn, seqfn1])
300
+ else
301
+ raise OData::FilterParseError
302
+ end
303
+ apply_op_to_dataset(dtcx, seqfunc, argval)
304
+ end
305
+ end
306
+
307
+ # equality expressions with functions having 1 parameter
308
+ # like for length(name) eq 2
211
309
  class FuncEqualFilter < EqualFilter
212
310
  FUNC = 'length|trim|tolower|toupper'.freeze
213
311
 
@@ -220,29 +318,12 @@ module OData
220
318
  def initialize(matx)
221
319
  super(matx)
222
320
  @funcname = matx[1]
223
- self.fn = matx[2]
321
+ @fn = matx[2]
224
322
  get_assoc if @fn
225
323
 
226
- @val = matx[4] ? matx[4].gsub("''", "'") : matx[5]
227
-
228
324
  @op = matx[3].downcase
229
- end
230
-
231
- # ugly hack... but working
232
- def gen_sql(dtcx)
233
- # handle ambiguous column names (joins) by qualifiying the names
234
- # seqfn = @assoc ? Sequel[@assoc.to_sym][@fn.to_sym] : @fn.to_sym
235
- # handle ambiguous column names (joins) by qualifiying the names
236
- # for the main table as well
237
- # TODO: find a better way to differentiate between the two types
238
- # of dtcx : Model or Dataset
239
325
 
240
- # DONE: same handling for order and substring and everywhere where
241
- # qualified fieldnames could be needed (uses attrib path regexp)
242
- x = apply_to_dataset(dtcx)
243
- # ugly ugly hack :-(
244
- y = x.unordered.sql.sub(x.unfiltered.unordered.sql + ' WHERE', '')
245
- y
326
+ @val = matx[4] ? matx[4].gsub("''", "'") : matx[5]
246
327
  end
247
328
 
248
329
  def apply_to_dataset(dtcx)
@@ -264,22 +345,7 @@ module OData
264
345
  raise OData::FilterParseError
265
346
  end
266
347
 
267
- case @op
268
- when 'eq'
269
- dtcx.where(seqfunc => argval)
270
- when 'ne'
271
- dtcx.exclude(seqfunc => argval)
272
- when 'le'
273
- dtcx.where { seqfunc <= argval }
274
- when 'ge'
275
- dtcx.where { seqfunc >= argval }
276
- when 'lt'
277
- dtcx.where { seqfunc < argval }
278
- when 'gt'
279
- dtcx.where { seqfunc > argval }
280
- else
281
- raise OData::FilterParseError
282
- end
348
+ apply_op_to_dataset(dtcx, seqfunc, argval)
283
349
  end
284
350
  end
285
351
 
@@ -290,7 +356,6 @@ module OData
290
356
 
291
357
  # for substringof('value', field)
292
358
  class SubstringOfFilterSig1 < FilterWithKeyword
293
- include FilterWithRuby
294
359
  include FilterWithAssoc
295
360
 
296
361
  def self.qualified_regexp(paths_rx)
@@ -303,8 +368,8 @@ module OData
303
368
 
304
369
  def initialize(matx)
305
370
  super(matx)
306
- # binding.pry
307
- self.fn = matx[4]
371
+
372
+ @fn = matx[4]
308
373
  get_assoc if @fn
309
374
  # @val = matx[2].strip_single_quote
310
375
  @val = matx[2] ? matx[2].gsub("''", "'") : matx[3]
@@ -328,19 +393,14 @@ module OData
328
393
  def apply_to_dataset(dtcx)
329
394
  dtcx.where(whcl(dtcx))
330
395
  end
331
-
332
- def apply_to_object(inp)
333
- get_value(inp).include?(@val)
334
- end
335
396
  end
336
397
  # for substringof(field,'value')
337
398
  class SubstringOfFilterSig2 < FilterWithKeyword
338
- include FilterWithRuby
339
399
  include FilterWithAssoc
340
400
 
341
401
  def initialize(matx)
342
402
  super(matx)
343
- self.fn = matx[2]
403
+ @fn = matx[2]
344
404
  get_assoc if @fn
345
405
  @val = matx[3]
346
406
  @keyword = matx[1]
@@ -351,15 +411,10 @@ module OData
351
411
  def apply_to_dataset(dtcx)
352
412
  dtcx
353
413
  end
354
-
355
- def apply_to_object(inp)
356
- get_value(inp).include?(@val)
357
- end
358
414
  end
359
415
 
360
416
  # Filter by start/end with
361
417
  class StartOrEndsWithFilter < FilterWithKeyword
362
- include FilterWithRuby
363
418
  include FilterWithAssoc
364
419
  # DONE: better handle quotes vs not-quotes. Unblanced quotes are now handled
365
420
  # example : startswith(year, 190')
@@ -372,21 +427,11 @@ module OData
372
427
  super(matx)
373
428
  # DONE: the regexp should only match on known field names...
374
429
  # --> use qualified_regexp(attr_paths_rgx)
375
- self.fn = matx[2]
430
+ @fn = matx[2]
376
431
  get_assoc if @fn
377
432
  # double quotes need to be unescaped
378
433
  @val = matx[3] ? matx[3].gsub("''", "'") : matx[4]
379
434
  @keyword = matx[1]
380
- ve = Regexp.escape(@val)
381
- # used for "filter with ruby"
382
- case @keyword
383
- when 'startswith'
384
- @startend_rgx = Regexp.new("\A#{ve}")
385
- when 'endswith'
386
- @startend_rgx = Regexp.new("#{ve}\z")
387
- else
388
- raise FilterParseError
389
- end
390
435
  end
391
436
 
392
437
  def whcl(dtcx)
@@ -412,10 +457,6 @@ module OData
412
457
  def apply_to_dataset(dtcx)
413
458
  dtcx.where(whcl(dtcx))
414
459
  end
415
-
416
- def apply_to_object(inp)
417
- get_value(inp) =~ @startend_rgx
418
- end
419
460
  end
420
461
 
421
462
  FILTER_CLASSES = [EqualFilter,
@@ -435,6 +476,9 @@ module OData
435
476
  # list of active Subfilter classes. The ordering is important
436
477
  SUBFILTERS = [EqualFilter,
437
478
  FuncEqualFilter,
479
+ Func2a_EqualFilter,
480
+ Func2b_EqualFilter,
481
+ Func2c_EqualFilter,
438
482
  SubstringOfFilterSig1,
439
483
  StartOrEndsWithFilter].freeze
440
484
  # for counting number of AND OR's
@@ -487,39 +531,4 @@ module OData
487
531
  dtcx.where(Sequel.lit(@osql))
488
532
  end
489
533
  end
490
-
491
- # Handle complex filter expression with Ruby
492
- class ComplexFilterByRuby < Filter
493
- def initialize(filterstr)
494
- @subf = []
495
- @f = nil
496
- @rbcode = filterstr.dup
497
- @rbcode.with_mask_quoted_substrings! do |_s|
498
- SUBFILTERS.each { |klass| init_subfilter(klass) }
499
- downcase_and_or
500
- end
501
- end
502
-
503
- # downcase AND OR in @rbcode otherwise it is seen as a Ruby constant
504
- # instead as a ruby langu keyword
505
- def downcase_and_or
506
- @rbcode.gsub!(/(OR|Or|AND|And)/) do |_mx|
507
- Regexp.last_match[1].downcase
508
- end
509
- end
510
-
511
- def init_subfilter(subfiltclass)
512
- @rbcode.gsub!(subfiltclass.regexp) do |_mx|
513
- @f = subfiltclass.new(Regexp.last_match)
514
- @subf << @f
515
- "@subf[#{@subf.size - 1}].apply_to_object(@o)"
516
- end
517
- end
518
-
519
- def apply_to_object(inp)
520
- @o = inp
521
- b = binding
522
- eval(@rbcode, b)
523
- end
524
- end
525
534
  end
data/lib/odata/entity.rb CHANGED
@@ -17,6 +17,7 @@ module OData
17
17
  alltr = [
18
18
  Safrano::TransitionEnd,
19
19
  Safrano::TransitionCount,
20
+ Safrano::TransitionLinks,
20
21
  Safrano::Transition.new(%r{\A/(#{aurgx})(.*)\z},
21
22
  trans: 'transition_attribute')
22
23
  ]
@@ -42,6 +43,10 @@ module OData
42
43
  [self, :end]
43
44
  end
44
45
 
46
+ def transition_links(_match_result)
47
+ [self, :run_with_links]
48
+ end
49
+
45
50
  def transition_attribute(match_result)
46
51
  attrib = match_result[1]
47
52
  # [values[attrib.to_sym], :run]
@@ -97,6 +102,7 @@ module OData
97
102
  def to_odata_json(service:)
98
103
  { 'd' => service.get_entity_odata_h(entity: self,
99
104
  expand: @params['$expand'],
105
+ # links: @do_links,
100
106
  uribase: @uribase) }.to_json
101
107
  end
102
108
 
@@ -120,6 +126,7 @@ module OData
120
126
  def odata_get(req)
121
127
  @params = req.params
122
128
  @uribase = req.uribase
129
+ @do_links = req.walker.do_links
123
130
  if req.accept?('application/json')
124
131
  [200, { 'Content-Type' => 'application/json;charset=utf-8' },
125
132
  to_odata_json(service: req.service)]
data/lib/odata/error.rb CHANGED
@@ -49,6 +49,11 @@ module OData
49
49
  HTTP_CODE = 400
50
50
  @msg = 'Bad Request: Syntax error in Filter'
51
51
  end
52
+ # for $inlinecount error
53
+ class BadRequestInlineCountParamError < BadRequestError
54
+ HTTP_CODE = 400
55
+ @msg = 'Bad Request: wrong $inlinecount parameter'
56
+ end
52
57
  # http not found
53
58
  class ErrorNotFound
54
59
  extend Error
data/lib/odata/walker.rb CHANGED
@@ -25,6 +25,9 @@ module OData
25
25
  # is $value requested?
26
26
  attr_reader :raw_value
27
27
 
28
+ # are $links requested ?
29
+ attr_reader :do_links
30
+
28
31
  def initialize(service, path)
29
32
  path = URI.decode_www_form_component(path)
30
33
  @context = service
@@ -82,13 +85,16 @@ module OData
82
85
  @path_remain = @tr_next.path_remain
83
86
  @path_done << @tr_next.path_done
84
87
  # little hack's
85
- if @status == :end_with_count
88
+ case @status
89
+ when :end_with_count
86
90
  @do_count = true
87
91
  @status == :end
88
- end
89
- if @status == :end_with_value
92
+ when :end_with_value
90
93
  @raw_value = true
91
94
  @status == :end
95
+ when :run_with_links
96
+ @do_links = true
97
+ @status = :run
92
98
  end
93
99
  else
94
100
  @context = nil
data/lib/safrano_core.rb CHANGED
@@ -85,5 +85,7 @@ module Safrano
85
85
  trans: 'transition_count')
86
86
  TransitionValue = Transition.new('(\A\/\$value)(.*)\z',
87
87
  trans: 'transition_value')
88
+ TransitionLinks = Transition.new('(\A\/\$links)(.*)\z',
89
+ trans: 'transition_links')
88
90
  attr_accessor :allowed_transitions
89
91
  end
data/lib/service.rb CHANGED
@@ -74,6 +74,12 @@ module OData
74
74
  end
75
75
  end
76
76
 
77
+ # handle $links ... Note: $expand seems to be ignored when $links
78
+ # are requested
79
+ def get_entity_odata_link_h(entity:, uribase:)
80
+ hres = { uri: entity.uri(uribase) }
81
+ end
82
+
77
83
  def get_entity_odata_h(entity:, expand: nil, uribase:)
78
84
  hres = {}
79
85
  hres['__metadata'] = entity.metadata_h(uribase: uribase)
@@ -511,7 +517,7 @@ module OData
511
517
  @data_service_version = '1.0'
512
518
  end
513
519
 
514
- def get_coll_odata_h(array:, expand: nil, uribase:)
520
+ def get_coll_odata_h(array:, expand: nil, uribase:, icount: nil)
515
521
  array.map do |w|
516
522
  get_entity_odata_h(entity: w,
517
523
  expand: expand,
@@ -530,13 +536,23 @@ module OData
530
536
  @data_service_version = '2.0'
531
537
  end
532
538
 
533
- def get_coll_odata_h(array:, expand: nil, uribase:)
534
- { 'results' =>
535
- array.map do |w|
536
- get_entity_odata_h(entity: w,
537
- expand: expand,
538
- uribase: uribase)
539
- end }
539
+ def get_coll_odata_links_h(array:, uribase:)
540
+ array.map do |w|
541
+ get_entity_odata_link_h(entity: w, uribase: uribase)
542
+ end
543
+ end
544
+
545
+ def get_coll_odata_h(array:, expand: nil, uribase:, icount: nil)
546
+ res = array.map do |w|
547
+ get_entity_odata_h(entity: w,
548
+ expand: expand,
549
+ uribase: uribase)
550
+ end
551
+ if icount
552
+ { 'results' => res, '__count' => icount }
553
+ else
554
+ { 'results' => res }
555
+ end
540
556
  end
541
557
 
542
558
  def get_emptycoll_odata_h
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.0.6
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - D.M.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-19 00:00:00.000000000 Z
11
+ date: 2019-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -66,8 +66,7 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.51'
69
- description: Safrano is a small experimental OData server framework based on Ruby,
70
- Rack and Sequel.
69
+ description: Safrano is a small OData server framework based on Ruby, Rack and Sequel.
71
70
  email: dm@0data.dev
72
71
  executables: []
73
72
  extensions: []