Skip to content

Instantly share code, notes, and snippets.

View jmakeig's full-sized avatar

Justin Makeig jmakeig

View GitHub Profile
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 */
}
@jmakeig
jmakeig / export-workspaces.sh
Created March 24, 2017 18:17
cURL script to export MarkLogic Query Console workspaces
#!/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, 
@jmakeig
jmakeig / about.md
Last active May 24, 2017 23:01
Search MarkLogic Query Console buffers

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.

Set-up

  1. Enable word search indexes in the App-Services database
  2. Paste qconsole-search.sjs above into a Query Console query buffer (how meta)
  3. Modify the first parameter of the findBuffers() call at bottom to change the actual search term

To-do

  1. Weight highest to lowest: current query buffer, active buffers, current workspace, other workspaces
  2. Figure out security: There don’t look to be document permissions (other than qconsole-internal) on any of the Query Console data. (Shouldn’t workspaces, queries, and histories be “owned” by a user?)
@jmakeig
jmakeig / database-xpath.sjs
Last active January 31, 2020 23:50
Database-wide XPath evaluation in JavaScript in MarkLogic
/**
* @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]);
@jmakeig
jmakeig / about.md
Last active April 14, 2017 00:40
Separating concerns with chained lambdas in MarkLogic Server-Side JavaScript.

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 });
}
@jmakeig
jmakeig / example.sjs
Last active February 25, 2017 17:58
Decorator function for updates in MarkLogic that wraps a document update with a lock on the URI.
'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.
*
@jmakeig
jmakeig / row-sequence.sjs
Last active February 17, 2017 23:20
Experiments with typing tabular output from the MarkLogic Optic API
'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');
@jmakeig
jmakeig / version-test.sjs
Created December 10, 2016 19:28
MarkLogic version test
/**
* @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');
/**