plywood
Version:
A query planner and executor
1,261 lines • 74 kB
JavaScript
import { __assign, __awaiter, __extends, __generator } from "tslib";
import { Duration, parseISODate, Timezone } from 'chronoshift';
import * as hasOwnProp from 'has-own-prop';
import { generalLookupsEqual, isImmutableClass } from 'immutable-class';
import { PassThrough } from 'readable-stream';
import { Dataset, fillExpressionExternalAlteration, NumberRange, Range, Set, sizeOfDatasetExternalAlterations, StringRange, TimeRange, } from '../datatypes';
import { failIfIntrospectNeededInDatum, getFullTypeFromDatum, introspectDatum, } from '../datatypes/common';
import { Ip } from '../datatypes/ip';
import { iteratorFactory } from '../datatypes/valueStream';
import { External } from '../external/baseExternal';
import { promiseWhile } from '../helper/promiseWhile';
import { deduplicateSort, pipeWithError, repeat, shallowCopy } from '../helper/utils';
import { AbsoluteExpression } from './absoluteExpression';
import { AddExpression } from './addExpression';
import { AndExpression } from './andExpression';
import { ApplyExpression } from './applyExpression';
import { AverageExpression } from './averageExpression';
import { CardinalityExpression } from './cardinalityExpression';
import { CastExpression } from './castExpression';
import { CollectExpression } from './collectExpression';
import { ConcatExpression } from './concatExpression';
import { ContainsExpression } from './containsExpression';
import { CountDistinctExpression } from './countDistinctExpression';
import { CountExpression } from './countExpression';
import { CustomAggregateExpression } from './customAggregateExpression';
import { CustomTransformExpression } from './customTransformExpression';
import { DivideExpression } from './divideExpression';
import { ExternalExpression } from './externalExpression';
import { ExtractExpression } from './extractExpression';
import { FallbackExpression } from './fallbackExpression';
import { FilterExpression } from './filterExpression';
import { GreaterThanExpression } from './greaterThanExpression';
import { GreaterThanOrEqualExpression } from './greaterThanOrEqualExpression';
import { IndexOfExpression } from './indexOfExpression';
import { InExpression } from './inExpression';
import { IpMatchExpression } from './ipMatchExpression';
import { IpSearchExpression } from './ipSearchExpression';
import { IpStringifyExpression } from './ipStringifyExpression';
import { IsExpression } from './isExpression';
import { JoinExpression } from './joinExpression';
import { LengthExpression } from './lengthExpression';
import { LessThanExpression } from './lessThanExpression';
import { LessThanOrEqualExpression } from './lessThanOrEqualExpression';
import { LimitExpression } from './limitExpression';
import { LiteralExpression } from './literalExpression';
import { LogExpression } from './logExpression';
import { LookupExpression } from './lookupExpression';
import { MatchExpression } from './matchExpression';
import { MaxExpression } from './maxExpression';
import { MinExpression } from './minExpression';
import { MultiplyExpression } from './multiplyExpression';
import { MvContainsExpression } from './mvContainsExpression';
import { MvFilterOnlyExpression } from './mvFilterOnlyExpression';
import { MvOverlapExpression } from './mvOverlapExpression';
import { NotExpression } from './notExpression';
import { NumberBucketExpression } from './numberBucketExpression';
import { OrExpression } from './orExpression';
import { OverlapExpression } from './overlapExpression';
import { PowerExpression } from './powerExpression';
import { QuantileExpression } from './quantileExpression';
import { RefExpression } from './refExpression';
import { SelectExpression } from './selectExpression';
import { SortExpression } from './sortExpression';
import { SplitExpression } from './splitExpression';
import { SqlAggregateExpression } from './sqlAggregateExpression';
import { SqlRefExpression } from './sqlRefExpression';
import { SubstrExpression } from './substrExpression';
import { SubtractExpression } from './subtractExpression';
import { SumExpression } from './sumExpression';
import { ThenExpression } from './thenExpression';
import { TimeBucketExpression } from './timeBucketExpression';
import { TimeFloorExpression } from './timeFloorExpression';
import { TimePartExpression } from './timePartExpression';
import { TimeRangeExpression } from './timeRangeExpression';
import { TimeShiftExpression } from './timeShiftExpression';
import { TransformCaseExpression } from './transformCaseExpression';
function fillExpressionExternalAlterationAsync(alteration, filler) {
var tasks = [];
fillExpressionExternalAlteration(alteration, function (external, terminal) {
tasks.push(filler(external, terminal));
return null;
});
return Promise.all(tasks).then(function (results) {
var i = 0;
fillExpressionExternalAlteration(alteration, function () {
var res = results[i];
i++;
return res;
});
return alteration;
});
}
function runtimeAbstract() {
return new Error('must be implemented');
}
function getDataName(ex) {
if (ex instanceof RefExpression) {
return ex.name;
}
else if (ex instanceof ChainableExpression) {
return getDataName(ex.operand);
}
else {
return null;
}
}
function getValue(param) {
if (param instanceof LiteralExpression)
return param.value;
return param;
}
function getString(param) {
if (typeof param === 'string')
return param;
if (param instanceof LiteralExpression && param.type === 'STRING') {
return param.value;
}
if (param instanceof RefExpression && param.nest === 0) {
return param.name;
}
throw new Error('could not extract a string out of ' + String(param));
}
function getNumber(param) {
if (typeof param === 'number')
return param;
if (param instanceof LiteralExpression && param.type === 'NUMBER') {
return param.value;
}
throw new Error('could not extract a number out of ' + String(param));
}
export function ply(dataset) {
if (!dataset) {
dataset = new Dataset({
keys: [],
data: [{}],
});
}
return r(dataset);
}
export function $(name, nest, type) {
if (typeof name !== 'string')
throw new TypeError('$() argument must be a string');
if (typeof nest === 'string') {
type = nest;
nest = 0;
}
return new RefExpression({
name: name,
nest: nest != null ? nest : 0,
type: type,
});
}
export function i$(name, nest, type) {
if (typeof name !== 'string')
throw new TypeError('i$() argument must be a string');
if (typeof nest === 'string') {
type = nest;
nest = 0;
}
return new RefExpression({
name: name,
nest: nest != null ? nest : 0,
type: type,
ignoreCase: true,
});
}
export function s$(sql, type) {
if (typeof sql !== 'string')
throw new TypeError('s$() argument must be a string');
return new SqlRefExpression({ sql: sql, type: type });
}
export function r(value) {
if (value instanceof External)
throw new TypeError('r() can not accept externals');
if (Array.isArray(value))
value = Set.fromJS(value);
return LiteralExpression.fromJS({ op: 'literal', value: value });
}
export function toJS(thing) {
return thing && typeof thing.toJS === 'function' ? thing.toJS() : thing;
}
function chainVia(op, expressions, zero) {
var n = expressions.length;
if (!n)
return zero;
var acc = expressions[0];
if (!(acc instanceof Expression))
acc = Expression.fromJSLoose(acc);
for (var i = 1; i < n; i++)
acc = acc[op](expressions[i]);
return acc;
}
var Expression = (function () {
function Expression(parameters, dummy) {
if (dummy === void 0) { dummy = null; }
this.op = parameters.op;
if (dummy !== dummyObject) {
throw new TypeError('can not call `new Expression` directly use Expression.fromJS instead');
}
if (parameters.simple)
this.simple = true;
if (parameters.options)
this.options = parameters.options;
}
Expression.isExpression = function (candidate) {
return candidate instanceof Expression;
};
Expression.expressionLookupFromJS = function (expressionJSs) {
var expressions = Object.create(null);
for (var name_1 in expressionJSs) {
if (!hasOwnProp(expressionJSs, name_1))
continue;
expressions[name_1] = Expression.fromJSLoose(expressionJSs[name_1]);
}
return expressions;
};
Expression.expressionLookupToJS = function (expressions) {
var expressionsJSs = {};
for (var name_2 in expressions) {
if (!hasOwnProp(expressions, name_2))
continue;
expressionsJSs[name_2] = expressions[name_2].toJS();
}
return expressionsJSs;
};
Expression.parse = function (str, timezone) {
if (str[0] === '{' && str[str.length - 1] === '}') {
return Expression.fromJS(JSON.parse(str));
}
var original = Expression.defaultParserTimezone;
if (timezone)
Expression.defaultParserTimezone = timezone;
try {
return Expression.expressionParser.parse(str);
}
catch (e) {
throw new Error("Expression parse error: ".concat(e.message, " on '").concat(str, "'"));
}
finally {
Expression.defaultParserTimezone = original;
}
};
Expression.fromJSLoose = function (param) {
var expressionJS;
switch (typeof param) {
case 'undefined':
throw new Error('must have an expression');
case 'object':
if (param === null) {
return Expression.NULL;
}
else if (param instanceof Expression) {
return param;
}
else if (isImmutableClass(param)) {
if (param.constructor.type) {
expressionJS = { op: 'literal', value: param };
}
else {
throw new Error('unknown object');
}
}
else if (param.op) {
expressionJS = param;
}
else if (param.toISOString) {
expressionJS = { op: 'literal', value: new Date(param) };
}
else if (Array.isArray(param)) {
expressionJS = { op: 'literal', value: Set.fromJS(param) };
}
else if (hasOwnProp(param, 'start') && hasOwnProp(param, 'end')) {
expressionJS = { op: 'literal', value: Range.fromJS(param) };
}
else {
throw new Error('unknown parameter');
}
break;
case 'number':
case 'boolean':
expressionJS = { op: 'literal', value: param };
break;
case 'string':
return Expression.parse(param);
default:
throw new Error('unrecognizable expression');
}
return Expression.fromJS(expressionJS);
};
Expression.parseTuning = function (tuning) {
if (typeof tuning !== 'string')
return {};
var parts = tuning.split(',');
var parsed = {};
for (var _i = 0, parts_1 = parts; _i < parts_1.length; _i++) {
var part = parts_1[_i];
var subParts = part.split('=');
if (subParts.length !== 2)
throw new Error("can not parse tuning '".concat(tuning, "'"));
parsed[subParts[0]] = subParts[1];
}
return parsed;
};
Expression.safeString = function (str) {
return /^[a-z]\w+$/i.test(str) ? str : JSON.stringify(str);
};
Expression.and = function (expressions) {
return chainVia('and', expressions, Expression.TRUE);
};
Expression.or = function (expressions) {
return chainVia('or', expressions, Expression.FALSE);
};
Expression.add = function (expressions) {
return chainVia('add', expressions, Expression.ZERO);
};
Expression.subtract = function (expressions) {
return chainVia('subtract', expressions, Expression.ZERO);
};
Expression.multiply = function (expressions) {
return chainVia('multiply', expressions, Expression.ONE);
};
Expression.power = function (expressions) {
return chainVia('power', expressions, Expression.ZERO);
};
Expression.concat = function (expressions) {
return chainVia('concat', expressions, Expression.EMPTY_STRING);
};
Expression.register = function (ex) {
var op = ex.op.replace(/^\w/, function (s) { return s.toLowerCase(); });
Expression.classMap[op] = ex;
};
Expression.getConstructorFor = function (op) {
var ClassFn = Expression.classMap[op];
if (!ClassFn)
throw new Error("unsupported expression op '".concat(op, "'"));
return ClassFn;
};
Expression.applyMixins = function (derivedCtor, baseCtors) {
baseCtors.forEach(function (baseCtor) {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(function (name) {
derivedCtor.prototype[name] = baseCtor.prototype[name];
});
});
};
Expression.jsToValue = function (js) {
return {
op: js.op,
type: js.type,
options: js.options,
};
};
Expression.fromJS = function (expressionJS) {
if (!expressionJS)
throw new Error('must have expressionJS');
if (!hasOwnProp(expressionJS, 'op')) {
if (hasOwnProp(expressionJS, 'action')) {
expressionJS = shallowCopy(expressionJS);
expressionJS.op = expressionJS.action;
delete expressionJS.action;
expressionJS.operand = { op: 'ref', name: '_' };
}
else {
throw new Error('op must be defined');
}
}
if (expressionJS.op === 'custom') {
expressionJS = shallowCopy(expressionJS);
expressionJS.op = 'customAggregate';
}
var op = expressionJS.op;
if (typeof op !== 'string') {
throw new Error('op must be a string');
}
if (op === 'chain') {
var actions = expressionJS.actions || [expressionJS.action];
return Expression.fromJS(expressionJS.expression).performActions(actions.map(Expression.fromJS));
}
var ClassFn = Expression.getConstructorFor(op);
return ClassFn.fromJS(expressionJS);
};
Expression.fromValue = function (parameters) {
var op = parameters.op;
var ClassFn = Expression.getConstructorFor(op);
return new ClassFn(parameters);
};
Expression.prototype._ensureOp = function (op) {
if (!this.op) {
this.op = op;
return;
}
if (this.op !== op) {
throw new TypeError("incorrect expression op '".concat(this.op, "' (needs to be: '").concat(op, "')"));
}
};
Expression.prototype.valueOf = function () {
var value = { op: this.op };
if (this.simple)
value.simple = true;
if (this.options)
value.options = this.options;
return value;
};
Expression.prototype.toJS = function () {
var js = { op: this.op };
if (this.options)
js.options = this.options;
return js;
};
Expression.prototype.toJSON = function () {
return this.toJS();
};
Expression.prototype.equals = function (other) {
return (other instanceof Expression &&
this.op === other.op &&
this.type === other.type &&
generalLookupsEqual(this.options, other.options));
};
Expression.prototype.canHaveType = function (wantedType) {
var type = this.type;
if (!type || type === 'NULL')
return true;
if (wantedType === 'SET') {
return Set.isSetType(type);
}
else {
return type === wantedType;
}
};
Expression.prototype.expressionCount = function () {
return 1;
};
Expression.prototype.isOp = function (op) {
return this.op === op;
};
Expression.prototype.markSimple = function () {
if (this.simple)
return this;
var value = this.valueOf();
value.simple = true;
return Expression.fromValue(value);
};
Expression.prototype.containsOp = function (op) {
return this.some(function (ex) { return ex.isOp(op) || null; });
};
Expression.prototype.hasExternal = function () {
return this.some(function (ex) {
if (ex instanceof ExternalExpression)
return true;
return null;
});
};
Expression.prototype.getBaseExternals = function () {
var externals = [];
this.forEach(function (ex) {
if (ex instanceof ExternalExpression)
externals.push(ex.external.getBase());
});
return External.deduplicateExternals(externals);
};
Expression.prototype.getRawExternals = function () {
var externals = [];
this.forEach(function (ex) {
if (ex instanceof ExternalExpression)
externals.push(ex.external.getRaw());
});
return External.deduplicateExternals(externals);
};
Expression.prototype.getReadyExternals = function (limit) {
if (limit === void 0) { limit = Infinity; }
var indexToSkip = {};
var externalsByIndex = {};
this.every(function (ex, index) {
if (limit <= 0)
return null;
if (ex instanceof ExternalExpression) {
if (indexToSkip[index])
return null;
if (!ex.external.suppress) {
limit--;
externalsByIndex[index] = {
external: ex.external,
terminal: true,
};
}
}
else if (ex instanceof ChainableExpression) {
var h = ex._headExternal();
if (h) {
if (h.allGood) {
limit--;
externalsByIndex[index + h.offset] = { external: h.external };
return true;
}
else {
indexToSkip[index + h.offset] = true;
return null;
}
}
}
else if (ex instanceof LiteralExpression && ex.type === 'DATASET') {
var datasetExternals = ex.value.getReadyExternals(limit);
var size = sizeOfDatasetExternalAlterations(datasetExternals);
if (size) {
limit -= size;
externalsByIndex[index] = datasetExternals;
}
return null;
}
return null;
});
return externalsByIndex;
};
Expression.prototype.applyReadyExternals = function (alterations) {
return this.substitute(function (ex, index) {
var alteration = alterations[index];
if (!alteration)
return null;
if (Array.isArray(alteration)) {
return r(ex.getLiteralValue().applyReadyExternals(alteration));
}
else {
return r(alteration.result);
}
}).simplify();
};
Expression.prototype._headExternal = function () {
var ex = this;
var allGood = true;
var offset = 0;
while (ex instanceof ChainableExpression) {
allGood =
allGood &&
(ex.op === 'filter' ? ex.argumentsResolvedWithoutExternals() : ex.argumentsResolved());
ex = ex.operand;
offset++;
}
if (ex instanceof ExternalExpression) {
return {
allGood: allGood,
external: ex.external,
offset: offset,
};
}
else {
return null;
}
};
Expression.prototype.getHeadOperand = function () {
return this;
};
Expression.prototype.getFreeReferences = function () {
var freeReferences = [];
this.forEach(function (ex, index, depth, nestDiff) {
if (ex instanceof RefExpression && nestDiff <= ex.nest) {
freeReferences.push(repeat('^', ex.nest - nestDiff) + ex.name);
}
});
return deduplicateSort(freeReferences);
};
Expression.prototype.getFreeReferenceIndexes = function () {
var freeReferenceIndexes = [];
this.forEach(function (ex, index, depth, nestDiff) {
if (ex instanceof RefExpression && nestDiff <= ex.nest) {
freeReferenceIndexes.push(index);
}
});
return freeReferenceIndexes;
};
Expression.prototype.incrementNesting = function (by) {
if (by === void 0) { by = 1; }
var freeReferenceIndexes = this.getFreeReferenceIndexes();
if (freeReferenceIndexes.length === 0)
return this;
return this.substitute(function (ex, index) {
if (ex instanceof RefExpression && freeReferenceIndexes.indexOf(index) !== -1) {
return ex.incrementNesting(by);
}
return null;
});
};
Expression.prototype.simplify = function () {
return this;
};
Expression.prototype.every = function (iter, thisArg) {
return this._everyHelper(iter, thisArg, { index: 0 }, 0, 0);
};
Expression.prototype._everyHelper = function (iter, thisArg, indexer, depth, nestDiff) {
var pass = iter.call(thisArg, this, indexer.index, depth, nestDiff);
if (pass != null) {
return pass;
}
else {
indexer.index++;
}
return true;
};
Expression.prototype.some = function (iter, thisArg) {
var _this = this;
return !this.every(function (ex, index, depth, nestDiff) {
var v = iter.call(_this, ex, index, depth, nestDiff);
return v == null ? null : !v;
}, thisArg);
};
Expression.prototype.forEach = function (iter, thisArg) {
var _this = this;
this.every(function (ex, index, depth, nestDiff) {
iter.call(_this, ex, index, depth, nestDiff);
return null;
}, thisArg);
};
Expression.prototype.substitute = function (substitutionFn, typeContext) {
if (typeContext === void 0) { typeContext = null; }
return this._substituteHelper(substitutionFn, { index: 0 }, 0, 0, typeContext).expression;
};
Expression.prototype._substituteHelper = function (substitutionFn, indexer, depth, nestDiff, typeContext) {
var sub = substitutionFn.call(this, this, indexer.index, depth, nestDiff, typeContext);
if (sub) {
indexer.index += this.expressionCount();
return {
expression: sub,
typeContext: sub.updateTypeContextIfNeeded(typeContext),
};
}
else {
indexer.index++;
}
return {
expression: this,
typeContext: this.updateTypeContextIfNeeded(typeContext),
};
};
Expression.prototype.fullyDefined = function () {
return true;
};
Expression.prototype.extractFromAnd = function (matchFn) {
if (this.type !== 'BOOLEAN')
return null;
if (matchFn(this)) {
return {
extract: this,
rest: Expression.TRUE,
};
}
else {
return {
extract: Expression.TRUE,
rest: this,
};
}
};
Expression.prototype.breakdownByDataset = function (_tempNamePrefix) {
if (_tempNamePrefix === void 0) { _tempNamePrefix = 'b'; }
throw new Error('ToDo');
};
Expression.prototype.getLiteralValue = function () {
return null;
};
Expression.prototype.upgradeToType = function (_targetType) {
return this;
};
Expression.prototype.performAction = function (action) {
var _this = this;
return action.substitute(function (ex) { return (ex.equals(Expression._) ? _this : null); });
};
Expression.prototype.performActions = function (actions) {
var ex = this;
for (var _i = 0, actions_1 = actions; _i < actions_1.length; _i++) {
var action = actions_1[_i];
ex = ex.performAction(action);
}
return ex;
};
Expression.prototype.getOptions = function () {
return this.options || {};
};
Expression.prototype.setOptions = function (options) {
var value = this.valueOf();
value.options = options;
return Expression.fromValue(value);
};
Expression.prototype.setOption = function (optionKey, optionValue) {
var newOptions = __assign({}, this.getOptions());
newOptions[optionKey] = optionValue;
return this.setOptions(newOptions);
};
Expression.prototype._mkChain = function (ExpressionClass, exs) {
var cur = this;
for (var _i = 0, exs_1 = exs; _i < exs_1.length; _i++) {
var ex = exs_1[_i];
cur = new ExpressionClass({
operand: cur,
expression: ex instanceof Expression ? ex : Expression.fromJSLoose(ex),
});
}
return cur;
};
Expression.prototype.add = function () {
var exs = [];
for (var _i = 0; _i < arguments.length; _i++) {
exs[_i] = arguments[_i];
}
return this._mkChain(AddExpression, exs);
};
Expression.prototype.subtract = function () {
var exs = [];
for (var _i = 0; _i < arguments.length; _i++) {
exs[_i] = arguments[_i];
}
return this._mkChain(SubtractExpression, exs);
};
Expression.prototype.negate = function () {
return Expression.ZERO.subtract(this);
};
Expression.prototype.multiply = function () {
var exs = [];
for (var _i = 0; _i < arguments.length; _i++) {
exs[_i] = arguments[_i];
}
return this._mkChain(MultiplyExpression, exs);
};
Expression.prototype.divide = function () {
var exs = [];
for (var _i = 0; _i < arguments.length; _i++) {
exs[_i] = arguments[_i];
}
return this._mkChain(DivideExpression, exs);
};
Expression.prototype.reciprocate = function () {
return Expression.ONE.divide(this);
};
Expression.prototype.sqrt = function () {
return this.power(0.5);
};
Expression.prototype.power = function () {
var exs = [];
for (var _i = 0; _i < arguments.length; _i++) {
exs[_i] = arguments[_i];
}
return this._mkChain(PowerExpression, exs);
};
Expression.prototype.log = function (ex) {
if (ex === void 0) { ex = Math.E; }
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new LogExpression({ operand: this, expression: ex });
};
Expression.prototype.ln = function () {
return new LogExpression({ operand: this, expression: r(Math.E) });
};
Expression.prototype.then = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new ThenExpression({ operand: this, expression: ex });
};
Expression.prototype.fallback = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new FallbackExpression({ operand: this, expression: ex });
};
Expression.prototype.is = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new IsExpression({ operand: this, expression: ex });
};
Expression.prototype.isnt = function (ex) {
return this.is(ex).not();
};
Expression.prototype.lessThan = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new LessThanExpression({ operand: this, expression: ex });
};
Expression.prototype.lessThanOrEqual = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new LessThanOrEqualExpression({ operand: this, expression: ex });
};
Expression.prototype.greaterThan = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new GreaterThanExpression({ operand: this, expression: ex });
};
Expression.prototype.greaterThanOrEqual = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new GreaterThanOrEqualExpression({ operand: this, expression: ex });
};
Expression.prototype.contains = function (ex, compare) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
if (compare)
compare = getString(compare);
return new ContainsExpression({ operand: this, expression: ex, compare: compare });
};
Expression.prototype.mvContains = function (mvArray) {
return new MvContainsExpression({ operand: this, mvArray: mvArray });
};
Expression.prototype.mvFilterOnly = function (mvArray) {
return new MvFilterOnlyExpression({ operand: this, mvArray: mvArray });
};
Expression.prototype.mvOverlap = function (mvArray) {
return new MvOverlapExpression({ operand: this, mvArray: mvArray });
};
Expression.prototype.match = function (re) {
return new MatchExpression({ operand: this, regexp: getString(re) });
};
Expression.prototype.in = function (ex) {
if (arguments.length === 2) {
return this.overlap(ex, arguments[1]);
}
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
if (Range.isRangeType(ex.type)) {
return new OverlapExpression({ operand: this, expression: ex });
}
return new InExpression({ operand: this, expression: ex });
};
Expression.prototype.overlap = function (ex, snd) {
if (arguments.length === 2) {
ex = getValue(ex);
snd = getValue(snd);
if (typeof ex === 'string') {
var parse = parseISODate(ex, Expression.defaultParserTimezone);
if (parse)
ex = parse;
}
if (typeof snd === 'string') {
var parse = parseISODate(snd, Expression.defaultParserTimezone);
if (parse)
snd = parse;
}
if (typeof ex === 'number' && typeof snd === 'number') {
ex = new NumberRange({ start: ex, end: snd });
}
else if (ex.toISOString && snd.toISOString) {
ex = new TimeRange({ start: ex, end: snd });
}
else if (typeof ex === 'string' && typeof snd === 'string') {
ex = new StringRange({ start: ex, end: snd });
}
else {
throw new Error('uninterpretable IN parameters');
}
}
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new OverlapExpression({ operand: this, expression: ex });
};
Expression.prototype.not = function () {
return new NotExpression({ operand: this });
};
Expression.prototype.and = function () {
var exs = [];
for (var _i = 0; _i < arguments.length; _i++) {
exs[_i] = arguments[_i];
}
return this._mkChain(AndExpression, exs);
};
Expression.prototype.or = function () {
var exs = [];
for (var _i = 0; _i < arguments.length; _i++) {
exs[_i] = arguments[_i];
}
return this._mkChain(OrExpression, exs);
};
Expression.prototype.ipMatch = function (searchString, ipSearchType) {
return new IpMatchExpression({
operand: this,
ipToSearch: Ip.fromString(searchString),
ipSearchType: ipSearchType,
});
};
Expression.prototype.ipSearch = function (searchString, ipSearchType) {
return new IpSearchExpression({
operand: this,
ipToSearch: Ip.fromString(searchString),
ipSearchType: ipSearchType,
});
};
Expression.prototype.ipStringify = function () {
return new IpStringifyExpression({ operand: this });
};
Expression.prototype.substr = function (position, len) {
return new SubstrExpression({
operand: this,
position: getNumber(position),
len: getNumber(len),
});
};
Expression.prototype.extract = function (re) {
return new ExtractExpression({ operand: this, regexp: getString(re) });
};
Expression.prototype.concat = function () {
var exs = [];
for (var _i = 0; _i < arguments.length; _i++) {
exs[_i] = arguments[_i];
}
return this._mkChain(ConcatExpression, exs);
};
Expression.prototype.lookup = function (lookupFn) {
return new LookupExpression({ operand: this, lookupFn: getString(lookupFn) });
};
Expression.prototype.indexOf = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new IndexOfExpression({ operand: this, expression: ex });
};
Expression.prototype.transformCase = function (transformType) {
return new TransformCaseExpression({
operand: this,
transformType: getString(transformType),
});
};
Expression.prototype.customTransform = function (custom, outputType) {
if (!custom)
throw new Error('Must provide an extraction function name for custom transform');
outputType = outputType !== undefined ? getString(outputType) : null;
return new CustomTransformExpression({ operand: this, custom: getString(custom), outputType: outputType });
};
Expression.prototype.numberBucket = function (size, offset) {
if (offset === void 0) { offset = 0; }
return new NumberBucketExpression({
operand: this,
size: getNumber(size),
offset: getNumber(offset),
});
};
Expression.prototype.absolute = function () {
return new AbsoluteExpression({ operand: this });
};
Expression.prototype.length = function () {
return new LengthExpression({ operand: this });
};
Expression.prototype.timeBucket = function (duration, timezone) {
if (!(duration instanceof Duration))
duration = Duration.fromJS(getString(duration));
if (timezone && !(timezone instanceof Timezone))
timezone = Timezone.fromJS(getString(timezone));
return new TimeBucketExpression({ operand: this, duration: duration, timezone: timezone });
};
Expression.prototype.timeFloor = function (duration, timezone) {
if (!(duration instanceof Duration))
duration = Duration.fromJS(getString(duration));
if (timezone && !(timezone instanceof Timezone))
timezone = Timezone.fromJS(getString(timezone));
return new TimeFloorExpression({ operand: this, duration: duration, timezone: timezone });
};
Expression.prototype.timeShift = function (duration, step, timezone) {
if (!(duration instanceof Duration))
duration = Duration.fromJS(getString(duration));
step = typeof step !== 'undefined' ? getNumber(step) : null;
if (timezone && !(timezone instanceof Timezone))
timezone = Timezone.fromJS(getString(timezone));
return new TimeShiftExpression({ operand: this, duration: duration, step: step, timezone: timezone });
};
Expression.prototype.timeRange = function (duration, step, timezone) {
if (!(duration instanceof Duration))
duration = Duration.fromJS(getString(duration));
step = typeof step !== 'undefined' ? getNumber(step) : null;
if (timezone && !(timezone instanceof Timezone))
timezone = Timezone.fromJS(getString(timezone));
return new TimeRangeExpression({ operand: this, duration: duration, step: step, timezone: timezone });
};
Expression.prototype.timePart = function (part, timezone) {
if (timezone && !(timezone instanceof Timezone))
timezone = Timezone.fromJS(getString(timezone));
return new TimePartExpression({ operand: this, part: getString(part), timezone: timezone });
};
Expression.prototype.cast = function (outputType) {
return new CastExpression({
operand: this,
outputType: getString(outputType),
});
};
Expression.prototype.cardinality = function () {
return new CardinalityExpression({ operand: this });
};
Expression.prototype.filter = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new FilterExpression({ operand: this, expression: ex });
};
Expression.prototype.split = function (splits, name, dataName) {
if (arguments.length === 3 ||
((arguments.length === 2 || arguments.length === 1) &&
(typeof splits === 'string' || typeof splits.op === 'string'))) {
name = arguments.length === 1 ? 'split' : getString(name);
var realSplits = Object.create(null);
realSplits[name] = splits;
splits = realSplits;
}
else {
dataName = name;
}
var parsedSplits = Object.create(null);
for (var k in splits) {
if (!hasOwnProp(splits, k))
continue;
var ex = splits[k];
parsedSplits[k] = ex instanceof Expression ? ex : Expression.fromJSLoose(ex);
}
dataName = dataName ? getString(dataName) : getDataName(this);
if (!dataName)
throw new Error('could not guess data name in `split`, please provide one explicitly');
return new SplitExpression({ operand: this, splits: parsedSplits, dataName: dataName });
};
Expression.prototype.apply = function (name, ex) {
if (arguments.length < 2)
throw new Error('invalid arguments to .apply, did you forget to specify a name?');
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new ApplyExpression({ operand: this, name: getString(name), expression: ex });
};
Expression.prototype.sort = function (ex, direction) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new SortExpression({
operand: this,
expression: ex,
direction: direction ? getString(direction) : null,
});
};
Expression.prototype.limit = function (value) {
return new LimitExpression({ operand: this, value: getNumber(value) });
};
Expression.prototype.select = function () {
var attributes = [];
for (var _i = 0; _i < arguments.length; _i++) {
attributes[_i] = arguments[_i];
}
attributes =
attributes.length === 1 && Array.isArray(attributes[0])
? attributes[0]
: attributes.map(getString);
return new SelectExpression({ operand: this, attributes: attributes });
};
Expression.prototype.count = function () {
if (arguments.length)
throw new Error('.count() should not have arguments, did you want to .filter().count() ?');
return new CountExpression({ operand: this });
};
Expression.prototype.sum = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new SumExpression({ operand: this, expression: ex });
};
Expression.prototype.min = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new MinExpression({ operand: this, expression: ex });
};
Expression.prototype.max = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new MaxExpression({ operand: this, expression: ex });
};
Expression.prototype.average = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new AverageExpression({ operand: this, expression: ex });
};
Expression.prototype.countDistinct = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new CountDistinctExpression({ operand: this, expression: ex });
};
Expression.prototype.quantile = function (ex, value, tuning) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new QuantileExpression({
operand: this,
expression: ex,
value: getNumber(value),
tuning: tuning ? getString(tuning) : null,
});
};
Expression.prototype.collect = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new CollectExpression({ operand: this, expression: ex });
};
Expression.prototype.customAggregate = function (custom) {
return new CustomAggregateExpression({ operand: this, custom: getString(custom) });
};
Expression.prototype.sqlAggregate = function (sql) {
return new SqlAggregateExpression({ operand: this, sql: getString(sql) });
};
Expression.prototype.join = function (ex) {
if (!(ex instanceof Expression))
ex = Expression.fromJSLoose(ex);
return new JoinExpression({ operand: this, expression: ex });
};
Expression.prototype.needsEnvironment = function () {
return false;
};
Expression.prototype.defineEnvironment = function (environment) {
if (!environment.timezone)
environment = { timezone: Timezone.UTC };
if (typeof environment.timezone === 'string')
environment = { timezone: Timezone.fromJS(environment.timezone) };
return this.substitute(function (ex) {
if (ex.needsEnvironment()) {
return ex.defineEnvironment(environment);
}
return null;
});
};
Expression.prototype.referenceCheck = function (context) {
return this.changeInTypeContext(getFullTypeFromDatum(context));
};
Expression.prototype.definedInTypeContext = function (typeContext) {
try {
this.changeInTypeContext(typeContext);
}
catch (e) {
return false;
}
return true;
};
Expression.prototype.referenceCheckInTypeContext = function (typeContext) {
console.warn("referenceCheckInTypeContext is deprecated, use changeInTypeContext instead");
return this.changeInTypeContext(typeContext);
};
Expression.prototype.changeInTypeContext = function (typeContext) {
return this.substitute(function (ex, index, depth, nestDiff, typeContext) {
if (ex instanceof RefExpression) {
return ex.changeInTypeContext(typeContext);
}
return null;
}, typeContext);
};
Expression.prototype.updateTypeContext = function (typeContext, _extra) {
return typeContext;
};
Expression.prototype.updateTypeContextIfNeeded = function (typeContext, extra) {
return typeContext ? this.updateTypeContext(typeContext, extra) : null;
};
Expression.prototype.resolve = function (context, ifNotFound) {
if (ifNotFound === void 0) { ifNotFound = 'throw'; }
var expressions = Object.create(null);
for (var k in context) {
if (!hasOwnProp(context, k))
continue;
var value = context[k];
if (value instanceof External) {
expressions[k] = new ExternalExpression({ external: value });
}
else if (value instanceof Expression) {
expressions[k] = value;
}
else {
expressions[k] = new LiteralExpression({ value: value });
}
}
return this.resolveWithExpressions(expressions, ifNotFound);
};
Expression.prototype.resolveWithExpressions = function (expressions, ifNotFound) {
if (ifNotFound === void 0) { ifNotFound = 'throw'; }
return this.substitute(function (ex, index, depth, nestDiff) {
if (ex instanceof RefExpression) {
var nest = ex.nest, ignoreCase = ex.ignoreCase, name_3 = ex.name;
if (nestDiff === nest) {
var foundExpression = null;
var valueFound = false;
var property = ignoreCase
? RefExpression.findPropertyCI(expressions, name_3)
: RefExpression.findProperty(expressions, name_3);
if (property != null) {
foundExpression = expressions[property];
valueFound = true;
}
if (foundExpression instanceof ExternalExpression) {
var mode = foundExpression.external.mode;
if (mode === 'split') {
return ex;
}
if (nest > 0 && mode !== 'raw') {
return ex;
}
}
if (valueFound) {
return foundExpression;
}
else if (ifNotFound === 'throw') {
throw new Error("could not resolve ".concat(ex, " because is was not in the context"));
}
else if (ifNotFound === 'null') {
return Expression.NULL;
}
else if (ifNotFound === 'leave') {
return ex;
}
}
else if (nestDiff < nest) {
throw new Error("went too deep during resolve on: ".concat(ex));
}
}
return null;
});
};
Expression.prototype.resolved = function () {
return this.every(function (ex, index, depth, nestDiff) {
return ex instanceof RefExpression ? ex.nest <= nestDiff : null;
});
};
Expression.prototype.resolvedWithoutExternals = function () {
return this.every(function (ex, index, depth, nestDiff) {
if (ex instanceof ExternalExpression)
return false;
return ex instanceof RefExpression ? ex.nest <= nestDiff : null;
});
};
Expression.prototype.noRefs = function () {
return this.every(function (ex) {
if (ex instanceof RefExpression)
return false;
return null;
});
};
Expression.prototype.isAggregate = function () {
return false;
};
Expression.prototype.decomposeAverage = function (countEx) {
return this.substitute(function (ex) {
if (ex instanceof AverageExpression) {
return ex.decomposeAverage(countEx);
}
return null;
});
};
Expression.prototype.distribute = function () {
return this.substitute(function (ex, index) {
if (index === 0)
return null;
var distributedEx = ex.distribute();
if (distributedEx === ex)
return null;
return distributedEx;
}).simplify();
};
Expression.prototype.maxPossibleSplitValues = function () {
return this.type === 'BOOLEAN' ? 3 : Infinity;
};
Expression.prototype._initialPrepare = function (context, environment) {
return this.defineEnvironment(environment).referenceCheck(context).resolve(context).simplify();
};
Expression.prototype.simulate = function (context, options) {
if (context === void 0) { context = {}; }
if (options === void 0) { options = {}; }
failIfIntrospectNeededInDatum(context);
var readyExpression = this._initialPrepare(context, options);
if (readyExpression instanceof ExternalExpression) {
readyExpression = readyExpression.unsuppress();
}
return readyExpression._computeResolvedSimulate(options, []);
};
Expression.prototype.simulateQueryPlan = function (context, options) {
if (context === void 0) { context = {}; }
if (options === void 0) { options = {}; }
failIfIntrospectNeededInDatum(context);
var readyExpression = this._initialPrepare(c