UNPKG

vega-parser

Version:

Parse Vega specifications to runtime dataflows.

146 lines (119 loc) 3.64 kB
import {Aggregate, Collect} from './transforms.js'; import {aggrField, entry, keyFieldRef, ref, sortKey} from './util.js'; import {isString} from 'vega-util'; export default function DataScope(scope, input, output, values, aggr) { this.scope = scope; // parent scope object this.input = input; // first operator in pipeline (tuple input) this.output = output; // last operator in pipeline (tuple output) this.values = values; // operator for accessing tuples (but not tuple flow) // last aggregate in transform pipeline this.aggregate = aggr; // lookup table of field indices this.index = {}; } DataScope.fromEntries = function(scope, entries) { const n = entries.length, values = entries[n-1], output = entries[n-2]; let input = entries[0], aggr = null, i = 1; if (input && input.type === 'load') { input = entries[1]; } // add operator entries to this scope, wire up pulse chain scope.add(entries[0]); for (; i<n; ++i) { entries[i].params.pulse = ref(entries[i-1]); scope.add(entries[i]); if (entries[i].type === 'aggregate') aggr = entries[i]; } return new DataScope(scope, input, output, values, aggr); }; function fieldKey(field) { return isString(field) ? field : null; } function addSortField(scope, p, sort) { const as = aggrField(sort.op, sort.field); let s; if (p.ops) { for (let i = 0, n = p.as.length; i < n; ++i) { if (p.as[i] === as) return; } } else { p.ops = ['count']; p.fields = [null]; p.as = ['count']; } if (sort.op) { p.ops.push((s=sort.op.signal) ? scope.signalRef(s) : sort.op); p.fields.push(scope.fieldRef(sort.field)); p.as.push(as); } } function cache(scope, ds, name, optype, field, counts, index) { const cache = ds[name] || (ds[name] = {}), sort = sortKey(counts); let k = fieldKey(field), v, op; if (k != null) { scope = ds.scope; k = k + (sort ? '|' + sort : ''); v = cache[k]; } if (!v) { const params = counts ? {field: keyFieldRef, pulse: ds.countsRef(scope, field, counts)} : {field: scope.fieldRef(field), pulse: ref(ds.output)}; if (sort) params.sort = scope.sortRef(counts); op = scope.add(entry(optype, undefined, params)); if (index) ds.index[field] = op; v = ref(op); if (k != null) cache[k] = v; } return v; } DataScope.prototype = { countsRef(scope, field, sort) { const ds = this, cache = ds.counts || (ds.counts = {}), k = fieldKey(field); let v, a, p; if (k != null) { scope = ds.scope; v = cache[k]; } if (!v) { p = { groupby: scope.fieldRef(field, 'key'), pulse: ref(ds.output) }; if (sort && sort.field) addSortField(scope, p, sort); a = scope.add(Aggregate(p)); v = scope.add(Collect({pulse: ref(a)})); v = {agg: a, ref: ref(v)}; if (k != null) cache[k] = v; } else if (sort && sort.field) { addSortField(scope, v.agg.params, sort); } return v.ref; }, tuplesRef() { return ref(this.values); }, extentRef(scope, field) { return cache(scope, this, 'extent', 'extent', field, false); }, domainRef(scope, field) { return cache(scope, this, 'domain', 'values', field, false); }, valuesRef(scope, field, sort) { return cache(scope, this, 'vals', 'values', field, sort || true); }, lookupRef(scope, field) { return cache(scope, this, 'lookup', 'tupleindex', field, false); }, indataRef(scope, field) { return cache(scope, this, 'indata', 'tupleindex', field, true, true); } };