# frozen_string_literal: true module ShotgunApiRuby class Entities def initialize(connection, type) @connection = connection.dup @type = type @connection.url_prefix = "#{@connection.url_prefix}/entity/#{type}" end attr_reader :connection, :type def first( fields: nil, sort: nil, filter: nil, retired: nil, include_archived_projects: nil, logical_operator: 'and' ) all( fields: fields, sort: sort, filter: filter, retired: retired, logical_operator: logical_operator, include_archived_projects: include_archived_projects, page_size: 1 ).first end def find(id, fields: nil, retired: nil, include_archived_projects: nil) params = Params.new params.add_fields(fields) params.add_options(retired, include_archived_projects) resp = @connection.get(id.to_s, params) resp_body = JSON.parse(resp.body) if resp.status >= 300 raise "Error while getting #{type}: #{resp_body['errors']}" end entity = resp_body["data"] Entity.new( entity['type'], OpenStruct.new(entity['attributes']), entity['relationships'], entity['id'], entity['links'] ) end def all( fields: nil, logical_operator: 'and', sort: nil, filter: nil, page: nil, page_size: nil, retired: nil, include_archived_projects: nil ) if filter && !filters_are_simple?(filter) return search( fields: fields, logical_operator: logical_operator, sort: sort, filter: filter, page: page, page_size: page_size, retired: retired, include_archived_projects: include_archived_projects ) end params = Params.new params.add_fields(fields) params.add_sort(sort) params.add_filter(filter) params.add_page(page, page_size) params.add_options(retired, include_archived_projects) resp = @connection.get('', params) resp_body = JSON.parse(resp.body) if resp.status >= 300 raise "Error while getting #{type}: #{resp_body['errors']}" end resp_body["data"].map do |entity| Entity.new( entity['type'], OpenStruct.new(entity['attributes']), entity['relationships'], entity['id'], entity['links'] ) end end def search( fields: nil, logical_operator: 'and', sort: nil, filter: nil, page: nil, page_size: nil, retired: nil, include_archived_projects: nil ) if filter.nil? || filters_are_simple?(filter) return all( fields: fields, logical_operator: logical_operator, sort: sort, filter: filter, page: page, page_size: page_size, retired: retired, include_archived_projects: include_archived_projects ) end params = Params.new params.add_fields(fields) params.add_sort(sort) params.add_page(page, page_size) params.add_options(retired, include_archived_projects) new_filter = {} if filter.is_a?(Hash) new_filter[:conditions] = (filter[:conditions] || translate_complex_to_sg_filters(filter)) new_filter[:logical_operator] = filter[:logical_operator] || filter['logical_operator'] || logical_operator else new_filter[:conditions] = filter new_filter[:logical_operator] = logical_operator end filter = new_filter resp = @connection.post('_search', params) do |req| if filter.is_a? Array req.headers["Content-Type"] = 'application/vnd+shotgun.api3_array+json' else req.headers['Content-Type'] = 'application/vnd+shotgun.api3_hash+json' end req.body = params.to_h.merge(filters: filter).to_json pp JSON.parse(req.body) end resp_body = JSON.parse(resp.body) if resp.status >= 300 raise "Error while getting #{type}: #{resp_body['errors']}" end resp_body["data"].map do |entity| Entity.new( entity['type'], OpenStruct.new(entity['attributes']), entity['relationships'], entity['id'], entity['links'] ) end end private def filters_are_simple?(filters) return false if filters.is_a? Array filters.values.all? do |filter_val| (filter_val.is_a?(Integer) || filter_val.is_a?(String) || filter_val.is_a?(Symbol)) || (filter_val.is_a?(Array) && filter_val.all?{ |val| val.is_a?(String) || val.is_a?(Symbol) || val.is_a?(Integer) } ) end end def translate_complex_to_sg_filters(filters) # We don't know how to translate anything but hashes return filters if !filters.is_a?(Hash) filters.each.with_object([]) do |item, result| field, value = item case value when String, Symbol, Integer, Float result << [field, "is", value] when Hash value.each do |subfield, subvalue| sanitized_subfield = "#{field.capitalize}.#{subfield}" unless subfield.to_s.include?(".") case subvalue when String, Symbol, Integer, Float result << ["#{field}.#{sanitized_subfield}", "is", subvalue] when Array result << ["#{field}.#{sanitized_subfield}", "in", subvalue] else raise "This case is too complex to auto-translate. Please use shotgun query syntax." end end when Array result << [field, "in", value] else raise "This case is too complex to auto-translate. Please use shotgun query syntax." end end end end end