@uwdata/mosaic-inputs 0.8.0 → 0.10.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.
@@ -123,7 +123,6 @@ var MosaicClient = class {
123
123
  * @returns {this}
124
124
  */
125
125
  queryError(error) {
126
- console.error(error);
127
126
  return this;
128
127
  }
129
128
  /**
@@ -147,7 +146,7 @@ var MosaicClient = class {
147
146
  /**
148
147
  * Requests a client update.
149
148
  * For example to (re-)render an interface component.
150
- *
149
+ *
151
150
  * @returns {this | Promise<any>}
152
151
  */
153
152
  update() {
@@ -211,16 +210,24 @@ function __await(v) {
211
210
  function __asyncGenerator(thisArg, _arguments, generator) {
212
211
  if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
213
212
  var g = generator.apply(thisArg, _arguments || []), i, q = [];
214
- return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {
213
+ return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function() {
215
214
  return this;
216
215
  }, i;
217
- function verb(n) {
218
- if (g[n]) i[n] = function(v) {
219
- return new Promise(function(a, b) {
220
- q.push([n, v, a, b]) > 1 || resume(n, v);
221
- });
216
+ function awaitReturn(f) {
217
+ return function(v) {
218
+ return Promise.resolve(v).then(f, reject);
222
219
  };
223
220
  }
221
+ function verb(n, f) {
222
+ if (g[n]) {
223
+ i[n] = function(v) {
224
+ return new Promise(function(a, b) {
225
+ q.push([n, v, a, b]) > 1 || resume(n, v);
226
+ });
227
+ };
228
+ if (f) i[n] = f(i[n]);
229
+ }
230
+ }
224
231
  function resume(n, v) {
225
232
  try {
226
233
  step(g[n](v));
@@ -840,26 +847,26 @@ var IntervalUnit;
840
847
  IntervalUnit2[IntervalUnit2["MONTH_DAY_NANO"] = 2] = "MONTH_DAY_NANO";
841
848
  })(IntervalUnit || (IntervalUnit = {}));
842
849
 
843
- // ../../node_modules/flatbuffers/mjs/constants.js
850
+ // ../../node_modules/apache-arrow/node_modules/flatbuffers/mjs/constants.js
844
851
  var SIZEOF_SHORT = 2;
845
852
  var SIZEOF_INT = 4;
846
853
  var FILE_IDENTIFIER_LENGTH = 4;
847
854
  var SIZE_PREFIX_LENGTH = 4;
848
855
 
849
- // ../../node_modules/flatbuffers/mjs/utils.js
856
+ // ../../node_modules/apache-arrow/node_modules/flatbuffers/mjs/utils.js
850
857
  var int32 = new Int32Array(2);
851
858
  var float32 = new Float32Array(int32.buffer);
852
859
  var float64 = new Float64Array(int32.buffer);
853
860
  var isLittleEndian = new Uint16Array(new Uint8Array([1, 0]).buffer)[0] === 1;
854
861
 
855
- // ../../node_modules/flatbuffers/mjs/encoding.js
862
+ // ../../node_modules/apache-arrow/node_modules/flatbuffers/mjs/encoding.js
856
863
  var Encoding;
857
864
  (function(Encoding2) {
858
865
  Encoding2[Encoding2["UTF8_BYTES"] = 1] = "UTF8_BYTES";
859
866
  Encoding2[Encoding2["UTF16_STRING"] = 2] = "UTF16_STRING";
860
867
  })(Encoding || (Encoding = {}));
861
868
 
862
- // ../../node_modules/flatbuffers/mjs/byte-buffer.js
869
+ // ../../node_modules/apache-arrow/node_modules/flatbuffers/mjs/byte-buffer.js
863
870
  var ByteBuffer = class _ByteBuffer {
864
871
  /**
865
872
  * Create a new ByteBuffer with a given array of bytes (`Uint8Array`)
@@ -1103,7 +1110,7 @@ var ByteBuffer = class _ByteBuffer {
1103
1110
  }
1104
1111
  };
1105
1112
 
1106
- // ../../node_modules/flatbuffers/mjs/builder.js
1113
+ // ../../node_modules/apache-arrow/node_modules/flatbuffers/mjs/builder.js
1107
1114
  var Builder = class _Builder {
1108
1115
  /**
1109
1116
  * Create a FlatBufferBuilder.
@@ -1543,9 +1550,22 @@ var Builder = class _Builder {
1543
1550
  this.addInt8(0);
1544
1551
  this.startVector(1, utf8.length, 1);
1545
1552
  this.bb.setPosition(this.space -= utf8.length);
1546
- for (let i = 0, offset = this.space, bytes = this.bb.bytes(); i < utf8.length; i++) {
1547
- bytes[offset++] = utf8[i];
1553
+ this.bb.bytes().set(utf8, this.space);
1554
+ return this.endVector();
1555
+ }
1556
+ /**
1557
+ * Create a byte vector.
1558
+ *
1559
+ * @param v The bytes to add
1560
+ * @returns The offset in the buffer where the byte vector starts
1561
+ */
1562
+ createByteVector(v) {
1563
+ if (v === null || v === void 0) {
1564
+ return 0;
1548
1565
  }
1566
+ this.startVector(1, v.length, 1);
1567
+ this.bb.setPosition(this.space -= v.length);
1568
+ this.bb.bytes().set(v, this.space);
1549
1569
  return this.endVector();
1550
1570
  }
1551
1571
  /**
@@ -3148,9 +3168,9 @@ var BufferType;
3148
3168
  // ../../node_modules/apache-arrow/util/vector.mjs
3149
3169
  var vector_exports = {};
3150
3170
  __export(vector_exports, {
3151
- clampIndex: () => clampIndex,
3152
3171
  clampRange: () => clampRange,
3153
- createElementComparator: () => createElementComparator
3172
+ createElementComparator: () => createElementComparator,
3173
+ wrapIndex: () => wrapIndex
3154
3174
  });
3155
3175
 
3156
3176
  // ../../node_modules/apache-arrow/util/pretty.mjs
@@ -3191,9 +3211,23 @@ var bn_exports = {};
3191
3211
  __export(bn_exports, {
3192
3212
  BN: () => BN,
3193
3213
  bigNumToBigInt: () => bigNumToBigInt,
3214
+ bigNumToNumber: () => bigNumToNumber,
3194
3215
  bigNumToString: () => bigNumToString,
3195
3216
  isArrowBigNumSymbol: () => isArrowBigNumSymbol
3196
3217
  });
3218
+
3219
+ // ../../node_modules/apache-arrow/util/bigint.mjs
3220
+ function bigIntToNumber(number) {
3221
+ if (typeof number === "bigint" && (number < Number.MIN_SAFE_INTEGER || number > Number.MAX_SAFE_INTEGER)) {
3222
+ throw new TypeError(`${number} is not safe to convert to a number.`);
3223
+ }
3224
+ return Number(number);
3225
+ }
3226
+ function divideBigInts(number, divisor) {
3227
+ return bigIntToNumber(number / divisor) + bigIntToNumber(number % divisor) / bigIntToNumber(divisor);
3228
+ }
3229
+
3230
+ // ../../node_modules/apache-arrow/util/bn.mjs
3197
3231
  var isArrowBigNumSymbol = Symbol.for("isArrowBigNum");
3198
3232
  function BigNum(x2, ...xs) {
3199
3233
  if (xs.length === 0) {
@@ -3205,8 +3239,8 @@ BigNum.prototype[isArrowBigNumSymbol] = true;
3205
3239
  BigNum.prototype.toJSON = function() {
3206
3240
  return `"${bigNumToString(this)}"`;
3207
3241
  };
3208
- BigNum.prototype.valueOf = function() {
3209
- return bigNumToNumber(this);
3242
+ BigNum.prototype.valueOf = function(scale) {
3243
+ return bigNumToNumber(this, scale);
3210
3244
  };
3211
3245
  BigNum.prototype.toString = function() {
3212
3246
  return bigNumToString(this);
@@ -3237,25 +3271,34 @@ Object.setPrototypeOf(DecimalBigNum.prototype, Object.create(Uint32Array.prototy
3237
3271
  Object.assign(SignedBigNum.prototype, BigNum.prototype, { "constructor": SignedBigNum, "signed": true, "TypedArray": Int32Array, "BigIntArray": BigInt64Array });
3238
3272
  Object.assign(UnsignedBigNum.prototype, BigNum.prototype, { "constructor": UnsignedBigNum, "signed": false, "TypedArray": Uint32Array, "BigIntArray": BigUint64Array });
3239
3273
  Object.assign(DecimalBigNum.prototype, BigNum.prototype, { "constructor": DecimalBigNum, "signed": true, "TypedArray": Uint32Array, "BigIntArray": BigUint64Array });
3240
- function bigNumToNumber(bn) {
3241
- const { buffer, byteOffset, length: length2, "signed": signed } = bn;
3242
- const words = new BigUint64Array(buffer, byteOffset, length2);
3274
+ var TWO_TO_THE_64 = BigInt(4294967296) * BigInt(4294967296);
3275
+ var TWO_TO_THE_64_MINUS_1 = TWO_TO_THE_64 - BigInt(1);
3276
+ function bigNumToNumber(bn, scale) {
3277
+ const { buffer, byteOffset, byteLength, "signed": signed } = bn;
3278
+ const words = new BigUint64Array(buffer, byteOffset, byteLength / 8);
3243
3279
  const negative = signed && words.at(-1) & BigInt(1) << BigInt(63);
3244
- let number = negative ? BigInt(1) : BigInt(0);
3245
- let i = BigInt(0);
3246
- if (!negative) {
3280
+ let number = BigInt(0);
3281
+ let i = 0;
3282
+ if (negative) {
3247
3283
  for (const word of words) {
3248
- number += word * (BigInt(1) << BigInt(32) * i++);
3284
+ number |= (word ^ TWO_TO_THE_64_MINUS_1) * (BigInt(1) << BigInt(64 * i++));
3249
3285
  }
3286
+ number *= BigInt(-1);
3287
+ number -= BigInt(1);
3250
3288
  } else {
3251
3289
  for (const word of words) {
3252
- number += ~word * (BigInt(1) << BigInt(32) * i++);
3290
+ number |= word * (BigInt(1) << BigInt(64 * i++));
3253
3291
  }
3254
- number *= BigInt(-1);
3255
3292
  }
3256
- return number;
3293
+ if (typeof scale === "number") {
3294
+ const denominator = BigInt(Math.pow(10, scale));
3295
+ const quotient = number / denominator;
3296
+ const remainder = number % denominator;
3297
+ return bigIntToNumber(quotient) + bigIntToNumber(remainder) / bigIntToNumber(denominator);
3298
+ }
3299
+ return bigIntToNumber(number);
3257
3300
  }
3258
- var bigNumToString = (a) => {
3301
+ function bigNumToString(a) {
3259
3302
  if (a.byteLength === 8) {
3260
3303
  const bigIntArray = new a["BigIntArray"](a.buffer, a.byteOffset, 1);
3261
3304
  return `${bigIntArray[0]}`;
@@ -3278,15 +3321,15 @@ var bigNumToString = (a) => {
3278
3321
  }
3279
3322
  const negated = unsignedBigNumToString(array);
3280
3323
  return `-${negated}`;
3281
- };
3282
- var bigNumToBigInt = (a) => {
3324
+ }
3325
+ function bigNumToBigInt(a) {
3283
3326
  if (a.byteLength === 8) {
3284
3327
  const bigIntArray = new a["BigIntArray"](a.buffer, a.byteOffset, 1);
3285
3328
  return bigIntArray[0];
3286
3329
  } else {
3287
3330
  return bigNumToString(a);
3288
3331
  }
3289
- };
3332
+ }
3290
3333
  function unsignedBigNumToString(a) {
3291
3334
  let digits = "";
3292
3335
  const base64 = new Uint32Array(2);
@@ -3343,14 +3386,6 @@ var BN = class _BN {
3343
3386
  }
3344
3387
  };
3345
3388
 
3346
- // ../../node_modules/apache-arrow/util/bigint.mjs
3347
- function bigIntToNumber(number) {
3348
- if (typeof number === "bigint" && (number < Number.MIN_SAFE_INTEGER || number > Number.MAX_SAFE_INTEGER)) {
3349
- throw new TypeError(`${number} is not safe to convert to a number.`);
3350
- }
3351
- return Number(number);
3352
- }
3353
-
3354
3389
  // ../../node_modules/apache-arrow/type.mjs
3355
3390
  var _a;
3356
3391
  var _b;
@@ -3725,11 +3760,13 @@ var Date_ = class extends DataType {
3725
3760
  toString() {
3726
3761
  return `Date${(this.unit + 1) * 32}<${DateUnit[this.unit]}>`;
3727
3762
  }
3763
+ get ArrayType() {
3764
+ return this.unit === DateUnit.DAY ? Int32Array : BigInt64Array;
3765
+ }
3728
3766
  };
3729
3767
  _l = Symbol.toStringTag;
3730
3768
  Date_[_l] = ((proto) => {
3731
3769
  proto.unit = null;
3732
- proto.ArrayType = Int32Array;
3733
3770
  return proto[Symbol.toStringTag] = "Date";
3734
3771
  })(Date_.prototype);
3735
3772
  var Time_ = class extends DataType {
@@ -3771,7 +3808,7 @@ _o = Symbol.toStringTag;
3771
3808
  Timestamp_[_o] = ((proto) => {
3772
3809
  proto.unit = null;
3773
3810
  proto.timezone = null;
3774
- proto.ArrayType = Int32Array;
3811
+ proto.ArrayType = BigInt64Array;
3775
3812
  return proto[Symbol.toStringTag] = "Timestamp";
3776
3813
  })(Timestamp_.prototype);
3777
3814
  var Interval_ = class extends DataType {
@@ -3976,10 +4013,6 @@ function strideForType(type) {
3976
4013
  switch (type.typeId) {
3977
4014
  case Type2.Decimal:
3978
4015
  return type.bitWidth / 32;
3979
- case Type2.Timestamp:
3980
- return 2;
3981
- case Type2.Date:
3982
- return 1 + t.unit;
3983
4016
  case Type2.Interval:
3984
4017
  return 1 + t.unit;
3985
4018
  case Type2.FixedSizeList:
@@ -4446,19 +4479,7 @@ function wrapSet(fn) {
4446
4479
  };
4447
4480
  }
4448
4481
  var setEpochMsToDays = (data, index, epochMs) => {
4449
- data[index] = Math.trunc(epochMs / 864e5);
4450
- };
4451
- var setEpochMsToMillisecondsLong = (data, index, epochMs) => {
4452
- data[index] = Math.trunc(epochMs % 4294967296);
4453
- data[index + 1] = Math.trunc(epochMs / 4294967296);
4454
- };
4455
- var setEpochMsToMicrosecondsLong = (data, index, epochMs) => {
4456
- data[index] = Math.trunc(epochMs * 1e3 % 4294967296);
4457
- data[index + 1] = Math.trunc(epochMs * 1e3 / 4294967296);
4458
- };
4459
- var setEpochMsToNanosecondsLong = (data, index, epochMs) => {
4460
- data[index] = Math.trunc(epochMs * 1e6 % 4294967296);
4461
- data[index + 1] = Math.trunc(epochMs * 1e6 / 4294967296);
4482
+ data[index] = Math.floor(epochMs / 864e5);
4462
4483
  };
4463
4484
  var setVariableWidthBytes = (values, valueOffsets, index, value) => {
4464
4485
  if (index + 1 < valueOffsets.length) {
@@ -4493,7 +4514,7 @@ var setDateDay = ({ values }, index, value) => {
4493
4514
  setEpochMsToDays(values, index, value.valueOf());
4494
4515
  };
4495
4516
  var setDateMillisecond = ({ values }, index, value) => {
4496
- setEpochMsToMillisecondsLong(values, index * 2, value.valueOf());
4517
+ values[index] = BigInt(value);
4497
4518
  };
4498
4519
  var setFixedSizeBinary = ({ stride, values }, index, value) => {
4499
4520
  values.set(value.subarray(0, stride), stride * index);
@@ -4503,10 +4524,18 @@ var setUtf8 = ({ values, valueOffsets }, index, value) => setVariableWidthBytes(
4503
4524
  var setDate = (data, index, value) => {
4504
4525
  data.type.unit === DateUnit.DAY ? setDateDay(data, index, value) : setDateMillisecond(data, index, value);
4505
4526
  };
4506
- var setTimestampSecond = ({ values }, index, value) => setEpochMsToMillisecondsLong(values, index * 2, value / 1e3);
4507
- var setTimestampMillisecond = ({ values }, index, value) => setEpochMsToMillisecondsLong(values, index * 2, value);
4508
- var setTimestampMicrosecond = ({ values }, index, value) => setEpochMsToMicrosecondsLong(values, index * 2, value);
4509
- var setTimestampNanosecond = ({ values }, index, value) => setEpochMsToNanosecondsLong(values, index * 2, value);
4527
+ var setTimestampSecond = ({ values }, index, value) => {
4528
+ values[index] = BigInt(value / 1e3);
4529
+ };
4530
+ var setTimestampMillisecond = ({ values }, index, value) => {
4531
+ values[index] = BigInt(value);
4532
+ };
4533
+ var setTimestampMicrosecond = ({ values }, index, value) => {
4534
+ values[index] = BigInt(value * 1e3);
4535
+ };
4536
+ var setTimestampNanosecond = ({ values }, index, value) => {
4537
+ values[index] = BigInt(value * 1e6);
4538
+ };
4510
4539
  var setTimestamp = (data, index, value) => {
4511
4540
  switch (data.type.unit) {
4512
4541
  case TimeUnit.SECOND:
@@ -4811,12 +4840,6 @@ function wrapGet(fn) {
4811
4840
  return (data, _1) => data.getValid(_1) ? fn(data, _1) : null;
4812
4841
  }
4813
4842
  var epochDaysToMs = (data, index) => 864e5 * data[index];
4814
- var epochMillisecondsLongToMs = (data, index) => 4294967296 * data[index + 1] + (data[index] >>> 0);
4815
- var epochMicrosecondsLongToMs = (data, index) => 4294967296 * (data[index + 1] / 1e3) + (data[index] >>> 0) / 1e3;
4816
- var epochNanosecondsLongToMs = (data, index) => 4294967296 * (data[index + 1] / 1e6) + (data[index] >>> 0) / 1e6;
4817
- var epochMillisecondsToDate = (epochMs) => new Date(epochMs);
4818
- var epochDaysToDate = (data, index) => epochMillisecondsToDate(epochDaysToMs(data, index));
4819
- var epochMillisecondsLongToDate = (data, index) => epochMillisecondsToDate(epochMillisecondsLongToMs(data, index));
4820
4843
  var getNull = (_data, _index) => null;
4821
4844
  var getVariableWidthBytes = (values, valueOffsets, index) => {
4822
4845
  if (index + 1 >= valueOffsets.length) {
@@ -4831,8 +4854,8 @@ var getBool = ({ offset, values }, index) => {
4831
4854
  const byte = values[idx >> 3];
4832
4855
  return (byte & 1 << idx % 8) !== 0;
4833
4856
  };
4834
- var getDateDay = ({ values }, index) => epochDaysToDate(values, index);
4835
- var getDateMillisecond = ({ values }, index) => epochMillisecondsLongToDate(values, index * 2);
4857
+ var getDateDay = ({ values }, index) => epochDaysToMs(values, index);
4858
+ var getDateMillisecond = ({ values }, index) => bigIntToNumber(values[index]);
4836
4859
  var getNumeric = ({ stride, values }, index) => values[stride * index];
4837
4860
  var getFloat16 = ({ stride, values }, index) => uint16ToFloat64(values[stride * index]);
4838
4861
  var getBigInts = ({ values }, index) => values[index];
@@ -4845,10 +4868,10 @@ var getUtf8 = ({ values, valueOffsets }, index) => {
4845
4868
  var getInt = ({ values }, index) => values[index];
4846
4869
  var getFloat = ({ type, values }, index) => type.precision !== Precision.HALF ? values[index] : uint16ToFloat64(values[index]);
4847
4870
  var getDate = (data, index) => data.type.unit === DateUnit.DAY ? getDateDay(data, index) : getDateMillisecond(data, index);
4848
- var getTimestampSecond = ({ values }, index) => 1e3 * epochMillisecondsLongToMs(values, index * 2);
4849
- var getTimestampMillisecond = ({ values }, index) => epochMillisecondsLongToMs(values, index * 2);
4850
- var getTimestampMicrosecond = ({ values }, index) => epochMicrosecondsLongToMs(values, index * 2);
4851
- var getTimestampNanosecond = ({ values }, index) => epochNanosecondsLongToMs(values, index * 2);
4871
+ var getTimestampSecond = ({ values }, index) => 1e3 * bigIntToNumber(values[index]);
4872
+ var getTimestampMillisecond = ({ values }, index) => bigIntToNumber(values[index]);
4873
+ var getTimestampMicrosecond = ({ values }, index) => divideBigInts(values[index], BigInt(1e3));
4874
+ var getTimestampNanosecond = ({ values }, index) => divideBigInts(values[index], BigInt(1e6));
4852
4875
  var getTimestamp = (data, index) => {
4853
4876
  switch (data.type.unit) {
4854
4877
  case TimeUnit.SECOND:
@@ -4997,12 +5020,18 @@ var instance2 = new GetVisitor();
4997
5020
  // ../../node_modules/apache-arrow/row/map.mjs
4998
5021
  var kKeys = Symbol.for("keys");
4999
5022
  var kVals = Symbol.for("vals");
5023
+ var kKeysAsStrings = Symbol.for("kKeysAsStrings");
5024
+ var _kKeysAsStrings = Symbol.for("_kKeysAsStrings");
5000
5025
  var MapRow = class {
5001
5026
  constructor(slice) {
5002
5027
  this[kKeys] = new Vector([slice.children[0]]).memoize();
5003
5028
  this[kVals] = slice.children[1];
5004
5029
  return new Proxy(this, new MapRowProxyHandler());
5005
5030
  }
5031
+ /** @ignore */
5032
+ get [kKeysAsStrings]() {
5033
+ return this[_kKeysAsStrings] || (this[_kKeysAsStrings] = Array.from(this[kKeys].toArray(), String));
5034
+ }
5006
5035
  [Symbol.iterator]() {
5007
5036
  return new MapRowIterator(this[kKeys], this[kVals]);
5008
5037
  }
@@ -5064,13 +5093,13 @@ var MapRowProxyHandler = class {
5064
5093
  return true;
5065
5094
  }
5066
5095
  ownKeys(row) {
5067
- return row[kKeys].toArray().map(String);
5096
+ return row[kKeysAsStrings];
5068
5097
  }
5069
5098
  has(row, key) {
5070
- return row[kKeys].includes(key);
5099
+ return row[kKeysAsStrings].includes(key);
5071
5100
  }
5072
5101
  getOwnPropertyDescriptor(row, key) {
5073
- const idx = row[kKeys].indexOf(key);
5102
+ const idx = row[kKeysAsStrings].indexOf(key);
5074
5103
  if (idx !== -1) {
5075
5104
  return { writable: true, enumerable: true, configurable: true };
5076
5105
  }
@@ -5080,7 +5109,7 @@ var MapRowProxyHandler = class {
5080
5109
  if (Reflect.has(row, key)) {
5081
5110
  return row[key];
5082
5111
  }
5083
- const idx = row[kKeys].indexOf(key);
5112
+ const idx = row[kKeysAsStrings].indexOf(key);
5084
5113
  if (idx !== -1) {
5085
5114
  const val = instance2.visit(Reflect.get(row, kVals), idx);
5086
5115
  Reflect.set(row, key, val);
@@ -5088,7 +5117,7 @@ var MapRowProxyHandler = class {
5088
5117
  }
5089
5118
  }
5090
5119
  set(row, key, val) {
5091
- const idx = row[kKeys].indexOf(key);
5120
+ const idx = row[kKeysAsStrings].indexOf(key);
5092
5121
  if (idx !== -1) {
5093
5122
  instance.visit(Reflect.get(row, kVals), idx, val);
5094
5123
  return Reflect.set(row, key, val);
@@ -5101,15 +5130,11 @@ var MapRowProxyHandler = class {
5101
5130
  Object.defineProperties(MapRow.prototype, {
5102
5131
  [Symbol.toStringTag]: { enumerable: false, configurable: false, value: "Row" },
5103
5132
  [kKeys]: { writable: true, enumerable: false, configurable: false, value: null },
5104
- [kVals]: { writable: true, enumerable: false, configurable: false, value: null }
5133
+ [kVals]: { writable: true, enumerable: false, configurable: false, value: null },
5134
+ [_kKeysAsStrings]: { writable: true, enumerable: false, configurable: false, value: null }
5105
5135
  });
5106
5136
 
5107
5137
  // ../../node_modules/apache-arrow/util/vector.mjs
5108
- function clampIndex(source, index, then) {
5109
- const length2 = source.length;
5110
- const adjust = index > -1 ? index : length2 + index % length2;
5111
- return then ? then(source, adjust) : adjust;
5112
- }
5113
5138
  var tmp;
5114
5139
  function clampRange(source, begin, end, then) {
5115
5140
  const { length: len = 0 } = source;
@@ -5121,6 +5146,7 @@ function clampRange(source, begin, end, then) {
5121
5146
  rhs > len && (rhs = len);
5122
5147
  return then ? then(source, lhs, rhs) : [lhs, rhs];
5123
5148
  }
5149
+ var wrapIndex = (index, len) => index < 0 ? len + index : index;
5124
5150
  var isNaNFast = (value) => value !== value;
5125
5151
  function createElementComparator(search2) {
5126
5152
  const typeofSearch = typeof search2;
@@ -5409,7 +5435,10 @@ var Data = class _Data {
5409
5435
  let nullCount = this._nullCount;
5410
5436
  let nullBitmap;
5411
5437
  if (nullCount <= kUnknownNullCount && (nullBitmap = this.nullBitmap)) {
5412
- this._nullCount = nullCount = this.length - popcnt_bit_range(nullBitmap, this.offset, this.offset + this.length);
5438
+ this._nullCount = nullCount = nullBitmap.length === 0 ? (
5439
+ // no null bitmap, so all values are valid
5440
+ 0
5441
+ ) : this.length - popcnt_bit_range(nullBitmap, this.offset, this.offset + this.length);
5413
5442
  }
5414
5443
  return nullCount;
5415
5444
  }
@@ -5471,12 +5500,14 @@ var Data = class _Data {
5471
5500
  nullBitmap = new Uint8Array((offset + length2 + 63 & ~63) >> 3).fill(255);
5472
5501
  if (this.nullCount > 0) {
5473
5502
  nullBitmap.set(truncateBitmap(offset, length2, this.nullBitmap), 0);
5503
+ Object.assign(this, { nullBitmap });
5504
+ } else {
5505
+ Object.assign(this, { nullBitmap, _nullCount: 0 });
5474
5506
  }
5475
- Object.assign(this, { nullBitmap, _nullCount: -1 });
5476
5507
  }
5477
5508
  const byte = nullBitmap[byteOffset];
5478
5509
  prev = (byte & mask) !== 0;
5479
- value ? nullBitmap[byteOffset] = byte | mask : nullBitmap[byteOffset] = byte & ~mask;
5510
+ nullBitmap[byteOffset] = value ? byte | mask : byte & ~mask;
5480
5511
  }
5481
5512
  if (prev !== !!value) {
5482
5513
  this._nullCount = this.nullCount + (value ? -1 : 1);
@@ -5917,7 +5948,9 @@ var IteratorVisitor = class extends Visitor {
5917
5948
  };
5918
5949
  function vectorIterator(vector) {
5919
5950
  const { type } = vector;
5920
- if (vector.nullCount === 0 && vector.stride === 1 && (type.typeId === Type2.Timestamp || type instanceof Int_ && type.bitWidth !== 64 || type instanceof Time_ && type.bitWidth !== 64 || type instanceof Float && type.precision !== Precision.HALF)) {
5951
+ if (vector.nullCount === 0 && vector.stride === 1 && // Don't defer to native iterator for timestamps since Numbers are expected
5952
+ // (DataType.isTimestamp(type)) && type.unit === TimeUnit.MILLISECOND ||
5953
+ (DataType.isInt(type) && type.bitWidth !== 64 || DataType.isTime(type) && type.bitWidth !== 64 || DataType.isFloat(type) && type.precision !== Precision.HALF)) {
5921
5954
  return new ChunkedIterator(vector.data.length, (chunkIndex) => {
5922
5955
  const data = vector.data[chunkIndex];
5923
5956
  return data.values.subarray(0, data.length)[Symbol.iterator]();
@@ -6091,6 +6124,13 @@ var Vector = class _Vector {
6091
6124
  get(index) {
6092
6125
  return null;
6093
6126
  }
6127
+ /**
6128
+ * Get an element value by position.
6129
+ * @param index The index of the element to read. A negative index will count back from the last element.
6130
+ */
6131
+ at(index) {
6132
+ return this.get(wrapIndex(index, this.length));
6133
+ }
6094
6134
  /**
6095
6135
  * Set an element value by position.
6096
6136
  * @param index The index of the element to write.
@@ -7368,8 +7408,8 @@ var AsyncByteStreamSource = class {
7368
7408
  return (yield this.next(size, "peek")).value;
7369
7409
  });
7370
7410
  }
7371
- next(size, cmd = "read") {
7372
- return __awaiter(this, void 0, void 0, function* () {
7411
+ next(size_1) {
7412
+ return __awaiter(this, arguments, void 0, function* (size, cmd = "read") {
7373
7413
  return yield this.source.next({ cmd, size });
7374
7414
  });
7375
7415
  }
@@ -8946,6 +8986,14 @@ var Table = class _Table {
8946
8986
  get(index) {
8947
8987
  return null;
8948
8988
  }
8989
+ /**
8990
+ * Get an element value by position.
8991
+ * @param index The index of the element to read. A negative index will count back from the last element.
8992
+ */
8993
+ // @ts-ignore
8994
+ at(index) {
8995
+ return this.get(wrapIndex(index, this.numRows));
8996
+ }
8949
8997
  /**
8950
8998
  * Set an element value by position.
8951
8999
  *
@@ -9183,7 +9231,7 @@ var RecordBatch2 = class _RecordBatch {
9183
9231
  return this.data.nullCount;
9184
9232
  }
9185
9233
  /**
9186
- * Check whether an element is null.
9234
+ * Check whether an row is null.
9187
9235
  * @param index The index at which to read the validity bitmap.
9188
9236
  */
9189
9237
  isValid(index) {
@@ -9191,14 +9239,21 @@ var RecordBatch2 = class _RecordBatch {
9191
9239
  }
9192
9240
  /**
9193
9241
  * Get a row by position.
9194
- * @param index The index of the element to read.
9242
+ * @param index The index of the row to read.
9195
9243
  */
9196
9244
  get(index) {
9197
9245
  return instance2.visit(this.data, index);
9198
9246
  }
9247
+ /**
9248
+ * Get a row value by position.
9249
+ * @param index The index of the row to read. A negative index will count back from the last row.
9250
+ */
9251
+ at(index) {
9252
+ return this.get(wrapIndex(index, this.numRows));
9253
+ }
9199
9254
  /**
9200
9255
  * Set a row by position.
9201
- * @param index The index of the element to write.
9256
+ * @param index The index of the row to write.
9202
9257
  * @param value The value to set.
9203
9258
  */
9204
9259
  set(index, value) {
@@ -9235,7 +9290,7 @@ var RecordBatch2 = class _RecordBatch {
9235
9290
  /**
9236
9291
  * Return a zero-copy sub-section of this RecordBatch.
9237
9292
  * @param start The beginning of the specified portion of the RecordBatch.
9238
- * @param end The end of the specified portion of the RecordBatch. This is exclusive of the element at the index 'end'.
9293
+ * @param end The end of the specified portion of the RecordBatch. This is exclusive of the row at the index 'end'.
9239
9294
  */
9240
9295
  slice(begin, end) {
9241
9296
  const [slice] = new Vector([this.data]).slice(begin, end).data;
@@ -10323,8 +10378,8 @@ var AsyncMessageReader = class {
10323
10378
  );
10324
10379
  });
10325
10380
  }
10326
- readSchema(throwIfNull = false) {
10327
- return __awaiter(this, void 0, void 0, function* () {
10381
+ readSchema() {
10382
+ return __awaiter(this, arguments, void 0, function* (throwIfNull = false) {
10328
10383
  const type = MessageHeader.Schema;
10329
10384
  const message = yield this.readMessage(type);
10330
10385
  const schema = message === null || message === void 0 ? void 0 : message.header();
@@ -10572,8 +10627,8 @@ var AsyncRecordBatchStreamReader = class extends RecordBatchReader {
10572
10627
  this._impl = _impl;
10573
10628
  }
10574
10629
  readAll() {
10575
- var _a5, e_1, _b2, _c2;
10576
10630
  return __awaiter(this, void 0, void 0, function* () {
10631
+ var _a5, e_1, _b2, _c2;
10577
10632
  const batches = new Array();
10578
10633
  try {
10579
10634
  for (var _d2 = true, _e2 = __asyncValues(this), _f2; _f2 = yield _e2.next(), _a5 = _f2.done, !_a5; _d2 = true) {
@@ -10946,8 +11001,8 @@ var AsyncRecordBatchFileReaderImpl = class extends AsyncRecordBatchStreamReaderI
10946
11001
  });
10947
11002
  }
10948
11003
  readRecordBatch(index) {
10949
- var _a5;
10950
11004
  return __awaiter(this, void 0, void 0, function* () {
11005
+ var _a5;
10951
11006
  if (this.closed) {
10952
11007
  return null;
10953
11008
  }
@@ -10968,8 +11023,8 @@ var AsyncRecordBatchFileReaderImpl = class extends AsyncRecordBatchStreamReaderI
10968
11023
  });
10969
11024
  }
10970
11025
  _readDictionaryBatch(index) {
10971
- var _a5;
10972
11026
  return __awaiter(this, void 0, void 0, function* () {
11027
+ var _a5;
10973
11028
  const block = (_a5 = this._footer) === null || _a5 === void 0 ? void 0 : _a5.getDictionaryBatch(index);
10974
11029
  if (block && (yield this._handle.seek(block.offset))) {
10975
11030
  const message = yield this._reader.readMessage(MessageHeader.DictionaryBatch);
@@ -11474,9 +11529,9 @@ function writeAll(writer, input2) {
11474
11529
  return writer.finish();
11475
11530
  }
11476
11531
  function writeAllAsync(writer, batches) {
11477
- var _a5, batches_1, batches_1_1;
11478
- var _b2, e_1, _c2, _d2;
11479
11532
  return __awaiter(this, void 0, void 0, function* () {
11533
+ var _a5, batches_1, batches_1_1;
11534
+ var _b2, e_1, _c2, _d2;
11480
11535
  try {
11481
11536
  for (_a5 = true, batches_1 = __asyncValues(batches); batches_1_1 = yield batches_1.next(), _b2 = batches_1_1.done, !_b2; _a5 = true) {
11482
11537
  _d2 = batches_1_1.value;
@@ -11839,6 +11894,13 @@ function socketConnector(uri = "ws://localhost:3000/") {
11839
11894
  get connected() {
11840
11895
  return connected;
11841
11896
  },
11897
+ /**
11898
+ * Query the DuckDB server.
11899
+ * @param {object} query
11900
+ * @param {'exec' | 'arrow' | 'json'} [query.type] The query type: 'exec', 'arrow', or 'json'.
11901
+ * @param {string} query.sql A SQL query string.
11902
+ * @returns the query result
11903
+ */
11842
11904
  query(query) {
11843
11905
  return new Promise(
11844
11906
  (resolve, reject) => enqueue(query, resolve, reject)
@@ -11909,7 +11971,7 @@ function literalToSQL(value) {
11909
11971
  case "boolean":
11910
11972
  return value ? "TRUE" : "FALSE";
11911
11973
  case "string":
11912
- return `'${value}'`;
11974
+ return `'${value.replace(`'`, `''`)}'`;
11913
11975
  case "number":
11914
11976
  return Number.isFinite(value) ? String(value) : "NULL";
11915
11977
  default:
@@ -11992,7 +12054,7 @@ var SQLExpression = class {
11992
12054
  /**
11993
12055
  * Annotate this expression instance with additional properties.
11994
12056
  * @param {object[]} [props] One or more objects with properties to add.
11995
- * @returns {this} This SQL expression.
12057
+ * @returns This SQL expression.
11996
12058
  */
11997
12059
  annotate(...props) {
11998
12060
  return Object.assign(this, ...props);
@@ -12260,6 +12322,9 @@ var last_value = winf("LAST_VALUE");
12260
12322
  var nth_value = winf("NTH_VALUE");
12261
12323
 
12262
12324
  // ../sql/src/aggregates.js
12325
+ function agg(strings, ...exprs) {
12326
+ return sql(strings, ...exprs).annotate({ aggregate: true });
12327
+ }
12263
12328
  var AggregateFunction = class _AggregateFunction extends SQLExpression {
12264
12329
  /**
12265
12330
  * Create a new AggregateFunction instance.
@@ -12390,6 +12455,7 @@ var entropy = aggf("ENTROPY");
12390
12455
  var varPop = aggf("VAR_POP");
12391
12456
  var stddevPop = aggf("STDDEV_POP");
12392
12457
  var corr = aggf("CORR");
12458
+ var covariance = aggf("COVAR_SAMP");
12393
12459
  var covarPop = aggf("COVAR_POP");
12394
12460
  var regrIntercept = aggf("REGR_INTERCEPT");
12395
12461
  var regrSlope = aggf("REGR_SLOPE");
@@ -12532,7 +12598,8 @@ var Query = class _Query {
12532
12598
  }
12533
12599
  }
12534
12600
  }
12535
- query.select = query.select.concat(list);
12601
+ const keys = new Set(list.map((x2) => x2.as));
12602
+ query.select = query.select.filter((x2) => !keys.has(x2.as)).concat(list.filter((x2) => x2.expr));
12536
12603
  return this;
12537
12604
  }
12538
12605
  }
@@ -13005,6 +13072,7 @@ function scaleTime() {
13005
13072
  };
13006
13073
  }
13007
13074
  var scales = {
13075
+ identity: scaleLinear,
13008
13076
  linear: scaleLinear,
13009
13077
  log: scaleLog,
13010
13078
  symlog: scaleSymlog,
@@ -13027,179 +13095,97 @@ function create(name, query, {
13027
13095
  return "CREATE" + (replace ? " OR REPLACE " : " ") + (temp ? "TEMP " : "") + (view ? "VIEW" : "TABLE") + (replace ? " " : " IF NOT EXISTS ") + name + " AS " + query;
13028
13096
  }
13029
13097
 
13030
- // ../core/src/util/hash.js
13031
- function fnv_hash(v) {
13032
- let a = 2166136261;
13033
- for (let i = 0, n = v.length; i < n; ++i) {
13034
- const c = v.charCodeAt(i);
13035
- const d = c & 65280;
13036
- if (d) a = fnv_multiply(a ^ d >> 8);
13037
- a = fnv_multiply(a ^ c & 255);
13038
- }
13039
- return fnv_mix(a);
13040
- }
13041
- function fnv_multiply(a) {
13042
- return a + (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24);
13043
- }
13044
- function fnv_mix(a) {
13045
- a += a << 13;
13046
- a ^= a >>> 7;
13047
- a += a << 3;
13048
- a ^= a >>> 17;
13049
- a += a << 5;
13050
- return a & 4294967295;
13051
- }
13052
-
13053
- // ../core/src/DataCubeIndexer.js
13054
- var DataCubeIndexer = class {
13055
- /**
13056
- *
13057
- * @param {import('./Coordinator.js').Coordinator} mc a Mosaic coordinator
13058
- * @param {*} options Options hash to configure the data cube indexes and pass selections to the coordinator.
13059
- */
13060
- constructor(mc, { selection, temp = true }) {
13061
- this.mc = mc;
13062
- this.selection = selection;
13063
- this.temp = temp;
13064
- this.reset();
13065
- }
13066
- reset() {
13067
- this.enabled = false;
13068
- this.clients = null;
13069
- this.indices = null;
13070
- this.activeView = null;
13071
- }
13072
- clear() {
13073
- if (this.indices) {
13074
- this.mc.cancel(Array.from(this.indices.values(), (index) => index.result));
13075
- this.indices = null;
13076
- }
13077
- }
13078
- index(clients, active) {
13079
- if (this.clients !== clients) {
13080
- const cols = Array.from(clients, getIndexColumns);
13081
- const from = cols[0]?.from;
13082
- this.enabled = cols.every((c) => c && c.from === from);
13083
- this.clients = clients;
13084
- this.activeView = null;
13085
- this.clear();
13086
- }
13087
- if (!this.enabled) return false;
13088
- active = active || this.selection.active;
13089
- const { source } = active;
13090
- if (source && source === this.activeView?.source) return true;
13091
- this.clear();
13092
- if (!source) return false;
13093
- const activeView = this.activeView = getActiveView(active);
13094
- if (!activeView) return false;
13095
- this.mc.logger().warn("DATA CUBE INDEX CONSTRUCTION");
13096
- const sel = this.selection.remove(source);
13097
- const indices = this.indices = /* @__PURE__ */ new Map();
13098
- const { mc, temp } = this;
13099
- for (const client of clients) {
13100
- if (sel.skip(client, active)) continue;
13101
- const index = getIndexColumns(client);
13102
- const query = client.query(sel.predicate(client)).select({ ...activeView.columns, ...index.aux }).groupby(Object.keys(activeView.columns));
13103
- const [subq] = query.subqueries;
13104
- if (subq) {
13105
- const cols = Object.values(activeView.columns).map((c) => c.columns[0]);
13106
- subqueryPushdown(subq, cols);
13107
- }
13108
- const order = query.orderby();
13109
- query.query.orderby = [];
13110
- const sql2 = query.toString();
13111
- const id = (fnv_hash(sql2) >>> 0).toString(16);
13112
- const table2 = `cube_index_${id}`;
13113
- const result = mc.exec(create(table2, sql2, { temp }));
13114
- indices.set(client, { table: table2, result, order, ...index });
13115
- }
13116
- return true;
13117
- }
13118
- async update() {
13119
- const { clients, selection, activeView } = this;
13120
- const filter = activeView.predicate(selection.active.predicate);
13121
- return Promise.all(
13122
- Array.from(clients).map((client) => this.updateClient(client, filter))
13123
- );
13124
- }
13125
- async updateClient(client, filter) {
13126
- const index = this.indices.get(client);
13127
- if (!index) return;
13128
- if (!filter) {
13129
- filter = this.activeView.predicate(this.selection.active.predicate);
13130
- }
13131
- const { table: table2, dims, aggr, order = [] } = index;
13132
- const query = Query.select(dims, aggr).from(table2).groupby(dims).where(filter).orderby(order);
13133
- return this.mc.updateClient(client, query);
13134
- }
13135
- };
13136
- function getActiveView(clause) {
13137
- const { source, schema } = clause;
13138
- let columns = clause.predicate?.columns;
13139
- if (!schema || !columns) return null;
13140
- const { type, scales: scales2, pixelSize = 1 } = schema;
13141
- let predicate;
13142
- if (type === "interval" && scales2) {
13143
- const bins = scales2.map((s) => binInterval(s, pixelSize));
13144
- if (bins.some((b) => b == null)) return null;
13145
- if (bins.length === 1) {
13146
- predicate = (p) => p ? isBetween("active0", p.range.map(bins[0])) : [];
13147
- columns = { active0: bins[0](clause.predicate.field) };
13148
- } else {
13149
- predicate = (p) => p ? and(p.children.map(({ range }, i) => isBetween(`active${i}`, range.map(bins[i])))) : [];
13150
- columns = Object.fromEntries(
13151
- clause.predicate.children.map((p, i) => [`active${i}`, bins[i](p.field)])
13152
- );
13153
- }
13154
- } else if (type === "point") {
13155
- predicate = (x2) => x2;
13156
- columns = Object.fromEntries(columns.map((col) => [col.toString(), col]));
13157
- } else {
13158
- return null;
13159
- }
13160
- return { source, columns, predicate };
13161
- }
13162
- function binInterval(scale, pixelSize) {
13163
- const { apply, sqlApply } = scaleTransform(scale);
13164
- if (apply) {
13165
- const { domain, range } = scale;
13166
- const lo = apply(Math.min(...domain));
13167
- const hi = apply(Math.max(...domain));
13168
- const a = Math.abs(range[1] - range[0]) / (hi - lo) / pixelSize;
13169
- const s = pixelSize === 1 ? "" : `${pixelSize}::INTEGER * `;
13170
- return (value) => sql`${s}FLOOR(${a}::DOUBLE * (${sqlApply(value)} - ${lo}::DOUBLE))::INTEGER`;
13171
- }
13172
- }
13173
- var NO_INDEX = { from: NaN };
13174
- function getIndexColumns(client) {
13175
- if (!client.filterIndexable) return NO_INDEX;
13098
+ // ../core/src/util/index-columns.js
13099
+ function indexColumns(client) {
13100
+ if (!client.filterIndexable) return null;
13176
13101
  const q = client.query();
13177
13102
  const from = getBaseTable(q);
13178
- if (!from || !q.groupby) return NO_INDEX;
13179
- const g = new Set(q.groupby().map((c) => c.column));
13103
+ if (typeof from !== "string" || !q.select) return null;
13180
13104
  const aggr = [];
13181
13105
  const dims = [];
13182
13106
  const aux = {};
13183
- let auxAs;
13184
13107
  for (const entry of q.select()) {
13185
13108
  const { as, expr: { aggregate, args } } = entry;
13186
13109
  const op = aggregate?.toUpperCase?.();
13187
13110
  switch (op) {
13188
13111
  case "COUNT":
13189
13112
  case "SUM":
13190
- aggr.push({ [as]: sql`SUM("${as}")::DOUBLE` });
13113
+ aggr.push({ [as]: agg`SUM("${as}")::DOUBLE` });
13191
13114
  break;
13192
13115
  case "AVG":
13193
- aux[auxAs = "__count__"] = sql`COUNT(*)`;
13194
- aggr.push({ [as]: sql`(SUM("${as}" * ${auxAs}) / SUM(${auxAs}))::DOUBLE` });
13116
+ aggr.push({ [as]: avgExpr(aux, as, args[0]) });
13195
13117
  break;
13196
13118
  case "ARG_MAX":
13197
- aux[auxAs = `__max_${as}__`] = sql`MAX(${args[1]})`;
13198
- aggr.push({ [as]: sql`ARG_MAX("${as}", ${auxAs})` });
13119
+ aggr.push({ [as]: argmaxExpr(aux, as, args) });
13199
13120
  break;
13200
13121
  case "ARG_MIN":
13201
- aux[auxAs = `__min_${as}__`] = sql`MIN(${args[1]})`;
13202
- aggr.push({ [as]: sql`ARG_MIN("${as}", ${auxAs})` });
13122
+ aggr.push({ [as]: argminExpr(aux, as, args) });
13123
+ break;
13124
+ case "VARIANCE":
13125
+ case "VAR_SAMP":
13126
+ aux[as] = null;
13127
+ aggr.push({ [as]: varianceExpr(aux, args[0], from) });
13128
+ break;
13129
+ case "VAR_POP":
13130
+ aux[as] = null;
13131
+ aggr.push({ [as]: varianceExpr(aux, args[0], from, false) });
13132
+ break;
13133
+ case "STDDEV":
13134
+ case "STDDEV_SAMP":
13135
+ aux[as] = null;
13136
+ aggr.push({ [as]: agg`SQRT(${varianceExpr(aux, args[0], from)})` });
13137
+ break;
13138
+ case "STDDEV_POP":
13139
+ aux[as] = null;
13140
+ aggr.push({ [as]: agg`SQRT(${varianceExpr(aux, args[0], from, false)})` });
13141
+ break;
13142
+ case "COVAR_SAMP":
13143
+ aux[as] = null;
13144
+ aggr.push({ [as]: covarianceExpr(aux, args, from) });
13145
+ break;
13146
+ case "COVAR_POP":
13147
+ aux[as] = null;
13148
+ aggr.push({ [as]: covarianceExpr(aux, args, from, false) });
13149
+ break;
13150
+ case "CORR":
13151
+ aux[as] = null;
13152
+ aggr.push({ [as]: corrExpr(aux, args, from) });
13153
+ break;
13154
+ case "REGR_COUNT":
13155
+ aux[as] = null;
13156
+ aggr.push({ [as]: agg`${regrCountExpr(aux, args)}::DOUBLE` });
13157
+ break;
13158
+ case "REGR_AVGX":
13159
+ aux[as] = null;
13160
+ aggr.push({ [as]: regrAvgXExpr(aux, args) });
13161
+ break;
13162
+ case "REGR_AVGY":
13163
+ aux[as] = null;
13164
+ aggr.push({ [as]: regrAvgYExpr(aux, args) });
13165
+ break;
13166
+ case "REGR_SYY":
13167
+ aux[as] = null;
13168
+ aggr.push({ [as]: regrVarExpr(aux, 0, args, from) });
13169
+ break;
13170
+ case "REGR_SXX":
13171
+ aux[as] = null;
13172
+ aggr.push({ [as]: regrVarExpr(aux, 1, args, from) });
13173
+ break;
13174
+ case "REGR_SXY":
13175
+ aux[as] = null;
13176
+ aggr.push({ [as]: covarianceExpr(aux, args, from, null) });
13177
+ break;
13178
+ case "REGR_SLOPE":
13179
+ aux[as] = null;
13180
+ aggr.push({ [as]: regrSlopeExpr(aux, args, from) });
13181
+ break;
13182
+ case "REGR_INTERCEPT":
13183
+ aux[as] = null;
13184
+ aggr.push({ [as]: regrInterceptExpr(aux, args, from) });
13185
+ break;
13186
+ case "REGR_R2":
13187
+ aux[as] = null;
13188
+ aggr.push({ [as]: agg`(${corrExpr(aux, args, from)}) ** 2` });
13203
13189
  break;
13204
13190
  case "MAX":
13205
13191
  case "MIN":
@@ -13209,14 +13195,22 @@ function getIndexColumns(client) {
13209
13195
  case "BOOL_AND":
13210
13196
  case "BOOL_OR":
13211
13197
  case "PRODUCT":
13212
- aggr.push({ [as]: sql`${op}("${as}")` });
13198
+ aggr.push({ [as]: agg`${op}("${as}")` });
13213
13199
  break;
13214
13200
  default:
13215
- if (g.has(as)) dims.push(as);
13201
+ if (!aggregate) dims.push(as);
13216
13202
  else return null;
13217
13203
  }
13218
13204
  }
13219
- return { aggr, dims, aux, from };
13205
+ if (!aggr.length) return null;
13206
+ return { from, dims, aggr, aux };
13207
+ }
13208
+ function auxName(type, ...args) {
13209
+ const cols = args.length ? "_" + args.map(sanitize).join("_") : "";
13210
+ return `__${type}${cols}__`;
13211
+ }
13212
+ function sanitize(col) {
13213
+ return `${col}`.replaceAll('"', "").replaceAll(" ", "_");
13220
13214
  }
13221
13215
  function getBaseTable(query) {
13222
13216
  const subq = query.subqueries;
@@ -13233,6 +13227,291 @@ function getBaseTable(query) {
13233
13227
  }
13234
13228
  return base;
13235
13229
  }
13230
+ function countExpr(aux, arg) {
13231
+ const n = auxName("count", arg);
13232
+ aux[n] = agg`COUNT(${arg})`;
13233
+ return agg`SUM(${n})`.annotate({ name: n });
13234
+ }
13235
+ function avgExpr(aux, as, arg) {
13236
+ const n = countExpr(aux, arg);
13237
+ return agg`(SUM("${as}" * ${n.name}) / ${n})`;
13238
+ }
13239
+ function avg2(x2, from) {
13240
+ return sql`(SELECT AVG(${x2}) FROM "${from}")`;
13241
+ }
13242
+ function argmaxExpr(aux, as, [, y2]) {
13243
+ const max2 = auxName("max", y2);
13244
+ aux[max2] = agg`MAX(${y2})`;
13245
+ return agg`ARG_MAX("${as}", ${max2})`;
13246
+ }
13247
+ function argminExpr(aux, as, [, y2]) {
13248
+ const min2 = auxName("min", y2);
13249
+ aux[min2] = agg`MIN(${y2})`;
13250
+ return agg`ARG_MIN("${as}", ${min2})`;
13251
+ }
13252
+ function varianceExpr(aux, x2, from, correction = true) {
13253
+ const n = countExpr(aux, x2);
13254
+ const ssq = auxName("rssq", x2);
13255
+ const sum2 = auxName("rsum", x2);
13256
+ const delta = sql`${x2} - ${avg2(x2, from)}`;
13257
+ aux[ssq] = agg`SUM((${delta}) ** 2)`;
13258
+ aux[sum2] = agg`SUM(${delta})`;
13259
+ const adj = correction ? ` - 1` : "";
13260
+ return agg`(SUM(${ssq}) - (SUM(${sum2}) ** 2 / ${n})) / (${n}${adj})`;
13261
+ }
13262
+ function covarianceExpr(aux, args, from, correction = true) {
13263
+ const n = regrCountExpr(aux, args);
13264
+ const sxy = regrSumXYExpr(aux, args, from);
13265
+ const sx = regrSumExpr(aux, 1, args, from);
13266
+ const sy = regrSumExpr(aux, 0, args, from);
13267
+ const adj = correction === null ? "" : correction ? ` / (${n} - 1)` : ` / ${n}`;
13268
+ return agg`(${sxy} - ${sx} * ${sy} / ${n})${adj}`;
13269
+ }
13270
+ function corrExpr(aux, args, from) {
13271
+ const n = regrCountExpr(aux, args);
13272
+ const sxy = regrSumXYExpr(aux, args, from);
13273
+ const sxx = regrSumSqExpr(aux, 1, args, from);
13274
+ const syy = regrSumSqExpr(aux, 0, args, from);
13275
+ const sx = regrSumExpr(aux, 1, args, from);
13276
+ const sy = regrSumExpr(aux, 0, args, from);
13277
+ const vx = agg`(${sxx} - (${sx} ** 2) / ${n})`;
13278
+ const vy = agg`(${syy} - (${sy} ** 2) / ${n})`;
13279
+ return agg`(${sxy} - ${sx} * ${sy} / ${n}) / SQRT(${vx} * ${vy})`;
13280
+ }
13281
+ function regrCountExpr(aux, [y2, x2]) {
13282
+ const n = auxName("count", y2, x2);
13283
+ aux[n] = agg`REGR_COUNT(${y2}, ${x2})`;
13284
+ return agg`SUM(${n})`.annotate({ name: n });
13285
+ }
13286
+ function regrSumExpr(aux, i, args, from) {
13287
+ const v = args[i];
13288
+ const o = args[1 - i];
13289
+ const sum2 = auxName("rs", v);
13290
+ aux[sum2] = agg`SUM(${v} - ${avg2(v, from)}) FILTER (${o} IS NOT NULL)`;
13291
+ return agg`SUM(${sum2})`;
13292
+ }
13293
+ function regrSumSqExpr(aux, i, args, from) {
13294
+ const v = args[i];
13295
+ const u = args[1 - i];
13296
+ const ssq = auxName("rss", v);
13297
+ aux[ssq] = agg`SUM((${v} - ${avg2(v, from)}) ** 2) FILTER (${u} IS NOT NULL)`;
13298
+ return agg`SUM(${ssq})`;
13299
+ }
13300
+ function regrSumXYExpr(aux, args, from) {
13301
+ const [y2, x2] = args;
13302
+ const sxy = auxName("sxy", y2, x2);
13303
+ aux[sxy] = agg`SUM((${x2} - ${avg2(x2, from)}) * (${y2} - ${avg2(y2, from)}))`;
13304
+ return agg`SUM(${sxy})`;
13305
+ }
13306
+ function regrAvgXExpr(aux, args) {
13307
+ const [y2, x2] = args;
13308
+ const n = regrCountExpr(aux, args);
13309
+ const a = auxName("avg", x2, y2);
13310
+ aux[a] = agg`REGR_AVGX(${y2}, ${x2})`;
13311
+ return agg`(SUM(${a} * ${n.name}) / ${n})`;
13312
+ }
13313
+ function regrAvgYExpr(aux, args) {
13314
+ const [y2, x2] = args;
13315
+ const n = regrCountExpr(aux, args);
13316
+ const a = auxName("avg", y2, x2);
13317
+ aux[a] = agg`REGR_AVGY(${y2}, ${x2})`;
13318
+ return agg`(SUM(${a} * ${n.name}) / ${n})`;
13319
+ }
13320
+ function regrVarExpr(aux, i, args, from) {
13321
+ const n = regrCountExpr(aux, args);
13322
+ const sum2 = regrSumExpr(aux, i, args, from);
13323
+ const ssq = regrSumSqExpr(aux, i, args, from);
13324
+ return agg`(${ssq} - (${sum2} ** 2 / ${n}))`;
13325
+ }
13326
+ function regrSlopeExpr(aux, args, from) {
13327
+ const cov = covarianceExpr(aux, args, from, null);
13328
+ const varx = regrVarExpr(aux, 1, args, from);
13329
+ return agg`(${cov}) / ${varx}`;
13330
+ }
13331
+ function regrInterceptExpr(aux, args, from) {
13332
+ const ax = regrAvgXExpr(aux, args);
13333
+ const ay = regrAvgYExpr(aux, args);
13334
+ const m = regrSlopeExpr(aux, args, from);
13335
+ return agg`${ay} - (${m}) * ${ax}`;
13336
+ }
13337
+
13338
+ // ../core/src/util/hash.js
13339
+ function fnv_hash(v) {
13340
+ let a = 2166136261;
13341
+ for (let i = 0, n = v.length; i < n; ++i) {
13342
+ const c = v.charCodeAt(i);
13343
+ const d = c & 65280;
13344
+ if (d) a = fnv_multiply(a ^ d >> 8);
13345
+ a = fnv_multiply(a ^ c & 255);
13346
+ }
13347
+ return fnv_mix(a);
13348
+ }
13349
+ function fnv_multiply(a) {
13350
+ return a + (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24);
13351
+ }
13352
+ function fnv_mix(a) {
13353
+ a += a << 13;
13354
+ a ^= a >>> 7;
13355
+ a += a << 3;
13356
+ a ^= a >>> 17;
13357
+ a += a << 5;
13358
+ return a & 4294967295;
13359
+ }
13360
+
13361
+ // ../core/src/DataCubeIndexer.js
13362
+ var Skip = { skip: true, result: null };
13363
+ var DataCubeIndexer = class {
13364
+ /**
13365
+ * Create a new data cube index table manager.
13366
+ * @param {import('./Coordinator.js').Coordinator} coordinator A Mosaic coordinator.
13367
+ * @param {object} [options] Indexer options.
13368
+ * @param {boolean} [options.enabled=true] Flag to enable/disable indexer.
13369
+ * @param {boolean} [options.temp=true] Flag to indicate if generated data
13370
+ * cube index tables should be temporary tables.
13371
+ */
13372
+ constructor(coordinator2, {
13373
+ enabled = true,
13374
+ temp = true
13375
+ } = {}) {
13376
+ this.indexes = /* @__PURE__ */ new Map();
13377
+ this.active = null;
13378
+ this.temp = temp;
13379
+ this.mc = coordinator2;
13380
+ this._enabled = enabled;
13381
+ }
13382
+ /**
13383
+ * Set the enabled state of this indexer. If false, any cached state is
13384
+ * cleared and subsequent index calls will return null until re-enabled.
13385
+ * @param {boolean} state The enabled state.
13386
+ */
13387
+ enabled(state) {
13388
+ if (state === void 0) {
13389
+ return this._enabled;
13390
+ } else if (this._enabled !== state) {
13391
+ if (!state) this.clear();
13392
+ this._enabled = state;
13393
+ }
13394
+ }
13395
+ /**
13396
+ * Clear the cache of data cube index table entries for the current active
13397
+ * selection clause. This method will also cancel any queued data cube table
13398
+ * creation queries that have not yet been submitted to the database. This
13399
+ * method does _not_ drop any existing data cube tables.
13400
+ */
13401
+ clear() {
13402
+ this.mc.cancel(Array.from(this.indexes.values(), (info) => info?.result));
13403
+ this.indexes.clear();
13404
+ this.active = null;
13405
+ }
13406
+ /**
13407
+ * Return data cube index table information for the active state of a
13408
+ * client-selection pair, or null if the client is not indexable. This
13409
+ * method has multiple possible side effects, including data cube table
13410
+ * generation and updating internal caches.
13411
+ * @param {import('./MosaicClient.js').MosaicClient} client A Mosaic client.
13412
+ * @param {import('./Selection.js').Selection} selection A Mosaic selection
13413
+ * to filter the client by.
13414
+ * @param {import('./util/selection-types.js').SelectionClause} activeClause
13415
+ * A representative active selection clause for which to (possibly) generate
13416
+ * data cube index tables.
13417
+ * @returns {DataCubeInfo | Skip | null} Data cube index table
13418
+ * information and query generator, or null if the client is not indexable.
13419
+ */
13420
+ index(client, selection, activeClause) {
13421
+ if (!this._enabled) return null;
13422
+ const { indexes, mc, temp } = this;
13423
+ const { source } = activeClause;
13424
+ if (!source) return null;
13425
+ if (this.active) {
13426
+ if (this.active.source !== source) this.clear();
13427
+ if (this.active?.source === null) return null;
13428
+ }
13429
+ let { active } = this;
13430
+ if (!active) {
13431
+ this.active = active = activeColumns(activeClause);
13432
+ if (active.source === null) return null;
13433
+ }
13434
+ if (indexes.has(client)) {
13435
+ return indexes.get(client);
13436
+ }
13437
+ const indexCols = indexColumns(client);
13438
+ let info;
13439
+ if (!indexCols) {
13440
+ info = null;
13441
+ } else if (selection.skip(client, activeClause)) {
13442
+ info = Skip;
13443
+ } else {
13444
+ const filter = selection.remove(source).predicate(client);
13445
+ info = dataCubeInfo(client.query(filter), active, indexCols);
13446
+ info.result = mc.exec(create(info.table, info.create, { temp }));
13447
+ info.result.catch((e) => mc.logger().error(e));
13448
+ }
13449
+ indexes.set(client, info);
13450
+ return info;
13451
+ }
13452
+ };
13453
+ function activeColumns(clause) {
13454
+ const { source, meta } = clause;
13455
+ const clausePred = clause.predicate;
13456
+ const clauseCols = clausePred?.columns;
13457
+ let predicate;
13458
+ let columns;
13459
+ if (!meta || !clauseCols) {
13460
+ return { source: null, columns, predicate };
13461
+ }
13462
+ const { type, scales: scales2, bin, pixelSize = 1 } = meta;
13463
+ if (type === "point") {
13464
+ predicate = (x2) => x2;
13465
+ columns = Object.fromEntries(
13466
+ clauseCols.map((col) => [`${col}`, asColumn(col)])
13467
+ );
13468
+ } else if (type === "interval" && scales2) {
13469
+ const bins = scales2.map((s) => binInterval(s, pixelSize, bin));
13470
+ if (bins.some((b) => !b)) {
13471
+ } else if (bins.length === 1) {
13472
+ predicate = (p) => p ? isBetween("active0", p.range.map(bins[0])) : [];
13473
+ columns = { active0: bins[0](clausePred.field) };
13474
+ } else {
13475
+ predicate = (p) => p ? and(p.children.map(
13476
+ ({ range }, i) => isBetween(`active${i}`, range.map(bins[i]))
13477
+ )) : [];
13478
+ columns = Object.fromEntries(
13479
+ // @ts-ignore
13480
+ clausePred.children.map((p, i) => [`active${i}`, bins[i](p.field)])
13481
+ );
13482
+ }
13483
+ }
13484
+ return { source: columns ? source : null, columns, predicate };
13485
+ }
13486
+ var BIN = { ceil: "CEIL", round: "ROUND" };
13487
+ function binInterval(scale, pixelSize, bin) {
13488
+ const { type, domain, range, apply, sqlApply } = scaleTransform(scale);
13489
+ if (!apply) return;
13490
+ const fn = BIN[`${bin}`.toLowerCase()] || "FLOOR";
13491
+ const lo = apply(Math.min(...domain));
13492
+ const hi = apply(Math.max(...domain));
13493
+ const a = type === "identity" ? 1 : Math.abs(range[1] - range[0]) / (hi - lo);
13494
+ const s = a / pixelSize === 1 ? "" : `${a / pixelSize}::DOUBLE * `;
13495
+ const d = lo === 0 ? "" : ` - ${lo}::DOUBLE`;
13496
+ return (value) => sql`${fn}(${s}(${sqlApply(value)}${d}))::INTEGER`;
13497
+ }
13498
+ function dataCubeInfo(clientQuery, active, indexCols) {
13499
+ const { dims, aggr, aux } = indexCols;
13500
+ const { columns } = active;
13501
+ const query = clientQuery.select({ ...columns, ...aux }).groupby(Object.keys(columns));
13502
+ const [subq] = query.subqueries;
13503
+ if (subq) {
13504
+ const cols = Object.values(columns).flatMap((c) => c.columns);
13505
+ subqueryPushdown(subq, cols);
13506
+ }
13507
+ const order = query.orderby();
13508
+ query.query.orderby = [];
13509
+ const create2 = query.toString();
13510
+ const id = (fnv_hash(create2) >>> 0).toString(16);
13511
+ const table2 = `cube_index_${id}`;
13512
+ const select = Query.select(dims, aggr).from(table2).groupby(dims).orderby(order);
13513
+ return new DataCubeInfo({ table: table2, create: create2, active, select });
13514
+ }
13236
13515
  function subqueryPushdown(query, cols) {
13237
13516
  const memo = /* @__PURE__ */ new Set();
13238
13517
  const pushdown = (q) => {
@@ -13245,78 +13524,65 @@ function subqueryPushdown(query, cols) {
13245
13524
  };
13246
13525
  pushdown(query);
13247
13526
  }
13248
-
13249
- // ../core/src/FilterGroup.js
13250
- var FilterGroup = class {
13527
+ var DataCubeInfo = class {
13251
13528
  /**
13252
- * @param {import('./Coordinator.js').Coordinator} coordinator The Mosaic coordinator.
13253
- * @param {*} selection The shared filter selection.
13254
- * @param {*} index Boolean flag or options hash for data cube indexer.
13255
- * Falsy values disable indexing.
13529
+ * Create a new DataCubeInfo instance.
13530
+ * @param {object} options
13256
13531
  */
13257
- constructor(coordinator2, selection, index = true) {
13258
- this.mc = coordinator2;
13259
- this.selection = selection;
13260
- this.clients = /* @__PURE__ */ new Set();
13261
- this.indexer = index ? new DataCubeIndexer(this.mc, { ...index, selection }) : null;
13262
- const { value, activate } = this.handlers = {
13263
- value: () => this.update(),
13264
- activate: (clause) => this.indexer?.index(this.clients, clause)
13265
- };
13266
- selection.addEventListener("value", value);
13267
- selection.addEventListener("activate", activate);
13532
+ constructor({ table: table2, create: create2, active, select } = {}) {
13533
+ this.table = table2;
13534
+ this.create = create2;
13535
+ this.result = null;
13536
+ this.active = active;
13537
+ this.select = select;
13538
+ this.skip = false;
13268
13539
  }
13269
- finalize() {
13270
- const { value, activate } = this.handlers;
13271
- this.selection.removeEventListener("value", value);
13272
- this.selection.removeEventListener("activate", activate);
13273
- }
13274
- reset() {
13275
- this.indexer?.reset();
13540
+ /**
13541
+ * Generate a data cube index table query for the given predicate.
13542
+ * @param {import('@uwdata/mosaic-sql').SQLExpression} predicate The current
13543
+ * active clause predicate.
13544
+ * @returns {Query} A data cube index table query.
13545
+ */
13546
+ query(predicate) {
13547
+ return this.select.clone().where(this.active.predicate(predicate));
13276
13548
  }
13277
- add(client) {
13278
- (this.clients = new Set(this.clients)).add(client);
13279
- return this;
13549
+ };
13550
+
13551
+ // ../core/src/util/query-result.js
13552
+ var QueryResult = class extends Promise {
13553
+ /**
13554
+ * Create a new query result Promise.
13555
+ */
13556
+ constructor() {
13557
+ let resolve;
13558
+ let reject;
13559
+ super((r, e) => {
13560
+ resolve = r;
13561
+ reject = e;
13562
+ });
13563
+ this._resolve = resolve;
13564
+ this._reject = reject;
13280
13565
  }
13281
- remove(client) {
13282
- if (this.clients.has(client)) {
13283
- (this.clients = new Set(this.clients)).delete(client);
13284
- }
13566
+ /**
13567
+ * Resolve the result Promise with the provided value.
13568
+ * @param {*} value The result value.
13569
+ * @returns {this}
13570
+ */
13571
+ fulfill(value) {
13572
+ this._resolve(value);
13285
13573
  return this;
13286
13574
  }
13287
13575
  /**
13288
- * Internal method to process a selection update.
13289
- * The return value is passed as a selection callback value.
13290
- * @returns {Promise} A Promise that resolves when the update completes.
13576
+ * Rejects the result Promise with the provided error.
13577
+ * @param {*} error The error value.
13578
+ * @returns {this}
13291
13579
  */
13292
- update() {
13293
- const { mc, indexer, clients, selection } = this;
13294
- const hasIndex = indexer?.index(clients);
13295
- return hasIndex ? indexer.update() : defaultUpdate(mc, clients, selection);
13580
+ reject(error) {
13581
+ this._reject(error);
13582
+ return this;
13296
13583
  }
13297
13584
  };
13298
- function defaultUpdate(mc, clients, selection) {
13299
- return Promise.all(Array.from(clients).map((client) => {
13300
- const filter = selection.predicate(client);
13301
- if (filter != null) {
13302
- return mc.updateClient(client, client.query(filter));
13303
- }
13304
- }));
13305
- }
13306
-
13307
- // ../core/src/util/query-result.js
13308
- function queryResult() {
13309
- let resolve;
13310
- let reject;
13311
- const p = new Promise((r, e) => {
13312
- resolve = r;
13313
- reject = e;
13314
- });
13315
- return Object.assign(p, {
13316
- fulfill: (value) => (resolve(value), p),
13317
- reject: (err) => (reject(err), p)
13318
- });
13319
- }
13585
+ QueryResult.prototype.constructor = Promise;
13320
13586
 
13321
13587
  // ../core/src/QueryConsolidator.js
13322
13588
  function wait(callback) {
@@ -13392,7 +13658,7 @@ function consolidate(group, enqueue, record) {
13392
13658
  record: false,
13393
13659
  query: group.query = consolidatedQuery(group, record)
13394
13660
  },
13395
- result: group.result = queryResult()
13661
+ result: group.result = new QueryResult()
13396
13662
  });
13397
13663
  } else {
13398
13664
  for (const { entry, priority } of group) {
@@ -13608,115 +13874,124 @@ function priorityQueue(ranks) {
13608
13874
 
13609
13875
  // ../core/src/QueryManager.js
13610
13876
  var Priority = { High: 0, Normal: 1, Low: 2 };
13611
- function QueryManager() {
13612
- const queue = priorityQueue(3);
13613
- let db;
13614
- let clientCache;
13615
- let logger;
13616
- let recorders = [];
13617
- let pending = null;
13618
- let consolidate2;
13619
- function next() {
13620
- if (pending || queue.isEmpty()) return;
13621
- const { request, result } = queue.next();
13622
- pending = submit(request, result);
13623
- pending.finally(() => {
13624
- pending = null;
13625
- next();
13877
+ var QueryManager = class {
13878
+ constructor() {
13879
+ this.queue = priorityQueue(3);
13880
+ this.db = null;
13881
+ this.clientCache = null;
13882
+ this._logger = null;
13883
+ this._logQueries = false;
13884
+ this.recorders = [];
13885
+ this.pending = null;
13886
+ this._consolidate = null;
13887
+ }
13888
+ next() {
13889
+ if (this.pending || this.queue.isEmpty()) return;
13890
+ const { request, result } = this.queue.next();
13891
+ this.pending = this.submit(request, result);
13892
+ this.pending.finally(() => {
13893
+ this.pending = null;
13894
+ this.next();
13626
13895
  });
13627
13896
  }
13628
- function enqueue(entry, priority = Priority.Normal) {
13629
- queue.insert(entry, priority);
13630
- next();
13897
+ enqueue(entry, priority = Priority.Normal) {
13898
+ this.queue.insert(entry, priority);
13899
+ this.next();
13631
13900
  }
13632
- function recordQuery(sql2) {
13633
- if (recorders.length && sql2) {
13634
- recorders.forEach((rec) => rec.add(sql2));
13901
+ recordQuery(sql2) {
13902
+ if (this.recorders.length && sql2) {
13903
+ this.recorders.forEach((rec) => rec.add(sql2));
13635
13904
  }
13636
13905
  }
13637
- async function submit(request, result) {
13906
+ async submit(request, result) {
13638
13907
  try {
13639
13908
  const { query, type, cache = false, record = true, options } = request;
13640
13909
  const sql2 = query ? `${query}` : null;
13641
13910
  if (record) {
13642
- recordQuery(sql2);
13911
+ this.recordQuery(sql2);
13643
13912
  }
13644
13913
  if (cache) {
13645
- const cached = clientCache.get(sql2);
13914
+ const cached = this.clientCache.get(sql2);
13646
13915
  if (cached) {
13647
- logger.debug("Cache");
13916
+ this._logger.debug("Cache");
13648
13917
  result.fulfill(cached);
13649
13918
  return;
13650
13919
  }
13651
13920
  }
13652
13921
  const t0 = performance.now();
13653
- const data = await db.query({ type, sql: sql2, ...options });
13654
- if (cache) clientCache.set(sql2, data);
13655
- logger.debug(`Request: ${(performance.now() - t0).toFixed(1)}`);
13922
+ if (this._logQueries) {
13923
+ this._logger.debug("Query", { type, sql: sql2, ...options });
13924
+ }
13925
+ const data = await this.db.query({ type, sql: sql2, ...options });
13926
+ if (cache) this.clientCache.set(sql2, data);
13927
+ this._logger.debug(`Request: ${(performance.now() - t0).toFixed(1)}`);
13656
13928
  result.fulfill(data);
13657
13929
  } catch (err) {
13658
13930
  result.reject(err);
13659
13931
  }
13660
13932
  }
13661
- return {
13662
- cache(value) {
13663
- return value !== void 0 ? clientCache = value === true ? lruCache() : value || voidCache() : clientCache;
13664
- },
13665
- logger(value) {
13666
- return value ? logger = value : logger;
13667
- },
13668
- connector(connector) {
13669
- return connector ? db = connector : db;
13670
- },
13671
- consolidate(flag) {
13672
- if (flag && !consolidate2) {
13673
- consolidate2 = consolidator(enqueue, clientCache, recordQuery);
13674
- } else if (!flag && consolidate2) {
13675
- consolidate2 = null;
13676
- }
13677
- },
13678
- request(request, priority = Priority.Normal) {
13679
- const result = queryResult();
13680
- const entry = { request, result };
13681
- if (consolidate2) {
13682
- consolidate2.add(entry, priority);
13683
- } else {
13684
- enqueue(entry, priority);
13685
- }
13686
- return result;
13687
- },
13688
- cancel(requests) {
13689
- const set = new Set(requests);
13690
- queue.remove(({ result }) => set.has(result));
13691
- },
13692
- clear() {
13693
- queue.remove(({ result }) => {
13694
- result.reject("Cleared");
13695
- return true;
13696
- });
13697
- },
13698
- record() {
13699
- let state = [];
13700
- const recorder = {
13701
- add(query) {
13702
- state.push(query);
13703
- },
13704
- reset() {
13705
- state = [];
13706
- },
13707
- snapshot() {
13708
- return state.slice();
13709
- },
13710
- stop() {
13711
- recorders = recorders.filter((x2) => x2 !== recorder);
13712
- return state;
13713
- }
13714
- };
13715
- recorders.push(recorder);
13716
- return recorder;
13933
+ cache(value) {
13934
+ return value !== void 0 ? this.clientCache = value === true ? lruCache() : value || voidCache() : this.clientCache;
13935
+ }
13936
+ logger(value) {
13937
+ return value ? this._logger = value : this._logger;
13938
+ }
13939
+ logQueries(value) {
13940
+ return value !== void 0 ? this._logQueries = !!value : this._logQueries;
13941
+ }
13942
+ connector(connector) {
13943
+ return connector ? this.db = connector : this.db;
13944
+ }
13945
+ consolidate(flag) {
13946
+ if (flag && !this._consolidate) {
13947
+ this._consolidate = consolidator(this.enqueue.bind(this), this.clientCache, this.recordQuery.bind(this));
13948
+ } else if (!flag && this._consolidate) {
13949
+ this._consolidate = null;
13717
13950
  }
13718
- };
13719
- }
13951
+ }
13952
+ request(request, priority = Priority.Normal) {
13953
+ const result = new QueryResult();
13954
+ const entry = { request, result };
13955
+ if (this._consolidate) {
13956
+ this._consolidate.add(entry, priority);
13957
+ } else {
13958
+ this.enqueue(entry, priority);
13959
+ }
13960
+ return result;
13961
+ }
13962
+ cancel(requests) {
13963
+ const set = new Set(requests);
13964
+ if (set.size) {
13965
+ this.queue.remove(({ result }) => set.has(result));
13966
+ }
13967
+ }
13968
+ clear() {
13969
+ this.queue.remove(({ result }) => {
13970
+ result.reject("Cleared");
13971
+ return true;
13972
+ });
13973
+ }
13974
+ record() {
13975
+ let state = [];
13976
+ const recorder = {
13977
+ add(query) {
13978
+ state.push(query);
13979
+ },
13980
+ reset() {
13981
+ state = [];
13982
+ },
13983
+ snapshot() {
13984
+ return state.slice();
13985
+ },
13986
+ stop() {
13987
+ this.recorders = this.recorders.filter((x2) => x2 !== recorder);
13988
+ return state;
13989
+ }
13990
+ };
13991
+ this.recorders.push(recorder);
13992
+ return recorder;
13993
+ }
13994
+ };
13720
13995
 
13721
13996
  // ../core/src/util/js-type.js
13722
13997
  function jsType(type) {
@@ -13768,6 +14043,9 @@ function jsType(type) {
13768
14043
  }
13769
14044
 
13770
14045
  // ../core/src/util/convert-arrow.js
14046
+ function isArrowTable(values) {
14047
+ return typeof values?.getChild === "function";
14048
+ }
13771
14049
  function convertArrowValue(type) {
13772
14050
  if (DataType.isTimestamp(type)) {
13773
14051
  return (v) => v == null ? v : new Date(v);
@@ -13781,6 +14059,41 @@ function convertArrowValue(type) {
13781
14059
  }
13782
14060
  return (v) => v;
13783
14061
  }
14062
+ function convertArrowColumn(column2) {
14063
+ const { type } = column2;
14064
+ if (DataType.isTimestamp(type)) {
14065
+ const size = column2.length;
14066
+ const array = new Array(size);
14067
+ for (let row = 0; row < size; ++row) {
14068
+ const v = column2.get(row);
14069
+ array[row] = v == null ? null : new Date(v);
14070
+ }
14071
+ return array;
14072
+ }
14073
+ if (DataType.isInt(type) && type.bitWidth >= 64) {
14074
+ const size = column2.length;
14075
+ const array = column2.nullCount ? new Array(size) : new Float64Array(size);
14076
+ for (let row = 0; row < size; ++row) {
14077
+ const v = column2.get(row);
14078
+ array[row] = v == null ? null : Number(v);
14079
+ }
14080
+ return array;
14081
+ }
14082
+ if (DataType.isDecimal(type)) {
14083
+ const scale = 1 / Math.pow(10, type.scale);
14084
+ const size = column2.length;
14085
+ const array = column2.nullCount ? new Array(size) : new Float64Array(size);
14086
+ for (let row = 0; row < size; ++row) {
14087
+ const v = column2.get(row);
14088
+ array[row] = v == null ? null : decimalToNumber(v, scale);
14089
+ }
14090
+ return array;
14091
+ }
14092
+ if (column2.nullCount) {
14093
+ return Array.from(column2);
14094
+ }
14095
+ return column2.toArray();
14096
+ }
13784
14097
  var BASE32 = Array.from(
13785
14098
  { length: 8 },
13786
14099
  (_, i) => Math.pow(2, i * 32)
@@ -13885,58 +14198,92 @@ function coordinator(instance8) {
13885
14198
  return _instance;
13886
14199
  }
13887
14200
  var Coordinator = class {
13888
- constructor(db = socketConnector(), options = {}) {
13889
- const {
13890
- logger = console,
13891
- manager = QueryManager()
13892
- } = options;
14201
+ constructor(db = socketConnector(), {
14202
+ logger = console,
14203
+ manager = new QueryManager(),
14204
+ cache = true,
14205
+ consolidate: consolidate2 = true,
14206
+ indexes = {}
14207
+ } = {}) {
13893
14208
  this.manager = manager;
14209
+ this.manager.cache(cache);
14210
+ this.manager.consolidate(consolidate2);
14211
+ this.dataCubeIndexer = new DataCubeIndexer(this, indexes);
13894
14212
  this.logger(logger);
13895
- this.configure(options);
13896
14213
  this.databaseConnector(db);
13897
14214
  this.clear();
13898
14215
  }
13899
- logger(logger) {
13900
- if (arguments.length) {
13901
- this._logger = logger || voidLogger();
13902
- this.manager.logger(this._logger);
13903
- }
13904
- return this._logger;
13905
- }
13906
14216
  /**
13907
- * Set configuration options for this coordinator.
13908
- * @param {object} [options] Configration options.
13909
- * @param {boolean} [options.cache=true] Boolean flag to enable/disable query caching.
13910
- * @param {boolean} [options.consolidate=true] Boolean flag to enable/disable query consolidation.
13911
- * @param {boolean|object} [options.indexes=true] Boolean flag to enable/disable
13912
- * automatic data cube indexes or an index options object.
14217
+ * Clear the coordinator state.
14218
+ * @param {object} [options] Options object.
14219
+ * @param {boolean} [options.clients=true] If true, disconnect all clients.
14220
+ * @param {boolean} [options.cache=true] If true, clear the query cache.
13913
14221
  */
13914
- configure({ cache = true, consolidate: consolidate2 = true, indexes = true } = {}) {
13915
- this.manager.cache(cache);
13916
- this.manager.consolidate(consolidate2);
13917
- this.indexes = indexes;
13918
- }
13919
14222
  clear({ clients = true, cache = true } = {}) {
13920
14223
  this.manager.clear();
13921
14224
  if (clients) {
14225
+ this.filterGroups?.forEach((group) => group.disconnect());
14226
+ this.filterGroups = /* @__PURE__ */ new Map();
13922
14227
  this.clients?.forEach((client) => this.disconnect(client));
13923
- this.filterGroups?.forEach((group) => group.finalize());
13924
14228
  this.clients = /* @__PURE__ */ new Set();
13925
- this.filterGroups = /* @__PURE__ */ new Map();
13926
14229
  }
13927
14230
  if (cache) this.manager.cache().clear();
13928
14231
  }
14232
+ /**
14233
+ * Get or set the database connector.
14234
+ * @param {*} [db] The database connector to use.
14235
+ * @returns The current database connector.
14236
+ */
13929
14237
  databaseConnector(db) {
13930
14238
  return this.manager.connector(db);
13931
14239
  }
14240
+ /**
14241
+ * Get or set the logger.
14242
+ * @param {*} logger The logger to use.
14243
+ * @returns The current logger
14244
+ */
14245
+ logger(logger) {
14246
+ if (arguments.length) {
14247
+ this._logger = logger || voidLogger();
14248
+ this.manager.logger(this._logger);
14249
+ }
14250
+ return this._logger;
14251
+ }
13932
14252
  // -- Query Management ----
14253
+ /**
14254
+ * Cancel previosuly submitted query requests. These queries will be
14255
+ * canceled if they are queued but have not yet been submitted.
14256
+ * @param {import('./util/query-result.js').QueryResult[]} requests An array
14257
+ * of query result objects, such as those returned by the `query` method.
14258
+ */
13933
14259
  cancel(requests) {
13934
14260
  this.manager.cancel(requests);
13935
14261
  }
14262
+ /**
14263
+ * Issue a query for which no result (return value) is needed.
14264
+ * @param {import('@uwdata/mosaic-sql').Query | string} query The query.
14265
+ * @param {object} [options] An options object.
14266
+ * @param {number} [options.priority] The query priority, defaults to
14267
+ * `Priority.Normal`.
14268
+ * @returns {import('./util/query-result.js').QueryResult} A query result
14269
+ * promise.
14270
+ */
13936
14271
  exec(query, { priority = Priority.Normal } = {}) {
13937
14272
  query = Array.isArray(query) ? query.join(";\n") : query;
13938
14273
  return this.manager.request({ type: "exec", query }, priority);
13939
14274
  }
14275
+ /**
14276
+ * Issue a query to the backing database. The submitted query may be
14277
+ * consolidate with other queries and its results may be cached.
14278
+ * @param {import('@uwdata/mosaic-sql').Query | string} query The query.
14279
+ * @param {object} [options] An options object.
14280
+ * @param {'arrow' | 'json'} [options.type] The query result format type.
14281
+ * @param {boolean} [options.cache=true] If true, cache the query result.
14282
+ * @param {number} [options.priority] The query priority, defaults to
14283
+ * `Priority.Normal`.
14284
+ * @returns {import('./util/query-result.js').QueryResult} A query result
14285
+ * promise.
14286
+ */
13940
14287
  query(query, {
13941
14288
  type = "arrow",
13942
14289
  cache = true,
@@ -13945,6 +14292,15 @@ var Coordinator = class {
13945
14292
  } = {}) {
13946
14293
  return this.manager.request({ type, query, cache, options }, priority);
13947
14294
  }
14295
+ /**
14296
+ * Issue a query to prefetch data for later use. The query result is cached
14297
+ * for efficient future access.
14298
+ * @param {import('@uwdata/mosaic-sql').Query | string} query The query.
14299
+ * @param {object} [options] An options object.
14300
+ * @param {'arrow' | 'json'} [options.type] The query result format type.
14301
+ * @returns {import('./util/query-result.js').QueryResult} A query result
14302
+ * promise.
14303
+ */
13948
14304
  prefetch(query, options = {}) {
13949
14305
  return this.query(query, { ...options, cache: true, priority: Priority.Low });
13950
14306
  }
@@ -13957,26 +14313,44 @@ var Coordinator = class {
13957
14313
  return this.manager.request({ type: "load-bundle", options }, priority);
13958
14314
  }
13959
14315
  // -- Client Management ----
14316
+ /**
14317
+ * Update client data by submitting the given query and returning the
14318
+ * data (or error) to the client.
14319
+ * @param {import('./MosaicClient.js').MosaicClient} client A Mosaic client.
14320
+ * @param {import('@uwdata/mosaic-sql').Query | string} query The data query.
14321
+ * @param {number} [priority] The query priority.
14322
+ * @returns {Promise} A Promise that resolves upon completion of the update.
14323
+ */
13960
14324
  updateClient(client, query, priority = Priority.Normal) {
13961
14325
  client.queryPending();
13962
14326
  return this.query(query, { priority }).then(
13963
14327
  (data) => client.queryResult(data).update(),
13964
14328
  (err) => {
13965
- client.queryError(err);
13966
14329
  this._logger.error(err);
14330
+ client.queryError(err);
13967
14331
  }
13968
- );
14332
+ ).catch((err) => this._logger.error(err));
13969
14333
  }
14334
+ /**
14335
+ * Issue a query request for a client. If the query is null or undefined,
14336
+ * the client is simply updated. Otherwise `updateClient` is called. As a
14337
+ * side effect, this method clears the current data cube indexer state.
14338
+ * @param {import('./MosaicClient.js').MosaicClient} client The client
14339
+ * to update.
14340
+ * @param {import('@uwdata/mosaic-sql').Query | string | null} [query]
14341
+ * The query to issue.
14342
+ */
13970
14343
  requestQuery(client, query) {
13971
- this.filterGroups.get(client.filterBy)?.reset();
14344
+ this.dataCubeIndexer.clear();
13972
14345
  return query ? this.updateClient(client, query) : client.update();
13973
14346
  }
13974
14347
  /**
13975
14348
  * Connect a client to the coordinator.
13976
- * @param {import('./MosaicClient.js').MosaicClient} client the client to disconnect
14349
+ * @param {import('./MosaicClient.js').MosaicClient} client The Mosaic
14350
+ * client to connect.
13977
14351
  */
13978
14352
  async connect(client) {
13979
- const { clients, filterGroups, indexes } = this;
14353
+ const { clients } = this;
13980
14354
  if (clients.has(client)) {
13981
14355
  throw new Error("Client already connected.");
13982
14356
  }
@@ -13986,30 +14360,64 @@ var Coordinator = class {
13986
14360
  if (fields?.length) {
13987
14361
  client.fieldInfo(await queryFieldInfo(this, fields));
13988
14362
  }
13989
- const filter = client.filterBy;
13990
- if (filter) {
13991
- if (filterGroups.has(filter)) {
13992
- filterGroups.get(filter).add(client);
13993
- } else {
13994
- const group = new FilterGroup(this, filter, indexes);
13995
- filterGroups.set(filter, group.add(client));
13996
- }
13997
- }
14363
+ connectSelection(this, client.filterBy, client);
13998
14364
  client.requestQuery();
13999
14365
  }
14000
14366
  /**
14001
14367
  * Disconnect a client from the coordinator.
14002
- *
14003
- * @param {import('./MosaicClient.js').MosaicClient} client the client to disconnect
14368
+ * @param {import('./MosaicClient.js').MosaicClient} client The Mosaic
14369
+ * client to disconnect.
14004
14370
  */
14005
14371
  disconnect(client) {
14006
14372
  const { clients, filterGroups } = this;
14007
14373
  if (!clients.has(client)) return;
14008
14374
  clients.delete(client);
14009
- filterGroups.get(client.filterBy)?.remove(client);
14010
14375
  client.coordinator = null;
14376
+ const group = filterGroups.get(client.filterBy);
14377
+ if (group) {
14378
+ group.clients.delete(client);
14379
+ }
14011
14380
  }
14012
14381
  };
14382
+ function connectSelection(mc, selection, client) {
14383
+ if (!selection) return;
14384
+ let entry = mc.filterGroups.get(selection);
14385
+ if (!entry) {
14386
+ const activate = (clause) => activateSelection(mc, selection, clause);
14387
+ const value = () => updateSelection(mc, selection);
14388
+ selection.addEventListener("activate", activate);
14389
+ selection.addEventListener("value", value);
14390
+ entry = {
14391
+ selection,
14392
+ clients: /* @__PURE__ */ new Set(),
14393
+ disconnect() {
14394
+ selection.removeEventListener("activate", activate);
14395
+ selection.removeEventListener("value", value);
14396
+ }
14397
+ };
14398
+ mc.filterGroups.set(selection, entry);
14399
+ }
14400
+ entry.clients.add(client);
14401
+ }
14402
+ function activateSelection(mc, selection, clause) {
14403
+ const { dataCubeIndexer, filterGroups } = mc;
14404
+ const { clients } = filterGroups.get(selection);
14405
+ for (const client of clients) {
14406
+ dataCubeIndexer.index(client, selection, clause);
14407
+ }
14408
+ }
14409
+ function updateSelection(mc, selection) {
14410
+ const { dataCubeIndexer, filterGroups } = mc;
14411
+ const { clients } = filterGroups.get(selection);
14412
+ const { active } = selection;
14413
+ return Promise.allSettled(Array.from(clients, (client) => {
14414
+ const info = dataCubeIndexer.index(client, selection, active);
14415
+ const filter = info ? null : selection.predicate(client);
14416
+ if (info?.skip || !info && !filter) return;
14417
+ const query = info?.query(active.predicate) ?? client.query(filter);
14418
+ return mc.updateClient(client, query);
14419
+ }));
14420
+ }
14013
14421
 
14014
14422
  // ../core/src/util/AsyncDispatch.js
14015
14423
  var AsyncDispatch = class {
@@ -14066,7 +14474,7 @@ var AsyncDispatch = class {
14066
14474
  * queue of unemitted event values prior to enqueueing a new value.
14067
14475
  * This default implementation simply returns null, indicating that
14068
14476
  * any other unemitted event values should be dropped (that is, all
14069
- * queued events are filtered)
14477
+ * queued events are filtered).
14070
14478
  * @param {string} type The event type.
14071
14479
  * @param {*} value The new event value that will be enqueued.
14072
14480
  * @returns {(value: *) => boolean|null} A dispatch queue filter
@@ -14083,6 +14491,16 @@ var AsyncDispatch = class {
14083
14491
  const entry = this._callbacks.get(type);
14084
14492
  entry?.queue.clear();
14085
14493
  }
14494
+ /**
14495
+ * Returns a promise that resolves when any pending updates complete for
14496
+ * the event of the given type currently being processed. The Promise will
14497
+ * resolve immediately if the queue for the given event type is empty.
14498
+ * @param {string} type The event type to wait for.
14499
+ * @returns {Promise} A pending event promise.
14500
+ */
14501
+ async pending(type) {
14502
+ await this._callbacks.get(type)?.pending;
14503
+ }
14086
14504
  /**
14087
14505
  * Emit an event value to listeners for the given event type.
14088
14506
  * If a previous emit has not yet resolved, the event value
@@ -14270,10 +14688,13 @@ var Selection = class _Selection extends Param {
14270
14688
  * @param {boolean} [options.cross=false] Boolean flag indicating
14271
14689
  * cross-filtered resolution. If true, selection clauses will not
14272
14690
  * be applied to the clients they are associated with.
14691
+ * @param {boolean} [options.empty=false] Boolean flag indicating if a lack
14692
+ * of clauses should correspond to an empty selection with no records. This
14693
+ * setting determines the default selection state.
14273
14694
  * @returns {Selection} The new Selection instance.
14274
14695
  */
14275
- static intersect({ cross = false } = {}) {
14276
- return new _Selection(new SelectionResolver({ cross }));
14696
+ static intersect({ cross = false, empty = false } = {}) {
14697
+ return new _Selection(new SelectionResolver({ cross, empty }));
14277
14698
  }
14278
14699
  /**
14279
14700
  * Create a new Selection instance with a
@@ -14282,10 +14703,13 @@ var Selection = class _Selection extends Param {
14282
14703
  * @param {boolean} [options.cross=false] Boolean flag indicating
14283
14704
  * cross-filtered resolution. If true, selection clauses will not
14284
14705
  * be applied to the clients they are associated with.
14706
+ * @param {boolean} [options.empty=false] Boolean flag indicating if a lack
14707
+ * of clauses should correspond to an empty selection with no records. This
14708
+ * setting determines the default selection state.
14285
14709
  * @returns {Selection} The new Selection instance.
14286
14710
  */
14287
- static union({ cross = false } = {}) {
14288
- return new _Selection(new SelectionResolver({ cross, union: true }));
14711
+ static union({ cross = false, empty = false } = {}) {
14712
+ return new _Selection(new SelectionResolver({ cross, empty, union: true }));
14289
14713
  }
14290
14714
  /**
14291
14715
  * Create a new Selection instance with a singular resolution strategy
@@ -14294,18 +14718,25 @@ var Selection = class _Selection extends Param {
14294
14718
  * @param {boolean} [options.cross=false] Boolean flag indicating
14295
14719
  * cross-filtered resolution. If true, selection clauses will not
14296
14720
  * be applied to the clients they are associated with.
14721
+ * @param {boolean} [options.empty=false] Boolean flag indicating if a lack
14722
+ * of clauses should correspond to an empty selection with no records. This
14723
+ * setting determines the default selection state.
14297
14724
  * @returns {Selection} The new Selection instance.
14298
14725
  */
14299
- static single({ cross = false } = {}) {
14300
- return new _Selection(new SelectionResolver({ cross, single: true }));
14726
+ static single({ cross = false, empty = false } = {}) {
14727
+ return new _Selection(new SelectionResolver({ cross, empty, single: true }));
14301
14728
  }
14302
14729
  /**
14303
14730
  * Create a new Selection instance with a
14304
14731
  * cross-filtered intersect resolution strategy.
14732
+ * @param {object} [options] The selection options.
14733
+ * @param {boolean} [options.empty=false] Boolean flag indicating if a lack
14734
+ * of clauses should correspond to an empty selection with no records. This
14735
+ * setting determines the default selection state.
14305
14736
  * @returns {Selection} The new Selection instance.
14306
14737
  */
14307
- static crossfilter() {
14308
- return new _Selection(new SelectionResolver({ cross: true }));
14738
+ static crossfilter({ empty = false } = {}) {
14739
+ return new _Selection(new SelectionResolver({ cross: true, empty }));
14309
14740
  }
14310
14741
  /**
14311
14742
  * Create a new Selection instance.
@@ -14338,6 +14769,24 @@ var Selection = class _Selection extends Param {
14338
14769
  s._value.active = { source };
14339
14770
  return s;
14340
14771
  }
14772
+ /**
14773
+ * The selection clause resolver.
14774
+ */
14775
+ get resolver() {
14776
+ return this._resolver;
14777
+ }
14778
+ /**
14779
+ * Indicate if this selection has a single resolution strategy.
14780
+ */
14781
+ get single() {
14782
+ return this._resolver.single;
14783
+ }
14784
+ /**
14785
+ * The current array of selection clauses.
14786
+ */
14787
+ get clauses() {
14788
+ return super.value;
14789
+ }
14341
14790
  /**
14342
14791
  * The current active (most recently updated) selection clause.
14343
14792
  */
@@ -14352,16 +14801,12 @@ var Selection = class _Selection extends Param {
14352
14801
  return this.active?.value;
14353
14802
  }
14354
14803
  /**
14355
- * The current array of selection clauses.
14356
- */
14357
- get clauses() {
14358
- return super.value;
14359
- }
14360
- /**
14361
- * Indicate if this selection has a single resolution strategy.
14804
+ * The value corresponding to a given source. Returns undefined if
14805
+ * this selection does not include a clause from this source.
14806
+ * @param {*} source The clause source to look up the value for.
14362
14807
  */
14363
- get single() {
14364
- return this._resolver.single;
14808
+ valueFor(source) {
14809
+ return this.clauses.find((c) => c.source === source)?.value;
14365
14810
  }
14366
14811
  /**
14367
14812
  * Emit an activate event with the given selection clause.
@@ -14439,11 +14884,15 @@ var SelectionResolver = class {
14439
14884
  * If false, an intersection strategy is used.
14440
14885
  * @param {boolean} [options.cross=false] Boolean flag to indicate cross-filtering.
14441
14886
  * @param {boolean} [options.single=false] Boolean flag to indicate single clauses only.
14887
+ * @param {boolean} [options.empty=false] Boolean flag indicating if a lack
14888
+ * of clauses should correspond to an empty selection with no records. This
14889
+ * setting determines the default selection state.
14442
14890
  */
14443
- constructor({ union, cross, single } = {}) {
14891
+ constructor({ union, cross, single, empty } = {}) {
14444
14892
  this.union = !!union;
14445
14893
  this.cross = !!cross;
14446
14894
  this.single = !!single;
14895
+ this.empty = !!empty;
14447
14896
  }
14448
14897
  /**
14449
14898
  * Resolve a list of selection clauses according to the resolution strategy.
@@ -14478,7 +14927,10 @@ var SelectionResolver = class {
14478
14927
  * based on the current state of this selection.
14479
14928
  */
14480
14929
  predicate(clauseList, active, client) {
14481
- const { union } = this;
14930
+ const { empty, union } = this;
14931
+ if (empty && !clauseList.length) {
14932
+ return ["FALSE"];
14933
+ }
14482
14934
  if (this.skip(client, active)) return void 0;
14483
14935
  const predicates = clauseList.filter((clause) => !this.skip(client, clause)).map((clause) => clause.predicate);
14484
14936
  return union && predicates.length > 1 ? or(predicates) : predicates;
@@ -14498,6 +14950,96 @@ var SelectionResolver = class {
14498
14950
  }
14499
14951
  };
14500
14952
 
14953
+ // ../core/src/SelectionClause.js
14954
+ function clausePoint(field, value, {
14955
+ source,
14956
+ clients = source ? /* @__PURE__ */ new Set([source]) : void 0
14957
+ }) {
14958
+ const predicate = value !== void 0 ? isNotDistinct(field, literal(value)) : null;
14959
+ return {
14960
+ meta: { type: "point" },
14961
+ source,
14962
+ clients,
14963
+ value,
14964
+ predicate
14965
+ };
14966
+ }
14967
+ function clausePoints(fields, value, {
14968
+ source,
14969
+ clients = source ? /* @__PURE__ */ new Set([source]) : void 0
14970
+ }) {
14971
+ let predicate = null;
14972
+ if (value) {
14973
+ const clauses = value.map((vals) => {
14974
+ const list = vals.map((v, i) => isNotDistinct(fields[i], literal(v)));
14975
+ return list.length > 1 ? and(list) : list[0];
14976
+ });
14977
+ predicate = clauses.length > 1 ? or(clauses) : clauses[0];
14978
+ }
14979
+ return {
14980
+ meta: { type: "point" },
14981
+ source,
14982
+ clients,
14983
+ value,
14984
+ predicate
14985
+ };
14986
+ }
14987
+ function clauseInterval(field, value, {
14988
+ source,
14989
+ clients = source ? /* @__PURE__ */ new Set([source]) : void 0,
14990
+ bin,
14991
+ scale,
14992
+ pixelSize = 1
14993
+ }) {
14994
+ const predicate = value != null ? isBetween(field, value) : null;
14995
+ const meta = { type: "interval", scales: scale && [scale], bin, pixelSize };
14996
+ return { meta, source, clients, value, predicate };
14997
+ }
14998
+ var MATCH_METHODS = { contains, prefix, suffix, regexp: regexp_matches };
14999
+ function clauseMatch(field, value, {
15000
+ source,
15001
+ clients = void 0,
15002
+ method = "contains"
15003
+ }) {
15004
+ let fn = MATCH_METHODS[method];
15005
+ const predicate = value ? fn(field, literal(value)) : null;
15006
+ const meta = { type: "match", method };
15007
+ return { meta, source, clients, value, predicate };
15008
+ }
15009
+
15010
+ // ../core/src/util/to-data-columns.js
15011
+ function toDataColumns(data) {
15012
+ return isArrowTable(data) ? arrowToColumns(data) : arrayToColumns(data);
15013
+ }
15014
+ function arrowToColumns(data) {
15015
+ const { numRows, numCols, schema: { fields } } = data;
15016
+ const columns = {};
15017
+ for (let col = 0; col < numCols; ++col) {
15018
+ const name = fields[col].name;
15019
+ if (columns[name]) {
15020
+ console.warn(`Redundant column name "${name}". Skipping...`);
15021
+ } else {
15022
+ columns[name] = convertArrowColumn(data.getChildAt(col));
15023
+ }
15024
+ }
15025
+ return { numRows, columns };
15026
+ }
15027
+ function arrayToColumns(data) {
15028
+ const numRows = data.length;
15029
+ if (typeof data[0] === "object") {
15030
+ const names = numRows ? Object.keys(data[0]) : [];
15031
+ const columns = {};
15032
+ if (names.length > 0) {
15033
+ names.forEach((name) => {
15034
+ columns[name] = data.map((d) => d[name]);
15035
+ });
15036
+ }
15037
+ return { numRows, columns };
15038
+ } else {
15039
+ return { numRows, values: data };
15040
+ }
15041
+ }
15042
+
14501
15043
  // src/input.js
14502
15044
  function input(InputClass, options) {
14503
15045
  const input2 = new InputClass(options);
@@ -14512,8 +15054,31 @@ var isObject2 = (v) => {
14512
15054
  var menu = (options) => input(Menu, options);
14513
15055
  var Menu = class extends MosaicClient {
14514
15056
  /**
14515
- * Create a new Menu instance.
14516
- * @param {object} options Options object
15057
+ * Create a new menu input.
15058
+ * @param {object} [options] Options object
15059
+ * @param {HTMLElement} [options.element] The parent DOM element in which to
15060
+ * place the menu elements. If undefined, a new `div` element is created.
15061
+ * @param {Selection} [options.filterBy] A selection to filter the database
15062
+ * table indicated by the *from* option.
15063
+ * @param {Param} [options.as] The output param or selection. A selection
15064
+ * clause is added for the currently selected menu option.
15065
+ * @param {string} [options.field] The database column name to use within
15066
+ * generated selection clause predicates. Defaults to the *column* option.
15067
+ * @param {(any | { value: any, label?: string })[]} [options.options] An
15068
+ * array of menu options, as literal values or option objects. Option
15069
+ * objects have a `value` property and an optional `label` property. If no
15070
+ * label or *format* function is provided, the string-coerced value is used.
15071
+ * @param {(value: any) => string} [options.format] A format function that
15072
+ * takes an option value as input and generates a string label. The format
15073
+ * function is not applied when an explicit label is provided in an option
15074
+ * object.
15075
+ * @param {*} [options.value] The initial selected menu value.
15076
+ * @param {string} [options.from] The name of a database table to use as a data
15077
+ * source for this widget. Used in conjunction with the *column* option.
15078
+ * @param {string} [options.column] The name of a database column from which
15079
+ * to pull menu options. The unique column values are used as menu options.
15080
+ * Used in conjunction with the *from* option.
15081
+ * @param {string} [options.label] A text label for this input.
14517
15082
  */
14518
15083
  constructor({
14519
15084
  element,
@@ -14525,32 +15090,37 @@ var Menu = class extends MosaicClient {
14525
15090
  // TODO
14526
15091
  options,
14527
15092
  value,
15093
+ field = column2,
14528
15094
  as
14529
15095
  } = {}) {
14530
15096
  super(filterBy);
14531
15097
  this.from = from;
14532
15098
  this.column = column2;
14533
- this.selection = as;
14534
15099
  this.format = format2;
15100
+ this.field = field;
15101
+ const selection = this.selection = as;
14535
15102
  this.element = element ?? document.createElement("div");
14536
15103
  this.element.setAttribute("class", "input");
14537
- this.element.value = this;
15104
+ Object.defineProperty(this.element, "value", { value: this });
14538
15105
  const lab = document.createElement("label");
14539
15106
  lab.innerText = label || column2;
14540
15107
  this.element.appendChild(lab);
14541
15108
  this.select = document.createElement("select");
15109
+ this.element.appendChild(this.select);
14542
15110
  if (options) {
14543
15111
  this.data = options.map((value2) => isObject2(value2) ? value2 : { value: value2 });
15112
+ this.selectedValue(value ?? "");
14544
15113
  this.update();
14545
15114
  }
14546
- value = value ?? this.selection?.value ?? this.data?.[0]?.value;
14547
- if (this.selection?.value === void 0) this.publish(value);
14548
- this.element.appendChild(this.select);
14549
- if (this.selection) {
15115
+ if (selection) {
15116
+ const isParam2 = !isSelection(selection);
15117
+ if (value != null && (!isParam2 || selection.value === void 0)) {
15118
+ this.publish(value);
15119
+ }
14550
15120
  this.select.addEventListener("input", () => {
14551
15121
  this.publish(this.selectedValue() ?? null);
14552
15122
  });
14553
- if (!isSelection(this.selection)) {
15123
+ if (isParam2) {
14554
15124
  this.selection.addEventListener("value", (value2) => {
14555
15125
  if (value2 !== this.select.value) {
14556
15126
  this.selectedValue(value2);
@@ -14576,14 +15146,11 @@ var Menu = class extends MosaicClient {
14576
15146
  this.select.selectedIndex = this.from ? 0 : -1;
14577
15147
  }
14578
15148
  publish(value) {
14579
- const { selection, column: column2 } = this;
15149
+ const { selection, field } = this;
14580
15150
  if (isSelection(selection)) {
14581
- selection.update({
14582
- source: this,
14583
- schema: { type: "point" },
14584
- value,
14585
- predicate: value !== "" && value !== void 0 ? eq(column2, literal(value)) : null
14586
- });
15151
+ if (value === "") value = void 0;
15152
+ const clause = clausePoint(field, value, { source: this });
15153
+ selection.update(clause);
14587
15154
  } else if (isParam(selection)) {
14588
15155
  selection.update(value);
14589
15156
  }
@@ -14598,7 +15165,7 @@ var Menu = class extends MosaicClient {
14598
15165
  return this;
14599
15166
  }
14600
15167
  update() {
14601
- const { data, format: format2, select } = this;
15168
+ const { data, format: format2, select, selection } = this;
14602
15169
  select.replaceChildren();
14603
15170
  for (const { value, label } of data) {
14604
15171
  const opt = document.createElement("option");
@@ -14606,21 +15173,42 @@ var Menu = class extends MosaicClient {
14606
15173
  opt.innerText = label ?? format2(value);
14607
15174
  this.select.appendChild(opt);
14608
15175
  }
14609
- if (this.selection) {
14610
- this.selectedValue(this.selection?.value ?? "");
15176
+ if (selection) {
15177
+ const value = isSelection(selection) ? selection.valueFor(this) : selection.value;
15178
+ this.selectedValue(value ?? "");
14611
15179
  }
14612
15180
  return this;
14613
15181
  }
14614
15182
  };
14615
15183
 
14616
15184
  // src/Search.js
14617
- var FUNCTIONS = { contains, prefix, suffix, regexp: regexp_matches };
14618
15185
  var _id = 0;
14619
15186
  var search = (options) => input(Search, options);
14620
15187
  var Search = class extends MosaicClient {
14621
15188
  /**
14622
- * Create a new Search instance.
14623
- * @param {object} options Options object
15189
+ * Create a new text search input.
15190
+ * @param {object} [options] Options object
15191
+ * @param {HTMLElement} [options.element] The parent DOM element in which to
15192
+ * place the search elements. If undefined, a new `div` element is created.
15193
+ * @param {Selection} [options.filterBy] A selection to filter the database
15194
+ * table indicated by the *from* option.
15195
+ * @param {Param} [options.as] The output param or selection. A selection
15196
+ * clause is added based on the current text search query.
15197
+ * @param {string} [options.field] The database column name to use within
15198
+ * generated selection clause predicates. Defaults to the *column* option.
15199
+ * @param {'contains' | 'prefix' | 'suffix' | 'regexp'} [options.type] The
15200
+ * type of text search query to perform. One of:
15201
+ * - `"contains"` (default): the query string may appear anywhere in the text
15202
+ * - `"prefix"`: the query string must appear at the start of the text
15203
+ * - `"suffix"`: the query string must appear at the end of the text
15204
+ * - `"regexp"`: the query string is a regular expression the text must match
15205
+ * @param {string} [options.from] The name of a database table to use as an
15206
+ * autocomplete data source for this widget. Used in conjunction with the
15207
+ * *column* option.
15208
+ * @param {string} [options.column] The name of a database column from which
15209
+ * to pull valid search results. The unique column values are used as search
15210
+ * autocomplete values. Used in conjunction with the *from* option.
15211
+ * @param {string} [options.label] A text label for this input.
14624
15212
  */
14625
15213
  constructor({
14626
15214
  element,
@@ -14629,6 +15217,7 @@ var Search = class extends MosaicClient {
14629
15217
  column: column2,
14630
15218
  label,
14631
15219
  type = "contains",
15220
+ field = column2,
14632
15221
  as
14633
15222
  } = {}) {
14634
15223
  super(filterBy);
@@ -14637,9 +15226,10 @@ var Search = class extends MosaicClient {
14637
15226
  this.from = from;
14638
15227
  this.column = column2;
14639
15228
  this.selection = as;
15229
+ this.field = field;
14640
15230
  this.element = element ?? document.createElement("div");
14641
15231
  this.element.setAttribute("class", "input");
14642
- this.element.value = this;
15232
+ Object.defineProperty(this.element, "value", { value: this });
14643
15233
  if (label) {
14644
15234
  const lab = document.createElement("label");
14645
15235
  lab.setAttribute("for", this.id);
@@ -14668,14 +15258,10 @@ var Search = class extends MosaicClient {
14668
15258
  this.searchbox.value = "";
14669
15259
  }
14670
15260
  publish(value) {
14671
- const { selection, column: column2, type } = this;
15261
+ const { selection, field, type } = this;
14672
15262
  if (isSelection(selection)) {
14673
- selection.update({
14674
- source: this,
14675
- schema: { type },
14676
- value,
14677
- predicate: value ? FUNCTIONS[type](column2, literal(value)) : null
14678
- });
15263
+ const clause = clauseMatch(field, value, { source: this, method: type });
15264
+ selection.update(clause);
14679
15265
  } else if (isParam(selection)) {
14680
15266
  selection.update(value);
14681
15267
  }
@@ -14710,8 +15296,34 @@ var _id2 = 0;
14710
15296
  var slider = (options) => input(Slider, options);
14711
15297
  var Slider = class extends MosaicClient {
14712
15298
  /**
14713
- * Create a new Slider instance.
14714
- * @param {object} options Options object
15299
+ * Create a new slider input.
15300
+ * @param {object} [options] Options object
15301
+ * @param {HTMLElement} [options.element] The parent DOM element in which to
15302
+ * place the slider elements. If undefined, a new `div` element is created.
15303
+ * @param {Selection} [options.filterBy] A selection to filter the database
15304
+ * table indicated by the *from* option.
15305
+ * @param {Param} [options.as] The output param or selection. A selection
15306
+ * clause is added based on the currently selected slider option.
15307
+ * @param {string} [options.field] The database column name to use within
15308
+ * generated selection clause predicates. Defaults to the *column* option.
15309
+ * @param {'point' | 'interval'} [options.select] The type of selection clause
15310
+ * predicate to generate if the **as** option is a Selection. If `'point'`
15311
+ * (the default), the selection predicate is an equality check for the slider
15312
+ * value. If `'interval'`, the predicate checks an interval from the minimum
15313
+ * to the current slider value.
15314
+ * @param {number} [options.min] The minimum slider value.
15315
+ * @param {number} [options.max] The maximum slider value.
15316
+ * @param {number} [options.step] The slider step, the amount to increment
15317
+ * between consecutive values.
15318
+ * @param {number} [options.value] The initial slider value.
15319
+ * @param {string} [options.from] The name of a database table to use as a data
15320
+ * source for this widget. Used in conjunction with the *column* option.
15321
+ * The minimum and maximum values of the column determine the slider range.
15322
+ * @param {string} [options.column] The name of a database column whose values
15323
+ * determine the slider range. Used in conjunction with the *from* option.
15324
+ * The minimum and maximum values of the column determine the slider range.
15325
+ * @param {string} [options.label] A text label for this input.
15326
+ * @param {number} [options.width] The width of the slider in screen pixels.
14715
15327
  */
14716
15328
  constructor({
14717
15329
  element,
@@ -14724,6 +15336,8 @@ var Slider = class extends MosaicClient {
14724
15336
  column: column2,
14725
15337
  label = column2,
14726
15338
  value = as?.value,
15339
+ select = "point",
15340
+ field = column2,
14727
15341
  width
14728
15342
  } = {}) {
14729
15343
  super(filterBy);
@@ -14731,41 +15345,49 @@ var Slider = class extends MosaicClient {
14731
15345
  this.from = from;
14732
15346
  this.column = column2 || "value";
14733
15347
  this.selection = as;
15348
+ this.selectionType = select;
15349
+ this.field = field;
14734
15350
  this.min = min2;
14735
15351
  this.max = max2;
14736
15352
  this.step = step;
14737
15353
  this.element = element || document.createElement("div");
14738
15354
  this.element.setAttribute("class", "input");
14739
- this.element.value = this;
15355
+ Object.defineProperty(this.element, "value", { value: this });
14740
15356
  if (label) {
14741
- const lab = document.createElement("label");
14742
- lab.setAttribute("for", this.id);
14743
- lab.innerText = label;
14744
- this.element.appendChild(lab);
15357
+ const desc2 = document.createElement("label");
15358
+ desc2.setAttribute("for", this.id);
15359
+ desc2.innerText = label;
15360
+ this.element.appendChild(desc2);
14745
15361
  }
14746
15362
  this.slider = document.createElement("input");
14747
15363
  this.slider.setAttribute("id", this.id);
14748
15364
  this.slider.setAttribute("type", "range");
14749
15365
  if (width != null) this.slider.style.width = `${+width}px`;
14750
- if (min2 != null) this.slider.setAttribute("min", min2);
14751
- if (max2 != null) this.slider.setAttribute("max", max2);
14752
- if (step != null) this.slider.setAttribute("step", step);
15366
+ if (min2 != null) this.slider.setAttribute("min", `${min2}`);
15367
+ if (max2 != null) this.slider.setAttribute("max", `${max2}`);
15368
+ if (step != null) this.slider.setAttribute("step", `${step}`);
15369
+ this.element.appendChild(this.slider);
15370
+ this.curval = document.createElement("label");
15371
+ this.curval.setAttribute("for", this.id);
15372
+ this.curval.setAttribute("class", "value");
15373
+ this.element.appendChild(this.curval);
14753
15374
  if (value != null) {
14754
- this.slider.setAttribute("value", value);
15375
+ this.slider.setAttribute("value", `${value}`);
14755
15376
  if (this.selection?.value === void 0) this.publish(value);
14756
15377
  }
14757
- this.element.appendChild(this.slider);
14758
- if (this.selection) {
14759
- this.slider.addEventListener("input", () => {
14760
- this.publish(+this.slider.value);
15378
+ this.curval.innerText = this.slider.value;
15379
+ this.slider.addEventListener("input", () => {
15380
+ const { value: value2 } = this.slider;
15381
+ this.curval.innerText = value2;
15382
+ if (this.selection) this.publish(+value2);
15383
+ });
15384
+ if (this.selection && !isSelection(this.selection)) {
15385
+ this.selection.addEventListener("value", (value2) => {
15386
+ if (value2 !== +this.slider.value) {
15387
+ this.slider.value = value2;
15388
+ this.curval.innerText = value2;
15389
+ }
14761
15390
  });
14762
- if (!isSelection(this.selection)) {
14763
- this.selection.addEventListener("value", (value2) => {
14764
- if (value2 !== +this.slider.value) {
14765
- this.slider.value = value2;
14766
- }
14767
- });
14768
- }
14769
15391
  }
14770
15392
  }
14771
15393
  query(filter = []) {
@@ -14775,20 +15397,34 @@ var Slider = class extends MosaicClient {
14775
15397
  }
14776
15398
  queryResult(data) {
14777
15399
  const { min: min2, max: max2 } = Array.from(data)[0];
14778
- if (this.min == null) this.slider.setAttribute("min", min2);
14779
- if (this.max == null) this.slider.setAttribute("max", max2);
14780
- if (this.step == null) this.slider.setAttribute("step", String((max2 - min2) / 500));
15400
+ if (this.min == null) {
15401
+ this.min = min2;
15402
+ this.slider.setAttribute("min", `${min2}`);
15403
+ }
15404
+ if (this.max == null) {
15405
+ this.max = max2;
15406
+ this.slider.setAttribute("max", `${max2}`);
15407
+ }
15408
+ if (this.step == null) {
15409
+ this.step = (max2 - min2) / 500;
15410
+ this.slider.setAttribute("step", `${this.step}`);
15411
+ }
14781
15412
  return this;
14782
15413
  }
14783
15414
  publish(value) {
14784
- const { selection, column: column2 } = this;
15415
+ const { field, selectionType, selection } = this;
14785
15416
  if (isSelection(selection)) {
14786
- selection.update({
14787
- source: this,
14788
- schema: { type: "point" },
14789
- value,
14790
- predicate: eq(column2, literal(value))
14791
- });
15417
+ if (selectionType === "interval") {
15418
+ const domain = [this.min ?? 0, value];
15419
+ selection.update(clauseInterval(field, domain, {
15420
+ source: this,
15421
+ bin: "ceil",
15422
+ scale: { type: "identity", domain },
15423
+ pixelSize: this.step
15424
+ }));
15425
+ } else {
15426
+ selection.update(clausePoint(field, value, { source: this }));
15427
+ }
14792
15428
  } else if (isParam(this.selection)) {
14793
15429
  selection.update(value);
14794
15430
  }
@@ -14849,7 +15485,8 @@ var Table2 = class extends MosaicClient {
14849
15485
  width,
14850
15486
  maxWidth,
14851
15487
  height = 500,
14852
- rowBatch = 100
15488
+ rowBatch = 100,
15489
+ as
14853
15490
  } = {}) {
14854
15491
  super(filterBy);
14855
15492
  this.id = `table-${++_id3}`;
@@ -14861,12 +15498,14 @@ var Table2 = class extends MosaicClient {
14861
15498
  this.offset = 0;
14862
15499
  this.limit = +rowBatch;
14863
15500
  this.pending = false;
15501
+ this.selection = as;
15502
+ this.currentRow = -1;
14864
15503
  this.sortHeader = null;
14865
15504
  this.sortColumn = null;
14866
15505
  this.sortDesc = false;
14867
15506
  this.element = element || document.createElement("div");
14868
15507
  this.element.setAttribute("id", this.id);
14869
- this.element.value = this;
15508
+ Object.defineProperty(this.element, "value", { value: this });
14870
15509
  if (typeof width === "number") this.element.style.width = `${width}px`;
14871
15510
  if (maxWidth) this.element.style.maxWidth = `${maxWidth}px`;
14872
15511
  this.element.style.maxHeight = `${height}px`;
@@ -14889,9 +15528,31 @@ var Table2 = class extends MosaicClient {
14889
15528
  this.tbl.appendChild(this.head);
14890
15529
  this.body = document.createElement("tbody");
14891
15530
  this.tbl.appendChild(this.body);
15531
+ if (this.selection) {
15532
+ this.body.addEventListener("pointerover", (evt) => {
15533
+ const row = resolveRow(evt.target);
15534
+ if (row > -1 && row !== this.currentRow) {
15535
+ this.currentRow = row;
15536
+ this.selection.update(this.clause([row]));
15537
+ }
15538
+ });
15539
+ this.body.addEventListener("pointerleave", () => {
15540
+ this.currentRow = -1;
15541
+ this.selection.update(this.clause());
15542
+ });
15543
+ }
14892
15544
  this.style = document.createElement("style");
14893
15545
  this.element.appendChild(this.style);
14894
15546
  }
15547
+ clause(rows = []) {
15548
+ const { data, limit, schema } = this;
15549
+ const fields = schema.map((s) => s.column);
15550
+ const values = rows.map((row) => {
15551
+ const { columns } = data[~~(row / limit)];
15552
+ return fields.map((f) => columns[f][row % limit]);
15553
+ });
15554
+ return clausePoints(fields, values, { source: this });
15555
+ }
14895
15556
  requestData(offset = 0) {
14896
15557
  this.offset = offset;
14897
15558
  const query = this.query(this.filterBy?.predicate(this));
@@ -14929,27 +15590,32 @@ var Table2 = class extends MosaicClient {
14929
15590
  queryResult(data) {
14930
15591
  if (!this.pending) {
14931
15592
  this.loaded = false;
15593
+ this.data = [];
14932
15594
  this.body.replaceChildren();
15595
+ this.offset = 0;
14933
15596
  }
14934
- this.data = data;
15597
+ this.data.push(toDataColumns(data));
14935
15598
  return this;
14936
15599
  }
14937
15600
  update() {
14938
15601
  const { body, formats, data, schema, limit } = this;
14939
15602
  const nf = schema.length;
14940
- let count2 = 0;
14941
- for (const row of data) {
14942
- ++count2;
15603
+ const n = data.length - 1;
15604
+ const rowCount = limit * n;
15605
+ const { numRows, columns } = data[n];
15606
+ const cols = schema.map((s) => columns[s.column]);
15607
+ for (let i = 0; i < numRows; ++i) {
14943
15608
  const tr = document.createElement("tr");
14944
- for (let i = 0; i < nf; ++i) {
14945
- const value = row[schema[i].column];
15609
+ Object.assign(tr, { __row__: rowCount + i });
15610
+ for (let j = 0; j < nf; ++j) {
15611
+ const value = cols[j][i];
14946
15612
  const td = document.createElement("td");
14947
- td.innerText = value == null ? "" : formats[i](value);
15613
+ td.innerText = value == null ? "" : formats[j](value);
14948
15614
  tr.appendChild(td);
14949
15615
  }
14950
15616
  body.appendChild(tr);
14951
15617
  }
14952
- if (count2 < limit) {
15618
+ if (numRows < limit) {
14953
15619
  this.loaded = true;
14954
15620
  }
14955
15621
  this.pending = false;
@@ -14976,6 +15642,10 @@ var Table2 = class extends MosaicClient {
14976
15642
  this.requestData();
14977
15643
  }
14978
15644
  };
15645
+ function resolveRow(element) {
15646
+ const p = element.parentElement;
15647
+ return Object.hasOwn(p, "__row__") ? +p.__row__ : -1;
15648
+ }
14979
15649
  function formatof(base = {}, schema, locale) {
14980
15650
  return schema.map(({ column: column2, type }) => {
14981
15651
  if (column2 in base) {