@sqlrooms/deck 0.29.0-rc.10 → 0.29.0-rc.11

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.
Files changed (118) hide show
  1. package/README.md +42 -6
  2. package/dist/DeckJsonMap.d.ts.map +1 -1
  3. package/dist/DeckJsonMap.js +2 -6
  4. package/dist/DeckJsonMap.js.map +1 -1
  5. package/dist/DeckJsonMapSpec.d.ts +875 -53
  6. package/dist/DeckJsonMapSpec.d.ts.map +1 -1
  7. package/dist/DeckJsonMapSpec.js +7 -0
  8. package/dist/DeckJsonMapSpec.js.map +1 -1
  9. package/dist/DeckMapDefaultStylesProvider.d.ts +3 -4
  10. package/dist/DeckMapDefaultStylesProvider.d.ts.map +1 -1
  11. package/dist/DeckMapDefaultStylesProvider.js +13 -7
  12. package/dist/DeckMapDefaultStylesProvider.js.map +1 -1
  13. package/dist/MapSettings.d.ts.map +1 -1
  14. package/dist/MapSettings.js +25 -11
  15. package/dist/MapSettings.js.map +1 -1
  16. package/dist/ai.d.ts +19 -5
  17. package/dist/ai.d.ts.map +1 -1
  18. package/dist/ai.js +60 -112
  19. package/dist/ai.js.map +1 -1
  20. package/dist/aiNormalize.d.ts +31 -0
  21. package/dist/aiNormalize.d.ts.map +1 -0
  22. package/dist/aiNormalize.js +629 -0
  23. package/dist/aiNormalize.js.map +1 -0
  24. package/dist/dashboard.d.ts.map +1 -1
  25. package/dist/dashboard.js +72 -8
  26. package/dist/dashboard.js.map +1 -1
  27. package/dist/dashboardConfig.d.ts +10 -1
  28. package/dist/dashboardConfig.d.ts.map +1 -1
  29. package/dist/dashboardConfig.js +55 -22
  30. package/dist/dashboardConfig.js.map +1 -1
  31. package/dist/datasets/PreparedDatasetStore.d.ts.map +1 -1
  32. package/dist/datasets/PreparedDatasetStore.js +31 -2
  33. package/dist/datasets/PreparedDatasetStore.js.map +1 -1
  34. package/dist/datasets/wrapGeometryAsWkb.d.ts +20 -0
  35. package/dist/datasets/wrapGeometryAsWkb.d.ts.map +1 -0
  36. package/dist/datasets/wrapGeometryAsWkb.js +65 -0
  37. package/dist/datasets/wrapGeometryAsWkb.js.map +1 -0
  38. package/dist/index.d.ts +1 -0
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +1 -0
  41. package/dist/index.js.map +1 -1
  42. package/dist/json/compileGeoArrowAccessor.d.ts +5 -0
  43. package/dist/json/compileGeoArrowAccessor.d.ts.map +1 -1
  44. package/dist/json/compileGeoArrowAccessor.js +17 -3
  45. package/dist/json/compileGeoArrowAccessor.js.map +1 -1
  46. package/dist/json/createDeckJsonConfiguration.d.ts.map +1 -1
  47. package/dist/json/createDeckJsonConfiguration.js +85 -18
  48. package/dist/json/createDeckJsonConfiguration.js.map +1 -1
  49. package/dist/json/extractColorScaleLegends.d.ts.map +1 -1
  50. package/dist/json/extractColorScaleLegends.js +21 -7
  51. package/dist/json/extractColorScaleLegends.js.map +1 -1
  52. package/dist/json/layers/DeckH3HexagonLayer.d.ts.map +1 -1
  53. package/dist/json/layers/DeckH3HexagonLayer.js +9 -14
  54. package/dist/json/layers/DeckH3HexagonLayer.js.map +1 -1
  55. package/dist/json/layers/h3IndexFormat.d.ts +6 -0
  56. package/dist/json/layers/h3IndexFormat.d.ts.map +1 -0
  57. package/dist/json/layers/h3IndexFormat.js +17 -0
  58. package/dist/json/layers/h3IndexFormat.js.map +1 -0
  59. package/dist/json/layers/index.d.ts +1 -0
  60. package/dist/json/layers/index.d.ts.map +1 -1
  61. package/dist/json/layers/index.js +1 -0
  62. package/dist/json/layers/index.js.map +1 -1
  63. package/dist/json/rewriteGeoArrowAccessors.d.ts.map +1 -1
  64. package/dist/json/rewriteGeoArrowAccessors.js +9 -0
  65. package/dist/json/rewriteGeoArrowAccessors.js.map +1 -1
  66. package/dist/json/scaleFunction.d.ts +30 -0
  67. package/dist/json/scaleFunction.d.ts.map +1 -0
  68. package/dist/json/scaleFunction.js +126 -0
  69. package/dist/json/scaleFunction.js.map +1 -0
  70. package/dist/mapAiConfig.d.ts +2 -0
  71. package/dist/mapAiConfig.d.ts.map +1 -1
  72. package/dist/mapAiConfig.js +2 -1
  73. package/dist/mapAiConfig.js.map +1 -1
  74. package/dist/mapAiSharedInstructions.d.ts +3 -0
  75. package/dist/mapAiSharedInstructions.d.ts.map +1 -0
  76. package/dist/mapAiSharedInstructions.js +16 -0
  77. package/dist/mapAiSharedInstructions.js.map +1 -0
  78. package/dist/mapConfig.d.ts +6 -0
  79. package/dist/mapConfig.d.ts.map +1 -1
  80. package/dist/mapConfig.js.map +1 -1
  81. package/dist/mapConfigUtils.d.ts.map +1 -1
  82. package/dist/mapConfigUtils.js +2 -0
  83. package/dist/mapConfigUtils.js.map +1 -1
  84. package/dist/mapFit.d.ts +16 -0
  85. package/dist/mapFit.d.ts.map +1 -1
  86. package/dist/mapFit.js +208 -30
  87. package/dist/mapFit.js.map +1 -1
  88. package/dist/mapLayerConfigUtils.d.ts +9 -1
  89. package/dist/mapLayerConfigUtils.d.ts.map +1 -1
  90. package/dist/mapLayerConfigUtils.js +62 -12
  91. package/dist/mapLayerConfigUtils.js.map +1 -1
  92. package/dist/mapResourceAuthoring.d.ts +2 -0
  93. package/dist/mapResourceAuthoring.d.ts.map +1 -1
  94. package/dist/mapResourceAuthoring.js +402 -16
  95. package/dist/mapResourceAuthoring.js.map +1 -1
  96. package/dist/mosaic.d.ts +1 -1
  97. package/dist/mosaic.d.ts.map +1 -1
  98. package/dist/mosaic.js.map +1 -1
  99. package/dist/prepare/geoarrow.js.map +1 -1
  100. package/dist/prepare/wkbDecoder.d.ts +10 -0
  101. package/dist/prepare/wkbDecoder.d.ts.map +1 -1
  102. package/dist/prepare/wkbDecoder.js +93 -18
  103. package/dist/prepare/wkbDecoder.js.map +1 -1
  104. package/dist/prepare/wkbParser.d.ts +7 -0
  105. package/dist/prepare/wkbParser.d.ts.map +1 -1
  106. package/dist/prepare/wkbParser.js +21 -0
  107. package/dist/prepare/wkbParser.js.map +1 -1
  108. package/dist/selectStarAsWkbCollision.d.ts +3 -0
  109. package/dist/selectStarAsWkbCollision.d.ts.map +1 -0
  110. package/dist/selectStarAsWkbCollision.js +78 -0
  111. package/dist/selectStarAsWkbCollision.js.map +1 -0
  112. package/dist/types.d.ts +1 -1
  113. package/dist/types.d.ts.map +1 -1
  114. package/dist/types.js.map +1 -1
  115. package/dist/useDeckMapFitToBounds.d.ts.map +1 -1
  116. package/dist/useDeckMapFitToBounds.js +1 -1
  117. package/dist/useDeckMapFitToBounds.js.map +1 -1
  118. package/package.json +15 -15
