@carto/api-client 0.5.0-alpha.1 → 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 +4 -0
  2. package/build/api-client.cjs +3163 -3206
  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 +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 +200 -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,253 @@ 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
+
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
+ }
207
157
 
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 [];
158
+ // If request is aborted by user, immediately reject the Promise.
159
+ function onAbort() {
160
+ reject!(new Error(signal!.reason));
217
161
  }
218
162
 
219
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
163
+ worker.addEventListener('message', onMessage);
164
+ signal?.addEventListener('abort', onAbort);
220
165
 
221
- assertColumn(this._features, column as string, operationColumn as string);
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;
222
170
 
223
- const groups = groupValuesByColumn({
224
- data: filteredFeatures,
225
- valuesColumns: normalizeColumns(operationColumn || column),
226
- joinOperation,
227
- keysColumn: column,
228
- operation,
171
+ worker.postMessage({
172
+ requestId,
173
+ method,
174
+ params,
175
+ } as WorkerRequest);
229
176
  });
230
177
 
231
- return groups || [];
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);
182
+ });
183
+
184
+ return promise;
232
185
  }
233
186
 
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 [];
187
+ /////////////////////////////////////////////////////////////////////////////
188
+ // DATA LOADING
189
+
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);
243
198
  }
244
199
 
245
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
200
+ const worker = this._getWorker();
246
201
 
247
- assertColumn(this._features, xAxisColumn, yAxisColumn);
202
+ tiles = (tiles as Tile[]).map(({id, bbox, data}) => ({
203
+ id,
204
+ bbox,
205
+ data,
206
+ }));
248
207
 
249
- return scatterPlot({
250
- data: filteredFeatures,
251
- xAxisColumns: normalizeColumns(xAxisColumn),
252
- xAxisJoinOperation,
253
- yAxisColumns: normalizeColumns(yAxisColumn),
254
- yAxisJoinOperation,
255
- });
208
+ worker.postMessage({
209
+ method: Method.LOAD_TILES,
210
+ params: [tiles],
211
+ } as WorkerRequest);
256
212
  }
257
213
 
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
- );
214
+ /** Configures options used to extract features from tiles. */
215
+ setTileFeatureExtractOptions(options: TileFeatureExtractOptions) {
216
+ if (!this._workerEnabled) {
217
+ return this._localImpl?.setTileFeatureExtractOptions(options);
290
218
  }
291
219
 
292
- // Sort.
293
- let rows = applySorting(filteredFeatures, {
294
- sortBy,
295
- sortByDirection: sortDirection,
296
- sortByColumnType,
297
- });
298
- const totalCount = rows.length;
220
+ const worker = this._getWorker();
299
221
 
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;
222
+ worker.postMessage({
223
+ type: Method.SET_TILE_FEATURE_EXTRACT_OPTIONS,
224
+ params: [options],
313
225
  });
314
-
315
- return {rows, totalCount} as TableResponse;
316
226
  }
317
227
 
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: []};
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});
328
242
  }
329
243
 
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
- }) || [];
244
+ const worker = this._getWorker();
343
245
 
344
- return {rows};
246
+ worker.postMessage({
247
+ method: Method.LOAD_GEOJSON,
248
+ params: [{geojson, spatialFilter}],
249
+ } as WorkerRequest);
345
250
  }
346
251
 
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);
252
+ /////////////////////////////////////////////////////////////////////////////
253
+ // WIDGETS API
358
254
 
359
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
360
- return {
361
- min: aggregationFunctions.min(filteredFeatures, column),
362
- max: aggregationFunctions.max(filteredFeatures, column),
363
- };
255
+ // eslint-disable-next-line @typescript-eslint/require-await
256
+ override async getFeatures(): Promise<FeaturesResponse> {
257
+ throw new Error('getFeatures not supported for tilesets');
364
258
  }
365
259
 
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
- );
260
+ async getFormula({
261
+ signal,
262
+ ...options
263
+ }: FormulaRequestOptions): Promise<FormulaResponse> {
264
+ return this._executeWorkerMethod(Method.GET_FORMULA, [options], signal);
376
265
  }
377
- }
378
266
 
379
- function assertColumn(
380
- features: FeatureData[],
381
- ...columnArgs: string[] | string[][]
382
- ) {
383
- // 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
+ }
384
273
 
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()));
274
+ override async getCategories({
275
+ signal,
276
+ ...options
277
+ }: CategoryRequestOptions): Promise<CategoryResponse> {
278
+ return this._executeWorkerMethod(Method.GET_CATEGORIES, [options], signal);
279
+ }
387
280
 
388
- 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
+ }
389
287
 
390
- const invalidColumns = columns.filter(
391
- (column) => !featureKeys.includes(column)
392
- );
288
+ override async getTable({
289
+ signal,
290
+ ...options
291
+ }: TableRequestOptions): Promise<TableResponse> {
292
+ return this._executeWorkerMethod(Method.GET_TABLE, [options], signal);
293
+ }
393
294
 
394
- if (invalidColumns.length) {
395
- throw new InvalidColumnError(
396
- `Missing column(s): ${invalidColumns.join(', ')}`
397
- );
295
+ override async getTimeSeries({
296
+ signal,
297
+ ...options
298
+ }: TimeSeriesRequestOptions): Promise<TimeSeriesResponse> {
299
+ return this._executeWorkerMethod(Method.GET_TIME_SERIES, [options], signal);
398
300
  }
399
- }
400
301
 
401
- function normalizeColumns(columns: string | string[]): string[] {
402
- return Array.isArray(columns)
403
- ? columns
404
- : typeof columns === 'string'
405
- ? [columns]
406
- : [];
302
+ override async getRange({
303
+ signal,
304
+ ...options
305
+ }: RangeRequestOptions): Promise<RangeResponse> {
306
+ return this._executeWorkerMethod(Method.GET_RANGE, [options], signal);
307
+ }
407
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
- }