@carto/api-client 0.5.0-alpha.1 → 0.5.0-alpha.13

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 (127) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/build/api-client.cjs +3162 -3206
  3. package/build/api-client.cjs.map +1 -1
  4. package/build/api-client.d.cts +1399 -0
  5. package/build/api-client.d.ts +1399 -0
  6. package/build/api-client.js +3673 -0
  7. package/build/api-client.js.map +1 -0
  8. package/build/worker.d.ts +2 -0
  9. package/build/worker.js +1949 -0
  10. package/build/worker.js.map +1 -0
  11. package/package.json +61 -46
  12. package/src/api/carto-api-error.ts +1 -1
  13. package/src/api/query.ts +5 -5
  14. package/src/api/request-with-parameters.ts +6 -6
  15. package/src/client.ts +3 -3
  16. package/src/constants-internal.ts +5 -11
  17. package/src/constants.ts +6 -6
  18. package/src/deck/get-data-filter-extension-props.ts +164 -0
  19. package/src/deck/index.ts +1 -0
  20. package/src/filters/Filter.ts +18 -8
  21. package/src/filters/FilterTypes.ts +2 -2
  22. package/src/filters/geosjonFeatures.ts +2 -2
  23. package/src/filters/tileFeatures.ts +12 -17
  24. package/src/filters.ts +4 -4
  25. package/src/geo.ts +12 -14
  26. package/src/global.d.ts +3 -8
  27. package/src/index.ts +3 -0
  28. package/src/models/common.ts +11 -9
  29. package/src/models/model.ts +3 -4
  30. package/src/operations/aggregation.ts +5 -5
  31. package/src/operations/applySorting.ts +4 -4
  32. package/src/operations/groupBy.ts +4 -4
  33. package/src/operations/groupByDate.ts +1 -1
  34. package/src/operations/histogram.ts +4 -4
  35. package/src/operations/scatterPlot.ts +4 -4
  36. package/src/sources/base-source.ts +8 -8
  37. package/src/sources/boundary-query-source.ts +2 -2
  38. package/src/sources/boundary-table-source.ts +2 -2
  39. package/src/sources/h3-query-source.ts +7 -5
  40. package/src/sources/h3-table-source.ts +7 -5
  41. package/src/sources/h3-tileset-source.ts +4 -4
  42. package/src/sources/index.ts +26 -26
  43. package/src/sources/quadbin-query-source.ts +7 -5
  44. package/src/sources/quadbin-table-source.ts +7 -5
  45. package/src/sources/quadbin-tileset-source.ts +4 -4
  46. package/src/sources/raster-source.ts +2 -2
  47. package/src/sources/types.ts +9 -3
  48. package/src/sources/vector-query-source.ts +2 -3
  49. package/src/sources/vector-table-source.ts +2 -3
  50. package/src/sources/vector-tileset-source.ts +5 -5
  51. package/src/spatial-index.ts +12 -10
  52. package/src/types-internal.ts +5 -5
  53. package/src/types.ts +15 -15
  54. package/src/utils/makeIntervalComplete.ts +1 -1
  55. package/src/utils.ts +3 -3
  56. package/src/widget-sources/index.ts +1 -0
  57. package/src/widget-sources/types.ts +6 -4
  58. package/src/widget-sources/widget-query-source.ts +6 -2
  59. package/src/widget-sources/widget-remote-source.ts +67 -26
  60. package/src/widget-sources/widget-source.ts +10 -25
  61. package/src/widget-sources/widget-table-source.ts +6 -2
  62. package/src/widget-sources/widget-tileset-source-impl.ts +417 -0
  63. package/src/widget-sources/widget-tileset-source.ts +199 -299
  64. package/src/workers/constants.ts +13 -0
  65. package/src/workers/types.ts +19 -0
  66. package/src/workers/widget-tileset-worker.ts +40 -0
  67. package/build/api/carto-api-error.d.ts +0 -26
  68. package/build/api/endpoints.d.ts +0 -24
  69. package/build/api/index.d.ts +0 -5
  70. package/build/api/query.d.ts +0 -3
  71. package/build/api/request-with-parameters.d.ts +0 -10
  72. package/build/api-client.modern.js +0 -3574
  73. package/build/api-client.modern.js.map +0 -1
  74. package/build/client.d.ts +0 -14
  75. package/build/constants-internal.d.ts +0 -26
  76. package/build/constants.d.ts +0 -53
  77. package/build/filters/Filter.d.ts +0 -13
  78. package/build/filters/FilterTypes.d.ts +0 -3
  79. package/build/filters/geosjonFeatures.d.ts +0 -8
  80. package/build/filters/index.d.ts +0 -6
  81. package/build/filters/tileFeatures.d.ts +0 -20
  82. package/build/filters/tileFeaturesGeometries.d.ts +0 -13
  83. package/build/filters/tileFeaturesSpatialIndex.d.ts +0 -10
  84. package/build/filters.d.ts +0 -39
  85. package/build/geo.d.ts +0 -19
  86. package/build/index.d.ts +0 -14
  87. package/build/models/common.d.ts +0 -27
  88. package/build/models/index.d.ts +0 -3
  89. package/build/models/model.d.ts +0 -37
  90. package/build/operations/aggregation.d.ts +0 -8
  91. package/build/operations/applySorting.d.ts +0 -20
  92. package/build/operations/groupBy.d.ts +0 -15
  93. package/build/operations/groupByDate.d.ts +0 -11
  94. package/build/operations/histogram.d.ts +0 -13
  95. package/build/operations/index.d.ts +0 -6
  96. package/build/operations/scatterPlot.d.ts +0 -14
  97. package/build/sources/base-source.d.ts +0 -4
  98. package/build/sources/boundary-query-source.d.ts +0 -10
  99. package/build/sources/boundary-table-source.d.ts +0 -8
  100. package/build/sources/h3-query-source.d.ts +0 -5
  101. package/build/sources/h3-table-source.d.ts +0 -5
  102. package/build/sources/h3-tileset-source.d.ts +0 -5
  103. package/build/sources/index.d.ts +0 -26
  104. package/build/sources/quadbin-query-source.d.ts +0 -5
  105. package/build/sources/quadbin-table-source.d.ts +0 -5
  106. package/build/sources/quadbin-tileset-source.d.ts +0 -5
  107. package/build/sources/raster-source.d.ts +0 -4
  108. package/build/sources/types.d.ts +0 -366
  109. package/build/sources/vector-query-source.d.ts +0 -5
  110. package/build/sources/vector-table-source.d.ts +0 -5
  111. package/build/sources/vector-tileset-source.d.ts +0 -5
  112. package/build/spatial-index.d.ts +0 -8
  113. package/build/types-internal.d.ts +0 -56
  114. package/build/types.d.ts +0 -140
  115. package/build/utils/dateUtils.d.ts +0 -10
  116. package/build/utils/getTileFormat.d.ts +0 -3
  117. package/build/utils/makeIntervalComplete.d.ts +0 -2
  118. package/build/utils/transformTileCoordsToWGS84.d.ts +0 -8
  119. package/build/utils/transformToTileCoords.d.ts +0 -9
  120. package/build/utils.d.ts +0 -32
  121. package/build/widget-sources/index.d.ts +0 -5
  122. package/build/widget-sources/types.d.ts +0 -158
  123. package/build/widget-sources/widget-query-source.d.ts +0 -33
  124. package/build/widget-sources/widget-remote-source.d.ts +0 -18
  125. package/build/widget-sources/widget-source.d.ts +0 -74
  126. package/build/widget-sources/widget-table-source.d.ts +0 -33
  127. package/build/widget-sources/widget-tileset-source.d.ts +0 -76
