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

pulibrary / bibdata / 49fb6d5d-e981-4ec8-b09b-2a5f44a3120c

23 Sep 2025 08:49PM UTC coverage: 89.659% (-0.03%) from 89.687%
49fb6d5d-e981-4ec8-b09b-2a5f44a3120c

Pull #2938

circleci

sandbergja
Move comment to the correct file
Pull Request #2938: New implementation of cjk_notes field in rust

37 of 119 new or added lines in 3 files covered. (31.09%)

2 existing lines in 1 file now uncovered.

7838 of 8742 relevant lines covered (89.66%)

376.52 hits per line

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

0.0
/lib/bibdata_rs/src/marc.rs
1
use itertools::Itertools;
2
use magnus::exception;
3
use marctk::Record;
4

5
mod string_normalize;
6

7
pub mod cjk;
8
pub mod control_field;
9
pub mod fixed_field;
10
pub mod genre;
11
pub mod identifier;
12
pub mod language;
13
pub mod note;
14
pub mod publication;
15
pub mod record_facet_mapping;
16
pub mod scsb;
17
pub mod variable_length_field;
18

19
pub use string_normalize::trim_punctuation;
20

UNCOV
21
pub fn holding_id(
×
22
    field_string: String,
×
23
    full_record: String,
×
24
) -> Result<Option<String>, magnus::Error> {
×
25
    let field = field_852(&field_string)?;
×
26
    let record = get_record(&full_record)?;
×
27
    let subfield_code_8 = field.first_subfield("8");
×
28
    let subfield_code_0 = field.first_subfield("0");
×
29
    match (subfield_code_8, subfield_code_0) {
×
30
        (Some(subfield), _) if alma_code_start_22(subfield.content().to_owned()) => {
×
31
            Ok(Some(subfield.content().to_owned()))
×
32
        }
33
        (_, Some(subfield)) if scsb::is_scsb(&record) => Ok(Some(subfield.content().to_owned())),
×
34
        _ => Ok(None),
×
35
    }
36
}
×
37

38
pub fn alma_code_start_22(code: String) -> bool {
×
39
    code.starts_with("22") && code.ends_with("06421")
×
40
}
×
41
pub fn genres(record_string: String) -> Result<Vec<String>, magnus::Error> {
×
42
    let record = get_record(&record_string)?;
×
43
    Ok(genre::genres(&record))
×
44
}
×
45

46
pub fn original_languages_of_translation(
×
47
    record_string: String,
×
48
) -> Result<Vec<String>, magnus::Error> {
×
49
    let record = get_record(&record_string)?;
×
50
    Ok(language::original_languages_of_translation(&record)
×
51
        .iter()
×
52
        .map(|language| language.english_name.to_owned())
×
53
        .collect())
×
54
}
×
55

56
pub fn access_notes(record_string: String) -> Result<Option<Vec<String>>, magnus::Error> {
×
57
    let record = get_record(&record_string)?;
×
58
    Ok(note::access_notes(&record))
×
59
}
×
60

61
pub fn recap_partner_notes(record_string: String) -> Result<Vec<String>, magnus::Error> {
×
62
    let record = get_record(&record_string)?;
×
63
    Ok(scsb::recap_partner::recap_partner_notes(&record))
×
64
}
×
65

66
pub fn is_scsb(record_string: String) -> Result<bool, magnus::Error> {
×
67
    let record = get_record(&record_string)?;
×
68
    Ok(scsb::is_scsb(&record))
×
69
}
×
70

71
// Build the permanent location code from 852$b and 852$c
72
// Do not append the 852c if it is a SCSB - we save the SCSB locations as scsbnypl and scsbcul
73
pub fn permanent_location_code(field_string: String) -> Result<Option<String>, magnus::Error> {
×
74
    let field = field_852(&field_string)?;
×
75
    Ok(match field.first_subfield("8") {
×
76
        Some(alma_code) if alma_code_start_22(alma_code.content().to_string()) => {
×
77
            let b = field
×
78
                .first_subfield("b")
×
79
                .map(|subfield| subfield.content())
×
80
                .unwrap_or_default();
×
81
            let c = field
×
82
                .first_subfield("c")
×
83
                .map(|subfield| subfield.content())
×
84
                .unwrap_or_default();
×
85
            Some(format!("{b}${c}"))
×
86
        }
87
        _ => field
×
88
            .first_subfield("b")
×
89
            .map(|subfield| subfield.content().to_string()),
×
90
    })
91
}
×
92

