This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

Update Searchable#fetch to transform search on 'id'

  • Loading branch information...
Barrett Griffith
Barrett Griffith committed Nov 30, 2012
1 parent 61f235b commit 3ca0a3bf6c1310dc5b49efb3e7bf333b3bd768e5
@@ -0,0 +1,30 @@
Then /^the API will return a (\d+) http error message$/ do |status|
expect(last_response.status).to eq(status.to_i)
end
Then /^include all the fields available in the repository for that record$/ do
pending # express the regexp above with the code you wish you had
end
When /^I request details for items with ingestion identifiers "(.*?)"$/ do |arg1|
get "/api/v1/items/#{arg1}"
end
Then /^the API will return the items with the document identifiers "(.*?)"$/ do |arg1|
body = JSON.parse(last_response.body)
expected_ids = arg1.split(',')
body.delete_if{ |r| r['error'].present? }
expect(body.count).to eq(expected_ids.count)
docs = body.map { |r| r['doc'] }
returned_ids = docs.map { |d| d['_id'] }
expect(returned_ids - expected_ids).to eq([])
end
Then /^items that identify errors with ids "(.*?)"$/ do |missing_docs|
body = JSON.parse(last_response.body)
missing_ids = missing_docs.split(',')
error_docs = []
body.each { |r| error_docs << r if r['error'].present? }
error_ids = error_docs.map { |d| d['id'] }
expect(error_ids - missing_ids).to eq([])
end
@@ -0,0 +1,36 @@
Feature: Retrieve detailed information about items (UC008)
In order to use content within the DPLA
API users should be able to retrieve detailed information on items in the repository
# TODO: definition of 'basic' and 'detailed' sets of fields and options to retrieve them
Background:
Given that I have have a valid API key
And the default test dataset is loaded
Scenario: Try to retrieve an item that doesn't exist in the repository
When I request details for items with ingestion identifiers "I_DO_NOT_EXIST"
Then the API will return a 404 http error message
Scenario: Retrieve a single item from the repository with all fields
When I request details for items with ingestion identifiers "aaa"
Then the API will return the items with the document identifiers "A"
And include all the fields available in the repository for that record
@wip
Scenario: Retrieve a single item from the repository with specific fields
When I request details for an item with identifier "ACDEF"
And request the fields "title" and "description"
Then the API will return the item with the identifier "ACDEF"
And only include the "id", "title", and "description" fields in the record returned
Scenario: Retrieve multiple items with some missing
When I request details for items with ingestion identifiers "not_me,aaa,bbb,or_me"
Then the API will return the items with the document identifiers "A,B"
And items that identify errors with ids "not_me,or_me"
Scenario: Retrieve multiple items from the repository
When I request details for items with ingestion identifiers "aaa,bbb"
Then the API will return the items with the document identifiers "A,B"
@@ -15,8 +15,14 @@ def items
def fetch
ids = params[:ids].split(',')
results = V1::Item.fetch(ids)
render :json => render_json(results, params)
results = []
begin
results = V1::Item.fetch(ids)
status = 200
rescue
status = 404
end
render :json => render_json(results, params), :status => status
end
def render_json(results, params)
@@ -15,8 +15,10 @@
<li>#2890: <%= link_to nil, v1_api.items_path('some_invalid_field' => 'banana') %> Invalid field in query </li>
<li><%= link_to nil, v1_api.items_path('q' => 'banana', 'page_size' => '2') %> </li>
<li><%= link_to nil, v1_api.items_path('q' => 'banana', 'page_size' => '3', 'page' => '3') %> </li>
<li>UC008: <%= link_to nil, "#{v1_api.items_path}/A,B,C" %> A, B, C </li>
<li>UC008: <%= link_to nil, "#{v1_api.items_path}/A" %> A</li>
<li>UC008: <%= link_to nil, "#{v1_api.items_path}/aaa,bbb" %> A, B</li>
<li>UC008: <%= link_to nil, "#{v1_api.items_path}/aaa,bbb,ccc" %> A, B, C(Error Stub)</li>
<li>UC008: <%= link_to nil, "#{v1_api.items_path}/aaa" %> A</li>
<li>UC008: <%= link_to nil, "#{v1_api.items_path}/ccc" %> 404</li>
<li><%= link_to nil, v1_api.items_path('sort_by' => 'created') %></li>
<li><%= link_to nil, v1_api.items_path('sort_by' => 'created', 'sort_order' => 'desc') %></li>
<li><%= link_to nil, v1_api.items_path('fields' => 'title,description') %></li>
View
@@ -8,7 +8,10 @@ module Schema
'item' => {
'properties' => {
#NOTE: No longer needed now that the source data uses _id, I think. -phunk
#:id => { :type => 'string' },
'id' => {
:type => 'string',
:index => 'not_analyzed'
},
'@id' => { :type => 'string' },
'title' => { :type => 'string' },
'dplaContributor' => {
View
@@ -135,8 +135,29 @@ def get_search_size(params)
end
end
def fetch(id)
V1::Repository.fetch(id)
def fetch(ids)
doc_ids = []
missing_ids = []
ids.each do |id|
result = search({'id' => "#{id}"})
#Save the doc's '_id' if search returned a single 'id' match
doc_ids << result["docs"].first["_id"] if result["count"] == 1
#Save the 'id' as missing if search did not find the doc
missing_ids << id if result["count"] == 0
end
if doc_ids.empty? && ids.count == 1
raise NotFoundSearchError, "Document not found"
end
results = V1::Repository.fetch(doc_ids)
if missing_ids.any?
error_records = missing_ids.map { |id| { 'id' => id, 'error' => '404'} }
return results.concat(error_records)
end
results
end
def verbose_debug(search)
View
@@ -133,6 +133,7 @@
},
{
"_id": "A",
"id": "aaa",
"title": "title A",
"description": "",
"dplaContributor": null,
@@ -152,6 +153,7 @@
},
{
"_id": "B",
"id": "bbb",
"title": "title B",
"description": "",
"dplaContributor": null,
@@ -76,18 +76,64 @@ module Searchable
end
describe "#fetch" do
it "delegates to V1::Repository.fetch" do
let(:mock_result) {
{
"count" => 1,
"docs" => [
{"_id" => "1"}
]
}
}
let(:mock_result_b) {
{
"count" => 1,
"docs" => [
{"_id" => "2"}
]
}
}
let(:error_stub){
{
"id" => "ccc",
"error" => "404"
}
}
it "passes off 'id' lookup to #search" do
subject.should_receive(:search).with({"id" => "aaa" }) { mock_result }
subject.fetch(["aaa"])
end
it "delegates transformed ids to V1::Repository.fetch" do
repo_item_stub = stub
V1::Repository.should_receive(:fetch).with(2) { repo_item_stub }
expect(subject.fetch(2)).to eq repo_item_stub
subject.should_receive(:search).with({"id" => "aaa" }) { mock_result }
V1::Repository.should_receive(:fetch).with(["1"]) { repo_item_stub }
expect(subject.fetch(["aaa"])).to eq repo_item_stub
end
it "can accept more than one item" do
it "accepts more than one item" do
repo_item_stub_1 = stub
repo_item_stub_2 = stub
V1::Repository.should_receive(:fetch).with(["2","3"]) { [repo_item_stub_1, repo_item_stub_1] }
expect(subject.fetch(["2","3"])).to eq [repo_item_stub_1, repo_item_stub_1]
subject.stub(:search).twice.and_return(mock_result, mock_result_b)
V1::Repository.should_receive(:fetch).with(["1", "2"]) {
[repo_item_stub_1, repo_item_stub_2]
}
expect(subject.fetch(["aaa", "bbb"])).to eq [repo_item_stub_1, repo_item_stub_2]
end
it "can handle an item that does not exist" do
repo_item_stub_1 = stub
subject.stub(:search).twice.and_return(mock_result, {'count' => 0})
V1::Repository.should_receive(:fetch).with(["1"]) { [repo_item_stub_1] }
expect(subject.fetch(["aaa", "ccc"])).to eq [repo_item_stub_1, error_stub]
end
it "raises error when single item not found" do
subject.stub(:search) { {'count' => 0} }
expect { subject.fetch(["ccc"]) }.to raise_error(NotFoundSearchError)
end
end

0 comments on commit 3ca0a3b

Please sign in to comment.