@sqlrooms/deck 0.29.0-rc.10
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.md +10 -0
- package/README.md +654 -0
- package/dist/BlockMapSettings.d.ts +3 -0
- package/dist/BlockMapSettings.d.ts.map +1 -0
- package/dist/BlockMapSettings.js +57 -0
- package/dist/BlockMapSettings.js.map +1 -0
- package/dist/DashboardMapSettings.d.ts +7 -0
- package/dist/DashboardMapSettings.d.ts.map +1 -0
- package/dist/DashboardMapSettings.js +52 -0
- package/dist/DashboardMapSettings.js.map +1 -0
- package/dist/DeckJsonMap.d.ts +4 -0
- package/dist/DeckJsonMap.d.ts.map +1 -0
- package/dist/DeckJsonMap.js +370 -0
- package/dist/DeckJsonMap.js.map +1 -0
- package/dist/DeckJsonMapSpec.d.ts +7617 -0
- package/dist/DeckJsonMapSpec.d.ts.map +1 -0
- package/dist/DeckJsonMapSpec.js +82 -0
- package/dist/DeckJsonMapSpec.js.map +1 -0
- package/dist/DeckMapDefaultStylesProvider.d.ts +28 -0
- package/dist/DeckMapDefaultStylesProvider.d.ts.map +1 -0
- package/dist/DeckMapDefaultStylesProvider.js +23 -0
- package/dist/DeckMapDefaultStylesProvider.js.map +1 -0
- package/dist/DeckMapSurface.d.ts +39 -0
- package/dist/DeckMapSurface.d.ts.map +1 -0
- package/dist/DeckMapSurface.js +137 -0
- package/dist/DeckMapSurface.js.map +1 -0
- package/dist/DeckMapsSlice.d.ts +99 -0
- package/dist/DeckMapsSlice.d.ts.map +1 -0
- package/dist/DeckMapsSlice.js +89 -0
- package/dist/DeckMapsSlice.js.map +1 -0
- package/dist/MapSettings.d.ts +16 -0
- package/dist/MapSettings.d.ts.map +1 -0
- package/dist/MapSettings.js +292 -0
- package/dist/MapSettings.js.map +1 -0
- package/dist/MapSettingsControls.d.ts +40 -0
- package/dist/MapSettingsControls.d.ts.map +1 -0
- package/dist/MapSettingsControls.js +54 -0
- package/dist/MapSettingsControls.js.map +1 -0
- package/dist/ai.d.ts +261 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +392 -0
- package/dist/ai.js.map +1 -0
- package/dist/block.d.ts +21 -0
- package/dist/block.d.ts.map +1 -0
- package/dist/block.js +105 -0
- package/dist/block.js.map +1 -0
- package/dist/blockDocumentRegistration.d.ts +45 -0
- package/dist/blockDocumentRegistration.d.ts.map +1 -0
- package/dist/blockDocumentRegistration.js +68 -0
- package/dist/blockDocumentRegistration.js.map +1 -0
- package/dist/createDeckJsonSpecFromDatasets.d.ts +11 -0
- package/dist/createDeckJsonSpecFromDatasets.d.ts.map +1 -0
- package/dist/createDeckJsonSpecFromDatasets.js +85 -0
- package/dist/createDeckJsonSpecFromDatasets.js.map +1 -0
- package/dist/createOrUpdateDeckMapResource.d.ts +81 -0
- package/dist/createOrUpdateDeckMapResource.d.ts.map +1 -0
- package/dist/createOrUpdateDeckMapResource.js +82 -0
- package/dist/createOrUpdateDeckMapResource.js.map +1 -0
- package/dist/dashboard.d.ts +6 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/dashboard.js +337 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/dashboardConfig.d.ts +25 -0
- package/dist/dashboardConfig.d.ts.map +1 -0
- package/dist/dashboardConfig.js +82 -0
- package/dist/dashboardConfig.js.map +1 -0
- package/dist/dashboardIntegration.d.ts +3 -0
- package/dist/dashboardIntegration.d.ts.map +1 -0
- package/dist/dashboardIntegration.js +16 -0
- package/dist/dashboardIntegration.js.map +1 -0
- package/dist/datasetSourceUtils.d.ts +16 -0
- package/dist/datasetSourceUtils.d.ts.map +1 -0
- package/dist/datasetSourceUtils.js +25 -0
- package/dist/datasetSourceUtils.js.map +1 -0
- package/dist/datasets/PreparedDatasetStore.d.ts +120 -0
- package/dist/datasets/PreparedDatasetStore.d.ts.map +1 -0
- package/dist/datasets/PreparedDatasetStore.js +268 -0
- package/dist/datasets/PreparedDatasetStore.js.map +1 -0
- package/dist/datasets/helpers.d.ts +57 -0
- package/dist/datasets/helpers.d.ts.map +1 -0
- package/dist/datasets/helpers.js +155 -0
- package/dist/datasets/helpers.js.map +1 -0
- package/dist/datasets/normalizeDatasets.d.ts +11 -0
- package/dist/datasets/normalizeDatasets.d.ts.map +1 -0
- package/dist/datasets/normalizeDatasets.js +50 -0
- package/dist/datasets/normalizeDatasets.js.map +1 -0
- package/dist/datasets/tableAdapter.d.ts +11 -0
- package/dist/datasets/tableAdapter.d.ts.map +1 -0
- package/dist/datasets/tableAdapter.js +11 -0
- package/dist/datasets/tableAdapter.js.map +1 -0
- package/dist/datasets/tableDatasetSql.d.ts +16 -0
- package/dist/datasets/tableDatasetSql.d.ts.map +1 -0
- package/dist/datasets/tableDatasetSql.js +49 -0
- package/dist/datasets/tableDatasetSql.js.map +1 -0
- package/dist/datasets/types.d.ts +40 -0
- package/dist/datasets/types.d.ts.map +1 -0
- package/dist/datasets/types.js +2 -0
- package/dist/datasets/types.js.map +1 -0
- package/dist/datasets/usePreparedDatasetStates.d.ts +16 -0
- package/dist/datasets/usePreparedDatasetStates.d.ts.map +1 -0
- package/dist/datasets/usePreparedDatasetStates.js +59 -0
- package/dist/datasets/usePreparedDatasetStates.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/json/aggregateWaypoints.d.ts +14 -0
- package/dist/json/aggregateWaypoints.d.ts.map +1 -0
- package/dist/json/aggregateWaypoints.js +190 -0
- package/dist/json/aggregateWaypoints.js.map +1 -0
- package/dist/json/colorScaleFunction.d.ts +27 -0
- package/dist/json/colorScaleFunction.d.ts.map +1 -0
- package/dist/json/colorScaleFunction.js +46 -0
- package/dist/json/colorScaleFunction.js.map +1 -0
- package/dist/json/compileColorScale.d.ts +12 -0
- package/dist/json/compileColorScale.d.ts.map +1 -0
- package/dist/json/compileColorScale.js +125 -0
- package/dist/json/compileColorScale.js.map +1 -0
- package/dist/json/compileGeoArrowAccessor.d.ts +18 -0
- package/dist/json/compileGeoArrowAccessor.d.ts.map +1 -0
- package/dist/json/compileGeoArrowAccessor.js +129 -0
- package/dist/json/compileGeoArrowAccessor.js.map +1 -0
- package/dist/json/createDeckJsonConfiguration.d.ts +9 -0
- package/dist/json/createDeckJsonConfiguration.d.ts.map +1 -0
- package/dist/json/createDeckJsonConfiguration.js +315 -0
- package/dist/json/createDeckJsonConfiguration.js.map +1 -0
- package/dist/json/defaultClasses.d.ts +12 -0
- package/dist/json/defaultClasses.d.ts.map +1 -0
- package/dist/json/defaultClasses.js +35 -0
- package/dist/json/defaultClasses.js.map +1 -0
- package/dist/json/extractColorScaleLegends.d.ts +8 -0
- package/dist/json/extractColorScaleLegends.d.ts.map +1 -0
- package/dist/json/extractColorScaleLegends.js +86 -0
- package/dist/json/extractColorScaleLegends.js.map +1 -0
- package/dist/json/heatmapDefaults.d.ts +8 -0
- package/dist/json/heatmapDefaults.d.ts.map +1 -0
- package/dist/json/heatmapDefaults.js +14 -0
- package/dist/json/heatmapDefaults.js.map +1 -0
- package/dist/json/layerCompatibility.d.ts +21 -0
- package/dist/json/layerCompatibility.d.ts.map +1 -0
- package/dist/json/layerCompatibility.js +168 -0
- package/dist/json/layerCompatibility.js.map +1 -0
- package/dist/json/layerConfig.d.ts +14 -0
- package/dist/json/layerConfig.d.ts.map +1 -0
- package/dist/json/layerConfig.js +54 -0
- package/dist/json/layerConfig.js.map +1 -0
- package/dist/json/layers/DeckColumnLayer.d.ts +10 -0
- package/dist/json/layers/DeckColumnLayer.d.ts.map +1 -0
- package/dist/json/layers/DeckColumnLayer.js +26 -0
- package/dist/json/layers/DeckColumnLayer.js.map +1 -0
- package/dist/json/layers/DeckH3HexagonLayer.d.ts +37 -0
- package/dist/json/layers/DeckH3HexagonLayer.d.ts.map +1 -0
- package/dist/json/layers/DeckH3HexagonLayer.js +118 -0
- package/dist/json/layers/DeckH3HexagonLayer.js.map +1 -0
- package/dist/json/layers/DeckTripsLayer.d.ts +46 -0
- package/dist/json/layers/DeckTripsLayer.d.ts.map +1 -0
- package/dist/json/layers/DeckTripsLayer.js +170 -0
- package/dist/json/layers/DeckTripsLayer.js.map +1 -0
- package/dist/json/layers/createTableToRecordBatchAdapter.d.ts +20 -0
- package/dist/json/layers/createTableToRecordBatchAdapter.d.ts.map +1 -0
- package/dist/json/layers/createTableToRecordBatchAdapter.js +81 -0
- package/dist/json/layers/createTableToRecordBatchAdapter.js.map +1 -0
- package/dist/json/layers/index.d.ts +5 -0
- package/dist/json/layers/index.d.ts.map +1 -0
- package/dist/json/layers/index.js +5 -0
- package/dist/json/layers/index.js.map +1 -0
- package/dist/json/rewriteGeoArrowAccessors.d.ts +7 -0
- package/dist/json/rewriteGeoArrowAccessors.d.ts.map +1 -0
- package/dist/json/rewriteGeoArrowAccessors.js +55 -0
- package/dist/json/rewriteGeoArrowAccessors.js.map +1 -0
- package/dist/mapAiConfig.d.ts +111 -0
- package/dist/mapAiConfig.d.ts.map +1 -0
- package/dist/mapAiConfig.js +69 -0
- package/dist/mapAiConfig.js.map +1 -0
- package/dist/mapConfig.d.ts +73 -0
- package/dist/mapConfig.d.ts.map +1 -0
- package/dist/mapConfig.js +47 -0
- package/dist/mapConfig.js.map +1 -0
- package/dist/mapConfigUtils.d.ts +111 -0
- package/dist/mapConfigUtils.d.ts.map +1 -0
- package/dist/mapConfigUtils.js +502 -0
- package/dist/mapConfigUtils.js.map +1 -0
- package/dist/mapDataPolicy.d.ts +9 -0
- package/dist/mapDataPolicy.d.ts.map +1 -0
- package/dist/mapDataPolicy.js +25 -0
- package/dist/mapDataPolicy.js.map +1 -0
- package/dist/mapFit.d.ts +62 -0
- package/dist/mapFit.d.ts.map +1 -0
- package/dist/mapFit.js +325 -0
- package/dist/mapFit.js.map +1 -0
- package/dist/mapLayerConfigUtils.d.ts +54 -0
- package/dist/mapLayerConfigUtils.d.ts.map +1 -0
- package/dist/mapLayerConfigUtils.js +296 -0
- package/dist/mapLayerConfigUtils.js.map +1 -0
- package/dist/mapResourceAuthoring.d.ts +40 -0
- package/dist/mapResourceAuthoring.d.ts.map +1 -0
- package/dist/mapResourceAuthoring.js +266 -0
- package/dist/mapResourceAuthoring.js.map +1 -0
- package/dist/mosaic.d.ts +9 -0
- package/dist/mosaic.d.ts.map +1 -0
- package/dist/mosaic.js +8 -0
- package/dist/mosaic.js.map +1 -0
- package/dist/prepare/detectGeometryColumn.d.ts +19 -0
- package/dist/prepare/detectGeometryColumn.d.ts.map +1 -0
- package/dist/prepare/detectGeometryColumn.js +126 -0
- package/dist/prepare/detectGeometryColumn.js.map +1 -0
- package/dist/prepare/geoarrow.d.ts +18 -0
- package/dist/prepare/geoarrow.d.ts.map +1 -0
- package/dist/prepare/geoarrow.js +114 -0
- package/dist/prepare/geoarrow.js.map +1 -0
- package/dist/prepare/geometryDecoder.d.ts +8 -0
- package/dist/prepare/geometryDecoder.d.ts.map +1 -0
- package/dist/prepare/geometryDecoder.js +2 -0
- package/dist/prepare/geometryDecoder.js.map +1 -0
- package/dist/prepare/prepareDeckDataset.d.ts +57 -0
- package/dist/prepare/prepareDeckDataset.d.ts.map +1 -0
- package/dist/prepare/prepareDeckDataset.js +112 -0
- package/dist/prepare/prepareDeckDataset.js.map +1 -0
- package/dist/prepare/toGeoJsonBinary.d.ts +9 -0
- package/dist/prepare/toGeoJsonBinary.d.ts.map +1 -0
- package/dist/prepare/toGeoJsonBinary.js +26 -0
- package/dist/prepare/toGeoJsonBinary.js.map +1 -0
- package/dist/prepare/types.d.ts +25 -0
- package/dist/prepare/types.d.ts.map +1 -0
- package/dist/prepare/types.js +2 -0
- package/dist/prepare/types.js.map +1 -0
- package/dist/prepare/wkbDecoder.d.ts +3 -0
- package/dist/prepare/wkbDecoder.d.ts.map +1 -0
- package/dist/prepare/wkbDecoder.js +419 -0
- package/dist/prepare/wkbDecoder.js.map +1 -0
- package/dist/prepare/wkbParser.d.ts +24 -0
- package/dist/prepare/wkbParser.d.ts.map +1 -0
- package/dist/prepare/wkbParser.js +139 -0
- package/dist/prepare/wkbParser.js.map +1 -0
- package/dist/types.d.ts +92 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/dist/useDeckMapDatasetSchema.d.ts +33 -0
- package/dist/useDeckMapDatasetSchema.d.ts.map +1 -0
- package/dist/useDeckMapDatasetSchema.js +138 -0
- package/dist/useDeckMapDatasetSchema.js.map +1 -0
- package/dist/useDeckMapDatasets.d.ts +17 -0
- package/dist/useDeckMapDatasets.d.ts.map +1 -0
- package/dist/useDeckMapDatasets.js +69 -0
- package/dist/useDeckMapDatasets.js.map +1 -0
- package/dist/useDeckMapFitToBounds.d.ts +31 -0
- package/dist/useDeckMapFitToBounds.d.ts.map +1 -0
- package/dist/useDeckMapFitToBounds.js +58 -0
- package/dist/useDeckMapFitToBounds.js.map +1 -0
- package/package.json +98 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregateWaypoints.d.ts","sourceRoot":"","sources":["../../src/json/aggregateWaypoints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AA0DtC;;;;;;;GAOG;AACH,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,KAAK,CAAC,KAAK,GACjB;IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IAAC,cAAc,EAAE,KAAK,CAAC,MAAM,CAAA;CAAC,GAAG,IAAI,CAgJ3D"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import * as arrow from 'apache-arrow';
|
|
2
|
+
import { findCoordinateColumns } from '../prepare/detectGeometryColumn';
|
|
3
|
+
const GROUP_ID_PATTERNS = [
|
|
4
|
+
'path_id',
|
|
5
|
+
'route_id',
|
|
6
|
+
'trip_id',
|
|
7
|
+
'track_id',
|
|
8
|
+
'line_id',
|
|
9
|
+
'segment_id',
|
|
10
|
+
'id',
|
|
11
|
+
'path',
|
|
12
|
+
'route',
|
|
13
|
+
'trip',
|
|
14
|
+
'track',
|
|
15
|
+
];
|
|
16
|
+
const ORDER_PATTERNS = [
|
|
17
|
+
'waypoint_order',
|
|
18
|
+
'point_order',
|
|
19
|
+
'order',
|
|
20
|
+
'sequence',
|
|
21
|
+
'seq',
|
|
22
|
+
'waypoint',
|
|
23
|
+
'index',
|
|
24
|
+
'step',
|
|
25
|
+
'position',
|
|
26
|
+
'sort',
|
|
27
|
+
];
|
|
28
|
+
const TIMESTAMP_PATTERNS = [
|
|
29
|
+
'timestamp',
|
|
30
|
+
'timestamps',
|
|
31
|
+
'time',
|
|
32
|
+
't',
|
|
33
|
+
'elapsed',
|
|
34
|
+
'seconds',
|
|
35
|
+
'ms',
|
|
36
|
+
];
|
|
37
|
+
function findColumnByPatterns(fieldNames, patterns) {
|
|
38
|
+
const lower = fieldNames.map((n) => n.toLowerCase());
|
|
39
|
+
for (const pattern of patterns) {
|
|
40
|
+
const idx = lower.indexOf(pattern);
|
|
41
|
+
if (idx >= 0)
|
|
42
|
+
return fieldNames[idx];
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
function findLatLonColumns(table) {
|
|
47
|
+
const result = findCoordinateColumns(table);
|
|
48
|
+
if (!result)
|
|
49
|
+
return null;
|
|
50
|
+
return { lat: result.latField, lon: result.lonField };
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Auto-aggregates per-waypoint rows into LineString vectors for PathLayer.
|
|
54
|
+
* Detects group-by ID and order columns by naming patterns, groups rows,
|
|
55
|
+
* and builds a GeoArrow List<FixedSizeList<2, Float64>> linestring vector.
|
|
56
|
+
*
|
|
57
|
+
* Also builds a timestamps list column if a timestamp-like column is found,
|
|
58
|
+
* suitable for GeoArrowTripsLayer.
|
|
59
|
+
*/
|
|
60
|
+
export function tryAggregateWaypointsToLineStrings(table) {
|
|
61
|
+
const fieldNames = table.schema.fields.map((f) => f.name);
|
|
62
|
+
const groupCol = findColumnByPatterns(fieldNames, GROUP_ID_PATTERNS);
|
|
63
|
+
if (!groupCol)
|
|
64
|
+
return null;
|
|
65
|
+
const coords = findLatLonColumns(table);
|
|
66
|
+
if (!coords)
|
|
67
|
+
return null;
|
|
68
|
+
const orderCol = findColumnByPatterns(fieldNames, ORDER_PATTERNS);
|
|
69
|
+
const groupVector = table.getChild(groupCol);
|
|
70
|
+
const latVector = table.getChild(coords.lat);
|
|
71
|
+
const lonVector = table.getChild(coords.lon);
|
|
72
|
+
const orderVector = orderCol ? table.getChild(orderCol) : null;
|
|
73
|
+
// Collect rows per group
|
|
74
|
+
const groups = new Map();
|
|
75
|
+
const groupOrder = [];
|
|
76
|
+
for (let i = 0; i < table.numRows; i++) {
|
|
77
|
+
const key = String(groupVector.get(i) ?? '');
|
|
78
|
+
let group = groups.get(key);
|
|
79
|
+
if (!group) {
|
|
80
|
+
group = { indices: [] };
|
|
81
|
+
groups.set(key, group);
|
|
82
|
+
groupOrder.push(key);
|
|
83
|
+
}
|
|
84
|
+
group.indices.push(i);
|
|
85
|
+
}
|
|
86
|
+
// Sort indices within each group by order column
|
|
87
|
+
if (orderVector) {
|
|
88
|
+
for (const group of groups.values()) {
|
|
89
|
+
group.indices.sort((a, b) => {
|
|
90
|
+
const av = Number(orderVector.get(a)) || 0;
|
|
91
|
+
const bv = Number(orderVector.get(b)) || 0;
|
|
92
|
+
return av - bv;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const numPaths = groupOrder.length;
|
|
97
|
+
const offsets = new Int32Array(numPaths + 1);
|
|
98
|
+
let totalPoints = 0;
|
|
99
|
+
for (let g = 0; g < numPaths; g++) {
|
|
100
|
+
offsets[g] = totalPoints;
|
|
101
|
+
totalPoints += groups.get(groupOrder[g]).indices.length;
|
|
102
|
+
}
|
|
103
|
+
offsets[numPaths] = totalPoints;
|
|
104
|
+
const flatCoords = new Float64Array(totalPoints * 2);
|
|
105
|
+
let writeIdx = 0;
|
|
106
|
+
for (const key of groupOrder) {
|
|
107
|
+
for (const rowIdx of groups.get(key).indices) {
|
|
108
|
+
flatCoords[writeIdx++] = Number(lonVector.get(rowIdx)) || 0;
|
|
109
|
+
flatCoords[writeIdx++] = Number(latVector.get(rowIdx)) || 0;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Build GeoArrow LineString vector: List<FixedSizeList<2, Float64>>
|
|
113
|
+
const coordField = new arrow.Field('xy', new arrow.Float64(), false);
|
|
114
|
+
const vertexType = new arrow.FixedSizeList(2, coordField);
|
|
115
|
+
const vertexField = new arrow.Field('', vertexType, true);
|
|
116
|
+
const lineStringType = new arrow.List(vertexField);
|
|
117
|
+
const floatData = arrow.makeData({
|
|
118
|
+
type: new arrow.Float64(),
|
|
119
|
+
length: totalPoints * 2,
|
|
120
|
+
data: flatCoords,
|
|
121
|
+
});
|
|
122
|
+
const vertexData = arrow.makeData({
|
|
123
|
+
type: vertexType,
|
|
124
|
+
length: totalPoints,
|
|
125
|
+
child: floatData,
|
|
126
|
+
});
|
|
127
|
+
const lineData = arrow.makeData({
|
|
128
|
+
type: lineStringType,
|
|
129
|
+
length: numPaths,
|
|
130
|
+
valueOffsets: offsets,
|
|
131
|
+
child: vertexData,
|
|
132
|
+
});
|
|
133
|
+
const geometryVector = new arrow.Vector([lineData]);
|
|
134
|
+
// Build aggregated table with one row per path (first row's non-geom values)
|
|
135
|
+
const columns = {};
|
|
136
|
+
const timestampCol = findColumnByPatterns(fieldNames, TIMESTAMP_PATTERNS);
|
|
137
|
+
const excludeCols = new Set([coords.lat, coords.lon, orderCol, timestampCol].filter(Boolean));
|
|
138
|
+
for (const field of table.schema.fields) {
|
|
139
|
+
if (excludeCols.has(field.name))
|
|
140
|
+
continue;
|
|
141
|
+
const srcVector = table.getChild(field.name);
|
|
142
|
+
const values = [];
|
|
143
|
+
for (const key of groupOrder) {
|
|
144
|
+
const firstIdx = groups.get(key).indices[0];
|
|
145
|
+
values.push(srcVector.get(firstIdx));
|
|
146
|
+
}
|
|
147
|
+
columns[field.name] = arrow.vectorFromArray(values);
|
|
148
|
+
}
|
|
149
|
+
columns['__geom'] = geometryVector;
|
|
150
|
+
// Build timestamps list column if a timestamp column exists.
|
|
151
|
+
// Must be a proper Arrow List<Float64> vector for GeoArrowTripsLayer.
|
|
152
|
+
if (timestampCol) {
|
|
153
|
+
const tsVector = table.getChild(timestampCol);
|
|
154
|
+
const tsOffsets = new Int32Array(numPaths + 1);
|
|
155
|
+
let tsTotalValues = 0;
|
|
156
|
+
for (let g = 0; g < numPaths; g++) {
|
|
157
|
+
tsOffsets[g] = tsTotalValues;
|
|
158
|
+
tsTotalValues += groups.get(groupOrder[g]).indices.length;
|
|
159
|
+
}
|
|
160
|
+
tsOffsets[numPaths] = tsTotalValues;
|
|
161
|
+
const tsFlat = new Float64Array(tsTotalValues);
|
|
162
|
+
let tsWriteIdx = 0;
|
|
163
|
+
for (const key of groupOrder) {
|
|
164
|
+
for (const rowIdx of groups.get(key).indices) {
|
|
165
|
+
tsFlat[tsWriteIdx++] = Number(tsVector.get(rowIdx)) || 0;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const tsValueField = new arrow.Field('', new arrow.Float64(), true);
|
|
169
|
+
const tsListType = new arrow.List(tsValueField);
|
|
170
|
+
const tsValuesData = arrow.makeData({
|
|
171
|
+
type: new arrow.Float64(),
|
|
172
|
+
length: tsTotalValues,
|
|
173
|
+
data: tsFlat,
|
|
174
|
+
});
|
|
175
|
+
const tsListData = arrow.makeData({
|
|
176
|
+
type: tsListType,
|
|
177
|
+
length: numPaths,
|
|
178
|
+
valueOffsets: tsOffsets,
|
|
179
|
+
child: tsValuesData,
|
|
180
|
+
});
|
|
181
|
+
const tsListVector = new arrow.Vector([tsListData]);
|
|
182
|
+
columns[timestampCol] = tsListVector;
|
|
183
|
+
if (timestampCol !== 'timestamps') {
|
|
184
|
+
columns['timestamps'] = tsListVector;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const aggregatedTable = new arrow.Table(columns);
|
|
188
|
+
return { table: aggregatedTable, geometryVector };
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=aggregateWaypoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregateWaypoints.js","sourceRoot":"","sources":["../../src/json/aggregateWaypoints.ts"],"names":[],"mappings":"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","sourcesContent":["import * as arrow from 'apache-arrow';\nimport {findCoordinateColumns} from '../prepare/detectGeometryColumn';\n\nconst GROUP_ID_PATTERNS = [\n 'path_id',\n 'route_id',\n 'trip_id',\n 'track_id',\n 'line_id',\n 'segment_id',\n 'id',\n 'path',\n 'route',\n 'trip',\n 'track',\n];\nconst ORDER_PATTERNS = [\n 'waypoint_order',\n 'point_order',\n 'order',\n 'sequence',\n 'seq',\n 'waypoint',\n 'index',\n 'step',\n 'position',\n 'sort',\n];\nconst TIMESTAMP_PATTERNS = [\n 'timestamp',\n 'timestamps',\n 'time',\n 't',\n 'elapsed',\n 'seconds',\n 'ms',\n];\n\nfunction findColumnByPatterns(\n fieldNames: string[],\n patterns: string[],\n): string | undefined {\n const lower = fieldNames.map((n) => n.toLowerCase());\n for (const pattern of patterns) {\n const idx = lower.indexOf(pattern);\n if (idx >= 0) return fieldNames[idx];\n }\n return undefined;\n}\n\nfunction findLatLonColumns(\n table: arrow.Table,\n): {lat: string; lon: string} | null {\n const result = findCoordinateColumns(table);\n if (!result) return null;\n return {lat: result.latField, lon: result.lonField};\n}\n\n/**\n * Auto-aggregates per-waypoint rows into LineString vectors for PathLayer.\n * Detects group-by ID and order columns by naming patterns, groups rows,\n * and builds a GeoArrow List<FixedSizeList<2, Float64>> linestring vector.\n *\n * Also builds a timestamps list column if a timestamp-like column is found,\n * suitable for GeoArrowTripsLayer.\n */\nexport function tryAggregateWaypointsToLineStrings(\n table: arrow.Table,\n): {table: arrow.Table; geometryVector: arrow.Vector} | null {\n const fieldNames = table.schema.fields.map((f) => f.name);\n const groupCol = findColumnByPatterns(fieldNames, GROUP_ID_PATTERNS);\n if (!groupCol) return null;\n\n const coords = findLatLonColumns(table);\n if (!coords) return null;\n\n const orderCol = findColumnByPatterns(fieldNames, ORDER_PATTERNS);\n\n const groupVector = table.getChild(groupCol)!;\n const latVector = table.getChild(coords.lat)!;\n const lonVector = table.getChild(coords.lon)!;\n const orderVector = orderCol ? table.getChild(orderCol) : null;\n\n // Collect rows per group\n const groups = new Map<string, {indices: number[]}>();\n const groupOrder: string[] = [];\n for (let i = 0; i < table.numRows; i++) {\n const key = String(groupVector.get(i) ?? '');\n let group = groups.get(key);\n if (!group) {\n group = {indices: []};\n groups.set(key, group);\n groupOrder.push(key);\n }\n group.indices.push(i);\n }\n\n // Sort indices within each group by order column\n if (orderVector) {\n for (const group of groups.values()) {\n group.indices.sort((a, b) => {\n const av = Number(orderVector.get(a)) || 0;\n const bv = Number(orderVector.get(b)) || 0;\n return av - bv;\n });\n }\n }\n\n const numPaths = groupOrder.length;\n const offsets = new Int32Array(numPaths + 1);\n let totalPoints = 0;\n\n for (let g = 0; g < numPaths; g++) {\n offsets[g] = totalPoints;\n totalPoints += groups.get(groupOrder[g]!)!.indices.length;\n }\n offsets[numPaths] = totalPoints;\n\n const flatCoords = new Float64Array(totalPoints * 2);\n let writeIdx = 0;\n for (const key of groupOrder) {\n for (const rowIdx of groups.get(key)!.indices) {\n flatCoords[writeIdx++] = Number(lonVector.get(rowIdx)) || 0;\n flatCoords[writeIdx++] = Number(latVector.get(rowIdx)) || 0;\n }\n }\n\n // Build GeoArrow LineString vector: List<FixedSizeList<2, Float64>>\n const coordField = new arrow.Field('xy', new arrow.Float64(), false);\n const vertexType = new arrow.FixedSizeList(2, coordField);\n const vertexField = new arrow.Field('', vertexType, true);\n const lineStringType = new arrow.List(vertexField);\n\n const floatData = arrow.makeData({\n type: new arrow.Float64(),\n length: totalPoints * 2,\n data: flatCoords,\n });\n const vertexData = arrow.makeData({\n type: vertexType,\n length: totalPoints,\n child: floatData,\n });\n const lineData = arrow.makeData({\n type: lineStringType,\n length: numPaths,\n valueOffsets: offsets,\n child: vertexData,\n });\n const geometryVector = new arrow.Vector([lineData]);\n\n // Build aggregated table with one row per path (first row's non-geom values)\n const columns: Record<string, arrow.Vector> = {};\n const timestampCol = findColumnByPatterns(fieldNames, TIMESTAMP_PATTERNS);\n const excludeCols = new Set(\n [coords.lat, coords.lon, orderCol, timestampCol].filter(Boolean),\n );\n\n for (const field of table.schema.fields) {\n if (excludeCols.has(field.name)) continue;\n const srcVector = table.getChild(field.name)!;\n const values: unknown[] = [];\n for (const key of groupOrder) {\n const firstIdx = groups.get(key)!.indices[0]!;\n values.push(srcVector.get(firstIdx));\n }\n columns[field.name] = arrow.vectorFromArray(values);\n }\n columns['__geom'] = geometryVector;\n\n // Build timestamps list column if a timestamp column exists.\n // Must be a proper Arrow List<Float64> vector for GeoArrowTripsLayer.\n if (timestampCol) {\n const tsVector = table.getChild(timestampCol)!;\n const tsOffsets = new Int32Array(numPaths + 1);\n let tsTotalValues = 0;\n for (let g = 0; g < numPaths; g++) {\n tsOffsets[g] = tsTotalValues;\n tsTotalValues += groups.get(groupOrder[g]!)!.indices.length;\n }\n tsOffsets[numPaths] = tsTotalValues;\n\n const tsFlat = new Float64Array(tsTotalValues);\n let tsWriteIdx = 0;\n for (const key of groupOrder) {\n for (const rowIdx of groups.get(key)!.indices) {\n tsFlat[tsWriteIdx++] = Number(tsVector.get(rowIdx)) || 0;\n }\n }\n\n const tsValueField = new arrow.Field('', new arrow.Float64(), true);\n const tsListType = new arrow.List(tsValueField);\n const tsValuesData = arrow.makeData({\n type: new arrow.Float64(),\n length: tsTotalValues,\n data: tsFlat,\n });\n const tsListData = arrow.makeData({\n type: tsListType,\n length: numPaths,\n valueOffsets: tsOffsets,\n child: tsValuesData,\n });\n const tsListVector = new arrow.Vector([tsListData]);\n columns[timestampCol] = tsListVector;\n if (timestampCol !== 'timestamps') {\n columns['timestamps'] = tsListVector;\n }\n }\n\n const aggregatedTable = new arrow.Table(columns);\n return {table: aggregatedTable, geometryVector};\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ColorScaleConfig } from '@sqlrooms/color-scales';
|
|
2
|
+
declare const SQLROOMS_COLOR_SCALE_MARKER: unique symbol;
|
|
3
|
+
export type ColorScaleMarker = {
|
|
4
|
+
colorScale: ColorScaleConfig;
|
|
5
|
+
[SQLROOMS_COLOR_SCALE_MARKER]: true;
|
|
6
|
+
};
|
|
7
|
+
export declare function createColorScaleMarker(value: ColorScaleConfig): ColorScaleMarker;
|
|
8
|
+
export declare function isColorScaleMarker(value: unknown): value is ColorScaleMarker;
|
|
9
|
+
/** Names of layer accessor props that can carry a color scale. */
|
|
10
|
+
export type ColorScalePropName = 'getFillColor' | 'getLineColor' | 'getColor' | 'getSourceColor' | 'getTargetColor';
|
|
11
|
+
/** All known color accessor prop names. */
|
|
12
|
+
export declare const COLOR_SCALE_PROP_NAMES: readonly ColorScalePropName[];
|
|
13
|
+
/**
|
|
14
|
+
* Returns the first color scale entry found on the layer props, if any.
|
|
15
|
+
* Prefer {@link getAllColorScales} when a layer may define multiple color scale accessors.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getColorScale(props: Record<string, unknown>): {
|
|
18
|
+
propName: ColorScalePropName;
|
|
19
|
+
colorScale: ColorScaleConfig;
|
|
20
|
+
} | undefined;
|
|
21
|
+
/** Returns every color scale entry found across all known accessor props on the layer. */
|
|
22
|
+
export declare function getAllColorScales(props: Record<string, unknown>): Array<{
|
|
23
|
+
propName: ColorScalePropName;
|
|
24
|
+
colorScale: ColorScaleConfig;
|
|
25
|
+
}>;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=colorScaleFunction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colorScaleFunction.d.ts","sourceRoot":"","sources":["../../src/json/colorScaleFunction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAG7D,QAAA,MAAM,2BAA2B,eAEhC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,CAAC,2BAA2B,CAAC,EAAE,IAAI,CAAC;CACrC,CAAC;AAEF,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,gBAAgB,GACtB,gBAAgB,CAKlB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAU5E;AAED,kEAAkE;AAClE,MAAM,MAAM,kBAAkB,GAC1B,cAAc,GACd,cAAc,GACd,UAAU,GACV,gBAAgB,GAChB,gBAAgB,CAAC;AAErB,2CAA2C;AAC3C,eAAO,MAAM,sBAAsB,EAAE,SAAS,kBAAkB,EAM/D,CAAC;AAEF;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACxD;IACE,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,EAAE,gBAAgB,CAAC;CAC9B,GACD,SAAS,CAGZ;AAED,0FAA0F;AAC1F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC;IACvE,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,EAAE,gBAAgB,CAAC;CAC9B,CAAC,CAgBD"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { isColorScaleFunction } from './layerConfig';
|
|
2
|
+
const SQLROOMS_COLOR_SCALE_MARKER = Symbol.for('@sqlrooms/deck/sqlrooms-color-scale');
|
|
3
|
+
export function createColorScaleMarker(value) {
|
|
4
|
+
return {
|
|
5
|
+
colorScale: value,
|
|
6
|
+
[SQLROOMS_COLOR_SCALE_MARKER]: true,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export function isColorScaleMarker(value) {
|
|
10
|
+
return Boolean(value &&
|
|
11
|
+
typeof value === 'object' &&
|
|
12
|
+
value[SQLROOMS_COLOR_SCALE_MARKER] &&
|
|
13
|
+
typeof value.colorScale === 'object' &&
|
|
14
|
+
value.colorScale != null);
|
|
15
|
+
}
|
|
16
|
+
/** All known color accessor prop names. */
|
|
17
|
+
export const COLOR_SCALE_PROP_NAMES = [
|
|
18
|
+
'getFillColor',
|
|
19
|
+
'getLineColor',
|
|
20
|
+
'getColor',
|
|
21
|
+
'getSourceColor',
|
|
22
|
+
'getTargetColor',
|
|
23
|
+
];
|
|
24
|
+
/**
|
|
25
|
+
* Returns the first color scale entry found on the layer props, if any.
|
|
26
|
+
* Prefer {@link getAllColorScales} when a layer may define multiple color scale accessors.
|
|
27
|
+
*/
|
|
28
|
+
export function getColorScale(props) {
|
|
29
|
+
const all = getAllColorScales(props);
|
|
30
|
+
return all.length > 0 ? all[0] : undefined;
|
|
31
|
+
}
|
|
32
|
+
/** Returns every color scale entry found across all known accessor props on the layer. */
|
|
33
|
+
export function getAllColorScales(props) {
|
|
34
|
+
const results = [];
|
|
35
|
+
for (const propName of COLOR_SCALE_PROP_NAMES) {
|
|
36
|
+
const value = props[propName];
|
|
37
|
+
if (isColorScaleMarker(value)) {
|
|
38
|
+
results.push({ propName, colorScale: value.colorScale });
|
|
39
|
+
}
|
|
40
|
+
else if (isColorScaleFunction(value)) {
|
|
41
|
+
results.push({ propName, colorScale: value });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return results;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=colorScaleFunction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colorScaleFunction.js","sourceRoot":"","sources":["../../src/json/colorScaleFunction.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,oBAAoB,EAAC,MAAM,eAAe,CAAC;AAEnD,MAAM,2BAA2B,GAAG,MAAM,CAAC,GAAG,CAC5C,qCAAqC,CACtC,CAAC;AAOF,MAAM,UAAU,sBAAsB,CACpC,KAAuB;IAEvB,OAAO;QACL,UAAU,EAAE,KAAK;QACjB,CAAC,2BAA2B,CAAC,EAAE,IAAI;KACpC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,OAAO,OAAO,CACZ,KAAK;QACL,OAAO,KAAK,KAAK,QAAQ;QACxB,KAAmD,CAClD,2BAA2B,CAC5B;QACD,OAAQ,KAAgC,CAAC,UAAU,KAAK,QAAQ;QAC/D,KAAgC,CAAC,UAAU,IAAI,IAAI,CACrD,CAAC;AACJ,CAAC;AAUD,2CAA2C;AAC3C,MAAM,CAAC,MAAM,sBAAsB,GAAkC;IACnE,cAAc;IACd,cAAc;IACd,UAAU;IACV,gBAAgB;IAChB,gBAAgB;CACjB,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAA8B;IAM1D,MAAM,GAAG,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACrC,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7C,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,iBAAiB,CAAC,KAA8B;IAI9D,MAAM,OAAO,GAGR,EAAE,CAAC;IAER,KAAK,MAAM,QAAQ,IAAI,sBAAsB,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC9B,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,EAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAC,CAAC,CAAC;QACzD,CAAC;aAAM,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;YACvC,OAAO,CAAC,IAAI,CAAC,EAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAC,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["import type {ColorScaleConfig} from '@sqlrooms/color-scales';\nimport {isColorScaleFunction} from './layerConfig';\n\nconst SQLROOMS_COLOR_SCALE_MARKER = Symbol.for(\n '@sqlrooms/deck/sqlrooms-color-scale',\n);\n\nexport type ColorScaleMarker = {\n colorScale: ColorScaleConfig;\n [SQLROOMS_COLOR_SCALE_MARKER]: true;\n};\n\nexport function createColorScaleMarker(\n value: ColorScaleConfig,\n): ColorScaleMarker {\n return {\n colorScale: value,\n [SQLROOMS_COLOR_SCALE_MARKER]: true,\n };\n}\n\nexport function isColorScaleMarker(value: unknown): value is ColorScaleMarker {\n return Boolean(\n value &&\n typeof value === 'object' &&\n (value as {[SQLROOMS_COLOR_SCALE_MARKER]?: boolean})[\n SQLROOMS_COLOR_SCALE_MARKER\n ] &&\n typeof (value as {colorScale?: unknown}).colorScale === 'object' &&\n (value as {colorScale?: unknown}).colorScale != null,\n );\n}\n\n/** Names of layer accessor props that can carry a color scale. */\nexport type ColorScalePropName =\n | 'getFillColor'\n | 'getLineColor'\n | 'getColor'\n | 'getSourceColor'\n | 'getTargetColor';\n\n/** All known color accessor prop names. */\nexport const COLOR_SCALE_PROP_NAMES: readonly ColorScalePropName[] = [\n 'getFillColor',\n 'getLineColor',\n 'getColor',\n 'getSourceColor',\n 'getTargetColor',\n];\n\n/**\n * Returns the first color scale entry found on the layer props, if any.\n * Prefer {@link getAllColorScales} when a layer may define multiple color scale accessors.\n */\nexport function getColorScale(props: Record<string, unknown>):\n | {\n propName: ColorScalePropName;\n colorScale: ColorScaleConfig;\n }\n | undefined {\n const all = getAllColorScales(props);\n return all.length > 0 ? all[0] : undefined;\n}\n\n/** Returns every color scale entry found across all known accessor props on the layer. */\nexport function getAllColorScales(props: Record<string, unknown>): Array<{\n propName: ColorScalePropName;\n colorScale: ColorScaleConfig;\n}> {\n const results: Array<{\n propName: ColorScalePropName;\n colorScale: ColorScaleConfig;\n }> = [];\n\n for (const propName of COLOR_SCALE_PROP_NAMES) {\n const value = props[propName];\n if (isColorScaleMarker(value)) {\n results.push({propName, colorScale: value.colorScale});\n } else if (isColorScaleFunction(value)) {\n results.push({propName, colorScale: value});\n }\n }\n\n return results;\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ColorScaleConfig, type ResolvedColorLegend } from '@sqlrooms/color-scales';
|
|
2
|
+
import type * as arrow from 'apache-arrow';
|
|
3
|
+
export declare function compileColorScale(options: {
|
|
4
|
+
table: arrow.Table;
|
|
5
|
+
colorScale: ColorScaleConfig;
|
|
6
|
+
}): (value: unknown) => import("@sqlrooms/color-scales").ResolvedRGBA;
|
|
7
|
+
export declare function buildColorScaleLegend(options: {
|
|
8
|
+
table: arrow.Table;
|
|
9
|
+
colorScale: ColorScaleConfig;
|
|
10
|
+
title?: string;
|
|
11
|
+
}): ResolvedColorLegend | null;
|
|
12
|
+
//# sourceMappingURL=compileColorScale.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compileColorScale.d.ts","sourceRoot":"","sources":["../../src/json/compileColorScale.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC;AAuH3C,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;CAC9B,WA0BgB,OAAO,mDAEvB;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;IAC7C,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,GAAG,IAAI,CAuB7B"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { buildColorScaleLegend as buildGenericColorScaleLegend, coerceFiniteNumber, createColorScaleMapper, } from '@sqlrooms/color-scales';
|
|
2
|
+
function resolveFieldName(schemaOwner, requestedField) {
|
|
3
|
+
const exactMatch = schemaOwner.schema.fields.find((field) => field.name === requestedField)?.name;
|
|
4
|
+
if (exactMatch) {
|
|
5
|
+
return exactMatch;
|
|
6
|
+
}
|
|
7
|
+
const caseInsensitiveMatches = schemaOwner.schema.fields
|
|
8
|
+
.map((field) => field.name)
|
|
9
|
+
.filter((fieldName) => fieldName.toLowerCase() === requestedField.toLowerCase());
|
|
10
|
+
if (caseInsensitiveMatches.length === 1) {
|
|
11
|
+
return caseInsensitiveMatches[0];
|
|
12
|
+
}
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
function getRowValue(row, fieldName) {
|
|
16
|
+
if (!row || typeof row !== 'object') {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
const object = row;
|
|
20
|
+
const sources = [
|
|
21
|
+
object,
|
|
22
|
+
object.properties,
|
|
23
|
+
].filter((value) => Boolean(value && typeof value === 'object'));
|
|
24
|
+
for (const source of sources) {
|
|
25
|
+
if (fieldName in source) {
|
|
26
|
+
return source[fieldName];
|
|
27
|
+
}
|
|
28
|
+
const caseInsensitiveMatches = Object.keys(source).filter((key) => key.toLowerCase() === fieldName.toLowerCase());
|
|
29
|
+
if (caseInsensitiveMatches.length === 1) {
|
|
30
|
+
return source[caseInsensitiveMatches[0]];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
function getGeoArrowOrRowValue(options) {
|
|
36
|
+
const { value, fieldName, vector } = options;
|
|
37
|
+
if (value &&
|
|
38
|
+
typeof value === 'object' &&
|
|
39
|
+
'index' in value &&
|
|
40
|
+
typeof value.index === 'number') {
|
|
41
|
+
const objectInfo = value;
|
|
42
|
+
const batch = objectInfo.data?.data;
|
|
43
|
+
const batchFieldName = batch
|
|
44
|
+
? resolveFieldName(batch, fieldName)
|
|
45
|
+
: undefined;
|
|
46
|
+
if (batch && batchFieldName) {
|
|
47
|
+
return batch.getChild(batchFieldName)?.get(objectInfo.index);
|
|
48
|
+
}
|
|
49
|
+
if (batch) {
|
|
50
|
+
// Batch is present (GeoArrow path) but the field wasn't found in it.
|
|
51
|
+
// The index is batch-local and cannot be safely used against the global
|
|
52
|
+
// vector which spans all batches. Return undefined so the mapper
|
|
53
|
+
// applies nullColor rather than reading the wrong row.
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
// No batch context (e.g. GeoJSON binary path): the index is global,
|
|
57
|
+
// so using the table-level vector is safe.
|
|
58
|
+
return vector.get(objectInfo.index);
|
|
59
|
+
}
|
|
60
|
+
return getRowValue(value, fieldName);
|
|
61
|
+
}
|
|
62
|
+
function getColumnValues(vector) {
|
|
63
|
+
return Array.from({ length: vector.length }, (_, index) => vector.get(index));
|
|
64
|
+
}
|
|
65
|
+
function getColumn(table, field) {
|
|
66
|
+
const resolvedFieldName = resolveFieldName(table, field);
|
|
67
|
+
if (!resolvedFieldName) {
|
|
68
|
+
throw new Error(`Unknown colorScale field "${field}".`);
|
|
69
|
+
}
|
|
70
|
+
const vector = table.getChild(resolvedFieldName);
|
|
71
|
+
if (!vector) {
|
|
72
|
+
throw new Error(`Unable to read colorScale field "${resolvedFieldName}".`);
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
fieldName: resolvedFieldName,
|
|
76
|
+
vector,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const MISSING_FIELD_COLOR = [255, 0, 0, 200];
|
|
80
|
+
export function compileColorScale(options) {
|
|
81
|
+
const { table, colorScale } = options;
|
|
82
|
+
let column;
|
|
83
|
+
try {
|
|
84
|
+
column = getColumn(table, colorScale.field);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
console.warn(`[compileColorScale] Field "${colorScale.field}" not found in dataset. Color scale will use fallback color.`);
|
|
88
|
+
return () => MISSING_FIELD_COLOR;
|
|
89
|
+
}
|
|
90
|
+
const { fieldName, vector } = column;
|
|
91
|
+
let mapper;
|
|
92
|
+
try {
|
|
93
|
+
mapper = createColorScaleMapper({
|
|
94
|
+
colorScale,
|
|
95
|
+
values: getColumnValues(vector),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
console.warn(`[compileColorScale] Failed to create color scale for field "${colorScale.field}":`, err);
|
|
100
|
+
return () => MISSING_FIELD_COLOR;
|
|
101
|
+
}
|
|
102
|
+
return (value) => mapper(getGeoArrowOrRowValue({ value, fieldName, vector }));
|
|
103
|
+
}
|
|
104
|
+
export function buildColorScaleLegend(options) {
|
|
105
|
+
const { table, colorScale } = options;
|
|
106
|
+
let column;
|
|
107
|
+
try {
|
|
108
|
+
column = getColumn(table, colorScale.field);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const { vector } = column;
|
|
114
|
+
const values = getColumnValues(vector);
|
|
115
|
+
if (colorScale.type !== 'categorical' &&
|
|
116
|
+
values.every((value) => coerceFiniteNumber(value) === undefined)) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
return buildGenericColorScaleLegend({
|
|
120
|
+
colorScale,
|
|
121
|
+
values,
|
|
122
|
+
title: options.title,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=compileColorScale.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compileColorScale.js","sourceRoot":"","sources":["../../src/json/compileColorScale.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n buildColorScaleLegend as buildGenericColorScaleLegend,\n coerceFiniteNumber,\n createColorScaleMapper,\n type ColorScaleConfig,\n type ResolvedColorLegend,\n} from '@sqlrooms/color-scales';\nimport type * as arrow from 'apache-arrow';\n\nfunction resolveFieldName(\n schemaOwner: arrow.Table | arrow.RecordBatch,\n requestedField: string,\n) {\n const exactMatch = schemaOwner.schema.fields.find(\n (field) => field.name === requestedField,\n )?.name;\n if (exactMatch) {\n return exactMatch;\n }\n\n const caseInsensitiveMatches = schemaOwner.schema.fields\n .map((field) => field.name)\n .filter(\n (fieldName) => fieldName.toLowerCase() === requestedField.toLowerCase(),\n );\n\n if (caseInsensitiveMatches.length === 1) {\n return caseInsensitiveMatches[0]!;\n }\n\n return undefined;\n}\n\nfunction getRowValue(row: unknown, fieldName: string) {\n if (!row || typeof row !== 'object') {\n return undefined;\n }\n\n const object = row as Record<string, unknown>;\n const sources = [\n object,\n object.properties as Record<string, unknown> | undefined,\n ].filter((value): value is Record<string, unknown> =>\n Boolean(value && typeof value === 'object'),\n );\n\n for (const source of sources) {\n if (fieldName in source) {\n return source[fieldName];\n }\n\n const caseInsensitiveMatches = Object.keys(source).filter(\n (key) => key.toLowerCase() === fieldName.toLowerCase(),\n );\n if (caseInsensitiveMatches.length === 1) {\n return source[caseInsensitiveMatches[0]!] as unknown;\n }\n }\n\n return undefined;\n}\n\nfunction getGeoArrowOrRowValue(options: {\n value: unknown;\n fieldName: string;\n vector: arrow.Vector;\n}) {\n const {value, fieldName, vector} = options;\n if (\n value &&\n typeof value === 'object' &&\n 'index' in value &&\n typeof (value as {index?: unknown}).index === 'number'\n ) {\n const objectInfo = value as {\n index: number;\n data?: {data?: arrow.Table | arrow.RecordBatch};\n };\n const batch = objectInfo.data?.data;\n const batchFieldName = batch\n ? resolveFieldName(batch, fieldName)\n : undefined;\n\n if (batch && batchFieldName) {\n return batch.getChild(batchFieldName)?.get(objectInfo.index);\n }\n\n if (batch) {\n // Batch is present (GeoArrow path) but the field wasn't found in it.\n // The index is batch-local and cannot be safely used against the global\n // vector which spans all batches. Return undefined so the mapper\n // applies nullColor rather than reading the wrong row.\n return undefined;\n }\n\n // No batch context (e.g. GeoJSON binary path): the index is global,\n // so using the table-level vector is safe.\n return vector.get(objectInfo.index);\n }\n\n return getRowValue(value, fieldName);\n}\n\nfunction getColumnValues(vector: arrow.Vector) {\n return Array.from({length: vector.length}, (_, index) => vector.get(index));\n}\n\nfunction getColumn(table: arrow.Table, field: string) {\n const resolvedFieldName = resolveFieldName(table, field);\n if (!resolvedFieldName) {\n throw new Error(`Unknown colorScale field \"${field}\".`);\n }\n\n const vector = table.getChild(resolvedFieldName);\n if (!vector) {\n throw new Error(`Unable to read colorScale field \"${resolvedFieldName}\".`);\n }\n\n return {\n fieldName: resolvedFieldName,\n vector,\n };\n}\n\nconst MISSING_FIELD_COLOR: [number, number, number, number] = [255, 0, 0, 200];\n\nexport function compileColorScale(options: {\n table: arrow.Table;\n colorScale: ColorScaleConfig;\n}) {\n const {table, colorScale} = options;\n let column;\n try {\n column = getColumn(table, colorScale.field);\n } catch {\n console.warn(\n `[compileColorScale] Field \"${colorScale.field}\" not found in dataset. Color scale will use fallback color.`,\n );\n return () => MISSING_FIELD_COLOR;\n }\n const {fieldName, vector} = column;\n let mapper: ReturnType<typeof createColorScaleMapper>;\n try {\n mapper = createColorScaleMapper({\n colorScale,\n values: getColumnValues(vector),\n });\n } catch (err) {\n console.warn(\n `[compileColorScale] Failed to create color scale for field \"${colorScale.field}\":`,\n err,\n );\n return () => MISSING_FIELD_COLOR;\n }\n\n return (value: unknown) =>\n mapper(getGeoArrowOrRowValue({value, fieldName, vector}));\n}\n\nexport function buildColorScaleLegend(options: {\n table: arrow.Table;\n colorScale: ColorScaleConfig;\n title?: string;\n}): ResolvedColorLegend | null {\n const {table, colorScale} = options;\n let column;\n try {\n column = getColumn(table, colorScale.field);\n } catch {\n return null;\n }\n const {vector} = column;\n const values = getColumnValues(vector);\n\n if (\n colorScale.type !== 'categorical' &&\n values.every((value) => coerceFiniteNumber(value) === undefined)\n ) {\n return null;\n }\n\n return buildGenericColorScaleLegend({\n colorScale,\n values,\n title: options.title,\n });\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type * as arrow from 'apache-arrow';
|
|
2
|
+
export declare function compileGeoArrowAccessor(expression: string, table: arrow.Table): ({ index, data, target, }: {
|
|
3
|
+
index: number;
|
|
4
|
+
data: {
|
|
5
|
+
data: {
|
|
6
|
+
get: (i: number) => Record<string, unknown>;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
target: number[];
|
|
10
|
+
}) => unknown;
|
|
11
|
+
export declare function isCompiledGeoArrowAccessor(value: unknown): value is (info: {
|
|
12
|
+
index: number;
|
|
13
|
+
data: {
|
|
14
|
+
data: unknown;
|
|
15
|
+
};
|
|
16
|
+
target: number[];
|
|
17
|
+
}) => unknown;
|
|
18
|
+
//# sourceMappingURL=compileGeoArrowAccessor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compileGeoArrowAccessor.d.ts","sourceRoot":"","sources":["../../src/json/compileGeoArrowAccessor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC;AA8H3C,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,KAAK,CAAC,KAAK,8BAkBf;IACD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE;QAAC,IAAI,EAAE;YAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;SAAC,CAAA;KAAC,CAAC;IAC5D,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,aAiBF;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,CAAC,IAAI,EAAE;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE;QAAC,IAAI,EAAE,OAAO,CAAA;KAAC,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,KAAK,OAAO,CASZ"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
const GEOARROW_COMPILED_ACCESSOR = Symbol.for('@sqlrooms/deck/compiled-geoarrow-accessor');
|
|
2
|
+
function isValidIdentifier(name) {
|
|
3
|
+
return /^[A-Za-z_$][\w$]*$/.test(name);
|
|
4
|
+
}
|
|
5
|
+
const RESERVED_IDENTIFIERS = new Set([
|
|
6
|
+
// JS keywords & future reserved words
|
|
7
|
+
'abstract',
|
|
8
|
+
'arguments',
|
|
9
|
+
'async',
|
|
10
|
+
'await',
|
|
11
|
+
'break',
|
|
12
|
+
'case',
|
|
13
|
+
'catch',
|
|
14
|
+
'class',
|
|
15
|
+
'const',
|
|
16
|
+
'continue',
|
|
17
|
+
'debugger',
|
|
18
|
+
'default',
|
|
19
|
+
'delete',
|
|
20
|
+
'do',
|
|
21
|
+
'else',
|
|
22
|
+
'enum',
|
|
23
|
+
'eval',
|
|
24
|
+
'export',
|
|
25
|
+
'extends',
|
|
26
|
+
'finally',
|
|
27
|
+
'for',
|
|
28
|
+
'function',
|
|
29
|
+
'if',
|
|
30
|
+
'implements',
|
|
31
|
+
'import',
|
|
32
|
+
'in',
|
|
33
|
+
'instanceof',
|
|
34
|
+
'interface',
|
|
35
|
+
'let',
|
|
36
|
+
'new',
|
|
37
|
+
'of',
|
|
38
|
+
'package',
|
|
39
|
+
'private',
|
|
40
|
+
'protected',
|
|
41
|
+
'public',
|
|
42
|
+
'return',
|
|
43
|
+
'static',
|
|
44
|
+
'super',
|
|
45
|
+
'switch',
|
|
46
|
+
'this',
|
|
47
|
+
'throw',
|
|
48
|
+
'try',
|
|
49
|
+
'typeof',
|
|
50
|
+
'var',
|
|
51
|
+
'void',
|
|
52
|
+
'while',
|
|
53
|
+
'with',
|
|
54
|
+
'yield',
|
|
55
|
+
// Literals & globals used in expressions
|
|
56
|
+
'true',
|
|
57
|
+
'false',
|
|
58
|
+
'null',
|
|
59
|
+
'undefined',
|
|
60
|
+
'NaN',
|
|
61
|
+
'Infinity',
|
|
62
|
+
'Math',
|
|
63
|
+
'Number',
|
|
64
|
+
'String',
|
|
65
|
+
'Boolean',
|
|
66
|
+
'Array',
|
|
67
|
+
'Object',
|
|
68
|
+
'Date',
|
|
69
|
+
// Accessor runtime parameter
|
|
70
|
+
'target',
|
|
71
|
+
]);
|
|
72
|
+
function unique(values) {
|
|
73
|
+
return [...new Set(values)];
|
|
74
|
+
}
|
|
75
|
+
function resolveColumnBindings(expression, table) {
|
|
76
|
+
const schemaFieldNames = table.schema.fields
|
|
77
|
+
.map((field) => field.name)
|
|
78
|
+
.filter(isValidIdentifier);
|
|
79
|
+
const identifiers = unique(Array.from(expression.matchAll(/\b[A-Za-z_$][\w$]*\b/g))
|
|
80
|
+
.map((match) => match[0])
|
|
81
|
+
.filter((identifier) => !RESERVED_IDENTIFIERS.has(identifier)));
|
|
82
|
+
return identifiers.map((identifier) => {
|
|
83
|
+
const exactMatch = schemaFieldNames.find((fieldName) => fieldName === identifier);
|
|
84
|
+
if (exactMatch) {
|
|
85
|
+
return { identifier, columnName: exactMatch };
|
|
86
|
+
}
|
|
87
|
+
const caseInsensitiveMatches = schemaFieldNames.filter((fieldName) => fieldName.toLowerCase() === identifier.toLowerCase());
|
|
88
|
+
return {
|
|
89
|
+
identifier,
|
|
90
|
+
columnName: caseInsensitiveMatches.length === 1
|
|
91
|
+
? caseInsensitiveMatches[0]
|
|
92
|
+
: undefined,
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function copyArrayLikeIntoTarget(result) {
|
|
97
|
+
if (!Array.isArray(result) && !ArrayBuffer.isView(result)) {
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
// Keep returning plain JS arrays. Reusing deck's typed `target` buffer
|
|
101
|
+
// causes `ScatterplotLayer` binary attribute errors (`Float64Array`) when
|
|
102
|
+
// GeoArrow delegates to deck sublayers.
|
|
103
|
+
return Array.from(result);
|
|
104
|
+
}
|
|
105
|
+
export function compileGeoArrowAccessor(expression, table) {
|
|
106
|
+
const trimmedExpression = expression.trim();
|
|
107
|
+
const bindings = resolveColumnBindings(trimmedExpression, table);
|
|
108
|
+
const evaluator = new Function(...bindings.map((binding) => binding.identifier), 'target', `return (${trimmedExpression});`);
|
|
109
|
+
// GeoArrow 0.4.x callbacks are batch-oriented: they receive
|
|
110
|
+
// {index, data: {data: batch}, target} from the upstream layer wrapper.
|
|
111
|
+
const accessor = ({ index, data, target, }) => {
|
|
112
|
+
const batch = data.data;
|
|
113
|
+
const args = bindings.map((binding) => binding.columnName
|
|
114
|
+
? batch.getChild(binding.columnName)?.get(index)
|
|
115
|
+
: undefined);
|
|
116
|
+
const result = evaluator(...args, target);
|
|
117
|
+
return copyArrayLikeIntoTarget(result);
|
|
118
|
+
};
|
|
119
|
+
Object.defineProperty(accessor, GEOARROW_COMPILED_ACCESSOR, {
|
|
120
|
+
value: true,
|
|
121
|
+
enumerable: false,
|
|
122
|
+
});
|
|
123
|
+
return accessor;
|
|
124
|
+
}
|
|
125
|
+
export function isCompiledGeoArrowAccessor(value) {
|
|
126
|
+
return (typeof value === 'function' &&
|
|
127
|
+
Boolean(value[GEOARROW_COMPILED_ACCESSOR]));
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=compileGeoArrowAccessor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compileGeoArrowAccessor.js","sourceRoot":"","sources":["../../src/json/compileGeoArrowAccessor.ts"],"names":[],"mappings":"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","sourcesContent":["import type * as arrow from 'apache-arrow';\n\nconst GEOARROW_COMPILED_ACCESSOR = Symbol.for(\n '@sqlrooms/deck/compiled-geoarrow-accessor',\n);\n\nfunction isValidIdentifier(name: string) {\n return /^[A-Za-z_$][\\w$]*$/.test(name);\n}\n\nconst RESERVED_IDENTIFIERS = new Set([\n // JS keywords & future reserved words\n 'abstract',\n 'arguments',\n 'async',\n 'await',\n 'break',\n 'case',\n 'catch',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'else',\n 'enum',\n 'eval',\n 'export',\n 'extends',\n 'finally',\n 'for',\n 'function',\n 'if',\n 'implements',\n 'import',\n 'in',\n 'instanceof',\n 'interface',\n 'let',\n 'new',\n 'of',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'return',\n 'static',\n 'super',\n 'switch',\n 'this',\n 'throw',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'while',\n 'with',\n 'yield',\n // Literals & globals used in expressions\n 'true',\n 'false',\n 'null',\n 'undefined',\n 'NaN',\n 'Infinity',\n 'Math',\n 'Number',\n 'String',\n 'Boolean',\n 'Array',\n 'Object',\n 'Date',\n // Accessor runtime parameter\n 'target',\n]);\n\nfunction unique<T>(values: T[]) {\n return [...new Set(values)];\n}\n\nfunction resolveColumnBindings(expression: string, table: arrow.Table) {\n const schemaFieldNames = table.schema.fields\n .map((field) => field.name)\n .filter(isValidIdentifier);\n\n const identifiers = unique(\n Array.from(expression.matchAll(/\\b[A-Za-z_$][\\w$]*\\b/g))\n .map((match) => match[0])\n .filter((identifier) => !RESERVED_IDENTIFIERS.has(identifier)),\n );\n\n return identifiers.map((identifier) => {\n const exactMatch = schemaFieldNames.find(\n (fieldName) => fieldName === identifier,\n );\n if (exactMatch) {\n return {identifier, columnName: exactMatch};\n }\n\n const caseInsensitiveMatches = schemaFieldNames.filter(\n (fieldName) => fieldName.toLowerCase() === identifier.toLowerCase(),\n );\n\n return {\n identifier,\n columnName:\n caseInsensitiveMatches.length === 1\n ? caseInsensitiveMatches[0]!\n : undefined,\n };\n });\n}\n\nfunction copyArrayLikeIntoTarget(result: unknown) {\n if (!Array.isArray(result) && !ArrayBuffer.isView(result)) {\n return result;\n }\n\n // Keep returning plain JS arrays. Reusing deck's typed `target` buffer\n // causes `ScatterplotLayer` binary attribute errors (`Float64Array`) when\n // GeoArrow delegates to deck sublayers.\n return Array.from(result as ArrayLike<number>);\n}\n\nexport function compileGeoArrowAccessor(\n expression: string,\n table: arrow.Table,\n) {\n const trimmedExpression = expression.trim();\n\n const bindings = resolveColumnBindings(trimmedExpression, table);\n\n const evaluator = new Function(\n ...bindings.map((binding) => binding.identifier),\n 'target',\n `return (${trimmedExpression});`,\n ) as (...args: unknown[]) => unknown;\n\n // GeoArrow 0.4.x callbacks are batch-oriented: they receive\n // {index, data: {data: batch}, target} from the upstream layer wrapper.\n const accessor = ({\n index,\n data,\n target,\n }: {\n index: number;\n data: {data: {get: (i: number) => Record<string, unknown>}};\n target: number[];\n }) => {\n const batch = data.data as arrow.Table | arrow.RecordBatch;\n const args = bindings.map((binding) =>\n binding.columnName\n ? batch.getChild(binding.columnName)?.get(index)\n : undefined,\n );\n const result = evaluator(...args, target);\n return copyArrayLikeIntoTarget(result);\n };\n\n Object.defineProperty(accessor, GEOARROW_COMPILED_ACCESSOR, {\n value: true,\n enumerable: false,\n });\n\n return accessor;\n}\n\nexport function isCompiledGeoArrowAccessor(\n value: unknown,\n): value is (info: {\n index: number;\n data: {data: unknown};\n target: number[];\n}) => unknown {\n return (\n typeof value === 'function' &&\n Boolean(\n (value as {[GEOARROW_COMPILED_ACCESSOR]?: boolean})[\n GEOARROW_COMPILED_ACCESSOR\n ],\n )\n );\n}\n"]}
|