plywood
Version:
A query planner and executor
1,235 lines (1,234 loc) • 73.5 kB
JavaScript
import { Timezone } from 'chronoshift';
import * as hasOwnProp from 'has-own-prop';
import { immutableArraysEqual, immutableLookupsEqual, NamedArray, SimpleArray, } from 'immutable-class';
import { PassThrough, Transform, Writable } from 'readable-stream';
import { AttributeInfo, Dataset, NumberRange, PlywoodValueBuilder, } from '../datatypes';
import { Ip } from '../datatypes/ip';
import { Set } from '../datatypes/set';
import { StringRange } from '../datatypes/stringRange';
import { TimeRange } from '../datatypes/timeRange';
import { iteratorFactory } from '../datatypes/valueStream';
import { $, AndExpression, ApplyExpression, ChainableExpression, ChainableUnaryExpression, Expression, ExternalExpression, FallbackExpression, FilterExpression, LimitExpression, LiteralExpression, NumberBucketExpression, OverlapExpression, r, RefExpression, SelectExpression, SortExpression, SplitExpression, SqlRefExpression, ThenExpression, TimeBucketExpression, TimeFloorExpression, TimeShiftExpression, } from '../expressions';
import { ReadableError } from '../helper/streamBasics';
import { StreamConcat } from '../helper/streamConcat';
import { nonEmptyLookup, pipeWithError, safeRange } from '../helper/utils';
var TotalContainer = (function () {
function TotalContainer(d) {
this.datum = d;
}
TotalContainer.prototype.toJS = function () {
return {
datum: Dataset.datumToJS(this.datum),
};
};
return TotalContainer;
}());
export { TotalContainer };
function makeDate(thing) {
var dt = new Date(thing);
if (isNaN(dt.valueOf()))
dt = new Date(Number(thing));
return dt;
}
function nullMap(xs, fn) {
if (!xs)
return null;
var res = [];
for (var _i = 0, xs_1 = xs; _i < xs_1.length; _i++) {
var x = xs_1[_i];
var y = fn(x);
if (y)
res.push(y);
}
return res.length ? res : null;
}
function filterToAnds(filter) {
if (filter.equals(Expression.TRUE))
return [];
if (filter instanceof AndExpression)
return filter.getExpressionList();
return [filter];
}
function filterDiff(strongerFilter, weakerFilter) {
var strongerFilterAnds = filterToAnds(strongerFilter);
var weakerFilterAnds = filterToAnds(weakerFilter);
if (weakerFilterAnds.length > strongerFilterAnds.length)
return null;
for (var i = 0; i < weakerFilterAnds.length; i++) {
if (!weakerFilterAnds[i].equals(strongerFilterAnds[i]))
return null;
}
return Expression.and(strongerFilterAnds.slice(weakerFilterAnds.length));
}
function getCommonFilter(filter1, filter2) {
var filter1Ands = filterToAnds(filter1);
var filter2Ands = filterToAnds(filter2);
var minLength = Math.min(filter1Ands.length, filter2Ands.length);
var commonExpressions = [];
for (var i = 0; i < minLength; i++) {
if (!filter1Ands[i].equals(filter2Ands[i]))
break;
commonExpressions.push(filter1Ands[i]);
}
return Expression.and(commonExpressions);
}
function mergeDerivedAttributes(derivedAttributes1, derivedAttributes2) {
var derivedAttributes = Object.create(null);
for (var k in derivedAttributes1) {
derivedAttributes[k] = derivedAttributes1[k];
}
for (var k in derivedAttributes2) {
if (hasOwnProp(derivedAttributes, k) && !derivedAttributes[k].equals(derivedAttributes2[k])) {
throw new Error("can not currently redefine conflicting ".concat(k));
}
derivedAttributes[k] = derivedAttributes2[k];
}
return derivedAttributes;
}
function getSampleValue(valueType, ex) {
switch (valueType) {
case 'NULL':
return null;
case 'BOOLEAN':
return true;
case 'NUMBER':
return 4;
case 'NUMBER_RANGE':
if (ex instanceof NumberBucketExpression) {
return new NumberRange({
start: ex.offset,
end: ex.offset + ex.size,
});
}
else {
return new NumberRange({ start: 0, end: 1 });
}
case 'TIME':
return new Date('2015-03-14T00:00:00Z');
case 'TIME_RANGE':
if (ex instanceof TimeBucketExpression) {
var timezone = ex.timezone || Timezone.UTC;
var start = ex.duration.floor(new Date('2015-03-14T00:00:00Z'), timezone);
return new TimeRange({
start: start,
end: ex.duration.shift(start, timezone, 1),
});
}
else {
return new TimeRange({
start: new Date('2015-03-14T00:00:00Z'),
end: new Date('2015-03-15T00:00:00Z'),
});
}
case 'IP':
return Ip.fromString('127.0.0.1');
case 'STRING':
if (ex instanceof RefExpression) {
return 'some_' + ex.name;
}
else {
return 'something';
}
case 'SET/STRING':
if (ex instanceof RefExpression) {
return Set.fromJS([ex.name + '1']);
}
else {
return Set.fromJS(['something']);
}
case 'STRING_RANGE':
if (ex instanceof RefExpression) {
return StringRange.fromJS({ start: 'some_' + ex.name, end: null });
}
else {
return StringRange.fromJS({ start: 'something', end: null });
}
default:
if (ex instanceof SqlRefExpression) {
return null;
}
throw new Error('unsupported simulation on: ' + valueType);
}
}
function immutableAdd(obj, key, value) {
var newObj = Object.create(null);
for (var k in obj)
newObj[k] = obj[k];
newObj[key] = value;
return newObj;
}
function findApplyByExpression(applies, expression) {
for (var _i = 0, applies_1 = applies; _i < applies_1.length; _i++) {
var apply = applies_1[_i];
if (apply.expression.equals(expression))
return apply;
}
return null;
}
var External = (function () {
function External(parameters, dummy) {
if (dummy === void 0) { dummy = null; }
this.attributes = null;
this.attributeOverrides = null;
if (dummy !== dummyObject) {
throw new TypeError('can not call `new External` directly use External.fromJS instead');
}
this.engine = parameters.engine;
var version = null;
if (parameters.version) {
version = External.extractVersion(parameters.version);
if (!version)
throw new Error("invalid version ".concat(parameters.version));
}
this.version = version;
this.source = parameters.source;
this.suppress = Boolean(parameters.suppress);
this.rollup = Boolean(parameters.rollup);
if (parameters.attributes) {
this.attributes = parameters.attributes;
}
if (parameters.attributeOverrides) {
this.attributeOverrides = parameters.attributeOverrides;
}
this.derivedAttributes = parameters.derivedAttributes || {};
if (parameters.delegates) {
this.delegates = parameters.delegates;
}
this.concealBuckets = parameters.concealBuckets;
this.rawAttributes = parameters.rawAttributes || parameters.attributes || [];
this.requester = parameters.requester;
this.mode = parameters.mode || 'raw';
this.filter = parameters.filter || Expression.TRUE;
this.specialApplyTransform = parameters.specialApplyTransform;
if (this.rawAttributes.length) {
this.derivedAttributes = External.typeCheckDerivedAttributes(this.derivedAttributes, this.getRawFullType(true));
this.filter = this.filter.changeInTypeContext(this.getRawFullType());
}
switch (this.mode) {
case 'raw':
this.select = parameters.select;
this.sort = parameters.sort;
this.limit = parameters.limit;
break;
case 'value':
this.valueExpression = parameters.valueExpression;
break;
case 'total':
this.applies = parameters.applies || [];
break;
case 'split':
this.select = parameters.select;
this.dataName = parameters.dataName;
this.split = parameters.split;
if (!this.split)
throw new Error('must have split action in split mode');
this.applies = parameters.applies || [];
this.sort = parameters.sort;
this.limit = parameters.limit;
this.havingFilter = parameters.havingFilter || Expression.TRUE;
break;
}
}
External.isExternal = function (candidate) {
return candidate instanceof External;
};
External.extractVersion = function (v) {
if (!v)
return null;
var m = v.match(/^\d+\.\d+\.\d+(?:-[\w\-]+)?/);
return m ? m[0] : null;
};
External.versionLessThan = function (va, vb) {
var pa = va.split('-')[0].split('.');
var pb = vb.split('-')[0].split('.');
if (pa[0] !== pb[0])
return Number(pa[0]) < Number(pb[0]);
if (pa[1] !== pb[1])
return Number(pa[1]) < Number(pb[1]);
return Number(pa[2]) < Number(pb[2]);
};
External.deduplicateExternals = function (externals) {
if (externals.length < 2)
return externals;
var uniqueExternals = [externals[0]];
function addToUniqueExternals(external) {
for (var _i = 0, uniqueExternals_1 = uniqueExternals; _i < uniqueExternals_1.length; _i++) {
var uniqueExternal = uniqueExternals_1[_i];
if (uniqueExternal.equalBaseAndFilter(external))
return;
}
uniqueExternals.push(external);
}
for (var i = 1; i < externals.length; i++)
addToUniqueExternals(externals[i]);
return uniqueExternals;
};
External.addExtraFilter = function (ex, extraFilter) {
if (extraFilter.equals(Expression.TRUE))
return ex;
return ex.substitute(function (ex) {
if (ex instanceof RefExpression &&
ex.type === 'DATASET' &&
ex.name === External.SEGMENT_NAME) {
return ex.filter(extraFilter);
}
return null;
});
};
External.makeZeroDatum = function (applies) {
var newDatum = Object.create(null);
for (var _i = 0, applies_2 = applies; _i < applies_2.length; _i++) {
var apply = applies_2[_i];
var applyName = apply.name;
if (applyName[0] === '_')
continue;
newDatum[applyName] = 0;
}
return newDatum;
};
External.normalizeAndAddApply = function (attributesAndApplies, apply) {
var attributes = attributesAndApplies.attributes, applies = attributesAndApplies.applies;
var expressions = Object.create(null);
for (var _i = 0, applies_3 = applies; _i < applies_3.length; _i++) {
var existingApply = applies_3[_i];
expressions[existingApply.name] = existingApply.expression;
}
apply = apply.changeExpression(apply.expression.resolveWithExpressions(expressions, 'leave').simplify());
return {
attributes: NamedArray.overrideByName(attributes, new AttributeInfo({ name: apply.name, type: apply.expression.type })),
applies: NamedArray.overrideByName(applies, apply),
};
};
External.segregationAggregateApplies = function (applies) {
var aggregateApplies = [];
var postAggregateApplies = [];
var nameIndex = 0;
var appliesToSegregate = [];
for (var _i = 0, applies_4 = applies; _i < applies_4.length; _i++) {
var apply = applies_4[_i];
var applyExpression = apply.expression;
if (applyExpression.isAggregate()) {
aggregateApplies.push(apply);
}
else {
appliesToSegregate.push(apply);
}
}
for (var _a = 0, appliesToSegregate_1 = appliesToSegregate; _a < appliesToSegregate_1.length; _a++) {
var apply = appliesToSegregate_1[_a];
var newExpression = apply.expression.substitute(function (ex) {
if (ex.isAggregate()) {
var existingApply = findApplyByExpression(aggregateApplies, ex);
if (existingApply) {
return $(existingApply.name, ex.type);
}
else {
var name_1 = '!T_' + nameIndex++;
aggregateApplies.push(Expression._.apply(name_1, ex));
return $(name_1, ex.type);
}
}
return null;
});
postAggregateApplies.push(apply.changeExpression(newExpression));
}
return {
aggregateApplies: aggregateApplies,
postAggregateApplies: postAggregateApplies,
};
};
External.getCommonFilterFromExternals = function (externals) {
if (!externals.length)
throw new Error('must have externals');
var commonFilter = externals[0].filter;
for (var i = 1; i < externals.length; i++) {
commonFilter = getCommonFilter(commonFilter, externals[i].filter);
}
return commonFilter;
};
External.getMergedDerivedAttributesFromExternals = function (externals) {
if (!externals.length)
throw new Error('must have externals');
var derivedAttributes = externals[0].derivedAttributes;
for (var i = 1; i < externals.length; i++) {
derivedAttributes = mergeDerivedAttributes(derivedAttributes, externals[i].derivedAttributes);
}
return derivedAttributes;
};
External.getIntelligentInflater = function (expression, label) {
if (expression instanceof NumberBucketExpression) {
return External.numberRangeInflaterFactory(label, expression.size);
}
else if (expression instanceof TimeBucketExpression) {
return External.timeRangeInflaterFactory(label, expression.duration, expression.timezone);
}
else {
return External.getSimpleInflater(expression.type, label);
}
};
External.getSimpleInflater = function (type, label) {
switch (type) {
case 'BOOLEAN':
return External.booleanInflaterFactory(label);
case 'NULL':
return External.nullInflaterFactory(label);
case 'NUMBER':
return External.numberInflaterFactory(label);
case 'STRING':
return External.stringInflaterFactory(label);
case 'TIME':
return External.timeInflaterFactory(label);
case 'IP':
return External.ipInflaterFactory(label);
default:
return null;
}
};
External.booleanInflaterFactory = function (label) {
return function (d) {
if (typeof d[label] === 'undefined') {
d[label] = null;
return;
}
var v = '' + d[label];
switch (v) {
case 'null':
d[label] = null;
break;
case '1':
case 'true':
d[label] = true;
break;
default:
d[label] = false;
break;
}
};
};
External.timeRangeInflaterFactory = function (label, duration, timezone) {
return function (d) {
var v = d[label];
if ('' + v === 'null') {
d[label] = null;
return;
}
var start = makeDate(v);
d[label] = new TimeRange({ start: start, end: duration.shift(start, timezone) });
};
};
External.nullInflaterFactory = function (label) {
return function (d) {
var v = d[label];
if ('' + v === 'null' || typeof v === 'undefined') {
d[label] = null;
}
};
};
External.numberRangeInflaterFactory = function (label, rangeSize) {
return function (d) {
var v = d[label];
if ('' + v === 'null') {
d[label] = null;
return;
}
var start = Number(v);
d[label] = new NumberRange(safeRange(start, rangeSize));
};
};
External.numberInflaterFactory = function (label) {
return function (d) {
var v = d[label];
if ('' + v === 'null') {
d[label] = null;
return;
}
v = Number(v);
d[label] = isNaN(v) ? null : v;
};
};
External.stringInflaterFactory = function (label) {
return function (d) {
var v = d[label];
if (typeof v === 'undefined') {
d[label] = null;
}
};
};
External.timeInflaterFactory = function (label) {
return function (d) {
var v = d[label];
if ('' + v === 'null' || typeof v === 'undefined') {
d[label] = null;
return;
}
d[label] = makeDate(v);
};
};
External.ipInflaterFactory = function (label) {
return function (d) {
var v = d[label];
if ('' + v === 'null' || typeof v === 'undefined') {
d[label] = null;
return;
}
d[label] = Ip.fromString(v);
};
};
External.setStringInflaterFactory = function (label) {
return function (d) {
var v = d[label];
if ('' + v === 'null') {
d[label] = null;
return;
}
if (typeof v === 'string')
v = [v];
d[label] = Set.fromJS({
setType: 'STRING',
elements: v,
});
};
};
External.setCardinalityInflaterFactory = function (label) {
return function (d) {
var v = d[label];
d[label] = Array.isArray(v) ? v.length : 1;
};
};
External.typeCheckDerivedAttributes = function (derivedAttributes, typeContext) {
var changed = false;
var newDerivedAttributes = {};
for (var k in derivedAttributes) {
var ex = derivedAttributes[k];
var newEx = ex.changeInTypeContext(typeContext);
if (ex !== newEx)
changed = true;
newDerivedAttributes[k] = newEx;
}
return changed ? newDerivedAttributes : derivedAttributes;
};
External.valuePostTransformFactory = function () {
var valueSeen = false;
return new Transform({
objectMode: true,
transform: function (d, encoding, callback) {
valueSeen = true;
callback(null, { type: 'value', value: d[External.VALUE_NAME] });
},
flush: function (callback) {
callback(null, valueSeen ? null : { type: 'value', value: 0 });
},
});
};
External.inflateArrays = function (d, attributes) {
for (var _i = 0, attributes_1 = attributes; _i < attributes_1.length; _i++) {
var attribute = attributes_1[_i];
var attributeName = attribute.name;
if (Array.isArray(d[attributeName])) {
d[attributeName] = Set.fromJS(d[attributeName]);
}
}
};
External.postTransformFactory = function (inflaters, attributes, keys, zeroTotalApplies) {
var valueSeen = false;
return new Transform({
objectMode: true,
transform: function (d, encoding, callback) {
if (!valueSeen) {
this.push({
type: 'init',
attributes: attributes,
keys: keys,
});
valueSeen = true;
}
for (var _i = 0, inflaters_1 = inflaters; _i < inflaters_1.length; _i++) {
var inflater = inflaters_1[_i];
inflater(d);
}
External.inflateArrays(d, attributes);
callback(null, {
type: 'datum',
datum: d,
});
},
flush: function (callback) {
if (!valueSeen) {
this.push({
type: 'init',
attributes: attributes,
keys: null,
});
if (zeroTotalApplies) {
this.push({
type: 'datum',
datum: External.makeZeroDatum(zeroTotalApplies),
});
}
}
callback();
},
});
};
External.performQueryAndPostTransform = function (queryAndPostTransform, requester, engine, rawQueries) {
if (!requester) {
return new ReadableError('must have a requester to make queries');
}
var query = queryAndPostTransform.query, context = queryAndPostTransform.context, postTransform = queryAndPostTransform.postTransform, next = queryAndPostTransform.next;
if (!query || !postTransform) {
return new ReadableError('no query or postTransform');
}
if (next) {
var streamNumber_1 = 0;
var meta_1 = null;
var numResults_1;
var resultStream = new StreamConcat({
objectMode: true,
next: function () {
if (streamNumber_1)
query = next(query, numResults_1, meta_1);
if (!query)
return null;
streamNumber_1++;
if (rawQueries)
rawQueries.push({ engine: engine, query: query });
var stream = requester({ query: query, context: context });
meta_1 = null;
stream.on('meta', function (m) { return (meta_1 = m); });
numResults_1 = 0;
stream.on('data', function () { return numResults_1++; });
return stream;
},
});
return pipeWithError(resultStream, postTransform);
}
else {
if (rawQueries)
rawQueries.push({ engine: engine, query: query });
return pipeWithError(requester({ query: query, context: context }), postTransform);
}
};
External.buildValueFromStream = function (stream) {
return new Promise(function (resolve, reject) {
var pvb = new PlywoodValueBuilder();
var target = new Writable({
objectMode: true,
write: function (chunk, encoding, callback) {
pvb.processBit(chunk);
callback(null);
},
}).on('finish', function () {
resolve(pvb.getValue());
});
stream.pipe(target);
stream.on('error', function (e) {
stream.unpipe(target);
reject(e);
});
});
};
External.valuePromiseToStream = function (valuePromise) {
var pt = new PassThrough({ objectMode: true });
valuePromise
.then(function (v) {
var i = iteratorFactory(v);
var bit;
while ((bit = i())) {
pt.write(bit);
}
pt.end();
})
.catch(function (e) {
pt.emit('error', e);
});
return pt;
};
External.jsToValue = function (parameters, requester) {
var value = {
engine: parameters.engine,
version: parameters.version,
source: parameters.source,
suppress: true,
rollup: parameters.rollup,
concealBuckets: Boolean(parameters.concealBuckets),
requester: requester,
};
if (parameters.attributes) {
value.attributes = AttributeInfo.fromJSs(parameters.attributes);
}
if (parameters.attributeOverrides) {
value.attributeOverrides = AttributeInfo.fromJSs(parameters.attributeOverrides);
}
if (parameters.derivedAttributes) {
value.derivedAttributes = Expression.expressionLookupFromJS(parameters.derivedAttributes);
}
value.filter = parameters.filter ? Expression.fromJS(parameters.filter) : Expression.TRUE;
return value;
};
External.register = function (ex) {
var engine = ex.engine.replace(/^\w/, function (s) { return s.toLowerCase(); });
External.classMap[engine] = ex;
};
External.getConstructorFor = function (engine) {
var ClassFn = External.classMap[engine];
if (!ClassFn)
throw new Error("unsupported engine '".concat(engine, "'"));
return ClassFn;
};
External.uniteValueExternalsIntoTotal = function (keyExternals) {
if (keyExternals.length === 0)
return null;
var applies = [];
var baseExternal = null;
for (var _i = 0, keyExternals_1 = keyExternals; _i < keyExternals_1.length; _i++) {
var keyExternal = keyExternals_1[_i];
var key = keyExternal.key;
var external_1 = keyExternal.external;
if (!baseExternal)
baseExternal = external_1;
applies.push(Expression._.apply(key, new ExternalExpression({ external: external_1 })));
}
return keyExternals[0].external.getBase().makeTotal(applies);
};
External.fromJS = function (parameters, requester) {
if (requester === void 0) { requester = null; }
if (!hasOwnProp(parameters, 'engine')) {
throw new Error('external `engine` must be defined');
}
var engine = parameters.engine;
if (typeof engine !== 'string')
throw new Error('engine must be a string');
var ClassFn = External.getConstructorFor(engine);
if (!requester && hasOwnProp(parameters, 'requester')) {
console.warn("'requester' parameter should be passed as context (2nd argument)");
requester = parameters.requester;
}
if (parameters.source == null) {
parameters.source =
parameters.dataSource != null
? parameters.dataSource
: parameters.table;
}
return ClassFn.fromJS(parameters, requester);
};
External.fromValue = function (parameters) {
var engine = parameters.engine;
var ClassFn = External.getConstructorFor(engine);
return new ClassFn(parameters);
};
External.prototype._ensureEngine = function (engine) {
if (!this.engine) {
this.engine = engine;
return;
}
if (this.engine !== engine) {
throw new TypeError("incorrect engine '".concat(this.engine, "' (needs to be: '").concat(engine, "')"));
}
};
External.prototype._ensureMinVersion = function (minVersion) {
if (this.version && External.versionLessThan(this.version, minVersion)) {
throw new Error("only ".concat(this.engine, " versions >= ").concat(minVersion, " are supported"));
}
};
External.prototype.valueOf = function () {
var value = {
engine: this.engine,
version: this.version,
source: this.source,
rollup: this.rollup,
mode: this.mode,
};
if (this.suppress)
value.suppress = this.suppress;
if (this.attributes)
value.attributes = this.attributes;
if (this.attributeOverrides)
value.attributeOverrides = this.attributeOverrides;
if (nonEmptyLookup(this.derivedAttributes))
value.derivedAttributes = this.derivedAttributes;
if (this.delegates)
value.delegates = this.delegates;
value.concealBuckets = this.concealBuckets;
if (this.mode !== 'raw' && this.rawAttributes) {
value.rawAttributes = this.rawAttributes;
}
if (this.requester) {
value.requester = this.requester;
}
if (this.dataName) {
value.dataName = this.dataName;
}
value.filter = this.filter;
if (this.valueExpression) {
value.valueExpression = this.valueExpression;
}
if (this.select) {
value.select = this.select;
}
if (this.split) {
value.split = this.split;
}
if (this.applies) {
value.applies = this.applies;
}
if (this.sort) {
value.sort = this.sort;
}
if (this.limit) {
value.limit = this.limit;
}
if (this.havingFilter) {
value.havingFilter = this.havingFilter;
}
if (this.specialApplyTransform) {
value.specialApplyTransform = this.specialApplyTransform;
}
return value;
};
External.prototype.toJS = function () {
var js = {
engine: this.engine,
source: this.source,
};
if (this.version)
js.version = this.version;
if (this.rollup)
js.rollup = true;
if (this.attributes)
js.attributes = AttributeInfo.toJSs(this.attributes);
if (this.attributeOverrides)
js.attributeOverrides = AttributeInfo.toJSs(this.attributeOverrides);
if (nonEmptyLookup(this.derivedAttributes))
js.derivedAttributes = Expression.expressionLookupToJS(this.derivedAttributes);
if (this.concealBuckets)
js.concealBuckets = true;
if (this.mode !== 'raw' && this.rawAttributes)
js.rawAttributes = AttributeInfo.toJSs(this.rawAttributes);
if (!this.filter.equals(Expression.TRUE)) {
js.filter = this.filter.toJS();
}
return js;
};
External.prototype.toJSON = function () {
return this.toJS();
};
External.prototype.toString = function () {
var mode = this.mode;
switch (mode) {
case 'raw':
return "ExternalRaw(".concat(this.filter, ")");
case 'value':
return "ExternalValue(".concat(this.valueExpression, ")");
case 'total':
return "ExternalTotal(".concat(this.applies.length, ")");
case 'split':
return "ExternalSplit(".concat(this.split, ", ").concat(this.applies.length, ")");
default:
throw new Error("unknown mode: ".concat(mode));
}
};
External.prototype.equals = function (other) {
return (this.equalBaseAndFilter(other) &&
immutableLookupsEqual(this.derivedAttributes, other.derivedAttributes) &&
immutableArraysEqual(this.attributes, other.attributes) &&
immutableArraysEqual(this.delegates, other.delegates) &&
this.concealBuckets === other.concealBuckets &&
Boolean(this.requester) === Boolean(other.requester));
};
External.prototype.equalBaseAndFilter = function (other) {
return this.equalBase(other) && this.filter.equals(other.filter);
};
External.prototype.equalBase = function (other) {
return (other instanceof External &&
this.engine === other.engine &&
String(this.source) === String(other.source) &&
this.version === other.version &&
this.rollup === other.rollup &&
this.mode === other.mode);
};
External.prototype.changeVersion = function (version) {
var value = this.valueOf();
value.version = version;
return External.fromValue(value);
};
External.prototype.attachRequester = function (requester) {
var value = this.valueOf();
value.requester = requester;
return External.fromValue(value);
};
External.prototype.versionBefore = function (neededVersion) {
var version = this.version;
return version && External.versionLessThan(version, neededVersion);
};
External.prototype.capability = function (_cap) {
return false;
};
External.prototype.getAttributesInfo = function (attributeName) {
var attributeInfo = NamedArray.get(this.rawAttributes, attributeName);
if (!attributeInfo)
throw new Error("could not get attribute info for '".concat(attributeName, "'"));
return attributeInfo;
};
External.prototype.updateAttribute = function (newAttribute) {
if (!this.attributes)
return this;
var value = this.valueOf();
value.attributes = AttributeInfo.override(value.attributes, [newAttribute]);
return External.fromValue(value);
};
External.prototype.show = function () {
var value = this.valueOf();
value.suppress = false;
return External.fromValue(value);
};
External.prototype.hasAttribute = function (name) {
var _a = this, attributes = _a.attributes, rawAttributes = _a.rawAttributes, derivedAttributes = _a.derivedAttributes;
if (SimpleArray.find(rawAttributes || attributes, function (a) { return a.name === name; }))
return true;
return hasOwnProp(derivedAttributes, name);
};
External.prototype.expressionDefined = function (ex) {
return ex.definedInTypeContext(this.getFullType());
};
External.prototype.bucketsConcealed = function (ex) {
var _this = this;
return ex.every(function (ex, index, depth, nestDiff) {
if (nestDiff)
return true;
if (ex instanceof RefExpression) {
var refAttributeInfo = _this.getAttributesInfo(ex.name);
if (refAttributeInfo && refAttributeInfo.maker instanceof TimeFloorExpression) {
return refAttributeInfo.maker.alignsWith(ex);
}
}
else if (ex instanceof ChainableExpression) {
var refExpression = ex.operand;
if (refExpression instanceof RefExpression) {
var refAttributeInfo = _this.getAttributesInfo(refExpression.name);
if (refAttributeInfo && refAttributeInfo.maker instanceof TimeFloorExpression) {
return refAttributeInfo.maker.alignsWith(ex);
}
}
}
return null;
});
};
External.prototype.changeSpecialApplyTransform = function (specialApplyTransform) {
var value = this.valueOf();
value.specialApplyTransform = specialApplyTransform;
return External.fromValue(value);
};
External.prototype.addDelegate = function (delegate) {
var value = this.valueOf();
if (!value.delegates)
value.delegates = [];
value.delegates = value.delegates.concat(delegate);
return External.fromValue(value);
};
External.prototype.getBase = function () {
var value = this.valueOf();
value.suppress = true;
value.mode = 'raw';
value.dataName = null;
if (this.mode !== 'raw')
value.attributes = value.rawAttributes;
value.rawAttributes = null;
value.filter = null;
value.applies = [];
value.split = null;
value.sort = null;
value.limit = null;
value.delegates = nullMap(value.delegates, function (e) { return e.getBase(); });
return External.fromValue(value);
};
External.prototype.getRaw = function () {
if (this.mode === 'raw')
return this;
var value = this.valueOf();
value.suppress = true;
value.mode = 'raw';
value.dataName = null;
value.attributes = value.rawAttributes;
value.rawAttributes = null;
value.applies = [];
value.split = null;
value.sort = null;
value.limit = null;
value.specialApplyTransform = null;
value.delegates = nullMap(value.delegates, function (e) { return e.getRaw(); });
return External.fromValue(value);
};
External.prototype.makeTotal = function (applies) {
if (this.mode !== 'raw')
return null;
if (!applies.length)
throw new Error('must have applies');
var externals = [];
for (var _i = 0, applies_5 = applies; _i < applies_5.length; _i++) {
var apply = applies_5[_i];
var applyExpression = apply.expression;
if (applyExpression instanceof ExternalExpression) {
externals.push(applyExpression.external);
}
}
var commonFilter = External.getCommonFilterFromExternals(externals);
var value = this.valueOf();
value.mode = 'total';
value.suppress = false;
value.rawAttributes = value.attributes;
value.derivedAttributes = External.getMergedDerivedAttributesFromExternals(externals);
value.filter = commonFilter;
value.attributes = [];
value.applies = [];
value.delegates = nullMap(value.delegates, function (e) { return e.makeTotal(applies); });
var totalExternal = External.fromValue(value);
for (var _a = 0, applies_6 = applies; _a < applies_6.length; _a++) {
var apply = applies_6[_a];
totalExternal = totalExternal._addApplyExpression(apply);
if (!totalExternal)
return null;
}
return totalExternal;
};
External.prototype.getHybridTimeExpressionDecomposition = function (possibleHybrid) {
if (possibleHybrid instanceof FallbackExpression) {
var thenExpression = possibleHybrid.operand;
var timeShiftExpression = possibleHybrid.expression;
if (thenExpression instanceof ThenExpression &&
timeShiftExpression instanceof TimeShiftExpression) {
var mainOverlap = thenExpression.operand;
var timeRef = timeShiftExpression.operand;
if (mainOverlap instanceof OverlapExpression && this.isTimeRef(timeRef)) {
var mainOverlapLiteral = mainOverlap.expression;
if (mainOverlapLiteral instanceof LiteralExpression) {
return {
timeRef: timeRef,
mainRangeLiteral: mainOverlapLiteral,
timeShift: timeShiftExpression,
};
}
}
}
}
return undefined;
};
External.prototype._addFilterForNext = function (ex) {
var _this = this;
var hybridTimeBreakdown;
var curTimeRange;
var extractAndRest = ex.extractFromAnd(function (possibleHybrid) {
if (possibleHybrid instanceof OverlapExpression) {
var operand = possibleHybrid.operand, expression = possibleHybrid.expression;
var possibleHybridTimeBreakdown = _this.getHybridTimeExpressionDecomposition(operand);
if (possibleHybridTimeBreakdown && expression instanceof LiteralExpression) {
var literalValue = expression.getLiteralValue();
if (literalValue instanceof TimeRange) {
hybridTimeBreakdown = possibleHybridTimeBreakdown;
curTimeRange = literalValue;
return true;
}
}
}
return false;
});
if (hybridTimeBreakdown) {
var timeRef = hybridTimeBreakdown.timeRef, timeShift = hybridTimeBreakdown.timeShift, mainRangeLiteral = hybridTimeBreakdown.mainRangeLiteral;
var prevTimeRange = curTimeRange.shift(timeShift.duration, timeShift.getTimezone() || Timezone.UTC, -timeShift.step);
var newTimeFilter = timeRef.overlap(new Set({
setType: 'TIME_RANGE',
elements: [curTimeRange, prevTimeRange],
}));
return this._addFilterExpression(Expression._.filter(Expression.and([newTimeFilter, extractAndRest.rest]))).changeSpecialApplyTransform({
mainRangeLiteral: mainRangeLiteral,
curTimeRange: curTimeRange,
prevTimeRange: prevTimeRange,
});
}
return this._addFilterExpression(Expression._.filter(ex));
};
External.prototype.addExpression = function (ex) {
if (ex instanceof FilterExpression) {
return this._addFilterExpression(ex);
}
if (ex instanceof SelectExpression) {
return this._addSelectExpression(ex);
}
if (ex instanceof SplitExpression) {
return this._addSplitExpression(ex);
}
if (ex instanceof ApplyExpression) {
return this._addApplyExpression(ex);
}
if (ex instanceof SortExpression) {
return this._addSortExpression(ex);
}
if (ex instanceof LimitExpression) {
return this._addLimitExpression(ex);
}
if (ex.isAggregate()) {
return this._addAggregateExpression(ex);
}
return this._addPostAggregateExpression(ex);
};
External.prototype._addFilterExpression = function (filter) {
var expression = filter.expression;
if (!expression.resolvedWithoutExternals())
return null;
if (!this.expressionDefined(expression))
return null;
var value = this.valueOf();
switch (this.mode) {
case 'raw':
if (this.concealBuckets && !this.bucketsConcealed(expression))
return null;
if (!this.canHandleFilter(filter))
return null;
if (value.filter.equals(Expression.TRUE)) {
value.filter = expression;
}
else {
value.filter = value.filter.and(expression);
}
break;
case 'split':
if (this.limit)
return null;
value.havingFilter = value.havingFilter.and(expression).simplify();
break;
default:
return null;
}
value.delegates = nullMap(value.delegates, function (e) { return e._addFilterExpression(filter); });
return External.fromValue(value);
};
External.prototype._addSelectExpression = function (selectExpression) {
var mode = this.mode;
if (mode !== 'raw' && mode !== 'split')
return null;
var datasetType = this.getFullType().datasetType;
var attributes = selectExpression.attributes;
for (var _i = 0, attributes_2 = attributes; _i < attributes_2.length; _i++) {
var attribute = attributes_2[_i];
if (!datasetType[attribute])
return null;
}
var value = this.valueOf();
value.suppress = false;
value.select = selectExpression;
value.delegates = nullMap(value.delegates, function (e) { return e._addSelectExpression(selectExpression); });
if (mode === 'split') {
value.applies = value.applies.filter(function (apply) { return attributes.indexOf(apply.name) !== -1; });
value.attributes = value.attributes.filter(function (attribute) { return attributes.indexOf(attribute.name) !== -1; });
}
return External.fromValue(value);
};
External.prototype._addSplitExpression = function (split) {
if (this.mode !== 'raw')
return null;
var splitKeys = split.keys;
for (var _i = 0, splitKeys_1 = splitKeys; _i < splitKeys_1.length; _i++) {
var splitKey = splitKeys_1[_i];
var splitExpression = split.splits[splitKey];
if (!this.expressionDefined(splitExpression))
return null;
if (this.concealBuckets && !this.bucketsConcealed(splitExpression))
return null;
}
var value = this.valueOf();
value.suppress = false;
value.mode = 'split';
value.dataName = split.dataName;
value.split = split;
value.rawAttributes = value.attributes;
value.attributes = split.mapSplits(function (name, expression) { return new AttributeInfo({ name: name, type: Set.unwrapSetType(expression.type) }); });
value.delegates = nullMap(value.delegates, function (e) { return e._addSplitExpression(split); });
return External.fromValue(value);
};
External.prototype._addApplyExpression = function (apply) {
var _this = this;
var expression = apply.expression;
if (expression.type === 'DATASET')
return null;
if (!expression.resolved())
return null;
if (!this.expressionDefined(expression))
return null;
var value;
if (this.mode === 'raw') {
value = this.valueOf();
value.derivedAttributes = immutableAdd(value.derivedAttributes, apply.name, apply.expression);
}
else {
if (this.specialApplyTransform) {
var _a = this.specialApplyTransform, mainRangeLiteral_1 = _a.mainRangeLiteral, curTimeRange_1 = _a.curTimeRange, prevTimeRange_1 = _a.prevTimeRange;
apply = apply.changeExpression(apply.expression
.substitute(function (ex) {
if (ex instanceof OverlapExpression &&
_this.isTimeRef(ex.operand) &&
ex.expression instanceof LiteralExpression) {
return ex.changeExpression(r(mainRangeLiteral_1.equals(ex.expression) ? curTimeRange_1 : prevTimeRange_1));
}
return null;
})
.simplify());
}
if (this.split && this.split.hasKey(apply.name))
return null;
var applyExpression = apply.expression;
if (applyExpression instanceof ExternalExpression) {
apply = apply.changeExpression(applyExpression.external.valueExpressionWithinFilter(this.filter));
}
value = this.valueOf();
var added = External.normalizeAndAddApply(value, apply);
value.applies = added.applies;
value.attributes = added.attributes;
}
value.delegates = nullMap(value.delegates, function (e) { return e._addApplyExpression(apply); });
return External.fromValue(value);
};
External.prototype._addSortExpression = function (sort) {
if (this.limit)
return null;
if (!this.canHandleSort(sort))
return null;
var value = this.valueOf();
value.sort = sort;
value.delegates = nullMap(value.delegates, function (e) { return e._addSortExpression(sort); });
return External.fromValue(value);
};
External.prototype._addLimitExpression = function (limit) {
var value = this.valueOf();
value.suppress = false;
if (!value.limit || limit.value < value.limit.value) {
value.limit = limit;
}
value.delegates = nullMap(value.delegates, function (e) { return e._addLimitExpression(limit); });
return External.fromValue(value);
};
External.prototype._addAggregateExpression = function (aggregate) {
if (this.mode === 'split') {
if (aggregate.type !== 'NUMBER')
return null;
var valueExpression_1 = $(External.SEGMENT_NAME, 'DATASET').performAction(this.split.getAction());
this.applies.forEach(function (apply) {
valueExpression_1 = valueExpression_1.performAction(apply.getAction());
});
valueExpression_1 = valueExpression_1.performAction(aggregate);
var value = this.valueOf();
value.mode = 'value';
value.suppress = false;
value.valueExpression = valueExpression_1;
value.attributes = null;
value.delegates = nullMap(value.delegates, function (e) { return e._addAggregateExpression(aggregate); });
return External.fromValue(value);
}
if (this.mode !== 'raw' || this.limit)
return null;
if (aggregate instanceof ChainableExpression) {
if (aggregate instanceof ChainableUnaryExpression) {
if (!this.expressionDefined(aggregate.expression))
return null;
}
var value = this.valueOf();
value.mode = 'value';
value.suppress = false;