@@ -1,9 +1,6 @@
1
- import {TilesetSourceOptions} from '../sources/index.js';
2
- import type {ModelSource} from '../models/index.js';
3
1
  import {
4
2
  CategoryRequestOptions,
5
3
  CategoryResponse,
6
- FeaturesRequestOptions,
7
4
  FeaturesResponse,
8
5
  FormulaRequestOptions,
9
6
  FormulaResponse,
@@ -18,32 +15,15 @@ import {
18
15
  TimeSeriesRequestOptions,
19
16
  TimeSeriesResponse,
20
17
  } from './types.js';
21
- import {InvalidColumnError, getApplicableFilters} from '../utils.js';
22
- import {TileFormat} from '../constants.js';
23
18
  import {SpatialFilter, Tile} from '../types.js';
24
- import {
25
- TileFeatureExtractOptions,
26
- applyFilters,
27
- geojsonFeatures,
28
- tileFeatures,
29
- } from '../filters/index.js';
30
- import {
31
- aggregationFunctions,
32
- applySorting,
33
- groupValuesByColumn,
34
- groupValuesByDateColumn,
35
- histogram,
36
- scatterPlot,
37
- } from '../operations/index.js';
38
- import {FeatureData} from '../types-internal.js';
19
+ import {TileFeatureExtractOptions} from '../filters/index.js';
39
20
  import {FeatureCollection} from 'geojson';
40
- import {SpatialDataType} from '../sources/types.js';
41
21
  import {WidgetSource, WidgetSourceProps} from './widget-source.js';
42
-
43
- // TODO(cleanup): Parameter defaults in source functions and widget API calls are
44
- // currently duplicated and possibly inconsistent. Consider consolidating and
45
- // operating on Required<T> objects. See:
46
- // https://github.com/CartoDB/carto-api-client/issues/39
22
+ import {Method} from '../workers/constants.js';
23
+ import {WorkerRequest, WorkerResponse} from '../workers/types.js';
24
+ import {SpatialDataType, TilesetSourceOptions} from '../sources/types.js';
25
+ import {TileFormat} from '../constants.js';
26
+ import {WidgetTilesetSourceImpl} from './widget-tileset-source-impl.js';
47
27
 
48
28
  export type WidgetTilesetSourceProps = WidgetSourceProps &
49
29
  Omit<TilesetSourceOptions, 'filters'> & {
@@ -76,332 +56,252 @@ export type WidgetTilesetSourceResult = {widgetSource: WidgetTilesetSource};
76
56
  * ```
77
57
  */
78
58
  export class WidgetTilesetSource extends WidgetSource<WidgetTilesetSourceProps> {
79
- private _tiles: Tile[] = [];
80
- private _features: FeatureData[] = [];
81
-
82
- protected override getModelSource(owner: string): ModelSource {
83
- return {
84
- ...super._getModelSource(owner),
85
- type: 'tileset',
86
- data: this.props.tableName,
87
- };
88
- }
59
+ protected _localImpl: WidgetTilesetSourceImpl | null = null;
89
60
 
90
- /**
91
- * Loads features as a list of tiles (typically provided by deck.gl).
92
- * After tiles are loaded, {@link extractTileFeatures} must be called
93
- * before computing statistics on the tiles.
94
- */
95
- loadTiles(tiles: unknown[]) {
96
- this._tiles = tiles as Tile[];
97
- }
61
+ protected _workerImpl: Worker | null = null;
62
+ protected _workerEnabled: boolean;
63
+ protected _workerNextRequestId = 1;
98
64
 
99
- /**
100
- * Extracts feature data from tiles previously loaded with {@link loadTiles}.
101
- * Must be called before computing statistics on tiles.
102
- */
103
- extractTileFeatures({
104
- spatialFilter,
105
- uniqueIdProperty,
106
- options,
107
- }: {
108
- spatialFilter: SpatialFilter;
109
- // TODO(cleanup): As an optional property, 'uniqueIdProperty' will be easy to forget.
110
- // Would it be better to configure it on the source function, rather than separately
111
- // on the layer and in 'loadTiles()'?
112
- uniqueIdProperty?: string;
113
- options?: TileFeatureExtractOptions;
114
- }) {
115
- this._features = tileFeatures({
116
- tiles: this._tiles,
117
- options,
118
- spatialFilter,
119
- uniqueIdProperty,
120
- tileFormat: this.props.tileFormat,
121
- spatialDataColumn: this.props.spatialDataColumn,
122
- spatialDataType: this.props.spatialDataType,
123
- });
124
- }
65
+ constructor(props: WidgetTilesetSourceProps) {
66
+ super(props);
125
67
 
126
- /** Loads features as GeoJSON (used for testing). */
127
- loadGeoJSON({
128
- geojson,
129
- spatialFilter,
130
- uniqueIdProperty,
131
- }: {
132
- geojson: FeatureCollection;
133
- spatialFilter: SpatialFilter;
134
- uniqueIdProperty?: string;
135
- }) {
136
- this._features = geojsonFeatures({
137
- geojson,
138
- spatialFilter,
139
- uniqueIdProperty,
140
- });
141
- }
68
+ this._workerEnabled =
69
+ (props.widgetWorker ?? true) &&
70
+ TSUP_FORMAT !== 'cjs' &&
71
+ typeof Worker !== 'undefined';
142
72
 
143
- override async getFeatures(
144
- options: FeaturesRequestOptions
145
- ): Promise<FeaturesResponse> {
146
- throw new Error('getFeatures not supported for tilesets');
73
+ if (!this._workerEnabled) {
74
+ this._localImpl = new WidgetTilesetSourceImpl(this.props);
75
+ }
147
76
  }
148
77
 
149
- async getFormula({
150
- column = '*',
151
- operation = 'count',
152
- joinOperation,
153
- filterOwner,
154
- }: FormulaRequestOptions): Promise<FormulaResponse> {
155
- if (operation === 'custom') {
156
- throw new Error('Custom aggregation not supported for tilesets');
157
- }
78
+ destroy() {
79
+ this._localImpl?.destroy();
80
+ this._localImpl = null;
158
81
 
159
- if (!this._features.length) {
160
- return {value: null};
161
- }
82
+ this._workerImpl?.terminate();
83
+ this._workerImpl = null;
162
84
 
163
- // Column is required except when operation is 'count'.
164
- if ((column && column !== '*') || operation !== 'count') {
165
- assertColumn(this._features, column);
166
- }
85
+ super.destroy();
86
+ }
167
87
 
168
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
88
+ /////////////////////////////////////////////////////////////////////////////
89
+ // WEB WORKER MANAGEMENT
169
90
 
170
- if (filteredFeatures.length === 0 && operation !== 'count') {
171
- return {value: null};
91
+ /**
92
+ * Returns an initialized Worker, to be reused for the lifecycle of this
93
+ * source instance.
94
+ */
95
+ protected _getWorker(): Worker {
96
+ if (this._workerImpl) {
97
+ return this._workerImpl;
172
98
  }
173
99
 
174
- const targetOperation = aggregationFunctions[operation];
175
- return {
176
- value: targetOperation(
177
- filteredFeatures as FeatureData[],
178
- column,
179
- joinOperation
180
- ),
181
- };
100
+ this._workerImpl = new Worker(
101
+ new URL('@carto/api-client/worker', import.meta.url),
102
+ {
103
+ type: 'module',
104
+ name: 'cartowidgettileset',
105
+ }
106
+ );
107
+
108
+ this._workerImpl.postMessage({
109
+ method: Method.INIT,
110
+ params: [this.props],
111
+ } as WorkerRequest);
112
+
113
+ return this._workerImpl;
182
114
  }
183
115
 
184
- override async getHistogram({
185
- operation = 'count',
186
- ticks,
187
- column,
188
- joinOperation,
189
- filterOwner,
190
- }: HistogramRequestOptions): Promise<HistogramResponse> {
191
- if (!this._features.length) {
192
- return [];
116
+ /** Executes a given method on the worker. */
117
+ protected _executeWorkerMethod<T>(
118
+ method: Method,
119
+ params: unknown[],
120
+ signal?: AbortSignal
121
+ ): Promise<T> {
122
+ if (!this._workerEnabled) {
123
+ // @ts-expect-error No type-checking dynamic method name.
124
+ return this._localImpl[method](...params);
193
125
  }
194
126
 
195
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
127
+ const worker = this._getWorker();
128
+ const requestId = this._workerNextRequestId++;
196
129
 
197
- assertColumn(this._features, column);
130
+ // TODO: ViewState may contain non-serializable data, which we do not need.
131
+ // Remove this sanitization after sc-469614 is fixed.
132
+ const options = params[0] as any;
133
+ if (options?.spatialIndexReferenceViewState) {
134
+ const {zoom, latitude, longitude} =
135
+ options.spatialIndexReferenceViewState;
136
+ options.spatialIndexReferenceViewState = {zoom, latitude, longitude};
137
+ }
198
138
 
199
- return histogram({
200
- data: filteredFeatures,
201
- valuesColumns: normalizeColumns(column),
202
- joinOperation,
203
- ticks,
204
- operation,
205
- });
206
- }
139
+ let resolve: ((value: T) => void) | null = null;
140
+ let reject: ((reason: any) => void) | null = null;
141
+
142
+ // If worker sends message to main process, check whether it's a response
143
+ // to this request, and whether the request can been aborted. Then resolve
144
+ // or reject the Promise.
145
+ function onMessage(e: MessageEvent) {
146
+ const response = e.data as WorkerResponse;
147
+ if (response.requestId !== requestId) return;
148
+ if (signal?.aborted) return; // handled by 'abort' listener
149
+
150
+ if (response.ok) {
151
+ resolve!(response.result as T);
152
+ } else {
153
+ reject!(new Error(response.error));
154
+ }
155
+ }
207
156
 
208
- override async getCategories({
209
- column,
210
- operation = 'count',
211
- operationColumn,
212
- joinOperation,
213
- filterOwner,
214
- }: CategoryRequestOptions): Promise<CategoryResponse> {
215
- if (!this._features.length) {
216
- return [];
157
+ // If request is aborted by user, immediately reject the Promise.
158
+ function onAbort() {
159
+ reject!(new Error(signal!.reason));
217
160
  }
218
161
 
219
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
162
+ worker.addEventListener('message', onMessage);
163
+ signal?.addEventListener('abort', onAbort);
220
164
 
221
- assertColumn(this._features, column as string, operationColumn as string);
165
+ // Send the task to the worker, creating a Promise to resolve/reject later.
166
+ const promise = new Promise<T>((_resolve, _reject) => {
167
+ resolve = _resolve;
168
+ reject = _reject;
222
169
 
223
- const groups = groupValuesByColumn({
224
- data: filteredFeatures,
225
- valuesColumns: normalizeColumns(operationColumn || column),
226
- joinOperation,
227
- keysColumn: column,
228
- operation,
170
+ worker.postMessage({
171
+ requestId,
172
+ method,
173
+ params,
174
+ } as WorkerRequest);
229
175
  });
230
176
 
231
- return groups || [];
177
+ // Whether the task completes, fails, or aborts: clean up afterward.
178
+ void promise.finally(() => {
179
+ worker.removeEventListener('message', onMessage);
180
+ signal?.removeEventListener('abort', onAbort);
181
+ });
182
+
183
+ return promise;
232
184
  }
233
185
 
234
- override async getScatter({
235
- xAxisColumn,
236
- yAxisColumn,
237
- xAxisJoinOperation,
238
- yAxisJoinOperation,
239
- filterOwner,
240
- }: ScatterRequestOptions): Promise<ScatterResponse> {
241
- if (!this._features.length) {
242
- return [];
186
+ /////////////////////////////////////////////////////////////////////////////
187
+ // DATA LOADING
188
+
189
+ /**
190
+ * Loads features as a list of tiles (typically provided by deck.gl).
191
+ * After tiles are loaded, {@link extractTileFeatures} must be called
192
+ * before computing statistics on the tiles.
193
+ */
194
+ loadTiles(tiles: unknown[]) {
195
+ if (!this._workerEnabled) {
196
+ return this._localImpl!.loadTiles(tiles);
243
197
  }
244
198
 
245
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
199
+ const worker = this._getWorker();
246
200
 
247
- assertColumn(this._features, xAxisColumn, yAxisColumn);
201
+ tiles = (tiles as Tile[]).map(({id, bbox, data}) => ({
202
+ id,
203
+ bbox,
204
+ data,
205
+ }));
248
206
 
249
- return scatterPlot({
250
- data: filteredFeatures,
251
- xAxisColumns: normalizeColumns(xAxisColumn),
252
- xAxisJoinOperation,
253
- yAxisColumns: normalizeColumns(yAxisColumn),
254
- yAxisJoinOperation,
255
- });
207
+ worker.postMessage({
208
+ method: Method.LOAD_TILES,
209
+ params: [tiles],
210
+ } as WorkerRequest);
256
211
  }
257
212
 
258
- override async getTable(
259
- options: TableRequestOptions
260
- ): Promise<TableResponse> {
261
- const {filterOwner, spatialFilter, abortController, ...params} = options;
262
- const {
263
- columns,
264
- searchFilterColumn,
265
- searchFilterText,
266
- sortBy,
267
- sortDirection,
268
- sortByColumnType,
269
- offset = 0,
270
- limit = 10,
271
- } = params;
272
-
273
- if (!this._features.length) {
274
- return {rows: [], totalCount: 0};
275
- }
276
-
277
- // Filter.
278
- let filteredFeatures = this._getFilteredFeatures(filterOwner);
279
-
280
- // Search.
281
- // TODO: Could we get the same behavior by applying filters in loadTiles()?
282
- if (searchFilterColumn && searchFilterText) {
283
- filteredFeatures = filteredFeatures.filter(
284
- (row) =>
285
- row[searchFilterColumn] &&
286
- String(row[searchFilterColumn])
287
- .toLowerCase()
288
- .includes(String(searchFilterText).toLowerCase())
289
- );
213
+ /** Configures options used to extract features from tiles. */
214
+ setTileFeatureExtractOptions(options: TileFeatureExtractOptions) {
215
+ if (!this._workerEnabled) {
216
+ return this._localImpl?.setTileFeatureExtractOptions(options);
290
217
  }
291
218
 
292
- // Sort.
293
- let rows = applySorting(filteredFeatures, {
294
- sortBy,
295
- sortByDirection: sortDirection,
296
- sortByColumnType,
297
- });
298
- const totalCount = rows.length;
219
+ const worker = this._getWorker();
299
220
 
300
- // Offset and limit.
301
- rows = rows.slice(
302
- Math.min(offset, totalCount),
303
- Math.min(offset + limit, totalCount)
304
- );
305
-
306
- // Select columns.
307
- rows = rows.map((srcRow: FeatureData) => {
308
- const dstRow: FeatureData = {};
309
- for (const column of columns) {
310
- dstRow[column] = srcRow[column];
311
- }
312
- return dstRow;
221
+ worker.postMessage({
222
+ type: Method.SET_TILE_FEATURE_EXTRACT_OPTIONS,
223
+ params: [options],
313
224
  });
314
-
315
- return {rows, totalCount} as TableResponse;
316
225
  }
317
226
 
318
- override async getTimeSeries({
319
- column,
320
- stepSize,
321
- operation,
322
- operationColumn,
323
- joinOperation,
324
- filterOwner,
325
- }: TimeSeriesRequestOptions): Promise<TimeSeriesResponse> {
326
- if (!this._features.length) {
327
- return {rows: []};
227
+ /**
228
+ * Loads features as GeoJSON (used for testing).
229
+ * @experimental
230
+ * @internal Not for public use. Spatial filters in other method calls will be ignored.
231
+ */
232
+ loadGeoJSON({
233
+ geojson,
234
+ spatialFilter,
235
+ }: {
236
+ geojson: FeatureCollection;
237
+ spatialFilter: SpatialFilter;
238
+ }) {
239
+ if (!this._workerEnabled) {
240
+ return this._localImpl!.loadGeoJSON({geojson, spatialFilter});
328
241
  }
329
242
 
330
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
331
-
332
- assertColumn(this._features, column as string, operationColumn as string);
333
-
334
- const rows =
335
- groupValuesByDateColumn({
336
- data: filteredFeatures,
337
- valuesColumns: normalizeColumns(operationColumn || column),
338
- keysColumn: column,
339
- groupType: stepSize,
340
- operation,
341
- joinOperation,
342
- }) || [];
243
+ const worker = this._getWorker();
343
244
 
344
- return {rows};
245
+ worker.postMessage({
246
+ method: Method.LOAD_GEOJSON,
247
+ params: [{geojson, spatialFilter}],
248
+ } as WorkerRequest);
345
249
  }
346
250
 
347
- override async getRange({
348
- column,
349
- filterOwner,
350
- }: RangeRequestOptions): Promise<RangeResponse> {
351
- if (!this._features.length) {
352
- // TODO: Is this the only nullable response in the Widgets API? If so,
353
- // can we do something more consistent?
354
- return null;
355
- }
356
-
357
- assertColumn(this._features, column);
251
+ /////////////////////////////////////////////////////////////////////////////
252
+ // WIDGETS API
358
253
 
359
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
360
- return {
361
- min: aggregationFunctions.min(filteredFeatures, column),
362
- max: aggregationFunctions.max(filteredFeatures, column),
363
- };
254
+ // eslint-disable-next-line @typescript-eslint/require-await
255
+ override async getFeatures(): Promise<FeaturesResponse> {
256
+ throw new Error('getFeatures not supported for tilesets');
364
257
  }
365
258
 
366
- /****************************************************************************
367
- * INTERNAL
368
- */
369
-
370
- private _getFilteredFeatures(filterOwner: string | undefined): FeatureData[] {
371
- return applyFilters(
372
- this._features,
373
- getApplicableFilters(filterOwner, this.props.filters),
374
- this.props.filtersLogicalOperator || 'and'
375
- );
259
+ async getFormula({
260
+ signal,
261
+ ...options
262
+ }: FormulaRequestOptions): Promise<FormulaResponse> {
263
+ return this._executeWorkerMethod(Method.GET_FORMULA, [options], signal);
376
264
  }
377
- }
378
265
 
379
- function assertColumn(
380
- features: FeatureData[],
381
- ...columnArgs: string[] | string[][]
382
- ) {
383
- // TODO(cleanup): Can drop support for multiple column shapes here?
266
+ override async getHistogram({
267
+ signal,
268
+ ...options
269
+ }: HistogramRequestOptions): Promise<HistogramResponse> {
270
+ return this._executeWorkerMethod(Method.GET_HISTOGRAM, [options], signal);
271
+ }
384
272
 
385
- // Due to the multiple column shape, we normalise it as an array with normalizeColumns
386
- const columns = Array.from(new Set(columnArgs.map(normalizeColumns).flat()));
273
+ override async getCategories({
274
+ signal,
275
+ ...options
276
+ }: CategoryRequestOptions): Promise<CategoryResponse> {
277
+ return this._executeWorkerMethod(Method.GET_CATEGORIES, [options], signal);
278
+ }
387
279
 
388
- const featureKeys = Object.keys(features[0]);
280
+ override async getScatter({
281
+ signal,
282
+ ...options
283
+ }: ScatterRequestOptions): Promise<ScatterResponse> {
284
+ return this._executeWorkerMethod(Method.GET_SCATTER, [options], signal);
285
+ }
389
286
 
390
- const invalidColumns = columns.filter(
391
- (column) => !featureKeys.includes(column)
392
- );
287
+ override async getTable({
288
+ signal,
289
+ ...options
290
+ }: TableRequestOptions): Promise<TableResponse> {
291
+ return this._executeWorkerMethod(Method.GET_TABLE, [options], signal);
292
+ }
393
293
 
394
- if (invalidColumns.length) {
395
- throw new InvalidColumnError(
396
- `Missing column(s): ${invalidColumns.join(', ')}`
397
- );
294
+ override async getTimeSeries({
295
+ signal,
296
+ ...options
297
+ }: TimeSeriesRequestOptions): Promise<TimeSeriesResponse> {
298
+ return this._executeWorkerMethod(Method.GET_TIME_SERIES, [options], signal);
398
299
  }
399
- }
400
300
 
401
- function normalizeColumns(columns: string | string[]): string[] {
402
- return Array.isArray(columns)
403
- ? columns
404
- : typeof columns === 'string'
405
- ? [columns]
406
- : [];
301
+ override async getRange({
302
+ signal,
303
+ ...options
304
+ }: RangeRequestOptions): Promise<RangeResponse> {
305
+ return this._executeWorkerMethod(Method.GET_RANGE, [options], signal);
306
+ }
407
307
  }
@@ -0,0 +1,13 @@
1
+ export enum Method {
2
+ INIT = 'init',
3
+ LOAD_TILES = 'loadTiles',
4
+ SET_TILE_FEATURE_EXTRACT_OPTIONS = 'setTileFeatureExtractOptions',
5
+ LOAD_GEOJSON = 'loadGeoJSON',
6
+ GET_FORMULA = 'getFormula',
7
+ GET_HISTOGRAM = 'getHistogram',
8
+ GET_CATEGORIES = 'getCategories',
9
+ GET_SCATTER = 'getScatter',
10
+ GET_TABLE = 'getTable',
11
+ GET_TIME_SERIES = 'getTimeSeries',
12
+ GET_RANGE = 'getRange',
13
+ }
@@ -0,0 +1,19 @@
1
+ import type {Method} from './constants.js';
2
+
3
+ export type WorkerRequest = {
4
+ requestId?: number;
5
+ method: Method;
6
+ params: unknown[];
7
+ };
8
+
9
+ export type WorkerResponse =
10
+ | {
11
+ requestId: number;
12
+ ok: true;
13
+ result: unknown;
14
+ }
15
+ | {
16
+ requestId: number;
17
+ ok: false;
18
+ error: string;
19
+ };
@@ -0,0 +1,40 @@
1
+ import {WidgetTilesetSourceImpl} from '../widget-sources/widget-tileset-source-impl.js';
2
+ import {type WidgetTilesetSourceProps} from '../widget-sources/widget-tileset-source.js';
3
+ import {Method} from './constants.js';
4
+ import type {WorkerRequest, WorkerResponse} from './types.js';
5
+
6
+ /*
7
+ * Web Worker, compiled as a separate `@carto/api-client/worker` entrypoint.
8
+ *
9
+ * Workers are scoped to the lifecycle of a single WidgetTilesetSource instance,
10
+ * representing and executing calculations on a single datasource.
11
+ */
12
+
13
+ let source: WidgetTilesetSourceImpl;
14
+
15
+ addEventListener('message', (e) => {
16
+ const {method, params, requestId} = e.data as WorkerRequest;
17
+
18
+ if (method === Method.INIT) {
19
+ source = new WidgetTilesetSourceImpl({
20
+ ...(params[0] as WidgetTilesetSourceProps),
21
+ widgetWorker: false,
22
+ });
23
+ return;
24
+ }
25
+
26
+ if (!source) {
27
+ const error = `Cannot execute "${method}" on uninitialized source.`;
28
+ postMessage({ok: false, error, requestId} as WorkerResponse);
29
+ return;
30
+ }
31
+
32
+ // @ts-expect-error No type-checking dynamic method name.
33
+ Promise.resolve(source[method](...params))
34
+ .then((result) => {
35
+ postMessage({ok: true, result, requestId} as WorkerResponse);
36
+ })
37
+ .catch((error) => {
38
+ postMessage({ok: false, error, requestId} as WorkerResponse);
39
+ });
40
+ });
@@ -1,26 +0,0 @@
1
- import { MapType } from '../types';
2
- export type APIRequestType = 'Map data' | 'Map instantiation' | 'Public map' | 'Tile stats' | 'SQL' | 'Basemap style';
3
- export type APIErrorContext = {
4
- requestType: APIRequestType;
5
- mapId?: string;
6
- connection?: string;
7
- source?: string;
8
- type?: MapType;
9
- };
10
- /**
11
- *
12
- * Custom error for reported errors in CARTO Maps API.
13
- * Provides useful debugging information in console and context for applications.
14
- *
15
- */
16
- export declare class CartoAPIError extends Error {
17
- /** Source error from server */
18
- error: Error;
19
- /** Context (API call & parameters) in which error occured */
20
- errorContext: APIErrorContext;
21
- /** Response from server */
22
- response?: Response;
23
- /** JSON Response from server */
24
- responseJson?: any;
25
- constructor(error: Error, errorContext: APIErrorContext, response?: Response, responseJson?: any);
26
- }