Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Case insensitive term fallback search #179

Merged
merged 3 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ This project bumps the version number for any changes (including documentation u

## [Unreleased] - i.e. pushed to main branch but not yet tagged as a release

## [6.0.4] - 2024-10-21
- Make fallback term search fully case-insensitive, rather than just capitalizing/downcasing first letter of term

## [6.0.3] - 2024-10-18
- BUGFIX: Rescue error when record status check finds more than one matching record, and add to Response errors for handling by ingest application

Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ GIT
PATH
remote: .
specs:
collectionspace-mapper (6.0.3)
collectionspace-mapper (6.0.4)
activesupport (= 6.0.4.7)
chronic
collectionspace-client (~> 0.15.0)
Expand Down
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
2 changes: 1 addition & 1 deletion lib/collectionspace/mapper/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

module CollectionSpace
module Mapper
VERSION = "6.0.3"
VERSION = "6.0.4"
end
end
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
14 changes: 11 additions & 3 deletions 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 @@ -115,7 +118,7 @@ def initialize(type, subtype, handler)
term.send(:searched_term, val, :refname, termtype, termsubtype)
end

context "when val exists in instance", vcr: "vocab_publishto_All" do
context "when val exists in instance", vcr: "vocab_publishto_cap_all" do
let(:val) { "All" }
it "returns refname urn" do
expected = "urn:cspace:core.collectionspace.org:vocabularies:name"\
Expand All @@ -125,12 +128,17 @@ def initialize(type, subtype, handler)
end

context "when case-swapped val exists in instance",
vcr: "vocab_publishto_all" do
vcr: "vocab_publishto_lower_all" do
let(:val) { "all" }
it "returns refname urn" do
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
54 changes: 54 additions & 0 deletions spec/support/cassettes/core_concept_cats_tuxedo.yml

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

54 changes: 54 additions & 0 deletions spec/support/cassettes/core_nhr_ids_not_found.yml

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

Loading
Loading