@natlibfi/melinda-record-matching 2.2.0-alpha.1 → 2.2.0-alpha.4

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.
Files changed (45) hide show
  1. package/dist/candidate-search/candidate-search-utils.js.map +1 -1
  2. package/dist/candidate-search/index.js +9 -9
  3. package/dist/candidate-search/index.js.map +1 -1
  4. package/dist/candidate-search/index.spec.js.map +1 -1
  5. package/dist/candidate-search/query-list/bib.js +2 -2
  6. package/dist/candidate-search/query-list/bib.js.map +1 -1
  7. package/dist/candidate-search/query-list/bib.spec.js.map +1 -1
  8. package/dist/candidate-search/query-list/index.js.map +1 -1
  9. package/dist/index.js +103 -33
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.spec.js.map +1 -1
  12. package/dist/match-detection/features/bib/all-source-ids.js.map +1 -1
  13. package/dist/match-detection/features/bib/authors.js +1 -1
  14. package/dist/match-detection/features/bib/authors.js.map +1 -1
  15. package/dist/match-detection/features/bib/bibliographic-level.js.map +1 -1
  16. package/dist/match-detection/features/bib/host-component.js.map +1 -1
  17. package/dist/match-detection/features/bib/index.js.map +1 -1
  18. package/dist/match-detection/features/bib/index.spec.js.map +1 -1
  19. package/dist/match-detection/features/bib/isbn.js.map +1 -1
  20. package/dist/match-detection/features/bib/issn.js.map +1 -1
  21. package/dist/match-detection/features/bib/language.js.map +1 -1
  22. package/dist/match-detection/features/bib/melinda-id.js.map +1 -1
  23. package/dist/match-detection/features/bib/melinda-identifier-factory.js.map +1 -1
  24. package/dist/match-detection/features/bib/other-standard-identifier.js.map +1 -1
  25. package/dist/match-detection/features/bib/publication-time.js.map +1 -1
  26. package/dist/match-detection/features/bib/record-type.js.map +1 -1
  27. package/dist/match-detection/features/bib/standard-identifier-factory.js +3 -2
  28. package/dist/match-detection/features/bib/standard-identifier-factory.js.map +1 -1
  29. package/dist/match-detection/features/bib/title.js.map +1 -1
  30. package/dist/match-detection/features/index.js.map +1 -1
  31. package/dist/match-detection/index.js +36 -30
  32. package/dist/match-detection/index.js.map +1 -1
  33. package/dist/match-detection/index.spec.js +20 -2
  34. package/dist/match-detection/index.spec.js.map +1 -1
  35. package/dist/matching-utils.js +1 -1
  36. package/dist/matching-utils.js.map +1 -1
  37. package/package.json +13 -13
  38. package/src/candidate-search/index.js +11 -8
  39. package/src/candidate-search/query-list/bib.js +2 -2
  40. package/src/index.js +71 -30
  41. package/src/match-detection/features/bib/authors.js +1 -1
  42. package/src/match-detection/features/bib/standard-identifier-factory.js +2 -1
  43. package/src/match-detection/index.js +29 -19
  44. package/src/match-detection/index.spec.js +17 -3
  45. package/src/matching-utils.js +1 -1
package/dist/index.js CHANGED
@@ -48,6 +48,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
48
48
  * for the JavaScript code in this file.
49
49
  *
50
50
  */
