TL;DR: For custom types, it’s always better to extend an type’s prototype than to overwrite it.
function Custom() { // constructor
this.constructor.apply(this, arguments); // call the super-type’s constructor
}
Object.assign(
Custom.prototype, | const table = fn.head(xdmp.documentGet(CSV_FILE)).toObject(); // string | |
| const rows = table.split('\r\n'); // Parse lines into Array<string> | |
| const headers = rows.shift().split(','); // Array<string> | |
| // Array of functions used to parse column values | |
| // Only need to specify the left-most columns the others will be skipped | |
| const types = [ | |
| function(columnValue) { | |
| return; /* parsed representation or undefined to skip */ | |
| } |
| #!/usr/bin/env bash | |
| # Downloads Query Console workspaces to the current working directory in the | |
| # format `{host}_{workspace id}_{timestamp}.workspace`. | |
| # | |
| # Usage: ./query-console.sh localhost admin '******' | |
| # | |
| if command -v jq >/dev/null; then | |
| : |
TL;DR: For custom types, it’s always better to extend an type’s prototype than to overwrite it.
function Custom() { // constructor
this.constructor.apply(this, arguments); // call the super-type’s constructor
}
Object.assign(
Custom.prototype, Searches all Query Console workspaces. Uses exact match, like you’d do in the browser’s own find functionality. Only matches current buffers, not histories.
App-Services databaseqconsole-search.sjs above into a Query Console query buffer (how meta)findBuffers() call at bottom to change the actual search termqconsole-internal) on any of the Query Console data. (Shouldn’t workspaces, queries, and histories be “owned” by a user?)| /** | |
| * @param {string} path | |
| * @param {object} [bindings] | |
| * @param {string | Iterable<string>} [collection] | |
| * @return {Sequence<Node>} | |
| */ | |
| const xpath = (function _memo() { | |
| function isIterable(itr, ignoreStrings = false) { | |
| if ('string' === typeof itr) return !ignoreStrings; | |
| return Boolean(itr && itr[Symbol.iterator]); |
It’s a best practice in MarkLogic to lock a document, using xdmp.lockForUpdate(), before you update it to avoid deadlocks. This got me thinking about how to better decouple concerns like locking, transactions, and other context from the actual implementation of transformation logic.
For example, let’s say I’ve implemented my update business logic in a pure function, (i.e. no side-effects) like,
function addOrUpdateKey(doc, key) {
return Object.assign(doc.toObject(), { [key]: key });
}| 'use strict'; | |
| declareUpdate(); | |
| /** | |
| * An example function that take a Document node and some paramaters and returns | |
| * an updated copy, in Object form. Specifically, it adds a property with both the | |
| * name and value of the `letter` parameter. By design, this function doesn’t actually | |
| * change the input Document node. The point here is to decouple the mutation | |
| * of the document from the update in the database. | |
| * |
| 'use strict'; | |
| function RowSequence(rows) { | |
| //if(!(this instanceof RowSequence)) { return new RowSequence(rows); } | |
| this._rows = rows; | |
| } | |
| RowSequence.prototype = new Sequence; | |
| RowSequence.prototype[Symbol.iterator] = function*() { yield* this._rows; } // This won’t stream | |
| const op = require('/MarkLogic/optic'); |
| /** | |
| * @throws {Error} - Throws an error of the MarkLogic major version is less than 9 | |
| */ | |
| (function(ver){if(parseInt(xdmp.version().match(/(\d+)\.(\d+)-(\d+)(?:\.(\d+))?/)[1], 10) < ver) { throw new Error('This module will only run on MarkLogic ' + String(ver) + ' and up'); }})(9) |
| 'use strict'; | |
| /** {@link https://gist.github.com/jmakeig/0a331823ad9a458167f6#file-apply-as-9-sjs} */ | |
| function applyAs(fct,options,thisArg){return function(){const f=()=>{return[fct.call(thisArg,...arguments)]};options=options||{};if('string'===typeof options.database){options.database=xdmp.database(options.database)}if(options.user){options.userId=xdmp.user(options.user);delete options.user}if(fct.transactionMode&&!(options.transactionMode)){options.transactionMode=fct.transactionMode}return fn.head(xdmp.invokeFunction(f,options)).pop();}}; | |
| /** {@link https://gist.github.com/jmakeig/0a331823ad9a458167f6#file-hof-mapper-sjs} */ | |
| function map(fct,mapper){const ident=item=>item;mapper=mapper||ident;return function*_map(){const itr=fct.apply(null,arguments);if('string'===typeof itr||!(itr[Symbol.iterator])){yield itr}else{for(const item of itr){yield mapper(item)}}}}; | |
| const sec = require('/MarkLogic/security'); | |
| /** |