Skip to content

Commit

Permalink
Implement fully case insensitive fallback term search
Browse files Browse the repository at this point in the history
Only triggered if exact search returns no results.
Sends ILIKE operator through to client.find
  • Loading branch information
kspurgin committed Oct 21, 2024
1 parent 91d56d1 commit 0a16eb3
Show file tree
Hide file tree
Showing 6 changed files with 408 additions and 41 deletions.
29 changes: 22 additions & 7 deletions lib/collectionspace/mapper/searcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,13 @@ def call(value:, type:, subtype: nil)

attr_reader :client, :active, :search_fields

def case_swap(string)
string.match?(/[A-Z]/) ? string.downcase : string.capitalize
end

def get_response(value, type, subtype)
def get_response(value, type, subtype, operator = "=")
response = client.find(
type: type,
subtype: subtype,
value: value,
field: search_field(type)
field: search_field(type),
operator: operator
)
rescue => e
puts e.message
Expand All @@ -50,6 +47,10 @@ def lookup_search_field(type)

def parse_response(response)
parsed = response.parsed["abstract_common_list"]
return parsed if parsed["list_item"].is_a?(Array)

parsed["list_item"] = [parsed["list_item"]]
parsed
rescue => e
puts e.message
nil
Expand Down Expand Up @@ -83,7 +84,21 @@ def search_response(value, type, subtype)
as_is = get_response(value, type, subtype)
return as_is if response_usable?(as_is)

get_response(case_swap(value), type, subtype)
case_insensitive_response(value, type, subtype)
end

def case_insensitive_response(value, type, subtype)
response = get_response(value, type, subtype, "ILIKE")
return nil unless response_usable?(response)

displayname = response.dig("list_item", 0, "displayName") ||
response.dig("list_item", 0, "termDisplayName")
warning = {
category: "case_insensitive_match",
message: "Searched: #{value}. Using: #{displayname}"
}
response["warnings"] = [warning]
response
end
end
end
Expand Down
16 changes: 11 additions & 5 deletions lib/collectionspace/mapper/term_searchable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -194,13 +194,20 @@ def rec_from_response(category, val, apiresponse)
end

def return_record(category, val, apiresponse, term_ct)
rec = apiresponse["list_item"][0]

case term_ct
when 0
rec = nil
nil
when 1
rec = apiresponse["list_item"]
if apiresponse.key?("warnings")
apiresponse["warnings"].each do |warning|
response.add_warning(warning.merge({field: column}))
end
end
rec
# rec = apiresponse["list_item"]
else
rec = apiresponse["list_item"][0]
using_uri = "#{client.config.base_uri}#{rec["uri"]}"
response.add_warning({
category: :"multiple_records_found_for_#{category}",
Expand All @@ -210,9 +217,8 @@ def return_record(category, val, apiresponse, term_ct)
value: val,
message: "#{term_ct} records found. Using #{using_uri}"
})
rec
end

rec
end

def add_bad_lookup_error(category, val)
Expand Down
60 changes: 32 additions & 28 deletions spec/collectionspace/mapper/searcher_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,44 +15,48 @@

describe "#.call", vcr: "core_domain_check" do
let(:result) { searcher.call(**args) }
let(:args) { {value: "All", type: "vocabularies", subtype: "publishto"} }
let(:args) { {value: value, type: "vocabularies", subtype: "publishto"} }

context "when search_if_not_cached = true", vcr: "searcher_search" do
let(:config) { {} }
let(:value) { "All" }

it "returns expected hash" do
expected = {
"fieldsReturned" =>
"csid|uri|refName|updatedAt|workflowState|rev|sourcePage|sas|"\
"proposed|referenced|deprecated|termStatus|description|source|"\
"order|displayName|shortIdentifier",
"itemsInPage" => "1",
"list_item" => {
"csid" => "d614ebc5-96fd-4680-9727",
"displayName" => "All",
"proposed" => "true",
"refName" =>
"urn:cspace:core.collectionspace.org:vocabularies:name"\
"(publishto):item:name(all)'All'",
"rev" => "0",
"sas" => "false",
"shortIdentifier" => "all",
"updatedAt" => "2020-02-08T03:30:26.054Z",
"uri" =>
"/vocabularies/e2ea6ca3-4c60-427d-96e5/items/"\
"d614ebc5-96fd-4680-9727",
"workflowState" => "project"
},
"pageNum" => "0",
"pageSize" => "25",
"totalItems" => "1"
}
expect(result).to eq(expected)
expect(result["totalItems"]).to eq("1")
expect(result.dig("list_item", 0, "displayName")).to eq("All")
end

context "when term not matching case sensitively" do
context "when vocabulary", vcr: "searcher_ci_vocab" do
let(:value) { "alL" }

it "returns expected hash" do
expect(result.key?("warnings")).to be true
warning = result["warnings"].first
expect(warning[:category]).to eq("case_insensitive_match")
expect(warning[:message]).to eq("Searched: #{value}. Using: All")
end
end

context "when authority", vcr: "searcher_ci_authority" do
let(:value) { "Art" }
let(:args) do
{value: value, type: "conceptauthorities", subtype: "concept"}
end

it "returns expected hash" do
expect(result.key?("warnings")).to be true
warning = result["warnings"].first
expect(warning[:category]).to eq("case_insensitive_match")
expect(warning[:message]).to eq("Searched: #{value}. Using: art")
end
end
end
end

context "when search_if_not_cached = false" do
let(:config) { {search_if_not_cached: false} }
let(:value) { "All" }

it "returns nil" do
expect(result).to be_nil
Expand Down
10 changes: 9 additions & 1 deletion spec/collectionspace/mapper/term_searchable_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ class TermClass

include CollectionSpace::Mapper::TermSearchable

attr_reader :type, :subtype, :handler
attr_reader :type, :subtype, :handler, :response
def initialize(type, subtype, handler)
@type = type
@subtype = subtype
@handler = handler
@response = CollectionSpace::Mapper::Response.new({}, handler)
@errors = []
end

def column = "foo"
end

RSpec.describe CollectionSpace::Mapper::TermSearchable,
Expand Down Expand Up @@ -131,6 +134,11 @@ def initialize(type, subtype, handler)
expected = "urn:cspace:core.collectionspace.org:vocabularies:name"\
"(publishto):item:name(all)'All'"
expect(result).to eq(expected)
expect(term.response.warnings).to include({
category: "case_insensitive_match",
message: "Searched: all. Using: All",
field: "foo"
})
end
end
end
Expand Down
167 changes: 167 additions & 0 deletions spec/support/cassettes/searcher_ci_authority.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 0a16eb3

Please sign in to comment.