snomed-ecl-engine 0.1.1

Compact SNOMED CT ECL engine and RF2 index builder
Documentation
use super::*;
use crate::store::{Identifier, IdentifierIndex};
use std::io::BufRead;

pub(super) fn read(
    archive: &mut ZipArchive<BufReader<File>>,
    lookup: &HashMap<u64, u32>,
    edition_date: u32,
) -> Result<Vec<Identifier>> {
    let names: Vec<_> = archive
        .file_names()
        .filter(|n| {
            n.contains("/Snapshot/")
                && n.rsplit('/')
                    .next()
                    .is_some_and(|n| n.starts_with("sct2_Identifier_") && n.ends_with(".txt"))
        })
        .map(str::to_owned)
        .collect();
    let mut identifiers = Vec::new();
    for name in names {
        let mut header = String::new();
        BufReader::new(archive.by_name(&name)?).read_line(&mut header)?;
        let fields: Vec<_> = header
            .trim_start_matches('\u{feff}')
            .trim_end_matches(['\r', '\n'])
            .split('\t')
            .collect();
        let positions = if fields
            == [
                "alternateIdentifier",
                "effectiveTime",
                "active",
                "moduleId",
                "identifierSchemeId",
                "referencedComponentId",
            ] {
            [0, 1, 2, 3, 4, 5]
        } else if fields
            == [
                "identifierSchemeId",
                "alternateIdentifier",
                "effectiveTime",
                "active",
                "moduleId",
                "referencedComponentId",
            ]
        {
            [1, 2, 3, 4, 0, 5]
        } else {
            anyhow::bail!("Unexpected RF2 Identifier header");
        };
        rows(archive, &name, &fields, |r| {
            let r = positions.map(|p| r[p]);
            let effective = date(r[1])?;
            ensure!(
                effective <= edition_date,
                "Identifier is newer than edition"
            );
            let enabled = active(r[2])?;
            let module = id(r[3])?;
            let scheme = id(r[4])?;
            let reference = id(r[5])?;
            ensure!(
                lookup.contains_key(&module) && lookup.contains_key(&scheme),
                "Identifier module or scheme is absent"
            );
            if enabled && matches!((reference / 10) % 100, 0 | 10) {
                ensure!(
                    lookup.contains_key(&reference),
                    "Identifier references a missing concept"
                );
            }
            identifiers.push(Identifier {
                scheme,
                code: r[0].into(),
                referenced_component: reference,
                module,
                effective_time: effective,
                active: enabled,
            });
            Ok(())
        })?;
    }
    Ok(IdentifierIndex::build(identifiers)?.rows)
}