@natlibfi/melinda-record-matching 4.3.5 → 5.0.0-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/workflows/melinda-node-tests.yml +11 -7
- package/eslint.config.js +52 -0
- package/example.env +4 -0
- package/package.json +22 -90
- package/src/candidate-search/choose-queries.js +1 -3
- package/src/candidate-search/index.js +63 -89
- package/src/candidate-search/{index.spec.js → index.test.js} +19 -18
- package/src/candidate-search/query-list/bib.js +10 -4
- package/src/candidate-search/query-list/{bib.spec.js → bib.test.js} +8 -7
- package/src/candidate-search/query-list/component.js +127 -0
- package/src/candidate-search/query-list/index.js +23 -9
- package/src/cli.js +177 -0
- package/src/index.js +22 -37
- package/src/{index.spec.js → index.test.js} +11 -14
- package/src/match-detection/features/bib/all-source-ids.js +2 -2
- package/src/match-detection/features/bib/authors.js +3 -2
- package/src/match-detection/features/bib/index.js +16 -16
- package/src/match-detection/features/bib/{index.spec.js → index.test.js} +7 -6
- package/src/match-detection/features/bib/isbn.js +2 -2
- package/src/match-detection/features/bib/issn.js +1 -1
- package/src/match-detection/features/bib/language.js +5 -5
- package/src/match-detection/features/bib/media-type.js +1 -1
- package/src/match-detection/features/bib/melinda-id.js +1 -1
- package/src/match-detection/features/bib/melinda-identifier-factory.js +5 -5
- package/src/match-detection/features/bib/other-standard-identifier.js +1 -1
- package/src/match-detection/features/bib/publication-time-allow-cons-years-multi.js +6 -6
- package/src/match-detection/features/bib/publication-time-allow-cons-years.js +1 -1
- package/src/match-detection/features/bib/publication-time.js +1 -1
- package/src/match-detection/features/bib/standard-identifier-factory.js +1 -2
- package/src/match-detection/features/bib/title-version-original.js +2 -1
- package/src/match-detection/features/bib/title.js +6 -5
- package/src/match-detection/features/index.js +1 -1
- package/src/match-detection/index.js +1 -1
- package/src/match-detection/{index.spec.js → index.test.js} +9 -8
- package/src/matching-utils.js +8 -9
- package/dist/candidate-search/candidate-search-utils.js +0 -29
- package/dist/candidate-search/candidate-search-utils.js.map +0 -1
- package/dist/candidate-search/choose-queries.js +0 -122
- package/dist/candidate-search/choose-queries.js.map +0 -1
- package/dist/candidate-search/index.js +0 -260
- package/dist/candidate-search/index.js.map +0 -1
- package/dist/candidate-search/index.spec.js +0 -133
- package/dist/candidate-search/index.spec.js.map +0 -1
- package/dist/candidate-search/query-list/bib.js +0 -458
- package/dist/candidate-search/query-list/bib.js.map +0 -1
- package/dist/candidate-search/query-list/bib.spec.js +0 -46
- package/dist/candidate-search/query-list/bib.spec.js.map +0 -1
- package/dist/candidate-search/query-list/index.js +0 -47
- package/dist/candidate-search/query-list/index.js.map +0 -1
- package/dist/index.js +0 -555
- package/dist/index.js.map +0 -1
- package/dist/index.spec.js +0 -99
- package/dist/index.spec.js.map +0 -1
- package/dist/match-detection/features/bib/all-source-ids.js +0 -91
- package/dist/match-detection/features/bib/all-source-ids.js.map +0 -1
- package/dist/match-detection/features/bib/authors.js +0 -86
- package/dist/match-detection/features/bib/authors.js.map +0 -1
- package/dist/match-detection/features/bib/bibliographic-level.js +0 -15
- package/dist/match-detection/features/bib/bibliographic-level.js.map +0 -1
- package/dist/match-detection/features/bib/host-component.js +0 -15
- package/dist/match-detection/features/bib/host-component.js.map +0 -1
- package/dist/match-detection/features/bib/index.js +0 -119
- package/dist/match-detection/features/bib/index.js.map +0 -1
- package/dist/match-detection/features/bib/index.spec.js +0 -65
- package/dist/match-detection/features/bib/index.spec.js.map +0 -1
- package/dist/match-detection/features/bib/isbn.js +0 -49
- package/dist/match-detection/features/bib/isbn.js.map +0 -1
- package/dist/match-detection/features/bib/issn.js +0 -24
- package/dist/match-detection/features/bib/issn.js.map +0 -1
- package/dist/match-detection/features/bib/language.js +0 -113
- package/dist/match-detection/features/bib/language.js.map +0 -1
- package/dist/match-detection/features/bib/media-type.js +0 -56
- package/dist/match-detection/features/bib/media-type.js.map +0 -1
- package/dist/match-detection/features/bib/melinda-id.js +0 -21
- package/dist/match-detection/features/bib/melinda-id.js.map +0 -1
- package/dist/match-detection/features/bib/melinda-identifier-factory.js +0 -62
- package/dist/match-detection/features/bib/melinda-identifier-factory.js.map +0 -1
- package/dist/match-detection/features/bib/other-standard-identifier.js +0 -25
- package/dist/match-detection/features/bib/other-standard-identifier.js.map +0 -1
- package/dist/match-detection/features/bib/publication-time-allow-cons-years-multi.js +0 -229
- package/dist/match-detection/features/bib/publication-time-allow-cons-years-multi.js.map +0 -1
- package/dist/match-detection/features/bib/publication-time-allow-cons-years.js +0 -44
- package/dist/match-detection/features/bib/publication-time-allow-cons-years.js.map +0 -1
- package/dist/match-detection/features/bib/publication-time.js +0 -21
- package/dist/match-detection/features/bib/publication-time.js.map +0 -1
- package/dist/match-detection/features/bib/record-type.js +0 -18
- package/dist/match-detection/features/bib/record-type.js.map +0 -1
- package/dist/match-detection/features/bib/standard-identifier-factory.js +0 -188
- package/dist/match-detection/features/bib/standard-identifier-factory.js.map +0 -1
- package/dist/match-detection/features/bib/title-version-original.js +0 -52
- package/dist/match-detection/features/bib/title-version-original.js.map +0 -1
- package/dist/match-detection/features/bib/title.js +0 -70
- package/dist/match-detection/features/bib/title.js.map +0 -1
- package/dist/match-detection/features/index.js +0 -11
- package/dist/match-detection/features/index.js.map +0 -1
- package/dist/match-detection/index.js +0 -174
- package/dist/match-detection/index.js.map +0 -1
- package/dist/match-detection/index.spec.js +0 -63
- package/dist/match-detection/index.spec.js.map +0 -1
- package/dist/matching-utils.js +0 -115
- package/dist/matching-utils.js.map +0 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import {describe} from 'node:test';
|
|
4
|
+
import createDebugLogger from 'debug';
|
|
2
5
|
import generateTests from '@natlibfi/fixugen';
|
|
3
6
|
import {READERS} from '@natlibfi/fixura';
|
|
4
|
-
import {expect} from 'chai';
|
|
5
7
|
import {MarcRecord} from '@natlibfi/marc-record';
|
|
6
|
-
import * as features from '.';
|
|
7
|
-
import createDebugLogger from 'debug';
|
|
8
|
+
import * as features from './index.js';
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
const debug = createDebugLogger('@natlibfi/melinda-record-matching:match-detection:features/bib:test');
|
|
@@ -13,7 +14,7 @@ const debugData = debug.extend('data');
|
|
|
13
14
|
|
|
14
15
|
describe('match-detection/features/bib/', () => {
|
|
15
16
|
generateTests({
|
|
16
|
-
path: [
|
|
17
|
+
path: [import.meta.dirname, '..', '..', '..', '..', 'test-fixtures', 'match-detection', 'features', 'bib'],
|
|
17
18
|
useMetadataFile: true,
|
|
18
19
|
fixura: {
|
|
19
20
|
reader: READERS.JSON
|
|
@@ -33,7 +34,7 @@ describe('match-detection/features/bib/', () => {
|
|
|
33
34
|
debugData(`Record: ${record}`);
|
|
34
35
|
const {extract} = features[feature](options);
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
assert.deepStrictEqual(extract({record}), expectedFeatures);
|
|
37
38
|
return;
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -41,7 +42,7 @@ describe('match-detection/features/bib/', () => {
|
|
|
41
42
|
const {featuresA, featuresB, expectedPoints} = expectations;
|
|
42
43
|
const {compare} = features[feature](options);
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
assert.equal(compare(featuresA, featuresB), expectedPoints);
|
|
45
46
|
return;
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
|
-
import createInterface from './standard-identifier-factory';
|
|
3
|
-
import {parse as isbnParse} from 'isbn3';
|
|
4
2
|
import createDebugLogger from 'debug';
|
|
3
|
+
import {parse as isbnParse} from 'isbn3';
|
|
4
|
+
import createInterface from './standard-identifier-factory.js';
|
|
5
5
|
|
|
6
6
|
const debug = createDebugLogger(`@natlibfi/melinda-record-matching:match-detection:features:standard-identifiers:ISBN`);
|
|
7
7
|
const debugData = debug.extend('data');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import createDebugLogger from 'debug';
|
|
3
|
-
import {getMatchCounts} from '../../../matching-utils';
|
|
3
|
+
import {getMatchCounts} from '../../../matching-utils.js';
|
|
4
4
|
|
|
5
5
|
const debug = createDebugLogger('@natlibfi/melinda-record-matching:match-detection:features:language');
|
|
6
6
|
const debugData = debug.extend('data');
|
|
@@ -12,10 +12,10 @@ export default () => ({
|
|
|
12
12
|
|
|
13
13
|
const value008 = get008Value();
|
|
14
14
|
const values041 = get041Values();
|
|
15
|
-
debugData(`${label} 008: ${JSON.stringify(value008)}, 041: ${JSON.stringify(values041)}`);
|
|
15
|
+
debugData(`${label}: 008: ${JSON.stringify(value008)}, 041: ${JSON.stringify(values041)}`);
|
|
16
16
|
|
|
17
17
|
if (!value008 && values041.length < 1) {
|
|
18
|
-
debugData(
|
|
18
|
+
debugData(`${label}: No actual values found`);
|
|
19
19
|
return [];
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -26,14 +26,14 @@ export default () => ({
|
|
|
26
26
|
|
|
27
27
|
function get008Value() {
|
|
28
28
|
const value = record.get(/^008$/u)?.[0]?.value || undefined;
|
|
29
|
-
debugData(`${label} 008 value: ${value}`);
|
|
29
|
+
debugData(`${label}: 008 value: ${value}`);
|
|
30
30
|
|
|
31
31
|
if (!value) {
|
|
32
32
|
return undefined;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
const code = value.slice(35, 38);
|
|
36
|
-
debugData(`${label} 008 code: ${code}`);
|
|
36
|
+
debugData(`${label}: 008 code: ${code}`);
|
|
37
37
|
return isLangCodeForALanguage(code) ? code : undefined;
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -13,7 +13,7 @@ export default () => ({
|
|
|
13
13
|
debugData(`Record (${label}): ${JSON.stringify(record)}`);
|
|
14
14
|
debugData(`RecordExternal: ${JSON.stringify(recordExternal)}`);
|
|
15
15
|
const values337 = get337Values();
|
|
16
|
-
debug(`${label} 337 $b values: ${JSON.stringify(values337)}`);
|
|
16
|
+
debug(`${label}: 337 $b values: ${JSON.stringify(values337)}`);
|
|
17
17
|
|
|
18
18
|
return values337;
|
|
19
19
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import createDebugLogger from 'debug';
|
|
3
|
-
import {getMelindaIdsF035} from '../../../matching-utils';
|
|
3
|
+
import {getMelindaIdsF035} from '../../../matching-utils.js';
|
|
4
4
|
|
|
5
5
|
// 003+001 FI-MELINDA <melinda-id>
|
|
6
6
|
// 035 $a (FI-MELINDA)<melinda-id>
|
|
@@ -38,25 +38,25 @@ export default () => {
|
|
|
38
38
|
function compare(a, b) {
|
|
39
39
|
|
|
40
40
|
if (a.isMelindaRecord && b.isMelindaRecord &&
|
|
41
|
-
|
|
41
|
+
a.f001 === b.f001) {
|
|
42
42
|
debugData(`Melinda record's A f001 ${a.f001} matches Melinda record's B f001 ${a.f001}`);
|
|
43
43
|
return 1;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
if (a.isMelindaRecord && typeof b.f035MelindaIds !== 'undefined' &&
|
|
47
|
-
|
|
47
|
+
b.f035MelindaIds.some(id => id === a.f001)) {
|
|
48
48
|
debugData(`Melinda record's A f001 ${a.f001} matches record B f035 ${JSON.stringify(b.f035MelindaIds)}`);
|
|
49
49
|
return 1;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
if (b.isMelindaRecord && typeof a.f035MelindaIds !== 'undefined' &&
|
|
53
|
-
|
|
53
|
+
a.f035MelindaIds.some(id => id === b.f001)) {
|
|
54
54
|
debugData(`Melinda record's B f001 ${b.f001} matches record A f035 ${JSON.stringify(a.f035MelindaIds)}`);
|
|
55
55
|
return 1;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
if (typeof a.f035MelindaIds !== 'undefined' && typeof b.f035MelindaIds !== 'undefined' &&
|
|
59
|
-
|
|
59
|
+
a.f035MelindaIds.some(idA => b.f035MelindaIds.some(idB => idB === idA))) {
|
|
60
60
|
debugData(`Record A f035 ${JSON.stringify(a.f035MelindaIds)} matches record B f035 ${JSON.stringify(b.f035MelindaIds)}`);
|
|
61
61
|
return 1;
|
|
62
62
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import {testStringOrNumber} from '../../../matching-utils';
|
|
3
2
|
import createDebugLogger from 'debug';
|
|
3
|
+
import {testStringOrNumber} from '../../../matching-utils.js';
|
|
4
4
|
|
|
5
5
|
// We should also get copyright time and copyright/publication times from 26x
|
|
6
6
|
// We should also get publishing time type from f008
|
|
@@ -13,13 +13,13 @@ export default () => ({
|
|
|
13
13
|
const label = recordExternal && recordExternal.label ? recordExternal.label : 'record';
|
|
14
14
|
|
|
15
15
|
const f008Values = extractF008Values(record);
|
|
16
|
-
debug(`${label} f008: ${JSON.stringify(f008Values)}`);
|
|
16
|
+
debug(`${label}: f008: ${JSON.stringify(f008Values)}`);
|
|
17
17
|
|
|
18
18
|
const f26xValues = extractF26xValues(record);
|
|
19
|
-
debug(`${label} f26x: ${JSON.stringify(f26xValues)}`);
|
|
19
|
+
debug(`${label}: f26x: ${JSON.stringify(f26xValues)}`);
|
|
20
20
|
|
|
21
21
|
const f500Values = extractF500Years(record);
|
|
22
|
-
debug(`${label} f500: ${JSON.stringify(f500Values)}`);
|
|
22
|
+
debug(`${label}: f500: ${JSON.stringify(f500Values)}`);
|
|
23
23
|
|
|
24
24
|
// We should get copyrightYear from f008Date2 to copyrightYears when f008YearType = 'r'
|
|
25
25
|
// Is the original year (f008Date2) in f008YearType === 'r' comparable to copyrightYear?
|
|
@@ -123,7 +123,7 @@ export default () => ({
|
|
|
123
123
|
.flat()
|
|
124
124
|
.filter(({code}) => code === 'a')
|
|
125
125
|
.map(({value}) => value);
|
|
126
|
-
|
|
126
|
+
//.filter(value => value.test(reprintRegex));
|
|
127
127
|
|
|
128
128
|
debug(`f500 reprint field contents: ${JSON.stringify(reprintFieldContents)}`);
|
|
129
129
|
|
|
@@ -172,7 +172,7 @@ export default () => ({
|
|
|
172
172
|
// Handle consequent years as a match
|
|
173
173
|
// see publication-time for a version that does not handle consequent years as a match
|
|
174
174
|
if (!(isNaN(firstANumber) || isNaN(firstBNumber)) &&
|
|
175
|
-
|
|
175
|
+
(firstANumber + 1 === firstBNumber || firstANumber - 1 === firstBNumber)) {
|
|
176
176
|
return 0.1;
|
|
177
177
|
}
|
|
178
178
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
import {testStringOrNumber} from '../../../matching-utils';
|
|
3
|
+
import {testStringOrNumber} from '../../../matching-utils.js';
|
|
4
4
|
|
|
5
5
|
// We should also get copyright time and copyright/publication times from 26x
|
|
6
6
|
// see publication-time-allow-cons-years for a version allowing consequent years to match
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/* eslint-disable max-statements */
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import createDebugLogger from 'debug';
|
|
5
|
-
import {extractSubfieldsFromField, uniqueSubfields} from '../../../matching-utils';
|
|
4
|
+
import {extractSubfieldsFromField, uniqueSubfields} from '../../../matching-utils.js';
|
|
6
5
|
|
|
7
6
|
// Note about validity of standardIdentifiers:
|
|
8
7
|
// We have three types of invalid standardIdentifiers:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {LevenshteinDistance as leven} from 'natural';
|
|
2
|
-
import {testStringOrNumber} from '../../../matching-utils';
|
|
3
1
|
import createDebugLogger from 'debug';
|
|
2
|
+
import naturalPkg from 'natural';
|
|
3
|
+
const {LevenshteinDistance: leven} = naturalPkg;
|
|
4
|
+
import {testStringOrNumber} from '../../../matching-utils.js';
|
|
4
5
|
|
|
5
6
|
const debug = createDebugLogger('@natlibfi/melinda-record-matching:match-detection:features:title');
|
|
6
7
|
const debugData = debug.extend('data');
|
|
@@ -11,7 +12,7 @@ export default ({treshold = 10} = {}) => ({
|
|
|
11
12
|
extract: ({record, recordExternal}) => {
|
|
12
13
|
const label = recordExternal && recordExternal.label ? recordExternal.label : 'record';
|
|
13
14
|
const title = getTitle();
|
|
14
|
-
debug(`${label} title: ${title}`);
|
|
15
|
+
debug(`${label}: title: ${title}`);
|
|
15
16
|
|
|
16
17
|
if (testStringOrNumber(title)) {
|
|
17
18
|
const titleAsNormalizedString = String(title)
|
|
@@ -22,7 +23,7 @@ export default ({treshold = 10} = {}) => ({
|
|
|
22
23
|
// - we could precompose the finnish letters back to avoid this
|
|
23
24
|
.replace(/[^\p{Letter}\p{Number}]/gu, '')
|
|
24
25
|
.toLowerCase();
|
|
25
|
-
debug(`${label} titleString: ${titleAsNormalizedString}`);
|
|
26
|
+
debug(`${label}: titleString: ${titleAsNormalizedString}`);
|
|
26
27
|
return [titleAsNormalizedString];
|
|
27
28
|
}
|
|
28
29
|
|
|
@@ -30,7 +31,7 @@ export default ({treshold = 10} = {}) => ({
|
|
|
30
31
|
|
|
31
32
|
function getTitle() {
|
|
32
33
|
const [field] = record.get(/^245$/u);
|
|
33
|
-
debugData(`${label} titleField: ${JSON.stringify(field)}`);
|
|
34
|
+
debugData(`${label}: titleField: ${JSON.stringify(field)}`);
|
|
34
35
|
|
|
35
36
|
if (field) {
|
|
36
37
|
return field.subfields
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import {describe} from 'node:test';
|
|
3
|
+
import createDebugLogger from 'debug';
|
|
4
|
+
import {inspect} from 'util';
|
|
2
5
|
import generateTests from '@natlibfi/fixugen';
|
|
3
6
|
import {READERS} from '@natlibfi/fixura';
|
|
4
|
-
import {expect} from 'chai';
|
|
5
7
|
import {MarcRecord} from '@natlibfi/marc-record';
|
|
6
|
-
|
|
7
|
-
import createDetectionInterface from '.';
|
|
8
|
-
import
|
|
9
|
-
import createDebugLogger from 'debug';
|
|
8
|
+
|
|
9
|
+
import createDetectionInterface from './index.js';
|
|
10
|
+
import * as features from './features/index.js';
|
|
10
11
|
|
|
11
12
|
const debug = createDebugLogger('@natlibfi/melinda-record-matching:match-detection:test');
|
|
12
13
|
const debugData = debug.extend('data');
|
|
13
14
|
|
|
14
15
|
describe('match-detection', () => {
|
|
15
16
|
generateTests({
|
|
16
|
-
path: [
|
|
17
|
+
path: [import.meta.dirname, '..', '..', 'test-fixtures', 'match-detection', 'index'],
|
|
17
18
|
useMetadataFile: true,
|
|
18
19
|
recurse: false,
|
|
19
20
|
fixura: {
|
|
@@ -39,7 +40,7 @@ describe('match-detection', () => {
|
|
|
39
40
|
const results = detect({recordA, recordB});
|
|
40
41
|
debugData(`${JSON.stringify(results)}`);
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
assert.deepStrictEqual(results, expectedResults);
|
|
43
44
|
|
|
44
45
|
function formatOptions() {
|
|
45
46
|
const contextFeatures = features[options.strategy.type];
|
package/src/matching-utils.js
CHANGED
|
@@ -15,7 +15,7 @@ export function getMelindaIdsF035(record) {
|
|
|
15
15
|
return [];
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const allF035MelindaIds = [].concat(...f035s.map(toMelindaIds));
|
|
18
|
+
const allF035MelindaIds = [].concat(...f035s.map(field => toMelindaIds(field)));
|
|
19
19
|
const f035MelindaIds = [...new Set(allF035MelindaIds)];
|
|
20
20
|
|
|
21
21
|
debugData(`Fields (${f035s.length}): ${JSON.stringify(f035s)}`);
|
|
@@ -23,16 +23,15 @@ export function getMelindaIdsF035(record) {
|
|
|
23
23
|
debugData(`Unique ids (${f035MelindaIds.length}): ${JSON.stringify(f035MelindaIds)}`);
|
|
24
24
|
|
|
25
25
|
return f035MelindaIds;
|
|
26
|
+
}
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return subfields
|
|
31
|
-
.filter(sub => ['a', 'z'].includes(sub.code))
|
|
32
|
-
.filter(sub => testStringOrNumber(sub.value) && melindaIdRegExp.test(String(sub.value)))
|
|
33
|
-
.map(({value}) => testStringOrNumber(value) ? String(value).replace(melindaIdRegExp, '$<id>') : '');
|
|
28
|
+
export function toMelindaIds({subfields}, subfieldsToParse = ['a', 'z']) {
|
|
29
|
+
const melindaIdRegExp = /^(?<prefix>\(FI-MELINDA\)|FCC)(?<id>\d{9})$/u;
|
|
34
30
|
|
|
35
|
-
|
|
31
|
+
return subfields
|
|
32
|
+
.filter(sub => subfieldsToParse.includes(sub.code))
|
|
33
|
+
.filter(sub => testStringOrNumber(sub.value) && melindaIdRegExp.test(String(sub.value)))
|
|
34
|
+
.map(({value}) => testStringOrNumber(value) ? String(value).replace(melindaIdRegExp, '$<id>') : '');
|
|
36
35
|
}
|
|
37
36
|
|
|
38
37
|
export function validateSidFieldSubfieldCounts(field) {
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.toQueries = toQueries;
|
|
7
|
-
var _debug = _interopRequireDefault(require("debug"));
|
|
8
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
-
function toQueries(identifiers, queryString) {
|
|
10
|
-
const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:toQueries');
|
|
11
|
-
const debugData = debug.extend('data');
|
|
12
|
-
|
|
13
|
-
// We quote the identifier, if it contains a slash! (Slash in non-quoted SRU-search breaks search.)
|
|
14
|
-
const quotedIdentifiers = identifiers.map(identifier => identifier.match(/\//u) ? `"${identifier}"` : `${identifier}`);
|
|
15
|
-
|
|
16
|
-
// Aleph supports only two queries with or -operator (This is not actually true)
|
|
17
|
-
const pairs = toPairs(quotedIdentifiers);
|
|
18
|
-
const queries = pairs.map(([a, b]) => b ? `${queryString}=${a} or ${queryString}=${b}` : `${queryString}=${a}`);
|
|
19
|
-
debugData(`Pairs (${pairs.length}): ${JSON.stringify(pairs)}`);
|
|
20
|
-
debugData(`Queries (${queries.length}): ${JSON.stringify(queries)}`);
|
|
21
|
-
return queries;
|
|
22
|
-
}
|
|
23
|
-
function toPairs(array) {
|
|
24
|
-
if (array.length === 0) {
|
|
25
|
-
return [];
|
|
26
|
-
}
|
|
27
|
-
return [array.slice(0, 2)].concat(toPairs(array.slice(2), 2));
|
|
28
|
-
}
|
|
29
|
-
//# sourceMappingURL=candidate-search-utils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"candidate-search-utils.js","names":["_debug","_interopRequireDefault","require","e","__esModule","default","toQueries","identifiers","queryString","debug","createDebugLogger","debugData","extend","quotedIdentifiers","map","identifier","match","pairs","toPairs","queries","a","b","length","JSON","stringify","array","slice","concat"],"sources":["../../src/candidate-search/candidate-search-utils.js"],"sourcesContent":["import createDebugLogger from 'debug';\n\nexport function toQueries(identifiers, queryString) {\n\n const debug = createDebugLogger('@natlibfi/melinda-record-matching:toQueries');\n const debugData = debug.extend('data');\n\n // We quote the identifier, if it contains a slash! (Slash in non-quoted SRU-search breaks search.)\n const quotedIdentifiers = identifiers.map(identifier => identifier.match(/\\//u) ? `\"${identifier}\"` : `${identifier}`);\n\n // Aleph supports only two queries with or -operator (This is not actually true)\n const pairs = toPairs(quotedIdentifiers);\n const queries = pairs.map(([a, b]) => b ? `${queryString}=${a} or ${queryString}=${b}` : `${queryString}=${a}`);\n\n debugData(`Pairs (${pairs.length}): ${JSON.stringify(pairs)}`);\n debugData(`Queries (${queries.length}): ${JSON.stringify(queries)}`);\n\n return queries;\n}\n\nfunction toPairs(array) {\n if (array.length === 0) {\n return [];\n }\n return [array.slice(0, 2)].concat(toPairs(array.slice(2), 2));\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AAAsC,SAAAD,uBAAAE,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAE/B,SAASG,SAASA,CAACC,WAAW,EAAEC,WAAW,EAAE;EAElD,MAAMC,KAAK,GAAG,IAAAC,cAAiB,EAAC,6CAA6C,CAAC;EAC9E,MAAMC,SAAS,GAAGF,KAAK,CAACG,MAAM,CAAC,MAAM,CAAC;;EAEtC;EACA,MAAMC,iBAAiB,GAAGN,WAAW,CAACO,GAAG,CAACC,UAAU,IAAIA,UAAU,CAACC,KAAK,CAAC,KAAK,CAAC,GAAG,IAAID,UAAU,GAAG,GAAG,GAAGA,UAAU,EAAE,CAAC;;EAEtH;EACA,MAAME,KAAK,GAAGC,OAAO,CAACL,iBAAiB,CAAC;EACxC,MAAMM,OAAO,GAAGF,KAAK,CAACH,GAAG,CAAC,CAAC,CAACM,CAAC,EAAEC,CAAC,CAAC,KAAKA,CAAC,GAAG,GAAGb,WAAW,IAAIY,CAAC,OAAOZ,WAAW,IAAIa,CAAC,EAAE,GAAG,GAAGb,WAAW,IAAIY,CAAC,EAAE,CAAC;EAE/GT,SAAS,CAAC,UAAUM,KAAK,CAACK,MAAM,MAAMC,IAAI,CAACC,SAAS,CAACP,KAAK,CAAC,EAAE,CAAC;EAC9DN,SAAS,CAAC,YAAYQ,OAAO,CAACG,MAAM,MAAMC,IAAI,CAACC,SAAS,CAACL,OAAO,CAAC,EAAE,CAAC;EAEpE,OAAOA,OAAO;AAChB;AAEA,SAASD,OAAOA,CAACO,KAAK,EAAE;EACtB,IAAIA,KAAK,CAACH,MAAM,KAAK,CAAC,EAAE;IACtB,OAAO,EAAE;EACX;EACA,OAAO,CAACG,KAAK,CAACC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAACC,MAAM,CAACT,OAAO,CAACO,KAAK,CAACC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/D","ignoreList":[]}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.CandidateSearchError = void 0;
|
|
7
|
-
exports.default = _default;
|
|
8
|
-
var _debug = _interopRequireDefault(require("debug"));
|
|
9
|
-
var _sruClient = _interopRequireWildcard(require("@natlibfi/sru-client"));
|
|
10
|
-
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
11
|
-
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
12
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
-
class CandidateSearchError extends Error {}
|
|
14
|
-
exports.CandidateSearchError = CandidateSearchError;
|
|
15
|
-
async function _default({
|
|
16
|
-
url,
|
|
17
|
-
queryList,
|
|
18
|
-
queryListType,
|
|
19
|
-
maxCandidates = 50
|
|
20
|
-
}) {
|
|
21
|
-
const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:candidate-search:choose-queries');
|
|
22
|
-
const debugData = debug.extend('data');
|
|
23
|
-
const debugDev = debug.extend('dev');
|
|
24
|
-
debugData(`Url: ${url}`);
|
|
25
|
-
debugData(`QueryList: ${queryList}`);
|
|
26
|
-
debugData(`queryListType: ${queryListType}`);
|
|
27
|
-
const client = (0, _sruClient.default)({
|
|
28
|
-
url,
|
|
29
|
-
maxRecordsPerRequest: 0,
|
|
30
|
-
version: '2.0',
|
|
31
|
-
retrieveAll: false
|
|
32
|
-
});
|
|
33
|
-
debugDev(`QueryList (type: ${queryListType}) ${JSON.stringify(queryList)}`);
|
|
34
|
-
try {
|
|
35
|
-
const {
|
|
36
|
-
queriesWithTotals
|
|
37
|
-
} = await getQueryTotals({
|
|
38
|
-
queryList,
|
|
39
|
-
queryOffset: 0,
|
|
40
|
-
queriesWithTotals: []
|
|
41
|
-
});
|
|
42
|
-
debugDev(`QueryResult: ${JSON.stringify(queriesWithTotals)}`);
|
|
43
|
-
const filteredQueryResult = filterQueryResult({
|
|
44
|
-
queriesWithTotals,
|
|
45
|
-
maxCandidates
|
|
46
|
-
});
|
|
47
|
-
debugDev(`filteredQueryResult: ${JSON.stringify(filteredQueryResult)}`);
|
|
48
|
-
return filteredQueryResult;
|
|
49
|
-
} catch (err) {
|
|
50
|
-
throw new CandidateSearchError(err);
|
|
51
|
-
}
|
|
52
|
-
async function getQueryTotals({
|
|
53
|
-
queryList,
|
|
54
|
-
queryOffset = 0,
|
|
55
|
-
queriesWithTotals = []
|
|
56
|
-
}) {
|
|
57
|
-
const query = queryList[queryOffset];
|
|
58
|
-
debug(`Running query ${JSON.stringify(query)} (${queryOffset}) for total`);
|
|
59
|
-
if (query) {
|
|
60
|
-
const {
|
|
61
|
-
total
|
|
62
|
-
} = await retrieveTotal();
|
|
63
|
-
const newQueriesWithTotals = [...queriesWithTotals, {
|
|
64
|
-
query,
|
|
65
|
-
total
|
|
66
|
-
}];
|
|
67
|
-
debug(`Query ${queryOffset} ${query} done.`);
|
|
68
|
-
debug(`There are (${queryList.length - (queryOffset + 1)} queries left)`);
|
|
69
|
-
return getQueryTotals({
|
|
70
|
-
queryList,
|
|
71
|
-
queryOffset: queryOffset + 1,
|
|
72
|
-
queriesWithTotals: newQueriesWithTotals
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
debug(`All ${queryList.length} queries done, there's no query for ${queryOffset}`);
|
|
76
|
-
return {
|
|
77
|
-
queriesWithTotals
|
|
78
|
-
};
|
|
79
|
-
function retrieveTotal() {
|
|
80
|
-
return new Promise((resolve, reject) => {
|
|
81
|
-
// eslint-disable-next-line functional/no-let
|
|
82
|
-
let totalRecords = 0;
|
|
83
|
-
debug(`Searching total amount of candidates for query: ${query}`);
|
|
84
|
-
client.searchRetrieve(query).on('error', err => {
|
|
85
|
-
// eslint-disable-next-line functional/no-conditional-statements
|
|
86
|
-
if (err instanceof _sruClient.SruSearchError) {
|
|
87
|
-
debug(`SRU SruSearchError for query: ${query}: ${err}`);
|
|
88
|
-
reject(new CandidateSearchError(`SRU SruSearchError for query: ${query}: ${err}`));
|
|
89
|
-
}
|
|
90
|
-
debug(`SRU error for query: ${query}: ${err}`);
|
|
91
|
-
reject(new CandidateSearchError(`SRU error for query: ${query}: ${err}`));
|
|
92
|
-
}).on('total', total => {
|
|
93
|
-
debug(`Got total: ${total}`);
|
|
94
|
-
totalRecords += total;
|
|
95
|
-
}).on('end', () => {
|
|
96
|
-
try {
|
|
97
|
-
resolve({
|
|
98
|
-
total: totalRecords
|
|
99
|
-
});
|
|
100
|
-
} catch (err) {
|
|
101
|
-
debug(`Error caught on END`);
|
|
102
|
-
reject(err);
|
|
103
|
-
}
|
|
104
|
-
}).on('record', () => {
|
|
105
|
-
debugDev(`RECORD: We should no get records here`);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
function filterQueryResult({
|
|
111
|
-
queriesWithTotals,
|
|
112
|
-
maxCandidates
|
|
113
|
-
}) {
|
|
114
|
-
debug(`Filtering queries (${queriesWithTotals.length}), maxCandidates: ${maxCandidates}`);
|
|
115
|
-
debugData(`${JSON.stringify(queriesWithTotals)}`);
|
|
116
|
-
// Drop queries where total result is 0 or greater than given maxCandidates
|
|
117
|
-
const filteredQueryResult = queriesWithTotals.filter(queryWithTotal => queryWithTotal.total !== 0 && queryWithTotal.total < maxCandidates);
|
|
118
|
-
debugData(`${JSON.stringify(filteredQueryResult)}`);
|
|
119
|
-
return filteredQueryResult;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
//# sourceMappingURL=choose-queries.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"choose-queries.js","names":["_debug","_interopRequireDefault","require","_sruClient","_interopRequireWildcard","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","hasOwnProperty","call","i","set","CandidateSearchError","Error","exports","_default","url","queryList","queryListType","maxCandidates","debug","createDebugLogger","debugData","extend","debugDev","client","createClient","maxRecordsPerRequest","version","retrieveAll","JSON","stringify","queriesWithTotals","getQueryTotals","queryOffset","filteredQueryResult","filterQueryResult","err","query","total","retrieveTotal","newQueriesWithTotals","length","Promise","resolve","reject","totalRecords","searchRetrieve","on","SruSearchError","filter","queryWithTotal"],"sources":["../../src/candidate-search/choose-queries.js"],"sourcesContent":["import createDebugLogger from 'debug';\nimport createClient, {SruSearchError} from '@natlibfi/sru-client';\n\nexport class CandidateSearchError extends Error {}\n\nexport default async function ({url, queryList, queryListType, maxCandidates = 50}) {\n\n const debug = createDebugLogger('@natlibfi/melinda-record-matching:candidate-search:choose-queries');\n const debugData = debug.extend('data');\n const debugDev = debug.extend('dev');\n\n debugData(`Url: ${url}`);\n debugData(`QueryList: ${queryList}`);\n debugData(`queryListType: ${queryListType}`);\n\n const client = createClient({\n url,\n maxRecordsPerRequest: 0,\n version: '2.0',\n retrieveAll: false\n });\n\n debugDev(`QueryList (type: ${queryListType}) ${JSON.stringify(queryList)}`);\n try {\n const {queriesWithTotals} = await getQueryTotals({queryList, queryOffset: 0, queriesWithTotals: []});\n debugDev(`QueryResult: ${JSON.stringify(queriesWithTotals)}`);\n const filteredQueryResult = filterQueryResult({queriesWithTotals, maxCandidates});\n debugDev(`filteredQueryResult: ${JSON.stringify(filteredQueryResult)}`);\n return filteredQueryResult;\n } catch (err) {\n throw new CandidateSearchError(err);\n }\n\n async function getQueryTotals({queryList, queryOffset = 0, queriesWithTotals = []}) {\n\n const query = queryList[queryOffset];\n debug(`Running query ${JSON.stringify(query)} (${queryOffset}) for total`);\n\n if (query) {\n const {total} = await retrieveTotal();\n\n const newQueriesWithTotals = [...queriesWithTotals, {query, total}];\n debug(`Query ${queryOffset} ${query} done.`);\n debug(`There are (${queryList.length - (queryOffset + 1)} queries left)`);\n return getQueryTotals({queryList, queryOffset: queryOffset + 1, queriesWithTotals: newQueriesWithTotals});\n }\n\n debug(`All ${queryList.length} queries done, there's no query for ${queryOffset}`);\n return {queriesWithTotals};\n\n function retrieveTotal() {\n return new Promise((resolve, reject) => {\n // eslint-disable-next-line functional/no-let\n let totalRecords = 0;\n\n debug(`Searching total amount of candidates for query: ${query}`);\n\n client.searchRetrieve(query)\n .on('error', err => {\n // eslint-disable-next-line functional/no-conditional-statements\n if (err instanceof SruSearchError) {\n debug(`SRU SruSearchError for query: ${query}: ${err}`);\n reject(new CandidateSearchError(`SRU SruSearchError for query: ${query}: ${err}`));\n }\n debug(`SRU error for query: ${query}: ${err}`);\n reject(new CandidateSearchError(`SRU error for query: ${query}: ${err}`));\n })\n .on('total', total => {\n debug(`Got total: ${total}`);\n totalRecords += total;\n })\n .on('end', () => {\n try {\n resolve({total: totalRecords});\n } catch (err) {\n debug(`Error caught on END`);\n reject(err);\n }\n })\n .on('record', () => {\n debugDev(`RECORD: We should no get records here`);\n });\n });\n }\n }\n function filterQueryResult({queriesWithTotals, maxCandidates}) {\n debug(`Filtering queries (${queriesWithTotals.length}), maxCandidates: ${maxCandidates}`);\n debugData(`${JSON.stringify(queriesWithTotals)}`);\n // Drop queries where total result is 0 or greater than given maxCandidates\n const filteredQueryResult = queriesWithTotals.filter((queryWithTotal) => queryWithTotal.total !== 0 && queryWithTotal.total < maxCandidates);\n debugData(`${JSON.stringify(filteredQueryResult)}`);\n return filteredQueryResult;\n }\n\n}\n"],"mappings":"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","ignoreList":[]}
|