@natlibfi/melinda-record-matching 2.0.1 → 2.0.7-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/CODEOWNERS +2 -0
- package/.github/dependabot.yml +40 -0
- package/.github/workflows/melinda-node-tests.yml +70 -0
- package/README.md +1 -1
- package/dist/candidate-search/candidate-search-utils.js +3 -6
- package/dist/candidate-search/candidate-search-utils.js.map +1 -1
- package/dist/candidate-search/index.js +115 -50
- package/dist/candidate-search/index.js.map +1 -1
- package/dist/candidate-search/index.spec.js +41 -48
- package/dist/candidate-search/index.spec.js.map +1 -1
- package/dist/candidate-search/query-list/bib.js +154 -64
- package/dist/candidate-search/query-list/bib.js.map +1 -1
- package/dist/candidate-search/query-list/bib.spec.js +1 -10
- package/dist/candidate-search/query-list/bib.spec.js.map +1 -1
- package/dist/candidate-search/query-list/index.js +4 -10
- package/dist/candidate-search/query-list/index.js.map +1 -1
- package/dist/index.js +498 -50
- package/dist/index.js.map +1 -1
- package/dist/index.spec.js +60 -34
- package/dist/index.spec.js.map +1 -1
- package/dist/match-detection/features/bib/all-source-ids.js +16 -19
- package/dist/match-detection/features/bib/all-source-ids.js.map +1 -1
- package/dist/match-detection/features/bib/authors.js +31 -35
- package/dist/match-detection/features/bib/authors.js.map +1 -1
- package/dist/match-detection/features/bib/bibliographic-level.js +3 -3
- package/dist/match-detection/features/bib/bibliographic-level.js.map +1 -1
- package/dist/match-detection/features/bib/host-component.js +3 -3
- package/dist/match-detection/features/bib/host-component.js.map +1 -1
- package/dist/match-detection/features/bib/index.js +28 -13
- package/dist/match-detection/features/bib/index.js.map +1 -1
- package/dist/match-detection/features/bib/index.spec.js +9 -13
- package/dist/match-detection/features/bib/index.spec.js.map +1 -1
- package/dist/match-detection/features/bib/isbn.js +28 -6
- package/dist/match-detection/features/bib/isbn.js.map +1 -1
- package/dist/match-detection/features/bib/issn.js +0 -4
- package/dist/match-detection/features/bib/issn.js.map +1 -1
- package/dist/match-detection/features/bib/language.js +69 -41
- package/dist/match-detection/features/bib/language.js.map +1 -1
- package/dist/match-detection/features/bib/media-type.js +83 -0
- package/dist/match-detection/features/bib/media-type.js.map +1 -0
- package/dist/match-detection/features/bib/melinda-id.js +0 -4
- package/dist/match-detection/features/bib/melinda-id.js.map +1 -1
- package/dist/match-detection/features/bib/melinda-identifier-factory.js +6 -17
- package/dist/match-detection/features/bib/melinda-identifier-factory.js.map +1 -1
- package/dist/match-detection/features/bib/other-standard-identifier.js +1 -4
- package/dist/match-detection/features/bib/other-standard-identifier.js.map +1 -1
- package/dist/match-detection/features/bib/publication-time-allow-cons-years-multi.js +256 -0
- package/dist/match-detection/features/bib/publication-time-allow-cons-years-multi.js.map +1 -0
- package/dist/match-detection/features/bib/publication-time-allow-cons-years.js +71 -0
- package/dist/match-detection/features/bib/publication-time-allow-cons-years.js.map +1 -0
- package/dist/match-detection/features/bib/publication-time.js +9 -8
- package/dist/match-detection/features/bib/publication-time.js.map +1 -1
- package/dist/match-detection/features/bib/record-type.js +6 -3
- package/dist/match-detection/features/bib/record-type.js.map +1 -1
- package/dist/match-detection/features/bib/standard-identifier-factory.js +129 -39
- package/dist/match-detection/features/bib/standard-identifier-factory.js.map +1 -1
- package/dist/match-detection/features/bib/title-version-original.js +79 -0
- package/dist/match-detection/features/bib/title-version-original.js.map +1 -0
- package/dist/match-detection/features/bib/title.js +29 -22
- package/dist/match-detection/features/bib/title.js.map +1 -1
- package/dist/match-detection/features/index.js +0 -4
- package/dist/match-detection/features/index.js.map +1 -1
- package/dist/match-detection/index.js +94 -47
- package/dist/match-detection/index.js.map +1 -1
- package/dist/match-detection/index.spec.js +25 -15
- package/dist/match-detection/index.spec.js.map +1 -1
- package/dist/matching-utils.js +63 -15
- package/dist/matching-utils.js.map +1 -1
- package/package.json +27 -24
- package/src/candidate-search/index.js +93 -31
- package/src/candidate-search/index.spec.js +27 -24
- package/src/candidate-search/query-list/bib.js +149 -22
- package/src/candidate-search/query-list/index.js +1 -1
- package/src/index.js +310 -38
- package/src/index.spec.js +49 -21
- package/src/match-detection/features/bib/all-source-ids.js +3 -3
- package/src/match-detection/features/bib/authors.js +23 -16
- package/src/match-detection/features/bib/bibliographic-level.js +1 -1
- package/src/match-detection/features/bib/host-component.js +1 -1
- package/src/match-detection/features/bib/index.js +4 -0
- package/src/match-detection/features/bib/index.spec.js +10 -2
- package/src/match-detection/features/bib/isbn.js +21 -2
- package/src/match-detection/features/bib/language.js +63 -22
- package/src/match-detection/features/bib/media-type.js +77 -0
- package/src/match-detection/features/bib/melinda-identifier-factory.js +2 -3
- package/src/match-detection/features/bib/other-standard-identifier.js +2 -0
- package/src/match-detection/features/bib/publication-time-allow-cons-years-multi.js +268 -0
- package/src/match-detection/features/bib/publication-time-allow-cons-years.js +67 -0
- package/src/match-detection/features/bib/publication-time.js +9 -4
- package/src/match-detection/features/bib/record-type.js +5 -1
- package/src/match-detection/features/bib/standard-identifier-factory.js +107 -22
- package/src/match-detection/features/bib/title-version-original.js +78 -0
- package/src/match-detection/features/bib/title.js +27 -7
- package/src/match-detection/index.js +60 -22
- package/src/match-detection/index.spec.js +18 -4
- package/src/matching-utils.js +62 -5
|
@@ -1,28 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _chai = require("chai");
|
|
4
|
-
|
|
5
4
|
var _fixura = require("@natlibfi/fixura");
|
|
6
|
-
|
|
7
5
|
var _fixugenHttpClient = _interopRequireDefault(require("@natlibfi/fixugen-http-client"));
|
|
8
|
-
|
|
9
6
|
var _marcRecord = require("@natlibfi/marc-record");
|
|
10
|
-
|
|
7
|
+
var _melindaCommons = require("@natlibfi/melinda-commons");
|
|
11
8
|
var _ = _interopRequireWildcard(require("."));
|
|
12
|
-
|
|
9
|
+
var _debug = _interopRequireDefault(require("debug"));
|
|
13
10
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
14
|
-
|
|
15
11
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
16
|
-
|
|
17
12
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
18
|
-
|
|
19
13
|
/**
|
|
20
14
|
*
|
|
21
15
|
* @licstart The following is the entire license notice for the JavaScript code in this file.
|
|
22
16
|
*
|
|
23
17
|
* Melinda record matching modules for Javascript
|
|
24
18
|
*
|
|
25
|
-
* Copyright (C) 2020 University Of Helsinki (The National Library Of Finland)
|
|
19
|
+
* Copyright (C) 2020-2022 University Of Helsinki (The National Library Of Finland)
|
|
26
20
|
*
|
|
27
21
|
* This file is part of melinda-record-matching-js
|
|
28
22
|
*
|
|
@@ -43,6 +37,8 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
43
37
|
* for the JavaScript code in this file.
|
|
44
38
|
*
|
|
45
39
|
*/
|
|
40
|
+
|
|
41
|
+
const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:candidate-search:test');
|
|
46
42
|
describe('candidate-search', () => {
|
|
47
43
|
(0, _fixugenHttpClient.default)({
|
|
48
44
|
callback,
|
|
@@ -51,84 +47,88 @@ describe('candidate-search', () => {
|
|
|
51
47
|
fixura: {
|
|
52
48
|
reader: _fixura.READERS.JSON
|
|
53
49
|
}
|
|
54
|
-
});
|
|
55
|
-
|
|
50
|
+
});
|
|
56
51
|
async function callback({
|
|
57
52
|
getFixture,
|
|
58
53
|
factoryOptions,
|
|
59
54
|
searchOptions,
|
|
60
|
-
expectedFactoryError,
|
|
61
|
-
expectedSearchError,
|
|
55
|
+
expectedFactoryError = false,
|
|
56
|
+
expectedSearchError = false,
|
|
62
57
|
enabled = true
|
|
63
58
|
}) {
|
|
64
59
|
const url = 'http://foo.bar';
|
|
65
|
-
|
|
66
60
|
if (!enabled) {
|
|
67
61
|
return;
|
|
68
62
|
}
|
|
69
|
-
|
|
70
63
|
if (expectedFactoryError) {
|
|
71
64
|
if (expectedFactoryError.isCandidateSearchError) {
|
|
72
|
-
(0, _chai.expect)(() => (0, _.default)({
|
|
65
|
+
(0, _chai.expect)(() => (0, _.default)({
|
|
66
|
+
...formatFactoryOptions(),
|
|
73
67
|
url
|
|
74
68
|
})).to.throw(_.CandidateSearchError, new RegExp(expectedFactoryError, 'u'));
|
|
75
69
|
return;
|
|
76
70
|
}
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
(0, _chai.expect)(() => (0, _.default)({
|
|
72
|
+
...formatFactoryOptions(),
|
|
79
73
|
url
|
|
80
74
|
})).to.throw(new RegExp(expectedFactoryError, 'u'));
|
|
81
75
|
return;
|
|
82
76
|
}
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
const search = (0, _.default)({
|
|
78
|
+
...formatFactoryOptions(),
|
|
85
79
|
url
|
|
86
80
|
});
|
|
87
81
|
await iterate({
|
|
88
|
-
searchOptions
|
|
82
|
+
searchOptions,
|
|
83
|
+
expectedSearchError
|
|
89
84
|
});
|
|
90
|
-
|
|
91
85
|
function formatFactoryOptions() {
|
|
92
|
-
|
|
93
|
-
|
|
86
|
+
debug(`Using factoryOptions: ${JSON.stringify(factoryOptions)}`);
|
|
87
|
+
return {
|
|
88
|
+
...factoryOptions,
|
|
89
|
+
maxRecordsPerRequest: factoryOptions.maxRecordsPerRequest || 1,
|
|
90
|
+
maxServerResults: factoryOptions.maxServerResults || undefined,
|
|
94
91
|
record: new _marcRecord.MarcRecord(factoryOptions.record, {
|
|
95
92
|
subfieldValues: false
|
|
96
93
|
})
|
|
97
94
|
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
}
|
|
101
96
|
async function iterate({
|
|
102
97
|
searchOptions,
|
|
98
|
+
expectedSearchError,
|
|
99
|
+
expectedErrorStatus,
|
|
103
100
|
count = 1
|
|
104
101
|
}) {
|
|
105
102
|
const expectedResults = getFixture(`expectedResults${count}.json`);
|
|
106
|
-
|
|
107
103
|
if (expectedSearchError) {
|
|
108
|
-
// eslint-disable-line functional/no-conditional-
|
|
104
|
+
// eslint-disable-line functional/no-conditional-statements
|
|
109
105
|
try {
|
|
110
106
|
await search(searchOptions);
|
|
111
107
|
throw new Error('Expected an error');
|
|
112
108
|
} catch (err) {
|
|
109
|
+
debug(`Got an error: ${err}`);
|
|
113
110
|
(0, _chai.expect)(err).to.be.an('error');
|
|
114
|
-
|
|
111
|
+
const errorMessage = err instanceof _melindaCommons.Error ? err.payload.message : err.message;
|
|
112
|
+
const errorStatus = err instanceof _melindaCommons.Error ? err.status : undefined;
|
|
113
|
+
debug(`errorMessage: ${errorMessage}, errorStatus: ${errorStatus}`);
|
|
114
|
+
(0, _chai.expect)(errorMessage).to.match(new RegExp(expectedSearchError, 'u'));
|
|
115
|
+
if (expectedErrorStatus) {
|
|
116
|
+
(0, _chai.expect)(errorStatus).to.be(expectedErrorStatus);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
115
119
|
return;
|
|
116
120
|
}
|
|
117
121
|
}
|
|
118
122
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return iterate({
|
|
124
|
-
searchOptions: resultsToOptions(results),
|
|
125
|
-
count: count + 1
|
|
126
|
-
});
|
|
123
|
+
// eslint-disable-next-line functional/no-conditional-statements
|
|
124
|
+
if (!expectedSearchError) {
|
|
125
|
+
const results = await search(searchOptions);
|
|
126
|
+
(0, _chai.expect)(formatResults(results)).to.eql(expectedResults);
|
|
127
127
|
}
|
|
128
|
-
|
|
129
128
|
function formatResults(results) {
|
|
130
|
-
|
|
131
|
-
return {
|
|
129
|
+
debug(results);
|
|
130
|
+
return {
|
|
131
|
+
...results,
|
|
132
132
|
records: results.records.map(({
|
|
133
133
|
record,
|
|
134
134
|
id
|
|
@@ -138,13 +138,6 @@ describe('candidate-search', () => {
|
|
|
138
138
|
}))
|
|
139
139
|
};
|
|
140
140
|
}
|
|
141
|
-
|
|
142
|
-
function resultsToOptions(results) {
|
|
143
|
-
return Object.entries(results).filter(([k]) => k === 'records' === false) // If key is 'records' return false
|
|
144
|
-
.reduce((acc, [k, v]) => ({ ...acc,
|
|
145
|
-
[k]: v
|
|
146
|
-
}), {});
|
|
147
|
-
}
|
|
148
141
|
}
|
|
149
142
|
}
|
|
150
143
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"index.spec.js","names":["_chai","require","_fixura","_fixugenHttpClient","_interopRequireDefault","_marcRecord","_melindaCommons","_","_interopRequireWildcard","_debug","_getRequireWildcardCache","nodeInterop","WeakMap","cacheBabelInterop","cacheNodeInterop","obj","__esModule","default","cache","has","get","newObj","hasPropertyDescriptor","Object","defineProperty","getOwnPropertyDescriptor","key","prototype","hasOwnProperty","call","desc","set","debug","createDebugLogger","describe","generateTests","callback","path","__dirname","recurse","fixura","reader","READERS","JSON","getFixture","factoryOptions","searchOptions","expectedFactoryError","expectedSearchError","enabled","url","isCandidateSearchError","expect","createSearchInterface","formatFactoryOptions","to","throw","CandidateSearchError","RegExp","search","iterate","stringify","maxRecordsPerRequest","maxServerResults","undefined","record","MarcRecord","subfieldValues","expectedErrorStatus","count","expectedResults","Error","err","be","an","errorMessage","MatchingError","payload","message","errorStatus","status","match","results","formatResults","eql","records","map","id","toObject"],"sources":["../../src/candidate-search/index.spec.js"],"sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Melinda record matching modules for Javascript\n*\n* Copyright (C) 2020-2022 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-record-matching-js\n*\n* melinda-record-matching-js program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Lesser General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-record-matching-js is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Lesser General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nimport {expect} from 'chai';\nimport {READERS} from '@natlibfi/fixura';\nimport generateTests from '@natlibfi/fixugen-http-client';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport {Error as MatchingError} from '@natlibfi/melinda-commons';\nimport createSearchInterface, {CandidateSearchError} from '.';\nimport createDebugLogger from 'debug';\n\nconst debug = createDebugLogger('@natlibfi/melinda-record-matching:candidate-search:test');\n\ndescribe('candidate-search', () => {\n generateTests({\n callback,\n path: [__dirname, '..', '..', 'test-fixtures', 'candidate-search', 'index'],\n recurse: false,\n fixura: {\n reader: READERS.JSON\n }\n });\n\n async function callback({getFixture, factoryOptions, searchOptions, expectedFactoryError = false, expectedSearchError = false, enabled = true}) {\n const url = 'http://foo.bar';\n\n if (!enabled) {\n return;\n }\n\n if (expectedFactoryError) {\n if (expectedFactoryError.isCandidateSearchError) {\n expect(() => createSearchInterface({...formatFactoryOptions(), url})).to.throw(CandidateSearchError, new RegExp(expectedFactoryError, 'u'));\n return;\n }\n\n expect(() => createSearchInterface({...formatFactoryOptions(), url})).to.throw(new RegExp(expectedFactoryError, 'u'));\n return;\n }\n\n const search = createSearchInterface({...formatFactoryOptions(), url});\n await iterate({searchOptions, expectedSearchError});\n\n function formatFactoryOptions() {\n debug(`Using factoryOptions: ${JSON.stringify(factoryOptions)}`);\n return {\n ...factoryOptions,\n maxRecordsPerRequest: factoryOptions.maxRecordsPerRequest || 1,\n maxServerResults: factoryOptions.maxServerResults || undefined,\n record: new MarcRecord(factoryOptions.record, {subfieldValues: false})\n };\n }\n\n async function iterate({searchOptions, expectedSearchError, expectedErrorStatus, count = 1}) {\n const expectedResults = getFixture(`expectedResults${count}.json`);\n\n if (expectedSearchError) { // eslint-disable-line functional/no-conditional-statements\n try {\n await search(searchOptions);\n throw new Error('Expected an error');\n } catch (err) {\n debug(`Got an error: ${err}`);\n expect(err).to.be.an('error');\n const errorMessage = err instanceof MatchingError ? err.payload.message : err.message;\n const errorStatus = err instanceof MatchingError ? err.status : undefined;\n debug(`errorMessage: ${errorMessage}, errorStatus: ${errorStatus}`);\n expect(errorMessage).to.match(new RegExp(expectedSearchError, 'u'));\n\n if (expectedErrorStatus) {\n expect(errorStatus).to.be(expectedErrorStatus);\n return;\n }\n return;\n }\n }\n\n // eslint-disable-next-line functional/no-conditional-statements\n if (!expectedSearchError) {\n const results = await search(searchOptions);\n expect(formatResults(results)).to.eql(expectedResults);\n }\n\n function formatResults(results) {\n debug(results);\n return {\n ...results,\n records: results.records.map(({record, id}) => ({id, record: record.toObject()}))\n };\n }\n\n }\n }\n});\n"],"mappings":"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"}
|
|
@@ -3,27 +3,24 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
exports.bibAuthors = bibAuthors;
|
|
6
7
|
exports.bibHostComponents = bibHostComponents;
|
|
7
8
|
exports.bibMelindaIds = bibMelindaIds;
|
|
9
|
+
exports.bibPublishers = bibPublishers;
|
|
8
10
|
exports.bibSourceIds = bibSourceIds;
|
|
9
11
|
exports.bibStandardIdentifiers = bibStandardIdentifiers;
|
|
10
12
|
exports.bibTitle = bibTitle;
|
|
11
|
-
|
|
12
13
|
var _debug = _interopRequireDefault(require("debug"));
|
|
13
|
-
|
|
14
14
|
var _candidateSearchUtils = require("../candidate-search-utils");
|
|
15
|
-
|
|
16
15
|
var _matchingUtils = require("../../matching-utils");
|
|
17
|
-
|
|
18
16
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
|
-
|
|
20
17
|
/**
|
|
21
18
|
*
|
|
22
19
|
* @licstart The following is the entire license notice for the JavaScript code in this file.
|
|
23
20
|
*
|
|
24
21
|
* Melinda record matching modules for Javascript
|
|
25
22
|
*
|
|
26
|
-
* Copyright (C) 2020 University Of Helsinki (The National Library Of Finland)
|
|
23
|
+
* Copyright (C) 2020-2022 University Of Helsinki (The National Library Of Finland)
|
|
27
24
|
*
|
|
28
25
|
* This file is part of melinda-record-matching-js
|
|
29
26
|
*
|
|
@@ -44,6 +41,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
44
41
|
* for the JavaScript code in this file.
|
|
45
42
|
*
|
|
46
43
|
*/
|
|
44
|
+
|
|
47
45
|
function bibSourceIds(record) {
|
|
48
46
|
/* Melinda's SRU-index melinda.sourceid includes source IDs from SID fields in Melinda records
|
|
49
47
|
SID-fields in Melinda have sf $c with local id and sf $b with a code for the local db:
|
|
@@ -62,36 +60,33 @@ function bibSourceIds(record) {
|
|
|
62
60
|
afterwards. SIDs are also not reliably maintained. A record might or might not have a SID for a local db
|
|
63
61
|
after the matching record is removed from the local db.
|
|
64
62
|
*/
|
|
63
|
+
|
|
65
64
|
const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:candidate-search:query:source-ids');
|
|
66
|
-
const debugData = debug.extend('data');
|
|
65
|
+
const debugData = debug.extend('data');
|
|
66
|
+
//const debugInfo = debug.extend('info');
|
|
67
67
|
|
|
68
68
|
debug(`Creating queries for sourceid's`);
|
|
69
69
|
const fSids = record.get('SID');
|
|
70
70
|
debugData(`SID-fields (${fSids.length}): ${JSON.stringify(fSids)}`);
|
|
71
71
|
return fSids.length > 0 ? toSidQueries(fSids) : [];
|
|
72
|
-
|
|
73
72
|
function toSidQueries(fSids) {
|
|
74
73
|
debug(`Creating actual queries for sourceid's`);
|
|
75
74
|
const sidStrings = getSidStrings(fSids);
|
|
76
|
-
|
|
77
75
|
if (sidStrings.length < 1) {
|
|
78
76
|
debug(`No identifiers found, no queries created.`);
|
|
79
77
|
return [];
|
|
80
78
|
}
|
|
81
|
-
|
|
82
79
|
const sidQueries = (0, _candidateSearchUtils.toQueries)(sidStrings, 'melinda.sourceid');
|
|
83
80
|
return sidQueries;
|
|
84
|
-
|
|
85
81
|
function getSidStrings(fSids) {
|
|
86
|
-
debug(`Getting Sid strings from SID fields`);
|
|
82
|
+
debug(`Getting Sid strings from SID fields`);
|
|
87
83
|
|
|
84
|
+
// Map SID fields to valid sidStrings, filter out empty strings
|
|
88
85
|
const sidStrings = fSids.map(toSidString).filter(nonEmptySid => nonEmptySid);
|
|
89
86
|
return sidStrings;
|
|
90
|
-
|
|
91
87
|
function toSidString(field) {
|
|
92
88
|
debug(`Getting string from a field`);
|
|
93
89
|
return (0, _matchingUtils.validateSidFieldSubfieldCounts)(field) ? createSidString(field) : '';
|
|
94
|
-
|
|
95
90
|
function createSidString(field) {
|
|
96
91
|
debug(`Creating string from a field`);
|
|
97
92
|
const [sfC] = (0, _matchingUtils.getSubfieldValues)(field, 'c');
|
|
@@ -101,148 +96,243 @@ function bibSourceIds(record) {
|
|
|
101
96
|
debugData(`${JSON.stringify(sfC)} + ${JSON.stringify(sfB)}`);
|
|
102
97
|
return cleanedSfC.concat(cleanedSfB);
|
|
103
98
|
}
|
|
104
|
-
|
|
105
99
|
function removeSourcePrefix(subfieldValue) {
|
|
106
100
|
const sourcePrefixRegex = /^(?<sourcePrefix>\([A-Za-z0-9-]+\))(?<id>.+)$/u;
|
|
107
|
-
const normalizedValue = subfieldValue.replace(sourcePrefixRegex, '$<id>');
|
|
101
|
+
const normalizedValue = (0, _matchingUtils.testStringOrNumber)(subfieldValue) ? String(subfieldValue).replace(sourcePrefixRegex, '$<id>') : '';
|
|
108
102
|
debugData(`Normalized ${subfieldValue} to ${normalizedValue}`);
|
|
109
103
|
return normalizedValue;
|
|
110
104
|
}
|
|
111
|
-
|
|
112
105
|
function normalizeSidSubfieldValue(subfieldValue) {
|
|
113
106
|
debugData(`Normalizing ${subfieldValue}`);
|
|
114
107
|
const normalizeAwayRegex = /[- ]/u;
|
|
115
|
-
return subfieldValue.replace(normalizeAwayRegex, '');
|
|
108
|
+
return (0, _matchingUtils.testStringOrNumber)(subfieldValue) ? String(subfieldValue).replace(normalizeAwayRegex, '') : '';
|
|
116
109
|
}
|
|
117
110
|
}
|
|
118
111
|
}
|
|
119
112
|
}
|
|
120
113
|
}
|
|
121
|
-
|
|
122
114
|
function bibMelindaIds(record) {
|
|
123
115
|
// Melinda's SRU-index melinda.melindaid includes f001 controlnumbers and old Melinda-IDs from f035z's for all non-deleted Melinda-records
|
|
116
|
+
|
|
124
117
|
const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:candidate-search:query:bibMelindaIds');
|
|
125
118
|
const debugData = debug.extend('data');
|
|
126
|
-
debug(`Creating queries for MelindaIds`);
|
|
119
|
+
debug(`Creating queries for MelindaIds`);
|
|
120
|
+
|
|
121
|
+
// Note: Melinda-ID's for search queries are created just from records f035a's and f035z's
|
|
127
122
|
// Both (FI-MELINDA)- and FCC-prefixed forms are found
|
|
128
123
|
// f001 controlnumber is not currently included, even if record's f003 is FI-MELINDA
|
|
129
|
-
|
|
130
124
|
const melindaIds = (0, _matchingUtils.getMelindaIdsF035)(record);
|
|
131
125
|
debugData(`Unique identifiers (${melindaIds.length}): ${JSON.stringify(melindaIds)}`);
|
|
132
|
-
|
|
133
126
|
if (melindaIds.length < 1) {
|
|
134
127
|
debug(`No identifiers found, no queries created.`);
|
|
135
128
|
return [];
|
|
136
129
|
}
|
|
137
|
-
|
|
138
130
|
return (0, _candidateSearchUtils.toQueries)(melindaIds, 'melinda.melindaid');
|
|
139
|
-
}
|
|
140
|
-
// bibHostComponents should search all 773 $ws for possible host id, but what should it do in case of multiple host ids?
|
|
141
|
-
|
|
131
|
+
}
|
|
142
132
|
|
|
133
|
+
// bibHostComponents returns host id from the first subfield $w of first field f773, see test-fixtures 04 and 05
|
|
134
|
+
// bibHostComponents should search all 773 $ws for possible host id, but what should it do in case of multiple host ids?
|
|
143
135
|
function bibHostComponents(record) {
|
|
144
136
|
const id = getHostId();
|
|
145
|
-
return id ? [`melinda.partsofhost=${id}`] : [];
|
|
146
|
-
|
|
137
|
+
return (0, _matchingUtils.testStringOrNumber)(id) ? [`melinda.partsofhost=${id}`] : [];
|
|
147
138
|
function getHostId() {
|
|
148
139
|
const [field] = record.get(/^773$/u);
|
|
149
|
-
|
|
150
140
|
if (field) {
|
|
151
141
|
const {
|
|
152
142
|
value
|
|
153
143
|
} = field.subfields.find(({
|
|
154
144
|
code
|
|
155
145
|
}) => code === 'w') || {};
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
return value.replace(/^\(FI-MELINDA\)/u, '');
|
|
146
|
+
if ((0, _matchingUtils.testStringOrNumber)(value) && /^\(FI-MELINDA\)/u.test(String(value))) {
|
|
147
|
+
return String(value).replace(/^\(FI-MELINDA\)/u, '');
|
|
159
148
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return value.replace(/^\(FIN01\)/u, '');
|
|
149
|
+
if ((0, _matchingUtils.testStringOrNumber)(value) && /^\(FIN01\)/u.test(String(value))) {
|
|
150
|
+
return String(value).replace(/^\(FIN01\)/u, '');
|
|
163
151
|
}
|
|
164
|
-
|
|
165
152
|
return false;
|
|
166
153
|
}
|
|
167
|
-
|
|
168
154
|
return false;
|
|
169
155
|
}
|
|
170
|
-
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// SRU search dc.title with a search phrase starting with ^ maps currently in Melinda to
|
|
171
159
|
// (probably) to *headings* index TIT
|
|
160
|
+
// - Aleph cannot currently handle headings searches starting with a boolean - in these cases use word search
|
|
161
|
+
|
|
172
162
|
// Headings index TIT drops articles etc. from the start of the title according to the filing indicator
|
|
173
163
|
// Currently filing indicator is not implemented - if the title starts with an article and the Melinda
|
|
174
164
|
// record is correctly catalogued using a filing indicator -> dc.title search won't match
|
|
175
165
|
|
|
176
|
-
|
|
177
166
|
function bibTitle(record) {
|
|
178
167
|
const title = getTitle();
|
|
179
|
-
|
|
180
|
-
if (title) {
|
|
181
|
-
const formatted = title.replace(/[^\w\s\p{Alphabetic}]/gu, '')
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
168
|
+
const booleanStartWords = ['and', 'or', 'nor', 'not'];
|
|
169
|
+
if ((0, _matchingUtils.testStringOrNumber)(title)) {
|
|
170
|
+
const formatted = String(title).replace(/[^\w\s\p{Alphabetic}]/gu, '')
|
|
171
|
+
// Clean up concurrent spaces from fe. subfield changes
|
|
172
|
+
.replace(/ +/gu, ' ').trim().slice(0, 30).trim();
|
|
173
|
+
|
|
174
|
+
// use word search for titles starting with a boolean
|
|
175
|
+
const useWordSearch = booleanStartWords.some(word => formatted.toLowerCase().startsWith(word));
|
|
176
|
+
// Prevent too many matches by having a minimum length
|
|
177
|
+
// Note that currently this fails matching if there are no matches from previous matchers
|
|
178
|
+
if (formatted.length >= 5) {
|
|
179
|
+
return [`dc.title="${useWordSearch ? '' : '^'}${formatted}*"`];
|
|
180
|
+
}
|
|
181
|
+
// use word search without ending * also in combination searches to avoid SRU-server crashes [MRA-189]
|
|
182
|
+
return addAuthorsToSearch(`dc.title="${formatted}"`);
|
|
185
183
|
}
|
|
186
|
-
|
|
187
184
|
return [];
|
|
185
|
+
function addAuthorsToSearch(titleQuery) {
|
|
186
|
+
const [authorQuery] = bibAuthors(record);
|
|
187
|
+
if (authorQuery !== undefined) {
|
|
188
|
+
return [`${authorQuery} AND ${titleQuery}`];
|
|
189
|
+
}
|
|
190
|
+
return addPublisherToSearch(titleQuery);
|
|
191
|
+
//return [];
|
|
192
|
+
}
|
|
188
193
|
|
|
194
|
+
function addPublisherToSearch(query) {
|
|
195
|
+
const [publisherQuery] = bibPublishers(record);
|
|
196
|
+
if (publisherQuery !== undefined) {
|
|
197
|
+
return [`${publisherQuery} AND ${query}`];
|
|
198
|
+
}
|
|
199
|
+
return [];
|
|
200
|
+
}
|
|
189
201
|
function getTitle() {
|
|
190
202
|
const [field] = record.get(/^245$/u);
|
|
191
|
-
|
|
192
203
|
if (field) {
|
|
193
|
-
|
|
204
|
+
const titleString = field.subfields
|
|
205
|
+
//.filter(({code}) => ['a', 'b', 'n', 'p'].includes(code))
|
|
206
|
+
.filter(({
|
|
194
207
|
code
|
|
195
|
-
}) => ['a', 'b'].includes(code))
|
|
208
|
+
}) => ['a', 'b'].includes(code))
|
|
209
|
+
//.filter(({code}) => ['a'].includes(code))
|
|
210
|
+
.map(({
|
|
196
211
|
value
|
|
197
|
-
}) => value)
|
|
212
|
+
}) => (0, _matchingUtils.testStringOrNumber)(value) ? String(value) : '').filter(value => value)
|
|
213
|
+
// In Melinda's index subfield separators are indexed as ' '
|
|
198
214
|
.join(' ');
|
|
215
|
+
return titleString;
|
|
199
216
|
}
|
|
200
|
-
|
|
201
217
|
return false;
|
|
202
218
|
}
|
|
203
|
-
}
|
|
219
|
+
}
|
|
220
|
+
function bibAuthors(record) {
|
|
221
|
+
const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:candidate-search:query:bibAuthors');
|
|
222
|
+
const debugData = debug.extend('data');
|
|
223
|
+
debug(`Creating query for the first author`);
|
|
224
|
+
//debugData(record);
|
|
225
|
+
|
|
226
|
+
const author = getAuthor(record);
|
|
227
|
+
const booleanStartWords = ['and', 'or', 'nor', 'not'];
|
|
228
|
+
if ((0, _matchingUtils.testStringOrNumber)(author)) {
|
|
229
|
+
const formatted = String(author).replace(/[^\w\s\p{Alphabetic}]/gu, '')
|
|
230
|
+
// Clean up concurrent spaces from fe. subfield changes
|
|
231
|
+
.replace(/ +/gu, ' ').trim().slice(0, 30).trim();
|
|
232
|
+
|
|
233
|
+
// use word search for authors starting with a boolean
|
|
234
|
+
const useWordSearch = booleanStartWords.some(word => formatted.toLowerCase().startsWith(word));
|
|
235
|
+
// Prevent too many matches by having a minimum length
|
|
236
|
+
debugData(`Author string: ${formatted}`);
|
|
237
|
+
if (formatted.length >= 5) {
|
|
238
|
+
return [`dc.author="${useWordSearch ? '' : '^'}${formatted}*"`];
|
|
239
|
+
}
|
|
240
|
+
//if (formatted) {
|
|
241
|
+
// return [`dc.author="${formatted}"`];
|
|
242
|
+
//}
|
|
243
|
+
return [];
|
|
244
|
+
}
|
|
245
|
+
return [];
|
|
246
|
+
function getAuthor(record) {
|
|
247
|
+
//debugData(record);
|
|
248
|
+
// eslint-disable-next-line prefer-named-capture-group
|
|
249
|
+
const [field] = record.get(/^(100)|(110)|(111)|(700)|(710)|(711)$/u);
|
|
250
|
+
//debugData(field);
|
|
204
251
|
|
|
252
|
+
if (field) {
|
|
253
|
+
const authorString = field.subfields.filter(({
|
|
254
|
+
code
|
|
255
|
+
}) => ['a'].includes(code)).map(({
|
|
256
|
+
value
|
|
257
|
+
}) => (0, _matchingUtils.testStringOrNumber)(value) ? String(value) : '').filter(value => value)
|
|
258
|
+
// In Melinda's index subfield separators are indexed as ' '
|
|
259
|
+
.join(' ');
|
|
260
|
+
return authorString;
|
|
261
|
+
}
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function bibPublishers(record) {
|
|
266
|
+
const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:candidate-search:query:bibPublishers');
|
|
267
|
+
const debugData = debug.extend('data');
|
|
268
|
+
debug(`Creating query for the first publisher`);
|
|
269
|
+
//debugData(record);
|
|
270
|
+
|
|
271
|
+
const publisher = getPublisher(record);
|
|
272
|
+
if ((0, _matchingUtils.testStringOrNumber)(publisher)) {
|
|
273
|
+
const formatted = String(publisher).replace(/[^\w\s\p{Alphabetic}]/gu, '')
|
|
274
|
+
// Clean up concurrent spaces from fe. subfield changes
|
|
275
|
+
.replace(/ +/gu, ' ').trim().slice(0, 30).trim();
|
|
276
|
+
debugData(`Publisher string: ${formatted}`);
|
|
277
|
+
// use non-wildcard word search from dc.publisher
|
|
278
|
+
return [`dc.publisher="${formatted}"`];
|
|
279
|
+
}
|
|
280
|
+
return [];
|
|
281
|
+
function getPublisher(record) {
|
|
282
|
+
//debugData(record);
|
|
283
|
+
const [field] = record.get(/^(?:260)|(?:264)$/u);
|
|
284
|
+
//debugData(field);
|
|
205
285
|
|
|
286
|
+
if (field) {
|
|
287
|
+
const publisherString = field.subfields.filter(({
|
|
288
|
+
code
|
|
289
|
+
}) => ['b'].includes(code)).map(({
|
|
290
|
+
value
|
|
291
|
+
}) => (0, _matchingUtils.testStringOrNumber)(value) ? String(value) : '').filter(value => value)
|
|
292
|
+
// In Melinda's index subfield separators are indexed as ' '
|
|
293
|
+
.join(' ');
|
|
294
|
+
return publisherString;
|
|
295
|
+
}
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
206
299
|
function bibStandardIdentifiers(record) {
|
|
207
300
|
const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:candidate-search:query:bibStandardIdentifiers');
|
|
208
301
|
const debugData = debug.extend('data');
|
|
209
302
|
debug(`Creating queries for standard identifiers`);
|
|
303
|
+
|
|
304
|
+
// DEVELOP: should we query also f015 and f028?
|
|
305
|
+
|
|
210
306
|
const fields = record.get(/^(?<def>020|022|024)$/u);
|
|
211
307
|
const identifiers = [].concat(...fields.map(toIdentifiers));
|
|
212
308
|
const uniqueIdentifiers = [...new Set(identifiers)];
|
|
213
309
|
debugData(`Standard identifier fields: ${JSON.stringify(fields)}`);
|
|
214
310
|
debugData(`Identifiers (${identifiers.length}): ${JSON.stringify(identifiers)}`);
|
|
215
311
|
debugData(`Unique identifiers (${uniqueIdentifiers.length}): ${JSON.stringify(uniqueIdentifiers)}`);
|
|
216
|
-
|
|
217
312
|
if (uniqueIdentifiers.length < 1) {
|
|
218
313
|
debug(`No identifiers found, no queries created.`);
|
|
219
314
|
return [];
|
|
220
315
|
}
|
|
221
|
-
|
|
222
316
|
return (0, _candidateSearchUtils.toQueries)(uniqueIdentifiers, 'dc.identifier');
|
|
223
|
-
|
|
224
317
|
function toIdentifiers({
|
|
225
318
|
tag,
|
|
226
319
|
subfields
|
|
227
320
|
}) {
|
|
228
321
|
const issnIsbnReqExp = /^[A-Za-z0-9-]+$/u;
|
|
229
322
|
const otherIdReqExp = /^[A-Za-z0-9-:]+$/u;
|
|
230
|
-
|
|
231
323
|
if (tag === '022') {
|
|
232
|
-
return subfields.filter(sub => ['a', 'z', 'y'].includes(sub.code) &&
|
|
324
|
+
return subfields.filter(sub => ['a', 'z', 'y'].includes(sub.code) && (0, _matchingUtils.testStringOrNumber)(sub.value) && issnIsbnReqExp.test(String(sub.value))).map(({
|
|
233
325
|
value
|
|
234
|
-
}) => value);
|
|
326
|
+
}) => String(value));
|
|
235
327
|
}
|
|
236
|
-
|
|
237
328
|
if (tag === '020') {
|
|
238
|
-
return subfields.filter(sub => ['a', 'z'].includes(sub.code) &&
|
|
329
|
+
return subfields.filter(sub => ['a', 'z'].includes(sub.code) && (0, _matchingUtils.testStringOrNumber)(sub.value) && issnIsbnReqExp.test(String(sub.value))).map(({
|
|
239
330
|
value
|
|
240
|
-
}) => value);
|
|
331
|
+
}) => String(value));
|
|
241
332
|
}
|
|
242
|
-
|
|
243
|
-
return subfields.filter(sub => ['a', 'z'].includes(sub.code) && otherIdReqExp.test(sub.value) && sub.value !== undefined).map(({
|
|
333
|
+
return subfields.filter(sub => ['a', 'z'].includes(sub.code) && (0, _matchingUtils.testStringOrNumber)(sub.value) && otherIdReqExp.test(String(sub.value))).map(({
|
|
244
334
|
value
|
|
245
|
-
}) => value);
|
|
335
|
+
}) => String(value));
|
|
246
336
|
}
|
|
247
337
|
}
|
|
248
338
|
//# sourceMappingURL=bib.js.map
|