@@ -1 +1 @@
1
- {"version":3,"file":"mapFit.d.ts","sourceRoot":"","sources":["../src/mapFit.ts"],"names":[],"mappings":"AAOA,OAAO,EAA+B,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAKnE,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC5B,MAAM,aAAa,CAAC;AACrB,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACvB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GACvC,sBAAsB,GAAG,IAAI,CAqC/B;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,gBAAgB,GAAG,SAAS,GACpC,oBAAoB,GAAG,IAAI,CAU7B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAChD,MAAM,EAAE,oBAAoB,CAAC;IAC7B,SAAS,EAAE,sBAAsB,CAAC;CACnC,iBA0EA;AAmFD;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACzC,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACpC,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAChD,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC,QA6HA"}
1
+ {"version":3,"file":"mapFit.d.ts","sourceRoot":"","sources":["../src/mapFit.ts"],"names":[],"mappings":"AAOA,OAAO,EAAuC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAK3E,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC5B,MAAM,aAAa,CAAC;AACrB,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACvB,MAAM,SAAS,CAAC;AA4BjB;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GACvC,sBAAsB,GAAG,IAAI,CA4F/B;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,gBAAgB,GAAG,SAAS,GACpC,oBAAoB,GAAG,IAAI,CAU7B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAChD,MAAM,EAAE,oBAAoB,CAAC;IAC7B,SAAS,EAAE,sBAAsB,CAAC;CACnC,iBAgHA;AAqED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG;IACF,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAaA;AAoBD;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACzC,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACpC,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAChD,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC,QAmLA"}
package/dist/mapFit.js CHANGED
@@ -1,9 +1,36 @@
1
1
  import { WebMercatorViewport } from '@deck.gl/core';
2
2
  import { escapeId, getColValAsNumber, useStoreWithDuckDb, } from '@sqlrooms/duckdb';
