class Safrano::Walker

handle navigation in the Datamodel tree of entities/attributes input is the url path. Url parameters ($filter etc…) are NOT handled here This uses a state transition algorithm

Constants

EMPTYSTR
NIL_SERVICE_FATAL
SLASH

Attributes

context[RW]
contexts[RW]
do_count[RW]

is $count requested?

end_context[RW]
error[RW]
media_value[R]

is $value (of media entity) requested?

path_done[RW]
path_remain[RW]
path_start[R]
raw_value[R]

is $value (of attribute) requested?

request[R]
status[RW]

Public Class Methods

new(service, path, request, content_id_refs = nil) click to toggle source
# File lib/odata/walker.rb, line 39
def initialize(service, path, request, content_id_refs = nil)
  raise NIL_SERVICE_FATAL unless service

  path = URI.decode_www_form_component(path)
  @context = service
  @content_id_refs = content_id_refs

  # needed because for function import we need access to the url parameters (req.params)
  # who contains the functions params
  @request = request

  @contexts = [@context]

  @path_start = @path_remain = if service
                                 unprefixed(service.xpath_prefix, path)
                               else # This is for batch function
                                 path
                               end
  @path_done = String.new
  @status = :start
  @end_context = nil
  @do_count = nil
  eo
end

Public Instance Methods

do_next_transition() click to toggle source
# File lib/odata/walker.rb, line 146
def do_next_transition
  @context, @status, @error = @tr_next.do_transition(@context)
  # little hack's
  case @status
    # we dont have the content-id references data on service level
    # but we have it here, so in case of a $content-id transition
    # the returned context is just the id, and we get the final result
    # entity reference here and place it in @context
  when :run_with_content_id
    do_run_with_content_id
  when :run_with_execute_func
    do_run_with_execute_func
  end

  @contexts << @context
  @path_remain = @tr_next.path_remain
  @path_done << @tr_next.path_done

  # little hack's
  state_mappings
end
do_run_with_content_id() click to toggle source

perform a content-id ($batch changeset ref) transition

# File lib/odata/walker.rb, line 100
def do_run_with_content_id
  if @content_id_refs.is_a? Hash
    if (@context = @content_id_refs[@context.to_s])
      @status = :run
    else
      @context = nil
      @status = :error
      # TODO: more appropriate error handling
      @error = Safrano::ErrorNotFound
    end
  else
    @context = nil
    @status = :error
    # TODO: more appropriate error handling
    @error = Safrano::ErrorNotFound
  end
end
do_run_with_execute_func() click to toggle source

execute function import with request parameters input: @context containt the function to exectute,

@request.params should normally contain the params

result: validate the params for the given function, execute the function and

return it's result back into @context,
and finaly set status :end   (or error if anyting went wrong )
# File lib/odata/walker.rb, line 124
def do_run_with_execute_func
  @context, @status, @error = @context.do_execute_func(@request)
end
eo() click to toggle source
# File lib/odata/walker.rb, line 168
def eo
  while @context
    get_next_transition
    if @tr_next
      do_next_transition
    else
      @context = nil
      @status = :error
      @error = Safrano::ErrorNotFoundSegment.new(@path_remain)
    end
  end
  # TODO: shouldnt we raise an error here if @status != :end ?
  return false unless @status == :end

  @end_context = @contexts.size >= 2 ? @contexts[-2] : @contexts[1]
end
finalize() click to toggle source
# File lib/odata/walker.rb, line 185
def finalize
  (@status == :end) ? Contract.valid(@end_context) : @error
end
get_next_transition() click to toggle source
# File lib/odata/walker.rb, line 74
def get_next_transition
  # this does not work if there are multiple valid transitions
  # like when we have attributes that are substring of each other
  # --> instead of using detect (ie take first transition)
  # we need to use select and then find the longest match
  #        tr_next = @context.allowed_transitions.detect do |t|
  #          t.do_match(@path_remain)
  #        end

  valid_tr = @context.allowed_transitions.select do |t|
    t.do_match(@path_remain)
  end

  # this is a very fragile and obscure but required hack (wanted: a
  # better one) to make attributes that are substrings of each other
  # work well
  @tr_next = if valid_tr
               if valid_tr.size == 1
                 valid_tr.first
               elsif valid_tr.size > 1
                 valid_tr.max_by { |t| t.match_result[1].size }
               end
             end
end
state_mappings() click to toggle source

little hacks… depending on returned state, set some attributes

# File lib/odata/walker.rb, line 129
def state_mappings
  case @status
  when :end_with_count
    @do_count = true
    @status = :end
  when :end_with_value
    @raw_value = true
    @status = :end
  when :end_with_media_value
    @media_value = true
    @status = :end
  when :run_with_links
    @do_links = true
    @status = :run
  end
end
unprefixed(prefix, path) click to toggle source
# File lib/odata/walker.rb, line 64
def unprefixed(prefix, path)
  if (prefix == EMPTYSTR) || (prefix == SLASH)
    path
  else
    #        path.sub!(/\A#{prefix}/, '')
    # TODO check
    path.sub(/\A#{prefix}/, EMPTYSTR)
  end
end