@carto/api-client 0.5.0-alpha.0 → 0.5.0-alpha.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 (127) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/build/api-client.cjs +3178 -3200
  3. package/build/api-client.cjs.map +1 -1
  4. package/build/api-client.d.cts +1389 -0
  5. package/build/api-client.d.ts +1389 -0
  6. package/build/api-client.js +3674 -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 +60 -45
  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 +146 -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 +3 -2
  38. package/src/sources/boundary-table-source.ts +3 -2
  39. package/src/sources/h3-query-source.ts +14 -8
  40. package/src/sources/h3-table-source.ts +14 -8
  41. package/src/sources/h3-tileset-source.ts +4 -4
  42. package/src/sources/index.ts +28 -26
  43. package/src/sources/quadbin-query-source.ts +14 -8
  44. package/src/sources/quadbin-table-source.ts +13 -8
  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 +9 -5
  49. package/src/sources/vector-table-source.ts +9 -5
  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 +201 -289
  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 -3553
  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 -67
@@ -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,321 +56,253 @@ export type WidgetTilesetSourceResult = {widgetSource: WidgetTilesetSource};
76
56
  * ```
77
57
  */
78
58
  export class WidgetTilesetSource extends WidgetSource<WidgetTilesetSourceProps> {
79
- private _features: FeatureData[] = [];
80
-
81
- protected override getModelSource(owner: string): ModelSource {
82
- return {
83
- ...super._getModelSource(owner),
84
- type: 'tileset',
85
- data: this.props.tableName,
86
- };
87
- }
59
+ protected _localImpl: WidgetTilesetSourceImpl | null = null;
88
60
 
89
- /** Loads features as a list of tiles (typically provided by deck.gl). */
90
- loadTiles({
91
- tiles,
92
- spatialFilter,
93
- uniqueIdProperty,
94
- options,
95
- }: {
96
- tiles: Tile[];
97
- spatialFilter: SpatialFilter;
98
- // TODO(cleanup): As an optional property, 'uniqueIdProperty' will be easy to forget.
99
- // Would it be better to configure it on the source function, rather than separately
100
- // on the layer and in 'loadTiles()'?
101
- uniqueIdProperty?: string;
102
- options?: TileFeatureExtractOptions;
103
- }) {
104
- this._features = tileFeatures({
105
- tiles,
106
- options,
107
- spatialFilter,
108
- uniqueIdProperty,
109
- tileFormat: this.props.tileFormat,
110
- spatialDataColumn: this.props.spatialDataColumn,
111
- spatialDataType: this.props.spatialDataType,
112
- });
113
- }
61
+ protected _workerImpl: Worker | null = null;
62
+ protected _workerEnabled: boolean;
63
+ protected _workerNextRequestId = 1;
114
64
 
115
- /** Loads features as GeoJSON (used for testing). */
116
- loadGeoJSON({
117
- geojson,
118
- spatialFilter,
119
- uniqueIdProperty,
120
- }: {
121
- geojson: FeatureCollection;
122
- spatialFilter: SpatialFilter;
123
- uniqueIdProperty?: string;
124
- }) {
125
- this._features = geojsonFeatures({
126
- geojson,
127
- spatialFilter,
128
- uniqueIdProperty,
129
- });
130
- }
65
+ constructor(props: WidgetTilesetSourceProps) {
66
+ super(props);
131
67
 
132
- override async getFeatures(
133
- options: FeaturesRequestOptions
134
- ): Promise<FeaturesResponse> {
135
- throw new Error('getFeatures not supported for tilesets');
136
- }
68
+ this._workerEnabled =
69
+ (props.widgetWorker ?? true) &&
70
+ TSUP_FORMAT !== 'cjs' &&
71
+ typeof Worker !== 'undefined';
137
72
 
138
- async getFormula({
139
- column = '*',
140
- operation = 'count',
141
- joinOperation,
142
- filterOwner,
143
- }: FormulaRequestOptions): Promise<FormulaResponse> {
144
- if (operation === 'custom') {
145
- throw new Error('Custom aggregation not supported for tilesets');
146
- }
147
-
148
- if (!this._features.length) {
149
- return {value: null};
150
- }
151
-
152
- // Column is required except when operation is 'count'.
153
- if ((column && column !== '*') || operation !== 'count') {
154
- assertColumn(this._features, column);
73
+ if (!this._workerEnabled) {
74
+ this._localImpl = new WidgetTilesetSourceImpl(this.props);
155
75
  }
76
+ }
156
77
 
157
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
78
+ destroy() {
79
+ this._localImpl?.destroy();
80
+ this._localImpl = null;
158
81
 
159
- if (filteredFeatures.length === 0 && operation !== 'count') {
160
- return {value: null};
161
- }
82
+ this._workerImpl?.terminate();
83
+ this._workerImpl = null;
162
84
 
163
- const targetOperation = aggregationFunctions[operation];
164
- return {
165
- value: targetOperation(
166
- filteredFeatures as FeatureData[],
167
- column,
168
- joinOperation
169
- ),
170
- };
85
+ super.destroy();
171
86
  }
172
87
 
173
- override async getHistogram({
174
- operation = 'count',
175
- ticks,
176
- column,
177
- joinOperation,
178
- filterOwner,
179
- }: HistogramRequestOptions): Promise<HistogramResponse> {
180
- if (!this._features.length) {
181
- return [];
88
+ /////////////////////////////////////////////////////////////////////////////
89
+ // WEB WORKER MANAGEMENT
90
+
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;
182
98
  }
183
99
 
184
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
100
+ this._workerImpl = new Worker(
101
+ new URL('@carto/api-client/worker', import.meta.url),
102
+ {
103
+ type: 'module',
104
+ name: 'cartowidgettileset',
105
+ }
106
+ );
185
107
 
186
- assertColumn(this._features, column);
108
+ this._workerImpl.postMessage({
109
+ method: Method.INIT,
110
+ params: [this.props],
111
+ } as WorkerRequest);
187
112
 
188
- return histogram({
189
- data: filteredFeatures,
190
- valuesColumns: normalizeColumns(column),
191
- joinOperation,
192
- ticks,
193
- operation,
194
- });
113
+ return this._workerImpl;
195
114
  }
196
115
 
197
- override async getCategories({
198
- column,
199
- operation = 'count',
200
- operationColumn,
201
- joinOperation,
202
- filterOwner,
203
- }: CategoryRequestOptions): Promise<CategoryResponse> {
204
- if (!this._features.length) {
205
- 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);
206
125
  }
207
126
 
208
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
127
+ const worker = this._getWorker();
128
+ const requestId = this._workerNextRequestId++;
209
129
 
210
- assertColumn(this._features, column as string, operationColumn as string);
211
-
212
- const groups = groupValuesByColumn({
213
- data: filteredFeatures,
214
- valuesColumns: normalizeColumns(operationColumn || column),
215
- joinOperation,
216
- keysColumn: column,
217
- operation,
218
- });
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
+ }
219
138
 
220
- return groups || [];
221
- }
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
+
149
+ if (signal?.aborted) {
150
+ reject!(new Error(signal.reason));
151
+ } else if (response.ok) {
152
+ resolve!(response.result as T);
153
+ } else {
154
+ reject!(new Error(response.error));
155
+ }
156
+ }
222
157
 
223
- override async getScatter({
224
- xAxisColumn,
225
- yAxisColumn,
226
- xAxisJoinOperation,
227
- yAxisJoinOperation,
228
- filterOwner,
229
- }: ScatterRequestOptions): Promise<ScatterResponse> {
230
- if (!this._features.length) {
231
- return [];
158
+ // If request is aborted by user, immediately reject the Promise.
159
+ function onAbort() {
160
+ reject!(new Error(signal!.reason));
232
161
  }
233
162
 
234
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
163
+ worker.addEventListener('message', onMessage);
164
+ signal?.addEventListener('abort', onAbort);
165
+
166
+ // Send the task to the worker, creating a Promise to resolve/reject later.
167
+ const promise = new Promise<T>((_resolve, _reject) => {
168
+ resolve = _resolve;
169
+ reject = _reject;
235
170
 
236
- assertColumn(this._features, xAxisColumn, yAxisColumn);
171
+ worker.postMessage({
172
+ requestId,
173
+ method,
174
+ params,
175
+ } as WorkerRequest);
176
+ });
237
177
 
238
- return scatterPlot({
239
- data: filteredFeatures,
240
- xAxisColumns: normalizeColumns(xAxisColumn),
241
- xAxisJoinOperation,
242
- yAxisColumns: normalizeColumns(yAxisColumn),
243
- yAxisJoinOperation,
178
+ // Whether the task completes, fails, or aborts: clean up afterward.
179
+ void promise.finally(() => {
180
+ worker.removeEventListener('message', onMessage);
181
+ signal?.removeEventListener('abort', onAbort);
244
182
  });
183
+
184
+ return promise;
245
185
  }
246
186
 
247
- override async getTable(
248
- options: TableRequestOptions
249
- ): Promise<TableResponse> {
250
- const {filterOwner, spatialFilter, abortController, ...params} = options;
251
- const {
252
- columns,
253
- searchFilterColumn,
254
- searchFilterText,
255
- sortBy,
256
- sortDirection,
257
- sortByColumnType,
258
- offset = 0,
259
- limit = 10,
260
- } = params;
261
-
262
- if (!this._features.length) {
263
- return {rows: [], totalCount: 0};
264
- }
187
+ /////////////////////////////////////////////////////////////////////////////
188
+ // DATA LOADING
265
189
 
266
- // Filter.
267
- let filteredFeatures = this._getFilteredFeatures(filterOwner);
268
-
269
- // Search.
270
- // TODO: Could we get the same behavior by applying filters in loadTiles()?
271
- if (searchFilterColumn && searchFilterText) {
272
- filteredFeatures = filteredFeatures.filter(
273
- (row) =>
274
- row[searchFilterColumn] &&
275
- String(row[searchFilterColumn])
276
- .toLowerCase()
277
- .includes(String(searchFilterText).toLowerCase())
278
- );
190
+ /**
191
+ * Loads features as a list of tiles (typically provided by deck.gl).
192
+ * After tiles are loaded, {@link extractTileFeatures} must be called
193
+ * before computing statistics on the tiles.
194
+ */
195
+ loadTiles(tiles: unknown[]) {
196
+ if (!this._workerEnabled) {
197
+ return this._localImpl!.loadTiles(tiles);
279
198
  }
280
199
 
281
- // Sort.
282
- let rows = applySorting(filteredFeatures, {
283
- sortBy,
284
- sortByDirection: sortDirection,
285
- sortByColumnType,
286
- });
287
- const totalCount = rows.length;
200
+ const worker = this._getWorker();
288
201
 
289
- // Offset and limit.
290
- rows = rows.slice(
291
- Math.min(offset, totalCount),
292
- Math.min(offset + limit, totalCount)
293
- );
202
+ tiles = (tiles as Tile[]).map(({id, bbox, data}) => ({
203
+ id,
204
+ bbox,
205
+ data,
206
+ }));
294
207
 
295
- // Select columns.
296
- rows = rows.map((srcRow: FeatureData) => {
297
- const dstRow: FeatureData = {};
298
- for (const column of columns) {
299
- dstRow[column] = srcRow[column];
300
- }
301
- return dstRow;
302
- });
303
-
304
- return {rows, totalCount} as TableResponse;
208
+ worker.postMessage({
209
+ method: Method.LOAD_TILES,
210
+ params: [tiles],
211
+ } as WorkerRequest);
305
212
  }
306
213
 
307
- override async getTimeSeries({
308
- column,
309
- stepSize,
310
- operation,
311
- operationColumn,
312
- joinOperation,
313
- filterOwner,
314
- }: TimeSeriesRequestOptions): Promise<TimeSeriesResponse> {
315
- if (!this._features.length) {
316
- return {rows: []};
214
+ /** Configures options used to extract features from tiles. */
215
+ setTileFeatureExtractOptions(options: TileFeatureExtractOptions) {
216
+ if (!this._workerEnabled) {
217
+ return this._localImpl?.setTileFeatureExtractOptions(options);
317
218
  }
318
219
 
319
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
320
-
321
- assertColumn(this._features, column as string, operationColumn as string);
322
-
323
- const rows =
324
- groupValuesByDateColumn({
325
- data: filteredFeatures,
326
- valuesColumns: normalizeColumns(operationColumn || column),
327
- keysColumn: column,
328
- groupType: stepSize,
329
- operation,
330
- joinOperation,
331
- }) || [];
220
+ const worker = this._getWorker();
332
221
 
333
- return {rows};
222
+ worker.postMessage({
223
+ type: Method.SET_TILE_FEATURE_EXTRACT_OPTIONS,
224
+ params: [options],
225
+ });
334
226
  }
335
227
 
336
- override async getRange({
337
- column,
338
- filterOwner,
339
- }: RangeRequestOptions): Promise<RangeResponse> {
340
- if (!this._features.length) {
341
- // TODO: Is this the only nullable response in the Widgets API? If so,
342
- // can we do something more consistent?
343
- return null;
228
+ /**
229
+ * Loads features as GeoJSON (used for testing).
230
+ * @experimental
231
+ * @internal Not for public use. Spatial filters in other method calls will be ignored.
232
+ */
233
+ loadGeoJSON({
234
+ geojson,
235
+ spatialFilter,
236
+ }: {
237
+ geojson: FeatureCollection;
238
+ spatialFilter: SpatialFilter;
239
+ }) {
240
+ if (!this._workerEnabled) {
241
+ return this._localImpl!.loadGeoJSON({geojson, spatialFilter});
344
242
  }
345
243
 
346
- assertColumn(this._features, column);
244
+ const worker = this._getWorker();
347
245
 
348
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
349
- return {
350
- min: aggregationFunctions.min(filteredFeatures, column),
351
- max: aggregationFunctions.max(filteredFeatures, column),
352
- };
246
+ worker.postMessage({
247
+ method: Method.LOAD_GEOJSON,
248
+ params: [{geojson, spatialFilter}],
249
+ } as WorkerRequest);
353
250
  }
354
251
 
355
- /****************************************************************************
356
- * INTERNAL
357
- */
252
+ /////////////////////////////////////////////////////////////////////////////
253
+ // WIDGETS API
358
254
 
359
- private _getFilteredFeatures(filterOwner: string | undefined): FeatureData[] {
360
- return applyFilters(
361
- this._features,
362
- getApplicableFilters(filterOwner, this.props.filters),
363
- this.props.filtersLogicalOperator || 'and'
364
- );
255
+ // eslint-disable-next-line @typescript-eslint/require-await
256
+ override async getFeatures(): Promise<FeaturesResponse> {
257
+ throw new Error('getFeatures not supported for tilesets');
258
+ }
259
+
260
+ async getFormula({
261
+ signal,
262
+ ...options
263
+ }: FormulaRequestOptions): Promise<FormulaResponse> {
264
+ return this._executeWorkerMethod(Method.GET_FORMULA, [options], signal);
365
265
  }
366
- }
367
266
 
368
- function assertColumn(
369
- features: FeatureData[],
370
- ...columnArgs: string[] | string[][]
371
- ) {
372
- // TODO(cleanup): Can drop support for multiple column shapes here?
267
+ override async getHistogram({
268
+ signal,
269
+ ...options
270
+ }: HistogramRequestOptions): Promise<HistogramResponse> {
271
+ return this._executeWorkerMethod(Method.GET_HISTOGRAM, [options], signal);
272
+ }
373
273
 
374
- // Due to the multiple column shape, we normalise it as an array with normalizeColumns
375
- const columns = Array.from(new Set(columnArgs.map(normalizeColumns).flat()));
274
+ override async getCategories({
275
+ signal,
276
+ ...options
277
+ }: CategoryRequestOptions): Promise<CategoryResponse> {
278
+ return this._executeWorkerMethod(Method.GET_CATEGORIES, [options], signal);
279
+ }
376
280
 
377
- const featureKeys = Object.keys(features[0]);
281
+ override async getScatter({
282
+ signal,
283
+ ...options
284
+ }: ScatterRequestOptions): Promise<ScatterResponse> {
285
+ return this._executeWorkerMethod(Method.GET_SCATTER, [options], signal);
286
+ }
378
287
 
379
- const invalidColumns = columns.filter(
380
- (column) => !featureKeys.includes(column)
381
- );
288
+ override async getTable({
289
+ signal,
290
+ ...options
291
+ }: TableRequestOptions): Promise<TableResponse> {
292
+ return this._executeWorkerMethod(Method.GET_TABLE, [options], signal);
293
+ }
382
294
 
383
- if (invalidColumns.length) {
384
- throw new InvalidColumnError(
385
- `Missing column(s): ${invalidColumns.join(', ')}`
386
- );
295
+ override async getTimeSeries({
296
+ signal,
297
+ ...options
298
+ }: TimeSeriesRequestOptions): Promise<TimeSeriesResponse> {
299
+ return this._executeWorkerMethod(Method.GET_TIME_SERIES, [options], signal);
387
300
  }
388
- }
389
301
 
390
- function normalizeColumns(columns: string | string[]): string[] {
391
- return Array.isArray(columns)
392
- ? columns
393
- : typeof columns === 'string'
394
- ? [columns]
395
- : [];
302
+ override async getRange({
303
+ signal,
304
+ ...options
305
+ }: RangeRequestOptions): Promise<RangeResponse> {
306
+ return this._executeWorkerMethod(Method.GET_RANGE, [options], signal);
307
+ }
396
308
  }
@@ -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
- }