3
- import { useEffect, useMemo, useState } from 'react';
3
+ import { useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { DeckTableDatasetInvalidTableNameError, createDeckTableDatasetSql, } from './datasets/tableDatasetSql';
5
5
  import { isDeckMapSqlDatasetSource, } from './mapConfig';
6
6
  import { isSqlDatasetInput, isTableDatasetInput, } from './types';
7
+ /** True when `columnName` is an `ST_AsWKB(...) AS` alias (per-column fit decode). */
8
+ function columnAliasProducedByStAsWkb(sql, columnName) {
9
+ if (!sql || !columnName)
10
+ return false;
11
+ const lowerCol = columnName.toLowerCase();
12
+ const parts = sql.split(/\bST_AsWKB\s*\(/i);
13
+ for (let i = 1; i < parts.length; i++) {
14
+ const rest = parts[i];
15
+ let depth = 1;
16
+ let j = 0;
17
+ for (; j < rest.length && depth > 0; j++) {
18
+ const ch = rest[j];
19
+ if (ch === '(')
20
+ depth++;
21
+ else if (ch === ')')
22
+ depth--;
23
+ }
24
+ const after = rest.slice(j);
25
+ const match = after.match(/^\s*AS\s+("([^"]+)"|([A-Za-z_][\w$]*))/i);
26
+ if (!match)
27
+ continue;
28
+ const alias = (match[2] ?? match[3] ?? '').toLowerCase();
29
+ if (alias === lowerCol)
30
+ return true;
31
+ }
32
+ return false;
33
+ }
7
34
  /**
8
35
  * Resolves the effective fit-to-data configuration for a Deck map.
9
36
  *
@@ -22,29 +49,79 @@ export function resolveDeckMapFitToData(config) {
22
49
  return null;
23
50
  if (fitToData.longitudeColumn && fitToData.latitudeColumn)
24
51
  return fitToData;
25
- const dataset = config.datasets[fitToData.dataset];
26
- const geometryColumn = fitToData.geometryColumn ?? dataset?.geometryColumn;
27
- if (geometryColumn)
28
- return { ...fitToData, geometryColumn };
29
- if (config.interaction?.longitudeColumn &&
30
- config.interaction.latitudeColumn) {
31
- return {
32
- ...fitToData,
33
- longitudeColumn: config.interaction.longitudeColumn,
34
- latitudeColumn: config.interaction.latitudeColumn,
35
- };
52
+ if (fitToData.geometryColumns && fitToData.geometryColumns.length > 0) {
53
+ return fitToData;
54
+ }
55
+ // Explicit geometryColumn wins over inferred arc/H3.
56
+ if (fitToData.geometryColumn) {
57
+ return fitToData;
36
58
  }
37
59
  const spec = typeof config.spec === 'string'
38
60
  ? undefined
39
61
  : config.spec;
40
62
  const layers = Array.isArray(spec?.layers) ? spec.layers : [];
63
+ // Prefer both arc endpoints when fitToData did not name a single column.
41
64
  for (const layer of layers) {
42
65
  if (!layer || typeof layer !== 'object')
43
66
  continue;
44
- const binding = layer._sqlroomsBinding;
45
- if (binding?.dataset === fitToData.dataset && binding.hexagonColumn) {
67
+ const layerRecord = layer;
68
+ // Hidden layers must not drive fit (e.g. stale H3 over visible lon/lat).
69
+ if (layerRecord.visible === false)
70
+ continue;
71
+ const binding = layerRecord._sqlroomsBinding;
72
+ if (binding?.dataset !== fitToData.dataset)
73
+ continue;
74
+ if (layerRecord['@@type'] === 'GeoArrowArcLayer' &&
75
+ typeof binding.sourceGeometryColumn === 'string' &&
76
+ binding.sourceGeometryColumn.trim() &&
77
+ typeof binding.targetGeometryColumn === 'string' &&
78
+ binding.targetGeometryColumn.trim()) {
79
+ return {
80
+ ...fitToData,
81
+ geometryColumns: [
82
+ String(binding.sourceGeometryColumn),
83
+ String(binding.targetGeometryColumn),
84
+ ],
85
+ };
86
+ }
87
+ }
88
+ // Dataset default geometry wins over inferred H3.
89
+ const dataset = config.datasets[fitToData.dataset];
90
+ const geometryColumn = dataset?.geometryColumn;
91
+ if (geometryColumn)
92
+ return { ...fitToData, geometryColumn };
93
+ for (const layer of layers) {
94
+ if (!layer || typeof layer !== 'object')
95
+ continue;
96
+ const layerRecord = layer;
97
+ // Hidden layers must not drive fit (e.g. stale H3 over visible lon/lat).
98
+ if (layerRecord.visible === false)
99
+ continue;
100
+ const binding = layerRecord._sqlroomsBinding;
101
+ if (binding?.dataset !== fitToData.dataset)
102
+ continue;
103
+ if (binding.hexagonColumn) {
46
104
  return { ...fitToData, h3Column: String(binding.hexagonColumn) };
47
105
  }
106
+ // Fallback: getHexagon "@@=column" → h3Column.
107
+ if (layerRecord['@@type'] === 'GeoArrowH3HexagonLayer') {
108
+ const getHexagon = layerRecord.getHexagon;
109
+ if (typeof getHexagon === 'string') {
110
+ const match = getHexagon.trim().match(/^@@=([A-Za-z_][\w]*)$/);
111
+ const column = match?.[1];
112
+ if (column) {
113
+ return { ...fitToData, h3Column: column };
114
+ }
115
+ }
116
+ }
117
+ }
118
+ if (config.interaction?.longitudeColumn &&
119
+ config.interaction.latitudeColumn) {
120
+ return {
121
+ ...fitToData,
122
+ longitudeColumn: config.interaction.longitudeColumn,
123
+ latitudeColumn: config.interaction.latitudeColumn,
124
+ };
48
125
  }
49
126
  return fitToData;
50
127
  }
@@ -90,6 +167,7 @@ export function createDeckMapBoundsQuery(options) {
90
167
  : createDeckMapBoundsTableSourceSql(source);
91
168
  if (fitToData.h3Column) {
92
169
  const column = escapeId(fitToData.h3Column);
170
+ // Do not CAST to VARCHAR — numeric H3 IDs become invalid decimal text.
93
171
  return `
94
172
  SELECT
95
173
  MIN(h3_cell_to_lng(${column})) AS min_longitude,
@@ -100,26 +178,59 @@ export function createDeckMapBoundsQuery(options) {
100
178
  WHERE ${column} IS NOT NULL
101
179
  `;
102
180
  }
103
- if (fitToData.geometryColumn) {
104
- const column = escapeId(fitToData.geometryColumn);
181
+ const geometryColumns = fitToData.geometryColumns && fitToData.geometryColumns.length > 0
182
+ ? fitToData.geometryColumns
183
+ : fitToData.geometryColumn
184
+ ? [fitToData.geometryColumn]
185
+ : null;
186
+ if (geometryColumns) {
105
187
  const sourceSql = isDeckMapSqlDatasetSource(source)
106
188
  ? source.sqlQuery
107
189
  : (source.transformSql ?? '');
108
- const geometry = sourceSql.toLowerCase().includes('st_aswkb')
109
- ? `ST_GeomFromWKB(${column})`
110
- : `${column}::GEOMETRY`;
111
- return `
190
+ const asGeometry = (columnName) => {
191
+ // Per-column decode — a global ST_AsWKB check would break mixed arc columns.
192
+ const quoted = escapeId(columnName);
193
+ return columnAliasProducedByStAsWkb(sourceSql, columnName)
194
+ ? `ST_GeomFromWKB(${quoted})`
195
+ : `${quoted}::GEOMETRY`;
196
+ };
197
+ if (geometryColumns.length === 1) {
198
+ const columnName = geometryColumns[0];
199
+ const column = escapeId(columnName);
200
+ return `
112
201
  SELECT
113
202
  ST_XMin(extent) AS min_longitude,
114
203
  ST_YMin(extent) AS min_latitude,
115
204
  ST_XMax(extent) AS max_longitude,
116
205
  ST_YMax(extent) AS max_latitude
117
206
  FROM (
118
- SELECT ST_Extent_Agg(${geometry}) AS extent
207
+ SELECT ST_Extent_Agg(${asGeometry(columnName)}) AS extent
119
208
  FROM (${baseSourceSql}) AS "__sqlrooms_dashboard_map_geom"
120
209
  WHERE ${column} IS NOT NULL
121
210
  ) AS "__sqlrooms_dashboard_map_extent"
122
211
  WHERE extent IS NOT NULL
212
+ `;
213
+ }
214
+ // Multiple geom columns: unnest once so the source is scanned once.
215
+ const geomExprs = geometryColumns.map((col) => {
216
+ const column = escapeId(col);
217
+ return `CASE WHEN ${column} IS NOT NULL THEN ${asGeometry(col)} END`;
218
+ });
219
+ return `
220
+ SELECT
221
+ ST_XMin(extent) AS min_longitude,
222
+ ST_YMin(extent) AS min_latitude,
223
+ ST_XMax(extent) AS max_longitude,
224
+ ST_YMax(extent) AS max_latitude
225
+ FROM (
226
+ SELECT ST_Extent_Agg(geom) AS extent
227
+ FROM (
228
+ SELECT UNNEST([${geomExprs.join(', ')}]) AS geom
229
+ FROM (${baseSourceSql}) AS "__sqlrooms_dashboard_map_geom"
230
+ ) AS "__sqlrooms_dashboard_map_geoms"
231
+ WHERE geom IS NOT NULL
232
+ ) AS "__sqlrooms_dashboard_map_extent"
233
+ WHERE extent IS NOT NULL
123
234
  `;
124
235
  }
125
236
  if (fitToData.longitudeColumn && fitToData.latitudeColumn) {
@@ -201,6 +312,21 @@ function fitDeckMapView(options) {
201
312
  zoom: Math.min(fitted.zoom, maxZoom),
202
313
  };
203
314
  }
315
+ /**
316
+ * MapLibre `jumpTo` options. Omits pitch/bearing unless set so fit preserves
317
+ * a pitched `initialViewState` (needed for extruded columns).
318
+ */
319
+ export function buildDeckMapJumpToOptions(opts) {
320
+ const jumpOpts = {
321
+ center: [opts.longitude, opts.latitude],
322
+ zoom: opts.zoom,
323
+ };
324
+ if (opts.bearing != null)
325
+ jumpOpts.bearing = opts.bearing;
326
+ if (opts.pitch != null)
327
+ jumpOpts.pitch = opts.pitch;
328
+ return jumpOpts;
329
+ }
204
330
  function createInitialFitState(key, requestVersion) {
205
331
  return {
206
332
  key,
@@ -208,6 +334,9 @@ function createInitialFitState(key, requestVersion) {
208
334
  handledRequestVersion: requestVersion,
209
335
  };
210
336
  }
337
+ /** Retries for H3 extension load races. */
338
+ const FIT_MAX_ATTEMPTS = 5;
339
+ const FIT_RETRY_DELAY_MS = 750;
211
340
  /**
212
341
  * Executes host-neutral fit-to-data requests for a Deck map surface.
213
342
  *
@@ -223,6 +352,7 @@ export function useDeckMapFitController(options) {
223
352
  const { scopeId, fitToData, source, container, deckMapRef, requestVersion, autoFit = false, onSuccess, onError, } = options;
224
353
  const executeSql = useStoreWithDuckDb((state) => state.db.executeSql);
225
354
  const [containerSize, setContainerSize] = useState({ width: 0, height: 0 });
355
+ const [retryNonce, setRetryNonce] = useState(0);
226
356
  const fitKey = useMemo(() => JSON.stringify({ scopeId, fitToData, source }), [fitToData, scopeId, source]);
227
357
  const [fitState, setFitState] = useState(() => createInitialFitState(fitKey, requestVersion));
228
358
  // A source change resets auto-fit state, but must not mark a newer manual
@@ -230,6 +360,7 @@ export function useDeckMapFitController(options) {
230
360
  const activeFitState = fitState.key === fitKey
231
361
  ? fitState
232
362
  : createInitialFitState(fitKey, fitState.handledRequestVersion);
363
+ const fitAttemptsRef = useRef({ key: '', count: 0 });
233
364
  useEffect(() => {
234
365
  if (!container)
235
366
  return;
@@ -245,6 +376,11 @@ export function useDeckMapFitController(options) {
245
376
  return () => observer.disconnect();
246
377
  }, [container]);
247
378
  useEffect(() => {
379
+ // Reset retries on source change or Fit click — else exhausted autofit no-ops Fit.
380
+ const attemptsKey = `${fitKey}:${requestVersion}`;
381
+ if (fitAttemptsRef.current.key !== attemptsKey) {
382
+ fitAttemptsRef.current = { key: attemptsKey, count: 0 };
383
+ }
248
384
  const hasManualRequest = requestVersion > activeFitState.handledRequestVersion;
249
385
  if (!fitToData ||
250
386
  !source ||
@@ -254,11 +390,25 @@ export function useDeckMapFitController(options) {
254
390
  return;
255
391
  }
256
392
  let cancelled = false;
393
+ let retryTimer;
257
394
  const markHandled = () => setFitState({
258
395
  key: fitKey,
259
396
  didAutoFit: true,
260
397
  handledRequestVersion: requestVersion,
261
398
  });
399
+ const scheduleRetry = (error) => {
400
+ fitAttemptsRef.current.count += 1;
401
+ if (fitAttemptsRef.current.count >= FIT_MAX_ATTEMPTS) {
402
+ if (error)
403
+ onError?.(error);
404
+ markHandled();
405
+ return;
406
+ }
407
+ retryTimer = setTimeout(() => {
408
+ if (!cancelled)
409
+ setRetryNonce((value) => value + 1);
410
+ }, FIT_RETRY_DELAY_MS);
411
+ };
262
412
  void (async () => {
263
413
  try {
264
414
  if (fitToData.h3Column) {
@@ -278,18 +428,32 @@ export function useDeckMapFitController(options) {
278
428
  }
279
429
  const handle = await executeSql(query);
280
430
  const result = handle ? await handle : null;
281
- if (cancelled || !result)
431
+ if (cancelled)
432
+ return;
433
+ if (!result) {
434
+ // Empty handle ≈ cancelled query, not a transient race.
435
+ onError?.(new Error('Unable to fit map view to data: empty query result.'));
436
+ markHandled();
282
437
  return;
438
+ }
283
439
  const bounds = readDeckMapBounds(result);
284
- if (bounds) {
285
- deckMapRef.current?.jumpTo(fitDeckMapView({
286
- bounds,
287
- width: containerSize.width,
288
- height: containerSize.height,
289
- padding: fitToData.padding,
290
- maxZoom: fitToData.maxZoom,
291
- }));
440
+ if (!bounds) {
441
+ // Empty geometry is permanent; only retry H3 cold-start.
442
+ if (fitToData.h3Column) {
443
+ scheduleRetry(new Error('Unable to fit map view to H3 data. Check that the hexagon column contains valid H3 indexes.'));
444
+ return;
445
+ }
446
+ onError?.(new Error('Unable to determine map bounds from data.'));
447
+ markHandled();
448
+ return;
292
449
  }
450
+ deckMapRef.current?.jumpTo(fitDeckMapView({
451
+ bounds,
452
+ width: containerSize.width,
453
+ height: containerSize.height,
454
+ padding: fitToData.padding,
455
+ maxZoom: fitToData.maxZoom,
456
+ }));
293
457
  markHandled();
294
458
  onSuccess?.();
295
459
  }
@@ -299,12 +463,25 @@ export function useDeckMapFitController(options) {
299
463
  const fitError = error instanceof Error
300
464
  ? error
301
465
  : new Error('Unable to fit map view to data.');
466
+ // Retry only likely-transient H3 extension races.
467
+ const message = fitError.message.toLowerCase();
468
+ const maybeTransientH3 = Boolean(fitToData.h3Column) &&
469
+ (message.includes('h3') ||
470
+ message.includes('extension') ||
471
+ message.includes('not loaded') ||
472
+ message.includes('catalog'));
473
+ if (maybeTransientH3) {
474
+ scheduleRetry(fitError);
475
+ return;
476
+ }
302
477
  onError?.(fitError);
303
478
  markHandled();
304
479
  }
305
480
  })();
306
481
  return () => {
307
482
  cancelled = true;
483
+ if (retryTimer)
484
+ clearTimeout(retryTimer);
308
485
  };
309
486
  }, [
310
487
  activeFitState.didAutoFit,
@@ -319,6 +496,7 @@ export function useDeckMapFitController(options) {
319
496
  onError,
320
497
  onSuccess,
321
498
  requestVersion,
499
+ retryNonce,
322
500
  source,
323
501
  ]);
324
502
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mapFit.js","sourceRoot":"","sources":["../src/mapFit.ts"],"names":[],"mappings":"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","sourcesContent":["import {WebMercatorViewport} from '@deck.gl/core';\nimport {\n escapeId,\n getColValAsNumber,\n useStoreWithDuckDb,\n} from '@sqlrooms/duckdb';\nimport type {Table as ArrowTable} from 'apache-arrow';\nimport {useEffect, useMemo, useState, type RefObject} from 'react';\nimport {\n DeckTableDatasetInvalidTableNameError,\n createDeckTableDatasetSql,\n} from './datasets/tableDatasetSql';\nimport {\n isDeckMapSqlDatasetSource,\n type DeckMapConfig,\n type DeckMapDatasetSource,\n type DeckMapFitToDataConfig,\n} from './mapConfig';\nimport {\n isSqlDatasetInput,\n isTableDatasetInput,\n type DeckDatasetInput,\n type DeckJsonMapHandle,\n} from './types';\n\n/**\n * Resolves the effective fit-to-data configuration for a Deck map.\n *\n * Explicit coordinate or geometry fields take precedence. Missing geometry and\n * H3 fields are inferred from dataset metadata, interaction configuration, and\n * layer bindings without consulting host-specific state.\n *\n * @param config - Durable Deck map configuration to inspect.\n * @returns A normalized fit configuration, or `null` when fitting is disabled.\n */\nexport function resolveDeckMapFitToData(\n config: DeckMapConfig | null | undefined,\n): DeckMapFitToDataConfig | null {\n if (!config) return null;\n const fitToData = config.fitToData;\n if (!fitToData?.dataset) return null;\n if (fitToData.longitudeColumn && fitToData.latitudeColumn) return fitToData;\n\n const dataset = config.datasets[fitToData.dataset];\n const geometryColumn = fitToData.geometryColumn ?? dataset?.geometryColumn;\n if (geometryColumn) return {...fitToData, geometryColumn};\n\n if (\n config.interaction?.longitudeColumn &&\n config.interaction.latitudeColumn\n ) {\n return {\n ...fitToData,\n longitudeColumn: config.interaction.longitudeColumn,\n latitudeColumn: config.interaction.latitudeColumn,\n };\n }\n\n const spec =\n typeof config.spec === 'string'\n ? undefined\n : (config.spec as Record<string, unknown>);\n const layers = Array.isArray(spec?.layers) ? spec.layers : [];\n for (const layer of layers) {\n if (!layer || typeof layer !== 'object') continue;\n const binding = (layer as Record<string, unknown>)._sqlroomsBinding as\n | Record<string, unknown>\n | undefined;\n if (binding?.dataset === fitToData.dataset && binding.hexagonColumn) {\n return {...fitToData, h3Column: String(binding.hexagonColumn)};\n }\n }\n\n return fitToData;\n}\n\n/**\n * Converts a host-resolved Deck dataset input into a queryable map source.\n *\n * Prepared Arrow datasets intentionally return `null` because fitting them\n * requires host-provided bounds rather than a DuckDB source query.\n *\n * @param dataset - Dataset after the host data adapter has resolved its source.\n * @returns A SQL or table source suitable for bounds queries, or `null`.\n */\nexport function getDeckMapDatasetSource(\n dataset: DeckDatasetInput | undefined,\n): DeckMapDatasetSource | null {\n if (!dataset) return null;\n if (isSqlDatasetInput(dataset)) return {sqlQuery: dataset.sqlQuery};\n if (isTableDatasetInput(dataset)) {\n return {\n tableName: dataset.tableName,\n transformSql: dataset.transformSql,\n };\n }\n return null;\n}\n\n/**\n * Builds the DuckDB query used to calculate a map dataset's geographic extent.\n *\n * The query strategy follows the normalized fit configuration: H3 cells,\n * geometry values, explicit longitude/latitude columns, or conventional\n * `Longitude`/`Latitude` column names as a final fallback.\n *\n * @param options - Resolved dataset source and normalized fit configuration.\n * @returns SQL that yields min/max longitude and latitude, or `null` when the\n * configuration cannot identify a target dataset.\n */\nexport function createDeckMapBoundsQuery(options: {\n source: DeckMapDatasetSource;\n fitToData: DeckMapFitToDataConfig;\n}) {\n const {source, fitToData} = options;\n if (!fitToData.dataset) return null;\n const baseSourceSql = isDeckMapSqlDatasetSource(source)\n ? `SELECT * FROM (${source.sqlQuery.trim().replace(/(?:\\s*;+\\s*)+$/, '')}) AS \"__sqlrooms_dashboard_map_source\"`\n : createDeckMapBoundsTableSourceSql(source);\n\n if (fitToData.h3Column) {\n const column = escapeId(fitToData.h3Column);\n return `\n SELECT\n MIN(h3_cell_to_lng(${column})) AS min_longitude,\n MIN(h3_cell_to_lat(${column})) AS min_latitude,\n MAX(h3_cell_to_lng(${column})) AS max_longitude,\n MAX(h3_cell_to_lat(${column})) AS max_latitude\n FROM (${baseSourceSql}) AS \"__sqlrooms_dashboard_map_h3\"\n WHERE ${column} IS NOT NULL\n `;\n }\n\n if (fitToData.geometryColumn) {\n const column = escapeId(fitToData.geometryColumn);\n const sourceSql = isDeckMapSqlDatasetSource(source)\n ? source.sqlQuery\n : (source.transformSql ?? '');\n const geometry = sourceSql.toLowerCase().includes('st_aswkb')\n ? `ST_GeomFromWKB(${column})`\n : `${column}::GEOMETRY`;\n return `\n SELECT\n ST_XMin(extent) AS min_longitude,\n ST_YMin(extent) AS min_latitude,\n ST_XMax(extent) AS max_longitude,\n ST_YMax(extent) AS max_latitude\n FROM (\n SELECT ST_Extent_Agg(${geometry}) AS extent\n FROM (${baseSourceSql}) AS \"__sqlrooms_dashboard_map_geom\"\n WHERE ${column} IS NOT NULL\n ) AS \"__sqlrooms_dashboard_map_extent\"\n WHERE extent IS NOT NULL\n `;\n }\n\n if (fitToData.longitudeColumn && fitToData.latitudeColumn) {\n const longitude = escapeId(fitToData.longitudeColumn);\n const latitude = escapeId(fitToData.latitudeColumn);\n return `\n SELECT\n ST_XMin(extent) AS min_longitude,\n ST_YMin(extent) AS min_latitude,\n ST_XMax(extent) AS max_longitude,\n ST_YMax(extent) AS max_latitude\n FROM (\n SELECT ST_Extent_Agg(ST_Point(${longitude}, ${latitude})) AS extent\n FROM (${baseSourceSql}) AS \"__sqlrooms_dashboard_map_points\"\n WHERE ${longitude} IS NOT NULL AND ${latitude} IS NOT NULL\n ) AS \"__sqlrooms_dashboard_map_extent\"\n WHERE extent IS NOT NULL\n `;\n }\n\n return `\n SELECT\n ST_XMin(extent) AS min_longitude,\n ST_YMin(extent) AS min_latitude,\n ST_XMax(extent) AS max_longitude,\n ST_YMax(extent) AS max_latitude\n FROM (\n SELECT ST_Extent_Agg(ST_Point(Longitude, Latitude)) AS extent\n FROM (${baseSourceSql}) AS \"__sqlrooms_dashboard_map_points\"\n WHERE Longitude IS NOT NULL AND Latitude IS NOT NULL\n ) AS \"__sqlrooms_dashboard_map_extent\"\n WHERE extent IS NOT NULL\n `;\n}\n\nfunction createDeckMapBoundsTableSourceSql(\n source: Exclude<DeckMapDatasetSource, {sqlQuery: string}>,\n) {\n try {\n return createDeckTableDatasetSql(source);\n } catch (error) {\n if (error instanceof DeckTableDatasetInvalidTableNameError) {\n throw new Error('Deck map fit-to-data requires a valid table source.');\n }\n throw error;\n }\n}\n\nfunction readDeckMapBounds(result: ArrowTable) {\n const minLongitude = getColValAsNumber(result, 'min_longitude');\n const minLatitude = getColValAsNumber(result, 'min_latitude');\n const maxLongitude = getColValAsNumber(result, 'max_longitude');\n const maxLatitude = getColValAsNumber(result, 'max_latitude');\n if (\n !Number.isFinite(minLongitude) ||\n !Number.isFinite(minLatitude) ||\n !Number.isFinite(maxLongitude) ||\n !Number.isFinite(maxLatitude)\n ) {\n return null;\n }\n return [\n [\n minLongitude === maxLongitude ? minLongitude - 0.01 : minLongitude,\n minLatitude === maxLatitude ? minLatitude - 0.01 : minLatitude,\n ],\n [\n minLongitude === maxLongitude ? maxLongitude + 0.01 : maxLongitude,\n minLatitude === maxLatitude ? maxLatitude + 0.01 : maxLatitude,\n ],\n ] as const;\n}\n\nfunction fitDeckMapView(options: {\n bounds: readonly [readonly [number, number], readonly [number, number]];\n width: number;\n height: number;\n padding?: number;\n maxZoom?: number;\n}) {\n const {bounds, width, height, padding = 40, maxZoom = 18} = options;\n const fitted = new WebMercatorViewport({\n width: Math.max(width, 1),\n height: Math.max(height, 1),\n }).fitBounds(\n [\n [bounds[0][0], bounds[0][1]],\n [bounds[1][0], bounds[1][1]],\n ],\n {padding},\n ) as WebMercatorViewport & {\n longitude: number;\n latitude: number;\n zoom: number;\n };\n return {\n longitude: fitted.longitude,\n latitude: fitted.latitude,\n zoom: Math.min(fitted.zoom, maxZoom),\n };\n}\n\ntype DeckMapFitState = {\n key: string;\n didAutoFit: boolean;\n handledRequestVersion: number;\n};\n\nfunction createInitialFitState(key: string, requestVersion: number) {\n return {\n key,\n didAutoFit: false,\n handledRequestVersion: requestVersion,\n };\n}\n\n/**\n * Executes host-neutral fit-to-data requests for a Deck map surface.\n *\n * The controller observes the map container, de-duplicates manual requests,\n * optionally auto-fits when the source changes, loads H3 support when needed,\n * queries dataset bounds, and updates the imperative Deck map view. Hosts are\n * responsible only for resolving their dataset source and request version.\n *\n * @param options - Map identity, resolved fit inputs, view refs, request state,\n * and optional success and error callbacks.\n */\nexport function useDeckMapFitController(options: {\n scopeId: string;\n fitToData: DeckMapFitToDataConfig | null;\n source: DeckMapDatasetSource | null;\n container: HTMLElement | null;\n deckMapRef: RefObject<DeckJsonMapHandle | null>;\n requestVersion: number;\n autoFit?: boolean;\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n}) {\n const {\n scopeId,\n fitToData,\n source,\n container,\n deckMapRef,\n requestVersion,\n autoFit = false,\n onSuccess,\n onError,\n } = options;\n const executeSql = useStoreWithDuckDb((state) => state.db.executeSql);\n const [containerSize, setContainerSize] = useState({width: 0, height: 0});\n const fitKey = useMemo(\n () => JSON.stringify({scopeId, fitToData, source}),\n [fitToData, scopeId, source],\n );\n const [fitState, setFitState] = useState<DeckMapFitState>(() =>\n createInitialFitState(fitKey, requestVersion),\n );\n // A source change resets auto-fit state, but must not mark a newer manual\n // request as handled before the effect observes it.\n const activeFitState =\n fitState.key === fitKey\n ? fitState\n : createInitialFitState(fitKey, fitState.handledRequestVersion);\n\n useEffect(() => {\n if (!container) return;\n const updateSize = () =>\n setContainerSize({\n width: container.clientWidth,\n height: container.clientHeight,\n });\n updateSize();\n if (typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(updateSize);\n observer.observe(container);\n return () => observer.disconnect();\n }, [container]);\n\n useEffect(() => {\n const hasManualRequest =\n requestVersion > activeFitState.handledRequestVersion;\n if (\n !fitToData ||\n !source ||\n containerSize.width <= 0 ||\n containerSize.height <= 0 ||\n (!hasManualRequest && (!autoFit || activeFitState.didAutoFit))\n ) {\n return;\n }\n\n let cancelled = false;\n const markHandled = () =>\n setFitState({\n key: fitKey,\n didAutoFit: true,\n handledRequestVersion: requestVersion,\n });\n\n void (async () => {\n try {\n if (fitToData.h3Column) {\n try {\n await executeSql('INSTALL h3 FROM community');\n } catch {\n // The extension may already be installed.\n }\n await executeSql('LOAD h3');\n }\n const query = createDeckMapBoundsQuery({source, fitToData});\n if (!query) {\n markHandled();\n onSuccess?.();\n return;\n }\n const handle = await executeSql(query);\n const result = handle ? await handle : null;\n if (cancelled || !result) return;\n const bounds = readDeckMapBounds(result);\n if (bounds) {\n deckMapRef.current?.jumpTo(\n fitDeckMapView({\n bounds,\n width: containerSize.width,\n height: containerSize.height,\n padding: fitToData.padding,\n maxZoom: fitToData.maxZoom,\n }),\n );\n }\n markHandled();\n onSuccess?.();\n } catch (error) {\n if (cancelled) return;\n const fitError =\n error instanceof Error\n ? error\n : new Error('Unable to fit map view to data.');\n onError?.(fitError);\n markHandled();\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [\n activeFitState.didAutoFit,\n activeFitState.handledRequestVersion,\n autoFit,\n containerSize.height,\n containerSize.width,\n deckMapRef,\n executeSql,\n fitKey,\n fitToData,\n onError,\n onSuccess,\n requestVersion,\n source,\n ]);\n}\n"]}
1
+ {"version":3,"file":"mapFit.js","sourceRoot":"","sources":["../src/mapFit.ts"],"names":[],"mappings":"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","sourcesContent":["import {WebMercatorViewport} from '@deck.gl/core';\nimport {\n escapeId,\n getColValAsNumber,\n useStoreWithDuckDb,\n} from '@sqlrooms/duckdb';\nimport type {Table as ArrowTable} from 'apache-arrow';\nimport {useEffect, useMemo, useRef, useState, type RefObject} from 'react';\nimport {\n DeckTableDatasetInvalidTableNameError,\n createDeckTableDatasetSql,\n} from './datasets/tableDatasetSql';\nimport {\n isDeckMapSqlDatasetSource,\n type DeckMapConfig,\n type DeckMapDatasetSource,\n type DeckMapFitToDataConfig,\n} from './mapConfig';\nimport {\n isSqlDatasetInput,\n isTableDatasetInput,\n type DeckDatasetInput,\n type DeckJsonMapHandle,\n} from './types';\n\n/** True when `columnName` is an `ST_AsWKB(...) AS` alias (per-column fit decode). */\nfunction columnAliasProducedByStAsWkb(\n sql: string,\n columnName: string,\n): boolean {\n if (!sql || !columnName) return false;\n const lowerCol = columnName.toLowerCase();\n const parts = sql.split(/\\bST_AsWKB\\s*\\(/i);\n for (let i = 1; i < parts.length; i++) {\n const rest = parts[i]!;\n let depth = 1;\n let j = 0;\n for (; j < rest.length && depth > 0; j++) {\n const ch = rest[j];\n if (ch === '(') depth++;\n else if (ch === ')') depth--;\n }\n const after = rest.slice(j);\n const match = after.match(/^\\s*AS\\s+(\"([^\"]+)\"|([A-Za-z_][\\w$]*))/i);\n if (!match) continue;\n const alias = (match[2] ?? match[3] ?? '').toLowerCase();\n if (alias === lowerCol) return true;\n }\n return false;\n}\n\n/**\n * Resolves the effective fit-to-data configuration for a Deck map.\n *\n * Explicit coordinate or geometry fields take precedence. Missing geometry and\n * H3 fields are inferred from dataset metadata, interaction configuration, and\n * layer bindings without consulting host-specific state.\n *\n * @param config - Durable Deck map configuration to inspect.\n * @returns A normalized fit configuration, or `null` when fitting is disabled.\n */\nexport function resolveDeckMapFitToData(\n config: DeckMapConfig | null | undefined,\n): DeckMapFitToDataConfig | null {\n if (!config) return null;\n const fitToData = config.fitToData;\n if (!fitToData?.dataset) return null;\n if (fitToData.longitudeColumn && fitToData.latitudeColumn) return fitToData;\n if (fitToData.geometryColumns && fitToData.geometryColumns.length > 0) {\n return fitToData;\n }\n\n // Explicit geometryColumn wins over inferred arc/H3.\n if (fitToData.geometryColumn) {\n return fitToData;\n }\n\n const spec =\n typeof config.spec === 'string'\n ? undefined\n : (config.spec as Record<string, unknown>);\n const layers = Array.isArray(spec?.layers) ? spec.layers : [];\n\n // Prefer both arc endpoints when fitToData did not name a single column.\n for (const layer of layers) {\n if (!layer || typeof layer !== 'object') continue;\n const layerRecord = layer as Record<string, unknown>;\n // Hidden layers must not drive fit (e.g. stale H3 over visible lon/lat).\n if (layerRecord.visible === false) continue;\n const binding = layerRecord._sqlroomsBinding as\n | Record<string, unknown>\n | undefined;\n if (binding?.dataset !== fitToData.dataset) continue;\n\n if (\n layerRecord['@@type'] === 'GeoArrowArcLayer' &&\n typeof binding.sourceGeometryColumn === 'string' &&\n binding.sourceGeometryColumn.trim() &&\n typeof binding.targetGeometryColumn === 'string' &&\n binding.targetGeometryColumn.trim()\n ) {\n return {\n ...fitToData,\n geometryColumns: [\n String(binding.sourceGeometryColumn),\n String(binding.targetGeometryColumn),\n ],\n };\n }\n }\n\n // Dataset default geometry wins over inferred H3.\n const dataset = config.datasets[fitToData.dataset];\n const geometryColumn = dataset?.geometryColumn;\n if (geometryColumn) return {...fitToData, geometryColumn};\n\n for (const layer of layers) {\n if (!layer || typeof layer !== 'object') continue;\n const layerRecord = layer as Record<string, unknown>;\n // Hidden layers must not drive fit (e.g. stale H3 over visible lon/lat).\n if (layerRecord.visible === false) continue;\n const binding = layerRecord._sqlroomsBinding as\n | Record<string, unknown>\n | undefined;\n if (binding?.dataset !== fitToData.dataset) continue;\n\n if (binding.hexagonColumn) {\n return {...fitToData, h3Column: String(binding.hexagonColumn)};\n }\n\n // Fallback: getHexagon \"@@=column\" → h3Column.\n if (layerRecord['@@type'] === 'GeoArrowH3HexagonLayer') {\n const getHexagon = layerRecord.getHexagon;\n if (typeof getHexagon === 'string') {\n const match = getHexagon.trim().match(/^@@=([A-Za-z_][\\w]*)$/);\n const column = match?.[1];\n if (column) {\n return {...fitToData, h3Column: column};\n }\n }\n }\n }\n\n if (\n config.interaction?.longitudeColumn &&\n config.interaction.latitudeColumn\n ) {\n return {\n ...fitToData,\n longitudeColumn: config.interaction.longitudeColumn,\n latitudeColumn: config.interaction.latitudeColumn,\n };\n }\n\n return fitToData;\n}\n\n/**\n * Converts a host-resolved Deck dataset input into a queryable map source.\n *\n * Prepared Arrow datasets intentionally return `null` because fitting them\n * requires host-provided bounds rather than a DuckDB source query.\n *\n * @param dataset - Dataset after the host data adapter has resolved its source.\n * @returns A SQL or table source suitable for bounds queries, or `null`.\n */\nexport function getDeckMapDatasetSource(\n dataset: DeckDatasetInput | undefined,\n): DeckMapDatasetSource | null {\n if (!dataset) return null;\n if (isSqlDatasetInput(dataset)) return {sqlQuery: dataset.sqlQuery};\n if (isTableDatasetInput(dataset)) {\n return {\n tableName: dataset.tableName,\n transformSql: dataset.transformSql,\n };\n }\n return null;\n}\n\n/**\n * Builds the DuckDB query used to calculate a map dataset's geographic extent.\n *\n * The query strategy follows the normalized fit configuration: H3 cells,\n * geometry values, explicit longitude/latitude columns, or conventional\n * `Longitude`/`Latitude` column names as a final fallback.\n *\n * @param options - Resolved dataset source and normalized fit configuration.\n * @returns SQL that yields min/max longitude and latitude, or `null` when the\n * configuration cannot identify a target dataset.\n */\nexport function createDeckMapBoundsQuery(options: {\n source: DeckMapDatasetSource;\n fitToData: DeckMapFitToDataConfig;\n}) {\n const {source, fitToData} = options;\n if (!fitToData.dataset) return null;\n const baseSourceSql = isDeckMapSqlDatasetSource(source)\n ? `SELECT * FROM (${source.sqlQuery.trim().replace(/(?:\\s*;+\\s*)+$/, '')}) AS \"__sqlrooms_dashboard_map_source\"`\n : createDeckMapBoundsTableSourceSql(source);\n\n if (fitToData.h3Column) {\n const column = escapeId(fitToData.h3Column);\n // Do not CAST to VARCHAR — numeric H3 IDs become invalid decimal text.\n return `\n SELECT\n MIN(h3_cell_to_lng(${column})) AS min_longitude,\n MIN(h3_cell_to_lat(${column})) AS min_latitude,\n MAX(h3_cell_to_lng(${column})) AS max_longitude,\n MAX(h3_cell_to_lat(${column})) AS max_latitude\n FROM (${baseSourceSql}) AS \"__sqlrooms_dashboard_map_h3\"\n WHERE ${column} IS NOT NULL\n `;\n }\n\n const geometryColumns =\n fitToData.geometryColumns && fitToData.geometryColumns.length > 0\n ? fitToData.geometryColumns\n : fitToData.geometryColumn\n ? [fitToData.geometryColumn]\n : null;\n\n if (geometryColumns) {\n const sourceSql = isDeckMapSqlDatasetSource(source)\n ? source.sqlQuery\n : (source.transformSql ?? '');\n const asGeometry = (columnName: string) => {\n // Per-column decode — a global ST_AsWKB check would break mixed arc columns.\n const quoted = escapeId(columnName);\n return columnAliasProducedByStAsWkb(sourceSql, columnName)\n ? `ST_GeomFromWKB(${quoted})`\n : `${quoted}::GEOMETRY`;\n };\n\n if (geometryColumns.length === 1) {\n const columnName = geometryColumns[0]!;\n const column = escapeId(columnName);\n return `\n SELECT\n ST_XMin(extent) AS min_longitude,\n ST_YMin(extent) AS min_latitude,\n ST_XMax(extent) AS max_longitude,\n ST_YMax(extent) AS max_latitude\n FROM (\n SELECT ST_Extent_Agg(${asGeometry(columnName)}) AS extent\n FROM (${baseSourceSql}) AS \"__sqlrooms_dashboard_map_geom\"\n WHERE ${column} IS NOT NULL\n ) AS \"__sqlrooms_dashboard_map_extent\"\n WHERE extent IS NOT NULL\n `;\n }\n\n // Multiple geom columns: unnest once so the source is scanned once.\n const geomExprs = geometryColumns.map((col) => {\n const column = escapeId(col);\n return `CASE WHEN ${column} IS NOT NULL THEN ${asGeometry(col)} END`;\n });\n return `\n SELECT\n ST_XMin(extent) AS min_longitude,\n ST_YMin(extent) AS min_latitude,\n ST_XMax(extent) AS max_longitude,\n ST_YMax(extent) AS max_latitude\n FROM (\n SELECT ST_Extent_Agg(geom) AS extent\n FROM (\n SELECT UNNEST([${geomExprs.join(', ')}]) AS geom\n FROM (${baseSourceSql}) AS \"__sqlrooms_dashboard_map_geom\"\n ) AS \"__sqlrooms_dashboard_map_geoms\"\n WHERE geom IS NOT NULL\n ) AS \"__sqlrooms_dashboard_map_extent\"\n WHERE extent IS NOT NULL\n `;\n }\n\n if (fitToData.longitudeColumn && fitToData.latitudeColumn) {\n const longitude = escapeId(fitToData.longitudeColumn);\n const latitude = escapeId(fitToData.latitudeColumn);\n return `\n SELECT\n ST_XMin(extent) AS min_longitude,\n ST_YMin(extent) AS min_latitude,\n ST_XMax(extent) AS max_longitude,\n ST_YMax(extent) AS max_latitude\n FROM (\n SELECT ST_Extent_Agg(ST_Point(${longitude}, ${latitude})) AS extent\n FROM (${baseSourceSql}) AS \"__sqlrooms_dashboard_map_points\"\n WHERE ${longitude} IS NOT NULL AND ${latitude} IS NOT NULL\n ) AS \"__sqlrooms_dashboard_map_extent\"\n WHERE extent IS NOT NULL\n `;\n }\n\n return `\n SELECT\n ST_XMin(extent) AS min_longitude,\n ST_YMin(extent) AS min_latitude,\n ST_XMax(extent) AS max_longitude,\n ST_YMax(extent) AS max_latitude\n FROM (\n SELECT ST_Extent_Agg(ST_Point(Longitude, Latitude)) AS extent\n FROM (${baseSourceSql}) AS \"__sqlrooms_dashboard_map_points\"\n WHERE Longitude IS NOT NULL AND Latitude IS NOT NULL\n ) AS \"__sqlrooms_dashboard_map_extent\"\n WHERE extent IS NOT NULL\n `;\n}\n\nfunction createDeckMapBoundsTableSourceSql(\n source: Exclude<DeckMapDatasetSource, {sqlQuery: string}>,\n) {\n try {\n return createDeckTableDatasetSql(source);\n } catch (error) {\n if (error instanceof DeckTableDatasetInvalidTableNameError) {\n throw new Error('Deck map fit-to-data requires a valid table source.');\n }\n throw error;\n }\n}\n\nfunction readDeckMapBounds(result: ArrowTable) {\n const minLongitude = getColValAsNumber(result, 'min_longitude');\n const minLatitude = getColValAsNumber(result, 'min_latitude');\n const maxLongitude = getColValAsNumber(result, 'max_longitude');\n const maxLatitude = getColValAsNumber(result, 'max_latitude');\n if (\n !Number.isFinite(minLongitude) ||\n !Number.isFinite(minLatitude) ||\n !Number.isFinite(maxLongitude) ||\n !Number.isFinite(maxLatitude)\n ) {\n return null;\n }\n return [\n [\n minLongitude === maxLongitude ? minLongitude - 0.01 : minLongitude,\n minLatitude === maxLatitude ? minLatitude - 0.01 : minLatitude,\n ],\n [\n minLongitude === maxLongitude ? maxLongitude + 0.01 : maxLongitude,\n minLatitude === maxLatitude ? maxLatitude + 0.01 : maxLatitude,\n ],\n ] as const;\n}\n\nfunction fitDeckMapView(options: {\n bounds: readonly [readonly [number, number], readonly [number, number]];\n width: number;\n height: number;\n padding?: number;\n maxZoom?: number;\n}) {\n const {bounds, width, height, padding = 40, maxZoom = 18} = options;\n const fitted = new WebMercatorViewport({\n width: Math.max(width, 1),\n height: Math.max(height, 1),\n }).fitBounds(\n [\n [bounds[0][0], bounds[0][1]],\n [bounds[1][0], bounds[1][1]],\n ],\n {padding},\n ) as WebMercatorViewport & {\n longitude: number;\n latitude: number;\n zoom: number;\n };\n return {\n longitude: fitted.longitude,\n latitude: fitted.latitude,\n zoom: Math.min(fitted.zoom, maxZoom),\n };\n}\n\n/**\n * MapLibre `jumpTo` options. Omits pitch/bearing unless set so fit preserves\n * a pitched `initialViewState` (needed for extruded columns).\n */\nexport function buildDeckMapJumpToOptions(opts: {\n longitude: number;\n latitude: number;\n zoom: number;\n bearing?: number;\n pitch?: number;\n}): {\n center: [number, number];\n zoom: number;\n bearing?: number;\n pitch?: number;\n} {\n const jumpOpts: {\n center: [number, number];\n zoom: number;\n bearing?: number;\n pitch?: number;\n } = {\n center: [opts.longitude, opts.latitude],\n zoom: opts.zoom,\n };\n if (opts.bearing != null) jumpOpts.bearing = opts.bearing;\n if (opts.pitch != null) jumpOpts.pitch = opts.pitch;\n return jumpOpts;\n}\n\ntype DeckMapFitState = {\n key: string;\n didAutoFit: boolean;\n handledRequestVersion: number;\n};\n\nfunction createInitialFitState(key: string, requestVersion: number) {\n return {\n key,\n didAutoFit: false,\n handledRequestVersion: requestVersion,\n };\n}\n\n/** Retries for H3 extension load races. */\nconst FIT_MAX_ATTEMPTS = 5;\nconst FIT_RETRY_DELAY_MS = 750;\n\n/**\n * Executes host-neutral fit-to-data requests for a Deck map surface.\n *\n * The controller observes the map container, de-duplicates manual requests,\n * optionally auto-fits when the source changes, loads H3 support when needed,\n * queries dataset bounds, and updates the imperative Deck map view. Hosts are\n * responsible only for resolving their dataset source and request version.\n *\n * @param options - Map identity, resolved fit inputs, view refs, request state,\n * and optional success and error callbacks.\n */\nexport function useDeckMapFitController(options: {\n scopeId: string;\n fitToData: DeckMapFitToDataConfig | null;\n source: DeckMapDatasetSource | null;\n container: HTMLElement | null;\n deckMapRef: RefObject<DeckJsonMapHandle | null>;\n requestVersion: number;\n autoFit?: boolean;\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n}) {\n const {\n scopeId,\n fitToData,\n source,\n container,\n deckMapRef,\n requestVersion,\n autoFit = false,\n onSuccess,\n onError,\n } = options;\n const executeSql = useStoreWithDuckDb((state) => state.db.executeSql);\n const [containerSize, setContainerSize] = useState({width: 0, height: 0});\n const [retryNonce, setRetryNonce] = useState(0);\n const fitKey = useMemo(\n () => JSON.stringify({scopeId, fitToData, source}),\n [fitToData, scopeId, source],\n );\n const [fitState, setFitState] = useState<DeckMapFitState>(() =>\n createInitialFitState(fitKey, requestVersion),\n );\n // A source change resets auto-fit state, but must not mark a newer manual\n // request as handled before the effect observes it.\n const activeFitState =\n fitState.key === fitKey\n ? fitState\n : createInitialFitState(fitKey, fitState.handledRequestVersion);\n const fitAttemptsRef = useRef({key: '', count: 0});\n\n useEffect(() => {\n if (!container) return;\n const updateSize = () =>\n setContainerSize({\n width: container.clientWidth,\n height: container.clientHeight,\n });\n updateSize();\n if (typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(updateSize);\n observer.observe(container);\n return () => observer.disconnect();\n }, [container]);\n\n useEffect(() => {\n // Reset retries on source change or Fit click — else exhausted autofit no-ops Fit.\n const attemptsKey = `${fitKey}:${requestVersion}`;\n if (fitAttemptsRef.current.key !== attemptsKey) {\n fitAttemptsRef.current = {key: attemptsKey, count: 0};\n }\n\n const hasManualRequest =\n requestVersion > activeFitState.handledRequestVersion;\n if (\n !fitToData ||\n !source ||\n containerSize.width <= 0 ||\n containerSize.height <= 0 ||\n (!hasManualRequest && (!autoFit || activeFitState.didAutoFit))\n ) {\n return;\n }\n\n let cancelled = false;\n let retryTimer: ReturnType<typeof setTimeout> | undefined;\n const markHandled = () =>\n setFitState({\n key: fitKey,\n didAutoFit: true,\n handledRequestVersion: requestVersion,\n });\n const scheduleRetry = (error?: Error) => {\n fitAttemptsRef.current.count += 1;\n if (fitAttemptsRef.current.count >= FIT_MAX_ATTEMPTS) {\n if (error) onError?.(error);\n markHandled();\n return;\n }\n retryTimer = setTimeout(() => {\n if (!cancelled) setRetryNonce((value) => value + 1);\n }, FIT_RETRY_DELAY_MS);\n };\n\n void (async () => {\n try {\n if (fitToData.h3Column) {\n try {\n await executeSql('INSTALL h3 FROM community');\n } catch {\n // The extension may already be installed.\n }\n await executeSql('LOAD h3');\n }\n const query = createDeckMapBoundsQuery({source, fitToData});\n if (!query) {\n markHandled();\n onSuccess?.();\n return;\n }\n const handle = await executeSql(query);\n const result = handle ? await handle : null;\n if (cancelled) return;\n if (!result) {\n // Empty handle ≈ cancelled query, not a transient race.\n onError?.(\n new Error('Unable to fit map view to data: empty query result.'),\n );\n markHandled();\n return;\n }\n const bounds = readDeckMapBounds(result);\n if (!bounds) {\n // Empty geometry is permanent; only retry H3 cold-start.\n if (fitToData.h3Column) {\n scheduleRetry(\n new Error(\n 'Unable to fit map view to H3 data. Check that the hexagon column contains valid H3 indexes.',\n ),\n );\n return;\n }\n onError?.(new Error('Unable to determine map bounds from data.'));\n markHandled();\n return;\n }\n deckMapRef.current?.jumpTo(\n fitDeckMapView({\n bounds,\n width: containerSize.width,\n height: containerSize.height,\n padding: fitToData.padding,\n maxZoom: fitToData.maxZoom,\n }),\n );\n markHandled();\n onSuccess?.();\n } catch (error) {\n if (cancelled) return;\n const fitError =\n error instanceof Error\n ? error\n : new Error('Unable to fit map view to data.');\n // Retry only likely-transient H3 extension races.\n const message = fitError.message.toLowerCase();\n const maybeTransientH3 =\n Boolean(fitToData.h3Column) &&\n (message.includes('h3') ||\n message.includes('extension') ||\n message.includes('not loaded') ||\n message.includes('catalog'));\n if (maybeTransientH3) {\n scheduleRetry(fitError);\n return;\n }\n onError?.(fitError);\n markHandled();\n }\n })();\n\n return () => {\n cancelled = true;\n if (retryTimer) clearTimeout(retryTimer);\n };\n }, [\n activeFitState.didAutoFit,\n activeFitState.handledRequestVersion,\n autoFit,\n containerSize.height,\n containerSize.width,\n deckMapRef,\n executeSql,\n fitKey,\n fitToData,\n onError,\n onSuccess,\n requestVersion,\n retryNonce,\n source,\n ]);\n}\n"]}
@@ -7,7 +7,7 @@ export type DeckMapLayerColorScaleFunction = ColorScaleConfig & {
7
7
  };
8
8
  export type DeckMapLayerColorAccessor = 'getFillColor' | 'getLineColor' | 'getColor' | 'getSourceColor' | 'getTargetColor';
9
9
  export declare const DECK_MAP_LAYER_TYPE_OPTIONS: ReadonlyArray<{
10
- value: DeckAutoLayerType | 'GeoArrowSolidPolygonLayer';
10
+ value: DeckAutoLayerType;
11
11
  label: string;
12
12
  }>;
13
13
  export declare const DECK_MAP_COLOR_ACCESSOR_OPTIONS: ReadonlyArray<{
@@ -31,6 +31,14 @@ export declare function usesExtrusionSettings(layerType: unknown): boolean;
31
31
  export declare function getDeckMapColorAccessorOptions(layerType: unknown): typeof DECK_MAP_COLOR_ACCESSOR_OPTIONS;
32
32
  export declare function updateDeckMapLayer(config: DeckMapConfig, layerIndex: number, updater: (layer: DeckMapLayerRecord) => DeckMapLayerRecord): DeckMapConfig;
33
33
  export declare function setDeckMapLayerType(config: DeckMapConfig, layerIndex: number, layerType: string): DeckMapConfig;
34
+ /** Force meters and strip point/heatmap radius leftovers (does not set `radius`). */
35
+ export declare function stripDeckMapColumnLayerRadiusConflicts(layer: DeckMapLayerRecord): DeckMapLayerRecord;
36
+ /** True when ColumnLayer still carries point/heatmap radius props or pixel units. */
37
+ export declare function deckMapColumnLayerHasRadiusConflicts(layer: DeckMapLayerRecord): boolean;
38
+ /** Apply a column radius in meters and strip conflicting point/heatmap radius props. */
39
+ export declare function applyDeckMapColumnRadiusMeters(layer: DeckMapLayerRecord, radiusMeters: number): DeckMapLayerRecord;
40
+ /** Set GeoArrowColumnLayer disk radius in meters. */
41
+ export declare function setDeckMapLayerColumnRadius(config: DeckMapConfig, layerIndex: number, radiusMeters: number): DeckMapConfig;
34
42
  export declare function setDeckMapLayerGeometryColumn(config: DeckMapConfig, layerIndex: number, geometryColumn: string): DeckMapConfig;
35
43
  export declare function setDeckMapLayerHexagonColumn(config: DeckMapConfig, layerIndex: number, hexagonColumn: string): DeckMapConfig;
36
44
  export declare function setDeckMapLayerArcColumns(config: DeckMapConfig, layerIndex: number, columns: {
@@ -1 +1 @@
1
- {"version":3,"file":"mapLayerConfigUtils.d.ts","sourceRoot":"","sources":["../src/mapLayerConfigUtils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mapLayerConfigUtils.d.ts","sourceRoot":"","sources":["../src/mapLayerConfigUtils.ts"],"names":[],"mappings":"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"}