@uwdata/mosaic-core 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-core.js +1588 -1273
- package/dist/mosaic-core.min.js +8 -8
- package/package.json +5 -5
- package/src/Coordinator.js +1 -1
- package/src/DataCubeIndexer.js +74 -120
- package/src/FilterGroup.js +20 -9
- package/src/QueryManager.js +101 -93
- package/src/Selection.js +26 -11
- package/src/SelectionClause.js +147 -0
- package/src/connectors/rest.js +7 -0
- package/src/connectors/socket.js +7 -0
- package/src/connectors/wasm.js +2 -2
- package/src/index.js +1 -0
- package/src/util/convert-arrow.js +14 -5
- package/src/util/index-columns.js +538 -0
- package/src/util/selection-types.ts +137 -0
package/dist/mosaic-core.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);
|
|
@@ -12050,6 +12057,12 @@ function sql(strings, ...exprs) {
|
|
|
12050
12057
|
return new SQLExpression(spans, cols);
|
|
12051
12058
|
}
|
|
12052
12059
|
|
|
12060
|
+
// ../sql/src/literal.js
|
|
12061
|
+
var literal = (value) => ({
|
|
12062
|
+
value,
|
|
12063
|
+
toString: () => literalToSQL(value)
|
|
12064
|
+
});
|
|
12065
|
+
|
|
12053
12066
|
// ../sql/src/operators.js
|
|
12054
12067
|
function visit(callback) {
|
|
12055
12068
|
callback(this.op, this);
|
|
@@ -12248,6 +12261,9 @@ var last_value = winf("LAST_VALUE");
|
|
|
12248
12261
|
var nth_value = winf("NTH_VALUE");
|
|
12249
12262
|
|
|
12250
12263
|
// ../sql/src/aggregates.js
|
|
12264
|
+
function agg(strings, ...exprs) {
|
|
12265
|
+
return sql(strings, ...exprs).annotate({ aggregate: true });
|
|
12266
|
+
}
|
|
12251
12267
|
var AggregateFunction = class _AggregateFunction extends SQLExpression {
|
|
12252
12268
|
/**
|
|
12253
12269
|
* Create a new AggregateFunction instance.
|
|
@@ -12378,6 +12394,7 @@ var entropy = aggf("ENTROPY");
|
|
|
12378
12394
|
var varPop = aggf("VAR_POP");
|
|
12379
12395
|
var stddevPop = aggf("STDDEV_POP");
|
|
12380
12396
|
var corr = aggf("CORR");
|
|
12397
|
+
var covariance = aggf("COVAR_SAMP");
|
|
12381
12398
|
var covarPop = aggf("COVAR_POP");
|
|
12382
12399
|
var regrIntercept = aggf("REGR_INTERCEPT");
|
|
12383
12400
|
var regrSlope = aggf("REGR_SLOPE");
|
|
@@ -12520,7 +12537,8 @@ var Query = class _Query {
|
|
|
12520
12537
|
}
|
|
12521
12538
|
}
|
|
12522
12539
|
}
|
|
12523
|
-
|
|
12540
|
+
const keys = new Set(list.map((x3) => x3.as));
|
|
12541
|
+
query.select = query.select.filter((x3) => !keys.has(x3.as)).concat(list.filter((x3) => x3.expr));
|
|
12524
12542
|
return this;
|
|
12525
12543
|
}
|
|
12526
12544
|
}
|
|
@@ -12993,6 +13011,7 @@ function scaleTime() {
|
|
|
12993
13011
|
};
|
|
12994
13012
|
}
|
|
12995
13013
|
var scales = {
|
|
13014
|
+
identity: scaleLinear,
|
|
12996
13015
|
linear: scaleLinear,
|
|
12997
13016
|
log: scaleLog,
|
|
12998
13017
|
symlog: scaleSymlog,
|
|
@@ -13038,6 +13057,247 @@ function fnv_mix(a2) {
|
|
|
13038
13057
|
return a2 & 4294967295;
|
|
13039
13058
|
}
|
|
13040
13059
|
|
|
13060
|
+
// src/util/index-columns.js
|
|
13061
|
+
var NO_INDEX = { from: NaN };
|
|
13062
|
+
function indexColumns(client) {
|
|
13063
|
+
if (!client.filterIndexable) return NO_INDEX;
|
|
13064
|
+
const q2 = client.query();
|
|
13065
|
+
const from = getBaseTable(q2);
|
|
13066
|
+
if (typeof from !== "string" || !q2.groupby) return NO_INDEX;
|
|
13067
|
+
const g2 = new Set(q2.groupby().map((c) => c.column));
|
|
13068
|
+
const aggr = [];
|
|
13069
|
+
const dims = [];
|
|
13070
|
+
const aux = {};
|
|
13071
|
+
for (const entry of q2.select()) {
|
|
13072
|
+
const { as, expr: { aggregate, args } } = entry;
|
|
13073
|
+
const op = aggregate?.toUpperCase?.();
|
|
13074
|
+
switch (op) {
|
|
13075
|
+
case "COUNT":
|
|
13076
|
+
case "SUM":
|
|
13077
|
+
aggr.push({ [as]: agg`SUM("${as}")::DOUBLE` });
|
|
13078
|
+
break;
|
|
13079
|
+
case "AVG":
|
|
13080
|
+
aggr.push({ [as]: avgExpr(aux, as, args[0]) });
|
|
13081
|
+
break;
|
|
13082
|
+
case "ARG_MAX":
|
|
13083
|
+
aggr.push({ [as]: argmaxExpr(aux, as, args) });
|
|
13084
|
+
break;
|
|
13085
|
+
case "ARG_MIN":
|
|
13086
|
+
aggr.push({ [as]: argminExpr(aux, as, args) });
|
|
13087
|
+
break;
|
|
13088
|
+
case "VARIANCE":
|
|
13089
|
+
case "VAR_SAMP":
|
|
13090
|
+
aux[as] = null;
|
|
13091
|
+
aggr.push({ [as]: varianceExpr(aux, args[0], from) });
|
|
13092
|
+
break;
|
|
13093
|
+
case "VAR_POP":
|
|
13094
|
+
aux[as] = null;
|
|
13095
|
+
aggr.push({ [as]: varianceExpr(aux, args[0], from, false) });
|
|
13096
|
+
break;
|
|
13097
|
+
case "STDDEV":
|
|
13098
|
+
case "STDDEV_SAMP":
|
|
13099
|
+
aux[as] = null;
|
|
13100
|
+
aggr.push({ [as]: agg`SQRT(${varianceExpr(aux, args[0], from)})` });
|
|
13101
|
+
break;
|
|
13102
|
+
case "STDDEV_POP":
|
|
13103
|
+
aux[as] = null;
|
|
13104
|
+
aggr.push({ [as]: agg`SQRT(${varianceExpr(aux, args[0], from, false)})` });
|
|
13105
|
+
break;
|
|
13106
|
+
case "COVAR_SAMP":
|
|
13107
|
+
aux[as] = null;
|
|
13108
|
+
aggr.push({ [as]: covarianceExpr(aux, args, from) });
|
|
13109
|
+
break;
|
|
13110
|
+
case "COVAR_POP":
|
|
13111
|
+
aux[as] = null;
|
|
13112
|
+
aggr.push({ [as]: covarianceExpr(aux, args, from, false) });
|
|
13113
|
+
break;
|
|
13114
|
+
case "CORR":
|
|
13115
|
+
aux[as] = null;
|
|
13116
|
+
aggr.push({ [as]: corrExpr(aux, args, from) });
|
|
13117
|
+
break;
|
|
13118
|
+
case "REGR_COUNT":
|
|
13119
|
+
aux[as] = null;
|
|
13120
|
+
aggr.push({ [as]: agg`${regrCountExpr(aux, args)}::DOUBLE` });
|
|
13121
|
+
break;
|
|
13122
|
+
case "REGR_AVGX":
|
|
13123
|
+
aux[as] = null;
|
|
13124
|
+
aggr.push({ [as]: regrAvgXExpr(aux, args) });
|
|
13125
|
+
break;
|
|
13126
|
+
case "REGR_AVGY":
|
|
13127
|
+
aux[as] = null;
|
|
13128
|
+
aggr.push({ [as]: regrAvgYExpr(aux, args) });
|
|
13129
|
+
break;
|
|
13130
|
+
case "REGR_SYY":
|
|
13131
|
+
aux[as] = null;
|
|
13132
|
+
aggr.push({ [as]: regrVarExpr(aux, 0, args, from) });
|
|
13133
|
+
break;
|
|
13134
|
+
case "REGR_SXX":
|
|
13135
|
+
aux[as] = null;
|
|
13136
|
+
aggr.push({ [as]: regrVarExpr(aux, 1, args, from) });
|
|
13137
|
+
break;
|
|
13138
|
+
case "REGR_SXY":
|
|
13139
|
+
aux[as] = null;
|
|
13140
|
+
aggr.push({ [as]: covarianceExpr(aux, args, from, null) });
|
|
13141
|
+
break;
|
|
13142
|
+
case "REGR_SLOPE":
|
|
13143
|
+
aux[as] = null;
|
|
13144
|
+
aggr.push({ [as]: regrSlopeExpr(aux, args, from) });
|
|
13145
|
+
break;
|
|
13146
|
+
case "REGR_INTERCEPT":
|
|
13147
|
+
aux[as] = null;
|
|
13148
|
+
aggr.push({ [as]: regrInterceptExpr(aux, args, from) });
|
|
13149
|
+
break;
|
|
13150
|
+
case "REGR_R2":
|
|
13151
|
+
aux[as] = null;
|
|
13152
|
+
aggr.push({ [as]: agg`(${corrExpr(aux, args, from)}) ** 2` });
|
|
13153
|
+
break;
|
|
13154
|
+
case "MAX":
|
|
13155
|
+
case "MIN":
|
|
13156
|
+
case "BIT_AND":
|
|
13157
|
+
case "BIT_OR":
|
|
13158
|
+
case "BIT_XOR":
|
|
13159
|
+
case "BOOL_AND":
|
|
13160
|
+
case "BOOL_OR":
|
|
13161
|
+
case "PRODUCT":
|
|
13162
|
+
aggr.push({ [as]: agg`${op}("${as}")` });
|
|
13163
|
+
break;
|
|
13164
|
+
default:
|
|
13165
|
+
if (g2.has(as)) dims.push(as);
|
|
13166
|
+
else return null;
|
|
13167
|
+
}
|
|
13168
|
+
}
|
|
13169
|
+
return { from, dims, aggr, aux };
|
|
13170
|
+
}
|
|
13171
|
+
function auxName(type, ...args) {
|
|
13172
|
+
const cols = args.length ? "_" + args.map(sanitize).join("_") : "";
|
|
13173
|
+
return `__${type}${cols}__`;
|
|
13174
|
+
}
|
|
13175
|
+
function sanitize(col) {
|
|
13176
|
+
return `${col}`.replaceAll('"', "").replaceAll(" ", "_");
|
|
13177
|
+
}
|
|
13178
|
+
function getBaseTable(query) {
|
|
13179
|
+
const subq = query.subqueries;
|
|
13180
|
+
if (query.select) {
|
|
13181
|
+
const from = query.from();
|
|
13182
|
+
if (!from.length) return void 0;
|
|
13183
|
+
if (subq.length === 0) return from[0].from.table;
|
|
13184
|
+
}
|
|
13185
|
+
const base = getBaseTable(subq[0]);
|
|
13186
|
+
for (let i = 1; i < subq.length; ++i) {
|
|
13187
|
+
const from = getBaseTable(subq[i]);
|
|
13188
|
+
if (from === void 0) continue;
|
|
13189
|
+
if (from !== base) return NaN;
|
|
13190
|
+
}
|
|
13191
|
+
return base;
|
|
13192
|
+
}
|
|
13193
|
+
function countExpr(aux, arg) {
|
|
13194
|
+
const n = auxName("count", arg);
|
|
13195
|
+
aux[n] = agg`COUNT(${arg})`;
|
|
13196
|
+
return agg`SUM(${n})`.annotate({ name: n });
|
|
13197
|
+
}
|
|
13198
|
+
function avgExpr(aux, as, arg) {
|
|
13199
|
+
const n = countExpr(aux, arg);
|
|
13200
|
+
return agg`(SUM("${as}" * ${n.name}) / ${n})`;
|
|
13201
|
+
}
|
|
13202
|
+
function avg2(x3, from) {
|
|
13203
|
+
return sql`(SELECT AVG(${x3}) FROM "${from}")`;
|
|
13204
|
+
}
|
|
13205
|
+
function argmaxExpr(aux, as, [, y3]) {
|
|
13206
|
+
const max2 = auxName("max", y3);
|
|
13207
|
+
aux[max2] = agg`MAX(${y3})`;
|
|
13208
|
+
return agg`ARG_MAX("${as}", ${max2})`;
|
|
13209
|
+
}
|
|
13210
|
+
function argminExpr(aux, as, [, y3]) {
|
|
13211
|
+
const min2 = auxName("min", y3);
|
|
13212
|
+
aux[min2] = agg`MIN(${y3})`;
|
|
13213
|
+
return agg`ARG_MIN("${as}", ${min2})`;
|
|
13214
|
+
}
|
|
13215
|
+
function varianceExpr(aux, x3, from, correction = true) {
|
|
13216
|
+
const n = countExpr(aux, x3);
|
|
13217
|
+
const ssq = auxName("rssq", x3);
|
|
13218
|
+
const sum3 = auxName("rsum", x3);
|
|
13219
|
+
const delta = sql`${x3} - ${avg2(x3, from)}`;
|
|
13220
|
+
aux[ssq] = agg`SUM((${delta}) ** 2)`;
|
|
13221
|
+
aux[sum3] = agg`SUM(${delta})`;
|
|
13222
|
+
const adj = correction ? ` - 1` : "";
|
|
13223
|
+
return agg`(SUM(${ssq}) - (SUM(${sum3}) ** 2 / ${n})) / (${n}${adj})`;
|
|
13224
|
+
}
|
|
13225
|
+
function covarianceExpr(aux, args, from, correction = true) {
|
|
13226
|
+
const n = regrCountExpr(aux, args);
|
|
13227
|
+
const sxy = regrSumXYExpr(aux, args, from);
|
|
13228
|
+
const sx = regrSumExpr(aux, 1, args, from);
|
|
13229
|
+
const sy = regrSumExpr(aux, 0, args, from);
|
|
13230
|
+
const adj = correction === null ? "" : correction ? ` / (${n} - 1)` : ` / ${n}`;
|
|
13231
|
+
return agg`(${sxy} - ${sx} * ${sy} / ${n})${adj}`;
|
|
13232
|
+
}
|
|
13233
|
+
function corrExpr(aux, args, from) {
|
|
13234
|
+
const n = regrCountExpr(aux, args);
|
|
13235
|
+
const sxy = regrSumXYExpr(aux, args, from);
|
|
13236
|
+
const sxx = regrSumSqExpr(aux, 1, args, from);
|
|
13237
|
+
const syy = regrSumSqExpr(aux, 0, args, from);
|
|
13238
|
+
const sx = regrSumExpr(aux, 1, args, from);
|
|
13239
|
+
const sy = regrSumExpr(aux, 0, args, from);
|
|
13240
|
+
const vx = agg`(${sxx} - (${sx} ** 2) / ${n})`;
|
|
13241
|
+
const vy = agg`(${syy} - (${sy} ** 2) / ${n})`;
|
|
13242
|
+
return agg`(${sxy} - ${sx} * ${sy} / ${n}) / SQRT(${vx} * ${vy})`;
|
|
13243
|
+
}
|
|
13244
|
+
function regrCountExpr(aux, [y3, x3]) {
|
|
13245
|
+
const n = auxName("count", y3, x3);
|
|
13246
|
+
aux[n] = agg`REGR_COUNT(${y3}, ${x3})`;
|
|
13247
|
+
return agg`SUM(${n})`.annotate({ name: n });
|
|
13248
|
+
}
|
|
13249
|
+
function regrSumExpr(aux, i, args, from) {
|
|
13250
|
+
const v2 = args[i];
|
|
13251
|
+
const o = args[1 - i];
|
|
13252
|
+
const sum3 = auxName("rs", v2);
|
|
13253
|
+
aux[sum3] = agg`SUM(${v2} - ${avg2(v2, from)}) FILTER (${o} IS NOT NULL)`;
|
|
13254
|
+
return agg`SUM(${sum3})`;
|
|
13255
|
+
}
|
|
13256
|
+
function regrSumSqExpr(aux, i, args, from) {
|
|
13257
|
+
const v2 = args[i];
|
|
13258
|
+
const u = args[1 - i];
|
|
13259
|
+
const ssq = auxName("rss", v2);
|
|
13260
|
+
aux[ssq] = agg`SUM((${v2} - ${avg2(v2, from)}) ** 2) FILTER (${u} IS NOT NULL)`;
|
|
13261
|
+
return agg`SUM(${ssq})`;
|
|
13262
|
+
}
|
|
13263
|
+
function regrSumXYExpr(aux, args, from) {
|
|
13264
|
+
const [y3, x3] = args;
|
|
13265
|
+
const sxy = auxName("sxy", y3, x3);
|
|
13266
|
+
aux[sxy] = agg`SUM((${x3} - ${avg2(x3, from)}) * (${y3} - ${avg2(y3, from)}))`;
|
|
13267
|
+
return agg`SUM(${sxy})`;
|
|
13268
|
+
}
|
|
13269
|
+
function regrAvgXExpr(aux, args) {
|
|
13270
|
+
const [y3, x3] = args;
|
|
13271
|
+
const n = regrCountExpr(aux, args);
|
|
13272
|
+
const a2 = auxName("avg", x3, y3);
|
|
13273
|
+
aux[a2] = agg`REGR_AVGX(${y3}, ${x3})`;
|
|
13274
|
+
return agg`(SUM(${a2} * ${n.name}) / ${n})`;
|
|
13275
|
+
}
|
|
13276
|
+
function regrAvgYExpr(aux, args) {
|
|
13277
|
+
const [y3, x3] = args;
|
|
13278
|
+
const n = regrCountExpr(aux, args);
|
|
13279
|
+
const a2 = auxName("avg", y3, x3);
|
|
13280
|
+
aux[a2] = agg`REGR_AVGY(${y3}, ${x3})`;
|
|
13281
|
+
return agg`(SUM(${a2} * ${n.name}) / ${n})`;
|
|
13282
|
+
}
|
|
13283
|
+
function regrVarExpr(aux, i, args, from) {
|
|
13284
|
+
const n = regrCountExpr(aux, args);
|
|
13285
|
+
const sum3 = regrSumExpr(aux, i, args, from);
|
|
13286
|
+
const ssq = regrSumSqExpr(aux, i, args, from);
|
|
13287
|
+
return agg`(${ssq} - (${sum3} ** 2 / ${n}))`;
|
|
13288
|
+
}
|
|
13289
|
+
function regrSlopeExpr(aux, args, from) {
|
|
13290
|
+
const cov = covarianceExpr(aux, args, from, null);
|
|
13291
|
+
const varx = regrVarExpr(aux, 1, args, from);
|
|
13292
|
+
return agg`(${cov}) / ${varx}`;
|
|
13293
|
+
}
|
|
13294
|
+
function regrInterceptExpr(aux, args, from) {
|
|
13295
|
+
const ax = regrAvgXExpr(aux, args);
|
|
13296
|
+
const ay = regrAvgYExpr(aux, args);
|
|
13297
|
+
const m2 = regrSlopeExpr(aux, args, from);
|
|
13298
|
+
return agg`${ay} - (${m2}) * ${ax}`;
|
|
13299
|
+
}
|
|
13300
|
+
|
|
13041
13301
|
// src/DataCubeIndexer.js
|
|
13042
13302
|
var DataCubeIndexer = class {
|
|
13043
13303
|
/**
|
|
@@ -13055,42 +13315,49 @@ var DataCubeIndexer = class {
|
|
|
13055
13315
|
this.enabled = false;
|
|
13056
13316
|
this.clients = null;
|
|
13057
13317
|
this.indices = null;
|
|
13058
|
-
this.
|
|
13318
|
+
this.active = null;
|
|
13059
13319
|
}
|
|
13060
13320
|
clear() {
|
|
13061
13321
|
if (this.indices) {
|
|
13062
|
-
this.mc.cancel(Array.from(this.indices.values(), (index) => index
|
|
13322
|
+
this.mc.cancel(Array.from(this.indices.values(), (index) => index?.result));
|
|
13063
13323
|
this.indices = null;
|
|
13064
13324
|
}
|
|
13065
13325
|
}
|
|
13066
|
-
index(clients,
|
|
13326
|
+
index(clients, activeClause) {
|
|
13067
13327
|
if (this.clients !== clients) {
|
|
13068
|
-
const cols = Array.from(clients,
|
|
13328
|
+
const cols = Array.from(clients, indexColumns).filter((x3) => x3);
|
|
13069
13329
|
const from = cols[0]?.from;
|
|
13070
|
-
this.enabled = cols.every((c) => c
|
|
13330
|
+
this.enabled = cols.length && cols.every((c) => c.from === from);
|
|
13071
13331
|
this.clients = clients;
|
|
13072
|
-
this.
|
|
13332
|
+
this.active = null;
|
|
13073
13333
|
this.clear();
|
|
13074
13334
|
}
|
|
13075
13335
|
if (!this.enabled) return false;
|
|
13076
|
-
|
|
13077
|
-
const { source } =
|
|
13078
|
-
if (source && source === this.
|
|
13336
|
+
activeClause = activeClause || this.selection.active;
|
|
13337
|
+
const { source } = activeClause;
|
|
13338
|
+
if (source && source === this.active?.source) return true;
|
|
13079
13339
|
this.clear();
|
|
13080
13340
|
if (!source) return false;
|
|
13081
|
-
const
|
|
13082
|
-
if (!
|
|
13083
|
-
this.mc.logger()
|
|
13341
|
+
const active = this.active = activeColumns(activeClause);
|
|
13342
|
+
if (!active) return false;
|
|
13343
|
+
const logger = this.mc.logger();
|
|
13344
|
+
logger.warn("DATA CUBE INDEX CONSTRUCTION");
|
|
13084
13345
|
const sel = this.selection.remove(source);
|
|
13085
13346
|
const indices = this.indices = /* @__PURE__ */ new Map();
|
|
13086
13347
|
const { mc, temp } = this;
|
|
13087
13348
|
for (const client of clients) {
|
|
13088
|
-
if (sel.skip(client,
|
|
13089
|
-
|
|
13090
|
-
|
|
13349
|
+
if (sel.skip(client, activeClause)) {
|
|
13350
|
+
indices.set(client, null);
|
|
13351
|
+
continue;
|
|
13352
|
+
}
|
|
13353
|
+
const index = indexColumns(client);
|
|
13354
|
+
if (!index) {
|
|
13355
|
+
continue;
|
|
13356
|
+
}
|
|
13357
|
+
const query = client.query(sel.predicate(client)).select({ ...active.columns, ...index.aux }).groupby(Object.keys(active.columns));
|
|
13091
13358
|
const [subq] = query.subqueries;
|
|
13092
13359
|
if (subq) {
|
|
13093
|
-
const cols = Object.values(
|
|
13360
|
+
const cols = Object.values(active.columns).flatMap((c) => c.columns);
|
|
13094
13361
|
subqueryPushdown(subq, cols);
|
|
13095
13362
|
}
|
|
13096
13363
|
const order = query.orderby();
|
|
@@ -13099,36 +13366,40 @@ var DataCubeIndexer = class {
|
|
|
13099
13366
|
const id = (fnv_hash(sql2) >>> 0).toString(16);
|
|
13100
13367
|
const table = `cube_index_${id}`;
|
|
13101
13368
|
const result = mc.exec(create(table, sql2, { temp }));
|
|
13369
|
+
result.catch((e) => logger.error(e));
|
|
13102
13370
|
indices.set(client, { table, result, order, ...index });
|
|
13103
13371
|
}
|
|
13104
13372
|
return true;
|
|
13105
13373
|
}
|
|
13106
13374
|
async update() {
|
|
13107
|
-
const { clients, selection,
|
|
13108
|
-
const filter =
|
|
13375
|
+
const { clients, selection, active } = this;
|
|
13376
|
+
const filter = active.predicate(selection.active.predicate);
|
|
13109
13377
|
return Promise.all(
|
|
13110
13378
|
Array.from(clients).map((client) => this.updateClient(client, filter))
|
|
13111
13379
|
);
|
|
13112
13380
|
}
|
|
13113
13381
|
async updateClient(client, filter) {
|
|
13382
|
+
const { mc, indices, selection } = this;
|
|
13383
|
+
if (!indices.has(client)) {
|
|
13384
|
+
filter = selection.predicate(client);
|
|
13385
|
+
return mc.updateClient(client, client.query(filter));
|
|
13386
|
+
}
|
|
13387
|
+
;
|
|
13114
13388
|
const index = this.indices.get(client);
|
|
13115
13389
|
if (!index) return;
|
|
13116
|
-
if (!filter) {
|
|
13117
|
-
filter = this.activeView.predicate(this.selection.active.predicate);
|
|
13118
|
-
}
|
|
13119
13390
|
const { table, dims, aggr, order = [] } = index;
|
|
13120
13391
|
const query = Query.select(dims, aggr).from(table).groupby(dims).where(filter).orderby(order);
|
|
13121
|
-
return
|
|
13392
|
+
return mc.updateClient(client, query);
|
|
13122
13393
|
}
|
|
13123
13394
|
};
|
|
13124
|
-
function
|
|
13125
|
-
const { source,
|
|
13395
|
+
function activeColumns(clause) {
|
|
13396
|
+
const { source, meta } = clause;
|
|
13126
13397
|
let columns = clause.predicate?.columns;
|
|
13127
|
-
if (!
|
|
13128
|
-
const { type, scales: scales2, pixelSize = 1 } =
|
|
13398
|
+
if (!meta || !columns) return null;
|
|
13399
|
+
const { type, scales: scales2, bin, pixelSize = 1 } = meta;
|
|
13129
13400
|
let predicate;
|
|
13130
13401
|
if (type === "interval" && scales2) {
|
|
13131
|
-
const bins = scales2.map((s) => binInterval(s, pixelSize));
|
|
13402
|
+
const bins = scales2.map((s) => binInterval(s, pixelSize, bin));
|
|
13132
13403
|
if (bins.some((b2) => b2 == null)) return null;
|
|
13133
13404
|
if (bins.length === 1) {
|
|
13134
13405
|
predicate = (p2) => p2 ? isBetween("active0", p2.range.map(bins[0])) : [];
|
|
@@ -13141,85 +13412,23 @@ function getActiveView(clause) {
|
|
|
13141
13412
|
}
|
|
13142
13413
|
} else if (type === "point") {
|
|
13143
13414
|
predicate = (x3) => x3;
|
|
13144
|
-
columns = Object.fromEntries(columns.map((col) => [col
|
|
13415
|
+
columns = Object.fromEntries(columns.map((col) => [`${col}`, asColumn(col)]));
|
|
13145
13416
|
} else {
|
|
13146
13417
|
return null;
|
|
13147
13418
|
}
|
|
13148
13419
|
return { source, columns, predicate };
|
|
13149
13420
|
}
|
|
13150
|
-
|
|
13151
|
-
|
|
13152
|
-
|
|
13153
|
-
|
|
13154
|
-
|
|
13155
|
-
|
|
13156
|
-
|
|
13157
|
-
|
|
13158
|
-
|
|
13159
|
-
}
|
|
13160
|
-
}
|
|
13161
|
-
var NO_INDEX = { from: NaN };
|
|
13162
|
-
function getIndexColumns(client) {
|
|
13163
|
-
if (!client.filterIndexable) return NO_INDEX;
|
|
13164
|
-
const q2 = client.query();
|
|
13165
|
-
const from = getBaseTable(q2);
|
|
13166
|
-
if (!from || !q2.groupby) return NO_INDEX;
|
|
13167
|
-
const g2 = new Set(q2.groupby().map((c) => c.column));
|
|
13168
|
-
const aggr = [];
|
|
13169
|
-
const dims = [];
|
|
13170
|
-
const aux = {};
|
|
13171
|
-
let auxAs;
|
|
13172
|
-
for (const entry of q2.select()) {
|
|
13173
|
-
const { as, expr: { aggregate, args } } = entry;
|
|
13174
|
-
const op = aggregate?.toUpperCase?.();
|
|
13175
|
-
switch (op) {
|
|
13176
|
-
case "COUNT":
|
|
13177
|
-
case "SUM":
|
|
13178
|
-
aggr.push({ [as]: sql`SUM("${as}")::DOUBLE` });
|
|
13179
|
-
break;
|
|
13180
|
-
case "AVG":
|
|
13181
|
-
aux[auxAs = "__count__"] = sql`COUNT(*)`;
|
|
13182
|
-
aggr.push({ [as]: sql`(SUM("${as}" * ${auxAs}) / SUM(${auxAs}))::DOUBLE` });
|
|
13183
|
-
break;
|
|
13184
|
-
case "ARG_MAX":
|
|
13185
|
-
aux[auxAs = `__max_${as}__`] = sql`MAX(${args[1]})`;
|
|
13186
|
-
aggr.push({ [as]: sql`ARG_MAX("${as}", ${auxAs})` });
|
|
13187
|
-
break;
|
|
13188
|
-
case "ARG_MIN":
|
|
13189
|
-
aux[auxAs = `__min_${as}__`] = sql`MIN(${args[1]})`;
|
|
13190
|
-
aggr.push({ [as]: sql`ARG_MIN("${as}", ${auxAs})` });
|
|
13191
|
-
break;
|
|
13192
|
-
case "MAX":
|
|
13193
|
-
case "MIN":
|
|
13194
|
-
case "BIT_AND":
|
|
13195
|
-
case "BIT_OR":
|
|
13196
|
-
case "BIT_XOR":
|
|
13197
|
-
case "BOOL_AND":
|
|
13198
|
-
case "BOOL_OR":
|
|
13199
|
-
case "PRODUCT":
|
|
13200
|
-
aggr.push({ [as]: sql`${op}("${as}")` });
|
|
13201
|
-
break;
|
|
13202
|
-
default:
|
|
13203
|
-
if (g2.has(as)) dims.push(as);
|
|
13204
|
-
else return null;
|
|
13205
|
-
}
|
|
13206
|
-
}
|
|
13207
|
-
return { aggr, dims, aux, from };
|
|
13208
|
-
}
|
|
13209
|
-
function getBaseTable(query) {
|
|
13210
|
-
const subq = query.subqueries;
|
|
13211
|
-
if (query.select) {
|
|
13212
|
-
const from = query.from();
|
|
13213
|
-
if (!from.length) return void 0;
|
|
13214
|
-
if (subq.length === 0) return from[0].from.table;
|
|
13215
|
-
}
|
|
13216
|
-
const base = getBaseTable(subq[0]);
|
|
13217
|
-
for (let i = 1; i < subq.length; ++i) {
|
|
13218
|
-
const from = getBaseTable(subq[i]);
|
|
13219
|
-
if (from === void 0) continue;
|
|
13220
|
-
if (from !== base) return NaN;
|
|
13221
|
-
}
|
|
13222
|
-
return base;
|
|
13421
|
+
var BIN = { ceil: "CEIL", round: "ROUND" };
|
|
13422
|
+
function binInterval(scale, pixelSize, bin) {
|
|
13423
|
+
const { type, domain, range, apply, sqlApply } = scaleTransform(scale);
|
|
13424
|
+
if (!apply) return;
|
|
13425
|
+
const fn = BIN[`${bin}`.toLowerCase()] || "FLOOR";
|
|
13426
|
+
const lo = apply(Math.min(...domain));
|
|
13427
|
+
const hi = apply(Math.max(...domain));
|
|
13428
|
+
const a2 = type === "identity" ? 1 : Math.abs(range[1] - range[0]) / (hi - lo);
|
|
13429
|
+
const s = a2 / pixelSize === 1 ? "" : `${a2 / pixelSize}::DOUBLE * `;
|
|
13430
|
+
const d = lo === 0 ? "" : ` - ${lo}::DOUBLE`;
|
|
13431
|
+
return (value) => sql`${fn}(${s}(${sqlApply(value)}${d}))::INTEGER`;
|
|
13223
13432
|
}
|
|
13224
13433
|
function subqueryPushdown(query, cols) {
|
|
13225
13434
|
const memo = /* @__PURE__ */ new Set();
|
|
@@ -13234,1299 +13443,1400 @@ function subqueryPushdown(query, cols) {
|
|
|
13234
13443
|
pushdown(query);
|
|
13235
13444
|
}
|
|
13236
13445
|
|
|
13237
|
-
// src/
|
|
13238
|
-
var
|
|
13446
|
+
// src/util/AsyncDispatch.js
|
|
13447
|
+
var AsyncDispatch = class {
|
|
13239
13448
|
/**
|
|
13240
|
-
*
|
|
13241
|
-
* @param {*} selection The shared filter selection.
|
|
13242
|
-
* @param {*} index Boolean flag or options hash for data cube indexer.
|
|
13243
|
-
* Falsy values disable indexing.
|
|
13449
|
+
* Create a new asynchronous dispatcher instance.
|
|
13244
13450
|
*/
|
|
13245
|
-
constructor(
|
|
13246
|
-
this.
|
|
13247
|
-
this.selection = selection;
|
|
13248
|
-
this.clients = /* @__PURE__ */ new Set();
|
|
13249
|
-
this.indexer = index ? new DataCubeIndexer(this.mc, { ...index, selection }) : null;
|
|
13250
|
-
const { value, activate } = this.handlers = {
|
|
13251
|
-
value: () => this.update(),
|
|
13252
|
-
activate: (clause) => this.indexer?.index(this.clients, clause)
|
|
13253
|
-
};
|
|
13254
|
-
selection.addEventListener("value", value);
|
|
13255
|
-
selection.addEventListener("activate", activate);
|
|
13451
|
+
constructor() {
|
|
13452
|
+
this._callbacks = /* @__PURE__ */ new Map();
|
|
13256
13453
|
}
|
|
13257
|
-
|
|
13258
|
-
|
|
13259
|
-
|
|
13260
|
-
|
|
13454
|
+
/**
|
|
13455
|
+
* Add an event listener callback for the provided event type.
|
|
13456
|
+
* @param {string} type The event type.
|
|
13457
|
+
* @param {(value: *) => void | Promise} callback The event handler
|
|
13458
|
+
* callback function to add. If the callback has already been
|
|
13459
|
+
* added for the event type, this method has no effect.
|
|
13460
|
+
*/
|
|
13461
|
+
addEventListener(type, callback) {
|
|
13462
|
+
if (!this._callbacks.has(type)) {
|
|
13463
|
+
this._callbacks.set(type, {
|
|
13464
|
+
callbacks: /* @__PURE__ */ new Set(),
|
|
13465
|
+
pending: null,
|
|
13466
|
+
queue: new DispatchQueue()
|
|
13467
|
+
});
|
|
13468
|
+
}
|
|
13469
|
+
const entry = this._callbacks.get(type);
|
|
13470
|
+
entry.callbacks.add(callback);
|
|
13261
13471
|
}
|
|
13262
|
-
|
|
13263
|
-
|
|
13472
|
+
/**
|
|
13473
|
+
* Remove an event listener callback for the provided event type.
|
|
13474
|
+
* @param {string} type The event type.
|
|
13475
|
+
* @param {(value: *) => void | Promise} callback The event handler
|
|
13476
|
+
* callback function to remove.
|
|
13477
|
+
*/
|
|
13478
|
+
removeEventListener(type, callback) {
|
|
13479
|
+
const entry = this._callbacks.get(type);
|
|
13480
|
+
if (entry) {
|
|
13481
|
+
entry.callbacks.delete(callback);
|
|
13482
|
+
}
|
|
13264
13483
|
}
|
|
13265
|
-
|
|
13266
|
-
|
|
13267
|
-
|
|
13484
|
+
/**
|
|
13485
|
+
* Lifecycle method that returns the event value to emit.
|
|
13486
|
+
* This default implementation simply returns the input value as-is.
|
|
13487
|
+
* Subclasses may override this method to implement custom transformations
|
|
13488
|
+
* prior to emitting an event value to all listeners.
|
|
13489
|
+
* @param {string} type The event type.
|
|
13490
|
+
* @param {*} value The event value.
|
|
13491
|
+
* @returns The (possibly transformed) event value to emit.
|
|
13492
|
+
*/
|
|
13493
|
+
willEmit(type, value) {
|
|
13494
|
+
return value;
|
|
13268
13495
|
}
|
|
13269
|
-
|
|
13270
|
-
|
|
13271
|
-
|
|
13272
|
-
|
|
13273
|
-
|
|
13496
|
+
/**
|
|
13497
|
+
* Lifecycle method that returns a filter function for updating the
|
|
13498
|
+
* queue of unemitted event values prior to enqueueing a new value.
|
|
13499
|
+
* This default implementation simply returns null, indicating that
|
|
13500
|
+
* any other unemitted event values should be dropped (that is, all
|
|
13501
|
+
* queued events are filtered)
|
|
13502
|
+
* @param {string} type The event type.
|
|
13503
|
+
* @param {*} value The new event value that will be enqueued.
|
|
13504
|
+
* @returns {(value: *) => boolean|null} A dispatch queue filter
|
|
13505
|
+
* function, or null if all unemitted event values should be filtered.
|
|
13506
|
+
*/
|
|
13507
|
+
emitQueueFilter(type, value) {
|
|
13508
|
+
return null;
|
|
13274
13509
|
}
|
|
13275
13510
|
/**
|
|
13276
|
-
*
|
|
13277
|
-
*
|
|
13278
|
-
* @returns {Promise} A Promise that resolves when the update completes.
|
|
13511
|
+
* Cancel all unemitted event values for the given event type.
|
|
13512
|
+
* @param {string} type The event type.
|
|
13279
13513
|
*/
|
|
13280
|
-
|
|
13281
|
-
const
|
|
13282
|
-
|
|
13283
|
-
return hasIndex ? indexer.update() : defaultUpdate(mc, clients, selection);
|
|
13514
|
+
cancel(type) {
|
|
13515
|
+
const entry = this._callbacks.get(type);
|
|
13516
|
+
entry?.queue.clear();
|
|
13284
13517
|
}
|
|
13285
|
-
|
|
13286
|
-
|
|
13287
|
-
|
|
13288
|
-
|
|
13289
|
-
|
|
13290
|
-
|
|
13291
|
-
|
|
13292
|
-
|
|
13293
|
-
|
|
13294
|
-
|
|
13295
|
-
|
|
13296
|
-
|
|
13297
|
-
|
|
13298
|
-
|
|
13299
|
-
|
|
13300
|
-
|
|
13301
|
-
|
|
13302
|
-
|
|
13303
|
-
|
|
13304
|
-
|
|
13305
|
-
|
|
13306
|
-
|
|
13307
|
-
}
|
|
13308
|
-
|
|
13309
|
-
// src/QueryConsolidator.js
|
|
13310
|
-
function wait(callback) {
|
|
13311
|
-
const method = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : typeof setImmediate !== "undefined" ? setImmediate : setTimeout;
|
|
13312
|
-
return method(callback);
|
|
13313
|
-
}
|
|
13314
|
-
function consolidator(enqueue, cache, record) {
|
|
13315
|
-
let pending = [];
|
|
13316
|
-
let id = 0;
|
|
13317
|
-
function run() {
|
|
13318
|
-
const groups = entryGroups(pending, cache);
|
|
13319
|
-
pending = [];
|
|
13320
|
-
id = 0;
|
|
13321
|
-
for (const group of groups) {
|
|
13322
|
-
consolidate(group, enqueue, record);
|
|
13323
|
-
processResults(group, cache);
|
|
13324
|
-
}
|
|
13325
|
-
}
|
|
13326
|
-
return {
|
|
13327
|
-
add(entry, priority) {
|
|
13328
|
-
if (entry.request.type === "arrow") {
|
|
13329
|
-
id = id || wait(() => run());
|
|
13330
|
-
pending.push({ entry, priority, index: pending.length });
|
|
13331
|
-
} else {
|
|
13332
|
-
enqueue(entry, priority);
|
|
13518
|
+
/**
|
|
13519
|
+
* Emit an event value to listeners for the given event type.
|
|
13520
|
+
* If a previous emit has not yet resolved, the event value
|
|
13521
|
+
* will be queued to be emitted later.
|
|
13522
|
+
* The actual event value given to listeners will be the result
|
|
13523
|
+
* of passing the input value through the emitValue() method.
|
|
13524
|
+
* @param {string} type The event type.
|
|
13525
|
+
* @param {*} value The event value.
|
|
13526
|
+
*/
|
|
13527
|
+
emit(type, value) {
|
|
13528
|
+
const entry = this._callbacks.get(type) || {};
|
|
13529
|
+
if (entry.pending) {
|
|
13530
|
+
entry.queue.enqueue(value, this.emitQueueFilter(type, value));
|
|
13531
|
+
} else {
|
|
13532
|
+
const event = this.willEmit(type, value);
|
|
13533
|
+
const { callbacks, queue } = entry;
|
|
13534
|
+
if (callbacks?.size) {
|
|
13535
|
+
const callbackValues = Array.from(callbacks, (cb) => cb(event));
|
|
13536
|
+
entry.pending = Promise.allSettled(callbackValues).then(() => {
|
|
13537
|
+
entry.pending = null;
|
|
13538
|
+
if (!queue.isEmpty()) {
|
|
13539
|
+
this.emit(type, queue.dequeue());
|
|
13540
|
+
}
|
|
13541
|
+
});
|
|
13333
13542
|
}
|
|
13334
13543
|
}
|
|
13335
|
-
};
|
|
13336
|
-
}
|
|
13337
|
-
function entryGroups(entries, cache) {
|
|
13338
|
-
const groups = [];
|
|
13339
|
-
const groupMap = /* @__PURE__ */ new Map();
|
|
13340
|
-
for (const query of entries) {
|
|
13341
|
-
const { entry: { request } } = query;
|
|
13342
|
-
const key = consolidationKey(request.query, cache);
|
|
13343
|
-
if (!groupMap.has(key)) {
|
|
13344
|
-
const list = [];
|
|
13345
|
-
groups.push(list);
|
|
13346
|
-
groupMap.set(key, list);
|
|
13347
|
-
}
|
|
13348
|
-
groupMap.get(key).push(query);
|
|
13349
13544
|
}
|
|
13350
|
-
|
|
13351
|
-
|
|
13352
|
-
|
|
13353
|
-
|
|
13354
|
-
|
|
13355
|
-
|
|
13356
|
-
|
|
13357
|
-
query.orderby().length || query.where().length || // @ts-ignore
|
|
13358
|
-
query.qualify().length || query.having().length
|
|
13359
|
-
) {
|
|
13360
|
-
return sql2;
|
|
13361
|
-
}
|
|
13362
|
-
const q2 = query.clone().$select("*");
|
|
13363
|
-
const groupby = query.groupby();
|
|
13364
|
-
if (groupby.length) {
|
|
13365
|
-
const map = {};
|
|
13366
|
-
query.select().forEach(({ as, expr }) => map[as] = expr);
|
|
13367
|
-
q2.$groupby(groupby.map((e) => e instanceof Ref && map[e.column] || e));
|
|
13368
|
-
}
|
|
13369
|
-
return `${q2}`;
|
|
13370
|
-
} else {
|
|
13371
|
-
return sql2;
|
|
13545
|
+
};
|
|
13546
|
+
var DispatchQueue = class {
|
|
13547
|
+
/**
|
|
13548
|
+
* Create a new dispatch queue instance.
|
|
13549
|
+
*/
|
|
13550
|
+
constructor() {
|
|
13551
|
+
this.clear();
|
|
13372
13552
|
}
|
|
13373
|
-
|
|
13374
|
-
|
|
13375
|
-
|
|
13376
|
-
|
|
13377
|
-
|
|
13378
|
-
type: "arrow",
|
|
13379
|
-
cache: false,
|
|
13380
|
-
record: false,
|
|
13381
|
-
query: group.query = consolidatedQuery(group, record)
|
|
13382
|
-
},
|
|
13383
|
-
result: group.result = queryResult()
|
|
13384
|
-
});
|
|
13385
|
-
} else {
|
|
13386
|
-
for (const { entry, priority } of group) {
|
|
13387
|
-
enqueue(entry, priority);
|
|
13388
|
-
}
|
|
13553
|
+
/**
|
|
13554
|
+
* Clear the queue state of all event values.
|
|
13555
|
+
*/
|
|
13556
|
+
clear() {
|
|
13557
|
+
this.next = null;
|
|
13389
13558
|
}
|
|
13390
|
-
|
|
13391
|
-
|
|
13392
|
-
|
|
13393
|
-
|
|
13394
|
-
|
|
13395
|
-
|
|
13396
|
-
return true;
|
|
13397
|
-
}
|
|
13398
|
-
}
|
|
13559
|
+
/**
|
|
13560
|
+
* Indicate if the queue is empty.
|
|
13561
|
+
* @returns {boolean} True if queue is empty, false otherwise.
|
|
13562
|
+
*/
|
|
13563
|
+
isEmpty() {
|
|
13564
|
+
return !this.next;
|
|
13399
13565
|
}
|
|
13400
|
-
|
|
13401
|
-
|
|
13402
|
-
|
|
13403
|
-
|
|
13404
|
-
|
|
13405
|
-
|
|
13406
|
-
|
|
13407
|
-
|
|
13408
|
-
|
|
13409
|
-
|
|
13410
|
-
|
|
13411
|
-
|
|
13412
|
-
|
|
13566
|
+
/**
|
|
13567
|
+
* Add a new value to the queue, and optionally filter the
|
|
13568
|
+
* current queue content in response.
|
|
13569
|
+
* @param {*} value The value to add.
|
|
13570
|
+
* @param {(value: *) => boolean} [filter] An optional filter
|
|
13571
|
+
* function to apply to existing queue content. If unspecified
|
|
13572
|
+
* or falsy, all previously queued values are removed. Otherwise,
|
|
13573
|
+
* the provided function is applied to all queue entries. The
|
|
13574
|
+
* entry is retained if the filter function returns a truthy value,
|
|
13575
|
+
* otherwise the entry is removed.
|
|
13576
|
+
*/
|
|
13577
|
+
enqueue(value, filter) {
|
|
13578
|
+
const tail = { value };
|
|
13579
|
+
if (filter && this.next) {
|
|
13580
|
+
let curr = this;
|
|
13581
|
+
while (curr.next) {
|
|
13582
|
+
if (filter(curr.next.value)) {
|
|
13583
|
+
curr = curr.next;
|
|
13584
|
+
} else {
|
|
13585
|
+
curr.next = curr.next.next;
|
|
13586
|
+
}
|
|
13413
13587
|
}
|
|
13414
|
-
|
|
13415
|
-
|
|
13588
|
+
curr.next = tail;
|
|
13589
|
+
} else {
|
|
13590
|
+
this.next = tail;
|
|
13416
13591
|
}
|
|
13417
|
-
record(`${query2}`);
|
|
13418
13592
|
}
|
|
13419
|
-
|
|
13420
|
-
|
|
13421
|
-
|
|
13422
|
-
|
|
13423
|
-
|
|
13424
|
-
|
|
13593
|
+
/**
|
|
13594
|
+
* Remove and return the next queued event value.
|
|
13595
|
+
* @returns {*} The next event value in the queue.
|
|
13596
|
+
*/
|
|
13597
|
+
dequeue() {
|
|
13598
|
+
const { next } = this;
|
|
13599
|
+
this.next = next?.next;
|
|
13600
|
+
return next?.value;
|
|
13425
13601
|
}
|
|
13426
|
-
|
|
13602
|
+
};
|
|
13603
|
+
|
|
13604
|
+
// src/util/distinct.js
|
|
13605
|
+
function distinct(a2, b2) {
|
|
13606
|
+
return a2 === b2 ? false : a2 instanceof Date && b2 instanceof Date ? +a2 !== +b2 : Array.isArray(a2) && Array.isArray(b2) ? distinctArray(a2, b2) : true;
|
|
13427
13607
|
}
|
|
13428
|
-
|
|
13429
|
-
|
|
13430
|
-
|
|
13431
|
-
|
|
13432
|
-
try {
|
|
13433
|
-
data = await result;
|
|
13434
|
-
} catch (err) {
|
|
13435
|
-
for (const { entry } of group) {
|
|
13436
|
-
entry.result.reject(err);
|
|
13437
|
-
}
|
|
13438
|
-
return;
|
|
13608
|
+
function distinctArray(a2, b2) {
|
|
13609
|
+
if (a2.length !== b2.length) return true;
|
|
13610
|
+
for (let i = 0; i < a2.length; ++i) {
|
|
13611
|
+
if (a2[i] !== b2[i]) return true;
|
|
13439
13612
|
}
|
|
13440
|
-
|
|
13441
|
-
group.forEach(({ entry }, index) => {
|
|
13442
|
-
const { request, result: result2 } = entry;
|
|
13443
|
-
const map = maps[index];
|
|
13444
|
-
const extract = describe && map ? filterResult(data, map) : map ? projectResult(data, map) : data;
|
|
13445
|
-
if (request.cache) {
|
|
13446
|
-
cache.set(String(request.query), extract);
|
|
13447
|
-
}
|
|
13448
|
-
result2.fulfill(extract);
|
|
13449
|
-
});
|
|
13613
|
+
return false;
|
|
13450
13614
|
}
|
|
13451
|
-
|
|
13452
|
-
|
|
13453
|
-
|
|
13454
|
-
|
|
13455
|
-
}
|
|
13456
|
-
return new data.constructor(cols);
|
|
13615
|
+
|
|
13616
|
+
// src/Param.js
|
|
13617
|
+
function isParam(x3) {
|
|
13618
|
+
return x3 instanceof Param;
|
|
13457
13619
|
}
|
|
13458
|
-
|
|
13459
|
-
|
|
13460
|
-
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
|
|
13620
|
+
var Param = class _Param extends AsyncDispatch {
|
|
13621
|
+
/**
|
|
13622
|
+
* Create a new Param instance.
|
|
13623
|
+
* @param {*} value The initial value of the Param.
|
|
13624
|
+
*/
|
|
13625
|
+
constructor(value) {
|
|
13626
|
+
super();
|
|
13627
|
+
this._value = value;
|
|
13465
13628
|
}
|
|
13466
|
-
|
|
13467
|
-
|
|
13468
|
-
|
|
13469
|
-
|
|
13470
|
-
|
|
13471
|
-
|
|
13472
|
-
|
|
13473
|
-
set: (key, value) => value,
|
|
13474
|
-
clear: () => {
|
|
13629
|
+
/**
|
|
13630
|
+
* Create a new Param instance with the given initial value.
|
|
13631
|
+
* @param {*} value The initial value of the Param.
|
|
13632
|
+
* @returns {Param} The new Param instance.
|
|
13633
|
+
*/
|
|
13634
|
+
static value(value) {
|
|
13635
|
+
return new _Param(value);
|
|
13475
13636
|
}
|
|
13476
|
-
|
|
13477
|
-
|
|
13478
|
-
|
|
13479
|
-
|
|
13480
|
-
|
|
13481
|
-
|
|
13482
|
-
|
|
13483
|
-
|
|
13484
|
-
|
|
13485
|
-
|
|
13486
|
-
|
|
13487
|
-
|
|
13488
|
-
|
|
13489
|
-
|
|
13490
|
-
|
|
13491
|
-
lruKey = key;
|
|
13492
|
-
lruLast = last2;
|
|
13493
|
-
}
|
|
13494
|
-
if (expire > last2) {
|
|
13495
|
-
cache.delete(key);
|
|
13496
|
-
}
|
|
13637
|
+
/**
|
|
13638
|
+
* Create a new Param instance over an array of initial values,
|
|
13639
|
+
* which may contain nested Params.
|
|
13640
|
+
* @param {*} values The initial values of the Param.
|
|
13641
|
+
* @returns {Param} The new Param instance.
|
|
13642
|
+
*/
|
|
13643
|
+
static array(values) {
|
|
13644
|
+
if (values.some((v2) => isParam(v2))) {
|
|
13645
|
+
const p2 = new _Param();
|
|
13646
|
+
const update2 = () => {
|
|
13647
|
+
p2.update(values.map((v2) => isParam(v2) ? v2.value : v2));
|
|
13648
|
+
};
|
|
13649
|
+
update2();
|
|
13650
|
+
values.forEach((v2) => isParam(v2) ? v2.addEventListener("value", update2) : 0);
|
|
13651
|
+
return p2;
|
|
13497
13652
|
}
|
|
13498
|
-
|
|
13499
|
-
|
|
13653
|
+
return new _Param(values);
|
|
13654
|
+
}
|
|
13655
|
+
/**
|
|
13656
|
+
* The current value of the Param.
|
|
13657
|
+
*/
|
|
13658
|
+
get value() {
|
|
13659
|
+
return this._value;
|
|
13660
|
+
}
|
|
13661
|
+
/**
|
|
13662
|
+
* Update the Param value
|
|
13663
|
+
* @param {*} value The new value of the Param.
|
|
13664
|
+
* @param {object} [options] The update options.
|
|
13665
|
+
* @param {boolean} [options.force] A boolean flag indicating if the Param
|
|
13666
|
+
* should emit a 'value' event even if the internal value is unchanged.
|
|
13667
|
+
* @returns {this} This Param instance.
|
|
13668
|
+
*/
|
|
13669
|
+
update(value, { force } = {}) {
|
|
13670
|
+
const shouldEmit = distinct(this._value, value) || force;
|
|
13671
|
+
if (shouldEmit) {
|
|
13672
|
+
this.emit("value", value);
|
|
13673
|
+
} else {
|
|
13674
|
+
this.cancel("value");
|
|
13500
13675
|
}
|
|
13676
|
+
return this;
|
|
13501
13677
|
}
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13508
|
-
|
|
13509
|
-
|
|
13510
|
-
|
|
13511
|
-
|
|
13512
|
-
if (cache.size > max2) requestIdle(evict);
|
|
13513
|
-
return value;
|
|
13514
|
-
},
|
|
13515
|
-
clear() {
|
|
13516
|
-
cache = /* @__PURE__ */ new Map();
|
|
13678
|
+
/**
|
|
13679
|
+
* Upon value-typed updates, sets the current value to the input value
|
|
13680
|
+
* immediately prior to the event value being emitted to listeners.
|
|
13681
|
+
* @param {string} type The event type.
|
|
13682
|
+
* @param {*} value The input event value.
|
|
13683
|
+
* @returns {*} The input event value.
|
|
13684
|
+
*/
|
|
13685
|
+
willEmit(type, value) {
|
|
13686
|
+
if (type === "value") {
|
|
13687
|
+
this._value = value;
|
|
13517
13688
|
}
|
|
13518
|
-
|
|
13519
|
-
}
|
|
13689
|
+
return value;
|
|
13690
|
+
}
|
|
13691
|
+
};
|
|
13520
13692
|
|
|
13521
|
-
// src/
|
|
13522
|
-
function
|
|
13523
|
-
|
|
13524
|
-
|
|
13525
|
-
|
|
13526
|
-
|
|
13527
|
-
|
|
13528
|
-
|
|
13529
|
-
|
|
13530
|
-
|
|
13531
|
-
|
|
13532
|
-
|
|
13533
|
-
|
|
13534
|
-
|
|
13535
|
-
|
|
13536
|
-
|
|
13537
|
-
|
|
13538
|
-
|
|
13539
|
-
|
|
13540
|
-
|
|
13541
|
-
|
|
13542
|
-
|
|
13543
|
-
|
|
13544
|
-
|
|
13545
|
-
|
|
13546
|
-
|
|
13547
|
-
|
|
13548
|
-
|
|
13549
|
-
|
|
13550
|
-
|
|
13551
|
-
|
|
13552
|
-
|
|
13553
|
-
|
|
13554
|
-
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
|
|
13560
|
-
|
|
13561
|
-
|
|
13562
|
-
|
|
13563
|
-
|
|
13564
|
-
|
|
13565
|
-
|
|
13566
|
-
|
|
13567
|
-
|
|
13568
|
-
|
|
13569
|
-
|
|
13570
|
-
|
|
13571
|
-
|
|
13572
|
-
|
|
13573
|
-
|
|
13574
|
-
|
|
13575
|
-
|
|
13576
|
-
|
|
13577
|
-
|
|
13578
|
-
|
|
13579
|
-
|
|
13580
|
-
|
|
13581
|
-
|
|
13582
|
-
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13586
|
-
|
|
13587
|
-
|
|
13588
|
-
|
|
13589
|
-
|
|
13590
|
-
|
|
13591
|
-
|
|
13592
|
-
|
|
13693
|
+
// src/Selection.js
|
|
13694
|
+
function isSelection(x3) {
|
|
13695
|
+
return x3 instanceof Selection;
|
|
13696
|
+
}
|
|
13697
|
+
var Selection = class _Selection extends Param {
|
|
13698
|
+
/**
|
|
13699
|
+
* Create a new Selection instance with an
|
|
13700
|
+
* intersect (conjunction) resolution strategy.
|
|
13701
|
+
* @param {object} [options] The selection options.
|
|
13702
|
+
* @param {boolean} [options.cross=false] Boolean flag indicating
|
|
13703
|
+
* cross-filtered resolution. If true, selection clauses will not
|
|
13704
|
+
* be applied to the clients they are associated with.
|
|
13705
|
+
* @returns {Selection} The new Selection instance.
|
|
13706
|
+
*/
|
|
13707
|
+
static intersect({ cross = false } = {}) {
|
|
13708
|
+
return new _Selection(new SelectionResolver({ cross }));
|
|
13709
|
+
}
|
|
13710
|
+
/**
|
|
13711
|
+
* Create a new Selection instance with a
|
|
13712
|
+
* union (disjunction) resolution strategy.
|
|
13713
|
+
* @param {object} [options] The selection options.
|
|
13714
|
+
* @param {boolean} [options.cross=false] Boolean flag indicating
|
|
13715
|
+
* cross-filtered resolution. If true, selection clauses will not
|
|
13716
|
+
* be applied to the clients they are associated with.
|
|
13717
|
+
* @returns {Selection} The new Selection instance.
|
|
13718
|
+
*/
|
|
13719
|
+
static union({ cross = false } = {}) {
|
|
13720
|
+
return new _Selection(new SelectionResolver({ cross, union: true }));
|
|
13721
|
+
}
|
|
13722
|
+
/**
|
|
13723
|
+
* Create a new Selection instance with a singular resolution strategy
|
|
13724
|
+
* that keeps only the most recent selection clause.
|
|
13725
|
+
* @param {object} [options] The selection options.
|
|
13726
|
+
* @param {boolean} [options.cross=false] Boolean flag indicating
|
|
13727
|
+
* cross-filtered resolution. If true, selection clauses will not
|
|
13728
|
+
* be applied to the clients they are associated with.
|
|
13729
|
+
* @returns {Selection} The new Selection instance.
|
|
13730
|
+
*/
|
|
13731
|
+
static single({ cross = false } = {}) {
|
|
13732
|
+
return new _Selection(new SelectionResolver({ cross, single: true }));
|
|
13733
|
+
}
|
|
13734
|
+
/**
|
|
13735
|
+
* Create a new Selection instance with a
|
|
13736
|
+
* cross-filtered intersect resolution strategy.
|
|
13737
|
+
* @returns {Selection} The new Selection instance.
|
|
13738
|
+
*/
|
|
13739
|
+
static crossfilter() {
|
|
13740
|
+
return new _Selection(new SelectionResolver({ cross: true }));
|
|
13741
|
+
}
|
|
13742
|
+
/**
|
|
13743
|
+
* Create a new Selection instance.
|
|
13744
|
+
* @param {SelectionResolver} resolver The selection resolution
|
|
13745
|
+
* strategy to apply.
|
|
13746
|
+
*/
|
|
13747
|
+
constructor(resolver = new SelectionResolver()) {
|
|
13748
|
+
super([]);
|
|
13749
|
+
this._resolved = this._value;
|
|
13750
|
+
this._resolver = resolver;
|
|
13751
|
+
}
|
|
13752
|
+
/**
|
|
13753
|
+
* Create a cloned copy of this Selection instance.
|
|
13754
|
+
* @returns {Selection} A clone of this selection.
|
|
13755
|
+
*/
|
|
13756
|
+
clone() {
|
|
13757
|
+
const s = new _Selection(this._resolver);
|
|
13758
|
+
s._value = s._resolved = this._value;
|
|
13759
|
+
return s;
|
|
13760
|
+
}
|
|
13761
|
+
/**
|
|
13762
|
+
* Create a clone of this Selection with clauses corresponding
|
|
13763
|
+
* to the provided source removed.
|
|
13764
|
+
* @param {*} source The clause source to remove.
|
|
13765
|
+
* @returns {Selection} A cloned and updated Selection.
|
|
13766
|
+
*/
|
|
13767
|
+
remove(source) {
|
|
13768
|
+
const s = this.clone();
|
|
13769
|
+
s._value = s._resolved = s._resolver.resolve(this._resolved, { source });
|
|
13770
|
+
s._value.active = { source };
|
|
13771
|
+
return s;
|
|
13772
|
+
}
|
|
13773
|
+
/**
|
|
13774
|
+
* The selection clause resolver.
|
|
13775
|
+
*/
|
|
13776
|
+
get resolver() {
|
|
13777
|
+
return this._resolver;
|
|
13778
|
+
}
|
|
13779
|
+
/**
|
|
13780
|
+
* Indicate if this selection has a single resolution strategy.
|
|
13781
|
+
*/
|
|
13782
|
+
get single() {
|
|
13783
|
+
return this._resolver.single;
|
|
13784
|
+
}
|
|
13785
|
+
/**
|
|
13786
|
+
* The current array of selection clauses.
|
|
13787
|
+
*/
|
|
13788
|
+
get clauses() {
|
|
13789
|
+
return super.value;
|
|
13790
|
+
}
|
|
13791
|
+
/**
|
|
13792
|
+
* The current active (most recently updated) selection clause.
|
|
13793
|
+
*/
|
|
13794
|
+
get active() {
|
|
13795
|
+
return this.clauses.active;
|
|
13796
|
+
}
|
|
13797
|
+
/**
|
|
13798
|
+
* The value corresponding to the current active selection clause.
|
|
13799
|
+
* This method ensures compatibility where a normal Param is expected.
|
|
13800
|
+
*/
|
|
13801
|
+
get value() {
|
|
13802
|
+
return this.active?.value;
|
|
13803
|
+
}
|
|
13804
|
+
/**
|
|
13805
|
+
* The value corresponding to a given source. Returns undefined if
|
|
13806
|
+
* this selection does not include a clause from this source.
|
|
13807
|
+
* @param {*} source The clause source to look up the value for.
|
|
13808
|
+
*/
|
|
13809
|
+
valueFor(source) {
|
|
13810
|
+
return this.clauses.find((c) => c.source === source)?.value;
|
|
13811
|
+
}
|
|
13812
|
+
/**
|
|
13813
|
+
* Emit an activate event with the given selection clause.
|
|
13814
|
+
* @param {*} clause The clause repesenting the potential activation.
|
|
13815
|
+
*/
|
|
13816
|
+
activate(clause) {
|
|
13817
|
+
this.emit("activate", clause);
|
|
13818
|
+
}
|
|
13819
|
+
/**
|
|
13820
|
+
* Update the selection with a new selection clause.
|
|
13821
|
+
* @param {*} clause The selection clause to add.
|
|
13822
|
+
* @returns {this} This Selection instance.
|
|
13823
|
+
*/
|
|
13824
|
+
update(clause) {
|
|
13825
|
+
this._resolved = this._resolver.resolve(this._resolved, clause, true);
|
|
13826
|
+
this._resolved.active = clause;
|
|
13827
|
+
return super.update(this._resolved);
|
|
13828
|
+
}
|
|
13829
|
+
/**
|
|
13830
|
+
* Upon value-typed updates, sets the current clause list to the
|
|
13831
|
+
* input value and returns the active clause value.
|
|
13832
|
+
* @param {string} type The event type.
|
|
13833
|
+
* @param {*} value The input event value.
|
|
13834
|
+
* @returns {*} For value-typed events, returns the active clause
|
|
13835
|
+
* values. Otherwise returns the input event value as-is.
|
|
13836
|
+
*/
|
|
13837
|
+
willEmit(type, value) {
|
|
13838
|
+
if (type === "value") {
|
|
13839
|
+
this._value = value;
|
|
13840
|
+
return this.value;
|
|
13593
13841
|
}
|
|
13594
|
-
|
|
13595
|
-
}
|
|
13596
|
-
|
|
13597
|
-
// src/QueryManager.js
|
|
13598
|
-
var Priority = { High: 0, Normal: 1, Low: 2 };
|
|
13599
|
-
function QueryManager() {
|
|
13600
|
-
const queue = priorityQueue(3);
|
|
13601
|
-
let db;
|
|
13602
|
-
let clientCache;
|
|
13603
|
-
let logger;
|
|
13604
|
-
let recorders = [];
|
|
13605
|
-
let pending = null;
|
|
13606
|
-
let consolidate2;
|
|
13607
|
-
function next() {
|
|
13608
|
-
if (pending || queue.isEmpty()) return;
|
|
13609
|
-
const { request, result } = queue.next();
|
|
13610
|
-
pending = submit(request, result);
|
|
13611
|
-
pending.finally(() => {
|
|
13612
|
-
pending = null;
|
|
13613
|
-
next();
|
|
13614
|
-
});
|
|
13842
|
+
return value;
|
|
13615
13843
|
}
|
|
13616
|
-
|
|
13617
|
-
|
|
13618
|
-
|
|
13844
|
+
/**
|
|
13845
|
+
* Upon value-typed updates, returns a dispatch queue filter function.
|
|
13846
|
+
* The return value depends on the selection resolution strategy.
|
|
13847
|
+
* @param {string} type The event type.
|
|
13848
|
+
* @param {*} value The new event value that will be enqueued.
|
|
13849
|
+
* @returns {(value: *) => boolean|null} For value-typed events,
|
|
13850
|
+
* returns a dispatch queue filter function. Otherwise returns null.
|
|
13851
|
+
*/
|
|
13852
|
+
emitQueueFilter(type, value) {
|
|
13853
|
+
return type === "value" ? this._resolver.queueFilter(value) : null;
|
|
13619
13854
|
}
|
|
13620
|
-
|
|
13621
|
-
|
|
13622
|
-
|
|
13623
|
-
|
|
13855
|
+
/**
|
|
13856
|
+
* Indicates if a selection clause should not be applied to a given client.
|
|
13857
|
+
* The return value depends on the selection resolution strategy.
|
|
13858
|
+
* @param {*} client The selection clause.
|
|
13859
|
+
* @param {*} clause The client to test.
|
|
13860
|
+
* @returns True if the client should be skipped, false otherwise.
|
|
13861
|
+
*/
|
|
13862
|
+
skip(client, clause) {
|
|
13863
|
+
return this._resolver.skip(client, clause);
|
|
13624
13864
|
}
|
|
13625
|
-
|
|
13626
|
-
|
|
13627
|
-
|
|
13628
|
-
|
|
13629
|
-
|
|
13630
|
-
|
|
13631
|
-
|
|
13632
|
-
|
|
13633
|
-
|
|
13634
|
-
|
|
13635
|
-
|
|
13636
|
-
|
|
13637
|
-
|
|
13638
|
-
}
|
|
13639
|
-
}
|
|
13640
|
-
const t0 = performance.now();
|
|
13641
|
-
const data = await db.query({ type, sql: sql2, ...options });
|
|
13642
|
-
if (cache) clientCache.set(sql2, data);
|
|
13643
|
-
logger.debug(`Request: ${(performance.now() - t0).toFixed(1)}`);
|
|
13644
|
-
result.fulfill(data);
|
|
13645
|
-
} catch (err) {
|
|
13646
|
-
result.reject(err);
|
|
13647
|
-
}
|
|
13865
|
+
/**
|
|
13866
|
+
* Return a selection query predicate for the given client.
|
|
13867
|
+
* @param {*} client The client whose data may be filtered.
|
|
13868
|
+
* @param {boolean} [noSkip=false] Disable skipping of active
|
|
13869
|
+
* cross-filtered sources. If set true, the source of the active
|
|
13870
|
+
* clause in a cross-filtered selection will not be skipped.
|
|
13871
|
+
* @returns {*} The query predicate for filtering client data,
|
|
13872
|
+
* based on the current state of this selection.
|
|
13873
|
+
*/
|
|
13874
|
+
predicate(client, noSkip = false) {
|
|
13875
|
+
const { clauses } = this;
|
|
13876
|
+
const active = noSkip ? null : clauses.active;
|
|
13877
|
+
return this._resolver.predicate(clauses, active, client);
|
|
13648
13878
|
}
|
|
13649
|
-
|
|
13650
|
-
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
|
|
13654
|
-
|
|
13655
|
-
|
|
13656
|
-
|
|
13657
|
-
|
|
13658
|
-
|
|
13659
|
-
|
|
13660
|
-
|
|
13661
|
-
|
|
13662
|
-
|
|
13663
|
-
consolidate2 = null;
|
|
13664
|
-
}
|
|
13665
|
-
},
|
|
13666
|
-
request(request, priority = Priority.Normal) {
|
|
13667
|
-
const result = queryResult();
|
|
13668
|
-
const entry = { request, result };
|
|
13669
|
-
if (consolidate2) {
|
|
13670
|
-
consolidate2.add(entry, priority);
|
|
13671
|
-
} else {
|
|
13672
|
-
enqueue(entry, priority);
|
|
13673
|
-
}
|
|
13674
|
-
return result;
|
|
13675
|
-
},
|
|
13676
|
-
cancel(requests) {
|
|
13677
|
-
const set = new Set(requests);
|
|
13678
|
-
queue.remove(({ result }) => set.has(result));
|
|
13679
|
-
},
|
|
13680
|
-
clear() {
|
|
13681
|
-
queue.remove(({ result }) => {
|
|
13682
|
-
result.reject("Cleared");
|
|
13683
|
-
return true;
|
|
13684
|
-
});
|
|
13685
|
-
},
|
|
13686
|
-
record() {
|
|
13687
|
-
let state = [];
|
|
13688
|
-
const recorder = {
|
|
13689
|
-
add(query) {
|
|
13690
|
-
state.push(query);
|
|
13691
|
-
},
|
|
13692
|
-
reset() {
|
|
13693
|
-
state = [];
|
|
13694
|
-
},
|
|
13695
|
-
snapshot() {
|
|
13696
|
-
return state.slice();
|
|
13697
|
-
},
|
|
13698
|
-
stop() {
|
|
13699
|
-
recorders = recorders.filter((x3) => x3 !== recorder);
|
|
13700
|
-
return state;
|
|
13701
|
-
}
|
|
13702
|
-
};
|
|
13703
|
-
recorders.push(recorder);
|
|
13704
|
-
return recorder;
|
|
13705
|
-
}
|
|
13706
|
-
};
|
|
13707
|
-
}
|
|
13708
|
-
|
|
13709
|
-
// src/util/js-type.js
|
|
13710
|
-
function jsType(type) {
|
|
13711
|
-
switch (type) {
|
|
13712
|
-
case "BIGINT":
|
|
13713
|
-
case "HUGEINT":
|
|
13714
|
-
case "INTEGER":
|
|
13715
|
-
case "SMALLINT":
|
|
13716
|
-
case "TINYINT":
|
|
13717
|
-
case "UBIGINT":
|
|
13718
|
-
case "UINTEGER":
|
|
13719
|
-
case "USMALLINT":
|
|
13720
|
-
case "UTINYINT":
|
|
13721
|
-
case "DOUBLE":
|
|
13722
|
-
case "FLOAT":
|
|
13723
|
-
case "REAL":
|
|
13724
|
-
return "number";
|
|
13725
|
-
case "DATE":
|
|
13726
|
-
case "TIMESTAMP":
|
|
13727
|
-
case "TIMESTAMPTZ":
|
|
13728
|
-
case "TIMESTAMP WITH TIME ZONE":
|
|
13729
|
-
case "TIME":
|
|
13730
|
-
case "TIMESTAMP_NS":
|
|
13731
|
-
return "date";
|
|
13732
|
-
case "BOOLEAN":
|
|
13733
|
-
return "boolean";
|
|
13734
|
-
case "VARCHAR":
|
|
13735
|
-
case "UUID":
|
|
13736
|
-
case "JSON":
|
|
13737
|
-
return "string";
|
|
13738
|
-
case "ARRAY":
|
|
13739
|
-
case "LIST":
|
|
13740
|
-
return "array";
|
|
13741
|
-
case "BLOB":
|
|
13742
|
-
case "STRUCT":
|
|
13743
|
-
case "MAP":
|
|
13744
|
-
case "GEOMETRY":
|
|
13745
|
-
return "object";
|
|
13746
|
-
default:
|
|
13747
|
-
if (type.startsWith("DECIMAL")) {
|
|
13748
|
-
return "number";
|
|
13749
|
-
} else if (type.startsWith("STRUCT") || type.startsWith("MAP")) {
|
|
13750
|
-
return "object";
|
|
13751
|
-
} else if (type.endsWith("]")) {
|
|
13752
|
-
return "array";
|
|
13753
|
-
}
|
|
13754
|
-
throw new Error(`Unsupported type: ${type}`);
|
|
13879
|
+
};
|
|
13880
|
+
var SelectionResolver = class {
|
|
13881
|
+
/**
|
|
13882
|
+
* Create a new selection resolved instance.
|
|
13883
|
+
* @param {object} [options] The resolution strategy options.
|
|
13884
|
+
* @param {boolean} [options.union=false] Boolean flag to indicate a union strategy.
|
|
13885
|
+
* If false, an intersection strategy is used.
|
|
13886
|
+
* @param {boolean} [options.cross=false] Boolean flag to indicate cross-filtering.
|
|
13887
|
+
* @param {boolean} [options.single=false] Boolean flag to indicate single clauses only.
|
|
13888
|
+
*/
|
|
13889
|
+
constructor({ union, cross, single } = {}) {
|
|
13890
|
+
this.union = !!union;
|
|
13891
|
+
this.cross = !!cross;
|
|
13892
|
+
this.single = !!single;
|
|
13755
13893
|
}
|
|
13756
|
-
|
|
13757
|
-
|
|
13758
|
-
|
|
13759
|
-
|
|
13760
|
-
|
|
13761
|
-
|
|
13762
|
-
|
|
13763
|
-
|
|
13764
|
-
|
|
13765
|
-
|
|
13766
|
-
|
|
13767
|
-
|
|
13894
|
+
/**
|
|
13895
|
+
* Resolve a list of selection clauses according to the resolution strategy.
|
|
13896
|
+
* @param {*[]} clauseList An array of selection clauses.
|
|
13897
|
+
* @param {*} clause A new selection clause to add.
|
|
13898
|
+
* @returns {*[]} An updated array of selection clauses.
|
|
13899
|
+
*/
|
|
13900
|
+
resolve(clauseList, clause, reset = false) {
|
|
13901
|
+
const { source, predicate } = clause;
|
|
13902
|
+
const filtered = clauseList.filter((c) => source !== c.source);
|
|
13903
|
+
const clauses = this.single ? [] : filtered;
|
|
13904
|
+
if (this.single && reset) filtered.forEach((c) => c.source?.reset?.());
|
|
13905
|
+
if (predicate) clauses.push(clause);
|
|
13906
|
+
return clauses;
|
|
13768
13907
|
}
|
|
13769
|
-
|
|
13770
|
-
|
|
13908
|
+
/**
|
|
13909
|
+
* Indicates if a selection clause should not be applied to a given client.
|
|
13910
|
+
* The return value depends on the resolution strategy.
|
|
13911
|
+
* @param {*} client The selection clause.
|
|
13912
|
+
* @param {*} clause The client to test.
|
|
13913
|
+
* @returns True if the client should be skipped, false otherwise.
|
|
13914
|
+
*/
|
|
13915
|
+
skip(client, clause) {
|
|
13916
|
+
return this.cross && clause?.clients?.has(client);
|
|
13771
13917
|
}
|
|
13772
|
-
|
|
13773
|
-
|
|
13774
|
-
|
|
13918
|
+
/**
|
|
13919
|
+
* Return a selection query predicate for the given client.
|
|
13920
|
+
* @param {*[]} clauseList An array of selection clauses.
|
|
13921
|
+
* @param {*} active The current active selection clause.
|
|
13922
|
+
* @param {*} client The client whose data may be filtered.
|
|
13923
|
+
* @returns {*} The query predicate for filtering client data,
|
|
13924
|
+
* based on the current state of this selection.
|
|
13925
|
+
*/
|
|
13926
|
+
predicate(clauseList, active, client) {
|
|
13927
|
+
const { union } = this;
|
|
13928
|
+
if (this.skip(client, active)) return void 0;
|
|
13929
|
+
const predicates = clauseList.filter((clause) => !this.skip(client, clause)).map((clause) => clause.predicate);
|
|
13930
|
+
return union && predicates.length > 1 ? or(predicates) : predicates;
|
|
13775
13931
|
}
|
|
13776
|
-
|
|
13777
|
-
|
|
13778
|
-
|
|
13779
|
-
|
|
13780
|
-
if
|
|
13781
|
-
|
|
13782
|
-
|
|
13783
|
-
|
|
13784
|
-
const
|
|
13785
|
-
|
|
13932
|
+
/**
|
|
13933
|
+
* Returns a filter function for queued selection updates.
|
|
13934
|
+
* @param {*} value The new event value that will be enqueued.
|
|
13935
|
+
* @returns {(value: *) => boolean|null} A dispatch queue filter
|
|
13936
|
+
* function, or null if all unemitted event values should be filtered.
|
|
13937
|
+
*/
|
|
13938
|
+
queueFilter(value) {
|
|
13939
|
+
if (this.cross) {
|
|
13940
|
+
const source = value.active?.source;
|
|
13941
|
+
return (clauses) => clauses.active?.source !== source;
|
|
13786
13942
|
}
|
|
13787
|
-
return
|
|
13943
|
+
return null;
|
|
13788
13944
|
}
|
|
13789
|
-
|
|
13790
|
-
|
|
13791
|
-
|
|
13792
|
-
|
|
13793
|
-
|
|
13794
|
-
|
|
13795
|
-
|
|
13796
|
-
|
|
13945
|
+
};
|
|
13946
|
+
|
|
13947
|
+
// src/FilterGroup.js
|
|
13948
|
+
var FilterGroup = class {
|
|
13949
|
+
/**
|
|
13950
|
+
* @param {Coordinator} coordinator The Mosaic coordinator.
|
|
13951
|
+
* @param {Selection} selection The shared filter selection.
|
|
13952
|
+
* @param {object|boolean} index Boolean flag or options hash for
|
|
13953
|
+
* a data cube indexer. Falsy values disable indexing.
|
|
13954
|
+
*/
|
|
13955
|
+
constructor(coordinator2, selection, index = true) {
|
|
13956
|
+
this.mc = coordinator2;
|
|
13957
|
+
this.selection = selection;
|
|
13958
|
+
this.clients = /* @__PURE__ */ new Set();
|
|
13959
|
+
this.indexer = null;
|
|
13960
|
+
this.index(index);
|
|
13961
|
+
const { value, activate } = this.handlers = {
|
|
13962
|
+
value: () => this.update(),
|
|
13963
|
+
activate: (clause) => {
|
|
13964
|
+
this.indexer?.index(this.clients, clause);
|
|
13965
|
+
}
|
|
13966
|
+
};
|
|
13967
|
+
selection.addEventListener("value", value);
|
|
13968
|
+
selection.addEventListener("activate", activate);
|
|
13969
|
+
}
|
|
13970
|
+
finalize() {
|
|
13971
|
+
const { value, activate } = this.handlers;
|
|
13972
|
+
this.selection.removeEventListener("value", value);
|
|
13973
|
+
this.selection.removeEventListener("activate", activate);
|
|
13974
|
+
}
|
|
13975
|
+
index(state) {
|
|
13976
|
+
const { selection } = this;
|
|
13977
|
+
const { resolver } = selection;
|
|
13978
|
+
this.indexer = state && (resolver.single || !resolver.union) ? new DataCubeIndexer(this.mc, { ...state, selection }) : null;
|
|
13979
|
+
}
|
|
13980
|
+
reset() {
|
|
13981
|
+
this.indexer?.reset();
|
|
13797
13982
|
}
|
|
13798
|
-
|
|
13799
|
-
|
|
13800
|
-
|
|
13801
|
-
const array = new Float64Array(size);
|
|
13802
|
-
for (let row = 0; row < size; ++row) {
|
|
13803
|
-
const v2 = column2.get(row);
|
|
13804
|
-
array[row] = v2 == null ? NaN : decimalToNumber(v2, scale);
|
|
13805
|
-
}
|
|
13806
|
-
return array;
|
|
13983
|
+
add(client) {
|
|
13984
|
+
(this.clients = new Set(this.clients)).add(client);
|
|
13985
|
+
return this;
|
|
13807
13986
|
}
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
{ length: 8 },
|
|
13812
|
-
(_2, i) => Math.pow(2, i * 32)
|
|
13813
|
-
);
|
|
13814
|
-
function decimalToNumber(v2, scale) {
|
|
13815
|
-
const n = v2.length;
|
|
13816
|
-
let x3 = 0;
|
|
13817
|
-
if (v2.signed && (v2[n - 1] | 0) < 0) {
|
|
13818
|
-
for (let i = 0; i < n; ++i) {
|
|
13819
|
-
x3 += ~v2[i] * BASE32[i];
|
|
13820
|
-
}
|
|
13821
|
-
x3 = -(x3 + 1);
|
|
13822
|
-
} else {
|
|
13823
|
-
for (let i = 0; i < n; ++i) {
|
|
13824
|
-
x3 += v2[i] * BASE32[i];
|
|
13987
|
+
remove(client) {
|
|
13988
|
+
if (this.clients.has(client)) {
|
|
13989
|
+
(this.clients = new Set(this.clients)).delete(client);
|
|
13825
13990
|
}
|
|
13991
|
+
return this;
|
|
13826
13992
|
}
|
|
13827
|
-
|
|
13993
|
+
/**
|
|
13994
|
+
* Internal method to process a selection update.
|
|
13995
|
+
* The return value is passed as a selection callback value.
|
|
13996
|
+
* @returns {Promise} A Promise that resolves when the update completes.
|
|
13997
|
+
*/
|
|
13998
|
+
update() {
|
|
13999
|
+
const { mc, indexer, clients, selection } = this;
|
|
14000
|
+
const hasIndex = indexer?.index(clients);
|
|
14001
|
+
return hasIndex ? indexer.update() : defaultUpdate(mc, clients, selection);
|
|
14002
|
+
}
|
|
14003
|
+
};
|
|
14004
|
+
function defaultUpdate(mc, clients, selection) {
|
|
14005
|
+
return Promise.all(Array.from(clients).map((client) => {
|
|
14006
|
+
const filter = selection.predicate(client);
|
|
14007
|
+
if (filter != null) {
|
|
14008
|
+
return mc.updateClient(client, client.query(filter));
|
|
14009
|
+
}
|
|
14010
|
+
}));
|
|
13828
14011
|
}
|
|
13829
14012
|
|
|
13830
|
-
// src/util/
|
|
13831
|
-
|
|
13832
|
-
|
|
13833
|
-
|
|
13834
|
-
|
|
13835
|
-
|
|
13836
|
-
|
|
13837
|
-
|
|
13838
|
-
|
|
13839
|
-
|
|
13840
|
-
|
|
13841
|
-
|
|
13842
|
-
};
|
|
13843
|
-
function summarize(table, column2, stats) {
|
|
13844
|
-
return Query.from(table).select(Array.from(stats, (s) => [s, statMap[s](column2)]));
|
|
14013
|
+
// src/util/query-result.js
|
|
14014
|
+
function queryResult() {
|
|
14015
|
+
let resolve;
|
|
14016
|
+
let reject;
|
|
14017
|
+
const p2 = new Promise((r, e) => {
|
|
14018
|
+
resolve = r;
|
|
14019
|
+
reject = e;
|
|
14020
|
+
});
|
|
14021
|
+
return Object.assign(p2, {
|
|
14022
|
+
fulfill: (value) => (resolve(value), p2),
|
|
14023
|
+
reject: (err) => (reject(err), p2)
|
|
14024
|
+
});
|
|
13845
14025
|
}
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
}
|
|
14026
|
+
|
|
14027
|
+
// src/QueryConsolidator.js
|
|
14028
|
+
function wait(callback) {
|
|
14029
|
+
const method = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : typeof setImmediate !== "undefined" ? setImmediate : setTimeout;
|
|
14030
|
+
return method(callback);
|
|
13852
14031
|
}
|
|
13853
|
-
|
|
13854
|
-
|
|
13855
|
-
|
|
13856
|
-
|
|
13857
|
-
|
|
13858
|
-
|
|
13859
|
-
|
|
13860
|
-
|
|
13861
|
-
|
|
13862
|
-
|
|
13863
|
-
|
|
13864
|
-
const result = await mc.query(
|
|
13865
|
-
summarize(table, column2, stats),
|
|
13866
|
-
{ persist: true }
|
|
13867
|
-
);
|
|
13868
|
-
for (let i = 0; i < result.numCols; ++i) {
|
|
13869
|
-
const { name } = result.schema.fields[i];
|
|
13870
|
-
const child = result.getChildAt(i);
|
|
13871
|
-
const convert = convertArrowValue(child.type);
|
|
13872
|
-
info[name] = convert(child.get(0));
|
|
14032
|
+
function consolidator(enqueue, cache, record) {
|
|
14033
|
+
let pending = [];
|
|
14034
|
+
let id = 0;
|
|
14035
|
+
function run() {
|
|
14036
|
+
const groups = entryGroups(pending, cache);
|
|
14037
|
+
pending = [];
|
|
14038
|
+
id = 0;
|
|
14039
|
+
for (const group of groups) {
|
|
14040
|
+
consolidate(group, enqueue, record);
|
|
14041
|
+
processResults(group, cache);
|
|
14042
|
+
}
|
|
13873
14043
|
}
|
|
13874
|
-
return info;
|
|
13875
|
-
}
|
|
13876
|
-
async function getTableInfo(mc, table) {
|
|
13877
|
-
const result = await mc.query(`DESCRIBE ${asRelation(table)}`);
|
|
13878
|
-
return Array.from(result).map((desc2) => ({
|
|
13879
|
-
table,
|
|
13880
|
-
column: desc2.column_name,
|
|
13881
|
-
sqlType: desc2.column_type,
|
|
13882
|
-
type: jsType(desc2.column_type),
|
|
13883
|
-
nullable: desc2.null === "YES"
|
|
13884
|
-
}));
|
|
13885
|
-
}
|
|
13886
|
-
|
|
13887
|
-
// src/util/void-logger.js
|
|
13888
|
-
function voidLogger() {
|
|
13889
14044
|
return {
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
},
|
|
13898
|
-
error() {
|
|
14045
|
+
add(entry, priority) {
|
|
14046
|
+
if (entry.request.type === "arrow") {
|
|
14047
|
+
id = id || wait(() => run());
|
|
14048
|
+
pending.push({ entry, priority, index: pending.length });
|
|
14049
|
+
} else {
|
|
14050
|
+
enqueue(entry, priority);
|
|
14051
|
+
}
|
|
13899
14052
|
}
|
|
13900
14053
|
};
|
|
13901
14054
|
}
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
|
|
13905
|
-
|
|
13906
|
-
|
|
13907
|
-
|
|
13908
|
-
|
|
13909
|
-
|
|
14055
|
+
function entryGroups(entries, cache) {
|
|
14056
|
+
const groups = [];
|
|
14057
|
+
const groupMap = /* @__PURE__ */ new Map();
|
|
14058
|
+
for (const query of entries) {
|
|
14059
|
+
const { entry: { request } } = query;
|
|
14060
|
+
const key = consolidationKey(request.query, cache);
|
|
14061
|
+
if (!groupMap.has(key)) {
|
|
14062
|
+
const list = [];
|
|
14063
|
+
groups.push(list);
|
|
14064
|
+
groupMap.set(key, list);
|
|
14065
|
+
}
|
|
14066
|
+
groupMap.get(key).push(query);
|
|
13910
14067
|
}
|
|
13911
|
-
return
|
|
14068
|
+
return groups;
|
|
13912
14069
|
}
|
|
13913
|
-
|
|
13914
|
-
|
|
13915
|
-
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
14070
|
+
function consolidationKey(query, cache) {
|
|
14071
|
+
const sql2 = `${query}`;
|
|
14072
|
+
if (query instanceof Query && !cache.get(sql2)) {
|
|
14073
|
+
if (
|
|
14074
|
+
// @ts-ignore
|
|
14075
|
+
query.orderby().length || query.where().length || // @ts-ignore
|
|
14076
|
+
query.qualify().length || query.having().length
|
|
14077
|
+
) {
|
|
14078
|
+
return sql2;
|
|
14079
|
+
}
|
|
14080
|
+
const q2 = query.clone().$select("*");
|
|
14081
|
+
const groupby = query.groupby();
|
|
14082
|
+
if (groupby.length) {
|
|
14083
|
+
const map = {};
|
|
14084
|
+
query.select().forEach(({ as, expr }) => map[as] = expr);
|
|
14085
|
+
q2.$groupby(groupby.map((e) => e instanceof Ref && map[e.column] || e));
|
|
14086
|
+
}
|
|
14087
|
+
return `${q2}`;
|
|
14088
|
+
} else {
|
|
14089
|
+
return sql2;
|
|
13924
14090
|
}
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
14091
|
+
}
|
|
14092
|
+
function consolidate(group, enqueue, record) {
|
|
14093
|
+
if (shouldConsolidate(group)) {
|
|
14094
|
+
enqueue({
|
|
14095
|
+
request: {
|
|
14096
|
+
type: "arrow",
|
|
14097
|
+
cache: false,
|
|
14098
|
+
record: false,
|
|
14099
|
+
query: group.query = consolidatedQuery(group, record)
|
|
14100
|
+
},
|
|
14101
|
+
result: group.result = queryResult()
|
|
14102
|
+
});
|
|
14103
|
+
} else {
|
|
14104
|
+
for (const { entry, priority } of group) {
|
|
14105
|
+
enqueue(entry, priority);
|
|
13929
14106
|
}
|
|
13930
|
-
return this._logger;
|
|
13931
14107
|
}
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
|
|
13940
|
-
|
|
13941
|
-
this.manager.cache(cache);
|
|
13942
|
-
this.manager.consolidate(consolidate2);
|
|
13943
|
-
this.indexes = indexes;
|
|
14108
|
+
}
|
|
14109
|
+
function shouldConsolidate(group) {
|
|
14110
|
+
if (group.length > 1) {
|
|
14111
|
+
const sql2 = `${group[0].entry.request.query}`;
|
|
14112
|
+
for (let i = 1; i < group.length; ++i) {
|
|
14113
|
+
if (sql2 !== `${group[i].entry.request.query}`) {
|
|
14114
|
+
return true;
|
|
14115
|
+
}
|
|
14116
|
+
}
|
|
13944
14117
|
}
|
|
13945
|
-
|
|
13946
|
-
|
|
13947
|
-
|
|
13948
|
-
|
|
13949
|
-
|
|
13950
|
-
|
|
13951
|
-
|
|
14118
|
+
return false;
|
|
14119
|
+
}
|
|
14120
|
+
function consolidatedQuery(group, record) {
|
|
14121
|
+
const maps = group.maps = [];
|
|
14122
|
+
const fields = /* @__PURE__ */ new Map();
|
|
14123
|
+
for (const item of group) {
|
|
14124
|
+
const { query: query2 } = item.entry.request;
|
|
14125
|
+
const fieldMap = [];
|
|
14126
|
+
maps.push(fieldMap);
|
|
14127
|
+
for (const { as, expr } of query2.select()) {
|
|
14128
|
+
const e = `${expr}`;
|
|
14129
|
+
if (!fields.has(e)) {
|
|
14130
|
+
fields.set(e, [`col${fields.size}`, expr]);
|
|
14131
|
+
}
|
|
14132
|
+
const [name] = fields.get(e);
|
|
14133
|
+
fieldMap.push([name, as]);
|
|
13952
14134
|
}
|
|
13953
|
-
|
|
13954
|
-
}
|
|
13955
|
-
databaseConnector(db) {
|
|
13956
|
-
return this.manager.connector(db);
|
|
13957
|
-
}
|
|
13958
|
-
// -- Query Management ----
|
|
13959
|
-
cancel(requests) {
|
|
13960
|
-
this.manager.cancel(requests);
|
|
14135
|
+
record(`${query2}`);
|
|
13961
14136
|
}
|
|
13962
|
-
|
|
13963
|
-
|
|
13964
|
-
|
|
14137
|
+
const query = group[0].entry.request.query.clone();
|
|
14138
|
+
const groupby = query.groupby();
|
|
14139
|
+
if (groupby.length) {
|
|
14140
|
+
const map = {};
|
|
14141
|
+
group.maps[0].forEach(([name, as]) => map[as] = name);
|
|
14142
|
+
query.$groupby(groupby.map((e) => e instanceof Ref && map[e.column] || e));
|
|
13965
14143
|
}
|
|
13966
|
-
query(
|
|
13967
|
-
|
|
13968
|
-
|
|
13969
|
-
|
|
13970
|
-
|
|
13971
|
-
|
|
13972
|
-
|
|
14144
|
+
return query.$select(Array.from(fields.values()));
|
|
14145
|
+
}
|
|
14146
|
+
async function processResults(group, cache) {
|
|
14147
|
+
const { maps, query, result } = group;
|
|
14148
|
+
if (!maps) return;
|
|
14149
|
+
let data;
|
|
14150
|
+
try {
|
|
14151
|
+
data = await result;
|
|
14152
|
+
} catch (err) {
|
|
14153
|
+
for (const { entry } of group) {
|
|
14154
|
+
entry.result.reject(err);
|
|
14155
|
+
}
|
|
14156
|
+
return;
|
|
13973
14157
|
}
|
|
13974
|
-
|
|
13975
|
-
|
|
14158
|
+
const describe = isDescribeQuery(query);
|
|
14159
|
+
group.forEach(({ entry }, index) => {
|
|
14160
|
+
const { request, result: result2 } = entry;
|
|
14161
|
+
const map = maps[index];
|
|
14162
|
+
const extract = describe && map ? filterResult(data, map) : map ? projectResult(data, map) : data;
|
|
14163
|
+
if (request.cache) {
|
|
14164
|
+
cache.set(String(request.query), extract);
|
|
14165
|
+
}
|
|
14166
|
+
result2.fulfill(extract);
|
|
14167
|
+
});
|
|
14168
|
+
}
|
|
14169
|
+
function projectResult(data, map) {
|
|
14170
|
+
const cols = {};
|
|
14171
|
+
for (const [name, as] of map) {
|
|
14172
|
+
cols[as] = data.getChild(name);
|
|
13976
14173
|
}
|
|
13977
|
-
|
|
13978
|
-
|
|
13979
|
-
|
|
14174
|
+
return new data.constructor(cols);
|
|
14175
|
+
}
|
|
14176
|
+
function filterResult(data, map) {
|
|
14177
|
+
const lookup = new Map(map);
|
|
14178
|
+
const result = [];
|
|
14179
|
+
for (const d of data) {
|
|
14180
|
+
if (lookup.has(d.column_name)) {
|
|
14181
|
+
result.push({ ...d, column_name: lookup.get(d.column_name) });
|
|
14182
|
+
}
|
|
13980
14183
|
}
|
|
13981
|
-
|
|
13982
|
-
|
|
13983
|
-
|
|
14184
|
+
return result;
|
|
14185
|
+
}
|
|
14186
|
+
|
|
14187
|
+
// src/util/cache.js
|
|
14188
|
+
var requestIdle = typeof requestIdleCallback !== "undefined" ? requestIdleCallback : setTimeout;
|
|
14189
|
+
var voidCache = () => ({
|
|
14190
|
+
get: () => void 0,
|
|
14191
|
+
set: (key, value) => value,
|
|
14192
|
+
clear: () => {
|
|
13984
14193
|
}
|
|
13985
|
-
|
|
13986
|
-
|
|
13987
|
-
|
|
13988
|
-
|
|
13989
|
-
|
|
13990
|
-
|
|
13991
|
-
|
|
13992
|
-
|
|
14194
|
+
});
|
|
14195
|
+
function lruCache({
|
|
14196
|
+
max: max2 = 1e3,
|
|
14197
|
+
// max entries
|
|
14198
|
+
ttl = 3 * 60 * 60 * 1e3
|
|
14199
|
+
// time-to-live, default 3 hours
|
|
14200
|
+
} = {}) {
|
|
14201
|
+
let cache = /* @__PURE__ */ new Map();
|
|
14202
|
+
function evict() {
|
|
14203
|
+
const expire = performance.now() - ttl;
|
|
14204
|
+
let lruKey = null;
|
|
14205
|
+
let lruLast = Infinity;
|
|
14206
|
+
for (const [key, value] of cache) {
|
|
14207
|
+
const { last: last2 } = value;
|
|
14208
|
+
if (last2 < lruLast) {
|
|
14209
|
+
lruKey = key;
|
|
14210
|
+
lruLast = last2;
|
|
14211
|
+
}
|
|
14212
|
+
if (expire > last2) {
|
|
14213
|
+
cache.delete(key);
|
|
13993
14214
|
}
|
|
13994
|
-
);
|
|
13995
|
-
}
|
|
13996
|
-
requestQuery(client, query) {
|
|
13997
|
-
this.filterGroups.get(client.filterBy)?.reset();
|
|
13998
|
-
return query ? this.updateClient(client, query) : client.update();
|
|
13999
|
-
}
|
|
14000
|
-
/**
|
|
14001
|
-
* Connect a client to the coordinator.
|
|
14002
|
-
* @param {import('./MosaicClient.js').MosaicClient} client the client to disconnect
|
|
14003
|
-
*/
|
|
14004
|
-
async connect(client) {
|
|
14005
|
-
const { clients, filterGroups, indexes } = this;
|
|
14006
|
-
if (clients.has(client)) {
|
|
14007
|
-
throw new Error("Client already connected.");
|
|
14008
14215
|
}
|
|
14009
|
-
|
|
14010
|
-
|
|
14011
|
-
const fields = client.fields();
|
|
14012
|
-
if (fields?.length) {
|
|
14013
|
-
client.fieldInfo(await queryFieldInfo(this, fields));
|
|
14216
|
+
if (lruKey) {
|
|
14217
|
+
cache.delete(lruKey);
|
|
14014
14218
|
}
|
|
14015
|
-
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
|
|
14219
|
+
}
|
|
14220
|
+
return {
|
|
14221
|
+
get(key) {
|
|
14222
|
+
const entry = cache.get(key);
|
|
14223
|
+
if (entry) {
|
|
14224
|
+
entry.last = performance.now();
|
|
14225
|
+
return entry.value;
|
|
14226
|
+
}
|
|
14227
|
+
},
|
|
14228
|
+
set(key, value) {
|
|
14229
|
+
cache.set(key, { last: performance.now(), value });
|
|
14230
|
+
if (cache.size > max2) requestIdle(evict);
|
|
14231
|
+
return value;
|
|
14232
|
+
},
|
|
14233
|
+
clear() {
|
|
14234
|
+
cache = /* @__PURE__ */ new Map();
|
|
14235
|
+
}
|
|
14236
|
+
};
|
|
14237
|
+
}
|
|
14238
|
+
|
|
14239
|
+
// src/util/priority-queue.js
|
|
14240
|
+
function priorityQueue(ranks) {
|
|
14241
|
+
const queue = Array.from(
|
|
14242
|
+
{ length: ranks },
|
|
14243
|
+
() => ({ head: null, tail: null })
|
|
14244
|
+
);
|
|
14245
|
+
return {
|
|
14246
|
+
/**
|
|
14247
|
+
* Indicate if the queue is empty.
|
|
14248
|
+
* @returns [boolean] true if empty, false otherwise.
|
|
14249
|
+
*/
|
|
14250
|
+
isEmpty() {
|
|
14251
|
+
return queue.every((list) => !list.head);
|
|
14252
|
+
},
|
|
14253
|
+
/**
|
|
14254
|
+
* Insert an item into the queue with a given priority rank.
|
|
14255
|
+
* @param {*} item The item to add.
|
|
14256
|
+
* @param {number} rank The integer priority rank.
|
|
14257
|
+
* Priority ranks are integers starting at zero.
|
|
14258
|
+
* Lower ranks indicate higher priority.
|
|
14259
|
+
*/
|
|
14260
|
+
insert(item, rank2) {
|
|
14261
|
+
const list = queue[rank2];
|
|
14262
|
+
if (!list) {
|
|
14263
|
+
throw new Error(`Invalid queue priority rank: ${rank2}`);
|
|
14264
|
+
}
|
|
14265
|
+
const node = { item, next: null };
|
|
14266
|
+
if (list.head === null) {
|
|
14267
|
+
list.head = list.tail = node;
|
|
14019
14268
|
} else {
|
|
14020
|
-
|
|
14021
|
-
|
|
14269
|
+
list.tail = list.tail.next = node;
|
|
14270
|
+
}
|
|
14271
|
+
},
|
|
14272
|
+
/**
|
|
14273
|
+
* Remove a set of items from the queue, regardless of priority rank.
|
|
14274
|
+
* If a provided item is not in the queue it will be ignored.
|
|
14275
|
+
* @param {(item: *) => boolean} test A predicate function to test
|
|
14276
|
+
* if an item should be removed (true to drop, false to keep).
|
|
14277
|
+
*/
|
|
14278
|
+
remove(test) {
|
|
14279
|
+
for (const list of queue) {
|
|
14280
|
+
let { head, tail } = list;
|
|
14281
|
+
for (let prev = null, curr = head; curr; prev = curr, curr = curr.next) {
|
|
14282
|
+
if (test(curr.item)) {
|
|
14283
|
+
if (curr === head) {
|
|
14284
|
+
head = curr.next;
|
|
14285
|
+
} else {
|
|
14286
|
+
prev.next = curr.next;
|
|
14287
|
+
}
|
|
14288
|
+
if (curr === tail) tail = prev || head;
|
|
14289
|
+
}
|
|
14290
|
+
}
|
|
14291
|
+
list.head = head;
|
|
14292
|
+
list.tail = tail;
|
|
14293
|
+
}
|
|
14294
|
+
},
|
|
14295
|
+
/**
|
|
14296
|
+
* Remove and return the next highest priority item.
|
|
14297
|
+
* @returns {*} The next item in the queue,
|
|
14298
|
+
* or undefined if this queue is empty.
|
|
14299
|
+
*/
|
|
14300
|
+
next() {
|
|
14301
|
+
for (const list of queue) {
|
|
14302
|
+
const { head } = list;
|
|
14303
|
+
if (head !== null) {
|
|
14304
|
+
list.head = head.next;
|
|
14305
|
+
if (list.tail === head) {
|
|
14306
|
+
list.tail = null;
|
|
14307
|
+
}
|
|
14308
|
+
return head.item;
|
|
14309
|
+
}
|
|
14022
14310
|
}
|
|
14023
14311
|
}
|
|
14024
|
-
|
|
14025
|
-
|
|
14026
|
-
/**
|
|
14027
|
-
* Disconnect a client from the coordinator.
|
|
14028
|
-
*
|
|
14029
|
-
* @param {import('./MosaicClient.js').MosaicClient} client the client to disconnect
|
|
14030
|
-
*/
|
|
14031
|
-
disconnect(client) {
|
|
14032
|
-
const { clients, filterGroups } = this;
|
|
14033
|
-
if (!clients.has(client)) return;
|
|
14034
|
-
clients.delete(client);
|
|
14035
|
-
filterGroups.get(client.filterBy)?.remove(client);
|
|
14036
|
-
client.coordinator = null;
|
|
14037
|
-
}
|
|
14038
|
-
};
|
|
14312
|
+
};
|
|
14313
|
+
}
|
|
14039
14314
|
|
|
14040
|
-
// src/
|
|
14041
|
-
var
|
|
14042
|
-
|
|
14043
|
-
* Create a new asynchronous dispatcher instance.
|
|
14044
|
-
*/
|
|
14315
|
+
// src/QueryManager.js
|
|
14316
|
+
var Priority = { High: 0, Normal: 1, Low: 2 };
|
|
14317
|
+
var QueryManager = class {
|
|
14045
14318
|
constructor() {
|
|
14046
|
-
this.
|
|
14319
|
+
this.queue = priorityQueue(3);
|
|
14320
|
+
this.db = null;
|
|
14321
|
+
this.clientCache = null;
|
|
14322
|
+
this._logger = null;
|
|
14323
|
+
this._logQueries = false;
|
|
14324
|
+
this.recorders = [];
|
|
14325
|
+
this.pending = null;
|
|
14326
|
+
this._consolidate = null;
|
|
14047
14327
|
}
|
|
14048
|
-
|
|
14049
|
-
|
|
14050
|
-
|
|
14051
|
-
|
|
14052
|
-
|
|
14053
|
-
|
|
14054
|
-
|
|
14055
|
-
|
|
14056
|
-
|
|
14057
|
-
|
|
14058
|
-
|
|
14059
|
-
|
|
14060
|
-
|
|
14061
|
-
|
|
14328
|
+
next() {
|
|
14329
|
+
if (this.pending || this.queue.isEmpty()) return;
|
|
14330
|
+
const { request, result } = this.queue.next();
|
|
14331
|
+
this.pending = this.submit(request, result);
|
|
14332
|
+
this.pending.finally(() => {
|
|
14333
|
+
this.pending = null;
|
|
14334
|
+
this.next();
|
|
14335
|
+
});
|
|
14336
|
+
}
|
|
14337
|
+
enqueue(entry, priority = Priority.Normal) {
|
|
14338
|
+
this.queue.insert(entry, priority);
|
|
14339
|
+
this.next();
|
|
14340
|
+
}
|
|
14341
|
+
recordQuery(sql2) {
|
|
14342
|
+
if (this.recorders.length && sql2) {
|
|
14343
|
+
this.recorders.forEach((rec) => rec.add(sql2));
|
|
14062
14344
|
}
|
|
14063
|
-
const entry = this._callbacks.get(type);
|
|
14064
|
-
entry.callbacks.add(callback);
|
|
14065
14345
|
}
|
|
14066
|
-
|
|
14067
|
-
|
|
14068
|
-
|
|
14069
|
-
|
|
14070
|
-
|
|
14071
|
-
|
|
14072
|
-
|
|
14073
|
-
|
|
14074
|
-
|
|
14075
|
-
|
|
14346
|
+
async submit(request, result) {
|
|
14347
|
+
try {
|
|
14348
|
+
const { query, type, cache = false, record = true, options } = request;
|
|
14349
|
+
const sql2 = query ? `${query}` : null;
|
|
14350
|
+
if (record) {
|
|
14351
|
+
this.recordQuery(sql2);
|
|
14352
|
+
}
|
|
14353
|
+
if (cache) {
|
|
14354
|
+
const cached = this.clientCache.get(sql2);
|
|
14355
|
+
if (cached) {
|
|
14356
|
+
this._logger.debug("Cache");
|
|
14357
|
+
result.fulfill(cached);
|
|
14358
|
+
return;
|
|
14359
|
+
}
|
|
14360
|
+
}
|
|
14361
|
+
const t0 = performance.now();
|
|
14362
|
+
if (this._logQueries) {
|
|
14363
|
+
this._logger.debug("Query", { type, sql: sql2, ...options });
|
|
14364
|
+
}
|
|
14365
|
+
const data = await this.db.query({ type, sql: sql2, ...options });
|
|
14366
|
+
if (cache) this.clientCache.set(sql2, data);
|
|
14367
|
+
this._logger.debug(`Request: ${(performance.now() - t0).toFixed(1)}`);
|
|
14368
|
+
result.fulfill(data);
|
|
14369
|
+
} catch (err) {
|
|
14370
|
+
result.reject(err);
|
|
14076
14371
|
}
|
|
14077
14372
|
}
|
|
14078
|
-
|
|
14079
|
-
|
|
14080
|
-
* This default implementation simply returns the input value as-is.
|
|
14081
|
-
* Subclasses may override this method to implement custom transformations
|
|
14082
|
-
* prior to emitting an event value to all listeners.
|
|
14083
|
-
* @param {string} type The event type.
|
|
14084
|
-
* @param {*} value The event value.
|
|
14085
|
-
* @returns The (possibly transformed) event value to emit.
|
|
14086
|
-
*/
|
|
14087
|
-
willEmit(type, value) {
|
|
14088
|
-
return value;
|
|
14373
|
+
cache(value) {
|
|
14374
|
+
return value !== void 0 ? this.clientCache = value === true ? lruCache() : value || voidCache() : this.clientCache;
|
|
14089
14375
|
}
|
|
14090
|
-
|
|
14091
|
-
|
|
14092
|
-
* queue of unemitted event values prior to enqueueing a new value.
|
|
14093
|
-
* This default implementation simply returns null, indicating that
|
|
14094
|
-
* any other unemitted event values should be dropped (that is, all
|
|
14095
|
-
* queued events are filtered)
|
|
14096
|
-
* @param {string} type The event type.
|
|
14097
|
-
* @param {*} value The new event value that will be enqueued.
|
|
14098
|
-
* @returns {(value: *) => boolean|null} A dispatch queue filter
|
|
14099
|
-
* function, or null if all unemitted event values should be filtered.
|
|
14100
|
-
*/
|
|
14101
|
-
emitQueueFilter(type, value) {
|
|
14102
|
-
return null;
|
|
14376
|
+
logger(value) {
|
|
14377
|
+
return value ? this._logger = value : this._logger;
|
|
14103
14378
|
}
|
|
14104
|
-
|
|
14105
|
-
|
|
14106
|
-
* @param {string} type The event type.
|
|
14107
|
-
*/
|
|
14108
|
-
cancel(type) {
|
|
14109
|
-
const entry = this._callbacks.get(type);
|
|
14110
|
-
entry?.queue.clear();
|
|
14379
|
+
logQueries(value) {
|
|
14380
|
+
return value !== void 0 ? this._logQueries = !!value : this._logQueries;
|
|
14111
14381
|
}
|
|
14112
|
-
|
|
14113
|
-
|
|
14114
|
-
|
|
14115
|
-
|
|
14116
|
-
|
|
14117
|
-
|
|
14118
|
-
|
|
14119
|
-
|
|
14120
|
-
|
|
14121
|
-
|
|
14122
|
-
|
|
14123
|
-
|
|
14124
|
-
|
|
14382
|
+
connector(connector) {
|
|
14383
|
+
return connector ? this.db = connector : this.db;
|
|
14384
|
+
}
|
|
14385
|
+
consolidate(flag) {
|
|
14386
|
+
if (flag && !this._consolidate) {
|
|
14387
|
+
this._consolidate = consolidator(this.enqueue.bind(this), this.clientCache, this.recordQuery.bind(this));
|
|
14388
|
+
} else if (!flag && this._consolidate) {
|
|
14389
|
+
this._consolidate = null;
|
|
14390
|
+
}
|
|
14391
|
+
}
|
|
14392
|
+
request(request, priority = Priority.Normal) {
|
|
14393
|
+
const result = queryResult();
|
|
14394
|
+
const entry = { request, result };
|
|
14395
|
+
if (this._consolidate) {
|
|
14396
|
+
this._consolidate.add(entry, priority);
|
|
14125
14397
|
} else {
|
|
14126
|
-
|
|
14127
|
-
const { callbacks, queue } = entry;
|
|
14128
|
-
if (callbacks?.size) {
|
|
14129
|
-
const callbackValues = Array.from(callbacks, (cb) => cb(event));
|
|
14130
|
-
entry.pending = Promise.allSettled(callbackValues).then(() => {
|
|
14131
|
-
entry.pending = null;
|
|
14132
|
-
if (!queue.isEmpty()) {
|
|
14133
|
-
this.emit(type, queue.dequeue());
|
|
14134
|
-
}
|
|
14135
|
-
});
|
|
14136
|
-
}
|
|
14398
|
+
this.enqueue(entry, priority);
|
|
14137
14399
|
}
|
|
14400
|
+
return result;
|
|
14138
14401
|
}
|
|
14139
|
-
|
|
14140
|
-
|
|
14141
|
-
|
|
14142
|
-
* Create a new dispatch queue instance.
|
|
14143
|
-
*/
|
|
14144
|
-
constructor() {
|
|
14145
|
-
this.clear();
|
|
14402
|
+
cancel(requests) {
|
|
14403
|
+
const set = new Set(requests);
|
|
14404
|
+
this.queue.remove(({ result }) => set.has(result));
|
|
14146
14405
|
}
|
|
14147
|
-
/**
|
|
14148
|
-
* Clear the queue state of all event values.
|
|
14149
|
-
*/
|
|
14150
14406
|
clear() {
|
|
14151
|
-
this.
|
|
14152
|
-
|
|
14153
|
-
|
|
14154
|
-
|
|
14155
|
-
* @returns {boolean} True if queue is empty, false otherwise.
|
|
14156
|
-
*/
|
|
14157
|
-
isEmpty() {
|
|
14158
|
-
return !this.next;
|
|
14407
|
+
this.queue.remove(({ result }) => {
|
|
14408
|
+
result.reject("Cleared");
|
|
14409
|
+
return true;
|
|
14410
|
+
});
|
|
14159
14411
|
}
|
|
14160
|
-
|
|
14161
|
-
|
|
14162
|
-
|
|
14163
|
-
|
|
14164
|
-
|
|
14165
|
-
|
|
14166
|
-
|
|
14167
|
-
|
|
14168
|
-
|
|
14169
|
-
|
|
14170
|
-
|
|
14171
|
-
|
|
14172
|
-
|
|
14173
|
-
|
|
14174
|
-
|
|
14175
|
-
while (curr.next) {
|
|
14176
|
-
if (filter(curr.next.value)) {
|
|
14177
|
-
curr = curr.next;
|
|
14178
|
-
} else {
|
|
14179
|
-
curr.next = curr.next.next;
|
|
14180
|
-
}
|
|
14412
|
+
record() {
|
|
14413
|
+
let state = [];
|
|
14414
|
+
const recorder = {
|
|
14415
|
+
add(query) {
|
|
14416
|
+
state.push(query);
|
|
14417
|
+
},
|
|
14418
|
+
reset() {
|
|
14419
|
+
state = [];
|
|
14420
|
+
},
|
|
14421
|
+
snapshot() {
|
|
14422
|
+
return state.slice();
|
|
14423
|
+
},
|
|
14424
|
+
stop() {
|
|
14425
|
+
this.recorders = this.recorders.filter((x3) => x3 !== recorder);
|
|
14426
|
+
return state;
|
|
14181
14427
|
}
|
|
14182
|
-
|
|
14183
|
-
|
|
14184
|
-
|
|
14185
|
-
}
|
|
14186
|
-
}
|
|
14187
|
-
/**
|
|
14188
|
-
* Remove and return the next queued event value.
|
|
14189
|
-
* @returns {*} The next event value in the queue.
|
|
14190
|
-
*/
|
|
14191
|
-
dequeue() {
|
|
14192
|
-
const { next } = this;
|
|
14193
|
-
this.next = next?.next;
|
|
14194
|
-
return next?.value;
|
|
14428
|
+
};
|
|
14429
|
+
this.recorders.push(recorder);
|
|
14430
|
+
return recorder;
|
|
14195
14431
|
}
|
|
14196
14432
|
};
|
|
14197
14433
|
|
|
14198
|
-
// src/util/
|
|
14199
|
-
function
|
|
14200
|
-
|
|
14201
|
-
|
|
14202
|
-
|
|
14203
|
-
|
|
14204
|
-
|
|
14205
|
-
|
|
14206
|
-
|
|
14207
|
-
|
|
14208
|
-
|
|
14209
|
-
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
|
|
14215
|
-
|
|
14216
|
-
|
|
14217
|
-
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
|
|
14239
|
-
|
|
14240
|
-
|
|
14241
|
-
|
|
14242
|
-
}
|
|
14243
|
-
|
|
14244
|
-
values.forEach((v2) => isParam(v2) ? v2.addEventListener("value", update2) : 0);
|
|
14245
|
-
return p2;
|
|
14246
|
-
}
|
|
14247
|
-
return new _Param(values);
|
|
14434
|
+
// src/util/js-type.js
|
|
14435
|
+
function jsType(type) {
|
|
14436
|
+
switch (type) {
|
|
14437
|
+
case "BIGINT":
|
|
14438
|
+
case "HUGEINT":
|
|
14439
|
+
case "INTEGER":
|
|
14440
|
+
case "SMALLINT":
|
|
14441
|
+
case "TINYINT":
|
|
14442
|
+
case "UBIGINT":
|
|
14443
|
+
case "UINTEGER":
|
|
14444
|
+
case "USMALLINT":
|
|
14445
|
+
case "UTINYINT":
|
|
14446
|
+
case "DOUBLE":
|
|
14447
|
+
case "FLOAT":
|
|
14448
|
+
case "REAL":
|
|
14449
|
+
return "number";
|
|
14450
|
+
case "DATE":
|
|
14451
|
+
case "TIMESTAMP":
|
|
14452
|
+
case "TIMESTAMPTZ":
|
|
14453
|
+
case "TIMESTAMP WITH TIME ZONE":
|
|
14454
|
+
case "TIME":
|
|
14455
|
+
case "TIMESTAMP_NS":
|
|
14456
|
+
return "date";
|
|
14457
|
+
case "BOOLEAN":
|
|
14458
|
+
return "boolean";
|
|
14459
|
+
case "VARCHAR":
|
|
14460
|
+
case "UUID":
|
|
14461
|
+
case "JSON":
|
|
14462
|
+
return "string";
|
|
14463
|
+
case "ARRAY":
|
|
14464
|
+
case "LIST":
|
|
14465
|
+
return "array";
|
|
14466
|
+
case "BLOB":
|
|
14467
|
+
case "STRUCT":
|
|
14468
|
+
case "MAP":
|
|
14469
|
+
case "GEOMETRY":
|
|
14470
|
+
return "object";
|
|
14471
|
+
default:
|
|
14472
|
+
if (type.startsWith("DECIMAL")) {
|
|
14473
|
+
return "number";
|
|
14474
|
+
} else if (type.startsWith("STRUCT") || type.startsWith("MAP")) {
|
|
14475
|
+
return "object";
|
|
14476
|
+
} else if (type.endsWith("]")) {
|
|
14477
|
+
return "array";
|
|
14478
|
+
}
|
|
14479
|
+
throw new Error(`Unsupported type: ${type}`);
|
|
14248
14480
|
}
|
|
14249
|
-
|
|
14250
|
-
|
|
14251
|
-
|
|
14252
|
-
|
|
14253
|
-
|
|
14481
|
+
}
|
|
14482
|
+
|
|
14483
|
+
// src/util/convert-arrow.js
|
|
14484
|
+
function isArrowTable(values) {
|
|
14485
|
+
return typeof values?.getChild === "function";
|
|
14486
|
+
}
|
|
14487
|
+
function convertArrowArrayType(type) {
|
|
14488
|
+
return DataType.isInt(type) || DataType.isFloat(type) || DataType.isDecimal(type) ? Float64Array : Array;
|
|
14489
|
+
}
|
|
14490
|
+
function convertArrowValue(type) {
|
|
14491
|
+
if (DataType.isTimestamp(type)) {
|
|
14492
|
+
return (v2) => v2 == null ? v2 : new Date(v2);
|
|
14254
14493
|
}
|
|
14255
|
-
|
|
14256
|
-
|
|
14257
|
-
* @param {*} value The new value of the Param.
|
|
14258
|
-
* @param {object} [options] The update options.
|
|
14259
|
-
* @param {boolean} [options.force] A boolean flag indicating if the Param
|
|
14260
|
-
* should emit a 'value' event even if the internal value is unchanged.
|
|
14261
|
-
* @returns {this} This Param instance.
|
|
14262
|
-
*/
|
|
14263
|
-
update(value, { force } = {}) {
|
|
14264
|
-
const shouldEmit = distinct(this._value, value) || force;
|
|
14265
|
-
if (shouldEmit) {
|
|
14266
|
-
this.emit("value", value);
|
|
14267
|
-
} else {
|
|
14268
|
-
this.cancel("value");
|
|
14269
|
-
}
|
|
14270
|
-
return this;
|
|
14494
|
+
if (DataType.isInt(type) && type.bitWidth >= 64) {
|
|
14495
|
+
return (v2) => v2 == null ? v2 : Number(v2);
|
|
14271
14496
|
}
|
|
14272
|
-
|
|
14273
|
-
|
|
14274
|
-
|
|
14275
|
-
* @param {string} type The event type.
|
|
14276
|
-
* @param {*} value The input event value.
|
|
14277
|
-
* @returns {*} The input event value.
|
|
14278
|
-
*/
|
|
14279
|
-
willEmit(type, value) {
|
|
14280
|
-
if (type === "value") {
|
|
14281
|
-
this._value = value;
|
|
14282
|
-
}
|
|
14283
|
-
return value;
|
|
14497
|
+
if (DataType.isDecimal(type)) {
|
|
14498
|
+
const scale = 1 / Math.pow(10, type.scale);
|
|
14499
|
+
return (v2) => v2 == null ? v2 : decimalToNumber(v2, scale);
|
|
14284
14500
|
}
|
|
14285
|
-
|
|
14286
|
-
|
|
14287
|
-
// src/Selection.js
|
|
14288
|
-
function isSelection(x3) {
|
|
14289
|
-
return x3 instanceof Selection;
|
|
14501
|
+
return (v2) => v2;
|
|
14290
14502
|
}
|
|
14291
|
-
|
|
14292
|
-
|
|
14293
|
-
|
|
14294
|
-
|
|
14295
|
-
|
|
14296
|
-
|
|
14297
|
-
|
|
14298
|
-
|
|
14299
|
-
|
|
14300
|
-
|
|
14301
|
-
static intersect({ cross = false } = {}) {
|
|
14302
|
-
return new _Selection(new SelectionResolver({ cross }));
|
|
14503
|
+
function convertArrowColumn(column2) {
|
|
14504
|
+
const { type } = column2;
|
|
14505
|
+
if (DataType.isTimestamp(type)) {
|
|
14506
|
+
const size = column2.length;
|
|
14507
|
+
const array = new Array(size);
|
|
14508
|
+
for (let row = 0; row < size; ++row) {
|
|
14509
|
+
const v2 = column2.get(row);
|
|
14510
|
+
array[row] = v2 == null ? null : new Date(v2);
|
|
14511
|
+
}
|
|
14512
|
+
return array;
|
|
14303
14513
|
}
|
|
14304
|
-
|
|
14305
|
-
|
|
14306
|
-
|
|
14307
|
-
|
|
14308
|
-
|
|
14309
|
-
|
|
14310
|
-
|
|
14311
|
-
|
|
14312
|
-
*/
|
|
14313
|
-
static union({ cross = false } = {}) {
|
|
14314
|
-
return new _Selection(new SelectionResolver({ cross, union: true }));
|
|
14514
|
+
if (DataType.isInt(type) && type.bitWidth >= 64) {
|
|
14515
|
+
const size = column2.length;
|
|
14516
|
+
const array = column2.nullCount ? new Array(size) : new Float64Array(size);
|
|
14517
|
+
for (let row = 0; row < size; ++row) {
|
|
14518
|
+
const v2 = column2.get(row);
|
|
14519
|
+
array[row] = v2 == null ? null : Number(v2);
|
|
14520
|
+
}
|
|
14521
|
+
return array;
|
|
14315
14522
|
}
|
|
14316
|
-
|
|
14317
|
-
|
|
14318
|
-
|
|
14319
|
-
|
|
14320
|
-
|
|
14321
|
-
|
|
14322
|
-
|
|
14323
|
-
|
|
14324
|
-
|
|
14325
|
-
static single({ cross = false } = {}) {
|
|
14326
|
-
return new _Selection(new SelectionResolver({ cross, single: true }));
|
|
14523
|
+
if (DataType.isDecimal(type)) {
|
|
14524
|
+
const scale = 1 / Math.pow(10, type.scale);
|
|
14525
|
+
const size = column2.length;
|
|
14526
|
+
const array = column2.nullCount ? new Array(size) : new Float64Array(size);
|
|
14527
|
+
for (let row = 0; row < size; ++row) {
|
|
14528
|
+
const v2 = column2.get(row);
|
|
14529
|
+
array[row] = v2 == null ? null : decimalToNumber(v2, scale);
|
|
14530
|
+
}
|
|
14531
|
+
return array;
|
|
14327
14532
|
}
|
|
14328
|
-
|
|
14329
|
-
|
|
14330
|
-
* cross-filtered intersect resolution strategy.
|
|
14331
|
-
* @returns {Selection} The new Selection instance.
|
|
14332
|
-
*/
|
|
14333
|
-
static crossfilter() {
|
|
14334
|
-
return new _Selection(new SelectionResolver({ cross: true }));
|
|
14533
|
+
if (column2.nullCount) {
|
|
14534
|
+
return Array.from(column2);
|
|
14335
14535
|
}
|
|
14336
|
-
|
|
14337
|
-
|
|
14338
|
-
|
|
14339
|
-
|
|
14340
|
-
|
|
14341
|
-
|
|
14342
|
-
|
|
14343
|
-
|
|
14344
|
-
|
|
14536
|
+
return column2.toArray();
|
|
14537
|
+
}
|
|
14538
|
+
var BASE32 = Array.from(
|
|
14539
|
+
{ length: 8 },
|
|
14540
|
+
(_2, i) => Math.pow(2, i * 32)
|
|
14541
|
+
);
|
|
14542
|
+
function decimalToNumber(v2, scale) {
|
|
14543
|
+
const n = v2.length;
|
|
14544
|
+
let x3 = 0;
|
|
14545
|
+
if (v2.signed && (v2[n - 1] | 0) < 0) {
|
|
14546
|
+
for (let i = 0; i < n; ++i) {
|
|
14547
|
+
x3 += ~v2[i] * BASE32[i];
|
|
14548
|
+
}
|
|
14549
|
+
x3 = -(x3 + 1);
|
|
14550
|
+
} else {
|
|
14551
|
+
for (let i = 0; i < n; ++i) {
|
|
14552
|
+
x3 += v2[i] * BASE32[i];
|
|
14553
|
+
}
|
|
14345
14554
|
}
|
|
14346
|
-
|
|
14347
|
-
|
|
14348
|
-
|
|
14349
|
-
|
|
14350
|
-
|
|
14351
|
-
|
|
14352
|
-
|
|
14353
|
-
|
|
14555
|
+
return x3 * scale;
|
|
14556
|
+
}
|
|
14557
|
+
|
|
14558
|
+
// src/util/field-info.js
|
|
14559
|
+
var Count = "count";
|
|
14560
|
+
var Nulls = "nulls";
|
|
14561
|
+
var Max = "max";
|
|
14562
|
+
var Min = "min";
|
|
14563
|
+
var Distinct = "distinct";
|
|
14564
|
+
var statMap = {
|
|
14565
|
+
[Count]: count,
|
|
14566
|
+
[Distinct]: (column2) => count(column2).distinct(),
|
|
14567
|
+
[Max]: max,
|
|
14568
|
+
[Min]: min,
|
|
14569
|
+
[Nulls]: (column2) => count().where(isNull(column2))
|
|
14570
|
+
};
|
|
14571
|
+
function summarize(table, column2, stats) {
|
|
14572
|
+
return Query.from(table).select(Array.from(stats, (s) => [s, statMap[s](column2)]));
|
|
14573
|
+
}
|
|
14574
|
+
async function queryFieldInfo(mc, fields) {
|
|
14575
|
+
if (fields.length === 1 && `${fields[0].column}` === "*") {
|
|
14576
|
+
return getTableInfo(mc, fields[0].table);
|
|
14577
|
+
} else {
|
|
14578
|
+
return (await Promise.all(fields.map((f2) => getFieldInfo(mc, f2)))).filter((x3) => x3);
|
|
14354
14579
|
}
|
|
14355
|
-
|
|
14356
|
-
|
|
14357
|
-
|
|
14358
|
-
|
|
14359
|
-
|
|
14360
|
-
|
|
14361
|
-
|
|
14362
|
-
|
|
14363
|
-
|
|
14364
|
-
|
|
14365
|
-
|
|
14580
|
+
}
|
|
14581
|
+
async function getFieldInfo(mc, { table, column: column2, stats }) {
|
|
14582
|
+
const q2 = Query.from({ source: table }).select({ column: column2 }).groupby(column2.aggregate ? sql`ALL` : []);
|
|
14583
|
+
const [desc2] = Array.from(await mc.query(Query.describe(q2)));
|
|
14584
|
+
const info = {
|
|
14585
|
+
table,
|
|
14586
|
+
column: `${column2}`,
|
|
14587
|
+
sqlType: desc2.column_type,
|
|
14588
|
+
type: jsType(desc2.column_type),
|
|
14589
|
+
nullable: desc2.null === "YES"
|
|
14590
|
+
};
|
|
14591
|
+
if (!(stats?.length || stats?.size)) return info;
|
|
14592
|
+
const result = await mc.query(
|
|
14593
|
+
summarize(table, column2, stats),
|
|
14594
|
+
{ persist: true }
|
|
14595
|
+
);
|
|
14596
|
+
for (let i = 0; i < result.numCols; ++i) {
|
|
14597
|
+
const { name } = result.schema.fields[i];
|
|
14598
|
+
const child = result.getChildAt(i);
|
|
14599
|
+
const convert = convertArrowValue(child.type);
|
|
14600
|
+
info[name] = convert(child.get(0));
|
|
14366
14601
|
}
|
|
14367
|
-
|
|
14368
|
-
|
|
14369
|
-
|
|
14370
|
-
|
|
14371
|
-
|
|
14602
|
+
return info;
|
|
14603
|
+
}
|
|
14604
|
+
async function getTableInfo(mc, table) {
|
|
14605
|
+
const result = await mc.query(`DESCRIBE ${asRelation(table)}`);
|
|
14606
|
+
return Array.from(result).map((desc2) => ({
|
|
14607
|
+
table,
|
|
14608
|
+
column: desc2.column_name,
|
|
14609
|
+
sqlType: desc2.column_type,
|
|
14610
|
+
type: jsType(desc2.column_type),
|
|
14611
|
+
nullable: desc2.null === "YES"
|
|
14612
|
+
}));
|
|
14613
|
+
}
|
|
14614
|
+
|
|
14615
|
+
// src/util/void-logger.js
|
|
14616
|
+
function voidLogger() {
|
|
14617
|
+
return {
|
|
14618
|
+
debug() {
|
|
14619
|
+
},
|
|
14620
|
+
info() {
|
|
14621
|
+
},
|
|
14622
|
+
log() {
|
|
14623
|
+
},
|
|
14624
|
+
warn() {
|
|
14625
|
+
},
|
|
14626
|
+
error() {
|
|
14627
|
+
}
|
|
14628
|
+
};
|
|
14629
|
+
}
|
|
14630
|
+
|
|
14631
|
+
// src/Coordinator.js
|
|
14632
|
+
var _instance;
|
|
14633
|
+
function coordinator(instance16) {
|
|
14634
|
+
if (instance16) {
|
|
14635
|
+
_instance = instance16;
|
|
14636
|
+
} else if (_instance == null) {
|
|
14637
|
+
_instance = new Coordinator();
|
|
14372
14638
|
}
|
|
14373
|
-
|
|
14374
|
-
|
|
14375
|
-
|
|
14376
|
-
|
|
14377
|
-
|
|
14378
|
-
|
|
14639
|
+
return _instance;
|
|
14640
|
+
}
|
|
14641
|
+
var Coordinator = class {
|
|
14642
|
+
constructor(db = socketConnector(), options = {}) {
|
|
14643
|
+
const {
|
|
14644
|
+
logger = console,
|
|
14645
|
+
manager = new QueryManager()
|
|
14646
|
+
} = options;
|
|
14647
|
+
this.manager = manager;
|
|
14648
|
+
this.logger(logger);
|
|
14649
|
+
this.configure(options);
|
|
14650
|
+
this.databaseConnector(db);
|
|
14651
|
+
this.clear();
|
|
14379
14652
|
}
|
|
14380
|
-
|
|
14381
|
-
|
|
14382
|
-
|
|
14383
|
-
|
|
14384
|
-
|
|
14653
|
+
logger(logger) {
|
|
14654
|
+
if (arguments.length) {
|
|
14655
|
+
this._logger = logger || voidLogger();
|
|
14656
|
+
this.manager.logger(this._logger);
|
|
14657
|
+
}
|
|
14658
|
+
return this._logger;
|
|
14385
14659
|
}
|
|
14386
14660
|
/**
|
|
14387
|
-
*
|
|
14661
|
+
* Set configuration options for this coordinator.
|
|
14662
|
+
* @param {object} [options] Configration options.
|
|
14663
|
+
* @param {boolean} [options.cache=true] Boolean flag to enable/disable query caching.
|
|
14664
|
+
* @param {boolean} [options.consolidate=true] Boolean flag to enable/disable query consolidation.
|
|
14665
|
+
* @param {boolean|object} [options.indexes=true] Boolean flag to enable/disable
|
|
14666
|
+
* automatic data cube indexes or an index options object.
|
|
14388
14667
|
*/
|
|
14389
|
-
|
|
14390
|
-
|
|
14668
|
+
configure({ cache = true, consolidate: consolidate2 = true, indexes = true } = {}) {
|
|
14669
|
+
this.manager.cache(cache);
|
|
14670
|
+
this.manager.consolidate(consolidate2);
|
|
14671
|
+
this.indexes = indexes;
|
|
14391
14672
|
}
|
|
14392
|
-
|
|
14393
|
-
|
|
14394
|
-
|
|
14395
|
-
|
|
14396
|
-
|
|
14397
|
-
|
|
14673
|
+
clear({ clients = true, cache = true } = {}) {
|
|
14674
|
+
this.manager.clear();
|
|
14675
|
+
if (clients) {
|
|
14676
|
+
this.clients?.forEach((client) => this.disconnect(client));
|
|
14677
|
+
this.filterGroups?.forEach((group) => group.finalize());
|
|
14678
|
+
this.clients = /* @__PURE__ */ new Set();
|
|
14679
|
+
this.filterGroups = /* @__PURE__ */ new Map();
|
|
14680
|
+
}
|
|
14681
|
+
if (cache) this.manager.cache().clear();
|
|
14398
14682
|
}
|
|
14399
|
-
|
|
14400
|
-
|
|
14401
|
-
* @param {*} clause The selection clause to add.
|
|
14402
|
-
* @returns {this} This Selection instance.
|
|
14403
|
-
*/
|
|
14404
|
-
update(clause) {
|
|
14405
|
-
this._resolved = this._resolver.resolve(this._resolved, clause, true);
|
|
14406
|
-
this._resolved.active = clause;
|
|
14407
|
-
return super.update(this._resolved);
|
|
14683
|
+
databaseConnector(db) {
|
|
14684
|
+
return this.manager.connector(db);
|
|
14408
14685
|
}
|
|
14409
|
-
|
|
14410
|
-
|
|
14411
|
-
|
|
14412
|
-
* @param {string} type The event type.
|
|
14413
|
-
* @param {*} value The input event value.
|
|
14414
|
-
* @returns {*} For value-typed events, returns the active clause
|
|
14415
|
-
* values. Otherwise returns the input event value as-is.
|
|
14416
|
-
*/
|
|
14417
|
-
willEmit(type, value) {
|
|
14418
|
-
if (type === "value") {
|
|
14419
|
-
this._value = value;
|
|
14420
|
-
return this.value;
|
|
14421
|
-
}
|
|
14422
|
-
return value;
|
|
14686
|
+
// -- Query Management ----
|
|
14687
|
+
cancel(requests) {
|
|
14688
|
+
this.manager.cancel(requests);
|
|
14423
14689
|
}
|
|
14424
|
-
|
|
14425
|
-
|
|
14426
|
-
|
|
14427
|
-
* @param {string} type The event type.
|
|
14428
|
-
* @param {*} value The new event value that will be enqueued.
|
|
14429
|
-
* @returns {(value: *) => boolean|null} For value-typed events,
|
|
14430
|
-
* returns a dispatch queue filter function. Otherwise returns null.
|
|
14431
|
-
*/
|
|
14432
|
-
emitQueueFilter(type, value) {
|
|
14433
|
-
return type === "value" ? this._resolver.queueFilter(value) : null;
|
|
14690
|
+
exec(query, { priority = Priority.Normal } = {}) {
|
|
14691
|
+
query = Array.isArray(query) ? query.join(";\n") : query;
|
|
14692
|
+
return this.manager.request({ type: "exec", query }, priority);
|
|
14434
14693
|
}
|
|
14435
|
-
|
|
14436
|
-
|
|
14437
|
-
|
|
14438
|
-
|
|
14439
|
-
|
|
14440
|
-
|
|
14441
|
-
|
|
14442
|
-
skip(client, clause) {
|
|
14443
|
-
return this._resolver.skip(client, clause);
|
|
14694
|
+
query(query, {
|
|
14695
|
+
type = "arrow",
|
|
14696
|
+
cache = true,
|
|
14697
|
+
priority = Priority.Normal,
|
|
14698
|
+
...options
|
|
14699
|
+
} = {}) {
|
|
14700
|
+
return this.manager.request({ type, query, cache, options }, priority);
|
|
14444
14701
|
}
|
|
14445
|
-
|
|
14446
|
-
|
|
14447
|
-
* @param {*} client The client whose data may be filtered.
|
|
14448
|
-
* @param {boolean} [noSkip=false] Disable skipping of active
|
|
14449
|
-
* cross-filtered sources. If set true, the source of the active
|
|
14450
|
-
* clause in a cross-filtered selection will not be skipped.
|
|
14451
|
-
* @returns {*} The query predicate for filtering client data,
|
|
14452
|
-
* based on the current state of this selection.
|
|
14453
|
-
*/
|
|
14454
|
-
predicate(client, noSkip = false) {
|
|
14455
|
-
const { clauses } = this;
|
|
14456
|
-
const active = noSkip ? null : clauses.active;
|
|
14457
|
-
return this._resolver.predicate(clauses, active, client);
|
|
14702
|
+
prefetch(query, options = {}) {
|
|
14703
|
+
return this.query(query, { ...options, cache: true, priority: Priority.Low });
|
|
14458
14704
|
}
|
|
14459
|
-
|
|
14460
|
-
|
|
14461
|
-
|
|
14462
|
-
* Create a new selection resolved instance.
|
|
14463
|
-
* @param {object} [options] The resolution strategy options.
|
|
14464
|
-
* @param {boolean} [options.union=false] Boolean flag to indicate a union strategy.
|
|
14465
|
-
* If false, an intersection strategy is used.
|
|
14466
|
-
* @param {boolean} [options.cross=false] Boolean flag to indicate cross-filtering.
|
|
14467
|
-
* @param {boolean} [options.single=false] Boolean flag to indicate single clauses only.
|
|
14468
|
-
*/
|
|
14469
|
-
constructor({ union, cross, single } = {}) {
|
|
14470
|
-
this.union = !!union;
|
|
14471
|
-
this.cross = !!cross;
|
|
14472
|
-
this.single = !!single;
|
|
14705
|
+
createBundle(name, queries, priority = Priority.Low) {
|
|
14706
|
+
const options = { name, queries };
|
|
14707
|
+
return this.manager.request({ type: "create-bundle", options }, priority);
|
|
14473
14708
|
}
|
|
14474
|
-
|
|
14475
|
-
|
|
14476
|
-
|
|
14477
|
-
* @param {*} clause A new selection clause to add.
|
|
14478
|
-
* @returns {*[]} An updated array of selection clauses.
|
|
14479
|
-
*/
|
|
14480
|
-
resolve(clauseList, clause, reset = false) {
|
|
14481
|
-
const { source, predicate } = clause;
|
|
14482
|
-
const filtered = clauseList.filter((c) => source !== c.source);
|
|
14483
|
-
const clauses = this.single ? [] : filtered;
|
|
14484
|
-
if (this.single && reset) filtered.forEach((c) => c.source?.reset?.());
|
|
14485
|
-
if (predicate) clauses.push(clause);
|
|
14486
|
-
return clauses;
|
|
14709
|
+
loadBundle(name, priority = Priority.High) {
|
|
14710
|
+
const options = { name };
|
|
14711
|
+
return this.manager.request({ type: "load-bundle", options }, priority);
|
|
14487
14712
|
}
|
|
14488
|
-
|
|
14489
|
-
|
|
14490
|
-
|
|
14491
|
-
|
|
14492
|
-
|
|
14493
|
-
|
|
14494
|
-
|
|
14495
|
-
|
|
14496
|
-
|
|
14713
|
+
// -- Client Management ----
|
|
14714
|
+
updateClient(client, query, priority = Priority.Normal) {
|
|
14715
|
+
client.queryPending();
|
|
14716
|
+
return this.query(query, { priority }).then(
|
|
14717
|
+
(data) => client.queryResult(data).update(),
|
|
14718
|
+
(err) => {
|
|
14719
|
+
client.queryError(err);
|
|
14720
|
+
this._logger.error(err);
|
|
14721
|
+
}
|
|
14722
|
+
);
|
|
14723
|
+
}
|
|
14724
|
+
requestQuery(client, query) {
|
|
14725
|
+
this.filterGroups.get(client.filterBy)?.reset();
|
|
14726
|
+
return query ? this.updateClient(client, query) : client.update();
|
|
14497
14727
|
}
|
|
14498
14728
|
/**
|
|
14499
|
-
*
|
|
14500
|
-
* @param {
|
|
14501
|
-
* @param {*} active The current active selection clause.
|
|
14502
|
-
* @param {*} client The client whose data may be filtered.
|
|
14503
|
-
* @returns {*} The query predicate for filtering client data,
|
|
14504
|
-
* based on the current state of this selection.
|
|
14729
|
+
* Connect a client to the coordinator.
|
|
14730
|
+
* @param {import('./MosaicClient.js').MosaicClient} client the client to disconnect
|
|
14505
14731
|
*/
|
|
14506
|
-
|
|
14507
|
-
const {
|
|
14508
|
-
if (
|
|
14509
|
-
|
|
14510
|
-
|
|
14732
|
+
async connect(client) {
|
|
14733
|
+
const { clients, filterGroups, indexes } = this;
|
|
14734
|
+
if (clients.has(client)) {
|
|
14735
|
+
throw new Error("Client already connected.");
|
|
14736
|
+
}
|
|
14737
|
+
clients.add(client);
|
|
14738
|
+
client.coordinator = this;
|
|
14739
|
+
const fields = client.fields();
|
|
14740
|
+
if (fields?.length) {
|
|
14741
|
+
client.fieldInfo(await queryFieldInfo(this, fields));
|
|
14742
|
+
}
|
|
14743
|
+
const filter = client.filterBy;
|
|
14744
|
+
if (filter) {
|
|
14745
|
+
if (filterGroups.has(filter)) {
|
|
14746
|
+
filterGroups.get(filter).add(client);
|
|
14747
|
+
} else {
|
|
14748
|
+
const group = new FilterGroup(this, filter, indexes);
|
|
14749
|
+
filterGroups.set(filter, group.add(client));
|
|
14750
|
+
}
|
|
14751
|
+
}
|
|
14752
|
+
client.requestQuery();
|
|
14511
14753
|
}
|
|
14512
14754
|
/**
|
|
14513
|
-
*
|
|
14514
|
-
*
|
|
14515
|
-
* @
|
|
14516
|
-
* function, or null if all unemitted event values should be filtered.
|
|
14755
|
+
* Disconnect a client from the coordinator.
|
|
14756
|
+
*
|
|
14757
|
+
* @param {import('./MosaicClient.js').MosaicClient} client the client to disconnect
|
|
14517
14758
|
*/
|
|
14518
|
-
|
|
14519
|
-
|
|
14520
|
-
|
|
14521
|
-
|
|
14522
|
-
|
|
14523
|
-
|
|
14759
|
+
disconnect(client) {
|
|
14760
|
+
const { clients, filterGroups } = this;
|
|
14761
|
+
if (!clients.has(client)) return;
|
|
14762
|
+
clients.delete(client);
|
|
14763
|
+
filterGroups.get(client.filterBy)?.remove(client);
|
|
14764
|
+
client.coordinator = null;
|
|
14524
14765
|
}
|
|
14525
14766
|
};
|
|
14526
14767
|
|
|
14768
|
+
// src/SelectionClause.js
|
|
14769
|
+
function point(field, value, { source, clients = void 0 }) {
|
|
14770
|
+
const predicate = value !== void 0 ? isNotDistinct(field, literal(value)) : null;
|
|
14771
|
+
return {
|
|
14772
|
+
meta: { type: "point" },
|
|
14773
|
+
source,
|
|
14774
|
+
clients,
|
|
14775
|
+
value,
|
|
14776
|
+
predicate
|
|
14777
|
+
};
|
|
14778
|
+
}
|
|
14779
|
+
function points(fields, value, { source, clients = void 0 }) {
|
|
14780
|
+
let predicate = null;
|
|
14781
|
+
if (value) {
|
|
14782
|
+
const clauses = value.map((vals) => {
|
|
14783
|
+
const list = vals.map((v2, i) => isNotDistinct(fields[i], literal(v2)));
|
|
14784
|
+
return list.length > 1 ? and(list) : list[0];
|
|
14785
|
+
});
|
|
14786
|
+
predicate = clauses.length > 1 ? or(clauses) : clauses[0];
|
|
14787
|
+
}
|
|
14788
|
+
return {
|
|
14789
|
+
meta: { type: "point" },
|
|
14790
|
+
source,
|
|
14791
|
+
clients,
|
|
14792
|
+
value,
|
|
14793
|
+
predicate
|
|
14794
|
+
};
|
|
14795
|
+
}
|
|
14796
|
+
function interval(field, value, {
|
|
14797
|
+
source,
|
|
14798
|
+
clients,
|
|
14799
|
+
bin,
|
|
14800
|
+
scale,
|
|
14801
|
+
pixelSize = 1
|
|
14802
|
+
}) {
|
|
14803
|
+
const predicate = value != null ? isBetween(field, value) : null;
|
|
14804
|
+
const meta = { type: "interval", scales: [scale], bin, pixelSize };
|
|
14805
|
+
return { meta, source, clients, value, predicate };
|
|
14806
|
+
}
|
|
14807
|
+
function intervals(fields, value, {
|
|
14808
|
+
source,
|
|
14809
|
+
clients,
|
|
14810
|
+
bin,
|
|
14811
|
+
scales: scales2 = [],
|
|
14812
|
+
pixelSize = 1
|
|
14813
|
+
}) {
|
|
14814
|
+
const predicate = value != null ? and(fields.map((f2, i) => isBetween(f2, value[i]))) : null;
|
|
14815
|
+
const meta = { type: "interval", scales: scales2, bin, pixelSize };
|
|
14816
|
+
return { meta, source, clients, value, predicate };
|
|
14817
|
+
}
|
|
14818
|
+
var MATCH_METHODS = { contains, prefix, suffix, regexp: regexp_matches };
|
|
14819
|
+
function match(field, value, {
|
|
14820
|
+
source,
|
|
14821
|
+
clients = void 0,
|
|
14822
|
+
method = "contains"
|
|
14823
|
+
}) {
|
|
14824
|
+
let fn = MATCH_METHODS[method];
|
|
14825
|
+
const predicate = value ? fn(field, literal(value)) : null;
|
|
14826
|
+
const meta = { type: "match", method };
|
|
14827
|
+
return { meta, source, clients, value, predicate };
|
|
14828
|
+
}
|
|
14829
|
+
|
|
14527
14830
|
// src/connectors/rest.js
|
|
14528
14831
|
function restConnector(uri = "http://localhost:3000/") {
|
|
14529
14832
|
return {
|
|
14833
|
+
/**
|
|
14834
|
+
* Query the DuckDB server.
|
|
14835
|
+
* @param {object} query
|
|
14836
|
+
* @param {'exec' | 'arrow' | 'json'} [query.type] The query type: 'exec', 'arrow', or 'json'.
|
|
14837
|
+
* @param {string} query.sql A SQL query string.
|
|
14838
|
+
* @returns the query result
|
|
14839
|
+
*/
|
|
14530
14840
|
async query(query) {
|
|
14531
14841
|
const req = fetch(uri, {
|
|
14532
14842
|
method: "POST",
|
|
@@ -16932,10 +17242,10 @@ var getDictionary2 = (data, index) => {
|
|
|
16932
17242
|
var getInterval2 = (data, index) => data.type.unit === IntervalUnit2.DAY_TIME ? getIntervalDayTime2(data, index) : getIntervalYearMonth2(data, index);
|
|
16933
17243
|
var getIntervalDayTime2 = ({ values }, index) => values.subarray(2 * index, 2 * (index + 1));
|
|
16934
17244
|
var getIntervalYearMonth2 = ({ values }, index) => {
|
|
16935
|
-
const
|
|
17245
|
+
const interval2 = values[index];
|
|
16936
17246
|
const int32s = new Int32Array(2);
|
|
16937
|
-
int32s[0] = Math.trunc(
|
|
16938
|
-
int32s[1] = Math.trunc(
|
|
17247
|
+
int32s[0] = Math.trunc(interval2 / 12);
|
|
17248
|
+
int32s[1] = Math.trunc(interval2 % 12);
|
|
16939
17249
|
return int32s;
|
|
16940
17250
|
};
|
|
16941
17251
|
var getDurationSecond2 = ({ values }, index) => values[index];
|
|
@@ -25903,7 +26213,7 @@ function wasmConnector(options = {}) {
|
|
|
25903
26213
|
/**
|
|
25904
26214
|
* Query the DuckDB-WASM instance.
|
|
25905
26215
|
* @param {object} query
|
|
25906
|
-
* @param {
|
|
26216
|
+
* @param {'exec' | 'arrow' | 'json'} [query.type] The query type: 'exec', 'arrow', or 'json'.
|
|
25907
26217
|
* @param {string} query.sql A SQL query string.
|
|
25908
26218
|
* @returns the query result
|
|
25909
26219
|
*/
|
|
@@ -25911,7 +26221,7 @@ function wasmConnector(options = {}) {
|
|
|
25911
26221
|
const { type, sql: sql2 } = query;
|
|
25912
26222
|
const con2 = await getConnection();
|
|
25913
26223
|
const result = await con2.query(sql2);
|
|
25914
|
-
return type === "exec" ? void 0 : type === "arrow" ? result :
|
|
26224
|
+
return type === "exec" ? void 0 : type === "arrow" ? result : result.toArray();
|
|
25915
26225
|
}
|
|
25916
26226
|
};
|
|
25917
26227
|
}
|
|
@@ -25985,9 +26295,14 @@ export {
|
|
|
25985
26295
|
convertArrowValue,
|
|
25986
26296
|
coordinator,
|
|
25987
26297
|
distinct,
|
|
26298
|
+
interval,
|
|
26299
|
+
intervals,
|
|
25988
26300
|
isArrowTable,
|
|
25989
26301
|
isParam,
|
|
25990
26302
|
isSelection,
|
|
26303
|
+
match,
|
|
26304
|
+
point,
|
|
26305
|
+
points,
|
|
25991
26306
|
restConnector,
|
|
25992
26307
|
socketConnector,
|
|
25993
26308
|
synchronizer,
|