@uwdata/mosaic-inputs 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -26,3 +26,22 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
26
  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
27
  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
28
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ ---
31
+
32
+ Portions of this software are derived from Observable Plot, which is released
33
+ under the ISC license.
34
+
35
+ Copyright 2020-2023 Observable, Inc.
36
+
37
+ Permission to use, copy, modify, and/or distribute this software for any purpose
38
+ with or without fee is hereby granted, provided that the above copyright notice
39
+ and this permission notice appear in all copies.
40
+
41
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
42
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
43
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
44
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
45
+ OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
46
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
47
+ THIS SOFTWARE.
@@ -12365,6 +12365,15 @@ var Query = class _Query {
12365
12365
  static except(...queries) {
12366
12366
  return new SetOperation("EXCEPT", queries.flat());
12367
12367
  }
12368
+ static describe(query) {
12369
+ const q = query.clone();
12370
+ const { clone, toString } = q;
12371
+ return Object.assign(q, {
12372
+ describe: true,
12373
+ clone: () => _Query.describe(clone.call(q)),
12374
+ toString: () => `DESCRIBE ${toString.call(q)}`
12375
+ });
12376
+ }
12368
12377
  constructor() {
12369
12378
  this.query = {
12370
12379
  with: [],
@@ -12599,6 +12608,7 @@ var Query = class _Query {
12599
12608
  }
12600
12609
  toString() {
12601
12610
  const {
12611
+ with: cte,
12602
12612
  select,
12603
12613
  distinct: distinct2,
12604
12614
  from,
@@ -12610,8 +12620,7 @@ var Query = class _Query {
12610
12620
  qualify,
12611
12621
  orderby,
12612
12622
  limit,
12613
- offset,
12614
- with: cte
12623
+ offset
12615
12624
  } = this.query;
12616
12625
  const sql2 = [];
12617
12626
  if (cte.length) {
@@ -12733,6 +12742,9 @@ var SetOperation = class _SetOperation {
12733
12742
  function isQuery(value) {
12734
12743
  return value instanceof Query || value instanceof SetOperation;
12735
12744
  }
12745
+ function isDescribeQuery(value) {
12746
+ return isQuery(value) && value.describe;
12747
+ }
12736
12748
  function unquote(s) {
12737
12749
  return isDoubleQuoted(s) ? s.slice(1, -1) : s;
12738
12750
  }
@@ -12832,131 +12844,6 @@ function create(name, query, {
12832
12844
  return "CREATE" + (replace ? " OR REPLACE " : " ") + (temp ? "TEMP " : "") + (view ? "VIEW" : "TABLE") + (replace ? " " : " IF NOT EXISTS ") + name + " AS " + query;
12833
12845
  }
12834
12846
 
12835
- // ../core/src/util/js-type.js
12836
- function jsType(type) {
12837
- switch (type) {
12838
- case "BIGINT":
12839
- case "HUGEINT":
12840
- case "INTEGER":
12841
- case "SMALLINT":
12842
- case "TINYINT":
12843
- case "UBIGINT":
12844
- case "UINTEGER":
12845
- case "USMALLINT":
12846
- case "UTINYINT":
12847
- case "DOUBLE":
12848
- case "FLOAT":
12849
- case "REAL":
12850
- case "DECIMAL":
12851
- return "number";
12852
- case "DATE":
12853
- case "TIMESTAMP":
12854
- case "TIMESTAMPTZ":
12855
- case "TIMESTAMP WITH TIME ZONE":
12856
- case "TIME":
12857
- case "TIMESTAMP_NS":
12858
- return "date";
12859
- case "BOOLEAN":
12860
- return "boolean";
12861
- case "VARCHAR":
12862
- case "UUID":
12863
- return "string";
12864
- case "LIST":
12865
- return "array";
12866
- case "BLOB":
12867
- case "STRUCT":
12868
- case "MAP":
12869
- return "object";
12870
- default:
12871
- throw new Error(`Unsupported type: ${type}`);
12872
- }
12873
- }
12874
-
12875
- // ../core/src/util/summarize.js
12876
- var Count = "count";
12877
- var Nulls = "nulls";
12878
- var Max = "max";
12879
- var Min = "min";
12880
- var Distinct = "distinct";
12881
- var statMap = {
12882
- [Count]: count,
12883
- [Distinct]: (column2) => count(column2).distinct(),
12884
- [Max]: max,
12885
- [Min]: min,
12886
- [Nulls]: (column2) => count().where(isNull(column2))
12887
- };
12888
- function summarize({ table: table2, column: column2 }, stats) {
12889
- return Query.from(table2).select(stats.map((s) => [s, statMap[s](column2)]));
12890
- }
12891
-
12892
- // ../core/src/Catalog.js
12893
- var object = () => /* @__PURE__ */ Object.create(null);
12894
- var Catalog = class {
12895
- constructor(coordinator2) {
12896
- this.mc = coordinator2;
12897
- this.clear();
12898
- }
12899
- clear() {
12900
- this.tables = object();
12901
- }
12902
- tableInfo(table2) {
12903
- const cache = this.tables;
12904
- if (cache[table2]) {
12905
- return cache[table2];
12906
- }
12907
- const infoPromise = getTableInfo(this.mc, table2).catch((err) => {
12908
- cache[table2] = null;
12909
- throw err;
12910
- });
12911
- return cache[table2] = infoPromise;
12912
- }
12913
- async fieldInfo({ table: table2, column: column2, stats }) {
12914
- const tableInfo = await this.tableInfo(table2);
12915
- const colInfo = tableInfo[column2];
12916
- if (colInfo == null)
12917
- return;
12918
- if (!stats?.length)
12919
- return colInfo;
12920
- const result = await this.mc.query(
12921
- summarize(colInfo, stats),
12922
- { persist: true }
12923
- );
12924
- const info = { ...colInfo, ...Array.from(result)[0] };
12925
- for (const key in info) {
12926
- const value = info[key];
12927
- if (typeof value === "bigint") {
12928
- info[key] = Number(value);
12929
- }
12930
- }
12931
- return info;
12932
- }
12933
- async queryFields(fields) {
12934
- const list = await resolveFields(this, fields);
12935
- const data = await Promise.all(list.map((f) => this.fieldInfo(f)));
12936
- return data.filter((x2) => x2);
12937
- }
12938
- };
12939
- async function getTableInfo(mc, table2) {
12940
- const result = await mc.query(
12941
- `DESCRIBE ${asRelation(table2)}`,
12942
- { type: "json", cache: false }
12943
- );
12944
- const columns = object();
12945
- for (const entry of result) {
12946
- columns[entry.column_name] = {
12947
- table: table2,
12948
- column: entry.column_name,
12949
- sqlType: entry.column_type,
12950
- type: jsType(entry.column_type),
12951
- nullable: entry.null === "YES"
12952
- };
12953
- }
12954
- return columns;
12955
- }
12956
- async function resolveFields(catalog, list) {
12957
- return list.length === 1 && list[0].column === "*" ? Object.values(await catalog.tableInfo(list[0].table)) : list;
12958
- }
12959
-
12960
12847
  // ../core/src/util/hash.js
12961
12848
  function fnv_hash(v) {
12962
12849
  let a = 2166136261;
@@ -13316,7 +13203,7 @@ function consolidate(group, enqueue, record) {
13316
13203
  type: "arrow",
13317
13204
  cache: false,
13318
13205
  record: false,
13319
- query: consolidatedQuery(group, record)
13206
+ query: group.query = consolidatedQuery(group, record)
13320
13207
  },
13321
13208
  result: group.result = queryResult()
13322
13209
  });
@@ -13364,7 +13251,7 @@ function consolidatedQuery(group, record) {
13364
13251
  return query.$select(Array.from(fields.values()));
13365
13252
  }
13366
13253
  async function processResults(group, cache) {
13367
- const { maps, result } = group;
13254
+ const { maps, query, result } = group;
13368
13255
  if (!maps)
13369
13256
  return;
13370
13257
  let data;
@@ -13376,25 +13263,33 @@ async function processResults(group, cache) {
13376
13263
  }
13377
13264
  return;
13378
13265
  }
13266
+ const describe = isDescribeQuery(query);
13379
13267
  group.forEach(({ entry }, index) => {
13380
13268
  const { request, result: result2 } = entry;
13381
- const projected = projectResult(data, maps[index]);
13269
+ const map = maps[index];
13270
+ const extract = describe && map ? filterResult(data, map) : map ? projectResult(data, map) : data;
13382
13271
  if (request.cache) {
13383
- cache.set(String(request.query), projected);
13272
+ cache.set(String(request.query), extract);
13384
13273
  }
13385
- result2.fulfill(projected);
13274
+ result2.fulfill(extract);
13386
13275
  });
13387
13276
  }
13388
13277
  function projectResult(data, map) {
13389
- if (map) {
13390
- const cols = {};
13391
- for (const [name, as] of map) {
13392
- cols[as] = data.getChild(name);
13278
+ const cols = {};
13279
+ for (const [name, as] of map) {
13280
+ cols[as] = data.getChild(name);
13281
+ }
13282
+ return new data.constructor(cols);
13283
+ }
13284
+ function filterResult(data, map) {
13285
+ const lookup = new Map(map);
13286
+ const result = [];
13287
+ for (const d of data) {
13288
+ if (lookup.has(d.column_name)) {
13289
+ result.push({ ...d, column_name: lookup.get(d.column_name) });
13393
13290
  }
13394
- return new data.constructor(cols);
13395
- } else {
13396
- return data;
13397
13291
  }
13292
+ return result;
13398
13293
  }
13399
13294
 
13400
13295
  // ../core/src/util/cache.js
@@ -13641,6 +13536,150 @@ function QueryManager() {
13641
13536
  };
13642
13537
  }
13643
13538
 
13539
+ // ../core/src/util/js-type.js
13540
+ function jsType(type) {
13541
+ switch (type) {
13542
+ case "BIGINT":
13543
+ case "HUGEINT":
13544
+ case "INTEGER":
13545
+ case "SMALLINT":
13546
+ case "TINYINT":
13547
+ case "UBIGINT":
13548
+ case "UINTEGER":
13549
+ case "USMALLINT":
13550
+ case "UTINYINT":
13551
+ case "DOUBLE":
13552
+ case "FLOAT":
13553
+ case "REAL":
13554
+ return "number";
13555
+ case "DATE":
13556
+ case "TIMESTAMP":
13557
+ case "TIMESTAMPTZ":
13558
+ case "TIMESTAMP WITH TIME ZONE":
13559
+ case "TIME":
13560
+ case "TIMESTAMP_NS":
13561
+ return "date";
13562
+ case "BOOLEAN":
13563
+ return "boolean";
13564
+ case "VARCHAR":
13565
+ case "UUID":
13566
+ return "string";
13567
+ case "ARRAY":
13568
+ case "LIST":
13569
+ return "array";
13570
+ case "BLOB":
13571
+ case "STRUCT":
13572
+ case "MAP":
13573
+ case "GEOMETRY":
13574
+ return "object";
13575
+ default:
13576
+ if (type.startsWith("DECIMAL")) {
13577
+ return "number";
13578
+ } else if (type.startsWith("STRUCT") || type.startsWith("MAP")) {
13579
+ return "object";
13580
+ } else if (type.endsWith("]")) {
13581
+ return "array";
13582
+ }
13583
+ throw new Error(`Unsupported type: ${type}`);
13584
+ }
13585
+ }
13586
+
13587
+ // ../core/src/util/convert-arrow.js
13588
+ var INTEGER = 2;
13589
+ var DECIMAL = 7;
13590
+ var TIMESTAMP = 10;
13591
+ function convertArrowValue(type) {
13592
+ const { typeId } = type;
13593
+ if (typeId === TIMESTAMP) {
13594
+ return (v) => v == null ? v : new Date(v);
13595
+ }
13596
+ if (typeId === INTEGER && type.bitWidth >= 64) {
13597
+ return (v) => v == null ? v : Number(v);
13598
+ }
13599
+ if (typeId === DECIMAL) {
13600
+ const scale = 1 / Math.pow(10, type.scale);
13601
+ return (v) => v == null ? v : decimalToNumber(v, scale);
13602
+ }
13603
+ return (v) => v;
13604
+ }
13605
+ var BASE32 = Array.from(
13606
+ { length: 8 },
13607
+ (_, i) => Math.pow(2, i * 32)
13608
+ );
13609
+ function decimalToNumber(v, scale) {
13610
+ const n = v.length;
13611
+ let x2 = 0;
13612
+ if (v.signed && (v[n - 1] | 0) < 0) {
13613
+ for (let i = 0; i < n; ++i) {
13614
+ x2 += ~(v[i] | 0) * BASE32[i];
13615
+ }
13616
+ x2 = -(x2 + 1);
13617
+ } else {
13618
+ for (let i = 0; i < n; ++i) {
13619
+ x2 += v[i] * BASE32[i];
13620
+ }
13621
+ }
13622
+ return x2 * scale;
13623
+ }
13624
+
13625
+ // ../core/src/util/field-info.js
13626
+ var Count = "count";
13627
+ var Nulls = "nulls";
13628
+ var Max = "max";
13629
+ var Min = "min";
13630
+ var Distinct = "distinct";
13631
+ var statMap = {
13632
+ [Count]: count,
13633
+ [Distinct]: (column2) => count(column2).distinct(),
13634
+ [Max]: max,
13635
+ [Min]: min,
13636
+ [Nulls]: (column2) => count().where(isNull(column2))
13637
+ };
13638
+ function summarize(table2, column2, stats) {
13639
+ return Query.from(table2).select(Array.from(stats, (s) => [s, statMap[s](column2)]));
13640
+ }
13641
+ async function queryFieldInfo(mc, fields) {
13642
+ if (fields.length === 1 && `${fields[0].column}` === "*") {
13643
+ return getTableInfo(mc, fields[0].table);
13644
+ } else {
13645
+ return (await Promise.all(fields.map((f) => getFieldInfo(mc, f)))).filter((x2) => x2);
13646
+ }
13647
+ }
13648
+ async function getFieldInfo(mc, { table: table2, column: column2, stats }) {
13649
+ const q = Query.from({ source: table2 }).select({ column: column2 }).groupby(column2.aggregate ? sql`ALL` : []);
13650
+ const [desc2] = Array.from(await mc.query(Query.describe(q)));
13651
+ const info = {
13652
+ table: table2,
13653
+ column: `${column2}`,
13654
+ sqlType: desc2.column_type,
13655
+ type: jsType(desc2.column_type),
13656
+ nullable: desc2.null === "YES"
13657
+ };
13658
+ if (!(stats?.length || stats?.size))
13659
+ return info;
13660
+ const result = await mc.query(
13661
+ summarize(table2, column2, stats),
13662
+ { persist: true }
13663
+ );
13664
+ for (let i = 0; i < result.numCols; ++i) {
13665
+ const { name } = result.schema.fields[i];
13666
+ const child = result.getChildAt(i);
13667
+ const convert = convertArrowValue(child.type);
13668
+ info[name] = convert(child.get(0));
13669
+ }
13670
+ return info;
13671
+ }
13672
+ async function getTableInfo(mc, table2) {
13673
+ const result = await mc.query(`DESCRIBE ${asRelation(table2)}`);
13674
+ return Array.from(result).map((desc2) => ({
13675
+ table: table2,
13676
+ column: desc2.column_name,
13677
+ sqlType: desc2.column_type,
13678
+ type: jsType(desc2.column_type),
13679
+ nullable: desc2.null === "YES"
13680
+ }));
13681
+ }
13682
+
13644
13683
  // ../core/src/util/void-logger.js
13645
13684
  function voidLogger() {
13646
13685
  return {
@@ -13673,7 +13712,6 @@ var Coordinator = class {
13673
13712
  logger = console,
13674
13713
  manager = QueryManager()
13675
13714
  } = options;
13676
- this.catalog = new Catalog(this);
13677
13715
  this.manager = manager;
13678
13716
  this.logger(logger);
13679
13717
  this.configure(options);
@@ -13692,7 +13730,7 @@ var Coordinator = class {
13692
13730
  this.manager.consolidate(consolidate2);
13693
13731
  this.indexes = indexes;
13694
13732
  }
13695
- clear({ clients = true, cache = true, catalog = false } = {}) {
13733
+ clear({ clients = true, cache = true } = {}) {
13696
13734
  this.manager.clear();
13697
13735
  if (clients) {
13698
13736
  this.clients?.forEach((client) => this.disconnect(client));
@@ -13702,8 +13740,6 @@ var Coordinator = class {
13702
13740
  }
13703
13741
  if (cache)
13704
13742
  this.manager.cache().clear();
13705
- if (catalog)
13706
- this.catalog.clear();
13707
13743
  }
13708
13744
  databaseConnector(db) {
13709
13745
  return this.manager.connector(db);
@@ -13756,7 +13792,7 @@ var Coordinator = class {
13756
13792
  * @param {import('./MosaicClient.js').MosaicClient} client the client to disconnect
13757
13793
  */
13758
13794
  async connect(client) {
13759
- const { catalog, clients, filterGroups, indexes } = this;
13795
+ const { clients, filterGroups, indexes } = this;
13760
13796
  if (clients.has(client)) {
13761
13797
  throw new Error("Client already connected.");
13762
13798
  }
@@ -13764,7 +13800,7 @@ var Coordinator = class {
13764
13800
  client.coordinator = this;
13765
13801
  const fields = client.fields();
13766
13802
  if (fields?.length) {
13767
- client.fieldInfo(await catalog.queryFields(fields));
13803
+ client.fieldInfo(await queryFieldInfo(this, fields));
13768
13804
  }
13769
13805
  const filter = client.filterBy;
13770
13806
  if (filter) {