UNPKG

@natlibfi/melinda-record-match-validator

Version:

Validates if two records matched by melinda-record-matching can be merged and sets merge priority

317 lines (304 loc) 10.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _debug = _interopRequireDefault(require("debug")); var _melindaCommons = require("@natlibfi/melinda-commons"); var _marcRecord = require("@natlibfi/marc-record"); var _fieldSID = require("./fieldSID"); var _fieldLOW = require("./fieldLOW"); var _fieldCAT = require("./fieldCAT"); var _field = require("./field040"); var _title = require("./title"); var _field26X = require("./field26X"); var _field2 = require("./field042"); var _field33X = require("./field33X"); var _field3 = require("./field773"); var _field4 = require("./field984"); var _leader = require("./leader"); var _controlFields = require("./controlFields"); var _partsAndSets = require("./partsAndSets"); var _sanityCheckAudio = require("./sanityCheckAudio"); var _sanityCheckDaisy = require("./sanityCheckDaisy"); var _sanityCheckDvd = require("./sanityCheckDvd"); var _sanityCheckIsbnQualifer = require("./sanityCheckIsbnQualifer"); var _utils = require("./utils"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } //import {check245} from './field245'; //import {getSubfieldValues} from './collectFunctions/collectUtils'; //import {collectRecordValues} from './collectRecordValues'; //import {compareRecordValues} from './compareRecordValues'; //import {validateCompareResults} from './validateRecordCompareResults'; const debug = (0, _debug.default)('@natlibfi/melinda-record-match-validator:index'); const debugDev = debug.extend('dev'); //const debugData = debug.extend('data'); function checkExistence({ record1, record2 }) { if (record1 === undefined || record2 === undefined) { return false; } if ((0, _melindaCommons.isDeletedRecord)(record1) || (0, _melindaCommons.isDeletedRecord)(record2)) { return false; } return true; } const comparisonTasks = [ // NB! These are/should be in priority order! // undefined or deleted records cannot be merged (both automatic and human merge) { 'description': 'existence (validation only)', 'function': checkExistence }, // checks record type LDR/06 && bibliographic level LDR/07 (validation) and LDR/17 for encoding level (preference) // DEVELOP: we'll need more nuanced check for human merge: // record type & specific bibliographic level can be warnings, // generic non-component / component difference should prevent merge // we should currently be able to block merge for records that *have* components, but that needs Melinda-search or f774, so... { 'description': 'leader (validation and preference)', 'function': _leader.checkLeader }, // Prioritize LDR/17 (encoding level) // just preference also for human merge { 'description': 'publisher (264>260) (preference only)', 'function': _field26X.checkPublisher }, // Bit high on the preference list, isn't it? // what are we checking here? could probably be a warning for human merge { 'description': '008 test (validation and preference)', 'function': _controlFields.check008 }, // This test checks is just for preference despite its description! // DEVELOP: human merge should not merge records with same LOW { 'description': 'LOW test (validation and preference)', 'function': _fieldLOW.checkLOW }, // Priority order: FIKKA > ANY > NONE // This test check 042 to preference { 'description': 'field 042: authentication code (preference only)', 'function': _field2.check042 }, { 'description': 'CAT test (preference only)', 'function': _fieldCAT.checkCAT }, // NB! I'd like to have a test for 008/06, but them specs for it are elusive? { 'description': 'field 245 (title)', 'function': _title.checkAllTitleFeatures }, //{'description': 'field 245 (title)', 'function': check245}, // human merge: warning { 'description': 'field 336 (content type) test (validation and preference)', 'function': _field33X.check336 }, // human merge: warning { 'description': 'field 337 (media type) test (validation and preference)', 'function': _field33X.check337 }, // human merge: warning { 'description': 'field 338 (carrier type) test (validation and preference)', 'function': _field33X.check338 }, // human merge: warning for subfields q&g - $w actually should be different ... { 'description': '773 $wgq test (validation only)', 'function': _field3.check773 }, { 'description': '040$b (language of cataloging) (preference only)', 'function': _field.check040b }, { 'description': '040$e (description conventions) (preference only)', 'function': _field.check040e }, { 'description': 'SID test (validation and preference)', 'function': _fieldSID.checkSID }, // just preference? { 'description': '005 timestamp test (validation and preference)', 'function': _controlFields.check005 }, // human merge: warning { 'description': 'audio sanity check (validation only)', 'function': _sanityCheckAudio.performAudioSanityCheck }, // human merge: warning { 'description': 'Daisy sanity check (validation only)', 'function': _sanityCheckDaisy.performDaisySanityCheck }, // human merge: warning { 'description': 'DVD vs Blu-Ray sanity check (validation only)', 'function': _sanityCheckDvd.performDvdSanityCheck }, // human merge: warning { 'description': 'ISBN qualifier sanity check (validation only)', 'function': _sanityCheckIsbnQualifer.performIsbnQualifierCheck }, // human merge: warning { 'description': 'Parts vs sets test (validation)', 'function': _partsAndSets.compareRecordsPartSetFeatures }]; // Apply some recursion evilness/madness/badness to perform only the tests we really really really want. function runComparisonTasks({ nth, record1, record2, checkPreference = true, record1External = {}, record2External = {} }) { const currResult = comparisonTasks[nth].function({ record1, record2, checkPreference, record1External, record2External }); // NB! Aborts after the last task or after a failure (meaning currResult === false)! No further tests are performed. Recursion means optimization :D if (nth === comparisonTasks.length - 1 || currResult === false) { return [currResult]; } return [currResult].concat(runComparisonTasks({ nth: nth + 1, record1, record2, checkPreference, record1External, record2External })); } function makeComparisons({ record1, record2, checkPreference = true, record1External = {}, record2External = {} }) { // Start with sanity check(s): if there are no tasks, it is not a failure: if (comparisonTasks.length === 0) { return true; } // Get results (up to the point of first failure): const results = runComparisonTasks({ nth: 0, record1, record2, checkPreference, record1External, record2External }); // If any test fails, return false. if (results.length < comparisonTasks.length || results[results.length - 1] === false) { (0, _utils.nvdebug)(`makeComparisons() failed. Reason: ${comparisonTasks[results.length - 1].description}. (TEST: ${results.length}/${comparisonTasks.length})`, debugDev); return { result: false, reason: `${comparisonTasks[results.length - 1].description} failed` }; } if (!checkPreference) { // This will also skip separate field 984 check return { result: true, reason: 'all tests passed' }; } const field984Override = (0, _field4.check984)({ record1, record2 }); if (field984Override === 'A' || field984Override === 'B') { return { result: field984Override, reason: 'Field 984 override applied (MRA-744)' }; } const decisionPoint = results.findIndex(val => val !== true && val !== false); if (decisionPoint === -1) { return { result: true, reason: 'both records passed all tests, but no winner was found' }; } return { result: results[decisionPoint], reason: `${results[decisionPoint]} won ${comparisonTasks[decisionPoint].description}` }; } // {Record, source, yms} // record1External/record2External includes external information for record (for example whether it is an incomingRecord or databaseRecord) var _default = ({ record1Object, record2Object, checkPreference = true, record1External = {}, record2External = {} }) => { //debug(recordAObject); // Create MarcRecords here to avoid problems with differing MarcRecord versions etc. const record1 = new _marcRecord.MarcRecord(record1Object, { subfieldValues: false }); const record2 = new _marcRecord.MarcRecord(record2Object, { subfieldValues: false }); // checkPreference should be multivalue: // X: NOT CHECK (current false), Y: CHECK MERGABILITY FOR HUMANS, Z: CHECK MERGABILITY FOR AUTOMATON (current true) //const debug = createDebugLogger('@natlibfi/melinda-record-match-validator:index'); //if (1) { // New version: Make checks only to the point of first failure... // console.log('ENTER THE PROGRAM'); const result = makeComparisons({ record1, record2, checkPreference, record1External, record2External }); debug(`Comparison result: ${result.result}, reason: ${result.reason}`); if (result.result === false) { return { action: false, preference: false, message: result.reason }; } return { action: 'merge', preference: { 'name': result.reason, 'value': result.result } }; //} /* // We never get here... if (recordA === undefined || recordB === undefined) { // eslint-disable-line functional/no-conditional-statement throw new Error('Record missing!'); } const recordValuesA = collectRecordValues(recordA); debugDev('Record values A: %o', recordValuesA); const recordValuesB = collectRecordValues(recordB); debugDev('Record values B: %o', recordValuesB); // Check record type if e & f -> false const comparedRecordValues = compareRecordValues(recordValuesA, recordValuesB); debugDev('Compared record values: %o', comparedRecordValues); return validateCompareResults(comparedRecordValues); */ }; exports.default = _default; //# sourceMappingURL=index.js.map