Module: Aspera::Rest::List

Included in:
Api::AoC, Api::Faspex
Defined in:
lib/aspera/rest/list.rb

Overview

List and lookup methods for Rest::Client To be included in classes inheriting Rest::Client that require those methods.

Constant Summary collapse

MAX_ITEMS =

max: special query parameter: max number of items for list command

'max'
MAX_PAGES =

pmax: special query parameter: max number of pages for list command

'pmax'

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.lookup_entity_generic(entity:, value:, field: 'name') { ... } ⇒ Hash

Lookup entity by field and value. Extracts a single result from the list returned by the block.

Parameters:

  • entity (String) —

    Type of entity to lookup (path, and by default it is also the field name in result)

  • value (String) —

    Value to match against the field.

  • field (String) (defaults to: 'name') —

    Field to match in the hashes (defaults to 'name').

Yields:

  • [] A mandatory block that returns an Array of Hashes.

Returns:

  • (Hash) —

    The unique matching object.

Raises:



129
130
131
132
133
134
135
136
# File 'lib/aspera/rest/list.rb', line 129

def lookup_entity_generic(entity:, value:, field: 'name')
  Aspera.assert(block_given?, 'block required for lookup_entity_generic')
  found = yield
  Aspera.assert_array_all(found, Hash)
  found = found.select { |i| i[field].eql?(value) }
  return found.first if found.length.eql?(1)
  raise Cli::BadIdentifier.new(entity, value, field: field, count: found.length)
end

Instance Method Details

#list_entities_limit_offset_total_count(entity:, operation: 'GET', items_key: nil, query: nil) ⇒ Array<(Array<Hash>, Integer)>

Get a (full or partial) list of all entities of a given type. Using query: offset + limit And response total_count

Parameters:

  • entity (String, Symbol) —

    API endpoint of entity to list

  • items_key (String) (defaults to: nil) —

    Key in the result to get the list of items (Default: same as entity)

  • query (Hash, nil) (defaults to: nil) —

    Additional query parameters

Returns:

  • (Array<(Array<Hash>, Integer)>) —

    items, total_count



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/aspera/rest/list.rb', line 57

def list_entities_limit_offset_total_count(
  entity:,
  operation: 'GET',
  items_key: nil,
  query: nil
)
  entity = entity.to_s if entity.is_a?(Symbol)
  items_key = entity.split('/').last if items_key.nil?
  query = {} if query.nil?
  Aspera.assert_type(entity, String)
  Aspera.assert_type(items_key, String)
  Aspera.assert_type(query, Hash)
  Log.log.debug { "list_entities t=#{entity} k=#{items_key}" }
  Log.dump(:query, query)
  result = []
  offset = 0
  max_items = query.delete(MAX_ITEMS)
  remain_pages = query.delete(MAX_PAGES)
  # Merge default parameters, by default 100 per page
  query = {'limit'=> PER_PAGE_DEFAULT}.merge(query)
  total_count = nil
  call_args = {
    operation: operation,
    subpath:   entity,
    query:     query,
    headers:   {'Accept' => Mime::JSON}
  }
  loop do
    query['offset'] = offset
    page_result = call(**call_args)
    Aspera.assert_type(page_result[items_key], Array)
    result.concat(page_result[items_key])
    # Reach the limit set by user ?
    if !max_items.nil? && (result.length >= max_items)
      result = result.slice(0, max_items)
      break
    end
    total_count ||= page_result['total_count']
    break if result.length >= total_count
    remain_pages -= 1 unless remain_pages.nil?
    break if remain_pages == 0
    offset += page_result[items_key].length
    Parameters.instance.spinner_cb.call("#{result.length} / #{total_count || '?'}")
  end
  Parameters.instance.spinner_cb.call(action: :success)
  return result, total_count
end

#lookup_entity_by_field(entity:, value:, field: 'name', items_key: nil, query: :default) ⇒ Object

Lookup an entity id from its name. Uses query q if query is :default and field is name.

Parameters:

  • entity (String) —

    Type of entity to lookup, by default it is the path, and it is also the field name in result

  • value (String) —

    Value to lookup

  • field (String) (defaults to: 'name') —

    Field to match, by default it is 'name'

  • items_key (String) (defaults to: nil) —

    Key in the result to get the list of items (override entity)

  • query (Hash) (defaults to: :default) —

    Additional query parameters (Default: :default)



112
113
114
115
116
117
118
# File 'lib/aspera/rest/list.rb', line 112

def lookup_entity_by_field(entity:, value:, field: 'name', items_key: nil, query: :default)
  if query.eql?(:default)
    Aspera.assert_values(field, ['name']) { 'Default query field' }
    query = {'q'=> value}
  end
  lookup_entity_generic(entity: entity, field: field, value: value) { list_entities_limit_offset_total_count(entity: entity, items_key: items_key, query: query).first }
end

#lookup_with_q(entity, value:, field: 'name', query: {}) ⇒ Hash

Query entity by general search (read with parameter q)

Parameters:

  • entity (String) —

    Path of entity in API

  • value (String) —

    Value of field of searched entity

  • field (String) (defaults to: 'name') —

    Field of searched entity

  • query (Hash) (defaults to: {}) —

    Optional additional search query parameters

Returns:

  • (Hash) —

    A single entity matching the search, or an exception if not found or multiple found



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/aspera/rest/list.rb', line 25

def lookup_with_q(entity, value:, field: 'name', query: {})
  Aspera.assert_type(query, Hash) { 'query' }
  Aspera.assert_type(field, String) { 'field' }
  # returns entities matching the query (it matches against several fields in case insensitive way)
  # We don't do paging, as anyway, we look for only one match
  matching_items = read(entity, query.merge({'q' => value}))
  # API style: {totalcount:, ...} cspell: disable-line: TODO: is that total_count ?
  # @type [Array<Hash{String => String}>]
  matching_items = matching_items[entity] if matching_items.is_a?(Hash)
  Aspera.assert_type(matching_items, Array)
  case matching_items.length
  when 1 then return matching_items.first
  when 0 then raise EntityNotFound, %Q{No such #{entity}: "#{value}"}
  else
    # multiple case insensitive partial matches, try case insensitive full match
    # (AoC does not allow 2 entities with same case insensitive name, except for some, e.g. packages)
    value_matches = matching_items.select { |i| i[field].casecmp?(value) }
    case value_matches.length
    when 1 then return value_matches.first
    when 0 then raise Error, "#{entity}: Multiple case insensitive partial match for: \"#{value}\" in #{matching_items.map { |i| i[field] }.join(', ')} but no case insensitive full match. Please be more specific or give exact #{field}."
    else raise Error, "#{entity}: Multiple entities with #{field}: \"#{value}\". Please use the identifier instead."
    end
  end
end