Skip to content

Commit a7d2d68

Browse files
committed
Refactor how TIMDEX records are nomalized
Why these changes are being introduced: Prior to USE, TIMDEX records were largely normalized in the view layer. While not ideal, this made some sense given that TIMDEX was the sole source we were working with in the UI. Now that we have introduced Primo results in USE, we should normalize TIMDEX records similarly, such that the two share a similar data structure. Relevant ticket(s): * [USE-73](https://mitlibraries.atlassian.net/browse/USE-73) How this addresses that need: This introduces NormalizeTimdexReuslts and NormalizeTimdexRecord models to parallel the Primo models. The normalization models share a structure to the extent that it is meaningful. Source-specific fields that will be used in the application are indicated as such. Side effects of this change: * Modifications to various parts of the view layer were necessary to retrofit this change. * In some cases, we are only mapping the necessary data. (E.g., TIMDEX links array only includes source link.) This is subject to change as we learn more about UX requirements. * We are still using separate result partials for TIMDEX and Primo, until we have a better sense of how different the requirements are for those sources. * The Primo result partial has been minimized to more closely resemble the TIMDEX partial. This is also subject to change based on UX requirements.
1 parent f229be7 commit a7d2d68

16 files changed

+560
-81
lines changed

app/controllers/search_controller.rb

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,11 @@ def load_gdt_results
4747

4848
# Handle errors
4949
@errors = extract_errors(response)
50-
@pagination = Analyzer.new(@enhanced_query, response).pagination if @errors.nil?
51-
@results = extract_results(response)
50+
return unless @errors.nil?
51+
52+
@pagination = Analyzer.new(@enhanced_query, response).pagination
53+
raw_results = extract_results(response)
54+
@results = NormalizeTimdexResults.new(raw_results, @enhanced_query[:q]).normalize
5255
@filters = extract_filters(response)
5356
end
5457

@@ -77,8 +80,11 @@ def load_timdex_results
7780
response = query_timdex(query)
7881

7982
@errors = extract_errors(response)
80-
@pagination = Analyzer.new(@enhanced_query, response).pagination if @errors.nil?
81-
@results = extract_results(response)
83+
return unless @errors.nil?
84+
85+
@pagination = Analyzer.new(@enhanced_query, response).pagination
86+
raw_results = extract_results(response)
87+
@results = NormalizeTimdexResults.new(raw_results, @enhanced_query[:q]).normalize
8288
end
8389

8490
def active_filters

app/helpers/search_helper.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ def format_highlight_label(field_name)
1515
end
1616

1717
def view_online(result)
18-
return unless result['sourceLink'].present?
18+
return unless result['source_link'].present?
1919

20-
link_to 'View online', result['sourceLink'], class: 'button button-primary'
20+
link_to 'View online', result['source_link'], class: 'button button-primary'
2121
end
2222

2323
def view_record(record_id)

app/models/normalize_primo_record.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Transforms a PNX doc from Primo Search API into a normalized record.
1+
# Transforms a Primo Search API result into a normalized record.
22
class NormalizePrimoRecord
33
def initialize(record, query)
44
@record = record
@@ -7,22 +7,24 @@ def initialize(record, query)
77

88
def normalize
99
{
10+
# Core fields
1011
'title' => title,
1112
'creators' => creators,
1213
'source' => source,
1314
'year' => year,
1415
'format' => format,
1516
'links' => links,
1617
'citation' => citation,
17-
'container' => container_title,
1818
'identifier' => record_id,
1919
'summary' => summary,
20-
'numbering' => numbering,
21-
'chapter_numbering' => chapter_numbering,
22-
'thumbnail' => thumbnail,
2320
'publisher' => publisher,
2421
'location' => best_location,
2522
'subjects' => subjects,
23+
# Primo-specific fields
24+
'container' => container_title,
25+
'numbering' => numbering,
26+
'chapter_numbering' => chapter_numbering,
27+
'thumbnail' => thumbnail,
2628
'availability' => best_availability,
2729
'other_availability' => other_availability?
2830
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Transforms a TIMDEX result into a normalized record.
2+
class NormalizeTimdexRecord
3+
def initialize(record, query)
4+
@record = record
5+
@query = query
6+
end
7+
8+
def normalize
9+
{
10+
# Core fields
11+
'title' => title,
12+
'creators' => creators,
13+
'source' => source,
14+
'year' => year,
15+
'format' => format,
16+
'links' => links,
17+
'citation' => citation,
18+
'identifier' => identifier,
19+
'summary' => summary,
20+
'publisher' => publisher,
21+
'location' => location,
22+
'subjects' => subjects,
23+
# TIMDEX-specific fields
24+
'content_type' => content_type,
25+
'dates' => dates,
26+
'contributors' => contributors,
27+
'highlight' => highlight,
28+
'source_link' => source_link
29+
}
30+
end
31+
32+
private
33+
34+
def title
35+
@record['title'] || 'Unknown title'
36+
end
37+
38+
def creators
39+
return [] unless @record['contributors']
40+
41+
# Convert TIMDEX contributors to Primo-style creators format
42+
@record['contributors']
43+
.select { |c| %w[Creator Author].include?(c['kind']) }
44+
.map { |creator| { 'value' => creator['value'], 'link' => nil } }
45+
end
46+
47+
def source
48+
return 'Unknown source' unless @record['source']
49+
50+
@record['source']
51+
end
52+
53+
def year
54+
# Extract year from dates
55+
return nil unless @record['dates']
56+
57+
pub_date = @record['dates'].find { |date| date['kind'] == 'Publication date' }
58+
return pub_date['value']&.match(/\d{4}/)&.to_s if pub_date
59+
60+
# Fallback to any date with a year
61+
@record['dates'].each do |date|
62+
year_match = date['value']&.match(/\d{4}/)
63+
return year_match.to_s if year_match
64+
end
65+
end
66+
67+
def format
68+
return '' unless @record['contentType']
69+
70+
@record['contentType'].map { |type| type['value'] }.join(' ; ')
71+
end
72+
73+
def links
74+
links = []
75+
76+
# Add source link if available
77+
if @record['sourceLink']
78+
links << {
79+
'kind' => 'full record',
80+
'url' => @record['sourceLink'],
81+
'text' => 'View full record'
82+
}
83+
end
84+
85+
links
86+
end
87+
88+
def citation
89+
@record['citation'] || nil
90+
end
91+
92+
def summary
93+
return nil unless @record['summary']
94+
95+
@record['summary'].is_a?(Array) ? @record['summary'].join(' ') : @record['summary']
96+
end
97+
98+
def publisher
99+
# Extract from contributors or other fields
100+
return nil unless @record['contributors']
101+
102+
publisher = @record['contributors'].find { |c| c['kind'] == 'Publisher' }
103+
publisher&.dig('value')
104+
end
105+
106+
def location
107+
return nil unless @record['locations']
108+
109+
@record['locations'].map { |loc| loc['value'] }.compact.join('; ')
110+
end
111+
112+
def subjects
113+
return [] unless @record['subjects']
114+
115+
@record['subjects'].map { |subject| subject['value'] }
116+
end
117+
118+
def identifier
119+
@record['timdexRecordId']
120+
end
121+
122+
# TIMDEX-specific methods
123+
def content_type
124+
@record['contentType']
125+
end
126+
127+
def dates
128+
@record['dates']
129+
end
130+
131+
def contributors
132+
@record['contributors']
133+
end
134+
135+
def highlight
136+
@record['highlight']
137+
end
138+
139+
def source_link
140+
@record['sourceLink']
141+
end
142+
end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Batch normalization for TIMDEX API results
2+
class NormalizeTimdexResults
3+
def initialize(results, query)
4+
@results = results
5+
@query = query
6+
end
7+
8+
def normalize
9+
return [] unless @results.is_a?(Array)
10+
11+
@results.filter_map do |doc|
12+
NormalizeTimdexRecord.new(doc, @query).normalize
13+
end
14+
end
15+
end

app/views/search/_result.html.erb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<li class="result">
22
<div class="result-content">
33
<h3 class="record-title">
4-
<span class="sr">Title: </span><%= link_to(result['title'], record_path(result['timdexRecordId'])) %>
4+
<span class="sr">Title: </span><%= link_to(result['title'], record_path(result['identifier'])) %>
55
</h3>
66

77
<p class="pub-info">
8-
<span><%= result['contentType']&.each { |type| type['value'] }&.join(' ; ') %></span>
8+
<span><%= result['content_type']&.each { |type| type['value'] }&.join(' ; ') %></span>
99
<span>
1010
<% result['dates']&.each do |date| %>
1111
<%= date['value'] if date['kind'] == 'Publication date' %>
Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,38 @@
11
<li class="result">
22
<div class="result-content">
33
<h3 class="record-title">
4-
<span class="sr">Title: </span><%= link_to(result_geo['title'], record_path(result_geo['timdexRecordId'])) %>
4+
<span class="sr">Title: </span><%= link_to(result_geo['title'], record_path(result_geo['identifier'])) %>
55
</h3>
66

77
<div class="data-info">
88
<%= render partial: 'shared/geo_data_info', locals: { metadata: result_geo } %>
99
</div>
1010

11-
<% if result_geo['contributors'] %>
11+
<% if result_geo['creators'].present? || result_geo['contributors'].present? %>
1212
<span class="sr">Contributors: </span>
1313
<ul class="list-inline truncate-list contributors">
14-
<%= render partial: 'shared/contributors', locals: { contributors: result_geo['contributors'] } %>
14+
<!-- Use normalized creators if available, otherwise fall back to raw contributors -->
15+
<% contributors = result_geo['creators'].present? ? result_geo['creators'] : result_geo['contributors'] %>
16+
<% if contributors %>
17+
<%= render partial: 'shared/contributors', locals: { contributors: contributors } %>
18+
<% end %>
1519
</ul>
1620
<% end %>
1721

18-
<% if result_geo['summary'] %>
22+
<% if result_geo['summary'].present? %>
1923
<p class="result-summary truncate-list">
20-
<span class="sr">Summary: </span><%= result_geo['summary'].join(' ') %>
24+
<span class="sr">Summary: </span><%= result_geo['summary'] %>
2125
</p>
2226
<% end %>
2327

2428
<% if result_geo['highlight'] %>
2529
<div class="result-highlights">
26-
<%= render partial: 'search/highlights', locals: { result: result_geo } %>
30+
<%= render partial: 'search/highlights', locals: { result: { 'highlight' => result_geo['highlight'] } } %>
2731
</div>
2832
<% end %>
2933

3034
<div class="result-record">
31-
<%= view_record(result_geo['timdexRecordId']) %>
35+
<%= view_record(result_geo['identifier']) %>
3236
</div>
3337
</div>
3438
</li>

app/views/search/_result_primo.html.erb

Lines changed: 14 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22
<div class="result-content">
33
<h3 class="record-title">
44
<span class="sr">Title: </span>
5-
<% if result_primo['links']&.find { |link| link['kind'] == 'full record' } %>
6-
<%= link_to(result_primo['title'], result_primo['links'].find { |link| link['kind'] == 'full record' }['url']) %>
5+
<% if result['links']&.find { |link| link['kind'] == 'full record' } %>
6+
<%= link_to(result['title'], result['links'].find { |link| link['kind'] == 'full record' }['url']) %>
77
<% else %>
8-
<%= result_primo['title'] %>
8+
<%= result['title'] %>
99
<% end %>
1010
</h3>
1111

1212
<p class="pub-info">
13-
<span><%= result_primo['format'] %></span>
14-
<span><%= result_primo['year'] %></span>
13+
<span><%= result['format'] %></span>
14+
<span><%= result['year'] %></span>
1515
</p>
1616

17-
<% if result_primo['creators'].present? %>
17+
<% if result['creators'].present? %>
1818
<span class="sr">Contributors: </span>
1919
<ul class="list-inline truncate-list contributors">
20-
<% result_primo['creators'].each do |creator| %>
20+
<% result['creators'].each do |creator| %>
2121
<li>
2222
<% if creator[:link] %>
2323
<%= link_to creator[:value], creator[:link] %>
@@ -29,49 +29,12 @@
2929
</ul>
3030
<% end %>
3131

32-
<% if result_primo['container'].present? %>
33-
<p class="pub-info">
34-
<span class="sr">Published in: </span>
35-
<em><%= result_primo['container'] %></em>
36-
</p>
37-
<% end %>
38-
39-
<% if result_primo['citation'].present? %>
40-
<p class="citation">
41-
<span class="sr">Citation: </span>
42-
<%= result_primo['citation'] %>
43-
</p>
44-
<% end %>
45-
46-
<% if result_primo['summary'].present? %>
47-
<p class="summary">
48-
<span class="sr">Summary: </span>
49-
<%= truncate(result_primo['summary'], length: 300) %>
50-
</p>
51-
<% end %>
52-
53-
<% if result_primo['subjects'].present? %>
54-
<p class="subjects">
55-
<span class="sr">Subjects: </span>
56-
<%= result_primo['subjects'].join('; ') %>
57-
</p>
58-
<% end %>
59-
60-
<% if result_primo['links'].present? %>
61-
<ul class="list-inline links">
62-
<% result_primo['links'].each do |link| %>
63-
<li>
64-
<%= link_to link['kind'].titleize, link['url'], class: 'link-button' %>
65-
</li>
32+
<div class="result-get">
33+
<% if result['links'].present? %>
34+
<% result['links'].each do |link| %>
35+
<%= link_to link['kind'].titleize, link['url'], class: 'link-button' %>
6636
<% end %>
67-
</ul>
68-
<% end %>
69-
70-
<% if result_primo['availability'].present? %>
71-
<p class="availability">
72-
<span class="sr">Availability: </span>
73-
<span class="availability-status"><%= result_primo['availability'] %></span>
74-
</p>
75-
<% end %>
37+
<% end %>
38+
</div>
7639
</div>
77-
</li>
40+
</li>

app/views/search/results.html.erb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,11 @@
3838
<% if @results.present? && @errors.blank? %>
3939
<h2 class="hd-3 results-context"><%= results_summary(@pagination[:hits]) %> returned</h2>
4040
<ol class="results-list" start="<%= @pagination[:start] %>">
41-
<% if @active_tab == 'primo' %>
42-
<%= render(partial: 'search/result_primo', collection: @results) %>
43-
<% else %>
44-
<%= render(partial: 'search/result', collection: @results) %>
41+
<% case @active_tab %>
42+
<% when 'primo' %>
43+
<%= render(partial: 'search/result_primo', collection: @results, as: :result) %>
44+
<% when 'timdex' %>
45+
<%= render(partial: 'search/result', collection: @results, as: :result) %>
4546
<% end %>
4647
</ol>
4748
<% elsif @errors.blank? %>

0 commit comments

Comments
 (0)