51
+ //import inspect from 'util';
51
52
  var _default = ({
52
53
  detection: detectionOptions,
53
54
  search: searchOptions,
@@ -56,7 +57,7 @@ var _default = ({
56
57
  returnStrategy = false,
57
58
  returnQuery = false,
58
59
  returnNonMatches = false,
59
- returnFailures
60
+ returnFailures = false
60
61
  }) => {
61
62
  const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:index');
62
63
  const debugData = debug.extend('data');
@@ -93,7 +94,8 @@ var _default = ({
93
94
  nonMatches = [],
94
95
  duplicateCount = 0,
95
96
  nonMatchCount = 0,
96
- conversionFailures = []
97
+ conversionFailures = [],
98
+ matchErrors = []
97
99
  }) {
98
100
  debugData(`Starting next matcher iteration.`);
99
101
  const {
@@ -101,7 +103,7 @@ var _default = ({
101
103
  failures,
102
104
  ...state
103
105
  } = await search(initialState);
104
- debugData(`Current state: ${JSON.stringify(state)}, matches: ${matches.length}, candidateCount: ${candidateCount}, nonMatches: ${nonMatches.length}, nonMatchCount: ${nonMatchCount}, conversionFailures: ${conversionFailures}`);
106
+ debugData(`Current state: ${JSON.stringify(state)}, matches: ${matches.length}, candidateCount: ${candidateCount}, nonMatches: ${nonMatches.length}, nonMatchCount: ${nonMatchCount}, conversionFailures: ${conversionFailures}, matchErrors: ${matchErrors.length}`);
105
107
  const recordSetSize = records.length;
106
108
  const failureSetSize = failures.length;
107
109
  const newCandidateCount = candidateCount + recordSetSize + failureSetSize;
@@ -121,7 +123,8 @@ var _default = ({
121
123
  nonMatches,
122
124
  nonMatchCount,
123
125
  duplicateCount,
124
- conversionFailures: newConversionFailures
126
+ conversionFailures: newConversionFailures,
127
+ matchErrors
125
128
  });
126
129
  }
127
130
 
@@ -134,7 +137,8 @@ var _default = ({
134
137
  nonMatchCount,
135
138
  candidateCount: newCandidateCount,
136
139
  duplicateCount,
137
- conversionFailures: newConversionFailures
140
+ conversionFailures: newConversionFailures,
141
+ matchErrors
138
142
  });
139
143
 
140
144
  function handleRecordSet() {
@@ -151,8 +155,9 @@ var _default = ({
151
155
  const newNonMatchCount = nonMatchCount + matchResult.nonMatchCount;
152
156
  const {
153
157
  newMatches,
154
- newNonMatches
155
- } = handleMatchResult(matchResult, matches, nonMatches);
158
+ newNonMatches,
159
+ newMatchErrors
160
+ } = handleMatchResult(matchResult, matches, nonMatches, matchErrors);
156
161
 
157
162
  if (maxMatchesFound({
158
163
  matches: newMatches,
@@ -166,7 +171,8 @@ var _default = ({
166
171
  duplicateCount: newDuplicateCount,
167
172
  candidateCount: newCandidateCount,
168
173
  nonMatchCount: newNonMatchCount,
169
- conversionFailures: newConversionFailures
174
+ conversionFailures: newConversionFailures,
175
+ matchErrors: newMatchErrors
170
176
  });
171
177
  }
172
178
 
@@ -179,7 +185,8 @@ var _default = ({
179
185
  duplicateCount: newDuplicateCount,
180
186
  candidateCount: newCandidateCount,
181
187
  nonMatchCount: newNonMatchCount,
182
- conversionFailures: newConversionFailures
188
+ conversionFailures: newConversionFailures,
189
+ matchErrors: newMatchErrors
183
190
  });
184
191
  }
185
192
 
@@ -190,11 +197,12 @@ var _default = ({
190
197
  nonMatches: newNonMatches,
191
198
  duplicateCount: newDuplicateCount,
192
199
  nonMatchCount: newNonMatchCount,
193
- conversionFailures: newConversionFailures
200
+ conversionFailures: newConversionFailures,
201
+ matchErrors: newMatchErrors
194
202
  });
195
203
  }
196
204
 
197
- function handleMatchResult(matchResult, matches, nonMatches) {
205
+ function handleMatchResult(matchResult, matches, nonMatches, matchErrors) {
198
206
  debugData(`- Amount of new matches from record set: ${matchResult.matches.length}`); // eslint-disable-next-line functional/no-conditional-statement
199
207
 
200
208
  if (returnNonMatches) {
@@ -203,15 +211,20 @@ var _default = ({
203
211
 
204
212
  const newMatches = matches.concat(returnQuery ? addQuery(matchResult.matches) : matchResult.matches);
205
213
  const newNonMatches = returnNonMatches ? nonMatches.concat(returnQuery ? addQuery(matchResult.nonMatches) : matchResult.nonMatches) : [];
214
+ const newMatchErrors = matchErrors.concat(matchResult.matchErrors);
206
215
  debugData(`- Total amount of matches: ${newMatches.length}`); // eslint-disable-next-line functional/no-conditional-statement
207
216
 
208
217
  if (returnNonMatches) {
209
218
  debugData(`- Total amount of nonMatches: ${newNonMatches.length}`);
210
219
  }
211
220
 
221
+ debugData(`MatchResult: ${JSON.stringify(matchResult)}`);
222
+ debugData(`Old matchErrors: ${JSON.stringify(matchErrors)}, matchErrors from matchResult: ${JSON.stringify(matchResult.matchErrors)}, New matchErrors: ${JSON.stringify(newMatchErrors)}`);
223
+ debugData(`- Total amount of matchErrors: ${newMatchErrors.length}`);
212
224
  return {
213
225
  newMatches,
214
- newNonMatches
226
+ newNonMatches,
227
+ newMatchErrors
215
228
  };
216
229
  }
217
230
 
@@ -238,6 +251,7 @@ var _default = ({
238
251
  // - strategy (if returnStrategy option is true)
239
252
  // - treshold (if returnStrategy option is true)
240
253
  // - matchQuery (if returnQuery option is true)
254
+ // failures: array of conversionFailures from candidate-search and matchErrors from matchDetection in error format {status, payload: {message, id}} if returnFailures is true
241
255
  // we could have here also returnRecords/returnMatchRecords/returnNonMatchRecord options that could be turned false for not to return actual record data
242
256
  // matchStatus.status: boolean, true if matcher retrieved and handled all found candidate records, false if it did not
243
257
  // matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries','conversionFailures', empty string/undefined), reason for stopping retrieving or handling the candidate records
@@ -253,18 +267,21 @@ var _default = ({
253
267
  duplicateCount,
254
268
  candidateCount,
255
269
  nonMatchCount,
256
- conversionFailures
270
+ conversionFailures,
271
+ matchErrors
257
272
  }) {
258
273
  const conversionFailureCount = conversionFailures.length;
274
+ const matchErrorCount = matchErrors.length;
259
275
  checkCounts({
260
276
  matches,
261
277
  nonMatches,
262
278
  candidateCount,
263
279
  duplicateCount,
264
280
  nonMatchCount,
265
- conversionFailureCount
281
+ conversionFailureCount,
282
+ matchErrorCount
266
283
  });
267
- const matchStatus = getMatchState(state, stopReason, conversionFailureCount); // add nonMatches to result only if returnNonMatches is 'true', otherwise nonMatches have not been gathered
284
+ const matchStatus = getMatchState(state, stopReason, conversionFailureCount, matchErrorCount); // add nonMatches to result only if returnNonMatches is 'true', otherwise nonMatches have not been gathered
268
285
 
269
286
  const matchesResult = returnNonMatches ? {
270
287
  matches,
@@ -274,8 +291,9 @@ var _default = ({
274
291
  matches,
275
292
  matchStatus
276
293
  };
294
+ const failures = [...conversionFailures, ...matchErrors];
277
295
  const result = returnFailures ? { ...matchesResult,
278
- conversionFailures
296
+ conversionFailures: failures
279
297
  } : matchesResult;
280
298
  debugData(`ReturnFailures ${returnFailures}`);
281
299
  debugData(`${JSON.stringify(result)}`);
@@ -287,13 +305,14 @@ var _default = ({
287
305
  candidateCount,
288
306
  duplicateCount,
289
307
  nonMatchCount,
290
- conversionFailureCount
308
+ conversionFailureCount,
309
+ matchErrorCount
291
310
  }) {
292
311
  const matchCount = matches.length;
293
312
  debugData(`Return nonMatches: ${returnNonMatches}`);
294
313
  const chosenNonMatchCount = returnNonMatches ? nonMatches.length : nonMatchCount;
295
314
  const totalHandled = matchCount + chosenNonMatchCount + duplicateCount;
296
- debug(`candidateCount: ${candidateCount}, matches: ${matchCount}, nonMatches: ${chosenNonMatchCount}, duplicateCount: ${duplicateCount}, conversionFailureCount: ${conversionFailureCount}`);
315
+ debug(`candidateCount: ${candidateCount}, matches: ${matchCount}, nonMatches: ${chosenNonMatchCount}, duplicateCount: ${duplicateCount}, conversionFailureCount: ${conversionFailureCount}, matchErrorCount: ${matchErrorCount}`);
297
316
  debug(`We got result for ${totalHandled} / ${candidateCount} retrieved candidates`);
298
317
 
299
318
  if (totalHandled !== candidateCount) {
@@ -302,24 +321,28 @@ var _default = ({
302
321
  }
303
322
 
304
323
  return;
305
- }
324
+ } // eslint-disable-next-line max-statements
325
+
306
326
 
307
- function getMatchState(state, stopReason, conversionFailuresCount) {
327
+ function getMatchState(state, stopReason, conversionFailuresCount, matchErrorCount) {
308
328
  debugData(`${JSON.stringify(state)}`);
309
329
  debug(`We had ${conversionFailuresCount} retrieved candidates that could not be converted.`);
330
+ debug(`We had ${matchErrorCount} retrieved candidates that errored in matchDetection.`);
310
331
  debug(`Queries left ${state.queriesLeft}, Searches for current query left: ${state.resultSetOffset && state.resultSetOffset <= state.totalRecords}, non-retrieved records: ${state.totalRecords - state.queryCandidateCounter}, maxedQueries (${state.maxedQueries.length}): ${state.maxedQueries}`);
311
332
  debugData(`StopReason: <${stopReason}>`);
312
333
  const searchesLeft = state.resultSetOffset && state.resultSetOffset <= state.totalRecords;
313
334
  const nonRetrieved = searchesLeft ? state.totalRecords - state.queryCandidateCounter : 0;
314
335
  debugData(`nonRetrieved: ${nonRetrieved}`); // matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries','conversionFailures', empty string/undefined), reason for stopping retrieving or handling the candidate records
315
- // 'maxMatches' and 'maxCandidates' are in stopReason, 'maxedQueries' and 'conversionFailures' are created here
336
+ // 'maxMatches' and 'maxCandidates' are in stopReason, 'maxedQueries', 'conversionFailures' and 'matchErrors' are created here
316
337
 
317
- if (state.queriesLeft > 0 || nonRetrieved > 0 || state.maxedQueries.length > 0 || conversionFailureCount > 0) {
338
+ if (state.queriesLeft > 0 || nonRetrieved > 0 || state.maxedQueries.length > 0 || conversionFailureCount > 0 || matchErrorCount > 0) {
318
339
  const maxedQueriesStopReason = state.maxedQueries.length > 0 ? 'maxedQueries' : undefined;
319
340
  const conversionFailuresStopReason = conversionFailureCount > 0 ? 'conversionFailures' : undefined;
320
- const newStopReason = stopReason === '' || stopReason === undefined ? maxedQueriesStopReason || conversionFailuresStopReason : stopReason;
341
+ const matchErrorsStopReason = matchErrorCount > 0 ? 'matchErrors' : undefined;
342
+ const newStopReason = stopReason === '' || stopReason === undefined ? maxedQueriesStopReason || conversionFailuresStopReason || matchErrorsStopReason : stopReason;
321
343
  debugData(`MaxedQueriesStopReason: <${maxedQueriesStopReason}>`);
322
344
  debugData(`ConversionFailureStopReason <${conversionFailuresStopReason}>`);
345
+ debugData(`MatchErrorsStopReason <${matchErrorsStopReason}>`);
323
346
  debugData(`NewStopReason: <${newStopReason}>`);
324
347
  debug(`Match status: false`);
325
348
  return {
@@ -334,7 +357,12 @@ var _default = ({
334
357
  stopReason
335
358
  };
336
359
  }
337
- }
360
+ } // NOTES:
361
+ // - we could optimize by creating the featureSet for the incoming record once and using it for all database/candidateRecords
362
+ // - if creating the featureSet for the incoming record fails we have an unprocessable entity
363
+ // - if creating the featureSet for a candidate record fails we could skip that candidate - but list the case as a detectionFailure, same as conversionFailures
364
+ // eslint-disable-next-line max-statements
365
+
338
366
 
339
367
  function iterateRecords({
340
368
  records,
@@ -346,7 +374,8 @@ var _default = ({
346
374
  recordNonMatches = [],
347
375
  recordCount = 0,
348
376
  recordDuplicateCount = 0,
349
- recordNonMatchCount = 0
377
+ recordNonMatchCount = 0,
378
+ recordMatchErrors = []
350
379
  }) {
351
380
  // recordSetSize : total amount of records in the current record set
352
381
  // recordCount : amount of records from the current record set that have been handled
@@ -357,21 +386,57 @@ var _default = ({
357
386
  // matches : found matches in the current matcher job
358
387
  // recordMatches : found matches in the current record set
359
388
  // recordNonMatches : found nonMatches in the current record set (only if returnNonMatches setting is true)
389
+ // recordMatchErrors: errored matchDetection in the current record set
360
390
  const [candidate] = records;
361
391
  const newRecordCount = candidate ? recordCount + 1 : recordCount; // The matcher uses same matchDetection strategy for candidates from all candidate-searches -> matchDetection result for the same candidate is always same
362
392
  // Exceptions would happen if the candidate would have been updated in the database between candidate searches
363
393
  // Note that if returnNonMatches is false, matcher won't remember candidates that didn't match, so they will be matched again everytime they are retrieved by
364
394
  // different candidate search queries. Same candidate search query won't have duplicate records.
365
395
 
396
+ /* We could optimize and detect all retrieved candidates at once
397
+ const candidateRecords = records.map(record => record.record);
398
+ const recordsIsArray = Array.isArray(candidateRecords);
399
+ debug(`records is an array: ${recordsIsArray}`);
400
+ const result = detect(record, candidateRecords);
401
+ debug(`${JSON.stringify(result)}`);
402
+ */
403
+
366
404
  if (candidate) {
405
+ // eslint-disable-next-line functional/no-conditional-statement
367
406
  if (candidateNotInMatches(matches.concat(nonMatches), candidate)) {
368
407
  const {
369
408
  record: candidateRecord,
370
409
  id: candidateId
371
410
  } = candidate;
372
- debug(`Running matchDetection for record ${candidateId} (${newRecordCount}/${recordSetSize})`);
373
- const detectionResult = detect(record, candidateRecord);
374
- return handleDetectionResult(detectionResult, candidateId, candidateRecord);
411
+
412
+ try {
413
+ debug(`Running matchDetection for record ${candidateId} (${newRecordCount}/${recordSetSize})`); // we should handle errors from detection somehow - ie. cases where either record or candidateRecord errors
414
+
415
+ const detectionResult = detect(record, candidateRecord);
416
+ return handleDetectionResult(detectionResult, candidateId, candidateRecord);
417
+ } catch (error) {
418
+ debug(`MatchDetection errored: database record ${candidateId}: ${error}`);
419
+ const matchError = {
420
+ status: 422,
421
+ payload: {
422
+ message: `Matching errored for database record ${candidateId}. ${error.message}.`,
423
+ id: candidateId
424
+ }
425
+ };
426
+ const newRecordMatchErrors = recordMatchErrors.concat(matchError);
427
+ return iterateRecords({
428
+ records: records.slice(1),
429
+ recordSetSize,
430
+ maxMatches,
431
+ matches,
432
+ recordMatches,
433
+ recordCount: newRecordCount,
434
+ recordNonMatches,
435
+ recordDuplicateCount,
436
+ recordNonMatchCount,
437
+ recordMatchErrors: newRecordMatchErrors
438
+ });
439
+ }
375
440
  }
376
441
 
377
442
  return iterateRecords({
@@ -383,7 +448,8 @@ var _default = ({
383
448
  recordCount: newRecordCount,
384
449
  recordNonMatches,
385
450
  recordDuplicateCount: recordDuplicateCount + 1,
386
- recordNonMatchCount
451
+ recordNonMatchCount,
452
+ recordMatchErrors
387
453
  });
388
454
  }
389
455
 
@@ -392,7 +458,8 @@ var _default = ({
392
458
  matches: recordMatches,
393
459
  nonMatches: returnNonMatches ? recordNonMatches : [],
394
460
  duplicateCount: recordDuplicateCount,
395
- nonMatchCount: recordNonMatchCount
461
+ nonMatchCount: recordNonMatchCount,
462
+ matchErrors: recordMatchErrors
396
463
  };
397
464
 
398
465
  function handleDetectionResult(detectionResult, candidateId, candidateRecord) {
@@ -431,7 +498,8 @@ var _default = ({
431
498
  recordCount: newRecordCount,
432
499
  recordNonMatches,
433
500
  recordDuplicateCount,
434
- recordNonMatchCount: newRecordNonMatchCount
501
+ recordNonMatchCount: newRecordNonMatchCount,
502
+ recordMatchErrors
435
503
  });
436
504
  }
437
505
 
@@ -456,7 +524,8 @@ var _default = ({
456
524
  matches: newRecordMatches,
457
525
  nonMatches: returnNonMatches ? newRecordNonMatches : [],
458
526
  duplicateCount: recordDuplicateCount,
459
- nonMatchCount: newRecordNonMatchCount
527
+ nonMatchCount: newRecordNonMatchCount,
528
+ matchErrors: recordMatchErrors
460
529
  };
461
530
  }
462
531
 
@@ -469,7 +538,8 @@ var _default = ({
469
538
  recordCount: newRecordCount,
470
539
  recordNonMatches: returnNonMatches ? newRecordNonMatches : [],
471
540
  duplicateCount: recordDuplicateCount,
472
- recordNonMatchCount: newRecordNonMatchCount
541
+ recordNonMatchCount: newRecordNonMatchCount,
542
+ matchErrors: recordMatchErrors
473
543
  });
474
544
  }
475
545
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.js"],"names":["detection","detectionOptions","search","searchOptions","maxMatches","maxCandidates","returnStrategy","returnQuery","returnNonMatches","returnFailures","debug","debugData","extend","JSON","stringify","detect","record","iterate","initialState","matches","candidateCount","nonMatches","duplicateCount","nonMatchCount","conversionFailures","records","failures","state","length","recordSetSize","failureSetSize","newCandidateCount","newConversionFailures","concat","handleRecordSet","queriesLeft","searchCounter","query","returnResult","stopReason","matchResult","iterateRecords","newDuplicateCount","newNonMatchCount","newMatches","newNonMatches","handleMatchResult","maxMatchesFound","maxCandidatesRetrieved","addQuery","map","match","matchQuery","conversionFailureCount","checkCounts","matchStatus","getMatchState","matchesResult","result","matchCount","chosenNonMatchCount","totalHandled","conversionFailuresCount","resultSetOffset","totalRecords","queryCandidateCounter","maxedQueries","searchesLeft","nonRetrieved","maxedQueriesStopReason","undefined","conversionFailuresStopReason","newStopReason","status","recordMatches","recordNonMatches","recordCount","recordDuplicateCount","recordNonMatchCount","candidate","newRecordCount","candidateNotInMatches","candidateRecord","id","candidateId","detectionResult","handleDetectionResult","slice","strategy","treshold","probability","strategyResult","newMatch","handleRecordMatch","newRecordNonMatchCount","isMatch","newRecordMatches","newRecordNonMatches","newCandidateId","find"],"mappings":"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","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 createDebugLogger from 'debug';\nimport createSearchInterface, * as candidateSearch from './candidate-search';\nimport createDetectionInterface, * as matchDetection from './match-detection';\n\nexport {candidateSearch, matchDetection};\n\nexport default ({detection: detectionOptions, search: searchOptions, maxMatches = 1, maxCandidates = 25, returnStrategy = false, returnQuery = false, returnNonMatches = false, returnFailures}) => {\n const debug = createDebugLogger('@natlibfi/melinda-record-matching:index');\n const debugData = debug.extend('data');\n\n debugData(`DetectionOptions: ${JSON.stringify(detectionOptions)}`);\n debugData(`SearchOptions: ${JSON.stringify(searchOptions)}`);\n debugData(`MaxMatches: ${JSON.stringify(maxMatches)}`);\n debugData(`MaxCandidates: ${JSON.stringify(maxCandidates)}`);\n debugData(`ReturnStrategy: ${JSON.stringify(returnStrategy)}`);\n debugData(`ReturnQuery: ${JSON.stringify(returnQuery)}`);\n debugData(`ReturnNonMatches: ${JSON.stringify(returnNonMatches)}`);\n debugData(`ReturnFailures: ${JSON.stringify(returnFailures)}`);\n\n\n const detect = createDetectionInterface(detectionOptions, returnStrategy);\n\n return record => {\n const search = createSearchInterface({...searchOptions, record, maxCandidates});\n return iterate({});\n\n // candidateCount : amount of candidate records retrived from SRU for matching, NOT including current record set\n // matches : candidates that have been detected as matches by current matcher job\n // nonMatches : candidates that have been detected as non-matches by current matcher job (only if returnNonMatches is 'true')\n // duplicateCount : amount of candidate records that were retrieved from the SRU but not handled further because they were already found in the matches/nonMatches\n\n // state.totalRecords : amount of candidate records available to the current query (undefined, if there was no queries left)\n // state.query : current query (undefined if there was no queries left)\n // state.searchCounter : sequence for current search for current query (undefined, if there we no queries left)\n // state.queryCandidateCounter: amount of candidate records retrieved from SRU for matching for current query, including the current record set (undefined if there were no queries left)\n // state.queriesLeft : amount of queries left\n // state.queryCounter : sequence for current query\n // state.maxedQueries : queries that resulted in more than serverMaxResults hits\n\n async function iterate({initialState = {}, matches = [], candidateCount = 0, nonMatches = [], duplicateCount = 0, nonMatchCount = 0, conversionFailures = []}) {\n debugData(`Starting next matcher iteration.`);\n const {records, failures, ...state} = await search(initialState);\n\n debugData(`Current state: ${JSON.stringify(state)}, matches: ${matches.length}, candidateCount: ${candidateCount}, nonMatches: ${nonMatches.length}, nonMatchCount: ${nonMatchCount}, conversionFailures: ${conversionFailures}`);\n const recordSetSize = records.length;\n const failureSetSize = failures.length;\n const newCandidateCount = candidateCount + recordSetSize + failureSetSize;\n\n const newConversionFailures = conversionFailures.concat(failures);\n debugData(`Failures: ${failures.length}, ConversionFailures: ${conversionFailures.length}, NewConversionFailures: ${newConversionFailures.length}`);\n\n if (recordSetSize > 0) {\n return handleRecordSet();\n }\n\n if (state.queriesLeft > 0) {\n debug(`Empty record set ${state.searchCounter} for ${state.query}, but there are ${state.queriesLeft} queries left`);\n return iterate({initialState: state, matches, candidateCount: newCandidateCount, nonMatches, nonMatchCount, duplicateCount, conversionFailures: newConversionFailures});\n }\n\n debug(`No (more) candidate records to check, no more queries left, matches: ${matches.length}`);\n return returnResult({matches, state, stopReason: '', nonMatches, nonMatchCount, candidateCount: newCandidateCount, duplicateCount, conversionFailures: newConversionFailures});\n\n function handleRecordSet() {\n debug(`Checking record set of ${recordSetSize} candidate records for possible matches, found by ${state.searchCounter} search for ${state.query}`);\n\n const matchResult = iterateRecords({records, recordSetSize, maxMatches, matches, nonMatches, nonMatchCount});\n\n const newDuplicateCount = duplicateCount + matchResult.duplicateCount;\n const newNonMatchCount = nonMatchCount + matchResult.nonMatchCount;\n const {newMatches, newNonMatches} = handleMatchResult(matchResult, matches, nonMatches);\n\n if (maxMatchesFound({matches: newMatches, maxMatches})) {\n return returnResult({matches: newMatches, state, stopReason: 'maxMatches', nonMatches: newNonMatches, duplicateCount: newDuplicateCount, candidateCount: newCandidateCount, nonMatchCount: newNonMatchCount, conversionFailures: newConversionFailures});\n }\n\n if (maxCandidatesRetrieved(newCandidateCount, maxCandidates)) {\n return returnResult({matches: newMatches, state, stopReason: 'maxCandidates', nonMatches: newNonMatches, duplicateCount: newDuplicateCount, candidateCount: newCandidateCount, nonMatchCount: newNonMatchCount, conversionFailures: newConversionFailures});\n }\n\n return iterate({initialState: state, matches: newMatches, candidateCount: newCandidateCount, nonMatches: newNonMatches, duplicateCount: newDuplicateCount, nonMatchCount: newNonMatchCount, conversionFailures: newConversionFailures});\n }\n\n function handleMatchResult(matchResult, matches, nonMatches) {\n debugData(`- Amount of new matches from record set: ${matchResult.matches.length}`);\n // eslint-disable-next-line functional/no-conditional-statement\n if (returnNonMatches) {\n debugData(`- Amount of new nonMatches from record set: ${matchResult.nonMatches.length}`);\n }\n\n const newMatches = matches.concat(returnQuery ? addQuery(matchResult.matches) : matchResult.matches);\n const newNonMatches = returnNonMatches ? nonMatches.concat(returnQuery ? addQuery(matchResult.nonMatches) : matchResult.nonMatches) : [];\n\n debugData(`- Total amount of matches: ${newMatches.length}`);\n // eslint-disable-next-line functional/no-conditional-statement\n if (returnNonMatches) {\n debugData(`- Total amount of nonMatches: ${newNonMatches.length}`);\n }\n\n return {newMatches, newNonMatches};\n }\n\n function addQuery(matches) {\n debugData(`Adding query ${state.query} to matches`);\n return matches.map((match) => ({...match, matchQuery: state.query}));\n }\n\n function maxCandidatesRetrieved(candidateCount, maxCandidates) {\n debugData(`Total amount of candidate records retrieved: ${newCandidateCount} (max: ${maxCandidates})`);\n if (maxCandidates && candidateCount >= maxCandidates) {\n debug(`Stopped matching because maximum number of candidate records ${candidateCount} / ${maxCandidates} have been retrieved`);\n return true;\n }\n }\n }\n\n // matches : array of matching candidate records\n // nonMatches : array of nonMatching candidate records (if returnNonMatches option is true, otherwise empty array)\n // - candidate.id\n // - candidate.record\n // - probability\n // - strategy (if returnStrategy option is true)\n // - treshold (if returnStrategy option is true)\n // - matchQuery (if returnQuery option is true)\n\n // we could have here also returnRecords/returnMatchRecords/returnNonMatchRecord options that could be turned false for not to return actual record data\n\n // matchStatus.status: boolean, true if matcher retrieved and handled all found candidate records, false if it did not\n // matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries','conversionFailures', empty string/undefined), reason for stopping retrieving or handling the candidate records\n // - only one stopReason is returned (if there would be several possible stopReasons, stopReason is picked in the above order)\n // - currently stopReason can be non-empty also in cases where status is true, if matcher hit the stop reason when handling the last available candidate record\n\n function returnResult({matches, state, stopReason, nonMatches, duplicateCount, candidateCount, nonMatchCount, conversionFailures}) {\n const conversionFailureCount = conversionFailures.length;\n checkCounts({matches, nonMatches, candidateCount, duplicateCount, nonMatchCount, conversionFailureCount});\n const matchStatus = getMatchState(state, stopReason, conversionFailureCount);\n // add nonMatches to result only if returnNonMatches is 'true', otherwise nonMatches have not been gathered\n const matchesResult = returnNonMatches ? {matches, matchStatus, nonMatches} : {matches, matchStatus};\n const result = returnFailures ? {...matchesResult, conversionFailures} : matchesResult;\n debugData(`ReturnFailures ${returnFailures}`);\n debugData(`${JSON.stringify(result)}`);\n return result;\n\n // note that in cases where the matching has been stopped because of maxMatches checkCounts won't (in most cases) match\n\n function checkCounts({matches, nonMatches, candidateCount, duplicateCount, nonMatchCount, conversionFailureCount}) {\n const matchCount = matches.length;\n debugData(`Return nonMatches: ${returnNonMatches}`);\n const chosenNonMatchCount = returnNonMatches ? nonMatches.length : nonMatchCount;\n const totalHandled = matchCount + chosenNonMatchCount + duplicateCount;\n debug(`candidateCount: ${candidateCount}, matches: ${matchCount}, nonMatches: ${chosenNonMatchCount}, duplicateCount: ${duplicateCount}, conversionFailureCount: ${conversionFailureCount}`);\n debug(`We got result for ${totalHandled} / ${candidateCount} retrieved candidates`);\n if (totalHandled !== candidateCount) {\n debug(`WARNING: Missing results for ${candidateCount - totalHandled} candidates`);\n return;\n }\n return;\n }\n\n function getMatchState(state, stopReason, conversionFailuresCount) {\n debugData(`${JSON.stringify(state)}`);\n debug(`We had ${conversionFailuresCount} retrieved candidates that could not be converted.`);\n debug(`Queries left ${state.queriesLeft}, Searches for current query left: ${state.resultSetOffset && state.resultSetOffset <= state.totalRecords}, non-retrieved records: ${state.totalRecords - state.queryCandidateCounter}, maxedQueries (${state.maxedQueries.length}): ${state.maxedQueries}`);\n\n debugData(`StopReason: <${stopReason}>`);\n\n const searchesLeft = state.resultSetOffset && state.resultSetOffset <= state.totalRecords;\n const nonRetrieved = searchesLeft ? state.totalRecords - state.queryCandidateCounter : 0;\n debugData(`nonRetrieved: ${nonRetrieved}`);\n\n // matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries','conversionFailures', empty string/undefined), reason for stopping retrieving or handling the candidate records\n // 'maxMatches' and 'maxCandidates' are in stopReason, 'maxedQueries' and 'conversionFailures' are created here\n\n if (state.queriesLeft > 0 || nonRetrieved > 0 || state.maxedQueries.length > 0 || conversionFailureCount > 0) {\n const maxedQueriesStopReason = state.maxedQueries.length > 0 ? 'maxedQueries' : undefined;\n const conversionFailuresStopReason = conversionFailureCount > 0 ? 'conversionFailures' : undefined;\n const newStopReason = stopReason === '' || stopReason === undefined ? maxedQueriesStopReason || conversionFailuresStopReason : stopReason;\n debugData(`MaxedQueriesStopReason: <${maxedQueriesStopReason}>`);\n debugData(`ConversionFailureStopReason <${conversionFailuresStopReason}>`);\n debugData(`NewStopReason: <${newStopReason}>`);\n debug(`Match status: false`);\n return {status: false, stopReason: newStopReason};\n }\n\n debug(`Match status: true`);\n return {status: true, stopReason};\n }\n }\n\n function iterateRecords({records, recordSetSize, maxMatches, matches = [], nonMatches = [], recordMatches = [], recordNonMatches = [], recordCount = 0, recordDuplicateCount = 0, recordNonMatchCount = 0}) {\n\n // recordSetSize : total amount of records in the current record set\n // recordCount : amount of records from the current record set that have been handled\n // maxMatches : setting for maximum amount found by current matcher job before the matcher job is stopped\n // recordDuplicateCount : amount of records from the current record set that are already included in matches/nonMatches results\n // recordNonMatchCount: amount of records from the current record set that are nonMatches (only is returnNonMatches setting is false)\n\n // records : non-handled records in the current record set\n // matches : found matches in the current matcher job\n // recordMatches : found matches in the current record set\n // recordNonMatches : found nonMatches in the current record set (only if returnNonMatches setting is true)\n\n const [candidate] = records;\n const newRecordCount = candidate ? recordCount + 1 : recordCount;\n\n // The matcher uses same matchDetection strategy for candidates from all candidate-searches -> matchDetection result for the same candidate is always same\n // Exceptions would happen if the candidate would have been updated in the database between candidate searches\n // Note that if returnNonMatches is false, matcher won't remember candidates that didn't match, so they will be matched again everytime they are retrieved by\n // different candidate search queries. Same candidate search query won't have duplicate records.\n\n if (candidate) {\n\n if (candidateNotInMatches(matches.concat(nonMatches), candidate)) {\n const {record: candidateRecord, id: candidateId} = candidate;\n debug(`Running matchDetection for record ${candidateId} (${newRecordCount}/${recordSetSize})`);\n const detectionResult = detect(record, candidateRecord);\n return handleDetectionResult(detectionResult, candidateId, candidateRecord);\n }\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches, recordCount: newRecordCount, recordNonMatches, recordDuplicateCount: recordDuplicateCount + 1, recordNonMatchCount});\n }\n\n debug(`No more candidates, record set (${recordCount}/${recordSetSize}) done, ${recordMatches.length} matches found, ${recordDuplicateCount} candidates already handled, ${returnNonMatches ? `${recordNonMatches.length}` : `${recordNonMatchCount}`} nonMatches found.`);\n return {matches: recordMatches, nonMatches: returnNonMatches ? recordNonMatches : [], duplicateCount: recordDuplicateCount, nonMatchCount: recordNonMatchCount};\n\n function handleDetectionResult(detectionResult, candidateId, candidateRecord) {\n debugData(`MatchDetection results for ${candidateId} (${newRecordCount}/${recordSetSize}): ${JSON.stringify(detectionResult)}`);\n\n if (detectionResult.match || returnNonMatches) {\n debug(`${detectionResult.match ? `Record ${candidateId} (${newRecordCount}/${recordSetSize}) is a match!` : `Record ${candidateId} (${newRecordCount}/${recordSetSize}) is NOT a match!`}`);\n debugData(`Strategy: ${JSON.stringify(detectionResult.strategy)}, Treshold: ${JSON.stringify(detectionResult.treshold)}`);\n\n const matchResult = {\n probability: detectionResult.probability,\n candidate: {\n id: candidateId,\n record: candidateRecord\n }\n };\n const strategyResult = {\n strategy: detectionResult.strategy,\n treshold: detectionResult.treshold\n };\n const newMatch = returnStrategy ? {...matchResult, ...strategyResult} : {...matchResult};\n\n debugData(`${JSON.stringify(newMatch)}`);\n\n return handleRecordMatch(detectionResult.match, newMatch);\n }\n\n const newRecordNonMatchCount = recordNonMatchCount + 1;\n debugData(`- Total nonMatches after this detection: ${newRecordNonMatchCount}`);\n\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches, recordCount: newRecordCount, recordNonMatches, recordDuplicateCount, recordNonMatchCount: newRecordNonMatchCount});\n }\n\n function handleRecordMatch(isMatch, newMatch) {\n const newRecordMatches = isMatch ? recordMatches.concat(newMatch) : recordMatches;\n const newRecordNonMatches = isMatch ? recordNonMatches : recordNonMatches.concat(newMatch);\n const newRecordNonMatchCount = isMatch ? recordNonMatchCount : recordNonMatchCount + 1;\n\n debugData(`- Total matches after this detection: ${matches.concat(newRecordMatches).length} (max: ${maxMatches})`);\n\n // eslint-disable-next-line functional/no-conditional-statement\n if (returnNonMatches) {\n debugData(`- Total nonMatches after this detection: ${nonMatches.concat(newRecordNonMatches).length}`);\n }\n debugData(`- Total nonMatchCount after this detection: ${recordNonMatchCount}`);\n\n if (maxMatchesFound({matches: matches.concat(newRecordMatches), maxMatches})) {\n debug(`MaxMatches (${maxMatches}) reached, handled candidates in record set: ${newRecordCount} non-handled candidates in record set ${recordSetSize - newRecordCount}`);\n return {matches: newRecordMatches, nonMatches: returnNonMatches ? newRecordNonMatches : [], duplicateCount: recordDuplicateCount, nonMatchCount: newRecordNonMatchCount};\n }\n\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches: newRecordMatches, recordCount: newRecordCount, recordNonMatches: returnNonMatches ? newRecordNonMatches : [], duplicateCount: recordDuplicateCount, recordNonMatchCount: newRecordNonMatchCount});\n }\n\n function candidateNotInMatches(matches, candidate) {\n debug(`Checking that record ${candidate.id} is not already included in ${matches.length} matches/nonMatches`);\n const newCandidateId = candidate.id;\n debugData(`newCandidateId: ${newCandidateId}`);\n const result = matches.find(({candidate}) => candidate.id === newCandidateId);\n debugData(`Result: ${result}`);\n if (result) {\n debug(`${candidate.id} was already handled.`);\n return false;\n }\n debug(`${candidate.id} not found in matches/nonMatches`);\n return true;\n }\n }\n\n function maxMatchesFound({matches, maxMatches}) {\n if (maxMatches && matches.length >= maxMatches) {\n debug(`Stopping recordSet iteration: maxMatches (${maxMatches}) for matcher job found.`);\n return true;\n }\n }\n };\n};\n"],"file":"index.js"}
1
+ {"version":3,"file":"index.js","names":["detection","detectionOptions","search","searchOptions","maxMatches","maxCandidates","returnStrategy","returnQuery","returnNonMatches","returnFailures","debug","createDebugLogger","debugData","extend","JSON","stringify","detect","createDetectionInterface","record","createSearchInterface","iterate","initialState","matches","candidateCount","nonMatches","duplicateCount","nonMatchCount","conversionFailures","matchErrors","records","failures","state","length","recordSetSize","failureSetSize","newCandidateCount","newConversionFailures","concat","handleRecordSet","queriesLeft","searchCounter","query","returnResult","stopReason","matchResult","iterateRecords","newDuplicateCount","newNonMatchCount","newMatches","newNonMatches","newMatchErrors","handleMatchResult","maxMatchesFound","maxCandidatesRetrieved","addQuery","map","match","matchQuery","conversionFailureCount","matchErrorCount","checkCounts","matchStatus","getMatchState","matchesResult","result","matchCount","chosenNonMatchCount","totalHandled","conversionFailuresCount","resultSetOffset","totalRecords","queryCandidateCounter","maxedQueries","searchesLeft","nonRetrieved","maxedQueriesStopReason","undefined","conversionFailuresStopReason","matchErrorsStopReason","newStopReason","status","recordMatches","recordNonMatches","recordCount","recordDuplicateCount","recordNonMatchCount","recordMatchErrors","candidate","newRecordCount","candidateNotInMatches","candidateRecord","id","candidateId","detectionResult","handleDetectionResult","error","matchError","payload","message","newRecordMatchErrors","slice","strategy","treshold","probability","strategyResult","newMatch","handleRecordMatch","newRecordNonMatchCount","isMatch","newRecordMatches","newRecordNonMatches","newCandidateId","find"],"sources":["../src/index.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 createDebugLogger from 'debug';\nimport createSearchInterface, * as candidateSearch from './candidate-search';\nimport createDetectionInterface, * as matchDetection from './match-detection';\n//import inspect from 'util';\n\nexport {candidateSearch, matchDetection};\n\nexport default ({detection: detectionOptions, search: searchOptions, maxMatches = 1, maxCandidates = 25, returnStrategy = false, returnQuery = false, returnNonMatches = false, returnFailures = false}) => {\n const debug = createDebugLogger('@natlibfi/melinda-record-matching:index');\n const debugData = debug.extend('data');\n\n debugData(`DetectionOptions: ${JSON.stringify(detectionOptions)}`);\n debugData(`SearchOptions: ${JSON.stringify(searchOptions)}`);\n debugData(`MaxMatches: ${JSON.stringify(maxMatches)}`);\n debugData(`MaxCandidates: ${JSON.stringify(maxCandidates)}`);\n debugData(`ReturnStrategy: ${JSON.stringify(returnStrategy)}`);\n debugData(`ReturnQuery: ${JSON.stringify(returnQuery)}`);\n debugData(`ReturnNonMatches: ${JSON.stringify(returnNonMatches)}`);\n debugData(`ReturnFailures: ${JSON.stringify(returnFailures)}`);\n\n\n const detect = createDetectionInterface(detectionOptions, returnStrategy);\n\n return record => {\n const search = createSearchInterface({...searchOptions, record, maxCandidates});\n return iterate({});\n\n // candidateCount : amount of candidate records retrived from SRU for matching, NOT including current record set\n // matches : candidates that have been detected as matches by current matcher job\n // nonMatches : candidates that have been detected as non-matches by current matcher job (only if returnNonMatches is 'true')\n // duplicateCount : amount of candidate records that were retrieved from the SRU but not handled further because they were already found in the matches/nonMatches\n\n // state.totalRecords : amount of candidate records available to the current query (undefined, if there was no queries left)\n // state.query : current query (undefined if there was no queries left)\n // state.searchCounter : sequence for current search for current query (undefined, if there we no queries left)\n // state.queryCandidateCounter: amount of candidate records retrieved from SRU for matching for current query, including the current record set (undefined if there were no queries left)\n // state.queriesLeft : amount of queries left\n // state.queryCounter : sequence for current query\n // state.maxedQueries : queries that resulted in more than serverMaxResults hits\n\n async function iterate({initialState = {}, matches = [], candidateCount = 0, nonMatches = [], duplicateCount = 0, nonMatchCount = 0, conversionFailures = [], matchErrors = []}) {\n debugData(`Starting next matcher iteration.`);\n const {records, failures, ...state} = await search(initialState);\n\n debugData(`Current state: ${JSON.stringify(state)}, matches: ${matches.length}, candidateCount: ${candidateCount}, nonMatches: ${nonMatches.length}, nonMatchCount: ${nonMatchCount}, conversionFailures: ${conversionFailures}, matchErrors: ${matchErrors.length}`);\n const recordSetSize = records.length;\n const failureSetSize = failures.length;\n const newCandidateCount = candidateCount + recordSetSize + failureSetSize;\n\n const newConversionFailures = conversionFailures.concat(failures);\n debugData(`Failures: ${failures.length}, ConversionFailures: ${conversionFailures.length}, NewConversionFailures: ${newConversionFailures.length}`);\n\n if (recordSetSize > 0) {\n return handleRecordSet();\n }\n\n if (state.queriesLeft > 0) {\n debug(`Empty record set ${state.searchCounter} for ${state.query}, but there are ${state.queriesLeft} queries left`);\n return iterate({initialState: state, matches, candidateCount: newCandidateCount, nonMatches, nonMatchCount, duplicateCount, conversionFailures: newConversionFailures, matchErrors});\n }\n\n debug(`No (more) candidate records to check, no more queries left, matches: ${matches.length}`);\n return returnResult({matches, state, stopReason: '', nonMatches, nonMatchCount, candidateCount: newCandidateCount, duplicateCount, conversionFailures: newConversionFailures, matchErrors});\n\n function handleRecordSet() {\n debug(`Checking record set of ${recordSetSize} candidate records for possible matches, found by ${state.searchCounter} search for ${state.query}`);\n\n const matchResult = iterateRecords({records, recordSetSize, maxMatches, matches, nonMatches, nonMatchCount});\n\n const newDuplicateCount = duplicateCount + matchResult.duplicateCount;\n const newNonMatchCount = nonMatchCount + matchResult.nonMatchCount;\n const {newMatches, newNonMatches, newMatchErrors} = handleMatchResult(matchResult, matches, nonMatches, matchErrors);\n\n if (maxMatchesFound({matches: newMatches, maxMatches})) {\n return returnResult({matches: newMatches, state, stopReason: 'maxMatches', nonMatches: newNonMatches, duplicateCount: newDuplicateCount, candidateCount: newCandidateCount, nonMatchCount: newNonMatchCount, conversionFailures: newConversionFailures, matchErrors: newMatchErrors});\n }\n\n if (maxCandidatesRetrieved(newCandidateCount, maxCandidates)) {\n return returnResult({matches: newMatches, state, stopReason: 'maxCandidates', nonMatches: newNonMatches, duplicateCount: newDuplicateCount, candidateCount: newCandidateCount, nonMatchCount: newNonMatchCount, conversionFailures: newConversionFailures, matchErrors: newMatchErrors});\n }\n\n return iterate({initialState: state, matches: newMatches, candidateCount: newCandidateCount, nonMatches: newNonMatches, duplicateCount: newDuplicateCount, nonMatchCount: newNonMatchCount, conversionFailures: newConversionFailures, matchErrors: newMatchErrors});\n }\n\n function handleMatchResult(matchResult, matches, nonMatches, matchErrors) {\n debugData(`- Amount of new matches from record set: ${matchResult.matches.length}`);\n // eslint-disable-next-line functional/no-conditional-statement\n if (returnNonMatches) {\n debugData(`- Amount of new nonMatches from record set: ${matchResult.nonMatches.length}`);\n }\n\n const newMatches = matches.concat(returnQuery ? addQuery(matchResult.matches) : matchResult.matches);\n const newNonMatches = returnNonMatches ? nonMatches.concat(returnQuery ? addQuery(matchResult.nonMatches) : matchResult.nonMatches) : [];\n const newMatchErrors = matchErrors.concat(matchResult.matchErrors);\n\n debugData(`- Total amount of matches: ${newMatches.length}`);\n // eslint-disable-next-line functional/no-conditional-statement\n if (returnNonMatches) {\n debugData(`- Total amount of nonMatches: ${newNonMatches.length}`);\n }\n\n debugData(`MatchResult: ${JSON.stringify(matchResult)}`);\n debugData(`Old matchErrors: ${JSON.stringify(matchErrors)}, matchErrors from matchResult: ${JSON.stringify(matchResult.matchErrors)}, New matchErrors: ${JSON.stringify(newMatchErrors)}`);\n\n debugData(`- Total amount of matchErrors: ${newMatchErrors.length}`);\n\n return {newMatches, newNonMatches, newMatchErrors};\n }\n\n function addQuery(matches) {\n debugData(`Adding query ${state.query} to matches`);\n return matches.map((match) => ({...match, matchQuery: state.query}));\n }\n\n function maxCandidatesRetrieved(candidateCount, maxCandidates) {\n debugData(`Total amount of candidate records retrieved: ${newCandidateCount} (max: ${maxCandidates})`);\n if (maxCandidates && candidateCount >= maxCandidates) {\n debug(`Stopped matching because maximum number of candidate records ${candidateCount} / ${maxCandidates} have been retrieved`);\n return true;\n }\n }\n }\n\n // matches : array of matching candidate records\n // nonMatches : array of nonMatching candidate records (if returnNonMatches option is true, otherwise empty array)\n // - candidate.id\n // - candidate.record\n // - probability\n // - strategy (if returnStrategy option is true)\n // - treshold (if returnStrategy option is true)\n // - matchQuery (if returnQuery option is true)\n // failures: array of conversionFailures from candidate-search and matchErrors from matchDetection in error format {status, payload: {message, id}} if returnFailures is true\n\n // we could have here also returnRecords/returnMatchRecords/returnNonMatchRecord options that could be turned false for not to return actual record data\n\n // matchStatus.status: boolean, true if matcher retrieved and handled all found candidate records, false if it did not\n // matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries','conversionFailures', empty string/undefined), reason for stopping retrieving or handling the candidate records\n // - only one stopReason is returned (if there would be several possible stopReasons, stopReason is picked in the above order)\n // - currently stopReason can be non-empty also in cases where status is true, if matcher hit the stop reason when handling the last available candidate record\n\n function returnResult({matches, state, stopReason, nonMatches, duplicateCount, candidateCount, nonMatchCount, conversionFailures, matchErrors}) {\n const conversionFailureCount = conversionFailures.length;\n const matchErrorCount = matchErrors.length;\n checkCounts({matches, nonMatches, candidateCount, duplicateCount, nonMatchCount, conversionFailureCount, matchErrorCount});\n const matchStatus = getMatchState(state, stopReason, conversionFailureCount, matchErrorCount);\n // add nonMatches to result only if returnNonMatches is 'true', otherwise nonMatches have not been gathered\n const matchesResult = returnNonMatches ? {matches, matchStatus, nonMatches} : {matches, matchStatus};\n const failures = [...conversionFailures, ...matchErrors];\n const result = returnFailures ? {...matchesResult, conversionFailures: failures} : matchesResult;\n debugData(`ReturnFailures ${returnFailures}`);\n debugData(`${JSON.stringify(result)}`);\n return result;\n\n // note that in cases where the matching has been stopped because of maxMatches checkCounts won't (in most cases) match\n\n function checkCounts({matches, nonMatches, candidateCount, duplicateCount, nonMatchCount, conversionFailureCount, matchErrorCount}) {\n const matchCount = matches.length;\n debugData(`Return nonMatches: ${returnNonMatches}`);\n const chosenNonMatchCount = returnNonMatches ? nonMatches.length : nonMatchCount;\n const totalHandled = matchCount + chosenNonMatchCount + duplicateCount;\n debug(`candidateCount: ${candidateCount}, matches: ${matchCount}, nonMatches: ${chosenNonMatchCount}, duplicateCount: ${duplicateCount}, conversionFailureCount: ${conversionFailureCount}, matchErrorCount: ${matchErrorCount}`);\n debug(`We got result for ${totalHandled} / ${candidateCount} retrieved candidates`);\n if (totalHandled !== candidateCount) {\n debug(`WARNING: Missing results for ${candidateCount - totalHandled} candidates`);\n return;\n }\n return;\n }\n\n // eslint-disable-next-line max-statements\n function getMatchState(state, stopReason, conversionFailuresCount, matchErrorCount) {\n debugData(`${JSON.stringify(state)}`);\n debug(`We had ${conversionFailuresCount} retrieved candidates that could not be converted.`);\n debug(`We had ${matchErrorCount} retrieved candidates that errored in matchDetection.`);\n debug(`Queries left ${state.queriesLeft}, Searches for current query left: ${state.resultSetOffset && state.resultSetOffset <= state.totalRecords}, non-retrieved records: ${state.totalRecords - state.queryCandidateCounter}, maxedQueries (${state.maxedQueries.length}): ${state.maxedQueries}`);\n\n debugData(`StopReason: <${stopReason}>`);\n\n const searchesLeft = state.resultSetOffset && state.resultSetOffset <= state.totalRecords;\n const nonRetrieved = searchesLeft ? state.totalRecords - state.queryCandidateCounter : 0;\n debugData(`nonRetrieved: ${nonRetrieved}`);\n\n // matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries','conversionFailures', empty string/undefined), reason for stopping retrieving or handling the candidate records\n // 'maxMatches' and 'maxCandidates' are in stopReason, 'maxedQueries', 'conversionFailures' and 'matchErrors' are created here\n\n if (state.queriesLeft > 0 || nonRetrieved > 0 || state.maxedQueries.length > 0 || conversionFailureCount > 0 || matchErrorCount > 0) {\n const maxedQueriesStopReason = state.maxedQueries.length > 0 ? 'maxedQueries' : undefined;\n const conversionFailuresStopReason = conversionFailureCount > 0 ? 'conversionFailures' : undefined;\n const matchErrorsStopReason = matchErrorCount > 0 ? 'matchErrors' : undefined;\n const newStopReason = stopReason === '' || stopReason === undefined ? maxedQueriesStopReason || conversionFailuresStopReason || matchErrorsStopReason : stopReason;\n debugData(`MaxedQueriesStopReason: <${maxedQueriesStopReason}>`);\n debugData(`ConversionFailureStopReason <${conversionFailuresStopReason}>`);\n debugData(`MatchErrorsStopReason <${matchErrorsStopReason}>`);\n debugData(`NewStopReason: <${newStopReason}>`);\n debug(`Match status: false`);\n return {status: false, stopReason: newStopReason};\n }\n\n debug(`Match status: true`);\n return {status: true, stopReason};\n }\n }\n\n // NOTES:\n // - we could optimize by creating the featureSet for the incoming record once and using it for all database/candidateRecords\n // - if creating the featureSet for the incoming record fails we have an unprocessable entity\n // - if creating the featureSet for a candidate record fails we could skip that candidate - but list the case as a detectionFailure, same as conversionFailures\n\n // eslint-disable-next-line max-statements\n function iterateRecords({records, recordSetSize, maxMatches, matches = [], nonMatches = [], recordMatches = [], recordNonMatches = [], recordCount = 0, recordDuplicateCount = 0, recordNonMatchCount = 0, recordMatchErrors = []}) {\n\n // recordSetSize : total amount of records in the current record set\n // recordCount : amount of records from the current record set that have been handled\n // maxMatches : setting for maximum amount found by current matcher job before the matcher job is stopped\n // recordDuplicateCount : amount of records from the current record set that are already included in matches/nonMatches results\n // recordNonMatchCount: amount of records from the current record set that are nonMatches (only is returnNonMatches setting is false)\n\n // records : non-handled records in the current record set\n // matches : found matches in the current matcher job\n // recordMatches : found matches in the current record set\n // recordNonMatches : found nonMatches in the current record set (only if returnNonMatches setting is true)\n // recordMatchErrors: errored matchDetection in the current record set\n\n const [candidate] = records;\n const newRecordCount = candidate ? recordCount + 1 : recordCount;\n\n // The matcher uses same matchDetection strategy for candidates from all candidate-searches -> matchDetection result for the same candidate is always same\n // Exceptions would happen if the candidate would have been updated in the database between candidate searches\n // Note that if returnNonMatches is false, matcher won't remember candidates that didn't match, so they will be matched again everytime they are retrieved by\n // different candidate search queries. Same candidate search query won't have duplicate records.\n\n /* We could optimize and detect all retrieved candidates at once\n const candidateRecords = records.map(record => record.record);\n const recordsIsArray = Array.isArray(candidateRecords);\n debug(`records is an array: ${recordsIsArray}`);\n const result = detect(record, candidateRecords);\n debug(`${JSON.stringify(result)}`);\n */\n\n if (candidate) {\n\n // eslint-disable-next-line functional/no-conditional-statement\n if (candidateNotInMatches(matches.concat(nonMatches), candidate)) {\n const {record: candidateRecord, id: candidateId} = candidate;\n try {\n debug(`Running matchDetection for record ${candidateId} (${newRecordCount}/${recordSetSize})`);\n // we should handle errors from detection somehow - ie. cases where either record or candidateRecord errors\n const detectionResult = detect(record, candidateRecord);\n\n return handleDetectionResult(detectionResult, candidateId, candidateRecord);\n } catch (error) {\n debug(`MatchDetection errored: database record ${candidateId}: ${error}`);\n\n const matchError = {status: 422, payload: {message: `Matching errored for database record ${candidateId}. ${error.message}.`, id: candidateId}};\n const newRecordMatchErrors = recordMatchErrors.concat(matchError);\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches, recordCount: newRecordCount, recordNonMatches, recordDuplicateCount, recordNonMatchCount, recordMatchErrors: newRecordMatchErrors});\n }\n }\n\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches, recordCount: newRecordCount, recordNonMatches, recordDuplicateCount: recordDuplicateCount + 1, recordNonMatchCount, recordMatchErrors});\n }\n\n debug(`No more candidates, record set (${recordCount}/${recordSetSize}) done, ${recordMatches.length} matches found, ${recordDuplicateCount} candidates already handled, ${returnNonMatches ? `${recordNonMatches.length}` : `${recordNonMatchCount}`} nonMatches found.`);\n return {matches: recordMatches, nonMatches: returnNonMatches ? recordNonMatches : [], duplicateCount: recordDuplicateCount, nonMatchCount: recordNonMatchCount, matchErrors: recordMatchErrors};\n\n function handleDetectionResult(detectionResult, candidateId, candidateRecord) {\n debugData(`MatchDetection results for ${candidateId} (${newRecordCount}/${recordSetSize}): ${JSON.stringify(detectionResult)}`);\n\n if (detectionResult.match || returnNonMatches) {\n debug(`${detectionResult.match ? `Record ${candidateId} (${newRecordCount}/${recordSetSize}) is a match!` : `Record ${candidateId} (${newRecordCount}/${recordSetSize}) is NOT a match!`}`);\n debugData(`Strategy: ${JSON.stringify(detectionResult.strategy)}, Treshold: ${JSON.stringify(detectionResult.treshold)}`);\n\n const matchResult = {\n probability: detectionResult.probability,\n candidate: {\n id: candidateId,\n record: candidateRecord\n }\n };\n const strategyResult = {\n strategy: detectionResult.strategy,\n treshold: detectionResult.treshold\n };\n const newMatch = returnStrategy ? {...matchResult, ...strategyResult} : {...matchResult};\n\n debugData(`${JSON.stringify(newMatch)}`);\n\n return handleRecordMatch(detectionResult.match, newMatch);\n }\n\n const newRecordNonMatchCount = recordNonMatchCount + 1;\n debugData(`- Total nonMatches after this detection: ${newRecordNonMatchCount}`);\n\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches, recordCount: newRecordCount, recordNonMatches, recordDuplicateCount, recordNonMatchCount: newRecordNonMatchCount, recordMatchErrors});\n }\n\n function handleRecordMatch(isMatch, newMatch) {\n const newRecordMatches = isMatch ? recordMatches.concat(newMatch) : recordMatches;\n const newRecordNonMatches = isMatch ? recordNonMatches : recordNonMatches.concat(newMatch);\n const newRecordNonMatchCount = isMatch ? recordNonMatchCount : recordNonMatchCount + 1;\n\n debugData(`- Total matches after this detection: ${matches.concat(newRecordMatches).length} (max: ${maxMatches})`);\n\n // eslint-disable-next-line functional/no-conditional-statement\n if (returnNonMatches) {\n debugData(`- Total nonMatches after this detection: ${nonMatches.concat(newRecordNonMatches).length}`);\n }\n debugData(`- Total nonMatchCount after this detection: ${recordNonMatchCount}`);\n\n if (maxMatchesFound({matches: matches.concat(newRecordMatches), maxMatches})) {\n debug(`MaxMatches (${maxMatches}) reached, handled candidates in record set: ${newRecordCount} non-handled candidates in record set ${recordSetSize - newRecordCount}`);\n return {matches: newRecordMatches, nonMatches: returnNonMatches ? newRecordNonMatches : [], duplicateCount: recordDuplicateCount, nonMatchCount: newRecordNonMatchCount, matchErrors: recordMatchErrors};\n }\n\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches: newRecordMatches, recordCount: newRecordCount, recordNonMatches: returnNonMatches ? newRecordNonMatches : [], duplicateCount: recordDuplicateCount, recordNonMatchCount: newRecordNonMatchCount, matchErrors: recordMatchErrors});\n }\n\n function candidateNotInMatches(matches, candidate) {\n debug(`Checking that record ${candidate.id} is not already included in ${matches.length} matches/nonMatches`);\n const newCandidateId = candidate.id;\n debugData(`newCandidateId: ${newCandidateId}`);\n const result = matches.find(({candidate}) => candidate.id === newCandidateId);\n debugData(`Result: ${result}`);\n if (result) {\n debug(`${candidate.id} was already handled.`);\n return false;\n }\n debug(`${candidate.id} not found in matches/nonMatches`);\n return true;\n }\n }\n\n function maxMatchesFound({matches, maxMatches}) {\n if (maxMatches && matches.length >= maxMatches) {\n debug(`Stopping recordSet iteration: maxMatches (${maxMatches}) for matcher job found.`);\n return true;\n }\n }\n };\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.spec.js"],"names":["debug","debugData","extend","describe","callback","path","__dirname","recurse","fixura","reader","READERS","JSON","getFixture","options","enabled","expectedMatchStatus","expectedStopReason","expectedFailures","record","MarcRecord","subfieldValues","expectedMatches","expectedNonMatches","match","formatOptions","matches","matchStatus","nonMatches","conversionFailures","length","status","stopReason","to","eql","formattedMatchResult","formatRecordResults","formattedNonMatchResult","contextFeatures","matchDetection","features","detection","strategy","type","search","detect","map","v","stringify","candidate","formatCandidate","id","newId","newRecord","toObject"],"mappings":"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","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 createMatchInterface, {matchDetection} from '.';\nimport createDebugLogger from 'debug';\n\nconst debug = createDebugLogger('@natlibfi/melinda-record-matching:index:test');\nconst debugData = debug.extend('data');\n\ndescribe('INDEX', () => {\n generateTests({\n callback,\n path: [__dirname, '..', 'test-fixtures', 'index'],\n recurse: false,\n fixura: {\n reader: READERS.JSON\n }\n });\n\n async function callback({getFixture, options, enabled = true, expectedMatchStatus, expectedStopReason, expectedFailures}) {\n\n if (!enabled) {\n debug(`Disabled test!`);\n return;\n }\n\n const record = new MarcRecord(getFixture('inputRecord.json'), {subfieldValues: false});\n const expectedMatches = getFixture('expectedMatches.json');\n const expectedNonMatches = getFixture('expectedNonMatches.json') || [];\n\n\n const match = createMatchInterface(formatOptions());\n const {matches, matchStatus, nonMatches, conversionFailures} = await match(record);\n debugData(`Matches: ${matches.length}, Status: ${matchStatus.status}/${matchStatus.stopReason}, NonMatches: ${nonMatches ? nonMatches.length : 'not returned'}, ConversionFailures: ${conversionFailures ? conversionFailures.length : 'not returned'}`);\n\n expect(matchStatus.status).to.eql(expectedMatchStatus);\n expect(matchStatus.stopReason).to.eql(expectedStopReason);\n\n const formattedMatchResult = formatRecordResults(matches);\n expect(formattedMatchResult).to.eql(expectedMatches);\n\n const formattedNonMatchResult = formatRecordResults(nonMatches);\n expect(formattedNonMatchResult).to.eql(expectedNonMatches);\n\n // eslint-disable-next-line functional/no-conditional-statement\n if (expectedFailures) {\n expect(conversionFailures).to.eql(expectedFailures);\n }\n\n function formatOptions() {\n const contextFeatures = matchDetection.features[options.detection.strategy.type];\n\n return {\n ...options,\n search: {\n ...options.search\n },\n detection: {\n ...options.detect,\n strategy: options.detection.strategy.features.map(v => contextFeatures[v]())\n }\n };\n }\n\n function formatRecordResults(matches) {\n if (matches) {\n debugData(JSON.stringify(matches));\n return matches.map((match) => ({\n ...match,\n candidate: formatCandidate(match.candidate)\n }));\n }\n return [];\n }\n\n // Format candidate to remove validationOptions from record\n function formatCandidate({id, record}) {\n const newId = id;\n const newRecord = record;\n return {\n id: newId,\n record: newRecord.toObject()\n };\n }\n\n\n }\n\n});\n"],"file":"index.spec.js"}
1
+ {"version":3,"file":"index.spec.js","names":["debug","createDebugLogger","debugData","extend","describe","generateTests","callback","path","__dirname","recurse","fixura","reader","READERS","JSON","getFixture","options","enabled","expectedMatchStatus","expectedStopReason","expectedFailures","record","MarcRecord","subfieldValues","expectedMatches","expectedNonMatches","match","createMatchInterface","formatOptions","matches","matchStatus","nonMatches","conversionFailures","length","status","stopReason","expect","to","eql","formattedMatchResult","formatRecordResults","formattedNonMatchResult","contextFeatures","matchDetection","features","detection","strategy","type","search","detect","map","v","stringify","candidate","formatCandidate","id","newId","newRecord","toObject"],"sources":["../src/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 createMatchInterface, {matchDetection} from '.';\nimport createDebugLogger from 'debug';\n\nconst debug = createDebugLogger('@natlibfi/melinda-record-matching:index:test');\nconst debugData = debug.extend('data');\n\ndescribe('INDEX', () => {\n generateTests({\n callback,\n path: [__dirname, '..', 'test-fixtures', 'index'],\n recurse: false,\n fixura: {\n reader: READERS.JSON\n }\n });\n\n async function callback({getFixture, options, enabled = true, expectedMatchStatus, expectedStopReason, expectedFailures}) {\n\n if (!enabled) {\n debug(`Disabled test!`);\n return;\n }\n\n const record = new MarcRecord(getFixture('inputRecord.json'), {subfieldValues: false});\n const expectedMatches = getFixture('expectedMatches.json');\n const expectedNonMatches = getFixture('expectedNonMatches.json') || [];\n\n\n const match = createMatchInterface(formatOptions());\n const {matches, matchStatus, nonMatches, conversionFailures} = await match(record);\n debugData(`Matches: ${matches.length}, Status: ${matchStatus.status}/${matchStatus.stopReason}, NonMatches: ${nonMatches ? nonMatches.length : 'not returned'}, ConversionFailures: ${conversionFailures ? conversionFailures.length : 'not returned'}`);\n\n expect(matchStatus.status).to.eql(expectedMatchStatus);\n expect(matchStatus.stopReason).to.eql(expectedStopReason);\n\n const formattedMatchResult = formatRecordResults(matches);\n expect(formattedMatchResult).to.eql(expectedMatches);\n\n const formattedNonMatchResult = formatRecordResults(nonMatches);\n expect(formattedNonMatchResult).to.eql(expectedNonMatches);\n\n // eslint-disable-next-line functional/no-conditional-statement\n if (expectedFailures) {\n expect(conversionFailures).to.eql(expectedFailures);\n }\n\n function formatOptions() {\n const contextFeatures = matchDetection.features[options.detection.strategy.type];\n\n return {\n ...options,\n search: {\n ...options.search\n },\n detection: {\n ...options.detect,\n strategy: options.detection.strategy.features.map(v => contextFeatures[v]())\n }\n };\n }\n\n function formatRecordResults(matches) {\n if (matches) {\n debugData(JSON.stringify(matches));\n return matches.map((match) => ({\n ...match,\n candidate: formatCandidate(match.candidate)\n }));\n }\n return [];\n }\n\n // Format candidate to remove validationOptions from record\n function formatCandidate({id, record}) {\n const newId = id;\n const newRecord = record;\n return {\n id: newId,\n record: newRecord.toObject()\n };\n }\n\n\n }\n\n});\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/match-detection/features/bib/all-source-ids.js"],"names":["debug","debugData","extend","name","extract","record","fSids","get","length","JSON","stringify","sidFeatures","getSidFeatures","map","toSidFeature","filter","nonEmptySid","field","createSidFeature","sfC","sfB","compare","a","b","matches","sidA","some","sidB","sourceDb","sourceId","mismatches"],"mappings":"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","sourcesContent":["/* eslint-disable max-statements */\n/**\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 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 createDebugLogger from 'debug';\nimport {validateSidFieldSubfieldCounts, getSubfieldValues} from '../../../matching-utils';\n\nconst debug = createDebugLogger('@natlibfi/melinda-record-matching:match-detection:features:all-source-ids');\nconst debugData = debug.extend('data');\n\n/*\n\nSID-fields in Melinda have sf $c with local id and sf $b with a code for the local db:\n\n SID__ $c 123457 $b helka\n SID__ $c (ANDL100020)1077305 $b sata\n SID__ $c VER999999 $ FI-KV\n\nallSourceIds matching feature is formatted as [{sourceDb: \"helka\", sourceId: \"123457\"}, {sourceDb: \"sata\", sourceId: \"(ANDL100020)1077305\"}, {sourceDb: \"FI-KV\", sourceId: \"VER999999\"}]\n- no normalization / prefix deletions etc. in the feature\n\nNote: All Melinda records that have a matching records in a local db do NOT have SID for that local records,\n existence of a SID field depends on how the record has been added to Melinda and how it has been handled\n afterwards. SIDs are also not reliably maintained. A record might or might not have a SID for a local db\n after the matching record is removed from the local db.\n\nRecords with mismatching local ids for matching local db are a strong mismatch.\nRecords with matching local ids for matching local db are a very good match.\n\n*/\n\nexport default () => ({\n name: 'All source IDs',\n extract: record => {\n debug(`Creating match detection features for all local source id's`);\n\n const fSids = record.get('SID');\n debugData(`SID-fields (${fSids.length}): ${JSON.stringify(fSids)}`);\n\n const sidFeatures = getSidFeatures(fSids);\n debugData(`SID-features (${sidFeatures.length}): ${JSON.stringify(sidFeatures)}`);\n\n return sidFeatures;\n\n function getSidFeatures(fSids) {\n debug(`Getting Sid strings from SID fields`);\n\n // Map SID fields to sidFeatures, filter out empty strings\n const sidFeatures = fSids.map(toSidFeature).filter(nonEmptySid => nonEmptySid);\n return sidFeatures;\n\n function toSidFeature(field) {\n debug(`Getting feature from a field`);\n\n return validateSidFieldSubfieldCounts(field) ? createSidFeature(field) : '';\n\n function createSidFeature(field) {\n debug(`Creating feature from a field`);\n const [sfC] = getSubfieldValues(field, 'c');\n const [sfB] = getSubfieldValues(field, 'b');\n\n debugData(`${JSON.stringify(sfC)} + ${JSON.stringify(sfB)}`);\n debugData(`sourceDb: ${sfB}, sourceId: ${sfC}`);\n return {'sourceDb': sfB, 'sourceId': sfC};\n }\n }\n\n }\n\n },\n compare: (a, b) => {\n\n debugData(`Comparing ${JSON.stringify(a)} and ${JSON.stringify(b)}`);\n\n const matches = a.filter(sidA => b.some(sidB => sidA.sourceDb === sidB.sourceDb &&\n sidA.sourceId === sidB.sourceId));\n debugData(`Matches (${matches.length}): ${JSON.stringify(matches)}`);\n\n const mismatches = a.filter(sidA => b.some(sidB => sidA.sourceDb === sidB.sourceDb &&\n sidA.sourceId !== sidB.sourceId));\n debugData(`Mismatches (${mismatches.length}): ${JSON.stringify(mismatches)}`);\n\n // If there's at least one mismatching source ID from matching source db\n if (mismatches.length > 0) {\n return -1;\n }\n\n // If there's at least one matching source ID from matching source db\n if (matches.length > 0) {\n return 1;\n }\n\n // If there are no source IDs with matching sources\n return 0;\n\n }\n});\n"],"file":"all-source-ids.js"}
1
+ {"version":3,"file":"all-source-ids.js","names":["debug","createDebugLogger","debugData","extend","name","extract","record","fSids","get","length","JSON","stringify","sidFeatures","getSidFeatures","map","toSidFeature","filter","nonEmptySid","field","validateSidFieldSubfieldCounts","createSidFeature","sfC","getSubfieldValues","sfB","compare","a","b","matches","sidA","some","sidB","sourceDb","sourceId","mismatches"],"sources":["../../../../src/match-detection/features/bib/all-source-ids.js"],"sourcesContent":["/* eslint-disable max-statements */\n/**\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 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 createDebugLogger from 'debug';\nimport {validateSidFieldSubfieldCounts, getSubfieldValues} from '../../../matching-utils';\n\nconst debug = createDebugLogger('@natlibfi/melinda-record-matching:match-detection:features:all-source-ids');\nconst debugData = debug.extend('data');\n\n/*\n\nSID-fields in Melinda have sf $c with local id and sf $b with a code for the local db:\n\n SID__ $c 123457 $b helka\n SID__ $c (ANDL100020)1077305 $b sata\n SID__ $c VER999999 $ FI-KV\n\nallSourceIds matching feature is formatted as [{sourceDb: \"helka\", sourceId: \"123457\"}, {sourceDb: \"sata\", sourceId: \"(ANDL100020)1077305\"}, {sourceDb: \"FI-KV\", sourceId: \"VER999999\"}]\n- no normalization / prefix deletions etc. in the feature\n\nNote: All Melinda records that have a matching records in a local db do NOT have SID for that local records,\n existence of a SID field depends on how the record has been added to Melinda and how it has been handled\n afterwards. SIDs are also not reliably maintained. A record might or might not have a SID for a local db\n after the matching record is removed from the local db.\n\nRecords with mismatching local ids for matching local db are a strong mismatch.\nRecords with matching local ids for matching local db are a very good match.\n\n*/\n\nexport default () => ({\n name: 'All source IDs',\n extract: record => {\n debug(`Creating match detection features for all local source id's`);\n\n const fSids = record.get('SID');\n debugData(`SID-fields (${fSids.length}): ${JSON.stringify(fSids)}`);\n\n const sidFeatures = getSidFeatures(fSids);\n debugData(`SID-features (${sidFeatures.length}): ${JSON.stringify(sidFeatures)}`);\n\n return sidFeatures;\n\n function getSidFeatures(fSids) {\n debug(`Getting Sid strings from SID fields`);\n\n // Map SID fields to sidFeatures, filter out empty strings\n const sidFeatures = fSids.map(toSidFeature).filter(nonEmptySid => nonEmptySid);\n return sidFeatures;\n\n function toSidFeature(field) {\n debug(`Getting feature from a field`);\n\n return validateSidFieldSubfieldCounts(field) ? createSidFeature(field) : '';\n\n function createSidFeature(field) {\n debug(`Creating feature from a field`);\n const [sfC] = getSubfieldValues(field, 'c');\n const [sfB] = getSubfieldValues(field, 'b');\n\n debugData(`${JSON.stringify(sfC)} + ${JSON.stringify(sfB)}`);\n debugData(`sourceDb: ${sfB}, sourceId: ${sfC}`);\n return {'sourceDb': sfB, 'sourceId': sfC};\n }\n }\n\n }\n\n },\n compare: (a, b) => {\n\n debugData(`Comparing ${JSON.stringify(a)} and ${JSON.stringify(b)}`);\n\n const matches = a.filter(sidA => b.some(sidB => sidA.sourceDb === sidB.sourceDb &&\n sidA.sourceId === sidB.sourceId));\n debugData(`Matches (${matches.length}): ${JSON.stringify(matches)}`);\n\n const mismatches = a.filter(sidA => b.some(sidB => sidA.sourceDb === sidB.sourceDb &&\n sidA.sourceId !== sidB.sourceId));\n debugData(`Mismatches (${mismatches.length}): ${JSON.stringify(mismatches)}`);\n\n // If there's at least one mismatching source ID from matching source db\n if (mismatches.length > 0) {\n return -1;\n }\n\n // If there's at least one matching source ID from matching source db\n if (matches.length > 0) {\n return 1;\n }\n\n // If there are no source IDs with matching sources\n return 0;\n\n }\n});\n"],"mappings":"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"}
@@ -56,7 +56,7 @@ var _default = ({
56
56
  }) {
57
57
  if (code === 'a') {
58
58
  return {
59
- name: value.replace(/[^\p{Letter}\p{Number}]/gu, '').toLowerCase()
59
+ name: value ? value.replace(/[^\p{Letter}\p{Number}]/gu, '').toLowerCase() : ''
60
60
  };
61
61
  }
62
62