最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why can’t I catch certain exceptions in a MarkLogic request? - Stack Overflow

programmeradmin0浏览0评论

I have some code that exercises the “invalid values” setting on an element range index. In this case, I have configured a dateTime element range index on the onDate element in my database (which will apply to both XML elements and JSON properties). I’ve set that index to reject invalid values. This setting means if I try to set the value of an onDate element and it is not castable to a dateTime or is null (literal null in JSON or xsi:nil="true" in XML), my update will fail. (The opposite behavior is to pletely ignore invalid values.)

I tried the following code in Server-Side JavaScript in MarkLogic 8.0-4:

'use strict';
declareUpdate();
var errors = [];
var inputs = {
 '/37107-valid.json': (new Date()).toISOString(),
 '/37107-invalid.json': 'asdf',  // Should throw an error
 '/37107-null.json': null  
};

for(var uri in inputs) {
 try {
   xdmp.documentInsert(
     uri,
     { 'onDate': inputs[uri] },
     xdmp.defaultPermissions(),
     ['37107'] // Collections
   );
 } catch(err) {
   errors.push(err);
 }
}
errors.length;

I would have expected my request to succeed and to end up with 1 === errors.length, because only the second insert would have failed because 'asdf' is not castable as a dateTime and it is not null. However, instead I get an XDMP-RANGEINDEX error and my transaction fails. Why doesn’t my try/catch work here?

I have some code that exercises the “invalid values” setting on an element range index. In this case, I have configured a dateTime element range index on the onDate element in my database (which will apply to both XML elements and JSON properties). I’ve set that index to reject invalid values. This setting means if I try to set the value of an onDate element and it is not castable to a dateTime or is null (literal null in JSON or xsi:nil="true" in XML), my update will fail. (The opposite behavior is to pletely ignore invalid values.)

I tried the following code in Server-Side JavaScript in MarkLogic 8.0-4:

'use strict';
declareUpdate();
var errors = [];
var inputs = {
 '/37107-valid.json': (new Date()).toISOString(),
 '/37107-invalid.json': 'asdf',  // Should throw an error
 '/37107-null.json': null  
};

for(var uri in inputs) {
 try {
   xdmp.documentInsert(
     uri,
     { 'onDate': inputs[uri] },
     xdmp.defaultPermissions(),
     ['37107'] // Collections
   );
 } catch(err) {
   errors.push(err);
 }
}
errors.length;

I would have expected my request to succeed and to end up with 1 === errors.length, because only the second insert would have failed because 'asdf' is not castable as a dateTime and it is not null. However, instead I get an XDMP-RANGEINDEX error and my transaction fails. Why doesn’t my try/catch work here?

Share Improve this question edited Sep 22, 2017 at 18:01 CommunityBot 11 silver badge asked Mar 1, 2016 at 19:19 Justin MakeigJustin Makeig 2,13715 silver badges29 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 14

The issue is how MarkLogic processes update transactions. Rather than actually changing the data with each xdmp.docuentInsert(…) call, MarkLogic queues up all of the updates and applies them atomically at the end of the request. (This is also why you can’t see database updates within the same transaction.) Thus, the error isn’t being thrown until after the loop has executed and the database tries to mit the queued transactions. This behavior is the same in XQuery (slightly simplified):

let $uris := (
 '/37107-valid.xml',
 '/37107-invalid.xml',
 '/37107-null.xml'
)
let $docs := (
 <onDate>{fn:current-dateTime()}</onDate>,
 <onDate>asdf</onDate>,
 <onDate xsi:nil="true" xmlns:xsi="http://www.w3/2001/XMLSchema-instance"/>
)
return
 for $uri at $i in $uris
 return 
   try {
     xdmp:document-insert($uri, $docs[$i], (), ('37107'))
   } catch($err) {
     xdmp:log($err)
   }

In order to catch the errors synchronously, you’d need to put each update into its own transaction. In general, this approach will be much slower and resource intensive than MarkLogic’s default transaction handling. However, it’s illustrative here to demonstrate what’s happening under the covers and can e in handy for specific use cases, like this one.

In the example below, I use xdmp.invokeFunction() to “call” a function in a separate transaction from the parent request. (First-class functions for the win!) This allows the updates to be fully applied (or rolled back with an error) and the calling module to see the updates (or errors). I’ve wrapped the low-level xdmp.invokeFunction() in my own applyAs() function to provide some niceties, like correctly passing function arguments to the curried function.

'use strict';

var errors = [];
var inputs = {
 '/37107-valid.json': (new Date()).toISOString(),
 '/37107-invalid.json': 'asdf',
 '/37107-null.json': null
};

var insert = applyAs(
 function(uri, value) {
   return xdmp.documentInsert(
     uri,
     { 'onDate': inputs[uri] },
     xdmp.defaultPermissions(),
     ['37107']
   );
 },
 { isolation: 'different-transaction', transactionMode: 'update' },
 'one'
);

for(var uri in inputs) {
 try {
   insert(uri, inputs[uri]);
 } catch(err) {
   errors.push(err);
 }
}
errors.length; // Correctly returns 1


// <https://gist.github./jmakeig/0a331823ad9a458167f6>
function applyAs(fct, options, returnType /* 'many', 'one', 'iterable' (default) */) {
  options = options || {};
  return function() {
    var params = Array.prototype.slice.call(arguments); 
    // Curry the function to include the params by closure.
    // xdmp.invokeFunction requires that invoked functions have
    // an arity of zero.
    var f = (function() {
       return fct.apply(null, params);
    }).bind(this);
    // Allow passing in user name, rather than id
    if(options.user) { options.userId = xdmp.user(options.user); delete options.user; }
    // Allow the functions themselves to declare their transaction mode
    if(fct.transactionMode && !(options.transactionMode)) { options.transactionMode = fct.transactionMode; }
    var result = xdmp.invokeFunction(f, options); // xdmp.invokeFunction returns a ValueIterator
    switch(returnType) {
      case 'one':
        // return fn.head(result); // 8.0-5
        return result.next().value;
      case 'many':
        return result.toArray();
      case 'iterable':
      default:
        return result;
    }
  }
}
发布评论

评论列表(0)

  1. 暂无评论