93
fn field_852(field_string: &String) -> Result<marctk::Field, magnus::Error> {
×
94
    let record = get_record(field_string)?;
×
95
    let field_852 = record.get_fields("852").into_iter().next();
×
96
    let field_852 = field_852.ok_or_else(|| {
×
97
        magnus::Error::new(
×
98
            exception::runtime_error(),
×
99
            format!("No 852 field found in record {}", field_string),
×
100
        )
101
    })?;
×
102
    Ok(field_852.clone())
×
103
}
×
104

105
pub fn current_location_code(field_string: String) -> Result<Option<String>, magnus::Error> {
×
106
    let record = get_record(&field_string)?;
×
107
    let field_876 = record.get_fields("876").into_iter().next();
×
108
    Ok(field_876.and_then(
×
109
        |field| match (field.first_subfield("y"), field.first_subfield("z")) {
×
110
            (Some(y), Some(z)) => Some(format!("{}${}", y.content(), z.content())),
×
111
            _ => None,
×
112
        },
×
113
    ))
114
}
×
115
pub fn build_call_number(field_string: String) -> Result<Option<String>, magnus::Error> {
×
116
    // call_number = [field_852['h'], field_852['i'], field_852['k'], field_852['j']].reject(&:blank?)
117
    let record = get_record(&field_string)?;
×
118
    let field_852 = record.get_fields("852").into_iter().next();
×
119
    let call_number = field_852.map(|field| {
×
120
        field
×
121
            .subfields()
×
122
            .iter()
×
123
            .filter(|subfield| ["h", "i", "k", "j"].contains(&subfield.code()))
×
124
            .map(|subfield| subfield.content().to_string())
×
125
            .filter(|s| !s.is_empty())
×
126
            //.collect::<Vec<String>>()
127
            .join(" ")
×
128
    });
×
129
    Ok(call_number.filter(|s| !s.is_empty()))
×
130
}
×
131

132
pub fn format_facets(record_string: String) -> Result<Vec<String>, magnus::Error> {
×
133
    let record = get_record(&record_string)?;
×
134
    Ok(record_facet_mapping::format_facets(&record)
×
135
        .iter()
×
136
        .map(|facet| format!("{facet}"))
×
137
        .collect())
×
138
}
×
139
pub fn private_items(record_string: String, holding_id: String) -> Result<bool, magnus::Error> {
×
140
    let record = get_record(&record_string)?;
×
141
    let fields_876 = record.get_fields("876");
×
142
    let mut items = fields_876.iter().filter(|field| {
×
143
        field.first_subfield("0").map(|subfield| subfield.content()) == Some(&holding_id)
×
144
    });
×
145
    Ok(items.any(|item| {
×
146
        item.first_subfield("x")
×
147
            .map_or(true, |subfield| subfield.content() == "Private")
×
148
    }))
×
149
}
×
150

NEW
151
pub fn notes_cjk(record_string: String) -> Result<Vec<String>, magnus::Error> {
×
152
    let record = get_record(&record_string)?;
×
NEW
153
    Ok(cjk::notes_cjk(&record).collect())
×
154
}
×
155

NEW
156
pub fn subjects_cjk(record_string: String) -> Result<Vec<String>, magnus::Error> {
×
NEW
157
    let record = get_record(&record_string)?;
×
NEW
158
    Ok(cjk::subjects_cjk(&record).collect())
×
UNCOV
159
}
×
160

161
pub fn normalize_oclc_number(string: String) -> String {
×
162
    identifier::normalize_oclc_number(&string)
×
163
}
×
164

165
pub fn is_oclc_number(string: String) -> bool {
×
166
    identifier::is_oclc_number(&string)
×
167
}
×
168

169
pub fn identifiers_of_all_versions(record_string: String) -> Result<Vec<String>, magnus::Error> {
×
170
    let record = get_record(&record_string)?;
×
171
    Ok(identifier::identifiers_of_all_versions(&record))
×
172
}
×
173

174
pub fn publication_statements(record_string: String) -> Result<Vec<String>, magnus::Error> {
×
175
    let record = get_record(&record_string)?;
×
176
    Ok(publication::publication_statements(&record).collect())
×
177
}
×
178

179
pub fn strip_non_numeric(string: String) -> String {
×
180
    string_normalize::strip_non_numeric(&string)
×
181
}
×
182

183
fn get_record(breaker: &str) -> Result<Record, magnus::Error> {
×
184
    Record::from_breaker(breaker).map_err(|err| {
×
185
        magnus::Error::new(
×
186
            exception::runtime_error(),
×
187
            format!("Found error {} while parsing breaker {}", err, breaker),
×
188
        )
189
    })
×
190
}
×
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