Add search service and normalizer for list

This commit is contained in:
Urban Rotnik 2019-06-13 14:17:15 +02:00
parent 4f6397b5b9
commit 7fad5fc594
9 changed files with 3334 additions and 11 deletions

View file

@ -0,0 +1,70 @@
# frozen_string_literal: true
module ProtocolImporters
class SearchProtocolsService
extend Service
attr_reader :errors, :protocols_list
CONSTANTS = Constants::PROTOCOLS_IO_V3_API
def initialize(protocol_source:, query_params: {})
@protocol_source = protocol_source
@query_params = query_params
@errors = Hash.new { |h, k| h[k] = {} }
end
def call
return self unless valid?
api_response = api_client.protocol_list(@query_params)
@protocols_list = normalizer.normalize_list(api_response)
self
end
def succeed?
@errors.none?
end
private
def valid?
# try if key is not empty
@errors[:invalid_params][:key] = 'Key cannot be empty' if @query_params[:key].blank?
# try if page id is ok
if @query_params[:page_id] && !@query_params[:page_id].positive?
@errors[:invalid_params][:page_id] = 'Page needs to be positive'
end
# try if order_field is ok
if CONSTANTS[:available_order_fields]&.exclude? @query_params[:order_field].to_sym
@errors[:invalid_params][:order_field] = 'Order field is not ok'
end
# try if order dir is ok
if CONSTANTS[:available_order_dirs]&.exclude? @query_params[:order_dir].to_sym
@errors[:invalid_params][:order_dir] = 'Order dir is not ok'
end
# try if endpints exists
@errors[:invalid_params][:source_endpoint] = 'Wrong source endpoint' unless endpoint_name&.is_a?(String)
succeed?
end
def endpoint_name
Constants::PROTOCOLS_ENDPOINTS.dig(*@protocol_source.split('/').map(&:to_sym))
end
def api_client
"ProtocolImporters::#{endpoint_name}::ApiClient".constantize.new
end
def normalizer
"ProtocolImporters::#{endpoint_name}::ProtocolNormalizer".constantize.new
end
end
end

View file

@ -2,7 +2,7 @@
module ProtocolImporters
class ProtocolNormalizer
def normalize_all_protocols(_client_data)
def normalize_list(_client_data)
raise NotImplementedError
end

View file

@ -50,6 +50,24 @@ module ProtocolImporters
{ protocol: normalized_data }
end
def normalize_list(client_data)
# client_data is HttpParty ApiReponse object
protocols_hash = client_data.parsed_response.with_indifferent_access[:items]
normalized_data = {}
normalized_data[:protocols] = protocols_hash.map do |e|
{
"id": e[:id],
"title": e[:title],
"created_on": e[:created_on],
"authors": e[:authors].map { |a| a[:name] }.join(', '),
"nr_of_steps": e[:stats][:number_of_steps],
"nr_of_views": e[:stats][:number_of_views],
"uri": e[:uri]
}
end
normalized_data
end
end
end
end

View file

@ -203,6 +203,8 @@ class Constants
base_uri: 'https://www.protocols.io/api/v3/',
default_timeout: 10,
debug_level: :debug,
available_order_fields: %i(title created_on),
available_order_dirs: %i(asc desc),
endpoints: {
protocols: {
default_query_params: {

View file

@ -0,0 +1,94 @@
{
"protocols": [
{
"id": 22532,
"title": "Producing rooted cassava plantlets for use in pot experiments",
"created_on": 1556012701,
"authors": "Matema Imakumbili",
"nr_of_steps": 13,
"nr_of_views": 37,
"uri": "producing-rooted-cassava-plantlets-for-use-in-pot-z9cf92w"
},
{
"id": 832,
"title": "Preparation of Virus DNA from Seawater for Metagenomics",
"created_on": 1434495014,
"authors": "Matthew Sullivan Lab",
"nr_of_steps": 11,
"nr_of_views": 457,
"uri": "Preparation-of-Virus-DNA-from-Seawater-for-Metagen-c28yhv"
},
{
"id": 14506,
"title": "MALE CIRCUMCISION FOR PREVENTION OF HETEROSEXUAL TRANSMISSION OF HIV IN ADULT MALES IN SOWETO, what do indicators and incidence rates show?untitled protocol",
"created_on": 1533553359,
"authors": "Hillary Mukudu, Neil Martinson, Benn Sartorius",
"nr_of_steps": 0,
"nr_of_views": 5,
"uri": "male-circumcision-for-prevention-of-heterosexual-t-seiebce"
},
{
"id": 10927,
"title": "physiological and biochemical parameters",
"created_on": 1521454618,
"authors": "Amor Slama, Elhem Mallek-Maalej, Hatem Ben Mohamed, Thouraya Rhim, Leila Radhouane, Amor SLAMA",
"nr_of_steps": 0,
"nr_of_views": 34,
"uri": "physiological-and-biochemical-parameters-nwpdfdn"
},
{
"id": 822,
"title": "Iron Chloride Precipitation of Viruses from Seawater",
"created_on": 1434402745,
"authors": "Seth John, Bonnie Poulos, Christine Schirmer",
"nr_of_steps": 17,
"nr_of_views": 1805,
"uri": "Iron-Chloride-Precipitation-of-Viruses-from-Seawat-c2wyfd"
},
{
"id": 12115,
"title": "Measuring specific leaf area and water content",
"created_on": 1526074093,
"authors": "Etienne Laliberté",
"nr_of_steps": 33,
"nr_of_views": 259,
"uri": "measuring-specific-leaf-area-and-water-content-p3tdqnn"
},
{
"id": 1842,
"title": "Purification of viral assemblages from seawater in CsCl gradients",
"created_on": 1445287995,
"authors": "Janice E. Lawrence and Grieg F. Steward",
"nr_of_steps": 23,
"nr_of_views": 116,
"uri": "Purification-of-viral-assemblages-from-seawater-in-d2s8ed"
},
{
"id": 12540,
"title": "An improved primer set and PCR amplification protocol with increased specificity and sensitivity targeting the Symbiodinium ITS2 region using the SymVar primer pair",
"created_on": 1527418313,
"authors": "Benjamin Hume, Maren Ziegler, Christian Voolstra, Julie Poulain, Xavier Pochon, Sarah Romac, Emilie Boissin, Colomban de Vargas, Serge Planes, Patrick Wincker",
"nr_of_steps": 1,
"nr_of_views": 234,
"uri": "an-improved-primer-set-and-pcr-amplification-proto-qg4dtyw"
},
{
"id": 985,
"title": "NATURAL SEAWATER-BASED PRO99 MEDIUM",
"created_on": 1435347035,
"authors": "Chisholm Lab",
"nr_of_steps": 10,
"nr_of_views": 85,
"uri": "NATURAL-SEAWATER-BASED-PRO99-MEDIUM-c7zzp5"
},
{
"id": 1033,
"title": "SN Maintenance Medium for Synechococcus",
"created_on": 1435778857,
"authors": "JB Waterbury \u0026 JM Willey",
"nr_of_steps": 6,
"nr_of_views": 33,
"uri": "SN-Maintenance-Medium-for-Synechococcus-c9hz35"
}
]
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,52 @@
# frozen_string_literal: true
require 'rails_helper'
describe ProtocolImporters::SearchProtocolsService do
let(:service_call) do
ProtocolImporters::SearchProtocolsService.call(protocol_source: 'protocolsio/v3',
query_params: {
key: 'someting',
page_id: 5,
order_field: 'title',
order_dir: 'asc'
})
end
let(:service_call_with_wrong_params) do
ProtocolImporters::SearchProtocolsService.call(protocol_source: 'protocolsio3',
query_params: {
key: '',
page_id: -1,
order_field: 'gender',
order_dir: 'descc'
})
end
let(:normalized_list) do
JSON.parse(file_fixture('protocol_importers/normalized_list.json').read).to_h.with_indifferent_access
end
context 'when have invalid attributes' do
it 'returns an error when params are invalid' do
expect(service_call_with_wrong_params.errors).to have_key(:invalid_params)
end
end
context 'when have valid attributes' do
before do
client_data = double('api_response')
allow_any_instance_of(ProtocolImporters::ProtocolsIO::V3::ApiClient)
.to(receive(:protocol_list)
.and_return(client_data))
allow_any_instance_of(ProtocolImporters::ProtocolsIO::V3::ProtocolNormalizer)
.to(receive(:normalize_list).with(client_data)
.and_return(normalized_list))
end
it 'returns an error when params are invalid' do
expect(service_call.protocols_list).to be == normalized_list
end
end
end

View file

@ -3,11 +3,11 @@
require 'rails_helper'
describe ProtocolImporters::ProtocolNormalizer do
describe '.normalize_all_protocols' do
it { expect { subject.normalize_all_protocols({}) }.to raise_error(NotImplementedError) }
describe '.normalize_list' do
it { expect { subject.normalize_list({}) }.to raise_error(NotImplementedError) }
end
describe '.normalize_protocols' do
describe '.normalize_protocol' do
it { expect { subject.normalize_protocol({}) }.to raise_error(NotImplementedError) }
end
end

View file

@ -5,20 +5,27 @@ require 'rails_helper'
describe ProtocolImporters::ProtocolsIO::V3::ProtocolNormalizer do
let(:client_data) { double('api_response') }
let(:response) do
let(:protocols_io_single_protocol) do
JSON.parse(file_fixture('protocol_importers/protocols_io/v3/single_protocol.json').read)
.to_h.with_indifferent_access
end
let(:response_without_title) do
res_without_title = response
res_without_title = protocols_io_single_protocol
res_without_title[:protocol].reject! { |a| a == 'title' }
res_without_title
end
let(:normalized_result) do
JSON.parse(file_fixture('protocol_importers/normalized_single_protocol.json').read)
.to_h.with_indifferent_access
let(:protocols_io_list) do
JSON.parse(file_fixture('protocol_importers/protocols_io/v3/protocols.json').read).to_h.with_indifferent_access
end
let(:normalized_protocol) do
JSON.parse(file_fixture('protocol_importers/normalized_single_protocol.json').read).to_h.with_indifferent_access
end
let(:normalized_list) do
JSON.parse(file_fixture('protocol_importers/normalized_list.json').read).to_h.with_indifferent_access
end
describe '#normalize_protocol' do
@ -30,9 +37,9 @@ describe ProtocolImporters::ProtocolsIO::V3::ProtocolNormalizer do
context 'when have all data' do
it 'should normalize data correctly' do
allow(client_data).to receive_message_chain(:parsed_response)
.and_return(response)
.and_return(protocols_io_single_protocol)
expect(subject.normalize_protocol(client_data).deep_stringify_keys).to be == normalized_result
expect(subject.normalize_protocol(client_data).deep_stringify_keys).to be == normalized_protocol
end
end
@ -45,4 +52,12 @@ describe ProtocolImporters::ProtocolsIO::V3::ProtocolNormalizer do
end
end
end
describe '#normalize_list' do
it 'should normalize data correctly' do
allow(client_data).to receive_message_chain(:parsed_response).and_return(protocols_io_list)
expect(subject.normalize_list(client_data).deep_stringify_keys).to be == normalized_list
end
end
end