• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pulibrary / orangelight / 00dbc10b-d747-4ad7-b211-7b26d753abbb

14 Aug 2025 01:25PM UTC coverage: 0.483% (-94.9%) from 95.343%
00dbc10b-d747-4ad7-b211-7b26d753abbb

push

circleci

web-flow
Merge pull request #5181 from pulibrary/dependabot/bundler/activestorage-7.2.2.2

Bump activestorage from 7.2.2.1 to 7.2.2.2

47 of 9721 relevant lines covered (0.48%)

0.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/lib/orangelight/browse_lists/call_number_csv.rb
1
# frozen_string_literal: true
2

3
module BrowseLists
×
4
  class SolrResponseError < StandardError; end
×
5

6
  class CallNumberCSV
×
7
    attr_reader :output_root, :facet_request, :conn, :rows
×
8
    attr_accessor :multi_cn_lookup
×
9
    def initialize(facet_request, conn, output_root: Pathname.new("/tmp"), rows: 5_000)
×
10
      @output_root = output_root
×
11
      @facet_request = facet_request
×
12
      @conn = conn
×
13
      @rows = rows
×
14
      @multi_cn_lookup = {}
×
15
    end
×
16

17
    def write
×
18
      write_multiple_call_numbers
×
19
      write_remaining_call_numbers
×
20
    end
×
21

22
    def filename
×
23
      output_root.join("#{facet_field}.csv")
×
24
    end
×
25

26
    private
×
27

28
      def core_url
×
29
        Blacklight.default_index.connection.uri.to_s.gsub(%r{^.*\/solr}, '/solr')
×
30
      end
×
31

32
      def facet_field
×
33
        "call_number_browse_s"
×
34
      end
×
35

36
      # Collect all the call numbers with facet count > 2
37
      # Write each as a row in the csv and add it to the lookup table
38
      def write_multiple_call_numbers
×
39
        # This request takes a minute or so
40
        resp = conn.get "#{facet_request}#{facet_field}&facet.mincount=2"
×
41
        req = JSON.parse(resp.body)
×
42
        CSV.open(filename, 'wb') do |csv|
×
43
          req['facet_counts']['facet_fields'][facet_field].each_slice(2) do |mcn, record_count|
×
44
            sort_cn = StringFunctions.cn_normalize(mcn)
×
45
            multi_cn_lookup[sort_cn] = record_count
×
46
            csv << [sort_cn, mcn, 'ltr', '', "#{record_count} titles with this call number", '', '', "?f[#{facet_field}][]=#{CGI.escape(mcn)}", '', 'Multiple locations']
×
47
          end
×
48
        end
×
49
      end
×
50

51
      # Append the rest of the call numbers to the file
52
      def write_remaining_call_numbers
×
53
        cursor_mark = '*'
×
54
        CSV.open(filename, 'ab') do |csv|
×
55
          loop do
×
56
            body = solr_cursor_page_body(cursor_mark)
×
57
            body['response']['docs'].each do |record|
×
58
              next unless record[facet_field]
×
59
              record[facet_field].each do |cn|
×
60
                sort_cn = StringFunctions.cn_normalize(cn)
×
61
                next if multi_cn_lookup.key?(sort_cn)
×
62
                csv << parse_cn_row(record, cn, sort_cn)
×
63
              end
×
64
            end
×
65
            next_cursor_mark = body['nextCursorMark']
×
66
            break if cursor_mark == next_cursor_mark
×
67
            cursor_mark = next_cursor_mark
×
68
          end
×
69
        end
×
70
      end
×
71

72
      # Get a page of solr results for actual items starting at the given cursor
73
      def solr_cursor_page_body(cursor_mark)
×
74
        retries = 0
×
75
        req = {}
×
76
        cn_fields = "#{facet_field},title_display,title_vern_display,author_display,author_s,id,pub_created_vern_display,pub_created_display,holdings_1display"
×
77
        loop do
×
78
          cn_request = "#{core_url}select?q=*%3A*&fl=#{cn_fields}&wt=json&indent=true&defType=edismax&facet=false&sort=id%20asc&rows=#{rows}&cursorMark=#{cursor_mark}"
×
79
          resp = conn.get cn_request.to_s
×
80
          req = JSON.parse(resp.body)
×
81
          break if req['response']
×
82
          Rails.logger.error "Call number browse generation failed at iteration with cursor mark #{cursor_mark}. Response from solr was: #{resp}"
×
83
          raise SolrResponseError if retries >= 2
×
84
          retries += 1
×
85
        end
×
86
        req
×
87
      end
×
88

89
      def parse_cn_row(record, cn, sort_cn)
×
90
        bibid = record['id']
×
91
        title = record['title_display']
×
92
        if record['title_vern_display']
×
93
          title = record['title_vern_display']
×
94
          dir = title.dir
×
95
        else
×
96
          dir = 'ltr' # ltr for non alt script
×
97
        end
×
98
        if record['pub_created_vern_display']
×
99
          date = record['pub_created_vern_display'][0]
×
100
        elsif record['pub_created_display'].present?
×
101
          date = record['pub_created_display'][0]
×
102
        end
×
103
        label = cn
×
104
        if record['author_display']
×
105
          author = record['author_display'][0..1].last
×
106
        elsif record['author_s']
×
107
          author = record['author_s'][0]
×
108
        end
×
109
        if record['holdings_1display']
×
110
          holding_block = JSON.parse(record['holdings_1display'])
×
111
          holding_record = holding_block.select { |_k, h| h['call_number_browse'] == cn }
×
112
          unless holding_record.empty?
×
113
            if multiple_locations?(holding_record)
×
114
              location = 'Multiple locations'
×
115
            else
×
116
              holding_id = holding_record.keys.first
×
117
              location = [holding_record[holding_id]['library'], holding_record[holding_id]['location']].select(&:present?).join(" - ")
×
118
            end
×
119
          end
×
120
        end
×
121
        holding_id ||= ''
×
122
        location ||= ''
×
123
        [sort_cn, label, dir, '', title, author, date, bibid, holding_id, location]
×
124
      end
×
125

126
      # determines if there are multiple locations for the same call number and same bib
127
      def multiple_locations?(holdings)
×
128
        locations = holdings.reject { |_k, h| h['library'] == 'Online' }.map { |_k, h| h['location'] }.uniq
×
129
        locations.length > 1
×
130
      end
×
131
  end
×
132
end
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc