@natlibfi/marc-record-merge 6.0.0-beta.9 → 7.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/CODEOWNERS +2 -9
- package/.github/dependabot.yml +2 -3
- package/.github/workflows/melinda-node-tests.yml +2 -2
- package/dist/index.js +49 -4
- package/dist/index.js.map +1 -1
- package/dist/index.spec.js +59 -0
- package/dist/index.spec.js.map +1 -0
- package/dist/reducers/copy.js +52 -62
- package/dist/reducers/copy.js.map +1 -1
- package/dist/reducers/copy.spec.js +6 -8
- package/dist/reducers/copy.spec.js.map +1 -1
- package/dist/reducers/copy2.spec.js +66 -0
- package/dist/reducers/copy2.spec.js.map +1 -0
- package/dist/reducers/index.js +0 -6
- package/dist/reducers/index.js.map +1 -1
- package/dist/reducers/select.js +43 -40
- package/dist/reducers/select.js.map +1 -1
- package/dist/reducers/select.spec.js +4 -15
- package/dist/reducers/select.spec.js.map +1 -1
- package/dist/reducers/select2.spec.js +58 -0
- package/dist/reducers/select2.spec.js.map +1 -0
- package/package.json +18 -18
- package/src/index.js +51 -1
- package/src/index.spec.js +45 -0
- package/src/reducers/copy.js +34 -8
- package/src/reducers/copy.spec.js +3 -1
- package/src/reducers/copy2.spec.js +55 -0
- package/src/reducers/select.js +31 -10
- package/src/reducers/select2.spec.js +49 -0
- package/test-fixtures/index/01/base.json +24 -0
- package/test-fixtures/index/01/merged.json +24 -0
- package/test-fixtures/index/01/metadata.json +8 -0
- package/test-fixtures/index/01/source.json +40 -0
- package/test-fixtures/index/02/base.json +24 -0
- package/test-fixtures/index/02/merged.json +24 -0
- package/test-fixtures/index/02/metadata.json +7 -0
- package/test-fixtures/index/02/source.json +40 -0
- package/test-fixtures/reducers/copy/04 - compareWithoutIndicators/03/metadata.json +6 -0
- package/test-fixtures/reducers/copy/04 - compareWithoutIndicators/04/base.json +20 -0
- package/test-fixtures/reducers/copy/04 - compareWithoutIndicators/04/merged.json +31 -0
- package/test-fixtures/reducers/copy/04 - compareWithoutIndicators/04/metadata.json +5 -0
- package/test-fixtures/reducers/copy/04 - compareWithoutIndicators/04/source.json +20 -0
- package/test-fixtures/reducers/copy/11 - compareWithoutTag/01/base.json +11 -0
- package/test-fixtures/reducers/copy/11 - compareWithoutTag/01/metadata.json +1 -2
- package/test-fixtures/reducers/copy/11 - compareWithoutTag/01/source.json +0 -11
- package/test-fixtures/reducers/copy/11 - compareWithoutTag/02/merged.json +11 -0
- package/test-fixtures/reducers/copy/11 - compareWithoutTag/02/metadata.json +1 -2
- package/test-fixtures/reducers/copy/11 - compareWithoutTag/02/source.json +6 -3
- package/test-fixtures/reducers/copy/11 - compareWithoutTag/04/base.json +17 -0
- package/test-fixtures/reducers/copy/11 - compareWithoutTag/04/merged.json +28 -0
- package/test-fixtures/reducers/copy/11 - compareWithoutTag/04/metadata.json +7 -0
- package/test-fixtures/reducers/copy/11 - compareWithoutTag/04/source.json +31 -0
- package/test-fixtures/reducers/copy/11 - compareWithoutTag/05/base.json +28 -0
- package/test-fixtures/reducers/copy/11 - compareWithoutTag/05/merged.json +28 -0
- package/test-fixtures/reducers/copy/11 - compareWithoutTag/05/metadata.json +7 -0
- package/test-fixtures/reducers/copy/11 - compareWithoutTag/05/source.json +28 -0
package/package.json
CHANGED
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
"url": "git@github.com:natlibfi/marc-record-merge-js.git"
|
|
15
15
|
},
|
|
16
16
|
"license": "MIT",
|
|
17
|
-
"version": "
|
|
17
|
+
"version": "7.0.0-alpha.1",
|
|
18
18
|
"main": "./dist/index.js",
|
|
19
19
|
"engines": {
|
|
20
|
-
"node": ">=
|
|
20
|
+
"node": ">=18"
|
|
21
21
|
},
|
|
22
22
|
"type": "commonjs",
|
|
23
23
|
"scripts": {
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"prepublishOnly": "npm run build:transpile",
|
|
26
26
|
"lint": "eslint ./src",
|
|
27
27
|
"lint:dev": "eslint ./src --fix",
|
|
28
|
-
"test:base": "cross-env NODE_ENV=test mocha --require @babel/register --reporter-option maxDiffSize=15000
|
|
29
|
-
"test": "npm run lint && npm run test:base",
|
|
28
|
+
"test:base": "cross-env NODE_ENV=test mocha --require @babel/register --reporter-option maxDiffSize=15000",
|
|
29
|
+
"test": "npm run lint && npm run test:base -- --recursive src",
|
|
30
30
|
"test:dev": "npm run lint:dev && npm run coverage",
|
|
31
31
|
"coverage": "npm run coverage:unit && npm run coverage:report",
|
|
32
32
|
"coverage:unit": "nyc --silent npm run test:base",
|
|
@@ -37,26 +37,26 @@
|
|
|
37
37
|
"dev:test:debug": "cross-env DEBUG=@natlibfi/* NODE_ENV=test nodemon -w src -w test-fixtures --exec 'clear && npm run test:dev'"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@natlibfi/
|
|
41
|
-
"@natlibfi/fixura": "^2.2.1",
|
|
42
|
-
"@natlibfi/marc-record": "^7.1.0-alpha.2",
|
|
40
|
+
"@natlibfi/marc-record": "^7.2.2",
|
|
43
41
|
"debug": "^4.3.4",
|
|
44
|
-
"normalize-diacritics": "2.
|
|
42
|
+
"normalize-diacritics": "^2.13.2"
|
|
45
43
|
},
|
|
46
44
|
"devDependencies": {
|
|
47
|
-
"@babel/cli": "^7.
|
|
48
|
-
"@babel/core": "^7.
|
|
49
|
-
"@babel/eslint-parser": "^7.
|
|
50
|
-
"@babel/preset-env": "^7.
|
|
51
|
-
"@babel/register": "^7.
|
|
52
|
-
"@natlibfi/eslint-config-melinda-backend": "^
|
|
45
|
+
"@babel/cli": "^7.21.0",
|
|
46
|
+
"@babel/core": "^7.21.4",
|
|
47
|
+
"@babel/eslint-parser": "^7.21.3",
|
|
48
|
+
"@babel/preset-env": "^7.21.4",
|
|
49
|
+
"@babel/register": "^7.21.0",
|
|
50
|
+
"@natlibfi/eslint-config-melinda-backend": "^3.0.0",
|
|
53
51
|
"babel-plugin-istanbul": "^6.1.1",
|
|
54
52
|
"babel-plugin-rewire": "^1.2.0",
|
|
55
|
-
"chai": "^4.3.
|
|
53
|
+
"chai": "^4.3.7",
|
|
56
54
|
"cross-env": "^7.0.3",
|
|
57
|
-
"eslint": "^8.
|
|
58
|
-
"mocha": "^10.
|
|
59
|
-
"
|
|
55
|
+
"eslint": "^8.38.0",
|
|
56
|
+
"mocha": "^10.2.0",
|
|
57
|
+
"@natlibfi/fixugen": "2.0.0",
|
|
58
|
+
"@natlibfi/fixura": "^3.0.0",
|
|
59
|
+
"nodemon": "^2.0.22",
|
|
60
60
|
"nyc": "^15.1.0"
|
|
61
61
|
},
|
|
62
62
|
"eslintConfig": {
|
package/src/index.js
CHANGED
|
@@ -1,4 +1,54 @@
|
|
|
1
1
|
import Reducers from './reducers';
|
|
2
|
+
import createDebugLogger from 'debug';
|
|
3
|
+
|
|
4
|
+
const debug = createDebugLogger('@natlibfi/melinda-marc-record-merge:index');
|
|
5
|
+
const debugData = debug.extend('data');
|
|
2
6
|
|
|
3
7
|
export {Reducers};
|
|
4
|
-
export default ({base, source, reducers}) => reducers.reduce((base, reducer) => reducer(base, source), base);
|
|
8
|
+
// export default ({base, source, reducers}) => reducers.reduce((base, reducer) => reducer(base, source), base);
|
|
9
|
+
|
|
10
|
+
// NV: Modified the reducer loop so, that not only base, but also is carried back.
|
|
11
|
+
// However, we try to be backward-compatible: normally after the reducers, only base is returned.
|
|
12
|
+
|
|
13
|
+
export default ({base, source, reducers}) => {
|
|
14
|
+
|
|
15
|
+
const combo = {base, source};
|
|
16
|
+
const resultCombo = reducers.reduce((combo, reducer) => {
|
|
17
|
+
const returnCombo = singleRound(reducer, combo.base, combo.source);
|
|
18
|
+
//debugData(`returnCombo after current reducer: ${JSON.stringify(returnCombo)}`);
|
|
19
|
+
return returnCombo;
|
|
20
|
+
}, combo);
|
|
21
|
+
|
|
22
|
+
debugData(`ResultCombo after reducers: ${JSON.stringify(resultCombo)}`);
|
|
23
|
+
|
|
24
|
+
// Hack to make my melinda-marc-record-merge-reducers single tests that expect both
|
|
25
|
+
// base and source to return them both:
|
|
26
|
+
if (reducers.length === 1 && resultCombo.base && resultCombo.source) {
|
|
27
|
+
debug('Single reducer, returning resultCombo');
|
|
28
|
+
debugData(JSON.stringify(resultCombo));
|
|
29
|
+
|
|
30
|
+
return resultCombo;
|
|
31
|
+
}
|
|
32
|
+
// All other tests return just base... Backward (compability) it is!
|
|
33
|
+
debug('Multiple reducers, returning just base');
|
|
34
|
+
debugData(JSON.stringify(resultCombo.base));
|
|
35
|
+
return resultCombo.base;
|
|
36
|
+
|
|
37
|
+
function singleRound(reducer, base, source) {
|
|
38
|
+
//debug(`SINGLE ROUND INPUT (base, source)`);
|
|
39
|
+
//debugData(base);
|
|
40
|
+
//debugData(base);
|
|
41
|
+
const reducerResult = reducer(base, source);
|
|
42
|
+
//debug(`reducerResult:`);
|
|
43
|
+
//debugData(reducerResult);
|
|
44
|
+
if (reducerResult.base !== undefined && reducerResult.source !== undefined) {
|
|
45
|
+
debug('NEW STYLE REDUCER RESULT v2');
|
|
46
|
+
const combo = reducerResult;
|
|
47
|
+
//debugData(combo);
|
|
48
|
+
return combo;
|
|
49
|
+
}
|
|
50
|
+
debug('OLD SCHOOL REDUCER RESULT v2');
|
|
51
|
+
//debugData({base: reducerResult, source});
|
|
52
|
+
return {base: reducerResult, source};
|
|
53
|
+
}
|
|
54
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import merger, {Reducers} from './index';
|
|
2
|
+
import {inspect} from 'util';
|
|
3
|
+
import createDebugLogger from 'debug';
|
|
4
|
+
import {expect} from 'chai';
|
|
5
|
+
import {MarcRecord} from '@natlibfi/marc-record';
|
|
6
|
+
import {READERS} from '@natlibfi/fixura';
|
|
7
|
+
import generateTests from '@natlibfi/fixugen';
|
|
8
|
+
|
|
9
|
+
generateTests({
|
|
10
|
+
callback,
|
|
11
|
+
path: [__dirname, '..', 'test-fixtures', 'index'],
|
|
12
|
+
recurse: false,
|
|
13
|
+
useMetadataFile: true,
|
|
14
|
+
fixura: {
|
|
15
|
+
failWhenNotFound: false,
|
|
16
|
+
reader: READERS.JSON
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
function callback({getFixture, reducerConfigs = []}) {
|
|
21
|
+
const base = new MarcRecord(getFixture('base.json'), {subfieldValues: false});
|
|
22
|
+
const source = new MarcRecord(getFixture('source.json'), {subfieldValues: false});
|
|
23
|
+
const expectedRecord = getFixture('merged.json');
|
|
24
|
+
|
|
25
|
+
const debug = createDebugLogger('@natlibfi/melinda-marc-record-merge-reducers:index:test');
|
|
26
|
+
const debugData = debug.extend('data');
|
|
27
|
+
|
|
28
|
+
const testReducerConfigs = reducerConfigs;
|
|
29
|
+
const reducers = [...testReducerConfigs.map(conf => Reducers.copy(conf))];
|
|
30
|
+
|
|
31
|
+
debugData(`Reducers: ${inspect(reducers, {colors: true, maxArrayLength: 10, depth: 8})})}`);
|
|
32
|
+
|
|
33
|
+
const result = merger({base, source, reducers});
|
|
34
|
+
|
|
35
|
+
debug(`Merge result is: ${result.constructor.name}`);
|
|
36
|
+
debugData(`${JSON.stringify(result)}`);
|
|
37
|
+
|
|
38
|
+
// Use either result.base or a plain result as resultRecord
|
|
39
|
+
// It can also be a MarcRecord or a plain object
|
|
40
|
+
const resultRecord = result.base || result;
|
|
41
|
+
const resultRecordToRecord = new MarcRecord(resultRecord, {subfieldValues: false});
|
|
42
|
+
expect(resultRecordToRecord.toObject()).to.eql(expectedRecord);
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
}
|
package/src/reducers/copy.js
CHANGED
|
@@ -9,6 +9,8 @@ export default ({
|
|
|
9
9
|
compareTagsOnly = false,
|
|
10
10
|
compareWithoutTag = false,
|
|
11
11
|
compareWithoutIndicators = false,
|
|
12
|
+
compareWithoutIndicator1 = false,
|
|
13
|
+
compareWithoutIndicator2 = false,
|
|
12
14
|
subfieldsMustBeIdentical = true,
|
|
13
15
|
excludeSubfields = [],
|
|
14
16
|
dropSubfields = [],
|
|
@@ -19,15 +21,37 @@ export default ({
|
|
|
19
21
|
swapSubfieldCode = [],
|
|
20
22
|
doNotCopyIfFieldPresent = false
|
|
21
23
|
}) => (base, source) => {
|
|
22
|
-
const baseRecord = new MarcRecord(base, baseValidators);
|
|
23
|
-
const sourceRecord = new MarcRecord(source, sourceValidators);
|
|
24
24
|
|
|
25
|
-
const debug = createDebugLogger('@natlibfi/marc-record-merge');
|
|
25
|
+
const debug = createDebugLogger('@natlibfi/marc-record-merge:copy');
|
|
26
|
+
const debugData = debug.extend('data');
|
|
26
27
|
const debugOptions = createDebugLogger('@natlibfi/marc-record-merge:compare-options');
|
|
27
28
|
const debugCompare = createDebugLogger('@natlibfi/marc-record-merge:compare');
|
|
29
|
+
|
|
30
|
+
debugData(`base: ${JSON.stringify(base)}`);
|
|
31
|
+
debugData(`source: ${JSON.stringify(source)}`);
|
|
32
|
+
|
|
33
|
+
const {baseRecord, sourceRecord} = getRecordsFromParameters(base, source, baseValidators, sourceValidators);
|
|
34
|
+
|
|
35
|
+
function getRecordsFromParameters(base, source, baseValidators, sourceValidators) {
|
|
36
|
+
// records if we got an object ({base, source}) as a parameter
|
|
37
|
+
if (source === undefined && base.base !== undefined && base.source !== undefined) {
|
|
38
|
+
const baseRecord = new MarcRecord(base.base, baseValidators);
|
|
39
|
+
const sourceRecord = new MarcRecord(base.source, sourceValidators);
|
|
40
|
+
return {baseRecord, sourceRecord};
|
|
41
|
+
}
|
|
42
|
+
// records if we got an non-object (base, source) as a parameter
|
|
43
|
+
const baseRecord = new MarcRecord(base, baseValidators);
|
|
44
|
+
const sourceRecord = new MarcRecord(source, sourceValidators);
|
|
45
|
+
return {baseRecord, sourceRecord};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const ignoreInd1 = compareWithoutIndicators || compareWithoutIndicator1;
|
|
49
|
+
const ignoreInd2 = compareWithoutIndicators || compareWithoutIndicator2;
|
|
50
|
+
|
|
28
51
|
debugOptions(`Tag Pattern: ${tagPattern}`);
|
|
29
52
|
debugOptions(`Compare tags only: ${compareTagsOnly}`);
|
|
30
|
-
debugOptions(`
|
|
53
|
+
debugOptions(`Omit indicator 1 from comparison: ${ignoreInd1}`);
|
|
54
|
+
debugOptions(`Omit indicator 2 from comparison: ${ignoreInd2}`);
|
|
31
55
|
debugOptions(`Copy if identical: ${subfieldsMustBeIdentical}`);
|
|
32
56
|
debugOptions(`Exclude subfields: [${excludeSubfields}]`);
|
|
33
57
|
debugOptions(`Drop subfields [${dropSubfields}]`);
|
|
@@ -40,7 +64,7 @@ export default ({
|
|
|
40
64
|
if (doNotCopy) {
|
|
41
65
|
return baseRecord.toObject();
|
|
42
66
|
}
|
|
43
|
-
|
|
67
|
+
debug(`FFS: ${compareWithoutIndicator1}, ${compareWithoutIndicators}, ${ignoreInd1}`);
|
|
44
68
|
debug(`Base fields: `, baseFields);
|
|
45
69
|
debug(`Source fields: `, sourceFields);
|
|
46
70
|
|
|
@@ -57,6 +81,8 @@ export default ({
|
|
|
57
81
|
|
|
58
82
|
// Add fields to base;
|
|
59
83
|
uniqueFields.forEach(field => baseRecord.insertField(field));
|
|
84
|
+
debugData(`baseRecord before return: ${JSON.stringify(baseRecord)}`);
|
|
85
|
+
//return baseRecord;
|
|
60
86
|
return baseRecord.toObject();
|
|
61
87
|
|
|
62
88
|
function compareFields(sourceFields, baseCompareFields, uniqFields = []) {
|
|
@@ -132,7 +158,7 @@ export default ({
|
|
|
132
158
|
}
|
|
133
159
|
}
|
|
134
160
|
|
|
135
|
-
// compare objects have only fields that matter in
|
|
161
|
+
// compare objects have only fields that matter in comparison
|
|
136
162
|
function createCompareField(field) {
|
|
137
163
|
if (compareTagsOnly) {
|
|
138
164
|
return {tag: field.tag};
|
|
@@ -148,8 +174,8 @@ export default ({
|
|
|
148
174
|
|
|
149
175
|
const params = [
|
|
150
176
|
{name: 'tag', value: compareWithoutTag ? replacementTag : field.tag},
|
|
151
|
-
{name: 'ind1', value:
|
|
152
|
-
{name: 'ind2', value:
|
|
177
|
+
{name: 'ind1', value: ignoreInd1 ? undefined : field.ind1},
|
|
178
|
+
{name: 'ind2', value: ignoreInd2 ? undefined : field.ind2},
|
|
153
179
|
{name: 'subfields', value: createCompareSubfields(filteredField.subfields)}
|
|
154
180
|
].map(param => [param.name, param.value]);
|
|
155
181
|
|
|
@@ -23,6 +23,8 @@ function callback({
|
|
|
23
23
|
compareTagsOnly = false,
|
|
24
24
|
compareWithoutTag = false,
|
|
25
25
|
compareWithoutIndicators = false,
|
|
26
|
+
compareWithoutIndicator1 = false,
|
|
27
|
+
compareWithoutIndicator2 = false,
|
|
26
28
|
subfieldsMustBeIdentical = false,
|
|
27
29
|
copyUnless = undefined,
|
|
28
30
|
excludeSubfields = undefined,
|
|
@@ -37,7 +39,7 @@ function callback({
|
|
|
37
39
|
const expectedRecord = getFixture('merged.json');
|
|
38
40
|
|
|
39
41
|
const merged = createReducer({
|
|
40
|
-
tagPattern, compareTagsOnly, compareWithoutTag, compareWithoutIndicators,
|
|
42
|
+
tagPattern, compareTagsOnly, compareWithoutTag, compareWithoutIndicators, compareWithoutIndicator1, compareWithoutIndicator2,
|
|
41
43
|
copyUnless, subfieldsMustBeIdentical, excludeSubfields,
|
|
42
44
|
dropSubfields, swapSubfieldCode, swapTag,
|
|
43
45
|
doNotCopyIfFieldPresent
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {READERS} from '@natlibfi/fixura';
|
|
3
|
+
import createReducer from './copy';
|
|
4
|
+
import generateTests from '@natlibfi/fixugen';
|
|
5
|
+
|
|
6
|
+
//import createDebugLogger from 'debug'; // <---
|
|
7
|
+
//const debug = createDebugLogger('@natlibfi/marc-record-merge/copy.spec.js'); // <---
|
|
8
|
+
|
|
9
|
+
generateTests({
|
|
10
|
+
callback,
|
|
11
|
+
path: [__dirname, '..', '..', 'test-fixtures', 'reducers', 'copy'],
|
|
12
|
+
useMetadataFile: true,
|
|
13
|
+
recurse: true,
|
|
14
|
+
fixura: {
|
|
15
|
+
reader: READERS.JSON,
|
|
16
|
+
failWhenNotFound: false
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
function callback({
|
|
22
|
+
getFixture,
|
|
23
|
+
tagPatternRegExp,
|
|
24
|
+
compareTagsOnly = false,
|
|
25
|
+
compareWithoutTag = false,
|
|
26
|
+
compareWithoutIndicators = false,
|
|
27
|
+
compareWithoutIndicator1 = false,
|
|
28
|
+
compareWithoutIndicator2 = false,
|
|
29
|
+
subfieldsMustBeIdentical = false,
|
|
30
|
+
copyUnless = undefined,
|
|
31
|
+
excludeSubfields = undefined,
|
|
32
|
+
dropSubfields = undefined,
|
|
33
|
+
swapSubfieldCode = [],
|
|
34
|
+
swapTag = [],
|
|
35
|
+
doNotCopyIfFieldPresent = false
|
|
36
|
+
}) {
|
|
37
|
+
const base = getFixture('base.json');
|
|
38
|
+
const source = getFixture('source.json');
|
|
39
|
+
const tagPattern = new RegExp(tagPatternRegExp, 'u');
|
|
40
|
+
const expectedRecord = getFixture('merged.json');
|
|
41
|
+
|
|
42
|
+
const merged = createReducer({
|
|
43
|
+
tagPattern, compareTagsOnly, compareWithoutTag, compareWithoutIndicators, compareWithoutIndicator1, compareWithoutIndicator2,
|
|
44
|
+
copyUnless, subfieldsMustBeIdentical, excludeSubfields,
|
|
45
|
+
dropSubfields, swapSubfieldCode, swapTag,
|
|
46
|
+
doNotCopyIfFieldPresent
|
|
47
|
+
})({base, source});
|
|
48
|
+
//debug(`*** mergedRecord: `, mergedRecord); //<--
|
|
49
|
+
//debug(`*** mergedRecord,Strfy: `, JSON.stringify(mergedRecord)); //<--
|
|
50
|
+
//debug(`*** expectedRecord: `, expectedRecord); //<--
|
|
51
|
+
//debug(`*** expectedRecord,Strfy: `, JSON.stringify(expectedRecord)); //<--
|
|
52
|
+
expect(merged.constructor.name).not.to.eql('MarcRecord');
|
|
53
|
+
expect(merged.constructor.name).to.eql('Object');
|
|
54
|
+
expect(merged).to.eql(expectedRecord);
|
|
55
|
+
}
|
package/src/reducers/select.js
CHANGED
|
@@ -12,10 +12,31 @@ export function subsetEquality(subfieldA, subfieldB) {
|
|
|
12
12
|
(subfieldA.value.indexOf(subfieldB.value) !== -1 || subfieldB.value.indexOf(subfieldA.value) !== -1);
|
|
13
13
|
}
|
|
14
14
|
// EqualityFunction can be either strictEquality or subsetEquality
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
export default ({
|
|
17
|
+
tagPattern,
|
|
18
|
+
equalityFunction = strictEquality,
|
|
19
|
+
baseValidators = {subfieldValues: false},
|
|
20
|
+
sourceValidators = {subfieldValues: false}
|
|
21
|
+
// eslint-disable-next-line max-statements
|
|
22
|
+
}) => (base, source) => {
|
|
16
23
|
const debug = createDebugLogger('@natlibfi/marc-record-merge:select');
|
|
17
|
-
|
|
18
|
-
const sourceRecord =
|
|
24
|
+
|
|
25
|
+
const {baseRecord, sourceRecord} = getRecordsFromParameters(base, source, baseValidators, sourceValidators);
|
|
26
|
+
|
|
27
|
+
function getRecordsFromParameters(base, source, baseValidators, sourceValidators) {
|
|
28
|
+
// records if we got an object ({base, source}) as a parameter
|
|
29
|
+
if (source === undefined && base.base !== undefined && base.source !== undefined) {
|
|
30
|
+
const baseRecord = new MarcRecord(base.base, baseValidators);
|
|
31
|
+
const sourceRecord = new MarcRecord(base.source, sourceValidators);
|
|
32
|
+
return {baseRecord, sourceRecord};
|
|
33
|
+
}
|
|
34
|
+
// records if we got an non-object (base, source) as a parameter
|
|
35
|
+
const baseRecord = new MarcRecord(base, baseValidators);
|
|
36
|
+
const sourceRecord = new MarcRecord(source, sourceValidators);
|
|
37
|
+
return {baseRecord, sourceRecord};
|
|
38
|
+
}
|
|
39
|
+
|
|
19
40
|
const baseFields = baseRecord.get(tagPattern);
|
|
20
41
|
const sourceFields = sourceRecord.get(tagPattern);
|
|
21
42
|
const fieldTag = sourceFields.map(field => field.tag);
|
|
@@ -27,7 +48,7 @@ export default ({tagPattern, equalityFunction = strictEquality}) => (base, sourc
|
|
|
27
48
|
if (baseFields.length > 1 || sourceFields.length > 1) {
|
|
28
49
|
debug(`Multiple fields in base or source`);
|
|
29
50
|
debug(`No changes to base`);
|
|
30
|
-
return
|
|
51
|
+
return baseRecord.toObject();
|
|
31
52
|
}
|
|
32
53
|
const [baseField] = baseFields;
|
|
33
54
|
const [sourceField] = sourceFields;
|
|
@@ -35,7 +56,7 @@ export default ({tagPattern, equalityFunction = strictEquality}) => (base, sourc
|
|
|
35
56
|
if (baseField.tag === sourceField.tag === false) {
|
|
36
57
|
debug(`Base tag ${baseField.tag} is not equal to source tag ${sourceField.tag}`);
|
|
37
58
|
debug(`No changes to base`);
|
|
38
|
-
return
|
|
59
|
+
return baseRecord.toObject();
|
|
39
60
|
}
|
|
40
61
|
const baseSubs = baseField.subfields;
|
|
41
62
|
const sourceSubs = sourceField.subfields;
|
|
@@ -61,7 +82,7 @@ export default ({tagPattern, equalityFunction = strictEquality}) => (base, sourc
|
|
|
61
82
|
if (baseSubs.length === sourceSubs.length && equalSubfieldsBase.length < baseSubs.length) {
|
|
62
83
|
debug(`Base and source subfields are not equal`);
|
|
63
84
|
debug(`No changes to base`);
|
|
64
|
-
return
|
|
85
|
+
return baseRecord.toObject();
|
|
65
86
|
}
|
|
66
87
|
|
|
67
88
|
if (baseSubs.length === sourceSubs.length && equalSubfieldsBase.length === equalSubfieldsSource.length) {
|
|
@@ -74,16 +95,16 @@ export default ({tagPattern, equalityFunction = strictEquality}) => (base, sourc
|
|
|
74
95
|
.reduce((acc, value) => acc + value);
|
|
75
96
|
|
|
76
97
|
if (totalSubfieldLengthSource > totalSubfieldLengthBase) {
|
|
77
|
-
return replaceBasefieldWithSourcefield(
|
|
98
|
+
return replaceBasefieldWithSourcefield(baseRecord.toObject());
|
|
78
99
|
}
|
|
79
100
|
}
|
|
80
101
|
|
|
81
102
|
if (sourceSubs.length > baseSubs.length && equalSubfieldsBase.length === baseSubs.length) {
|
|
82
|
-
return replaceBasefieldWithSourcefield(
|
|
103
|
+
return replaceBasefieldWithSourcefield(baseRecord.toObject());
|
|
83
104
|
}
|
|
84
105
|
|
|
85
106
|
debug(`No changes to base`);
|
|
86
|
-
return
|
|
107
|
+
return baseRecord.toObject();
|
|
87
108
|
|
|
88
109
|
function replaceBasefieldWithSourcefield(base) {
|
|
89
110
|
const index = base.fields.findIndex(field => field === baseField);
|
|
@@ -94,7 +115,7 @@ export default ({tagPattern, equalityFunction = strictEquality}) => (base, sourc
|
|
|
94
115
|
|
|
95
116
|
function checkFieldType(fields) {
|
|
96
117
|
const checkedFields = fields.map(field => {
|
|
97
|
-
if ('value' in field) { // eslint-disable-line functional/no-conditional-
|
|
118
|
+
if ('value' in field) { // eslint-disable-line functional/no-conditional-statements
|
|
98
119
|
throw new Error('Invalid control field, expected data field');
|
|
99
120
|
}
|
|
100
121
|
return field;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {MarcRecord} from '@natlibfi/marc-record';
|
|
3
|
+
import createReducer, {subsetEquality} from './select';
|
|
4
|
+
import {READERS} from '@natlibfi/fixura';
|
|
5
|
+
import generateTests from '@natlibfi/fixugen';
|
|
6
|
+
|
|
7
|
+
MarcRecord.setValidationOptions({subfieldValues: false});
|
|
8
|
+
|
|
9
|
+
generateTests({
|
|
10
|
+
callback,
|
|
11
|
+
path: [__dirname, '..', '..', 'test-fixtures', 'reducers', 'select'],
|
|
12
|
+
useMetadataFile: true,
|
|
13
|
+
recurse: false,
|
|
14
|
+
fixura: {
|
|
15
|
+
reader: READERS.JSON,
|
|
16
|
+
failWhenNotFound: false
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
function callback({
|
|
21
|
+
getFixture,
|
|
22
|
+
disabled = false,
|
|
23
|
+
tagPatternRegExp = false,
|
|
24
|
+
expectedError = false,
|
|
25
|
+
useSubsetEquality = false
|
|
26
|
+
}) {
|
|
27
|
+
if (disabled) {
|
|
28
|
+
console.log('TEST DISABLED!'); // eslint-disable-line no-console
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// const base = new MarcRecord(getFixture('base.json'), {subfieldValues: false});
|
|
32
|
+
// const source = new MarcRecord(getFixture('source.json'), {subfieldValues: false});
|
|
33
|
+
|
|
34
|
+
const base = getFixture('base.json');
|
|
35
|
+
const source = getFixture('source.json');
|
|
36
|
+
|
|
37
|
+
const tagPattern = new RegExp(tagPatternRegExp, 'u');
|
|
38
|
+
const expectedRecord = getFixture('merged.json');
|
|
39
|
+
const equalityFunction = useSubsetEquality ? subsetEquality : undefined;
|
|
40
|
+
|
|
41
|
+
// Bypass expected error in testing
|
|
42
|
+
if (expectedError) {
|
|
43
|
+
expect(() => createReducer.to.throw(Error, 'control field'));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const mergedRecord = createReducer({tagPattern, equalityFunction})({base, source});
|
|
48
|
+
expect(mergedRecord).to.eql(expectedRecord);
|
|
49
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"leader": "01331cam a22003494i 4500",
|
|
3
|
+
"fields": [
|
|
4
|
+
{
|
|
5
|
+
"tag": "001",
|
|
6
|
+
"value": "001_base"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"tag": "010",
|
|
10
|
+
"ind1": " ",
|
|
11
|
+
"ind2": " ",
|
|
12
|
+
"subfields": [
|
|
13
|
+
{
|
|
14
|
+
"code": "a",
|
|
15
|
+
"value": "010a_base"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"code": "b",
|
|
19
|
+
"value": "010b_base"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"leader": "01331cam a22003494i 4500",
|
|
3
|
+
"fields": [
|
|
4
|
+
{
|
|
5
|
+
"tag": "001",
|
|
6
|
+
"value": "001_base"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"tag": "010",
|
|
10
|
+
"ind1": " ",
|
|
11
|
+
"ind2": " ",
|
|
12
|
+
"subfields": [
|
|
13
|
+
{
|
|
14
|
+
"code": "a",
|
|
15
|
+
"value": "010a_base"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"code": "b",
|
|
19
|
+
"value": "010b_base"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"leader": "01331cam a22003494i 4500",
|
|
3
|
+
"fields": [
|
|
4
|
+
{
|
|
5
|
+
"tag": "001",
|
|
6
|
+
"value": "001_sorsa"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"tag": "010",
|
|
10
|
+
"ind1": " ",
|
|
11
|
+
"ind2": " ",
|
|
12
|
+
"subfields": [
|
|
13
|
+
{
|
|
14
|
+
"code": "a",
|
|
15
|
+
"value": "010a_sorsa"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"code": "b",
|
|
19
|
+
"value": "010b_sorsa"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"tag": "650",
|
|
25
|
+
"ind1": " ",
|
|
26
|
+
"ind2": "7",
|
|
27
|
+
"subfields": [
|
|
28
|
+
{
|
|
29
|
+
"code": "a",
|
|
30
|
+
"value": "poista mut"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"code": "2",
|
|
34
|
+
"value": "ysa"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
]
|
|
40
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"leader": "01331cam a22003494i 4500",
|
|
3
|
+
"fields": [
|
|
4
|
+
{
|
|
5
|
+
"tag": "001",
|
|
6
|
+
"value": "001_base"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"tag": "010",
|
|
10
|
+
"ind1": " ",
|
|
11
|
+
"ind2": " ",
|
|
12
|
+
"subfields": [
|
|
13
|
+
{
|
|
14
|
+
"code": "a",
|
|
15
|
+
"value": "010a_base"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"code": "b",
|
|
19
|
+
"value": "010b_base"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"leader": "01331cam a22003494i 4500",
|
|
3
|
+
"fields": [
|
|
4
|
+
{
|
|
5
|
+
"tag": "001",
|
|
6
|
+
"value": "001_base"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"tag": "010",
|
|
10
|
+
"ind1": " ",
|
|
11
|
+
"ind2": " ",
|
|
12
|
+
"subfields": [
|
|
13
|
+
{
|
|
14
|
+
"code": "a",
|
|
15
|
+
"value": "010a_base"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"code": "b",
|
|
19
|
+
"value": "010b_base"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"leader": "01331cam a22003494i 4500",
|
|
3
|
+
"fields": [
|
|
4
|
+
{
|
|
5
|
+
"tag": "001",
|
|
6
|
+
"value": "001_sorsa"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"tag": "010",
|
|
10
|
+
"ind1": " ",
|
|
11
|
+
"ind2": " ",
|
|
12
|
+
"subfields": [
|
|
13
|
+
{
|
|
14
|
+
"code": "a",
|
|
15
|
+
"value": "010a_sorsa"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"code": "b",
|
|
19
|
+
"value": "010b_sorsa"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"tag": "650",
|
|
25
|
+
"ind1": " ",
|
|
26
|
+
"ind2": "7",
|
|
27
|
+
"subfields": [
|
|
28
|
+
{
|
|
29
|
+
"code": "a",
|
|
30
|
+
"value": "poista mut"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"code": "2",
|
|
34
|
+
"value": "ysa"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
]
|
|
40
|
+
}
|