@uwdata/mosaic-inputs 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mosaic-inputs.js +1655 -1295
- package/dist/mosaic-inputs.min.js +5 -5
- package/package.json +4 -4
- package/src/Menu.js +66 -21
- package/src/Search.js +31 -15
- package/src/Slider.js +91 -34
- package/src/Table.js +1 -1
package/dist/mosaic-inputs.js
CHANGED
|
@@ -4914,10 +4914,10 @@ var getDictionary = (data, index) => {
|
|
|
4914
4914
|
var getInterval = (data, index) => data.type.unit === IntervalUnit.DAY_TIME ? getIntervalDayTime(data, index) : getIntervalYearMonth(data, index);
|
|
4915
4915
|
var getIntervalDayTime = ({ values }, index) => values.subarray(2 * index, 2 * (index + 1));
|
|
4916
4916
|
var getIntervalYearMonth = ({ values }, index) => {
|
|
4917
|
-
const
|
|
4917
|
+
const interval2 = values[index];
|
|
4918
4918
|
const int32s = new Int32Array(2);
|
|
4919
|
-
int32s[0] = Math.trunc(
|
|
4920
|
-
int32s[1] = Math.trunc(
|
|
4919
|
+
int32s[0] = Math.trunc(interval2 / 12);
|
|
4920
|
+
int32s[1] = Math.trunc(interval2 % 12);
|
|
4921
4921
|
return int32s;
|
|
4922
4922
|
};
|
|
4923
4923
|
var getDurationSecond = ({ values }, index) => values[index];
|
|
@@ -11839,6 +11839,13 @@ function socketConnector(uri = "ws://localhost:3000/") {
|
|
|
11839
11839
|
get connected() {
|
|
11840
11840
|
return connected;
|
|
11841
11841
|
},
|
|
11842
|
+
/**
|
|
11843
|
+
* Query the DuckDB server.
|
|
11844
|
+
* @param {object} query
|
|
11845
|
+
* @param {'exec' | 'arrow' | 'json'} [query.type] The query type: 'exec', 'arrow', or 'json'.
|
|
11846
|
+
* @param {string} query.sql A SQL query string.
|
|
11847
|
+
* @returns the query result
|
|
11848
|
+
*/
|
|
11842
11849
|
query(query) {
|
|
11843
11850
|
return new Promise(
|
|
11844
11851
|
(resolve, reject) => enqueue(query, resolve, reject)
|
|
@@ -11909,7 +11916,7 @@ function literalToSQL(value) {
|
|
|
11909
11916
|
case "boolean":
|
|
11910
11917
|
return value ? "TRUE" : "FALSE";
|
|
11911
11918
|
case "string":
|
|
11912
|
-
return `'${value}'`;
|
|
11919
|
+
return `'${value.replace(`'`, `''`)}'`;
|
|
11913
11920
|
case "number":
|
|
11914
11921
|
return Number.isFinite(value) ? String(value) : "NULL";
|
|
11915
11922
|
default:
|
|
@@ -11992,7 +11999,7 @@ var SQLExpression = class {
|
|
|
11992
11999
|
/**
|
|
11993
12000
|
* Annotate this expression instance with additional properties.
|
|
11994
12001
|
* @param {object[]} [props] One or more objects with properties to add.
|
|
11995
|
-
* @returns
|
|
12002
|
+
* @returns This SQL expression.
|
|
11996
12003
|
*/
|
|
11997
12004
|
annotate(...props) {
|
|
11998
12005
|
return Object.assign(this, ...props);
|
|
@@ -12260,6 +12267,9 @@ var last_value = winf("LAST_VALUE");
|
|
|
12260
12267
|
var nth_value = winf("NTH_VALUE");
|
|
12261
12268
|
|
|
12262
12269
|
// ../sql/src/aggregates.js
|
|
12270
|
+
function agg(strings, ...exprs) {
|
|
12271
|
+
return sql(strings, ...exprs).annotate({ aggregate: true });
|
|
12272
|
+
}
|
|
12263
12273
|
var AggregateFunction = class _AggregateFunction extends SQLExpression {
|
|
12264
12274
|
/**
|
|
12265
12275
|
* Create a new AggregateFunction instance.
|
|
@@ -12390,6 +12400,7 @@ var entropy = aggf("ENTROPY");
|
|
|
12390
12400
|
var varPop = aggf("VAR_POP");
|
|
12391
12401
|
var stddevPop = aggf("STDDEV_POP");
|
|
12392
12402
|
var corr = aggf("CORR");
|
|
12403
|
+
var covariance = aggf("COVAR_SAMP");
|
|
12393
12404
|
var covarPop = aggf("COVAR_POP");
|
|
12394
12405
|
var regrIntercept = aggf("REGR_INTERCEPT");
|
|
12395
12406
|
var regrSlope = aggf("REGR_SLOPE");
|
|
@@ -12532,7 +12543,8 @@ var Query = class _Query {
|
|
|
12532
12543
|
}
|
|
12533
12544
|
}
|
|
12534
12545
|
}
|
|
12535
|
-
|
|
12546
|
+
const keys = new Set(list.map((x2) => x2.as));
|
|
12547
|
+
query.select = query.select.filter((x2) => !keys.has(x2.as)).concat(list.filter((x2) => x2.expr));
|
|
12536
12548
|
return this;
|
|
12537
12549
|
}
|
|
12538
12550
|
}
|
|
@@ -13005,6 +13017,7 @@ function scaleTime() {
|
|
|
13005
13017
|
};
|
|
13006
13018
|
}
|
|
13007
13019
|
var scales = {
|
|
13020
|
+
identity: scaleLinear,
|
|
13008
13021
|
linear: scaleLinear,
|
|
13009
13022
|
log: scaleLog,
|
|
13010
13023
|
symlog: scaleSymlog,
|
|
@@ -13050,6 +13063,247 @@ function fnv_mix(a) {
|
|
|
13050
13063
|
return a & 4294967295;
|
|
13051
13064
|
}
|
|
13052
13065
|
|
|
13066
|
+
// ../core/src/util/index-columns.js
|
|
13067
|
+
var NO_INDEX = { from: NaN };
|
|
13068
|
+
function indexColumns(client) {
|
|
13069
|
+
if (!client.filterIndexable) return NO_INDEX;
|
|
13070
|
+
const q = client.query();
|
|
13071
|
+
const from = getBaseTable(q);
|
|
13072
|
+
if (typeof from !== "string" || !q.groupby) return NO_INDEX;
|
|
13073
|
+
const g = new Set(q.groupby().map((c) => c.column));
|
|
13074
|
+
const aggr = [];
|
|
13075
|
+
const dims = [];
|
|
13076
|
+
const aux = {};
|
|
13077
|
+
for (const entry of q.select()) {
|
|
13078
|
+
const { as, expr: { aggregate, args } } = entry;
|
|
13079
|
+
const op = aggregate?.toUpperCase?.();
|
|
13080
|
+
switch (op) {
|
|
13081
|
+
case "COUNT":
|
|
13082
|
+
case "SUM":
|
|
13083
|
+
aggr.push({ [as]: agg`SUM("${as}")::DOUBLE` });
|
|
13084
|
+
break;
|
|
13085
|
+
case "AVG":
|
|
13086
|
+
aggr.push({ [as]: avgExpr(aux, as, args[0]) });
|
|
13087
|
+
break;
|
|
13088
|
+
case "ARG_MAX":
|
|
13089
|
+
aggr.push({ [as]: argmaxExpr(aux, as, args) });
|
|
13090
|
+
break;
|
|
13091
|
+
case "ARG_MIN":
|
|
13092
|
+
aggr.push({ [as]: argminExpr(aux, as, args) });
|
|
13093
|
+
break;
|
|
13094
|
+
case "VARIANCE":
|
|
13095
|
+
case "VAR_SAMP":
|
|
13096
|
+
aux[as] = null;
|
|
13097
|
+
aggr.push({ [as]: varianceExpr(aux, args[0], from) });
|
|
13098
|
+
break;
|
|
13099
|
+
case "VAR_POP":
|
|
13100
|
+
aux[as] = null;
|
|
13101
|
+
aggr.push({ [as]: varianceExpr(aux, args[0], from, false) });
|
|
13102
|
+
break;
|
|
13103
|
+
case "STDDEV":
|
|
13104
|
+
case "STDDEV_SAMP":
|
|
13105
|
+
aux[as] = null;
|
|
13106
|
+
aggr.push({ [as]: agg`SQRT(${varianceExpr(aux, args[0], from)})` });
|
|
13107
|
+
break;
|
|
13108
|
+
case "STDDEV_POP":
|
|
13109
|
+
aux[as] = null;
|
|
13110
|
+
aggr.push({ [as]: agg`SQRT(${varianceExpr(aux, args[0], from, false)})` });
|
|
13111
|
+
break;
|
|
13112
|
+
case "COVAR_SAMP":
|
|
13113
|
+
aux[as] = null;
|
|
13114
|
+
aggr.push({ [as]: covarianceExpr(aux, args, from) });
|
|
13115
|
+
break;
|
|
13116
|
+
case "COVAR_POP":
|
|
13117
|
+
aux[as] = null;
|
|
13118
|
+
aggr.push({ [as]: covarianceExpr(aux, args, from, false) });
|
|
13119
|
+
break;
|
|
13120
|
+
case "CORR":
|
|
13121
|
+
aux[as] = null;
|
|
13122
|
+
aggr.push({ [as]: corrExpr(aux, args, from) });
|
|
13123
|
+
break;
|
|
13124
|
+
case "REGR_COUNT":
|
|
13125
|
+
aux[as] = null;
|
|
13126
|
+
aggr.push({ [as]: agg`${regrCountExpr(aux, args)}::DOUBLE` });
|
|
13127
|
+
break;
|
|
13128
|
+
case "REGR_AVGX":
|
|
13129
|
+
aux[as] = null;
|
|
13130
|
+
aggr.push({ [as]: regrAvgXExpr(aux, args) });
|
|
13131
|
+
break;
|
|
13132
|
+
case "REGR_AVGY":
|
|
13133
|
+
aux[as] = null;
|
|
13134
|
+
aggr.push({ [as]: regrAvgYExpr(aux, args) });
|
|
13135
|
+
break;
|
|
13136
|
+
case "REGR_SYY":
|
|
13137
|
+
aux[as] = null;
|
|
13138
|
+
aggr.push({ [as]: regrVarExpr(aux, 0, args, from) });
|
|
13139
|
+
break;
|
|
13140
|
+
case "REGR_SXX":
|
|
13141
|
+
aux[as] = null;
|
|
13142
|
+
aggr.push({ [as]: regrVarExpr(aux, 1, args, from) });
|
|
13143
|
+
break;
|
|
13144
|
+
case "REGR_SXY":
|
|
13145
|
+
aux[as] = null;
|
|
13146
|
+
aggr.push({ [as]: covarianceExpr(aux, args, from, null) });
|
|
13147
|
+
break;
|
|
13148
|
+
case "REGR_SLOPE":
|
|
13149
|
+
aux[as] = null;
|
|
13150
|
+
aggr.push({ [as]: regrSlopeExpr(aux, args, from) });
|
|
13151
|
+
break;
|
|
13152
|
+
case "REGR_INTERCEPT":
|
|
13153
|
+
aux[as] = null;
|
|
13154
|
+
aggr.push({ [as]: regrInterceptExpr(aux, args, from) });
|
|
13155
|
+
break;
|
|
13156
|
+
case "REGR_R2":
|
|
13157
|
+
aux[as] = null;
|
|
13158
|
+
aggr.push({ [as]: agg`(${corrExpr(aux, args, from)}) ** 2` });
|
|
13159
|
+
break;
|
|
13160
|
+
case "MAX":
|
|
13161
|
+
case "MIN":
|
|
13162
|
+
case "BIT_AND":
|
|
13163
|
+
case "BIT_OR":
|
|
13164
|
+
case "BIT_XOR":
|
|
13165
|
+
case "BOOL_AND":
|
|
13166
|
+
case "BOOL_OR":
|
|
13167
|
+
case "PRODUCT":
|
|
13168
|
+
aggr.push({ [as]: agg`${op}("${as}")` });
|
|
13169
|
+
break;
|
|
13170
|
+
default:
|
|
13171
|
+
if (g.has(as)) dims.push(as);
|
|
13172
|
+
else return null;
|
|
13173
|
+
}
|
|
13174
|
+
}
|
|
13175
|
+
return { from, dims, aggr, aux };
|
|
13176
|
+
}
|
|
13177
|
+
function auxName(type, ...args) {
|
|
13178
|
+
const cols = args.length ? "_" + args.map(sanitize).join("_") : "";
|
|
13179
|
+
return `__${type}${cols}__`;
|
|
13180
|
+
}
|
|
13181
|
+
function sanitize(col) {
|
|
13182
|
+
return `${col}`.replaceAll('"', "").replaceAll(" ", "_");
|
|
13183
|
+
}
|
|
13184
|
+
function getBaseTable(query) {
|
|
13185
|
+
const subq = query.subqueries;
|
|
13186
|
+
if (query.select) {
|
|
13187
|
+
const from = query.from();
|
|
13188
|
+
if (!from.length) return void 0;
|
|
13189
|
+
if (subq.length === 0) return from[0].from.table;
|
|
13190
|
+
}
|
|
13191
|
+
const base = getBaseTable(subq[0]);
|
|
13192
|
+
for (let i = 1; i < subq.length; ++i) {
|
|
13193
|
+
const from = getBaseTable(subq[i]);
|
|
13194
|
+
if (from === void 0) continue;
|
|
13195
|
+
if (from !== base) return NaN;
|
|
13196
|
+
}
|
|
13197
|
+
return base;
|
|
13198
|
+
}
|
|
13199
|
+
function countExpr(aux, arg) {
|
|
13200
|
+
const n = auxName("count", arg);
|
|
13201
|
+
aux[n] = agg`COUNT(${arg})`;
|
|
13202
|
+
return agg`SUM(${n})`.annotate({ name: n });
|
|
13203
|
+
}
|
|
13204
|
+
function avgExpr(aux, as, arg) {
|
|
13205
|
+
const n = countExpr(aux, arg);
|
|
13206
|
+
return agg`(SUM("${as}" * ${n.name}) / ${n})`;
|
|
13207
|
+
}
|
|
13208
|
+
function avg2(x2, from) {
|
|
13209
|
+
return sql`(SELECT AVG(${x2}) FROM "${from}")`;
|
|
13210
|
+
}
|
|
13211
|
+
function argmaxExpr(aux, as, [, y2]) {
|
|
13212
|
+
const max2 = auxName("max", y2);
|
|
13213
|
+
aux[max2] = agg`MAX(${y2})`;
|
|
13214
|
+
return agg`ARG_MAX("${as}", ${max2})`;
|
|
13215
|
+
}
|
|
13216
|
+
function argminExpr(aux, as, [, y2]) {
|
|
13217
|
+
const min2 = auxName("min", y2);
|
|
13218
|
+
aux[min2] = agg`MIN(${y2})`;
|
|
13219
|
+
return agg`ARG_MIN("${as}", ${min2})`;
|
|
13220
|
+
}
|
|
13221
|
+
function varianceExpr(aux, x2, from, correction = true) {
|
|
13222
|
+
const n = countExpr(aux, x2);
|
|
13223
|
+
const ssq = auxName("rssq", x2);
|
|
13224
|
+
const sum2 = auxName("rsum", x2);
|
|
13225
|
+
const delta = sql`${x2} - ${avg2(x2, from)}`;
|
|
13226
|
+
aux[ssq] = agg`SUM((${delta}) ** 2)`;
|
|
13227
|
+
aux[sum2] = agg`SUM(${delta})`;
|
|
13228
|
+
const adj = correction ? ` - 1` : "";
|
|
13229
|
+
return agg`(SUM(${ssq}) - (SUM(${sum2}) ** 2 / ${n})) / (${n}${adj})`;
|
|
13230
|
+
}
|
|
13231
|
+
function covarianceExpr(aux, args, from, correction = true) {
|
|
13232
|
+
const n = regrCountExpr(aux, args);
|
|
13233
|
+
const sxy = regrSumXYExpr(aux, args, from);
|
|
13234
|
+
const sx = regrSumExpr(aux, 1, args, from);
|
|
13235
|
+
const sy = regrSumExpr(aux, 0, args, from);
|
|
13236
|
+
const adj = correction === null ? "" : correction ? ` / (${n} - 1)` : ` / ${n}`;
|
|
13237
|
+
return agg`(${sxy} - ${sx} * ${sy} / ${n})${adj}`;
|
|
13238
|
+
}
|
|
13239
|
+
function corrExpr(aux, args, from) {
|
|
13240
|
+
const n = regrCountExpr(aux, args);
|
|
13241
|
+
const sxy = regrSumXYExpr(aux, args, from);
|
|
13242
|
+
const sxx = regrSumSqExpr(aux, 1, args, from);
|
|
13243
|
+
const syy = regrSumSqExpr(aux, 0, args, from);
|
|
13244
|
+
const sx = regrSumExpr(aux, 1, args, from);
|
|
13245
|
+
const sy = regrSumExpr(aux, 0, args, from);
|
|
13246
|
+
const vx = agg`(${sxx} - (${sx} ** 2) / ${n})`;
|
|
13247
|
+
const vy = agg`(${syy} - (${sy} ** 2) / ${n})`;
|
|
13248
|
+
return agg`(${sxy} - ${sx} * ${sy} / ${n}) / SQRT(${vx} * ${vy})`;
|
|
13249
|
+
}
|
|
13250
|
+
function regrCountExpr(aux, [y2, x2]) {
|
|
13251
|
+
const n = auxName("count", y2, x2);
|
|
13252
|
+
aux[n] = agg`REGR_COUNT(${y2}, ${x2})`;
|
|
13253
|
+
return agg`SUM(${n})`.annotate({ name: n });
|
|
13254
|
+
}
|
|
13255
|
+
function regrSumExpr(aux, i, args, from) {
|
|
13256
|
+
const v = args[i];
|
|
13257
|
+
const o = args[1 - i];
|
|
13258
|
+
const sum2 = auxName("rs", v);
|
|
13259
|
+
aux[sum2] = agg`SUM(${v} - ${avg2(v, from)}) FILTER (${o} IS NOT NULL)`;
|
|
13260
|
+
return agg`SUM(${sum2})`;
|
|
13261
|
+
}
|
|
13262
|
+
function regrSumSqExpr(aux, i, args, from) {
|
|
13263
|
+
const v = args[i];
|
|
13264
|
+
const u = args[1 - i];
|
|
13265
|
+
const ssq = auxName("rss", v);
|
|
13266
|
+
aux[ssq] = agg`SUM((${v} - ${avg2(v, from)}) ** 2) FILTER (${u} IS NOT NULL)`;
|
|
13267
|
+
return agg`SUM(${ssq})`;
|
|
13268
|
+
}
|
|
13269
|
+
function regrSumXYExpr(aux, args, from) {
|
|
13270
|
+
const [y2, x2] = args;
|
|
13271
|
+
const sxy = auxName("sxy", y2, x2);
|
|
13272
|
+
aux[sxy] = agg`SUM((${x2} - ${avg2(x2, from)}) * (${y2} - ${avg2(y2, from)}))`;
|
|
13273
|
+
return agg`SUM(${sxy})`;
|
|
13274
|
+
}
|
|
13275
|
+
function regrAvgXExpr(aux, args) {
|
|
13276
|
+
const [y2, x2] = args;
|
|
13277
|
+
const n = regrCountExpr(aux, args);
|
|
13278
|
+
const a = auxName("avg", x2, y2);
|
|
13279
|
+
aux[a] = agg`REGR_AVGX(${y2}, ${x2})`;
|
|
13280
|
+
return agg`(SUM(${a} * ${n.name}) / ${n})`;
|
|
13281
|
+
}
|
|
13282
|
+
function regrAvgYExpr(aux, args) {
|
|
13283
|
+
const [y2, x2] = args;
|
|
13284
|
+
const n = regrCountExpr(aux, args);
|
|
13285
|
+
const a = auxName("avg", y2, x2);
|
|
13286
|
+
aux[a] = agg`REGR_AVGY(${y2}, ${x2})`;
|
|
13287
|
+
return agg`(SUM(${a} * ${n.name}) / ${n})`;
|
|
13288
|
+
}
|
|
13289
|
+
function regrVarExpr(aux, i, args, from) {
|
|
13290
|
+
const n = regrCountExpr(aux, args);
|
|
13291
|
+
const sum2 = regrSumExpr(aux, i, args, from);
|
|
13292
|
+
const ssq = regrSumSqExpr(aux, i, args, from);
|
|
13293
|
+
return agg`(${ssq} - (${sum2} ** 2 / ${n}))`;
|
|
13294
|
+
}
|
|
13295
|
+
function regrSlopeExpr(aux, args, from) {
|
|
13296
|
+
const cov = covarianceExpr(aux, args, from, null);
|
|
13297
|
+
const varx = regrVarExpr(aux, 1, args, from);
|
|
13298
|
+
return agg`(${cov}) / ${varx}`;
|
|
13299
|
+
}
|
|
13300
|
+
function regrInterceptExpr(aux, args, from) {
|
|
13301
|
+
const ax = regrAvgXExpr(aux, args);
|
|
13302
|
+
const ay = regrAvgYExpr(aux, args);
|
|
13303
|
+
const m = regrSlopeExpr(aux, args, from);
|
|
13304
|
+
return agg`${ay} - (${m}) * ${ax}`;
|
|
13305
|
+
}
|
|
13306
|
+
|
|
13053
13307
|
// ../core/src/DataCubeIndexer.js
|
|
13054
13308
|
var DataCubeIndexer = class {
|
|
13055
13309
|
/**
|
|
@@ -13067,42 +13321,49 @@ var DataCubeIndexer = class {
|
|
|
13067
13321
|
this.enabled = false;
|
|
13068
13322
|
this.clients = null;
|
|
13069
13323
|
this.indices = null;
|
|
13070
|
-
this.
|
|
13324
|
+
this.active = null;
|
|
13071
13325
|
}
|
|
13072
13326
|
clear() {
|
|
13073
13327
|
if (this.indices) {
|
|
13074
|
-
this.mc.cancel(Array.from(this.indices.values(), (index) => index
|
|
13328
|
+
this.mc.cancel(Array.from(this.indices.values(), (index) => index?.result));
|
|
13075
13329
|
this.indices = null;
|
|
13076
13330
|
}
|
|
13077
13331
|
}
|
|
13078
|
-
index(clients,
|
|
13332
|
+
index(clients, activeClause) {
|
|
13079
13333
|
if (this.clients !== clients) {
|
|
13080
|
-
const cols = Array.from(clients,
|
|
13334
|
+
const cols = Array.from(clients, indexColumns).filter((x2) => x2);
|
|
13081
13335
|
const from = cols[0]?.from;
|
|
13082
|
-
this.enabled = cols.every((c) => c
|
|
13336
|
+
this.enabled = cols.length && cols.every((c) => c.from === from);
|
|
13083
13337
|
this.clients = clients;
|
|
13084
|
-
this.
|
|
13338
|
+
this.active = null;
|
|
13085
13339
|
this.clear();
|
|
13086
13340
|
}
|
|
13087
13341
|
if (!this.enabled) return false;
|
|
13088
|
-
|
|
13089
|
-
const { source } =
|
|
13090
|
-
if (source && source === this.
|
|
13342
|
+
activeClause = activeClause || this.selection.active;
|
|
13343
|
+
const { source } = activeClause;
|
|
13344
|
+
if (source && source === this.active?.source) return true;
|
|
13091
13345
|
this.clear();
|
|
13092
13346
|
if (!source) return false;
|
|
13093
|
-
const
|
|
13094
|
-
if (!
|
|
13095
|
-
this.mc.logger()
|
|
13347
|
+
const active = this.active = activeColumns(activeClause);
|
|
13348
|
+
if (!active) return false;
|
|
13349
|
+
const logger = this.mc.logger();
|
|
13350
|
+
logger.warn("DATA CUBE INDEX CONSTRUCTION");
|
|
13096
13351
|
const sel = this.selection.remove(source);
|
|
13097
13352
|
const indices = this.indices = /* @__PURE__ */ new Map();
|
|
13098
13353
|
const { mc, temp } = this;
|
|
13099
13354
|
for (const client of clients) {
|
|
13100
|
-
if (sel.skip(client,
|
|
13101
|
-
|
|
13102
|
-
|
|
13355
|
+
if (sel.skip(client, activeClause)) {
|
|
13356
|
+
indices.set(client, null);
|
|
13357
|
+
continue;
|
|
13358
|
+
}
|
|
13359
|
+
const index = indexColumns(client);
|
|
13360
|
+
if (!index) {
|
|
13361
|
+
continue;
|
|
13362
|
+
}
|
|
13363
|
+
const query = client.query(sel.predicate(client)).select({ ...active.columns, ...index.aux }).groupby(Object.keys(active.columns));
|
|
13103
13364
|
const [subq] = query.subqueries;
|
|
13104
13365
|
if (subq) {
|
|
13105
|
-
const cols = Object.values(
|
|
13366
|
+
const cols = Object.values(active.columns).flatMap((c) => c.columns);
|
|
13106
13367
|
subqueryPushdown(subq, cols);
|
|
13107
13368
|
}
|
|
13108
13369
|
const order = query.orderby();
|
|
@@ -13111,36 +13372,40 @@ var DataCubeIndexer = class {
|
|
|
13111
13372
|
const id = (fnv_hash(sql2) >>> 0).toString(16);
|
|
13112
13373
|
const table2 = `cube_index_${id}`;
|
|
13113
13374
|
const result = mc.exec(create(table2, sql2, { temp }));
|
|
13375
|
+
result.catch((e) => logger.error(e));
|
|
13114
13376
|
indices.set(client, { table: table2, result, order, ...index });
|
|
13115
13377
|
}
|
|
13116
13378
|
return true;
|
|
13117
13379
|
}
|
|
13118
13380
|
async update() {
|
|
13119
|
-
const { clients, selection,
|
|
13120
|
-
const filter =
|
|
13381
|
+
const { clients, selection, active } = this;
|
|
13382
|
+
const filter = active.predicate(selection.active.predicate);
|
|
13121
13383
|
return Promise.all(
|
|
13122
13384
|
Array.from(clients).map((client) => this.updateClient(client, filter))
|
|
13123
13385
|
);
|
|
13124
13386
|
}
|
|
13125
13387
|
async updateClient(client, filter) {
|
|
13388
|
+
const { mc, indices, selection } = this;
|
|
13389
|
+
if (!indices.has(client)) {
|
|
13390
|
+
filter = selection.predicate(client);
|
|
13391
|
+
return mc.updateClient(client, client.query(filter));
|
|
13392
|
+
}
|
|
13393
|
+
;
|
|
13126
13394
|
const index = this.indices.get(client);
|
|
13127
13395
|
if (!index) return;
|
|
13128
|
-
if (!filter) {
|
|
13129
|
-
filter = this.activeView.predicate(this.selection.active.predicate);
|
|
13130
|
-
}
|
|
13131
13396
|
const { table: table2, dims, aggr, order = [] } = index;
|
|
13132
13397
|
const query = Query.select(dims, aggr).from(table2).groupby(dims).where(filter).orderby(order);
|
|
13133
|
-
return
|
|
13398
|
+
return mc.updateClient(client, query);
|
|
13134
13399
|
}
|
|
13135
13400
|
};
|
|
13136
|
-
function
|
|
13137
|
-
const { source,
|
|
13401
|
+
function activeColumns(clause) {
|
|
13402
|
+
const { source, meta } = clause;
|
|
13138
13403
|
let columns = clause.predicate?.columns;
|
|
13139
|
-
if (!
|
|
13140
|
-
const { type, scales: scales2, pixelSize = 1 } =
|
|
13404
|
+
if (!meta || !columns) return null;
|
|
13405
|
+
const { type, scales: scales2, bin, pixelSize = 1 } = meta;
|
|
13141
13406
|
let predicate;
|
|
13142
13407
|
if (type === "interval" && scales2) {
|
|
13143
|
-
const bins = scales2.map((s) => binInterval(s, pixelSize));
|
|
13408
|
+
const bins = scales2.map((s) => binInterval(s, pixelSize, bin));
|
|
13144
13409
|
if (bins.some((b) => b == null)) return null;
|
|
13145
13410
|
if (bins.length === 1) {
|
|
13146
13411
|
predicate = (p) => p ? isBetween("active0", p.range.map(bins[0])) : [];
|
|
@@ -13153,85 +13418,23 @@ function getActiveView(clause) {
|
|
|
13153
13418
|
}
|
|
13154
13419
|
} else if (type === "point") {
|
|
13155
13420
|
predicate = (x2) => x2;
|
|
13156
|
-
columns = Object.fromEntries(columns.map((col) => [col
|
|
13421
|
+
columns = Object.fromEntries(columns.map((col) => [`${col}`, asColumn(col)]));
|
|
13157
13422
|
} else {
|
|
13158
13423
|
return null;
|
|
13159
13424
|
}
|
|
13160
13425
|
return { source, columns, predicate };
|
|
13161
13426
|
}
|
|
13162
|
-
|
|
13163
|
-
|
|
13164
|
-
|
|
13165
|
-
|
|
13166
|
-
|
|
13167
|
-
|
|
13168
|
-
|
|
13169
|
-
|
|
13170
|
-
|
|
13171
|
-
}
|
|
13172
|
-
}
|
|
13173
|
-
var NO_INDEX = { from: NaN };
|
|
13174
|
-
function getIndexColumns(client) {
|
|
13175
|
-
if (!client.filterIndexable) return NO_INDEX;
|
|
13176
|
-
const q = client.query();
|
|
13177
|
-
const from = getBaseTable(q);
|
|
13178
|
-
if (!from || !q.groupby) return NO_INDEX;
|
|
13179
|
-
const g = new Set(q.groupby().map((c) => c.column));
|
|
13180
|
-
const aggr = [];
|
|
13181
|
-
const dims = [];
|
|
13182
|
-
const aux = {};
|
|
13183
|
-
let auxAs;
|
|
13184
|
-
for (const entry of q.select()) {
|
|
13185
|
-
const { as, expr: { aggregate, args } } = entry;
|
|
13186
|
-
const op = aggregate?.toUpperCase?.();
|
|
13187
|
-
switch (op) {
|
|
13188
|
-
case "COUNT":
|
|
13189
|
-
case "SUM":
|
|
13190
|
-
aggr.push({ [as]: sql`SUM("${as}")::DOUBLE` });
|
|
13191
|
-
break;
|
|
13192
|
-
case "AVG":
|
|
13193
|
-
aux[auxAs = "__count__"] = sql`COUNT(*)`;
|
|
13194
|
-
aggr.push({ [as]: sql`(SUM("${as}" * ${auxAs}) / SUM(${auxAs}))::DOUBLE` });
|
|
13195
|
-
break;
|
|
13196
|
-
case "ARG_MAX":
|
|
13197
|
-
aux[auxAs = `__max_${as}__`] = sql`MAX(${args[1]})`;
|
|
13198
|
-
aggr.push({ [as]: sql`ARG_MAX("${as}", ${auxAs})` });
|
|
13199
|
-
break;
|
|
13200
|
-
case "ARG_MIN":
|
|
13201
|
-
aux[auxAs = `__min_${as}__`] = sql`MIN(${args[1]})`;
|
|
13202
|
-
aggr.push({ [as]: sql`ARG_MIN("${as}", ${auxAs})` });
|
|
13203
|
-
break;
|
|
13204
|
-
case "MAX":
|
|
13205
|
-
case "MIN":
|
|
13206
|
-
case "BIT_AND":
|
|
13207
|
-
case "BIT_OR":
|
|
13208
|
-
case "BIT_XOR":
|
|
13209
|
-
case "BOOL_AND":
|
|
13210
|
-
case "BOOL_OR":
|
|
13211
|
-
case "PRODUCT":
|
|
13212
|
-
aggr.push({ [as]: sql`${op}("${as}")` });
|
|
13213
|
-
break;
|
|
13214
|
-
default:
|
|
13215
|
-
if (g.has(as)) dims.push(as);
|
|
13216
|
-
else return null;
|
|
13217
|
-
}
|
|
13218
|
-
}
|
|
13219
|
-
return { aggr, dims, aux, from };
|
|
13220
|
-
}
|
|
13221
|
-
function getBaseTable(query) {
|
|
13222
|
-
const subq = query.subqueries;
|
|
13223
|
-
if (query.select) {
|
|
13224
|
-
const from = query.from();
|
|
13225
|
-
if (!from.length) return void 0;
|
|
13226
|
-
if (subq.length === 0) return from[0].from.table;
|
|
13227
|
-
}
|
|
13228
|
-
const base = getBaseTable(subq[0]);
|
|
13229
|
-
for (let i = 1; i < subq.length; ++i) {
|
|
13230
|
-
const from = getBaseTable(subq[i]);
|
|
13231
|
-
if (from === void 0) continue;
|
|
13232
|
-
if (from !== base) return NaN;
|
|
13233
|
-
}
|
|
13234
|
-
return base;
|
|
13427
|
+
var BIN = { ceil: "CEIL", round: "ROUND" };
|
|
13428
|
+
function binInterval(scale, pixelSize, bin) {
|
|
13429
|
+
const { type, domain, range, apply, sqlApply } = scaleTransform(scale);
|
|
13430
|
+
if (!apply) return;
|
|
13431
|
+
const fn = BIN[`${bin}`.toLowerCase()] || "FLOOR";
|
|
13432
|
+
const lo = apply(Math.min(...domain));
|
|
13433
|
+
const hi = apply(Math.max(...domain));
|
|
13434
|
+
const a = type === "identity" ? 1 : Math.abs(range[1] - range[0]) / (hi - lo);
|
|
13435
|
+
const s = a / pixelSize === 1 ? "" : `${a / pixelSize}::DOUBLE * `;
|
|
13436
|
+
const d = lo === 0 ? "" : ` - ${lo}::DOUBLE`;
|
|
13437
|
+
return (value) => sql`${fn}(${s}(${sqlApply(value)}${d}))::INTEGER`;
|
|
13235
13438
|
}
|
|
13236
13439
|
function subqueryPushdown(query, cols) {
|
|
13237
13440
|
const memo = /* @__PURE__ */ new Set();
|
|
@@ -13246,1258 +13449,1321 @@ function subqueryPushdown(query, cols) {
|
|
|
13246
13449
|
pushdown(query);
|
|
13247
13450
|
}
|
|
13248
13451
|
|
|
13249
|
-
// ../core/src/
|
|
13250
|
-
var
|
|
13452
|
+
// ../core/src/util/AsyncDispatch.js
|
|
13453
|
+
var AsyncDispatch = class {
|
|
13251
13454
|
/**
|
|
13252
|
-
*
|
|
13253
|
-
* @param {*} selection The shared filter selection.
|
|
13254
|
-
* @param {*} index Boolean flag or options hash for data cube indexer.
|
|
13255
|
-
* Falsy values disable indexing.
|
|
13455
|
+
* Create a new asynchronous dispatcher instance.
|
|
13256
13456
|
*/
|
|
13257
|
-
constructor(
|
|
13258
|
-
this.
|
|
13259
|
-
this.selection = selection;
|
|
13260
|
-
this.clients = /* @__PURE__ */ new Set();
|
|
13261
|
-
this.indexer = index ? new DataCubeIndexer(this.mc, { ...index, selection }) : null;
|
|
13262
|
-
const { value, activate } = this.handlers = {
|
|
13263
|
-
value: () => this.update(),
|
|
13264
|
-
activate: (clause) => this.indexer?.index(this.clients, clause)
|
|
13265
|
-
};
|
|
13266
|
-
selection.addEventListener("value", value);
|
|
13267
|
-
selection.addEventListener("activate", activate);
|
|
13457
|
+
constructor() {
|
|
13458
|
+
this._callbacks = /* @__PURE__ */ new Map();
|
|
13268
13459
|
}
|
|
13269
|
-
|
|
13270
|
-
|
|
13271
|
-
|
|
13272
|
-
|
|
13460
|
+
/**
|
|
13461
|
+
* Add an event listener callback for the provided event type.
|
|
13462
|
+
* @param {string} type The event type.
|
|
13463
|
+
* @param {(value: *) => void | Promise} callback The event handler
|
|
13464
|
+
* callback function to add. If the callback has already been
|
|
13465
|
+
* added for the event type, this method has no effect.
|
|
13466
|
+
*/
|
|
13467
|
+
addEventListener(type, callback) {
|
|
13468
|
+
if (!this._callbacks.has(type)) {
|
|
13469
|
+
this._callbacks.set(type, {
|
|
13470
|
+
callbacks: /* @__PURE__ */ new Set(),
|
|
13471
|
+
pending: null,
|
|
13472
|
+
queue: new DispatchQueue()
|
|
13473
|
+
});
|
|
13474
|
+
}
|
|
13475
|
+
const entry = this._callbacks.get(type);
|
|
13476
|
+
entry.callbacks.add(callback);
|
|
13273
13477
|
}
|
|
13274
|
-
|
|
13275
|
-
|
|
13478
|
+
/**
|
|
13479
|
+
* Remove an event listener callback for the provided event type.
|
|
13480
|
+
* @param {string} type The event type.
|
|
13481
|
+
* @param {(value: *) => void | Promise} callback The event handler
|
|
13482
|
+
* callback function to remove.
|
|
13483
|
+
*/
|
|
13484
|
+
removeEventListener(type, callback) {
|
|
13485
|
+
const entry = this._callbacks.get(type);
|
|
13486
|
+
if (entry) {
|
|
13487
|
+
entry.callbacks.delete(callback);
|
|
13488
|
+
}
|
|
13276
13489
|
}
|
|
13277
|
-
|
|
13278
|
-
|
|
13279
|
-
|
|
13490
|
+
/**
|
|
13491
|
+
* Lifecycle method that returns the event value to emit.
|
|
13492
|
+
* This default implementation simply returns the input value as-is.
|
|
13493
|
+
* Subclasses may override this method to implement custom transformations
|
|
13494
|
+
* prior to emitting an event value to all listeners.
|
|
13495
|
+
* @param {string} type The event type.
|
|
13496
|
+
* @param {*} value The event value.
|
|
13497
|
+
* @returns The (possibly transformed) event value to emit.
|
|
13498
|
+
*/
|
|
13499
|
+
willEmit(type, value) {
|
|
13500
|
+
return value;
|
|
13280
13501
|
}
|
|
13281
|
-
|
|
13282
|
-
|
|
13283
|
-
|
|
13284
|
-
|
|
13285
|
-
|
|
13502
|
+
/**
|
|
13503
|
+
* Lifecycle method that returns a filter function for updating the
|
|
13504
|
+
* queue of unemitted event values prior to enqueueing a new value.
|
|
13505
|
+
* This default implementation simply returns null, indicating that
|
|
13506
|
+
* any other unemitted event values should be dropped (that is, all
|
|
13507
|
+
* queued events are filtered)
|
|
13508
|
+
* @param {string} type The event type.
|
|
13509
|
+
* @param {*} value The new event value that will be enqueued.
|
|
13510
|
+
* @returns {(value: *) => boolean|null} A dispatch queue filter
|
|
13511
|
+
* function, or null if all unemitted event values should be filtered.
|
|
13512
|
+
*/
|
|
13513
|
+
emitQueueFilter(type, value) {
|
|
13514
|
+
return null;
|
|
13286
13515
|
}
|
|
13287
13516
|
/**
|
|
13288
|
-
*
|
|
13289
|
-
*
|
|
13290
|
-
* @returns {Promise} A Promise that resolves when the update completes.
|
|
13517
|
+
* Cancel all unemitted event values for the given event type.
|
|
13518
|
+
* @param {string} type The event type.
|
|
13291
13519
|
*/
|
|
13292
|
-
|
|
13293
|
-
const
|
|
13294
|
-
|
|
13295
|
-
return hasIndex ? indexer.update() : defaultUpdate(mc, clients, selection);
|
|
13520
|
+
cancel(type) {
|
|
13521
|
+
const entry = this._callbacks.get(type);
|
|
13522
|
+
entry?.queue.clear();
|
|
13296
13523
|
}
|
|
13297
|
-
|
|
13298
|
-
|
|
13299
|
-
|
|
13300
|
-
|
|
13301
|
-
|
|
13302
|
-
|
|
13524
|
+
/**
|
|
13525
|
+
* Emit an event value to listeners for the given event type.
|
|
13526
|
+
* If a previous emit has not yet resolved, the event value
|
|
13527
|
+
* will be queued to be emitted later.
|
|
13528
|
+
* The actual event value given to listeners will be the result
|
|
13529
|
+
* of passing the input value through the emitValue() method.
|
|
13530
|
+
* @param {string} type The event type.
|
|
13531
|
+
* @param {*} value The event value.
|
|
13532
|
+
*/
|
|
13533
|
+
emit(type, value) {
|
|
13534
|
+
const entry = this._callbacks.get(type) || {};
|
|
13535
|
+
if (entry.pending) {
|
|
13536
|
+
entry.queue.enqueue(value, this.emitQueueFilter(type, value));
|
|
13537
|
+
} else {
|
|
13538
|
+
const event = this.willEmit(type, value);
|
|
13539
|
+
const { callbacks, queue } = entry;
|
|
13540
|
+
if (callbacks?.size) {
|
|
13541
|
+
const callbackValues = Array.from(callbacks, (cb) => cb(event));
|
|
13542
|
+
entry.pending = Promise.allSettled(callbackValues).then(() => {
|
|
13543
|
+
entry.pending = null;
|
|
13544
|
+
if (!queue.isEmpty()) {
|
|
13545
|
+
this.emit(type, queue.dequeue());
|
|
13546
|
+
}
|
|
13547
|
+
});
|
|
13548
|
+
}
|
|
13303
13549
|
}
|
|
13304
|
-
}));
|
|
13305
|
-
}
|
|
13306
|
-
|
|
13307
|
-
// ../core/src/util/query-result.js
|
|
13308
|
-
function queryResult() {
|
|
13309
|
-
let resolve;
|
|
13310
|
-
let reject;
|
|
13311
|
-
const p = new Promise((r, e) => {
|
|
13312
|
-
resolve = r;
|
|
13313
|
-
reject = e;
|
|
13314
|
-
});
|
|
13315
|
-
return Object.assign(p, {
|
|
13316
|
-
fulfill: (value) => (resolve(value), p),
|
|
13317
|
-
reject: (err) => (reject(err), p)
|
|
13318
|
-
});
|
|
13319
|
-
}
|
|
13320
|
-
|
|
13321
|
-
// ../core/src/QueryConsolidator.js
|
|
13322
|
-
function wait(callback) {
|
|
13323
|
-
const method = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : typeof setImmediate !== "undefined" ? setImmediate : setTimeout;
|
|
13324
|
-
return method(callback);
|
|
13325
|
-
}
|
|
13326
|
-
function consolidator(enqueue, cache, record) {
|
|
13327
|
-
let pending = [];
|
|
13328
|
-
let id = 0;
|
|
13329
|
-
function run() {
|
|
13330
|
-
const groups = entryGroups(pending, cache);
|
|
13331
|
-
pending = [];
|
|
13332
|
-
id = 0;
|
|
13333
|
-
for (const group of groups) {
|
|
13334
|
-
consolidate(group, enqueue, record);
|
|
13335
|
-
processResults(group, cache);
|
|
13336
|
-
}
|
|
13337
|
-
}
|
|
13338
|
-
return {
|
|
13339
|
-
add(entry, priority) {
|
|
13340
|
-
if (entry.request.type === "arrow") {
|
|
13341
|
-
id = id || wait(() => run());
|
|
13342
|
-
pending.push({ entry, priority, index: pending.length });
|
|
13343
|
-
} else {
|
|
13344
|
-
enqueue(entry, priority);
|
|
13345
|
-
}
|
|
13346
|
-
}
|
|
13347
|
-
};
|
|
13348
|
-
}
|
|
13349
|
-
function entryGroups(entries, cache) {
|
|
13350
|
-
const groups = [];
|
|
13351
|
-
const groupMap = /* @__PURE__ */ new Map();
|
|
13352
|
-
for (const query of entries) {
|
|
13353
|
-
const { entry: { request } } = query;
|
|
13354
|
-
const key = consolidationKey(request.query, cache);
|
|
13355
|
-
if (!groupMap.has(key)) {
|
|
13356
|
-
const list = [];
|
|
13357
|
-
groups.push(list);
|
|
13358
|
-
groupMap.set(key, list);
|
|
13359
|
-
}
|
|
13360
|
-
groupMap.get(key).push(query);
|
|
13361
13550
|
}
|
|
13362
|
-
|
|
13363
|
-
|
|
13364
|
-
|
|
13365
|
-
|
|
13366
|
-
|
|
13367
|
-
|
|
13368
|
-
|
|
13369
|
-
query.orderby().length || query.where().length || // @ts-ignore
|
|
13370
|
-
query.qualify().length || query.having().length
|
|
13371
|
-
) {
|
|
13372
|
-
return sql2;
|
|
13373
|
-
}
|
|
13374
|
-
const q = query.clone().$select("*");
|
|
13375
|
-
const groupby = query.groupby();
|
|
13376
|
-
if (groupby.length) {
|
|
13377
|
-
const map = {};
|
|
13378
|
-
query.select().forEach(({ as, expr }) => map[as] = expr);
|
|
13379
|
-
q.$groupby(groupby.map((e) => e instanceof Ref && map[e.column] || e));
|
|
13380
|
-
}
|
|
13381
|
-
return `${q}`;
|
|
13382
|
-
} else {
|
|
13383
|
-
return sql2;
|
|
13551
|
+
};
|
|
13552
|
+
var DispatchQueue = class {
|
|
13553
|
+
/**
|
|
13554
|
+
* Create a new dispatch queue instance.
|
|
13555
|
+
*/
|
|
13556
|
+
constructor() {
|
|
13557
|
+
this.clear();
|
|
13384
13558
|
}
|
|
13385
|
-
|
|
13386
|
-
|
|
13387
|
-
|
|
13388
|
-
|
|
13389
|
-
|
|
13390
|
-
type: "arrow",
|
|
13391
|
-
cache: false,
|
|
13392
|
-
record: false,
|
|
13393
|
-
query: group.query = consolidatedQuery(group, record)
|
|
13394
|
-
},
|
|
13395
|
-
result: group.result = queryResult()
|
|
13396
|
-
});
|
|
13397
|
-
} else {
|
|
13398
|
-
for (const { entry, priority } of group) {
|
|
13399
|
-
enqueue(entry, priority);
|
|
13400
|
-
}
|
|
13559
|
+
/**
|
|
13560
|
+
* Clear the queue state of all event values.
|
|
13561
|
+
*/
|
|
13562
|
+
clear() {
|
|
13563
|
+
this.next = null;
|
|
13401
13564
|
}
|
|
13402
|
-
|
|
13403
|
-
|
|
13404
|
-
|
|
13405
|
-
|
|
13406
|
-
|
|
13407
|
-
|
|
13408
|
-
return true;
|
|
13409
|
-
}
|
|
13410
|
-
}
|
|
13565
|
+
/**
|
|
13566
|
+
* Indicate if the queue is empty.
|
|
13567
|
+
* @returns {boolean} True if queue is empty, false otherwise.
|
|
13568
|
+
*/
|
|
13569
|
+
isEmpty() {
|
|
13570
|
+
return !this.next;
|
|
13411
13571
|
}
|
|
13412
|
-
|
|
13413
|
-
|
|
13414
|
-
|
|
13415
|
-
|
|
13416
|
-
|
|
13417
|
-
|
|
13418
|
-
|
|
13419
|
-
|
|
13420
|
-
|
|
13421
|
-
|
|
13422
|
-
|
|
13423
|
-
|
|
13424
|
-
|
|
13572
|
+
/**
|
|
13573
|
+
* Add a new value to the queue, and optionally filter the
|
|
13574
|
+
* current queue content in response.
|
|
13575
|
+
* @param {*} value The value to add.
|
|
13576
|
+
* @param {(value: *) => boolean} [filter] An optional filter
|
|
13577
|
+
* function to apply to existing queue content. If unspecified
|
|
13578
|
+
* or falsy, all previously queued values are removed. Otherwise,
|
|
13579
|
+
* the provided function is applied to all queue entries. The
|
|
13580
|
+
* entry is retained if the filter function returns a truthy value,
|
|
13581
|
+
* otherwise the entry is removed.
|
|
13582
|
+
*/
|
|
13583
|
+
enqueue(value, filter) {
|
|
13584
|
+
const tail = { value };
|
|
13585
|
+
if (filter && this.next) {
|
|
13586
|
+
let curr = this;
|
|
13587
|
+
while (curr.next) {
|
|
13588
|
+
if (filter(curr.next.value)) {
|
|
13589
|
+
curr = curr.next;
|
|
13590
|
+
} else {
|
|
13591
|
+
curr.next = curr.next.next;
|
|
13592
|
+
}
|
|
13425
13593
|
}
|
|
13426
|
-
|
|
13427
|
-
|
|
13594
|
+
curr.next = tail;
|
|
13595
|
+
} else {
|
|
13596
|
+
this.next = tail;
|
|
13428
13597
|
}
|
|
13429
|
-
record(`${query2}`);
|
|
13430
13598
|
}
|
|
13431
|
-
|
|
13432
|
-
|
|
13433
|
-
|
|
13434
|
-
|
|
13435
|
-
|
|
13436
|
-
|
|
13599
|
+
/**
|
|
13600
|
+
* Remove and return the next queued event value.
|
|
13601
|
+
* @returns {*} The next event value in the queue.
|
|
13602
|
+
*/
|
|
13603
|
+
dequeue() {
|
|
13604
|
+
const { next } = this;
|
|
13605
|
+
this.next = next?.next;
|
|
13606
|
+
return next?.value;
|
|
13437
13607
|
}
|
|
13438
|
-
|
|
13608
|
+
};
|
|
13609
|
+
|
|
13610
|
+
// ../core/src/util/distinct.js
|
|
13611
|
+
function distinct(a, b) {
|
|
13612
|
+
return a === b ? false : a instanceof Date && b instanceof Date ? +a !== +b : Array.isArray(a) && Array.isArray(b) ? distinctArray(a, b) : true;
|
|
13439
13613
|
}
|
|
13440
|
-
|
|
13441
|
-
|
|
13442
|
-
|
|
13443
|
-
|
|
13444
|
-
try {
|
|
13445
|
-
data = await result;
|
|
13446
|
-
} catch (err) {
|
|
13447
|
-
for (const { entry } of group) {
|
|
13448
|
-
entry.result.reject(err);
|
|
13449
|
-
}
|
|
13450
|
-
return;
|
|
13614
|
+
function distinctArray(a, b) {
|
|
13615
|
+
if (a.length !== b.length) return true;
|
|
13616
|
+
for (let i = 0; i < a.length; ++i) {
|
|
13617
|
+
if (a[i] !== b[i]) return true;
|
|
13451
13618
|
}
|
|
13452
|
-
|
|
13453
|
-
group.forEach(({ entry }, index) => {
|
|
13454
|
-
const { request, result: result2 } = entry;
|
|
13455
|
-
const map = maps[index];
|
|
13456
|
-
const extract = describe && map ? filterResult(data, map) : map ? projectResult(data, map) : data;
|
|
13457
|
-
if (request.cache) {
|
|
13458
|
-
cache.set(String(request.query), extract);
|
|
13459
|
-
}
|
|
13460
|
-
result2.fulfill(extract);
|
|
13461
|
-
});
|
|
13619
|
+
return false;
|
|
13462
13620
|
}
|
|
13463
|
-
|
|
13464
|
-
|
|
13465
|
-
|
|
13466
|
-
|
|
13467
|
-
}
|
|
13468
|
-
return new data.constructor(cols);
|
|
13621
|
+
|
|
13622
|
+
// ../core/src/Param.js
|
|
13623
|
+
function isParam(x2) {
|
|
13624
|
+
return x2 instanceof Param;
|
|
13469
13625
|
}
|
|
13470
|
-
|
|
13471
|
-
|
|
13472
|
-
|
|
13473
|
-
|
|
13474
|
-
|
|
13475
|
-
|
|
13476
|
-
|
|
13626
|
+
var Param = class _Param extends AsyncDispatch {
|
|
13627
|
+
/**
|
|
13628
|
+
* Create a new Param instance.
|
|
13629
|
+
* @param {*} value The initial value of the Param.
|
|
13630
|
+
*/
|
|
13631
|
+
constructor(value) {
|
|
13632
|
+
super();
|
|
13633
|
+
this._value = value;
|
|
13477
13634
|
}
|
|
13478
|
-
|
|
13479
|
-
|
|
13480
|
-
|
|
13481
|
-
|
|
13482
|
-
|
|
13483
|
-
|
|
13484
|
-
|
|
13485
|
-
set: (key, value) => value,
|
|
13486
|
-
clear: () => {
|
|
13635
|
+
/**
|
|
13636
|
+
* Create a new Param instance with the given initial value.
|
|
13637
|
+
* @param {*} value The initial value of the Param.
|
|
13638
|
+
* @returns {Param} The new Param instance.
|
|
13639
|
+
*/
|
|
13640
|
+
static value(value) {
|
|
13641
|
+
return new _Param(value);
|
|
13487
13642
|
}
|
|
13488
|
-
|
|
13489
|
-
|
|
13490
|
-
|
|
13491
|
-
|
|
13492
|
-
|
|
13493
|
-
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
|
|
13503
|
-
lruKey = key;
|
|
13504
|
-
lruLast = last2;
|
|
13505
|
-
}
|
|
13506
|
-
if (expire > last2) {
|
|
13507
|
-
cache.delete(key);
|
|
13508
|
-
}
|
|
13643
|
+
/**
|
|
13644
|
+
* Create a new Param instance over an array of initial values,
|
|
13645
|
+
* which may contain nested Params.
|
|
13646
|
+
* @param {*} values The initial values of the Param.
|
|
13647
|
+
* @returns {Param} The new Param instance.
|
|
13648
|
+
*/
|
|
13649
|
+
static array(values) {
|
|
13650
|
+
if (values.some((v) => isParam(v))) {
|
|
13651
|
+
const p = new _Param();
|
|
13652
|
+
const update2 = () => {
|
|
13653
|
+
p.update(values.map((v) => isParam(v) ? v.value : v));
|
|
13654
|
+
};
|
|
13655
|
+
update2();
|
|
13656
|
+
values.forEach((v) => isParam(v) ? v.addEventListener("value", update2) : 0);
|
|
13657
|
+
return p;
|
|
13509
13658
|
}
|
|
13510
|
-
|
|
13511
|
-
|
|
13659
|
+
return new _Param(values);
|
|
13660
|
+
}
|
|
13661
|
+
/**
|
|
13662
|
+
* The current value of the Param.
|
|
13663
|
+
*/
|
|
13664
|
+
get value() {
|
|
13665
|
+
return this._value;
|
|
13666
|
+
}
|
|
13667
|
+
/**
|
|
13668
|
+
* Update the Param value
|
|
13669
|
+
* @param {*} value The new value of the Param.
|
|
13670
|
+
* @param {object} [options] The update options.
|
|
13671
|
+
* @param {boolean} [options.force] A boolean flag indicating if the Param
|
|
13672
|
+
* should emit a 'value' event even if the internal value is unchanged.
|
|
13673
|
+
* @returns {this} This Param instance.
|
|
13674
|
+
*/
|
|
13675
|
+
update(value, { force } = {}) {
|
|
13676
|
+
const shouldEmit = distinct(this._value, value) || force;
|
|
13677
|
+
if (shouldEmit) {
|
|
13678
|
+
this.emit("value", value);
|
|
13679
|
+
} else {
|
|
13680
|
+
this.cancel("value");
|
|
13512
13681
|
}
|
|
13682
|
+
return this;
|
|
13513
13683
|
}
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
|
|
13519
|
-
|
|
13520
|
-
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13524
|
-
if (cache.size > max2) requestIdle(evict);
|
|
13525
|
-
return value;
|
|
13526
|
-
},
|
|
13527
|
-
clear() {
|
|
13528
|
-
cache = /* @__PURE__ */ new Map();
|
|
13684
|
+
/**
|
|
13685
|
+
* Upon value-typed updates, sets the current value to the input value
|
|
13686
|
+
* immediately prior to the event value being emitted to listeners.
|
|
13687
|
+
* @param {string} type The event type.
|
|
13688
|
+
* @param {*} value The input event value.
|
|
13689
|
+
* @returns {*} The input event value.
|
|
13690
|
+
*/
|
|
13691
|
+
willEmit(type, value) {
|
|
13692
|
+
if (type === "value") {
|
|
13693
|
+
this._value = value;
|
|
13529
13694
|
}
|
|
13530
|
-
|
|
13531
|
-
}
|
|
13695
|
+
return value;
|
|
13696
|
+
}
|
|
13697
|
+
};
|
|
13532
13698
|
|
|
13533
|
-
// ../core/src/
|
|
13534
|
-
function
|
|
13535
|
-
|
|
13536
|
-
{ length: ranks },
|
|
13537
|
-
() => ({ head: null, tail: null })
|
|
13538
|
-
);
|
|
13539
|
-
return {
|
|
13540
|
-
/**
|
|
13541
|
-
* Indicate if the queue is empty.
|
|
13542
|
-
* @returns [boolean] true if empty, false otherwise.
|
|
13543
|
-
*/
|
|
13544
|
-
isEmpty() {
|
|
13545
|
-
return queue.every((list) => !list.head);
|
|
13546
|
-
},
|
|
13547
|
-
/**
|
|
13548
|
-
* Insert an item into the queue with a given priority rank.
|
|
13549
|
-
* @param {*} item The item to add.
|
|
13550
|
-
* @param {number} rank The integer priority rank.
|
|
13551
|
-
* Priority ranks are integers starting at zero.
|
|
13552
|
-
* Lower ranks indicate higher priority.
|
|
13553
|
-
*/
|
|
13554
|
-
insert(item, rank2) {
|
|
13555
|
-
const list = queue[rank2];
|
|
13556
|
-
if (!list) {
|
|
13557
|
-
throw new Error(`Invalid queue priority rank: ${rank2}`);
|
|
13558
|
-
}
|
|
13559
|
-
const node = { item, next: null };
|
|
13560
|
-
if (list.head === null) {
|
|
13561
|
-
list.head = list.tail = node;
|
|
13562
|
-
} else {
|
|
13563
|
-
list.tail = list.tail.next = node;
|
|
13564
|
-
}
|
|
13565
|
-
},
|
|
13566
|
-
/**
|
|
13567
|
-
* Remove a set of items from the queue, regardless of priority rank.
|
|
13568
|
-
* If a provided item is not in the queue it will be ignored.
|
|
13569
|
-
* @param {(item: *) => boolean} test A predicate function to test
|
|
13570
|
-
* if an item should be removed (true to drop, false to keep).
|
|
13571
|
-
*/
|
|
13572
|
-
remove(test) {
|
|
13573
|
-
for (const list of queue) {
|
|
13574
|
-
let { head, tail } = list;
|
|
13575
|
-
for (let prev = null, curr = head; curr; prev = curr, curr = curr.next) {
|
|
13576
|
-
if (test(curr.item)) {
|
|
13577
|
-
if (curr === head) {
|
|
13578
|
-
head = curr.next;
|
|
13579
|
-
} else {
|
|
13580
|
-
prev.next = curr.next;
|
|
13581
|
-
}
|
|
13582
|
-
if (curr === tail) tail = prev || head;
|
|
13583
|
-
}
|
|
13584
|
-
}
|
|
13585
|
-
list.head = head;
|
|
13586
|
-
list.tail = tail;
|
|
13587
|
-
}
|
|
13588
|
-
},
|
|
13589
|
-
/**
|
|
13590
|
-
* Remove and return the next highest priority item.
|
|
13591
|
-
* @returns {*} The next item in the queue,
|
|
13592
|
-
* or undefined if this queue is empty.
|
|
13593
|
-
*/
|
|
13594
|
-
next() {
|
|
13595
|
-
for (const list of queue) {
|
|
13596
|
-
const { head } = list;
|
|
13597
|
-
if (head !== null) {
|
|
13598
|
-
list.head = head.next;
|
|
13599
|
-
if (list.tail === head) {
|
|
13600
|
-
list.tail = null;
|
|
13601
|
-
}
|
|
13602
|
-
return head.item;
|
|
13603
|
-
}
|
|
13604
|
-
}
|
|
13605
|
-
}
|
|
13606
|
-
};
|
|
13699
|
+
// ../core/src/Selection.js
|
|
13700
|
+
function isSelection(x2) {
|
|
13701
|
+
return x2 instanceof Selection;
|
|
13607
13702
|
}
|
|
13608
|
-
|
|
13609
|
-
|
|
13610
|
-
|
|
13611
|
-
|
|
13612
|
-
|
|
13613
|
-
|
|
13614
|
-
|
|
13615
|
-
|
|
13616
|
-
|
|
13617
|
-
|
|
13618
|
-
|
|
13619
|
-
|
|
13620
|
-
if (pending || queue.isEmpty()) return;
|
|
13621
|
-
const { request, result } = queue.next();
|
|
13622
|
-
pending = submit(request, result);
|
|
13623
|
-
pending.finally(() => {
|
|
13624
|
-
pending = null;
|
|
13625
|
-
next();
|
|
13626
|
-
});
|
|
13703
|
+
var Selection = class _Selection extends Param {
|
|
13704
|
+
/**
|
|
13705
|
+
* Create a new Selection instance with an
|
|
13706
|
+
* intersect (conjunction) resolution strategy.
|
|
13707
|
+
* @param {object} [options] The selection options.
|
|
13708
|
+
* @param {boolean} [options.cross=false] Boolean flag indicating
|
|
13709
|
+
* cross-filtered resolution. If true, selection clauses will not
|
|
13710
|
+
* be applied to the clients they are associated with.
|
|
13711
|
+
* @returns {Selection} The new Selection instance.
|
|
13712
|
+
*/
|
|
13713
|
+
static intersect({ cross = false } = {}) {
|
|
13714
|
+
return new _Selection(new SelectionResolver({ cross }));
|
|
13627
13715
|
}
|
|
13628
|
-
|
|
13629
|
-
|
|
13630
|
-
|
|
13716
|
+
/**
|
|
13717
|
+
* Create a new Selection instance with a
|
|
13718
|
+
* union (disjunction) resolution strategy.
|
|
13719
|
+
* @param {object} [options] The selection options.
|
|
13720
|
+
* @param {boolean} [options.cross=false] Boolean flag indicating
|
|
13721
|
+
* cross-filtered resolution. If true, selection clauses will not
|
|
13722
|
+
* be applied to the clients they are associated with.
|
|
13723
|
+
* @returns {Selection} The new Selection instance.
|
|
13724
|
+
*/
|
|
13725
|
+
static union({ cross = false } = {}) {
|
|
13726
|
+
return new _Selection(new SelectionResolver({ cross, union: true }));
|
|
13631
13727
|
}
|
|
13632
|
-
|
|
13633
|
-
|
|
13634
|
-
|
|
13635
|
-
|
|
13728
|
+
/**
|
|
13729
|
+
* Create a new Selection instance with a singular resolution strategy
|
|
13730
|
+
* that keeps only the most recent selection clause.
|
|
13731
|
+
* @param {object} [options] The selection options.
|
|
13732
|
+
* @param {boolean} [options.cross=false] Boolean flag indicating
|
|
13733
|
+
* cross-filtered resolution. If true, selection clauses will not
|
|
13734
|
+
* be applied to the clients they are associated with.
|
|
13735
|
+
* @returns {Selection} The new Selection instance.
|
|
13736
|
+
*/
|
|
13737
|
+
static single({ cross = false } = {}) {
|
|
13738
|
+
return new _Selection(new SelectionResolver({ cross, single: true }));
|
|
13636
13739
|
}
|
|
13637
|
-
|
|
13638
|
-
|
|
13639
|
-
|
|
13640
|
-
|
|
13641
|
-
|
|
13642
|
-
|
|
13643
|
-
|
|
13644
|
-
if (cache) {
|
|
13645
|
-
const cached = clientCache.get(sql2);
|
|
13646
|
-
if (cached) {
|
|
13647
|
-
logger.debug("Cache");
|
|
13648
|
-
result.fulfill(cached);
|
|
13649
|
-
return;
|
|
13650
|
-
}
|
|
13651
|
-
}
|
|
13652
|
-
const t0 = performance.now();
|
|
13653
|
-
const data = await db.query({ type, sql: sql2, ...options });
|
|
13654
|
-
if (cache) clientCache.set(sql2, data);
|
|
13655
|
-
logger.debug(`Request: ${(performance.now() - t0).toFixed(1)}`);
|
|
13656
|
-
result.fulfill(data);
|
|
13657
|
-
} catch (err) {
|
|
13658
|
-
result.reject(err);
|
|
13659
|
-
}
|
|
13740
|
+
/**
|
|
13741
|
+
* Create a new Selection instance with a
|
|
13742
|
+
* cross-filtered intersect resolution strategy.
|
|
13743
|
+
* @returns {Selection} The new Selection instance.
|
|
13744
|
+
*/
|
|
13745
|
+
static crossfilter() {
|
|
13746
|
+
return new _Selection(new SelectionResolver({ cross: true }));
|
|
13660
13747
|
}
|
|
13661
|
-
|
|
13662
|
-
|
|
13663
|
-
|
|
13664
|
-
|
|
13665
|
-
|
|
13666
|
-
|
|
13667
|
-
|
|
13668
|
-
|
|
13669
|
-
|
|
13670
|
-
},
|
|
13671
|
-
consolidate(flag) {
|
|
13672
|
-
if (flag && !consolidate2) {
|
|
13673
|
-
consolidate2 = consolidator(enqueue, clientCache, recordQuery);
|
|
13674
|
-
} else if (!flag && consolidate2) {
|
|
13675
|
-
consolidate2 = null;
|
|
13676
|
-
}
|
|
13677
|
-
},
|
|
13678
|
-
request(request, priority = Priority.Normal) {
|
|
13679
|
-
const result = queryResult();
|
|
13680
|
-
const entry = { request, result };
|
|
13681
|
-
if (consolidate2) {
|
|
13682
|
-
consolidate2.add(entry, priority);
|
|
13683
|
-
} else {
|
|
13684
|
-
enqueue(entry, priority);
|
|
13685
|
-
}
|
|
13686
|
-
return result;
|
|
13687
|
-
},
|
|
13688
|
-
cancel(requests) {
|
|
13689
|
-
const set = new Set(requests);
|
|
13690
|
-
queue.remove(({ result }) => set.has(result));
|
|
13691
|
-
},
|
|
13692
|
-
clear() {
|
|
13693
|
-
queue.remove(({ result }) => {
|
|
13694
|
-
result.reject("Cleared");
|
|
13695
|
-
return true;
|
|
13696
|
-
});
|
|
13697
|
-
},
|
|
13698
|
-
record() {
|
|
13699
|
-
let state = [];
|
|
13700
|
-
const recorder = {
|
|
13701
|
-
add(query) {
|
|
13702
|
-
state.push(query);
|
|
13703
|
-
},
|
|
13704
|
-
reset() {
|
|
13705
|
-
state = [];
|
|
13706
|
-
},
|
|
13707
|
-
snapshot() {
|
|
13708
|
-
return state.slice();
|
|
13709
|
-
},
|
|
13710
|
-
stop() {
|
|
13711
|
-
recorders = recorders.filter((x2) => x2 !== recorder);
|
|
13712
|
-
return state;
|
|
13713
|
-
}
|
|
13714
|
-
};
|
|
13715
|
-
recorders.push(recorder);
|
|
13716
|
-
return recorder;
|
|
13717
|
-
}
|
|
13718
|
-
};
|
|
13719
|
-
}
|
|
13720
|
-
|
|
13721
|
-
// ../core/src/util/js-type.js
|
|
13722
|
-
function jsType(type) {
|
|
13723
|
-
switch (type) {
|
|
13724
|
-
case "BIGINT":
|
|
13725
|
-
case "HUGEINT":
|
|
13726
|
-
case "INTEGER":
|
|
13727
|
-
case "SMALLINT":
|
|
13728
|
-
case "TINYINT":
|
|
13729
|
-
case "UBIGINT":
|
|
13730
|
-
case "UINTEGER":
|
|
13731
|
-
case "USMALLINT":
|
|
13732
|
-
case "UTINYINT":
|
|
13733
|
-
case "DOUBLE":
|
|
13734
|
-
case "FLOAT":
|
|
13735
|
-
case "REAL":
|
|
13736
|
-
return "number";
|
|
13737
|
-
case "DATE":
|
|
13738
|
-
case "TIMESTAMP":
|
|
13739
|
-
case "TIMESTAMPTZ":
|
|
13740
|
-
case "TIMESTAMP WITH TIME ZONE":
|
|
13741
|
-
case "TIME":
|
|
13742
|
-
case "TIMESTAMP_NS":
|
|
13743
|
-
return "date";
|
|
13744
|
-
case "BOOLEAN":
|
|
13745
|
-
return "boolean";
|
|
13746
|
-
case "VARCHAR":
|
|
13747
|
-
case "UUID":
|
|
13748
|
-
case "JSON":
|
|
13749
|
-
return "string";
|
|
13750
|
-
case "ARRAY":
|
|
13751
|
-
case "LIST":
|
|
13752
|
-
return "array";
|
|
13753
|
-
case "BLOB":
|
|
13754
|
-
case "STRUCT":
|
|
13755
|
-
case "MAP":
|
|
13756
|
-
case "GEOMETRY":
|
|
13757
|
-
return "object";
|
|
13758
|
-
default:
|
|
13759
|
-
if (type.startsWith("DECIMAL")) {
|
|
13760
|
-
return "number";
|
|
13761
|
-
} else if (type.startsWith("STRUCT") || type.startsWith("MAP")) {
|
|
13762
|
-
return "object";
|
|
13763
|
-
} else if (type.endsWith("]")) {
|
|
13764
|
-
return "array";
|
|
13765
|
-
}
|
|
13766
|
-
throw new Error(`Unsupported type: ${type}`);
|
|
13748
|
+
/**
|
|
13749
|
+
* Create a new Selection instance.
|
|
13750
|
+
* @param {SelectionResolver} resolver The selection resolution
|
|
13751
|
+
* strategy to apply.
|
|
13752
|
+
*/
|
|
13753
|
+
constructor(resolver = new SelectionResolver()) {
|
|
13754
|
+
super([]);
|
|
13755
|
+
this._resolved = this._value;
|
|
13756
|
+
this._resolver = resolver;
|
|
13767
13757
|
}
|
|
13768
|
-
|
|
13769
|
-
|
|
13770
|
-
|
|
13771
|
-
|
|
13772
|
-
|
|
13773
|
-
|
|
13758
|
+
/**
|
|
13759
|
+
* Create a cloned copy of this Selection instance.
|
|
13760
|
+
* @returns {Selection} A clone of this selection.
|
|
13761
|
+
*/
|
|
13762
|
+
clone() {
|
|
13763
|
+
const s = new _Selection(this._resolver);
|
|
13764
|
+
s._value = s._resolved = this._value;
|
|
13765
|
+
return s;
|
|
13774
13766
|
}
|
|
13775
|
-
|
|
13776
|
-
|
|
13767
|
+
/**
|
|
13768
|
+
* Create a clone of this Selection with clauses corresponding
|
|
13769
|
+
* to the provided source removed.
|
|
13770
|
+
* @param {*} source The clause source to remove.
|
|
13771
|
+
* @returns {Selection} A cloned and updated Selection.
|
|
13772
|
+
*/
|
|
13773
|
+
remove(source) {
|
|
13774
|
+
const s = this.clone();
|
|
13775
|
+
s._value = s._resolved = s._resolver.resolve(this._resolved, { source });
|
|
13776
|
+
s._value.active = { source };
|
|
13777
|
+
return s;
|
|
13777
13778
|
}
|
|
13778
|
-
|
|
13779
|
-
|
|
13780
|
-
|
|
13779
|
+
/**
|
|
13780
|
+
* The selection clause resolver.
|
|
13781
|
+
*/
|
|
13782
|
+
get resolver() {
|
|
13783
|
+
return this._resolver;
|
|
13781
13784
|
}
|
|
13782
|
-
|
|
13783
|
-
|
|
13784
|
-
|
|
13785
|
-
|
|
13786
|
-
|
|
13787
|
-
);
|
|
13788
|
-
function decimalToNumber(v, scale) {
|
|
13789
|
-
const n = v.length;
|
|
13790
|
-
let x2 = 0;
|
|
13791
|
-
if (v.signed && (v[n - 1] | 0) < 0) {
|
|
13792
|
-
for (let i = 0; i < n; ++i) {
|
|
13793
|
-
x2 += ~v[i] * BASE32[i];
|
|
13794
|
-
}
|
|
13795
|
-
x2 = -(x2 + 1);
|
|
13796
|
-
} else {
|
|
13797
|
-
for (let i = 0; i < n; ++i) {
|
|
13798
|
-
x2 += v[i] * BASE32[i];
|
|
13799
|
-
}
|
|
13785
|
+
/**
|
|
13786
|
+
* Indicate if this selection has a single resolution strategy.
|
|
13787
|
+
*/
|
|
13788
|
+
get single() {
|
|
13789
|
+
return this._resolver.single;
|
|
13800
13790
|
}
|
|
13801
|
-
|
|
13802
|
-
|
|
13803
|
-
|
|
13804
|
-
|
|
13805
|
-
|
|
13806
|
-
var Nulls = "nulls";
|
|
13807
|
-
var Max = "max";
|
|
13808
|
-
var Min = "min";
|
|
13809
|
-
var Distinct = "distinct";
|
|
13810
|
-
var statMap = {
|
|
13811
|
-
[Count]: count,
|
|
13812
|
-
[Distinct]: (column2) => count(column2).distinct(),
|
|
13813
|
-
[Max]: max,
|
|
13814
|
-
[Min]: min,
|
|
13815
|
-
[Nulls]: (column2) => count().where(isNull(column2))
|
|
13816
|
-
};
|
|
13817
|
-
function summarize(table2, column2, stats) {
|
|
13818
|
-
return Query.from(table2).select(Array.from(stats, (s) => [s, statMap[s](column2)]));
|
|
13819
|
-
}
|
|
13820
|
-
async function queryFieldInfo(mc, fields) {
|
|
13821
|
-
if (fields.length === 1 && `${fields[0].column}` === "*") {
|
|
13822
|
-
return getTableInfo(mc, fields[0].table);
|
|
13823
|
-
} else {
|
|
13824
|
-
return (await Promise.all(fields.map((f) => getFieldInfo(mc, f)))).filter((x2) => x2);
|
|
13791
|
+
/**
|
|
13792
|
+
* The current array of selection clauses.
|
|
13793
|
+
*/
|
|
13794
|
+
get clauses() {
|
|
13795
|
+
return super.value;
|
|
13825
13796
|
}
|
|
13826
|
-
|
|
13827
|
-
|
|
13828
|
-
|
|
13829
|
-
|
|
13830
|
-
|
|
13831
|
-
table: table2,
|
|
13832
|
-
column: `${column2}`,
|
|
13833
|
-
sqlType: desc2.column_type,
|
|
13834
|
-
type: jsType(desc2.column_type),
|
|
13835
|
-
nullable: desc2.null === "YES"
|
|
13836
|
-
};
|
|
13837
|
-
if (!(stats?.length || stats?.size)) return info;
|
|
13838
|
-
const result = await mc.query(
|
|
13839
|
-
summarize(table2, column2, stats),
|
|
13840
|
-
{ persist: true }
|
|
13841
|
-
);
|
|
13842
|
-
for (let i = 0; i < result.numCols; ++i) {
|
|
13843
|
-
const { name } = result.schema.fields[i];
|
|
13844
|
-
const child = result.getChildAt(i);
|
|
13845
|
-
const convert = convertArrowValue(child.type);
|
|
13846
|
-
info[name] = convert(child.get(0));
|
|
13797
|
+
/**
|
|
13798
|
+
* The current active (most recently updated) selection clause.
|
|
13799
|
+
*/
|
|
13800
|
+
get active() {
|
|
13801
|
+
return this.clauses.active;
|
|
13847
13802
|
}
|
|
13848
|
-
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
|
|
13852
|
-
|
|
13853
|
-
|
|
13854
|
-
|
|
13855
|
-
|
|
13856
|
-
|
|
13857
|
-
|
|
13858
|
-
|
|
13859
|
-
|
|
13860
|
-
|
|
13861
|
-
|
|
13862
|
-
|
|
13863
|
-
|
|
13864
|
-
|
|
13865
|
-
|
|
13866
|
-
|
|
13867
|
-
|
|
13868
|
-
|
|
13869
|
-
|
|
13870
|
-
|
|
13871
|
-
|
|
13872
|
-
|
|
13803
|
+
/**
|
|
13804
|
+
* The value corresponding to the current active selection clause.
|
|
13805
|
+
* This method ensures compatibility where a normal Param is expected.
|
|
13806
|
+
*/
|
|
13807
|
+
get value() {
|
|
13808
|
+
return this.active?.value;
|
|
13809
|
+
}
|
|
13810
|
+
/**
|
|
13811
|
+
* The value corresponding to a given source. Returns undefined if
|
|
13812
|
+
* this selection does not include a clause from this source.
|
|
13813
|
+
* @param {*} source The clause source to look up the value for.
|
|
13814
|
+
*/
|
|
13815
|
+
valueFor(source) {
|
|
13816
|
+
return this.clauses.find((c) => c.source === source)?.value;
|
|
13817
|
+
}
|
|
13818
|
+
/**
|
|
13819
|
+
* Emit an activate event with the given selection clause.
|
|
13820
|
+
* @param {*} clause The clause repesenting the potential activation.
|
|
13821
|
+
*/
|
|
13822
|
+
activate(clause) {
|
|
13823
|
+
this.emit("activate", clause);
|
|
13824
|
+
}
|
|
13825
|
+
/**
|
|
13826
|
+
* Update the selection with a new selection clause.
|
|
13827
|
+
* @param {*} clause The selection clause to add.
|
|
13828
|
+
* @returns {this} This Selection instance.
|
|
13829
|
+
*/
|
|
13830
|
+
update(clause) {
|
|
13831
|
+
this._resolved = this._resolver.resolve(this._resolved, clause, true);
|
|
13832
|
+
this._resolved.active = clause;
|
|
13833
|
+
return super.update(this._resolved);
|
|
13834
|
+
}
|
|
13835
|
+
/**
|
|
13836
|
+
* Upon value-typed updates, sets the current clause list to the
|
|
13837
|
+
* input value and returns the active clause value.
|
|
13838
|
+
* @param {string} type The event type.
|
|
13839
|
+
* @param {*} value The input event value.
|
|
13840
|
+
* @returns {*} For value-typed events, returns the active clause
|
|
13841
|
+
* values. Otherwise returns the input event value as-is.
|
|
13842
|
+
*/
|
|
13843
|
+
willEmit(type, value) {
|
|
13844
|
+
if (type === "value") {
|
|
13845
|
+
this._value = value;
|
|
13846
|
+
return this.value;
|
|
13873
13847
|
}
|
|
13874
|
-
|
|
13875
|
-
}
|
|
13876
|
-
|
|
13877
|
-
|
|
13878
|
-
|
|
13879
|
-
|
|
13880
|
-
|
|
13881
|
-
|
|
13882
|
-
|
|
13883
|
-
|
|
13848
|
+
return value;
|
|
13849
|
+
}
|
|
13850
|
+
/**
|
|
13851
|
+
* Upon value-typed updates, returns a dispatch queue filter function.
|
|
13852
|
+
* The return value depends on the selection resolution strategy.
|
|
13853
|
+
* @param {string} type The event type.
|
|
13854
|
+
* @param {*} value The new event value that will be enqueued.
|
|
13855
|
+
* @returns {(value: *) => boolean|null} For value-typed events,
|
|
13856
|
+
* returns a dispatch queue filter function. Otherwise returns null.
|
|
13857
|
+
*/
|
|
13858
|
+
emitQueueFilter(type, value) {
|
|
13859
|
+
return type === "value" ? this._resolver.queueFilter(value) : null;
|
|
13884
13860
|
}
|
|
13885
|
-
|
|
13886
|
-
|
|
13887
|
-
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
this.
|
|
13894
|
-
this.logger(logger);
|
|
13895
|
-
this.configure(options);
|
|
13896
|
-
this.databaseConnector(db);
|
|
13897
|
-
this.clear();
|
|
13861
|
+
/**
|
|
13862
|
+
* Indicates if a selection clause should not be applied to a given client.
|
|
13863
|
+
* The return value depends on the selection resolution strategy.
|
|
13864
|
+
* @param {*} client The selection clause.
|
|
13865
|
+
* @param {*} clause The client to test.
|
|
13866
|
+
* @returns True if the client should be skipped, false otherwise.
|
|
13867
|
+
*/
|
|
13868
|
+
skip(client, clause) {
|
|
13869
|
+
return this._resolver.skip(client, clause);
|
|
13898
13870
|
}
|
|
13899
|
-
|
|
13900
|
-
|
|
13901
|
-
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
|
|
13871
|
+
/**
|
|
13872
|
+
* Return a selection query predicate for the given client.
|
|
13873
|
+
* @param {*} client The client whose data may be filtered.
|
|
13874
|
+
* @param {boolean} [noSkip=false] Disable skipping of active
|
|
13875
|
+
* cross-filtered sources. If set true, the source of the active
|
|
13876
|
+
* clause in a cross-filtered selection will not be skipped.
|
|
13877
|
+
* @returns {*} The query predicate for filtering client data,
|
|
13878
|
+
* based on the current state of this selection.
|
|
13879
|
+
*/
|
|
13880
|
+
predicate(client, noSkip = false) {
|
|
13881
|
+
const { clauses } = this;
|
|
13882
|
+
const active = noSkip ? null : clauses.active;
|
|
13883
|
+
return this._resolver.predicate(clauses, active, client);
|
|
13905
13884
|
}
|
|
13885
|
+
};
|
|
13886
|
+
var SelectionResolver = class {
|
|
13906
13887
|
/**
|
|
13907
|
-
*
|
|
13908
|
-
* @param {object} [options]
|
|
13909
|
-
* @param {boolean} [options.
|
|
13910
|
-
*
|
|
13911
|
-
* @param {boolean
|
|
13912
|
-
*
|
|
13888
|
+
* Create a new selection resolved instance.
|
|
13889
|
+
* @param {object} [options] The resolution strategy options.
|
|
13890
|
+
* @param {boolean} [options.union=false] Boolean flag to indicate a union strategy.
|
|
13891
|
+
* If false, an intersection strategy is used.
|
|
13892
|
+
* @param {boolean} [options.cross=false] Boolean flag to indicate cross-filtering.
|
|
13893
|
+
* @param {boolean} [options.single=false] Boolean flag to indicate single clauses only.
|
|
13913
13894
|
*/
|
|
13914
|
-
|
|
13915
|
-
this.
|
|
13916
|
-
this.
|
|
13917
|
-
this.
|
|
13895
|
+
constructor({ union, cross, single } = {}) {
|
|
13896
|
+
this.union = !!union;
|
|
13897
|
+
this.cross = !!cross;
|
|
13898
|
+
this.single = !!single;
|
|
13918
13899
|
}
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13900
|
+
/**
|
|
13901
|
+
* Resolve a list of selection clauses according to the resolution strategy.
|
|
13902
|
+
* @param {*[]} clauseList An array of selection clauses.
|
|
13903
|
+
* @param {*} clause A new selection clause to add.
|
|
13904
|
+
* @returns {*[]} An updated array of selection clauses.
|
|
13905
|
+
*/
|
|
13906
|
+
resolve(clauseList, clause, reset = false) {
|
|
13907
|
+
const { source, predicate } = clause;
|
|
13908
|
+
const filtered = clauseList.filter((c) => source !== c.source);
|
|
13909
|
+
const clauses = this.single ? [] : filtered;
|
|
13910
|
+
if (this.single && reset) filtered.forEach((c) => c.source?.reset?.());
|
|
13911
|
+
if (predicate) clauses.push(clause);
|
|
13912
|
+
return clauses;
|
|
13913
|
+
}
|
|
13914
|
+
/**
|
|
13915
|
+
* Indicates if a selection clause should not be applied to a given client.
|
|
13916
|
+
* The return value depends on the resolution strategy.
|
|
13917
|
+
* @param {*} client The selection clause.
|
|
13918
|
+
* @param {*} clause The client to test.
|
|
13919
|
+
* @returns True if the client should be skipped, false otherwise.
|
|
13920
|
+
*/
|
|
13921
|
+
skip(client, clause) {
|
|
13922
|
+
return this.cross && clause?.clients?.has(client);
|
|
13923
|
+
}
|
|
13924
|
+
/**
|
|
13925
|
+
* Return a selection query predicate for the given client.
|
|
13926
|
+
* @param {*[]} clauseList An array of selection clauses.
|
|
13927
|
+
* @param {*} active The current active selection clause.
|
|
13928
|
+
* @param {*} client The client whose data may be filtered.
|
|
13929
|
+
* @returns {*} The query predicate for filtering client data,
|
|
13930
|
+
* based on the current state of this selection.
|
|
13931
|
+
*/
|
|
13932
|
+
predicate(clauseList, active, client) {
|
|
13933
|
+
const { union } = this;
|
|
13934
|
+
if (this.skip(client, active)) return void 0;
|
|
13935
|
+
const predicates = clauseList.filter((clause) => !this.skip(client, clause)).map((clause) => clause.predicate);
|
|
13936
|
+
return union && predicates.length > 1 ? or(predicates) : predicates;
|
|
13937
|
+
}
|
|
13938
|
+
/**
|
|
13939
|
+
* Returns a filter function for queued selection updates.
|
|
13940
|
+
* @param {*} value The new event value that will be enqueued.
|
|
13941
|
+
* @returns {(value: *) => boolean|null} A dispatch queue filter
|
|
13942
|
+
* function, or null if all unemitted event values should be filtered.
|
|
13943
|
+
*/
|
|
13944
|
+
queueFilter(value) {
|
|
13945
|
+
if (this.cross) {
|
|
13946
|
+
const source = value.active?.source;
|
|
13947
|
+
return (clauses) => clauses.active?.source !== source;
|
|
13926
13948
|
}
|
|
13927
|
-
|
|
13949
|
+
return null;
|
|
13928
13950
|
}
|
|
13929
|
-
|
|
13930
|
-
|
|
13951
|
+
};
|
|
13952
|
+
|
|
13953
|
+
// ../core/src/FilterGroup.js
|
|
13954
|
+
var FilterGroup = class {
|
|
13955
|
+
/**
|
|
13956
|
+
* @param {Coordinator} coordinator The Mosaic coordinator.
|
|
13957
|
+
* @param {Selection} selection The shared filter selection.
|
|
13958
|
+
* @param {object|boolean} index Boolean flag or options hash for
|
|
13959
|
+
* a data cube indexer. Falsy values disable indexing.
|
|
13960
|
+
*/
|
|
13961
|
+
constructor(coordinator2, selection, index = true) {
|
|
13962
|
+
this.mc = coordinator2;
|
|
13963
|
+
this.selection = selection;
|
|
13964
|
+
this.clients = /* @__PURE__ */ new Set();
|
|
13965
|
+
this.indexer = null;
|
|
13966
|
+
this.index(index);
|
|
13967
|
+
const { value, activate } = this.handlers = {
|
|
13968
|
+
value: () => this.update(),
|
|
13969
|
+
activate: (clause) => {
|
|
13970
|
+
this.indexer?.index(this.clients, clause);
|
|
13971
|
+
}
|
|
13972
|
+
};
|
|
13973
|
+
selection.addEventListener("value", value);
|
|
13974
|
+
selection.addEventListener("activate", activate);
|
|
13931
13975
|
}
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
this.
|
|
13976
|
+
finalize() {
|
|
13977
|
+
const { value, activate } = this.handlers;
|
|
13978
|
+
this.selection.removeEventListener("value", value);
|
|
13979
|
+
this.selection.removeEventListener("activate", activate);
|
|
13935
13980
|
}
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
13981
|
+
index(state) {
|
|
13982
|
+
const { selection } = this;
|
|
13983
|
+
const { resolver } = selection;
|
|
13984
|
+
this.indexer = state && (resolver.single || !resolver.union) ? new DataCubeIndexer(this.mc, { ...state, selection }) : null;
|
|
13939
13985
|
}
|
|
13940
|
-
|
|
13941
|
-
|
|
13942
|
-
cache = true,
|
|
13943
|
-
priority = Priority.Normal,
|
|
13944
|
-
...options
|
|
13945
|
-
} = {}) {
|
|
13946
|
-
return this.manager.request({ type, query, cache, options }, priority);
|
|
13986
|
+
reset() {
|
|
13987
|
+
this.indexer?.reset();
|
|
13947
13988
|
}
|
|
13948
|
-
|
|
13949
|
-
|
|
13989
|
+
add(client) {
|
|
13990
|
+
(this.clients = new Set(this.clients)).add(client);
|
|
13991
|
+
return this;
|
|
13950
13992
|
}
|
|
13951
|
-
|
|
13952
|
-
|
|
13953
|
-
|
|
13993
|
+
remove(client) {
|
|
13994
|
+
if (this.clients.has(client)) {
|
|
13995
|
+
(this.clients = new Set(this.clients)).delete(client);
|
|
13996
|
+
}
|
|
13997
|
+
return this;
|
|
13954
13998
|
}
|
|
13955
|
-
|
|
13956
|
-
|
|
13957
|
-
|
|
13999
|
+
/**
|
|
14000
|
+
* Internal method to process a selection update.
|
|
14001
|
+
* The return value is passed as a selection callback value.
|
|
14002
|
+
* @returns {Promise} A Promise that resolves when the update completes.
|
|
14003
|
+
*/
|
|
14004
|
+
update() {
|
|
14005
|
+
const { mc, indexer, clients, selection } = this;
|
|
14006
|
+
const hasIndex = indexer?.index(clients);
|
|
14007
|
+
return hasIndex ? indexer.update() : defaultUpdate(mc, clients, selection);
|
|
13958
14008
|
}
|
|
13959
|
-
|
|
13960
|
-
|
|
13961
|
-
|
|
13962
|
-
|
|
13963
|
-
|
|
13964
|
-
(
|
|
13965
|
-
|
|
13966
|
-
|
|
13967
|
-
|
|
13968
|
-
|
|
14009
|
+
};
|
|
14010
|
+
function defaultUpdate(mc, clients, selection) {
|
|
14011
|
+
return Promise.all(Array.from(clients).map((client) => {
|
|
14012
|
+
const filter = selection.predicate(client);
|
|
14013
|
+
if (filter != null) {
|
|
14014
|
+
return mc.updateClient(client, client.query(filter));
|
|
14015
|
+
}
|
|
14016
|
+
}));
|
|
14017
|
+
}
|
|
14018
|
+
|
|
14019
|
+
// ../core/src/util/query-result.js
|
|
14020
|
+
function queryResult() {
|
|
14021
|
+
let resolve;
|
|
14022
|
+
let reject;
|
|
14023
|
+
const p = new Promise((r, e) => {
|
|
14024
|
+
resolve = r;
|
|
14025
|
+
reject = e;
|
|
14026
|
+
});
|
|
14027
|
+
return Object.assign(p, {
|
|
14028
|
+
fulfill: (value) => (resolve(value), p),
|
|
14029
|
+
reject: (err) => (reject(err), p)
|
|
14030
|
+
});
|
|
14031
|
+
}
|
|
14032
|
+
|
|
14033
|
+
// ../core/src/QueryConsolidator.js
|
|
14034
|
+
function wait(callback) {
|
|
14035
|
+
const method = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : typeof setImmediate !== "undefined" ? setImmediate : setTimeout;
|
|
14036
|
+
return method(callback);
|
|
14037
|
+
}
|
|
14038
|
+
function consolidator(enqueue, cache, record) {
|
|
14039
|
+
let pending = [];
|
|
14040
|
+
let id = 0;
|
|
14041
|
+
function run() {
|
|
14042
|
+
const groups = entryGroups(pending, cache);
|
|
14043
|
+
pending = [];
|
|
14044
|
+
id = 0;
|
|
14045
|
+
for (const group of groups) {
|
|
14046
|
+
consolidate(group, enqueue, record);
|
|
14047
|
+
processResults(group, cache);
|
|
14048
|
+
}
|
|
13969
14049
|
}
|
|
13970
|
-
|
|
13971
|
-
|
|
13972
|
-
|
|
14050
|
+
return {
|
|
14051
|
+
add(entry, priority) {
|
|
14052
|
+
if (entry.request.type === "arrow") {
|
|
14053
|
+
id = id || wait(() => run());
|
|
14054
|
+
pending.push({ entry, priority, index: pending.length });
|
|
14055
|
+
} else {
|
|
14056
|
+
enqueue(entry, priority);
|
|
14057
|
+
}
|
|
14058
|
+
}
|
|
14059
|
+
};
|
|
14060
|
+
}
|
|
14061
|
+
function entryGroups(entries, cache) {
|
|
14062
|
+
const groups = [];
|
|
14063
|
+
const groupMap = /* @__PURE__ */ new Map();
|
|
14064
|
+
for (const query of entries) {
|
|
14065
|
+
const { entry: { request } } = query;
|
|
14066
|
+
const key = consolidationKey(request.query, cache);
|
|
14067
|
+
if (!groupMap.has(key)) {
|
|
14068
|
+
const list = [];
|
|
14069
|
+
groups.push(list);
|
|
14070
|
+
groupMap.set(key, list);
|
|
14071
|
+
}
|
|
14072
|
+
groupMap.get(key).push(query);
|
|
13973
14073
|
}
|
|
13974
|
-
|
|
13975
|
-
|
|
13976
|
-
|
|
13977
|
-
|
|
13978
|
-
|
|
13979
|
-
|
|
13980
|
-
|
|
13981
|
-
|
|
14074
|
+
return groups;
|
|
14075
|
+
}
|
|
14076
|
+
function consolidationKey(query, cache) {
|
|
14077
|
+
const sql2 = `${query}`;
|
|
14078
|
+
if (query instanceof Query && !cache.get(sql2)) {
|
|
14079
|
+
if (
|
|
14080
|
+
// @ts-ignore
|
|
14081
|
+
query.orderby().length || query.where().length || // @ts-ignore
|
|
14082
|
+
query.qualify().length || query.having().length
|
|
14083
|
+
) {
|
|
14084
|
+
return sql2;
|
|
13982
14085
|
}
|
|
13983
|
-
|
|
13984
|
-
|
|
13985
|
-
|
|
13986
|
-
|
|
13987
|
-
|
|
14086
|
+
const q = query.clone().$select("*");
|
|
14087
|
+
const groupby = query.groupby();
|
|
14088
|
+
if (groupby.length) {
|
|
14089
|
+
const map = {};
|
|
14090
|
+
query.select().forEach(({ as, expr }) => map[as] = expr);
|
|
14091
|
+
q.$groupby(groupby.map((e) => e instanceof Ref && map[e.column] || e));
|
|
13988
14092
|
}
|
|
13989
|
-
|
|
13990
|
-
|
|
13991
|
-
|
|
13992
|
-
|
|
13993
|
-
|
|
13994
|
-
|
|
13995
|
-
|
|
14093
|
+
return `${q}`;
|
|
14094
|
+
} else {
|
|
14095
|
+
return sql2;
|
|
14096
|
+
}
|
|
14097
|
+
}
|
|
14098
|
+
function consolidate(group, enqueue, record) {
|
|
14099
|
+
if (shouldConsolidate(group)) {
|
|
14100
|
+
enqueue({
|
|
14101
|
+
request: {
|
|
14102
|
+
type: "arrow",
|
|
14103
|
+
cache: false,
|
|
14104
|
+
record: false,
|
|
14105
|
+
query: group.query = consolidatedQuery(group, record)
|
|
14106
|
+
},
|
|
14107
|
+
result: group.result = queryResult()
|
|
14108
|
+
});
|
|
14109
|
+
} else {
|
|
14110
|
+
for (const { entry, priority } of group) {
|
|
14111
|
+
enqueue(entry, priority);
|
|
14112
|
+
}
|
|
14113
|
+
}
|
|
14114
|
+
}
|
|
14115
|
+
function shouldConsolidate(group) {
|
|
14116
|
+
if (group.length > 1) {
|
|
14117
|
+
const sql2 = `${group[0].entry.request.query}`;
|
|
14118
|
+
for (let i = 1; i < group.length; ++i) {
|
|
14119
|
+
if (sql2 !== `${group[i].entry.request.query}`) {
|
|
14120
|
+
return true;
|
|
13996
14121
|
}
|
|
13997
14122
|
}
|
|
13998
|
-
client.requestQuery();
|
|
13999
14123
|
}
|
|
14000
|
-
|
|
14001
|
-
|
|
14002
|
-
|
|
14003
|
-
|
|
14004
|
-
|
|
14005
|
-
|
|
14006
|
-
const {
|
|
14007
|
-
|
|
14008
|
-
|
|
14009
|
-
|
|
14010
|
-
|
|
14124
|
+
return false;
|
|
14125
|
+
}
|
|
14126
|
+
function consolidatedQuery(group, record) {
|
|
14127
|
+
const maps = group.maps = [];
|
|
14128
|
+
const fields = /* @__PURE__ */ new Map();
|
|
14129
|
+
for (const item of group) {
|
|
14130
|
+
const { query: query2 } = item.entry.request;
|
|
14131
|
+
const fieldMap = [];
|
|
14132
|
+
maps.push(fieldMap);
|
|
14133
|
+
for (const { as, expr } of query2.select()) {
|
|
14134
|
+
const e = `${expr}`;
|
|
14135
|
+
if (!fields.has(e)) {
|
|
14136
|
+
fields.set(e, [`col${fields.size}`, expr]);
|
|
14137
|
+
}
|
|
14138
|
+
const [name] = fields.get(e);
|
|
14139
|
+
fieldMap.push([name, as]);
|
|
14140
|
+
}
|
|
14141
|
+
record(`${query2}`);
|
|
14011
14142
|
}
|
|
14012
|
-
|
|
14013
|
-
|
|
14014
|
-
|
|
14015
|
-
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
*/
|
|
14019
|
-
constructor() {
|
|
14020
|
-
this._callbacks = /* @__PURE__ */ new Map();
|
|
14143
|
+
const query = group[0].entry.request.query.clone();
|
|
14144
|
+
const groupby = query.groupby();
|
|
14145
|
+
if (groupby.length) {
|
|
14146
|
+
const map = {};
|
|
14147
|
+
group.maps[0].forEach(([name, as]) => map[as] = name);
|
|
14148
|
+
query.$groupby(groupby.map((e) => e instanceof Ref && map[e.column] || e));
|
|
14021
14149
|
}
|
|
14022
|
-
|
|
14023
|
-
|
|
14024
|
-
|
|
14025
|
-
|
|
14026
|
-
|
|
14027
|
-
|
|
14028
|
-
|
|
14029
|
-
|
|
14030
|
-
|
|
14031
|
-
|
|
14032
|
-
|
|
14033
|
-
pending: null,
|
|
14034
|
-
queue: new DispatchQueue()
|
|
14035
|
-
});
|
|
14150
|
+
return query.$select(Array.from(fields.values()));
|
|
14151
|
+
}
|
|
14152
|
+
async function processResults(group, cache) {
|
|
14153
|
+
const { maps, query, result } = group;
|
|
14154
|
+
if (!maps) return;
|
|
14155
|
+
let data;
|
|
14156
|
+
try {
|
|
14157
|
+
data = await result;
|
|
14158
|
+
} catch (err) {
|
|
14159
|
+
for (const { entry } of group) {
|
|
14160
|
+
entry.result.reject(err);
|
|
14036
14161
|
}
|
|
14037
|
-
|
|
14038
|
-
entry.callbacks.add(callback);
|
|
14162
|
+
return;
|
|
14039
14163
|
}
|
|
14040
|
-
|
|
14041
|
-
|
|
14042
|
-
|
|
14043
|
-
|
|
14044
|
-
|
|
14045
|
-
|
|
14046
|
-
|
|
14047
|
-
const entry = this._callbacks.get(type);
|
|
14048
|
-
if (entry) {
|
|
14049
|
-
entry.callbacks.delete(callback);
|
|
14164
|
+
const describe = isDescribeQuery(query);
|
|
14165
|
+
group.forEach(({ entry }, index) => {
|
|
14166
|
+
const { request, result: result2 } = entry;
|
|
14167
|
+
const map = maps[index];
|
|
14168
|
+
const extract = describe && map ? filterResult(data, map) : map ? projectResult(data, map) : data;
|
|
14169
|
+
if (request.cache) {
|
|
14170
|
+
cache.set(String(request.query), extract);
|
|
14050
14171
|
}
|
|
14172
|
+
result2.fulfill(extract);
|
|
14173
|
+
});
|
|
14174
|
+
}
|
|
14175
|
+
function projectResult(data, map) {
|
|
14176
|
+
const cols = {};
|
|
14177
|
+
for (const [name, as] of map) {
|
|
14178
|
+
cols[as] = data.getChild(name);
|
|
14051
14179
|
}
|
|
14052
|
-
|
|
14053
|
-
|
|
14054
|
-
|
|
14055
|
-
|
|
14056
|
-
|
|
14057
|
-
|
|
14058
|
-
|
|
14059
|
-
|
|
14060
|
-
|
|
14061
|
-
willEmit(type, value) {
|
|
14062
|
-
return value;
|
|
14063
|
-
}
|
|
14064
|
-
/**
|
|
14065
|
-
* Lifecycle method that returns a filter function for updating the
|
|
14066
|
-
* queue of unemitted event values prior to enqueueing a new value.
|
|
14067
|
-
* This default implementation simply returns null, indicating that
|
|
14068
|
-
* any other unemitted event values should be dropped (that is, all
|
|
14069
|
-
* queued events are filtered)
|
|
14070
|
-
* @param {string} type The event type.
|
|
14071
|
-
* @param {*} value The new event value that will be enqueued.
|
|
14072
|
-
* @returns {(value: *) => boolean|null} A dispatch queue filter
|
|
14073
|
-
* function, or null if all unemitted event values should be filtered.
|
|
14074
|
-
*/
|
|
14075
|
-
emitQueueFilter(type, value) {
|
|
14076
|
-
return null;
|
|
14180
|
+
return new data.constructor(cols);
|
|
14181
|
+
}
|
|
14182
|
+
function filterResult(data, map) {
|
|
14183
|
+
const lookup = new Map(map);
|
|
14184
|
+
const result = [];
|
|
14185
|
+
for (const d of data) {
|
|
14186
|
+
if (lookup.has(d.column_name)) {
|
|
14187
|
+
result.push({ ...d, column_name: lookup.get(d.column_name) });
|
|
14188
|
+
}
|
|
14077
14189
|
}
|
|
14078
|
-
|
|
14079
|
-
|
|
14080
|
-
|
|
14081
|
-
|
|
14082
|
-
|
|
14083
|
-
|
|
14084
|
-
|
|
14190
|
+
return result;
|
|
14191
|
+
}
|
|
14192
|
+
|
|
14193
|
+
// ../core/src/util/cache.js
|
|
14194
|
+
var requestIdle = typeof requestIdleCallback !== "undefined" ? requestIdleCallback : setTimeout;
|
|
14195
|
+
var voidCache = () => ({
|
|
14196
|
+
get: () => void 0,
|
|
14197
|
+
set: (key, value) => value,
|
|
14198
|
+
clear: () => {
|
|
14085
14199
|
}
|
|
14086
|
-
|
|
14087
|
-
|
|
14088
|
-
|
|
14089
|
-
|
|
14090
|
-
|
|
14091
|
-
|
|
14092
|
-
|
|
14093
|
-
|
|
14094
|
-
|
|
14095
|
-
|
|
14096
|
-
|
|
14097
|
-
|
|
14098
|
-
|
|
14099
|
-
|
|
14100
|
-
|
|
14101
|
-
|
|
14102
|
-
|
|
14103
|
-
|
|
14104
|
-
|
|
14105
|
-
|
|
14106
|
-
if (!queue.isEmpty()) {
|
|
14107
|
-
this.emit(type, queue.dequeue());
|
|
14108
|
-
}
|
|
14109
|
-
});
|
|
14200
|
+
});
|
|
14201
|
+
function lruCache({
|
|
14202
|
+
max: max2 = 1e3,
|
|
14203
|
+
// max entries
|
|
14204
|
+
ttl = 3 * 60 * 60 * 1e3
|
|
14205
|
+
// time-to-live, default 3 hours
|
|
14206
|
+
} = {}) {
|
|
14207
|
+
let cache = /* @__PURE__ */ new Map();
|
|
14208
|
+
function evict() {
|
|
14209
|
+
const expire = performance.now() - ttl;
|
|
14210
|
+
let lruKey = null;
|
|
14211
|
+
let lruLast = Infinity;
|
|
14212
|
+
for (const [key, value] of cache) {
|
|
14213
|
+
const { last: last2 } = value;
|
|
14214
|
+
if (last2 < lruLast) {
|
|
14215
|
+
lruKey = key;
|
|
14216
|
+
lruLast = last2;
|
|
14217
|
+
}
|
|
14218
|
+
if (expire > last2) {
|
|
14219
|
+
cache.delete(key);
|
|
14110
14220
|
}
|
|
14111
14221
|
}
|
|
14222
|
+
if (lruKey) {
|
|
14223
|
+
cache.delete(lruKey);
|
|
14224
|
+
}
|
|
14112
14225
|
}
|
|
14113
|
-
|
|
14114
|
-
|
|
14115
|
-
|
|
14116
|
-
|
|
14117
|
-
|
|
14226
|
+
return {
|
|
14227
|
+
get(key) {
|
|
14228
|
+
const entry = cache.get(key);
|
|
14229
|
+
if (entry) {
|
|
14230
|
+
entry.last = performance.now();
|
|
14231
|
+
return entry.value;
|
|
14232
|
+
}
|
|
14233
|
+
},
|
|
14234
|
+
set(key, value) {
|
|
14235
|
+
cache.set(key, { last: performance.now(), value });
|
|
14236
|
+
if (cache.size > max2) requestIdle(evict);
|
|
14237
|
+
return value;
|
|
14238
|
+
},
|
|
14239
|
+
clear() {
|
|
14240
|
+
cache = /* @__PURE__ */ new Map();
|
|
14241
|
+
}
|
|
14242
|
+
};
|
|
14243
|
+
}
|
|
14244
|
+
|
|
14245
|
+
// ../core/src/util/priority-queue.js
|
|
14246
|
+
function priorityQueue(ranks) {
|
|
14247
|
+
const queue = Array.from(
|
|
14248
|
+
{ length: ranks },
|
|
14249
|
+
() => ({ head: null, tail: null })
|
|
14250
|
+
);
|
|
14251
|
+
return {
|
|
14252
|
+
/**
|
|
14253
|
+
* Indicate if the queue is empty.
|
|
14254
|
+
* @returns [boolean] true if empty, false otherwise.
|
|
14255
|
+
*/
|
|
14256
|
+
isEmpty() {
|
|
14257
|
+
return queue.every((list) => !list.head);
|
|
14258
|
+
},
|
|
14259
|
+
/**
|
|
14260
|
+
* Insert an item into the queue with a given priority rank.
|
|
14261
|
+
* @param {*} item The item to add.
|
|
14262
|
+
* @param {number} rank The integer priority rank.
|
|
14263
|
+
* Priority ranks are integers starting at zero.
|
|
14264
|
+
* Lower ranks indicate higher priority.
|
|
14265
|
+
*/
|
|
14266
|
+
insert(item, rank2) {
|
|
14267
|
+
const list = queue[rank2];
|
|
14268
|
+
if (!list) {
|
|
14269
|
+
throw new Error(`Invalid queue priority rank: ${rank2}`);
|
|
14270
|
+
}
|
|
14271
|
+
const node = { item, next: null };
|
|
14272
|
+
if (list.head === null) {
|
|
14273
|
+
list.head = list.tail = node;
|
|
14274
|
+
} else {
|
|
14275
|
+
list.tail = list.tail.next = node;
|
|
14276
|
+
}
|
|
14277
|
+
},
|
|
14278
|
+
/**
|
|
14279
|
+
* Remove a set of items from the queue, regardless of priority rank.
|
|
14280
|
+
* If a provided item is not in the queue it will be ignored.
|
|
14281
|
+
* @param {(item: *) => boolean} test A predicate function to test
|
|
14282
|
+
* if an item should be removed (true to drop, false to keep).
|
|
14283
|
+
*/
|
|
14284
|
+
remove(test) {
|
|
14285
|
+
for (const list of queue) {
|
|
14286
|
+
let { head, tail } = list;
|
|
14287
|
+
for (let prev = null, curr = head; curr; prev = curr, curr = curr.next) {
|
|
14288
|
+
if (test(curr.item)) {
|
|
14289
|
+
if (curr === head) {
|
|
14290
|
+
head = curr.next;
|
|
14291
|
+
} else {
|
|
14292
|
+
prev.next = curr.next;
|
|
14293
|
+
}
|
|
14294
|
+
if (curr === tail) tail = prev || head;
|
|
14295
|
+
}
|
|
14296
|
+
}
|
|
14297
|
+
list.head = head;
|
|
14298
|
+
list.tail = tail;
|
|
14299
|
+
}
|
|
14300
|
+
},
|
|
14301
|
+
/**
|
|
14302
|
+
* Remove and return the next highest priority item.
|
|
14303
|
+
* @returns {*} The next item in the queue,
|
|
14304
|
+
* or undefined if this queue is empty.
|
|
14305
|
+
*/
|
|
14306
|
+
next() {
|
|
14307
|
+
for (const list of queue) {
|
|
14308
|
+
const { head } = list;
|
|
14309
|
+
if (head !== null) {
|
|
14310
|
+
list.head = head.next;
|
|
14311
|
+
if (list.tail === head) {
|
|
14312
|
+
list.tail = null;
|
|
14313
|
+
}
|
|
14314
|
+
return head.item;
|
|
14315
|
+
}
|
|
14316
|
+
}
|
|
14317
|
+
}
|
|
14318
|
+
};
|
|
14319
|
+
}
|
|
14320
|
+
|
|
14321
|
+
// ../core/src/QueryManager.js
|
|
14322
|
+
var Priority = { High: 0, Normal: 1, Low: 2 };
|
|
14323
|
+
var QueryManager = class {
|
|
14118
14324
|
constructor() {
|
|
14119
|
-
this.
|
|
14325
|
+
this.queue = priorityQueue(3);
|
|
14326
|
+
this.db = null;
|
|
14327
|
+
this.clientCache = null;
|
|
14328
|
+
this._logger = null;
|
|
14329
|
+
this._logQueries = false;
|
|
14330
|
+
this.recorders = [];
|
|
14331
|
+
this.pending = null;
|
|
14332
|
+
this._consolidate = null;
|
|
14120
14333
|
}
|
|
14121
|
-
|
|
14122
|
-
|
|
14123
|
-
|
|
14124
|
-
|
|
14125
|
-
this.
|
|
14334
|
+
next() {
|
|
14335
|
+
if (this.pending || this.queue.isEmpty()) return;
|
|
14336
|
+
const { request, result } = this.queue.next();
|
|
14337
|
+
this.pending = this.submit(request, result);
|
|
14338
|
+
this.pending.finally(() => {
|
|
14339
|
+
this.pending = null;
|
|
14340
|
+
this.next();
|
|
14341
|
+
});
|
|
14126
14342
|
}
|
|
14127
|
-
|
|
14128
|
-
|
|
14129
|
-
|
|
14130
|
-
*/
|
|
14131
|
-
isEmpty() {
|
|
14132
|
-
return !this.next;
|
|
14343
|
+
enqueue(entry, priority = Priority.Normal) {
|
|
14344
|
+
this.queue.insert(entry, priority);
|
|
14345
|
+
this.next();
|
|
14133
14346
|
}
|
|
14134
|
-
|
|
14135
|
-
|
|
14136
|
-
|
|
14137
|
-
|
|
14138
|
-
|
|
14139
|
-
|
|
14140
|
-
|
|
14141
|
-
|
|
14142
|
-
|
|
14143
|
-
|
|
14144
|
-
|
|
14145
|
-
|
|
14146
|
-
|
|
14147
|
-
|
|
14148
|
-
|
|
14149
|
-
|
|
14150
|
-
|
|
14151
|
-
|
|
14152
|
-
} else {
|
|
14153
|
-
curr.next = curr.next.next;
|
|
14347
|
+
recordQuery(sql2) {
|
|
14348
|
+
if (this.recorders.length && sql2) {
|
|
14349
|
+
this.recorders.forEach((rec) => rec.add(sql2));
|
|
14350
|
+
}
|
|
14351
|
+
}
|
|
14352
|
+
async submit(request, result) {
|
|
14353
|
+
try {
|
|
14354
|
+
const { query, type, cache = false, record = true, options } = request;
|
|
14355
|
+
const sql2 = query ? `${query}` : null;
|
|
14356
|
+
if (record) {
|
|
14357
|
+
this.recordQuery(sql2);
|
|
14358
|
+
}
|
|
14359
|
+
if (cache) {
|
|
14360
|
+
const cached = this.clientCache.get(sql2);
|
|
14361
|
+
if (cached) {
|
|
14362
|
+
this._logger.debug("Cache");
|
|
14363
|
+
result.fulfill(cached);
|
|
14364
|
+
return;
|
|
14154
14365
|
}
|
|
14155
14366
|
}
|
|
14156
|
-
|
|
14157
|
-
|
|
14158
|
-
|
|
14367
|
+
const t0 = performance.now();
|
|
14368
|
+
if (this._logQueries) {
|
|
14369
|
+
this._logger.debug("Query", { type, sql: sql2, ...options });
|
|
14370
|
+
}
|
|
14371
|
+
const data = await this.db.query({ type, sql: sql2, ...options });
|
|
14372
|
+
if (cache) this.clientCache.set(sql2, data);
|
|
14373
|
+
this._logger.debug(`Request: ${(performance.now() - t0).toFixed(1)}`);
|
|
14374
|
+
result.fulfill(data);
|
|
14375
|
+
} catch (err) {
|
|
14376
|
+
result.reject(err);
|
|
14159
14377
|
}
|
|
14160
14378
|
}
|
|
14161
|
-
|
|
14162
|
-
|
|
14163
|
-
* @returns {*} The next event value in the queue.
|
|
14164
|
-
*/
|
|
14165
|
-
dequeue() {
|
|
14166
|
-
const { next } = this;
|
|
14167
|
-
this.next = next?.next;
|
|
14168
|
-
return next?.value;
|
|
14379
|
+
cache(value) {
|
|
14380
|
+
return value !== void 0 ? this.clientCache = value === true ? lruCache() : value || voidCache() : this.clientCache;
|
|
14169
14381
|
}
|
|
14170
|
-
|
|
14171
|
-
|
|
14172
|
-
// ../core/src/util/distinct.js
|
|
14173
|
-
function distinct(a, b) {
|
|
14174
|
-
return a === b ? false : a instanceof Date && b instanceof Date ? +a !== +b : Array.isArray(a) && Array.isArray(b) ? distinctArray(a, b) : true;
|
|
14175
|
-
}
|
|
14176
|
-
function distinctArray(a, b) {
|
|
14177
|
-
if (a.length !== b.length) return true;
|
|
14178
|
-
for (let i = 0; i < a.length; ++i) {
|
|
14179
|
-
if (a[i] !== b[i]) return true;
|
|
14382
|
+
logger(value) {
|
|
14383
|
+
return value ? this._logger = value : this._logger;
|
|
14180
14384
|
}
|
|
14181
|
-
|
|
14182
|
-
|
|
14183
|
-
|
|
14184
|
-
// ../core/src/Param.js
|
|
14185
|
-
function isParam(x2) {
|
|
14186
|
-
return x2 instanceof Param;
|
|
14187
|
-
}
|
|
14188
|
-
var Param = class _Param extends AsyncDispatch {
|
|
14189
|
-
/**
|
|
14190
|
-
* Create a new Param instance.
|
|
14191
|
-
* @param {*} value The initial value of the Param.
|
|
14192
|
-
*/
|
|
14193
|
-
constructor(value) {
|
|
14194
|
-
super();
|
|
14195
|
-
this._value = value;
|
|
14385
|
+
logQueries(value) {
|
|
14386
|
+
return value !== void 0 ? this._logQueries = !!value : this._logQueries;
|
|
14196
14387
|
}
|
|
14197
|
-
|
|
14198
|
-
|
|
14199
|
-
* @param {*} value The initial value of the Param.
|
|
14200
|
-
* @returns {Param} The new Param instance.
|
|
14201
|
-
*/
|
|
14202
|
-
static value(value) {
|
|
14203
|
-
return new _Param(value);
|
|
14388
|
+
connector(connector) {
|
|
14389
|
+
return connector ? this.db = connector : this.db;
|
|
14204
14390
|
}
|
|
14205
|
-
|
|
14206
|
-
|
|
14207
|
-
|
|
14208
|
-
|
|
14209
|
-
|
|
14210
|
-
*/
|
|
14211
|
-
static array(values) {
|
|
14212
|
-
if (values.some((v) => isParam(v))) {
|
|
14213
|
-
const p = new _Param();
|
|
14214
|
-
const update2 = () => {
|
|
14215
|
-
p.update(values.map((v) => isParam(v) ? v.value : v));
|
|
14216
|
-
};
|
|
14217
|
-
update2();
|
|
14218
|
-
values.forEach((v) => isParam(v) ? v.addEventListener("value", update2) : 0);
|
|
14219
|
-
return p;
|
|
14391
|
+
consolidate(flag) {
|
|
14392
|
+
if (flag && !this._consolidate) {
|
|
14393
|
+
this._consolidate = consolidator(this.enqueue.bind(this), this.clientCache, this.recordQuery.bind(this));
|
|
14394
|
+
} else if (!flag && this._consolidate) {
|
|
14395
|
+
this._consolidate = null;
|
|
14220
14396
|
}
|
|
14221
|
-
return new _Param(values);
|
|
14222
14397
|
}
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
|
|
14228
|
-
}
|
|
14229
|
-
/**
|
|
14230
|
-
* Update the Param value
|
|
14231
|
-
* @param {*} value The new value of the Param.
|
|
14232
|
-
* @param {object} [options] The update options.
|
|
14233
|
-
* @param {boolean} [options.force] A boolean flag indicating if the Param
|
|
14234
|
-
* should emit a 'value' event even if the internal value is unchanged.
|
|
14235
|
-
* @returns {this} This Param instance.
|
|
14236
|
-
*/
|
|
14237
|
-
update(value, { force } = {}) {
|
|
14238
|
-
const shouldEmit = distinct(this._value, value) || force;
|
|
14239
|
-
if (shouldEmit) {
|
|
14240
|
-
this.emit("value", value);
|
|
14398
|
+
request(request, priority = Priority.Normal) {
|
|
14399
|
+
const result = queryResult();
|
|
14400
|
+
const entry = { request, result };
|
|
14401
|
+
if (this._consolidate) {
|
|
14402
|
+
this._consolidate.add(entry, priority);
|
|
14241
14403
|
} else {
|
|
14242
|
-
this.
|
|
14404
|
+
this.enqueue(entry, priority);
|
|
14243
14405
|
}
|
|
14244
|
-
return
|
|
14406
|
+
return result;
|
|
14245
14407
|
}
|
|
14246
|
-
|
|
14247
|
-
|
|
14248
|
-
|
|
14249
|
-
|
|
14250
|
-
|
|
14251
|
-
|
|
14252
|
-
|
|
14253
|
-
|
|
14254
|
-
|
|
14255
|
-
|
|
14256
|
-
|
|
14257
|
-
|
|
14408
|
+
cancel(requests) {
|
|
14409
|
+
const set = new Set(requests);
|
|
14410
|
+
this.queue.remove(({ result }) => set.has(result));
|
|
14411
|
+
}
|
|
14412
|
+
clear() {
|
|
14413
|
+
this.queue.remove(({ result }) => {
|
|
14414
|
+
result.reject("Cleared");
|
|
14415
|
+
return true;
|
|
14416
|
+
});
|
|
14417
|
+
}
|
|
14418
|
+
record() {
|
|
14419
|
+
let state = [];
|
|
14420
|
+
const recorder = {
|
|
14421
|
+
add(query) {
|
|
14422
|
+
state.push(query);
|
|
14423
|
+
},
|
|
14424
|
+
reset() {
|
|
14425
|
+
state = [];
|
|
14426
|
+
},
|
|
14427
|
+
snapshot() {
|
|
14428
|
+
return state.slice();
|
|
14429
|
+
},
|
|
14430
|
+
stop() {
|
|
14431
|
+
this.recorders = this.recorders.filter((x2) => x2 !== recorder);
|
|
14432
|
+
return state;
|
|
14433
|
+
}
|
|
14434
|
+
};
|
|
14435
|
+
this.recorders.push(recorder);
|
|
14436
|
+
return recorder;
|
|
14258
14437
|
}
|
|
14259
14438
|
};
|
|
14260
14439
|
|
|
14261
|
-
// ../core/src/
|
|
14262
|
-
function
|
|
14263
|
-
|
|
14440
|
+
// ../core/src/util/js-type.js
|
|
14441
|
+
function jsType(type) {
|
|
14442
|
+
switch (type) {
|
|
14443
|
+
case "BIGINT":
|
|
14444
|
+
case "HUGEINT":
|
|
14445
|
+
case "INTEGER":
|
|
14446
|
+
case "SMALLINT":
|
|
14447
|
+
case "TINYINT":
|
|
14448
|
+
case "UBIGINT":
|
|
14449
|
+
case "UINTEGER":
|
|
14450
|
+
case "USMALLINT":
|
|
14451
|
+
case "UTINYINT":
|
|
14452
|
+
case "DOUBLE":
|
|
14453
|
+
case "FLOAT":
|
|
14454
|
+
case "REAL":
|
|
14455
|
+
return "number";
|
|
14456
|
+
case "DATE":
|
|
14457
|
+
case "TIMESTAMP":
|
|
14458
|
+
case "TIMESTAMPTZ":
|
|
14459
|
+
case "TIMESTAMP WITH TIME ZONE":
|
|
14460
|
+
case "TIME":
|
|
14461
|
+
case "TIMESTAMP_NS":
|
|
14462
|
+
return "date";
|
|
14463
|
+
case "BOOLEAN":
|
|
14464
|
+
return "boolean";
|
|
14465
|
+
case "VARCHAR":
|
|
14466
|
+
case "UUID":
|
|
14467
|
+
case "JSON":
|
|
14468
|
+
return "string";
|
|
14469
|
+
case "ARRAY":
|
|
14470
|
+
case "LIST":
|
|
14471
|
+
return "array";
|
|
14472
|
+
case "BLOB":
|
|
14473
|
+
case "STRUCT":
|
|
14474
|
+
case "MAP":
|
|
14475
|
+
case "GEOMETRY":
|
|
14476
|
+
return "object";
|
|
14477
|
+
default:
|
|
14478
|
+
if (type.startsWith("DECIMAL")) {
|
|
14479
|
+
return "number";
|
|
14480
|
+
} else if (type.startsWith("STRUCT") || type.startsWith("MAP")) {
|
|
14481
|
+
return "object";
|
|
14482
|
+
} else if (type.endsWith("]")) {
|
|
14483
|
+
return "array";
|
|
14484
|
+
}
|
|
14485
|
+
throw new Error(`Unsupported type: ${type}`);
|
|
14486
|
+
}
|
|
14264
14487
|
}
|
|
14265
|
-
|
|
14266
|
-
|
|
14267
|
-
|
|
14268
|
-
|
|
14269
|
-
|
|
14270
|
-
* @param {boolean} [options.cross=false] Boolean flag indicating
|
|
14271
|
-
* cross-filtered resolution. If true, selection clauses will not
|
|
14272
|
-
* be applied to the clients they are associated with.
|
|
14273
|
-
* @returns {Selection} The new Selection instance.
|
|
14274
|
-
*/
|
|
14275
|
-
static intersect({ cross = false } = {}) {
|
|
14276
|
-
return new _Selection(new SelectionResolver({ cross }));
|
|
14488
|
+
|
|
14489
|
+
// ../core/src/util/convert-arrow.js
|
|
14490
|
+
function convertArrowValue(type) {
|
|
14491
|
+
if (DataType.isTimestamp(type)) {
|
|
14492
|
+
return (v) => v == null ? v : new Date(v);
|
|
14277
14493
|
}
|
|
14278
|
-
|
|
14279
|
-
|
|
14280
|
-
* union (disjunction) resolution strategy.
|
|
14281
|
-
* @param {object} [options] The selection options.
|
|
14282
|
-
* @param {boolean} [options.cross=false] Boolean flag indicating
|
|
14283
|
-
* cross-filtered resolution. If true, selection clauses will not
|
|
14284
|
-
* be applied to the clients they are associated with.
|
|
14285
|
-
* @returns {Selection} The new Selection instance.
|
|
14286
|
-
*/
|
|
14287
|
-
static union({ cross = false } = {}) {
|
|
14288
|
-
return new _Selection(new SelectionResolver({ cross, union: true }));
|
|
14494
|
+
if (DataType.isInt(type) && type.bitWidth >= 64) {
|
|
14495
|
+
return (v) => v == null ? v : Number(v);
|
|
14289
14496
|
}
|
|
14290
|
-
|
|
14291
|
-
|
|
14292
|
-
|
|
14293
|
-
* @param {object} [options] The selection options.
|
|
14294
|
-
* @param {boolean} [options.cross=false] Boolean flag indicating
|
|
14295
|
-
* cross-filtered resolution. If true, selection clauses will not
|
|
14296
|
-
* be applied to the clients they are associated with.
|
|
14297
|
-
* @returns {Selection} The new Selection instance.
|
|
14298
|
-
*/
|
|
14299
|
-
static single({ cross = false } = {}) {
|
|
14300
|
-
return new _Selection(new SelectionResolver({ cross, single: true }));
|
|
14497
|
+
if (DataType.isDecimal(type)) {
|
|
14498
|
+
const scale = 1 / Math.pow(10, type.scale);
|
|
14499
|
+
return (v) => v == null ? v : decimalToNumber(v, scale);
|
|
14301
14500
|
}
|
|
14302
|
-
|
|
14303
|
-
|
|
14304
|
-
|
|
14305
|
-
|
|
14306
|
-
|
|
14307
|
-
|
|
14308
|
-
|
|
14501
|
+
return (v) => v;
|
|
14502
|
+
}
|
|
14503
|
+
var BASE32 = Array.from(
|
|
14504
|
+
{ length: 8 },
|
|
14505
|
+
(_, i) => Math.pow(2, i * 32)
|
|
14506
|
+
);
|
|
14507
|
+
function decimalToNumber(v, scale) {
|
|
14508
|
+
const n = v.length;
|
|
14509
|
+
let x2 = 0;
|
|
14510
|
+
if (v.signed && (v[n - 1] | 0) < 0) {
|
|
14511
|
+
for (let i = 0; i < n; ++i) {
|
|
14512
|
+
x2 += ~v[i] * BASE32[i];
|
|
14513
|
+
}
|
|
14514
|
+
x2 = -(x2 + 1);
|
|
14515
|
+
} else {
|
|
14516
|
+
for (let i = 0; i < n; ++i) {
|
|
14517
|
+
x2 += v[i] * BASE32[i];
|
|
14518
|
+
}
|
|
14309
14519
|
}
|
|
14310
|
-
|
|
14311
|
-
|
|
14312
|
-
|
|
14313
|
-
|
|
14314
|
-
|
|
14315
|
-
|
|
14316
|
-
|
|
14317
|
-
|
|
14318
|
-
|
|
14520
|
+
return x2 * scale;
|
|
14521
|
+
}
|
|
14522
|
+
|
|
14523
|
+
// ../core/src/util/field-info.js
|
|
14524
|
+
var Count = "count";
|
|
14525
|
+
var Nulls = "nulls";
|
|
14526
|
+
var Max = "max";
|
|
14527
|
+
var Min = "min";
|
|
14528
|
+
var Distinct = "distinct";
|
|
14529
|
+
var statMap = {
|
|
14530
|
+
[Count]: count,
|
|
14531
|
+
[Distinct]: (column2) => count(column2).distinct(),
|
|
14532
|
+
[Max]: max,
|
|
14533
|
+
[Min]: min,
|
|
14534
|
+
[Nulls]: (column2) => count().where(isNull(column2))
|
|
14535
|
+
};
|
|
14536
|
+
function summarize(table2, column2, stats) {
|
|
14537
|
+
return Query.from(table2).select(Array.from(stats, (s) => [s, statMap[s](column2)]));
|
|
14538
|
+
}
|
|
14539
|
+
async function queryFieldInfo(mc, fields) {
|
|
14540
|
+
if (fields.length === 1 && `${fields[0].column}` === "*") {
|
|
14541
|
+
return getTableInfo(mc, fields[0].table);
|
|
14542
|
+
} else {
|
|
14543
|
+
return (await Promise.all(fields.map((f) => getFieldInfo(mc, f)))).filter((x2) => x2);
|
|
14319
14544
|
}
|
|
14320
|
-
|
|
14321
|
-
|
|
14322
|
-
|
|
14323
|
-
|
|
14324
|
-
|
|
14325
|
-
|
|
14326
|
-
|
|
14327
|
-
|
|
14545
|
+
}
|
|
14546
|
+
async function getFieldInfo(mc, { table: table2, column: column2, stats }) {
|
|
14547
|
+
const q = Query.from({ source: table2 }).select({ column: column2 }).groupby(column2.aggregate ? sql`ALL` : []);
|
|
14548
|
+
const [desc2] = Array.from(await mc.query(Query.describe(q)));
|
|
14549
|
+
const info = {
|
|
14550
|
+
table: table2,
|
|
14551
|
+
column: `${column2}`,
|
|
14552
|
+
sqlType: desc2.column_type,
|
|
14553
|
+
type: jsType(desc2.column_type),
|
|
14554
|
+
nullable: desc2.null === "YES"
|
|
14555
|
+
};
|
|
14556
|
+
if (!(stats?.length || stats?.size)) return info;
|
|
14557
|
+
const result = await mc.query(
|
|
14558
|
+
summarize(table2, column2, stats),
|
|
14559
|
+
{ persist: true }
|
|
14560
|
+
);
|
|
14561
|
+
for (let i = 0; i < result.numCols; ++i) {
|
|
14562
|
+
const { name } = result.schema.fields[i];
|
|
14563
|
+
const child = result.getChildAt(i);
|
|
14564
|
+
const convert = convertArrowValue(child.type);
|
|
14565
|
+
info[name] = convert(child.get(0));
|
|
14328
14566
|
}
|
|
14329
|
-
|
|
14330
|
-
|
|
14331
|
-
|
|
14332
|
-
|
|
14333
|
-
|
|
14334
|
-
|
|
14335
|
-
|
|
14336
|
-
|
|
14337
|
-
|
|
14338
|
-
|
|
14339
|
-
|
|
14567
|
+
return info;
|
|
14568
|
+
}
|
|
14569
|
+
async function getTableInfo(mc, table2) {
|
|
14570
|
+
const result = await mc.query(`DESCRIBE ${asRelation(table2)}`);
|
|
14571
|
+
return Array.from(result).map((desc2) => ({
|
|
14572
|
+
table: table2,
|
|
14573
|
+
column: desc2.column_name,
|
|
14574
|
+
sqlType: desc2.column_type,
|
|
14575
|
+
type: jsType(desc2.column_type),
|
|
14576
|
+
nullable: desc2.null === "YES"
|
|
14577
|
+
}));
|
|
14578
|
+
}
|
|
14579
|
+
|
|
14580
|
+
// ../core/src/util/void-logger.js
|
|
14581
|
+
function voidLogger() {
|
|
14582
|
+
return {
|
|
14583
|
+
debug() {
|
|
14584
|
+
},
|
|
14585
|
+
info() {
|
|
14586
|
+
},
|
|
14587
|
+
log() {
|
|
14588
|
+
},
|
|
14589
|
+
warn() {
|
|
14590
|
+
},
|
|
14591
|
+
error() {
|
|
14592
|
+
}
|
|
14593
|
+
};
|
|
14594
|
+
}
|
|
14595
|
+
|
|
14596
|
+
// ../core/src/Coordinator.js
|
|
14597
|
+
var _instance;
|
|
14598
|
+
function coordinator(instance8) {
|
|
14599
|
+
if (instance8) {
|
|
14600
|
+
_instance = instance8;
|
|
14601
|
+
} else if (_instance == null) {
|
|
14602
|
+
_instance = new Coordinator();
|
|
14340
14603
|
}
|
|
14341
|
-
|
|
14342
|
-
|
|
14343
|
-
|
|
14344
|
-
|
|
14345
|
-
|
|
14604
|
+
return _instance;
|
|
14605
|
+
}
|
|
14606
|
+
var Coordinator = class {
|
|
14607
|
+
constructor(db = socketConnector(), options = {}) {
|
|
14608
|
+
const {
|
|
14609
|
+
logger = console,
|
|
14610
|
+
manager = new QueryManager()
|
|
14611
|
+
} = options;
|
|
14612
|
+
this.manager = manager;
|
|
14613
|
+
this.logger(logger);
|
|
14614
|
+
this.configure(options);
|
|
14615
|
+
this.databaseConnector(db);
|
|
14616
|
+
this.clear();
|
|
14346
14617
|
}
|
|
14347
|
-
|
|
14348
|
-
|
|
14349
|
-
|
|
14350
|
-
|
|
14351
|
-
|
|
14352
|
-
return this.
|
|
14618
|
+
logger(logger) {
|
|
14619
|
+
if (arguments.length) {
|
|
14620
|
+
this._logger = logger || voidLogger();
|
|
14621
|
+
this.manager.logger(this._logger);
|
|
14622
|
+
}
|
|
14623
|
+
return this._logger;
|
|
14353
14624
|
}
|
|
14354
14625
|
/**
|
|
14355
|
-
*
|
|
14626
|
+
* Set configuration options for this coordinator.
|
|
14627
|
+
* @param {object} [options] Configration options.
|
|
14628
|
+
* @param {boolean} [options.cache=true] Boolean flag to enable/disable query caching.
|
|
14629
|
+
* @param {boolean} [options.consolidate=true] Boolean flag to enable/disable query consolidation.
|
|
14630
|
+
* @param {boolean|object} [options.indexes=true] Boolean flag to enable/disable
|
|
14631
|
+
* automatic data cube indexes or an index options object.
|
|
14356
14632
|
*/
|
|
14357
|
-
|
|
14358
|
-
|
|
14633
|
+
configure({ cache = true, consolidate: consolidate2 = true, indexes = true } = {}) {
|
|
14634
|
+
this.manager.cache(cache);
|
|
14635
|
+
this.manager.consolidate(consolidate2);
|
|
14636
|
+
this.indexes = indexes;
|
|
14359
14637
|
}
|
|
14360
|
-
|
|
14361
|
-
|
|
14362
|
-
|
|
14363
|
-
|
|
14364
|
-
|
|
14638
|
+
clear({ clients = true, cache = true } = {}) {
|
|
14639
|
+
this.manager.clear();
|
|
14640
|
+
if (clients) {
|
|
14641
|
+
this.clients?.forEach((client) => this.disconnect(client));
|
|
14642
|
+
this.filterGroups?.forEach((group) => group.finalize());
|
|
14643
|
+
this.clients = /* @__PURE__ */ new Set();
|
|
14644
|
+
this.filterGroups = /* @__PURE__ */ new Map();
|
|
14645
|
+
}
|
|
14646
|
+
if (cache) this.manager.cache().clear();
|
|
14365
14647
|
}
|
|
14366
|
-
|
|
14367
|
-
|
|
14368
|
-
* @param {*} clause The clause repesenting the potential activation.
|
|
14369
|
-
*/
|
|
14370
|
-
activate(clause) {
|
|
14371
|
-
this.emit("activate", clause);
|
|
14648
|
+
databaseConnector(db) {
|
|
14649
|
+
return this.manager.connector(db);
|
|
14372
14650
|
}
|
|
14373
|
-
|
|
14374
|
-
|
|
14375
|
-
|
|
14376
|
-
* @returns {this} This Selection instance.
|
|
14377
|
-
*/
|
|
14378
|
-
update(clause) {
|
|
14379
|
-
this._resolved = this._resolver.resolve(this._resolved, clause, true);
|
|
14380
|
-
this._resolved.active = clause;
|
|
14381
|
-
return super.update(this._resolved);
|
|
14651
|
+
// -- Query Management ----
|
|
14652
|
+
cancel(requests) {
|
|
14653
|
+
this.manager.cancel(requests);
|
|
14382
14654
|
}
|
|
14383
|
-
|
|
14384
|
-
|
|
14385
|
-
|
|
14386
|
-
* @param {string} type The event type.
|
|
14387
|
-
* @param {*} value The input event value.
|
|
14388
|
-
* @returns {*} For value-typed events, returns the active clause
|
|
14389
|
-
* values. Otherwise returns the input event value as-is.
|
|
14390
|
-
*/
|
|
14391
|
-
willEmit(type, value) {
|
|
14392
|
-
if (type === "value") {
|
|
14393
|
-
this._value = value;
|
|
14394
|
-
return this.value;
|
|
14395
|
-
}
|
|
14396
|
-
return value;
|
|
14655
|
+
exec(query, { priority = Priority.Normal } = {}) {
|
|
14656
|
+
query = Array.isArray(query) ? query.join(";\n") : query;
|
|
14657
|
+
return this.manager.request({ type: "exec", query }, priority);
|
|
14397
14658
|
}
|
|
14398
|
-
|
|
14399
|
-
|
|
14400
|
-
|
|
14401
|
-
|
|
14402
|
-
|
|
14403
|
-
|
|
14404
|
-
|
|
14405
|
-
*/
|
|
14406
|
-
emitQueueFilter(type, value) {
|
|
14407
|
-
return type === "value" ? this._resolver.queueFilter(value) : null;
|
|
14659
|
+
query(query, {
|
|
14660
|
+
type = "arrow",
|
|
14661
|
+
cache = true,
|
|
14662
|
+
priority = Priority.Normal,
|
|
14663
|
+
...options
|
|
14664
|
+
} = {}) {
|
|
14665
|
+
return this.manager.request({ type, query, cache, options }, priority);
|
|
14408
14666
|
}
|
|
14409
|
-
|
|
14410
|
-
|
|
14411
|
-
* The return value depends on the selection resolution strategy.
|
|
14412
|
-
* @param {*} client The selection clause.
|
|
14413
|
-
* @param {*} clause The client to test.
|
|
14414
|
-
* @returns True if the client should be skipped, false otherwise.
|
|
14415
|
-
*/
|
|
14416
|
-
skip(client, clause) {
|
|
14417
|
-
return this._resolver.skip(client, clause);
|
|
14667
|
+
prefetch(query, options = {}) {
|
|
14668
|
+
return this.query(query, { ...options, cache: true, priority: Priority.Low });
|
|
14418
14669
|
}
|
|
14419
|
-
|
|
14420
|
-
|
|
14421
|
-
|
|
14422
|
-
* @param {boolean} [noSkip=false] Disable skipping of active
|
|
14423
|
-
* cross-filtered sources. If set true, the source of the active
|
|
14424
|
-
* clause in a cross-filtered selection will not be skipped.
|
|
14425
|
-
* @returns {*} The query predicate for filtering client data,
|
|
14426
|
-
* based on the current state of this selection.
|
|
14427
|
-
*/
|
|
14428
|
-
predicate(client, noSkip = false) {
|
|
14429
|
-
const { clauses } = this;
|
|
14430
|
-
const active = noSkip ? null : clauses.active;
|
|
14431
|
-
return this._resolver.predicate(clauses, active, client);
|
|
14670
|
+
createBundle(name, queries, priority = Priority.Low) {
|
|
14671
|
+
const options = { name, queries };
|
|
14672
|
+
return this.manager.request({ type: "create-bundle", options }, priority);
|
|
14432
14673
|
}
|
|
14433
|
-
|
|
14434
|
-
|
|
14435
|
-
|
|
14436
|
-
* Create a new selection resolved instance.
|
|
14437
|
-
* @param {object} [options] The resolution strategy options.
|
|
14438
|
-
* @param {boolean} [options.union=false] Boolean flag to indicate a union strategy.
|
|
14439
|
-
* If false, an intersection strategy is used.
|
|
14440
|
-
* @param {boolean} [options.cross=false] Boolean flag to indicate cross-filtering.
|
|
14441
|
-
* @param {boolean} [options.single=false] Boolean flag to indicate single clauses only.
|
|
14442
|
-
*/
|
|
14443
|
-
constructor({ union, cross, single } = {}) {
|
|
14444
|
-
this.union = !!union;
|
|
14445
|
-
this.cross = !!cross;
|
|
14446
|
-
this.single = !!single;
|
|
14674
|
+
loadBundle(name, priority = Priority.High) {
|
|
14675
|
+
const options = { name };
|
|
14676
|
+
return this.manager.request({ type: "load-bundle", options }, priority);
|
|
14447
14677
|
}
|
|
14448
|
-
|
|
14449
|
-
|
|
14450
|
-
|
|
14451
|
-
|
|
14452
|
-
|
|
14453
|
-
|
|
14454
|
-
|
|
14455
|
-
|
|
14456
|
-
|
|
14457
|
-
|
|
14458
|
-
if (this.single && reset) filtered.forEach((c) => c.source?.reset?.());
|
|
14459
|
-
if (predicate) clauses.push(clause);
|
|
14460
|
-
return clauses;
|
|
14678
|
+
// -- Client Management ----
|
|
14679
|
+
updateClient(client, query, priority = Priority.Normal) {
|
|
14680
|
+
client.queryPending();
|
|
14681
|
+
return this.query(query, { priority }).then(
|
|
14682
|
+
(data) => client.queryResult(data).update(),
|
|
14683
|
+
(err) => {
|
|
14684
|
+
client.queryError(err);
|
|
14685
|
+
this._logger.error(err);
|
|
14686
|
+
}
|
|
14687
|
+
);
|
|
14461
14688
|
}
|
|
14462
|
-
|
|
14463
|
-
|
|
14464
|
-
|
|
14465
|
-
* @param {*} client The selection clause.
|
|
14466
|
-
* @param {*} clause The client to test.
|
|
14467
|
-
* @returns True if the client should be skipped, false otherwise.
|
|
14468
|
-
*/
|
|
14469
|
-
skip(client, clause) {
|
|
14470
|
-
return this.cross && clause?.clients?.has(client);
|
|
14689
|
+
requestQuery(client, query) {
|
|
14690
|
+
this.filterGroups.get(client.filterBy)?.reset();
|
|
14691
|
+
return query ? this.updateClient(client, query) : client.update();
|
|
14471
14692
|
}
|
|
14472
14693
|
/**
|
|
14473
|
-
*
|
|
14474
|
-
* @param {
|
|
14475
|
-
* @param {*} active The current active selection clause.
|
|
14476
|
-
* @param {*} client The client whose data may be filtered.
|
|
14477
|
-
* @returns {*} The query predicate for filtering client data,
|
|
14478
|
-
* based on the current state of this selection.
|
|
14694
|
+
* Connect a client to the coordinator.
|
|
14695
|
+
* @param {import('./MosaicClient.js').MosaicClient} client the client to disconnect
|
|
14479
14696
|
*/
|
|
14480
|
-
|
|
14481
|
-
const {
|
|
14482
|
-
if (
|
|
14483
|
-
|
|
14484
|
-
|
|
14697
|
+
async connect(client) {
|
|
14698
|
+
const { clients, filterGroups, indexes } = this;
|
|
14699
|
+
if (clients.has(client)) {
|
|
14700
|
+
throw new Error("Client already connected.");
|
|
14701
|
+
}
|
|
14702
|
+
clients.add(client);
|
|
14703
|
+
client.coordinator = this;
|
|
14704
|
+
const fields = client.fields();
|
|
14705
|
+
if (fields?.length) {
|
|
14706
|
+
client.fieldInfo(await queryFieldInfo(this, fields));
|
|
14707
|
+
}
|
|
14708
|
+
const filter = client.filterBy;
|
|
14709
|
+
if (filter) {
|
|
14710
|
+
if (filterGroups.has(filter)) {
|
|
14711
|
+
filterGroups.get(filter).add(client);
|
|
14712
|
+
} else {
|
|
14713
|
+
const group = new FilterGroup(this, filter, indexes);
|
|
14714
|
+
filterGroups.set(filter, group.add(client));
|
|
14715
|
+
}
|
|
14716
|
+
}
|
|
14717
|
+
client.requestQuery();
|
|
14485
14718
|
}
|
|
14486
14719
|
/**
|
|
14487
|
-
*
|
|
14488
|
-
*
|
|
14489
|
-
* @
|
|
14490
|
-
* function, or null if all unemitted event values should be filtered.
|
|
14720
|
+
* Disconnect a client from the coordinator.
|
|
14721
|
+
*
|
|
14722
|
+
* @param {import('./MosaicClient.js').MosaicClient} client the client to disconnect
|
|
14491
14723
|
*/
|
|
14492
|
-
|
|
14493
|
-
|
|
14494
|
-
|
|
14495
|
-
|
|
14496
|
-
|
|
14497
|
-
|
|
14724
|
+
disconnect(client) {
|
|
14725
|
+
const { clients, filterGroups } = this;
|
|
14726
|
+
if (!clients.has(client)) return;
|
|
14727
|
+
clients.delete(client);
|
|
14728
|
+
filterGroups.get(client.filterBy)?.remove(client);
|
|
14729
|
+
client.coordinator = null;
|
|
14498
14730
|
}
|
|
14499
14731
|
};
|
|
14500
14732
|
|
|
14733
|
+
// ../core/src/SelectionClause.js
|
|
14734
|
+
function point(field, value, { source, clients = void 0 }) {
|
|
14735
|
+
const predicate = value !== void 0 ? isNotDistinct(field, literal(value)) : null;
|
|
14736
|
+
return {
|
|
14737
|
+
meta: { type: "point" },
|
|
14738
|
+
source,
|
|
14739
|
+
clients,
|
|
14740
|
+
value,
|
|
14741
|
+
predicate
|
|
14742
|
+
};
|
|
14743
|
+
}
|
|
14744
|
+
function interval(field, value, {
|
|
14745
|
+
source,
|
|
14746
|
+
clients,
|
|
14747
|
+
bin,
|
|
14748
|
+
scale,
|
|
14749
|
+
pixelSize = 1
|
|
14750
|
+
}) {
|
|
14751
|
+
const predicate = value != null ? isBetween(field, value) : null;
|
|
14752
|
+
const meta = { type: "interval", scales: [scale], bin, pixelSize };
|
|
14753
|
+
return { meta, source, clients, value, predicate };
|
|
14754
|
+
}
|
|
14755
|
+
var MATCH_METHODS = { contains, prefix, suffix, regexp: regexp_matches };
|
|
14756
|
+
function match(field, value, {
|
|
14757
|
+
source,
|
|
14758
|
+
clients = void 0,
|
|
14759
|
+
method = "contains"
|
|
14760
|
+
}) {
|
|
14761
|
+
let fn = MATCH_METHODS[method];
|
|
14762
|
+
const predicate = value ? fn(field, literal(value)) : null;
|
|
14763
|
+
const meta = { type: "match", method };
|
|
14764
|
+
return { meta, source, clients, value, predicate };
|
|
14765
|
+
}
|
|
14766
|
+
|
|
14501
14767
|
// src/input.js
|
|
14502
14768
|
function input(InputClass, options) {
|
|
14503
14769
|
const input2 = new InputClass(options);
|
|
@@ -14512,8 +14778,31 @@ var isObject2 = (v) => {
|
|
|
14512
14778
|
var menu = (options) => input(Menu, options);
|
|
14513
14779
|
var Menu = class extends MosaicClient {
|
|
14514
14780
|
/**
|
|
14515
|
-
* Create a new
|
|
14516
|
-
* @param {object} options Options object
|
|
14781
|
+
* Create a new menu input.
|
|
14782
|
+
* @param {object} [options] Options object
|
|
14783
|
+
* @param {HTMLElement} [options.element] The parent DOM element in which to
|
|
14784
|
+
* place the menu elements. If undefined, a new `div` element is created.
|
|
14785
|
+
* @param {Selection} [options.filterBy] A selection to filter the database
|
|
14786
|
+
* table indicated by the *from* option.
|
|
14787
|
+
* @param {Param} [options.as] The output param or selection. A selection
|
|
14788
|
+
* clause is added for the currently selected menu option.
|
|
14789
|
+
* @param {string} [options.field] The database column name to use within
|
|
14790
|
+
* generated selection clause predicates. Defaults to the *column* option.
|
|
14791
|
+
* @param {(any | { value: any, label?: string })[]} [options.options] An
|
|
14792
|
+
* array of menu options, as literal values or option objects. Option
|
|
14793
|
+
* objects have a `value` property and an optional `label` property. If no
|
|
14794
|
+
* label or *format* function is provided, the string-coerced value is used.
|
|
14795
|
+
* @param {(value: any) => string} [options.format] A format function that
|
|
14796
|
+
* takes an option value as input and generates a string label. The format
|
|
14797
|
+
* function is not applied when an explicit label is provided in an option
|
|
14798
|
+
* object.
|
|
14799
|
+
* @param {*} [options.value] The initial selected menu value.
|
|
14800
|
+
* @param {string} [options.from] The name of a database table to use as a data
|
|
14801
|
+
* source for this widget. Used in conjunction with the *column* option.
|
|
14802
|
+
* @param {string} [options.column] The name of a database column from which
|
|
14803
|
+
* to pull menu options. The unique column values are used as menu options.
|
|
14804
|
+
* Used in conjunction with the *from* option.
|
|
14805
|
+
* @param {string} [options.label] A text label for this input.
|
|
14517
14806
|
*/
|
|
14518
14807
|
constructor({
|
|
14519
14808
|
element,
|
|
@@ -14525,32 +14814,37 @@ var Menu = class extends MosaicClient {
|
|
|
14525
14814
|
// TODO
|
|
14526
14815
|
options,
|
|
14527
14816
|
value,
|
|
14817
|
+
field = column2,
|
|
14528
14818
|
as
|
|
14529
14819
|
} = {}) {
|
|
14530
14820
|
super(filterBy);
|
|
14531
14821
|
this.from = from;
|
|
14532
14822
|
this.column = column2;
|
|
14533
|
-
this.selection = as;
|
|
14534
14823
|
this.format = format2;
|
|
14824
|
+
this.field = field;
|
|
14825
|
+
const selection = this.selection = as;
|
|
14535
14826
|
this.element = element ?? document.createElement("div");
|
|
14536
14827
|
this.element.setAttribute("class", "input");
|
|
14537
|
-
this.element
|
|
14828
|
+
Object.defineProperty(this.element, "value", { value: this });
|
|
14538
14829
|
const lab = document.createElement("label");
|
|
14539
14830
|
lab.innerText = label || column2;
|
|
14540
14831
|
this.element.appendChild(lab);
|
|
14541
14832
|
this.select = document.createElement("select");
|
|
14833
|
+
this.element.appendChild(this.select);
|
|
14542
14834
|
if (options) {
|
|
14543
14835
|
this.data = options.map((value2) => isObject2(value2) ? value2 : { value: value2 });
|
|
14836
|
+
this.selectedValue(value ?? "");
|
|
14544
14837
|
this.update();
|
|
14545
14838
|
}
|
|
14546
|
-
|
|
14547
|
-
|
|
14548
|
-
|
|
14549
|
-
|
|
14839
|
+
if (selection) {
|
|
14840
|
+
const isParam2 = !isSelection(selection);
|
|
14841
|
+
if (value != null && (!isParam2 || selection.value === void 0)) {
|
|
14842
|
+
this.publish(value);
|
|
14843
|
+
}
|
|
14550
14844
|
this.select.addEventListener("input", () => {
|
|
14551
14845
|
this.publish(this.selectedValue() ?? null);
|
|
14552
14846
|
});
|
|
14553
|
-
if (
|
|
14847
|
+
if (isParam2) {
|
|
14554
14848
|
this.selection.addEventListener("value", (value2) => {
|
|
14555
14849
|
if (value2 !== this.select.value) {
|
|
14556
14850
|
this.selectedValue(value2);
|
|
@@ -14576,14 +14870,11 @@ var Menu = class extends MosaicClient {
|
|
|
14576
14870
|
this.select.selectedIndex = this.from ? 0 : -1;
|
|
14577
14871
|
}
|
|
14578
14872
|
publish(value) {
|
|
14579
|
-
const { selection,
|
|
14873
|
+
const { selection, field } = this;
|
|
14580
14874
|
if (isSelection(selection)) {
|
|
14581
|
-
|
|
14582
|
-
|
|
14583
|
-
|
|
14584
|
-
value,
|
|
14585
|
-
predicate: value !== "" && value !== void 0 ? eq(column2, literal(value)) : null
|
|
14586
|
-
});
|
|
14875
|
+
if (value === "") value = void 0;
|
|
14876
|
+
const clause = point(field, value, { source: this });
|
|
14877
|
+
selection.update(clause);
|
|
14587
14878
|
} else if (isParam(selection)) {
|
|
14588
14879
|
selection.update(value);
|
|
14589
14880
|
}
|
|
@@ -14598,7 +14889,7 @@ var Menu = class extends MosaicClient {
|
|
|
14598
14889
|
return this;
|
|
14599
14890
|
}
|
|
14600
14891
|
update() {
|
|
14601
|
-
const { data, format: format2, select } = this;
|
|
14892
|
+
const { data, format: format2, select, selection } = this;
|
|
14602
14893
|
select.replaceChildren();
|
|
14603
14894
|
for (const { value, label } of data) {
|
|
14604
14895
|
const opt = document.createElement("option");
|
|
@@ -14606,21 +14897,42 @@ var Menu = class extends MosaicClient {
|
|
|
14606
14897
|
opt.innerText = label ?? format2(value);
|
|
14607
14898
|
this.select.appendChild(opt);
|
|
14608
14899
|
}
|
|
14609
|
-
if (
|
|
14610
|
-
|
|
14900
|
+
if (selection) {
|
|
14901
|
+
const value = isSelection(selection) ? selection.valueFor(this) : selection.value;
|
|
14902
|
+
this.selectedValue(value ?? "");
|
|
14611
14903
|
}
|
|
14612
14904
|
return this;
|
|
14613
14905
|
}
|
|
14614
14906
|
};
|
|
14615
14907
|
|
|
14616
14908
|
// src/Search.js
|
|
14617
|
-
var FUNCTIONS = { contains, prefix, suffix, regexp: regexp_matches };
|
|
14618
14909
|
var _id = 0;
|
|
14619
14910
|
var search = (options) => input(Search, options);
|
|
14620
14911
|
var Search = class extends MosaicClient {
|
|
14621
14912
|
/**
|
|
14622
|
-
* Create a new
|
|
14623
|
-
* @param {object} options Options object
|
|
14913
|
+
* Create a new text search input.
|
|
14914
|
+
* @param {object} [options] Options object
|
|
14915
|
+
* @param {HTMLElement} [options.element] The parent DOM element in which to
|
|
14916
|
+
* place the search elements. If undefined, a new `div` element is created.
|
|
14917
|
+
* @param {Selection} [options.filterBy] A selection to filter the database
|
|
14918
|
+
* table indicated by the *from* option.
|
|
14919
|
+
* @param {Param} [options.as] The output param or selection. A selection
|
|
14920
|
+
* clause is added based on the current text search query.
|
|
14921
|
+
* @param {string} [options.field] The database column name to use within
|
|
14922
|
+
* generated selection clause predicates. Defaults to the *column* option.
|
|
14923
|
+
* @param {'contains' | 'prefix' | 'suffix' | 'regexp'} [options.type] The
|
|
14924
|
+
* type of text search query to perform. One of:
|
|
14925
|
+
* - `"contains"` (default): the query string may appear anywhere in the text
|
|
14926
|
+
* - `"prefix"`: the query string must appear at the start of the text
|
|
14927
|
+
* - `"suffix"`: the query string must appear at the end of the text
|
|
14928
|
+
* - `"regexp"`: the query string is a regular expression the text must match
|
|
14929
|
+
* @param {string} [options.from] The name of a database table to use as an
|
|
14930
|
+
* autocomplete data source for this widget. Used in conjunction with the
|
|
14931
|
+
* *column* option.
|
|
14932
|
+
* @param {string} [options.column] The name of a database column from which
|
|
14933
|
+
* to pull valid search results. The unique column values are used as search
|
|
14934
|
+
* autocomplete values. Used in conjunction with the *from* option.
|
|
14935
|
+
* @param {string} [options.label] A text label for this input.
|
|
14624
14936
|
*/
|
|
14625
14937
|
constructor({
|
|
14626
14938
|
element,
|
|
@@ -14629,6 +14941,7 @@ var Search = class extends MosaicClient {
|
|
|
14629
14941
|
column: column2,
|
|
14630
14942
|
label,
|
|
14631
14943
|
type = "contains",
|
|
14944
|
+
field = column2,
|
|
14632
14945
|
as
|
|
14633
14946
|
} = {}) {
|
|
14634
14947
|
super(filterBy);
|
|
@@ -14637,9 +14950,10 @@ var Search = class extends MosaicClient {
|
|
|
14637
14950
|
this.from = from;
|
|
14638
14951
|
this.column = column2;
|
|
14639
14952
|
this.selection = as;
|
|
14953
|
+
this.field = field;
|
|
14640
14954
|
this.element = element ?? document.createElement("div");
|
|
14641
14955
|
this.element.setAttribute("class", "input");
|
|
14642
|
-
this.element
|
|
14956
|
+
Object.defineProperty(this.element, "value", { value: this });
|
|
14643
14957
|
if (label) {
|
|
14644
14958
|
const lab = document.createElement("label");
|
|
14645
14959
|
lab.setAttribute("for", this.id);
|
|
@@ -14668,14 +14982,10 @@ var Search = class extends MosaicClient {
|
|
|
14668
14982
|
this.searchbox.value = "";
|
|
14669
14983
|
}
|
|
14670
14984
|
publish(value) {
|
|
14671
|
-
const { selection,
|
|
14985
|
+
const { selection, field, type } = this;
|
|
14672
14986
|
if (isSelection(selection)) {
|
|
14673
|
-
|
|
14674
|
-
|
|
14675
|
-
schema: { type },
|
|
14676
|
-
value,
|
|
14677
|
-
predicate: value ? FUNCTIONS[type](column2, literal(value)) : null
|
|
14678
|
-
});
|
|
14987
|
+
const clause = match(field, value, { source: this, method: type });
|
|
14988
|
+
selection.update(clause);
|
|
14679
14989
|
} else if (isParam(selection)) {
|
|
14680
14990
|
selection.update(value);
|
|
14681
14991
|
}
|
|
@@ -14710,8 +15020,34 @@ var _id2 = 0;
|
|
|
14710
15020
|
var slider = (options) => input(Slider, options);
|
|
14711
15021
|
var Slider = class extends MosaicClient {
|
|
14712
15022
|
/**
|
|
14713
|
-
* Create a new
|
|
14714
|
-
* @param {object} options Options object
|
|
15023
|
+
* Create a new slider input.
|
|
15024
|
+
* @param {object} [options] Options object
|
|
15025
|
+
* @param {HTMLElement} [options.element] The parent DOM element in which to
|
|
15026
|
+
* place the slider elements. If undefined, a new `div` element is created.
|
|
15027
|
+
* @param {Selection} [options.filterBy] A selection to filter the database
|
|
15028
|
+
* table indicated by the *from* option.
|
|
15029
|
+
* @param {Param} [options.as] The output param or selection. A selection
|
|
15030
|
+
* clause is added based on the currently selected slider option.
|
|
15031
|
+
* @param {string} [options.field] The database column name to use within
|
|
15032
|
+
* generated selection clause predicates. Defaults to the *column* option.
|
|
15033
|
+
* @param {'point' | 'interval'} [options.select] The type of selection clause
|
|
15034
|
+
* predicate to generate if the **as** option is a Selection. If `'point'`
|
|
15035
|
+
* (the default), the selection predicate is an equality check for the slider
|
|
15036
|
+
* value. If `'interval'`, the predicate checks an interval from the minimum
|
|
15037
|
+
* to the current slider value.
|
|
15038
|
+
* @param {number} [options.min] The minimum slider value.
|
|
15039
|
+
* @param {number} [options.max] The maximum slider value.
|
|
15040
|
+
* @param {number} [options.step] The slider step, the amount to increment
|
|
15041
|
+
* between consecutive values.
|
|
15042
|
+
* @param {number} [options.value] The initial slider value.
|
|
15043
|
+
* @param {string} [options.from] The name of a database table to use as a data
|
|
15044
|
+
* source for this widget. Used in conjunction with the *column* option.
|
|
15045
|
+
* The minimum and maximum values of the column determine the slider range.
|
|
15046
|
+
* @param {string} [options.column] The name of a database column whose values
|
|
15047
|
+
* determine the slider range. Used in conjunction with the *from* option.
|
|
15048
|
+
* The minimum and maximum values of the column determine the slider range.
|
|
15049
|
+
* @param {string} [options.label] A text label for this input.
|
|
15050
|
+
* @param {number} [options.width] The width of the slider in screen pixels.
|
|
14715
15051
|
*/
|
|
14716
15052
|
constructor({
|
|
14717
15053
|
element,
|
|
@@ -14724,6 +15060,8 @@ var Slider = class extends MosaicClient {
|
|
|
14724
15060
|
column: column2,
|
|
14725
15061
|
label = column2,
|
|
14726
15062
|
value = as?.value,
|
|
15063
|
+
select = "point",
|
|
15064
|
+
field = column2,
|
|
14727
15065
|
width
|
|
14728
15066
|
} = {}) {
|
|
14729
15067
|
super(filterBy);
|
|
@@ -14731,41 +15069,49 @@ var Slider = class extends MosaicClient {
|
|
|
14731
15069
|
this.from = from;
|
|
14732
15070
|
this.column = column2 || "value";
|
|
14733
15071
|
this.selection = as;
|
|
15072
|
+
this.selectionType = select;
|
|
15073
|
+
this.field = field;
|
|
14734
15074
|
this.min = min2;
|
|
14735
15075
|
this.max = max2;
|
|
14736
15076
|
this.step = step;
|
|
14737
15077
|
this.element = element || document.createElement("div");
|
|
14738
15078
|
this.element.setAttribute("class", "input");
|
|
14739
|
-
this.element
|
|
15079
|
+
Object.defineProperty(this.element, "value", { value: this });
|
|
14740
15080
|
if (label) {
|
|
14741
|
-
const
|
|
14742
|
-
|
|
14743
|
-
|
|
14744
|
-
this.element.appendChild(
|
|
15081
|
+
const desc2 = document.createElement("label");
|
|
15082
|
+
desc2.setAttribute("for", this.id);
|
|
15083
|
+
desc2.innerText = label;
|
|
15084
|
+
this.element.appendChild(desc2);
|
|
14745
15085
|
}
|
|
14746
15086
|
this.slider = document.createElement("input");
|
|
14747
15087
|
this.slider.setAttribute("id", this.id);
|
|
14748
15088
|
this.slider.setAttribute("type", "range");
|
|
14749
15089
|
if (width != null) this.slider.style.width = `${+width}px`;
|
|
14750
|
-
if (min2 != null) this.slider.setAttribute("min", min2);
|
|
14751
|
-
if (max2 != null) this.slider.setAttribute("max", max2);
|
|
14752
|
-
if (step != null) this.slider.setAttribute("step", step);
|
|
15090
|
+
if (min2 != null) this.slider.setAttribute("min", `${min2}`);
|
|
15091
|
+
if (max2 != null) this.slider.setAttribute("max", `${max2}`);
|
|
15092
|
+
if (step != null) this.slider.setAttribute("step", `${step}`);
|
|
15093
|
+
this.element.appendChild(this.slider);
|
|
15094
|
+
this.curval = document.createElement("label");
|
|
15095
|
+
this.curval.setAttribute("for", this.id);
|
|
15096
|
+
this.curval.setAttribute("class", "value");
|
|
15097
|
+
this.element.appendChild(this.curval);
|
|
14753
15098
|
if (value != null) {
|
|
14754
|
-
this.slider.setAttribute("value", value);
|
|
15099
|
+
this.slider.setAttribute("value", `${value}`);
|
|
14755
15100
|
if (this.selection?.value === void 0) this.publish(value);
|
|
14756
15101
|
}
|
|
14757
|
-
this.
|
|
14758
|
-
|
|
14759
|
-
this.slider
|
|
14760
|
-
|
|
15102
|
+
this.curval.innerText = this.slider.value;
|
|
15103
|
+
this.slider.addEventListener("input", () => {
|
|
15104
|
+
const { value: value2 } = this.slider;
|
|
15105
|
+
this.curval.innerText = value2;
|
|
15106
|
+
if (this.selection) this.publish(+value2);
|
|
15107
|
+
});
|
|
15108
|
+
if (this.selection && !isSelection(this.selection)) {
|
|
15109
|
+
this.selection.addEventListener("value", (value2) => {
|
|
15110
|
+
if (value2 !== +this.slider.value) {
|
|
15111
|
+
this.slider.value = value2;
|
|
15112
|
+
this.curval.innerText = value2;
|
|
15113
|
+
}
|
|
14761
15114
|
});
|
|
14762
|
-
if (!isSelection(this.selection)) {
|
|
14763
|
-
this.selection.addEventListener("value", (value2) => {
|
|
14764
|
-
if (value2 !== +this.slider.value) {
|
|
14765
|
-
this.slider.value = value2;
|
|
14766
|
-
}
|
|
14767
|
-
});
|
|
14768
|
-
}
|
|
14769
15115
|
}
|
|
14770
15116
|
}
|
|
14771
15117
|
query(filter = []) {
|
|
@@ -14775,20 +15121,34 @@ var Slider = class extends MosaicClient {
|
|
|
14775
15121
|
}
|
|
14776
15122
|
queryResult(data) {
|
|
14777
15123
|
const { min: min2, max: max2 } = Array.from(data)[0];
|
|
14778
|
-
if (this.min == null)
|
|
14779
|
-
|
|
14780
|
-
|
|
15124
|
+
if (this.min == null) {
|
|
15125
|
+
this.min = min2;
|
|
15126
|
+
this.slider.setAttribute("min", `${min2}`);
|
|
15127
|
+
}
|
|
15128
|
+
if (this.max == null) {
|
|
15129
|
+
this.max = max2;
|
|
15130
|
+
this.slider.setAttribute("max", `${max2}`);
|
|
15131
|
+
}
|
|
15132
|
+
if (this.step == null) {
|
|
15133
|
+
this.step = (max2 - min2) / 500;
|
|
15134
|
+
this.slider.setAttribute("step", `${this.step}`);
|
|
15135
|
+
}
|
|
14781
15136
|
return this;
|
|
14782
15137
|
}
|
|
14783
15138
|
publish(value) {
|
|
14784
|
-
const {
|
|
15139
|
+
const { field, selectionType, selection } = this;
|
|
14785
15140
|
if (isSelection(selection)) {
|
|
14786
|
-
|
|
14787
|
-
|
|
14788
|
-
|
|
14789
|
-
|
|
14790
|
-
|
|
14791
|
-
|
|
15141
|
+
if (selectionType === "interval") {
|
|
15142
|
+
const domain = [this.min ?? 0, value];
|
|
15143
|
+
selection.update(interval(field, domain, {
|
|
15144
|
+
source: this,
|
|
15145
|
+
bin: "ceil",
|
|
15146
|
+
scale: { type: "identity", domain },
|
|
15147
|
+
pixelSize: this.step
|
|
15148
|
+
}));
|
|
15149
|
+
} else {
|
|
15150
|
+
selection.update(point(field, value, { source: this }));
|
|
15151
|
+
}
|
|
14792
15152
|
} else if (isParam(this.selection)) {
|
|
14793
15153
|
selection.update(value);
|
|
14794
15154
|
}
|
|
@@ -14866,7 +15226,7 @@ var Table2 = class extends MosaicClient {
|
|
|
14866
15226
|
this.sortDesc = false;
|
|
14867
15227
|
this.element = element || document.createElement("div");
|
|
14868
15228
|
this.element.setAttribute("id", this.id);
|
|
14869
|
-
this.element
|
|
15229
|
+
Object.defineProperty(this.element, "value", { value: this });
|
|
14870
15230
|
if (typeof width === "number") this.element.style.width = `${width}px`;
|
|
14871
15231
|
if (maxWidth) this.element.style.maxWidth = `${maxWidth}px`;
|
|
14872
15232
|
this.element.style.maxHeight = `${height}px`;
|