@natlibfi/melinda-record-match-validator
Version:
Validates if two records matched by melinda-record-matching can be merged and sets merge priority
128 lines (127 loc) • 6.74 kB
JavaScript
import createDebugLogger from "debug";
import { comparisonTasksTable } from "./comparisonTasks.js";
import { check984 } from "./compareFunctions/compareField984.js";
import { MarcRecord } from "@natlibfi/marc-record";
import { nvdebug } from "./utils.js";
const debug = createDebugLogger("@natlibfi/melinda-record-match-validator:index");
const debugDev = debug.extend("dev");
function runComparisonTasks({ nth, record1, record2, checkPreference = true, record1External = {}, record2External = {}, returnAll = false, comparisonTasks = comparisonTasksTable.recordImport }) {
const currResult = comparisonTasks[nth].function({ record1, record2, checkPreference, record1External, record2External });
debugDev(`Running task ${nth} (${comparisonTasks[nth].name}) - returnAll: ${returnAll}`);
if (nth === comparisonTasks.length - 1 || !returnAll && currResult === false) {
return [currResult];
}
return [currResult].concat(runComparisonTasks({ nth: nth + 1, record1, record2, checkPreference, record1External, record2External, returnAll, comparisonTasks }));
}
function makeComparisons({ record1, record2, checkPreference = true, record1External = {}, record2External = {}, returnAll = false, comparisonTasks = comparisonTasksTable.recordImport }) {
debugDev(`returnAll: ${returnAll}`);
if (comparisonTasks.length === 0) {
const resultForZeroTasks = { result: true, reason: `No rules defined` };
if (returnAll) {
return [resultForZeroTasks];
}
return resultForZeroTasks;
}
const results = runComparisonTasks({ nth: 0, record1, record2, checkPreference, record1External, record2External, returnAll, comparisonTasks });
return returnAll ? returnAllResults() : returnDecisionPointResult();
function returnAllResults() {
const allResults = results.map((result, i) => ({
result,
reason: comparisonTasks[i].name,
preference: comparisonTasks[i].preference,
validation: comparisonTasks[i].validation,
level: comparisonTasks[i].manual === void 0 ? "error" : comparisonTasks[i].manual,
validation_message_fi: comparisonTasks[i].validation_message_fi,
preference_message_fi: comparisonTasks[i].preference_message_fi
}));
if (checkPreference) {
const field984OverrideResult = getField984OverrideResult();
if (field984OverrideResult) {
return allResults.concatenate(field984OverrideResult);
}
return allResults;
}
return allResults;
}
function returnDecisionPointResult() {
if (results.length < comparisonTasks.length || results[results.length - 1] === false) {
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) {
return { result: true, reason: "all tests passed" };
}
const field984OverrideResult = getField984OverrideResult();
if (field984OverrideResult) {
return field984OverrideResult;
}
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}` };
}
function getField984OverrideResult() {
const field984Override = check984({ record1, record2 });
if (field984Override === "A" || field984Override === "B") {
return { result: field984Override, reason: "Field 984 override applied (MRA-744)" };
}
return;
}
}
export function matchValidationForMergeUI({ record1Object, record2Object, checkPreference = true, record1External = { "recordSource": "databaseRecord" }, record2External = { "recordSource": "databaseRecord" }, manual = true, comparisonTasks = comparisonTasksTable.humanMerge }) {
debugDev(`Manual ${manual} (for Merge UI) - we have ${comparisonTasks.length} comparison tasks`);
debugDev(`FOOBAR`);
const record1 = new MarcRecord(record1Object, { subfieldValues: false });
const record2 = new MarcRecord(record2Object, { subfieldValues: false });
const result = makeComparisons({ record1, record2, checkPreference, record1External, record2External, returnAll: true, comparisonTasks });
debugDev(JSON.stringify(result));
const resultForMergeUI = filterResultsForMergeUI(result);
return resultForMergeUI;
function filterResultsForMergeUI(allResults) {
const failure = allResults.filter((r) => r.result !== true).filter((r) => r.result !== "B");
debugDev(`MatchValidator failed: ${JSON.stringify(failure, null, 4)}`);
const messages = failure.map(({ result: result2, level, validation_message_fi, preference_message_fi }) => ({
result: result2 === "A" ? "warning" : level,
// all preference-results are warning in UI
type: result2 === "A" ? "preference" : "validation",
//
message: result2 === "A" ? preference_message_fi : validation_message_fi
}));
debugDev(`MatchValidator results for MergeUI: ${JSON.stringify(messages, null, 4)}`);
const sortedMessages = messages.sort(sortMessages);
debugDev(`Sorted matchValidator results for MergeUI: ${JSON.stringify(sortedMessages, null, 4)}`);
return sortedMessages;
function sortMessages(a, b) {
if (a.result !== b.result) {
if (a.result === "error") {
return -1;
}
if (b.result === "error") {
return 1;
}
}
if (a.type !== b.type) {
if (a.type === "validation") {
return -1;
}
if (b.type === "validation") {
return 1;
}
}
return 0;
}
}
}
export default ({ record1Object, record2Object, checkPreference = true, record1External = {}, record2External = {}, manual = false, comparisonTasks = comparisonTasksTable.recordImport }) => {
debugDev(`Default (manual: ${manual}) (for record import) we have ${comparisonTasks.length} comparison tasks`);
const record1 = new MarcRecord(record1Object, { subfieldValues: false });
const record2 = new MarcRecord(record2Object, { subfieldValues: false });
const result = makeComparisons({ record1, record2, checkPreference, record1External, record2External, comparisonTasks });
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 } };
};
//# sourceMappingURL=index.js.map