Last active
February 17, 2017 23:20
-
-
Save jmakeig/bf8dfcff1111cdb7682de578be12f1f7 to your computer and use it in GitHub Desktop.
Experiments with typing tabular output from the MarkLogic Optic API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| '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'); | |
| const plan = | |
| op.fromLiterals([ | |
| {group:1, val:2}, | |
| {group:1, val:4}, | |
| {group:2, val:3}, | |
| {group:2, val:5}, | |
| {group:2, val:7} | |
| ]) | |
| .orderBy('group') | |
| .groupBy('group', op.avg('valAvg', 'val')); | |
| new RowSequence( | |
| plan.result('object') | |
| ); | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 'use strict'; | |
| /** | |
| * A wrapper class to expose a proper iterator on anything that’s “array-like”. | |
| * Criteria for being array-like: | |
| * 1) has a `length` property that’s a positive integer | |
| * 2) has items that are accessible with integer indexes | |
| * @class | |
| */ | |
| function ArrayLikeIterator (obj) { | |
| this._o = obj; | |
| this._i = 0; | |
| } | |
| ArrayLikeIterator.prototype[Symbol.iterator] = function () { | |
| return this; | |
| } | |
| ArrayLikeIterator.prototype.next = function () { | |
| if (this._o === void 0 || this._i >= this._o.length) { | |
| this._o = void 0; | |
| return { value: void 0, done: true } | |
| } | |
| return { value: this._o[this._i++], done: false } | |
| } | |
| /** | |
| * Base type. Just a marker interface so both `RowArray` and `RowObject` instances | |
| * share a common type. | |
| * @class | |
| */ | |
| function Row(){} | |
| /** | |
| * Row results expressible as array-like. | |
| * FIXME: Does’t currently handle headers. | |
| * @class | |
| * @extends Row | |
| */ | |
| function RowArray(values) { | |
| Row.apply(this); | |
| // Make it array-like without actually extending `Array` | |
| Object.defineProperty( | |
| this, | |
| 'length', | |
| { | |
| value: values.length, | |
| configurable: false, | |
| enumerable: false, | |
| writable: false, | |
| } | |
| ); | |
| // Yes, this is inefficient. | |
| for(let i = 0; i < values.length; i++) { | |
| // Array-like | |
| this[i] = values[i]; | |
| } | |
| Object.freeze(this); | |
| } | |
| RowArray.prototype = new Row; | |
| /** | |
| * @property {function} - An iterator to make `RowArray` iterable over its column values | |
| */ | |
| RowArray.prototype[Symbol.iterator] = function() { return new ArrayLikeIterator(this); } | |
| /** | |
| * Sibling of `RowArray` that has columns exposed as enumerable properties on the instance. | |
| * @class | |
| * @extends Row | |
| */ | |
| function RowObject(cols) { | |
| Row.apply(this); | |
| const config = { enumerable: true, writable: false, configurable: false }; | |
| for(const col in cols) { | |
| Object.defineProperty(this, col, Object.assign(config, {value: cols[col]})); | |
| } | |
| Object.freeze(this); | |
| } | |
| RowObject.prototype = new Row; | |
| RowObject.prototype.toObject = function() { | |
| return Object.assign({}, this); | |
| } | |
| function doOptic(plan, output) { | |
| switch(output) { | |
| case 'array': | |
| return Sequence.from(plan.result('array'), row => new RowArray(row)); | |
| case 'object': | |
| return Sequence.from(plan.result('object'), row => new RowObject(row)); | |
| default: | |
| throw new TypeError(`${String(output)} is not a supported type`); | |
| } | |
| } | |
| const op = require('/MarkLogic/optic'); | |
| const plan = | |
| op.fromLiterals([ | |
| {group:1, val:2}, | |
| {group:1, val:4}, | |
| {group:2, val:3}, | |
| {group:2, val:5}, | |
| {group:2, val:7} | |
| ]) | |
| .orderBy('group') | |
| .groupBy('group', op.avg('valAvg', 'val')); | |
| Sequence.from( | |
| doOptic(plan, 'array'), | |
| row => { return { typed: row instanceof RowArray && row instanceof Row, values: Array.from(row) } } | |
| ); | |
| // {"typed":true, "values":["group", "valAvg"]} | |
| // {"typed":true, "values":[1, 3]} | |
| // {"typed":true, "values":[2, 5]} | |
| Sequence.from( | |
| doOptic(plan, 'object'), | |
| row => { return { typed: row instanceof RowObject && row instanceof Row, values: row.toObject() } } | |
| ); | |
| // {"typed":true, "values":{"group":1, "valAvg":3}} | |
| // {"typed":true, "values":{"group":2, "valAvg":5}} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment