Skip to content
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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ client.find_instance_record(instance_record_id: 'some-instance-record-id')
client.find_instance_record(instance_record_hrid: 'some-instance-record-hrid')
client.find_source_record(instance_record_id: 'some-instance-record-id')
client.find_source_record(instance_record_hrid: 'some-instance-record-hrid')
client.find_source_marc_records(modified_since: '2025-01-01T00:00:00Z') { |marc_record_hash| }
client.find_source_marc_records(with_965_value: '965abc') { |marc_record_hash| }
client.find_source_marc_records(modified_since: '2025-01-01T00:00:00Z', with_965_value: '965abc') { |marc_record_hash| }

# Convert a FOLIO MARC source record to a marc gem MARC::Record object:
source_record = client.find_source_record(instance_record_id: 'some-instance-record-id')
Expand Down
19 changes: 13 additions & 6 deletions lib/folio_api_client/finders.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ def find_source_record(instance_record_id: nil, instance_record_hrid: nil)
source_record_search_results['sourceRecords'].first
end

def find_source_marc_records(modified_since, has_965hyacinth: false, &block)
query = marc_records_query(modified_since: modified_since, has_965hyacinth: has_965hyacinth)
def find_source_marc_records(modified_since: nil, with_965_value: nil, &block)
query = marc_records_query(modified_since: modified_since, with_965_value: with_965_value)

loop do
response = self.get('search/instances', query)
Expand All @@ -105,6 +105,8 @@ def find_source_marc_records(modified_since, has_965hyacinth: false, &block)
def process_marc_for_instance(instances, &block)
instances.each do |instance|
source_record = find_source_record(instance_record_id: instance['id'])
next if source_record.nil? # Occasionally, we find an instance record without a source record. Skip these.

marc_content = source_record.dig('parsedRecord', 'content')
yield(marc_content) if marc_content && block
end
Expand Down Expand Up @@ -133,17 +135,22 @@ def location_record_query(code: nil)
'Missing query field. Must supply a code.'
end

def marc_records_query(modified_since: nil, has_965hyacinth: false)
def marc_records_query(modified_since: nil, with_965_value: nil) # rubocop:disable Metrics/MethodLength
params = { limit: 100, offset: 0 }

if modified_since.nil? && !has_965hyacinth
if modified_since.nil? && with_965_value.nil?
raise FolioApiClient::Exceptions::MissingQueryFieldError,
'Missing query field. Must supply either modified_since or has_965hyacinth=true.'
'Missing query field. Must supply either modified_since or with_965_value.'
end

if modified_since && !modified_since.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/)
raise ArgumentError,
%(Invalid format for modified_since argument. Must be a date string like "2025-10-03T16:49:00Z".)
end

query_parts = []
query_parts << "metadata.updatedDate>=\"#{modified_since}\"" if modified_since
query_parts << 'identifiers.value="965hyacinth"' if has_965hyacinth
query_parts << %(identifiers.value="#{with_965_value}") if with_965_value

params[:query] = query_parts.join(' and ')
params
Expand Down
27 changes: 17 additions & 10 deletions spec/folio_api_client/finders_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@

describe '#find_source_marc_records' do
let(:modified_since) { '2025-01-01T00:00:00Z' }
let(:value_965) { '965hyacinth' }
let(:marc_content) { { 'fields' => [{ '001' => '12345' }] } }
let(:instance_record) { { 'id' => 'instance-123' } }
let(:instances_response) { { 'totalRecords' => 1, 'instances' => [instance_record] } }
Expand All @@ -350,50 +351,56 @@

it 'yields MARC content for each source record' do
yielded_records = []
instance.find_source_marc_records(modified_since) { |record| yielded_records << record }
instance.find_source_marc_records(modified_since: modified_since) { |record| yielded_records << record }
expect(yielded_records).to eq([marc_content])
end

it 'raises an exception if the given modified_since parameter is an invalid format' do
expect {
instance.find_source_marc_records(modified_since: 'banana') { |_| }
}.to raise_error(ArgumentError)
end
end

context 'with has_965hyacinth parameter' do
context 'with with_965_value parameter' do
before do
allow(instance).to receive(:get).with(
'search/instances', { query: 'identifiers.value="965hyacinth"', limit: 100, offset: 0 }
'search/instances', { query: %(identifiers.value="#{value_965}"), limit: 100, offset: 0 }
).and_return(instances_response)
end

it 'uses the correct query' do
instance.find_source_marc_records(nil, has_965hyacinth: true) { |_| }
instance.find_source_marc_records(with_965_value: value_965) { |_| }
expect(instance).to have_received(:get).with(
'search/instances', { query: 'identifiers.value="965hyacinth"', limit: 100, offset: 0 }
)
end
end

context 'with both parameters' do
context 'with modified_since and with_965_value parameters' do
before do
allow(instance).to receive(:get).with(
'search/instances', {
query: "metadata.updatedDate>=\"#{modified_since}\" and identifiers.value=\"965hyacinth\"",
query: %(metadata.updatedDate>="#{modified_since}" and identifiers.value="#{value_965}"),
limit: 100, offset: 0
}
).and_return(instances_response)
end

it 'combines both filters' do
instance.find_source_marc_records(modified_since, has_965hyacinth: true) { |_| }
instance.find_source_marc_records(modified_since: modified_since, with_965_value: value_965) { |_| }
expect(instance).to have_received(:get).with(
'search/instances', {
query: "metadata.updatedDate>=\"#{modified_since}\" and identifiers.value=\"965hyacinth\"",
query: %(metadata.updatedDate>="#{modified_since}" and identifiers.value="#{value_965}"),
limit: 100, offset: 0
}
)
end
end

it 'raises error when no parameters provided' do
it 'raises an error when no parameters provided' do
expect {
instance.find_source_marc_records(nil) { |_| }
instance.find_source_marc_records { |_| }
}.to raise_error(FolioApiClient::Exceptions::MissingQueryFieldError)
end
end
Expand Down