Skip to content

Commit 15cce30

Browse files
ryanjdewMarkLogic Builder
authored andcommitted
DHFPROD-7302: Better messages for common write errors
1 parent 9ccd31e commit 15cce30

File tree

5 files changed

+100
-12
lines changed

5 files changed

+100
-12
lines changed

marklogic-data-hub/src/main/resources/ml-modules/root/data-hub/5/impl/flow.sjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,8 @@ class Flow {
482482
// see if we can determine a uri based off the operation in the stackFrames
483483
if (operation) {
484484
uri = flowInstance.globalContext.failedItems.find((uri) => operation.includes(`"${uri}"`));
485+
} else if (error.message) {
486+
uri = flowInstance.globalContext.failedItems.find((uri) => error.message.includes(`URI: ${uri}`));
485487
}
486488
flowInstance.addBatchError(flowInstance, error, uri);
487489
}

marklogic-data-hub/src/main/resources/ml-modules/root/data-hub/5/impl/hub-utils.sjs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,50 @@ class HubUtils {
4444
* @return An object consisting of two properties - "transaction" and "dateTime"
4545
*/
4646
writeDocuments(writeQueue, permissions = xdmp.defaultPermissions(), collections = [], database = xdmp.databaseName(xdmp.database())){
47-
return fn.head(xdmp.invoke('/data-hub/5/impl/hub-utils/invoke-queue-write.sjs',
48-
{
49-
writeQueue,
50-
permissions,
51-
baseCollections: collections || []
52-
},
53-
{
54-
database: xdmp.database(database),
55-
commit: 'auto',
56-
update: 'true',
57-
ignoreAmps: true
58-
}));
47+
try {
48+
return fn.head(xdmp.invoke('/data-hub/5/impl/hub-utils/invoke-queue-write.sjs',
49+
{
50+
writeQueue,
51+
permissions,
52+
baseCollections: collections || []
53+
},
54+
{
55+
database: xdmp.database(database),
56+
commit: 'auto',
57+
update: 'true',
58+
ignoreAmps: true
59+
}));
60+
} catch (e) {
61+
this.handleWriteErrors(e, writeQueue);
62+
}
63+
}
64+
65+
66+
handleWriteErrors(error, contentArray) {
67+
switch (error.name) {
68+
case 'XDMP-CONFLICTINGUPDATES':
69+
let data = error.data[0];
70+
let parseUriRegex = /^xdmp\.documentInsert\("([^"]+)".*$/
71+
let uri = parseUriRegex.test(data) ? data.replace(parseUriRegex, '$1'): null;
72+
throw new Error(`Attempted to write to the same URI multiple times in the same transaction. ${ uri ? 'URI: ' + uri : ''}`);
73+
case 'TDE-INDEX':
74+
let isFailOnSubjectIRI = error.data.includes('$subject-iri');
75+
if (isFailOnSubjectIRI) {
76+
let failedContentObject = contentArray.find((contentObj) => error.data.includes(contentObj.uri));
77+
if (failedContentObject) {
78+
let contentValue = failedContentObject.value;
79+
let entityTitle;
80+
if (contentValue instanceof Node) {
81+
entityTitle = fn.string(contentValue.xpath('/*:envelope/*:instance/*:info/*:title'));
82+
} else {
83+
entityTitle = contentValue.envelope.instance.info.title;
84+
}
85+
throw new Error(`Cannot write ${entityTitle} instance with multiple values for identifier property. URI: ${failedContentObject.uri}`);
86+
}
87+
}
88+
default:
89+
throw error;
90+
}
5991
}
6092

6193
updateNodePath(docURI, xpath, newNode, database = xdmp.databaseName(xdmp.database())){
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
xquery version "1.0-ml";
2+
import module namespace hub-test = "http://marklogic.com/data-hub/test" at "/test/data-hub-test-helper.xqy";
3+
hub-test:reset-hub();
4+
5+
xquery version "1.0-ml";
6+
import module namespace hub-test = "http://marklogic.com/data-hub/test" at "/test/data-hub-test-helper.xqy";
7+
import module namespace test = "http://marklogic.com/test" at "/test/test-helper.xqy";
8+
hub-test:load-entities($test:__CALLER_FILE__);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"info": {
3+
"title": "Customer",
4+
"version": "0.0.1",
5+
"baseUri": "http://example.org/"
6+
},
7+
"definitions": {
8+
"Customer": {
9+
"primaryKey": "customerId",
10+
"properties": {
11+
"customerId": {
12+
"datatype": "integer"
13+
}
14+
}
15+
}
16+
}
17+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use strict';
2+
3+
const HubUtils = require("/data-hub/5/impl/hub-utils.sjs");
4+
const hubUtils = new HubUtils();
5+
const test = require("/test/test-helper.xqy");
6+
7+
const results = [];
8+
try {
9+
hubUtils.writeDocuments([{uri: "/0.json", value: {}},{uri: "/1.json", value: {}},{uri: "/1.json", value: {}},{uri: "/2.json", value: {}}]);
10+
test.assertTrue(false,'Should have thrown error for duplicate URIs!');
11+
} catch (e) {
12+
results.push(test.assertEqual('Attempted to write to the same URI multiple times in the same transaction. URI: /1.json',e.message));
13+
}
14+
// Testing with JSON Object value
15+
try {
16+
hubUtils.writeDocuments([{uri: "/customerObject.json", value: { envelope: { instance: { info: {version: '0.0.1', title: 'Customer'}, Customer: { customerId: [1,2]}}}}}]);
17+
test.assertTrue(false,'Should have thrown error for multiple identifiers in an entity instance!');
18+
} catch (e) {
19+
results.push(test.assertEqual('Cannot write Customer instance with multiple values for identifier property. URI: /customerObject.json',e.message));
20+
}
21+
// Testing with JSON Node value
22+
try {
23+
hubUtils.writeDocuments([{uri: "/customerNode.json", value: xdmp.toJSON({ envelope: { instance: { info: {version: '0.0.1', title: 'Customer'}, Customer: { customerId: [1,2]}}}})}]);
24+
test.assertTrue(false,'Should have thrown error for multiple identifiers in an entity instance!');
25+
} catch (e) {
26+
results.push(test.assertEqual('Cannot write Customer instance with multiple values for identifier property. URI: /customerNode.json', e.message));
27+
}
28+
29+
results;

0 commit comments

Comments
 (0)