@carto/api-client 0.4.2-alpha.0 → 0.4.2

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.
@@ -16,10 +16,9 @@ import {
16
16
  TableResponse,
17
17
  TimeSeriesRequestOptions,
18
18
  TimeSeriesResponse,
19
- ViewState,
20
19
  } from './types.js';
21
20
  import {FilterLogicalOperator, Filter} from '../types.js';
22
- import {assert, getApplicableFilters, normalizeObjectKeys} from '../utils.js';
21
+ import {getApplicableFilters, normalizeObjectKeys} from '../utils.js';
23
22
  import {getClient} from '../client.js';
24
23
  import {ModelSource} from '../models/model.js';
25
24
  import {SourceOptions} from '../sources/index.js';
@@ -28,11 +27,10 @@ import {
28
27
  DEFAULT_GEO_COLUMN,
29
28
  DEFAULT_TILE_RESOLUTION,
30
29
  } from '../constants-internal.js';
31
- import {getSpatialFiltersResolution} from '../spatial-index.js';
32
- import {AggregationOptions} from '../sources/types.js';
33
30
 
34
31
  export interface WidgetBaseSourceProps extends Omit<SourceOptions, 'filters'> {
35
32
  apiVersion?: ApiVersion;
33
+ geoColumn?: string;
36
34
  filters?: Record<string, Filter>;
37
35
  filtersLogicalOperator?: FilterLogicalOperator;
38
36
  }
@@ -53,6 +51,7 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
53
51
  clientId: getClient(),
54
52
  filters: {},
55
53
  filtersLogicalOperator: 'and',
54
+ geoColumn: DEFAULT_GEO_COLUMN,
56
55
  };
57
56
 
58
57
  constructor(props: Props) {
@@ -79,9 +78,7 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
79
78
  connectionName: props.connectionName,
80
79
  filters: getApplicableFilters(owner, props.filters),
81
80
  filtersLogicalOperator: props.filtersLogicalOperator,
82
- spatialDataType: props.spatialDataType,
83
- spatialDataColumn: props.spatialDataColumn,
84
- dataResolution: (props as Partial<AggregationOptions>).dataResolution,
81
+ geoColumn: props.geoColumn,
85
82
  };
86
83
  }
87
84
 
@@ -96,35 +93,14 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
96
93
  async getCategories(
97
94
  options: CategoryRequestOptions
98
95
  ): Promise<CategoryResponse> {
99
- const {
100
- filterOwner,
101
- spatialFilter,
102
- spatialFiltersMode,
103
- abortController,
104
- viewState,
105
- ...params
106
- } = options;
96
+ const {filterOwner, spatialFilter, abortController, ...params} = options;
107
97
  const {column, operation, operationColumn} = params;
108
- const source = this.getModelSource(filterOwner);
109
-
110
- let spatialFiltersResolution: number | undefined;
111
- if (spatialFilter && source.spatialDataType !== 'geo') {
112
- spatialFiltersResolution = getSpatialFiltersResolution({
113
- source,
114
- viewState,
115
- });
116
- }
117
98
 
118
99
  type CategoriesModelResponse = {rows: {name: string; value: number}[]};
119
100
 
120
101
  return executeModel({
121
102
  model: 'category',
122
- source: {
123
- ...source,
124
- spatialFiltersResolution,
125
- spatialFiltersMode,
126
- spatialFilter,
127
- },
103
+ source: {...this.getModelSource(filterOwner), spatialFilter},
128
104
  params: {
129
105
  column,
130
106
  operation,
@@ -149,35 +125,14 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
149
125
  async getFeatures(
150
126
  options: FeaturesRequestOptions
151
127
  ): Promise<FeaturesResponse> {
152
- const {
153
- filterOwner,
154
- spatialFilter,
155
- spatialFiltersMode,
156
- abortController,
157
- viewState,
158
- ...params
159
- } = options;
128
+ const {filterOwner, spatialFilter, abortController, ...params} = options;
160
129
  const {columns, dataType, featureIds, z, limit, tileResolution} = params;
161
- const source = this.getModelSource(filterOwner);
162
-
163
- let spatialFiltersResolution: number | undefined;
164
- if (spatialFilter && source.spatialDataType !== 'geo') {
165
- spatialFiltersResolution = getSpatialFiltersResolution({
166
- source,
167
- viewState,
168
- });
169
- }
170
130
 
171
131
  type FeaturesModelResponse = {rows: Record<string, unknown>[]};
172
132
 
173
133
  return executeModel({
174
134
  model: 'pick',
175
- source: {
176
- ...source,
177
- spatialFiltersResolution,
178
- spatialFiltersMode,
179
- spatialFilter,
180
- },
135
+ source: {...this.getModelSource(filterOwner), spatialFilter},
181
136
  params: {
182
137
  columns,
183
138
  dataType,
@@ -187,9 +142,8 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
187
142
  tileResolution: tileResolution || DEFAULT_TILE_RESOLUTION,
188
143
  },
189
144
  opts: {abortController},
190
- }).then((res: FeaturesModelResponse) => ({
191
- rows: normalizeObjectKeys(res.rows),
192
- }));
145
+ // Avoid `normalizeObjectKeys()`, which changes column names.
146
+ }).then(({rows}: FeaturesModelResponse) => ({rows}));
193
147
  }
194
148
 
195
149
  /****************************************************************************
@@ -204,33 +158,17 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
204
158
  const {
205
159
  filterOwner,
206
160
  spatialFilter,
207
- spatialFiltersMode,
208
161
  abortController,
209
162
  operationExp,
210
- viewState,
211
163
  ...params
212
164
  } = options;
213
165
  const {column, operation} = params;
214
- const source = this.getModelSource(filterOwner);
215
-
216
- let spatialFiltersResolution: number | undefined;
217
- if (spatialFilter && source.spatialDataType !== 'geo') {
218
- spatialFiltersResolution = getSpatialFiltersResolution({
219
- source,
220
- viewState,
221
- });
222
- }
223
166
 
224
167
  type FormulaModelResponse = {rows: {value: number}[]};
225
168
 
226
169
  return executeModel({
227
170
  model: 'formula',
228
- source: {
229
- ...source,
230
- spatialFiltersResolution,
231
- spatialFiltersMode,
232
- spatialFilter,
233
- },
171
+ source: {...this.getModelSource(filterOwner), spatialFilter},
234
172
  params: {column: column ?? '*', operation, operationExp},
235
173
  opts: {abortController},
236
174
  }).then((res: FormulaModelResponse) => normalizeObjectKeys(res.rows[0]));
@@ -247,35 +185,14 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
247
185
  async getHistogram(
248
186
  options: HistogramRequestOptions
249
187
  ): Promise<HistogramResponse> {
250
- const {
251
- filterOwner,
252
- spatialFilter,
253
- spatialFiltersMode,
254
- abortController,
255
- viewState,
256
- ...params
257
- } = options;
188
+ const {filterOwner, spatialFilter, abortController, ...params} = options;
258
189
  const {column, operation, ticks} = params;
259
- const source = this.getModelSource(filterOwner);
260
-
261
- let spatialFiltersResolution: number | undefined;
262
- if (spatialFilter && source.spatialDataType !== 'geo') {
263
- spatialFiltersResolution = getSpatialFiltersResolution({
264
- source,
265
- viewState,
266
- });
267
- }
268
190
 
269
191
  type HistogramModelResponse = {rows: {tick: number; value: number}[]};
270
192
 
271
193
  const data = await executeModel({
272
194
  model: 'histogram',
273
- source: {
274
- ...source,
275
- spatialFiltersResolution,
276
- spatialFiltersMode,
277
- spatialFilter,
278
- },
195
+ source: {...this.getModelSource(filterOwner), spatialFilter},
279
196
  params: {column, operation, ticks},
280
197
  opts: {abortController},
281
198
  }).then((res: HistogramModelResponse) => normalizeObjectKeys(res.rows));
@@ -303,35 +220,14 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
303
220
  * or rendering a range slider UI for filtering.
304
221
  */
305
222
  async getRange(options: RangeRequestOptions): Promise<RangeResponse> {
306
- const {
307
- filterOwner,
308
- spatialFilter,
309
- spatialFiltersMode,
310
- abortController,
311
- viewState,
312
- ...params
313
- } = options;
223
+ const {filterOwner, spatialFilter, abortController, ...params} = options;
314
224
  const {column} = params;
315
- const source = this.getModelSource(filterOwner);
316
-
317
- let spatialFiltersResolution: number | undefined;
318
- if (spatialFilter && source.spatialDataType !== 'geo') {
319
- spatialFiltersResolution = getSpatialFiltersResolution({
320
- source,
321
- viewState,
322
- });
323
- }
324
225
 
325
226
  type RangeModelResponse = {rows: {min: number; max: number}[]};
326
227
 
327
228
  return executeModel({
328
229
  model: 'range',
329
- source: {
330
- ...source,
331
- spatialFiltersResolution,
332
- spatialFiltersMode,
333
- spatialFilter,
334
- },
230
+ source: {...this.getModelSource(filterOwner), spatialFilter},
335
231
  params: {column},
336
232
  opts: {abortController},
337
233
  }).then((res: RangeModelResponse) => normalizeObjectKeys(res.rows[0]));
@@ -346,27 +242,10 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
346
242
  * values. Suitable for rendering scatter plots.
347
243
  */
348
244
  async getScatter(options: ScatterRequestOptions): Promise<ScatterResponse> {
349
- const {
350
- filterOwner,
351
- spatialFilter,
352
- spatialFiltersMode,
353
- abortController,
354
- viewState,
355
- ...params
356
- } = options;
245
+ const {filterOwner, spatialFilter, abortController, ...params} = options;
357
246
  const {xAxisColumn, xAxisJoinOperation, yAxisColumn, yAxisJoinOperation} =
358
247
  params;
359
248
 
360
- const source = this.getModelSource(filterOwner);
361
-
362
- let spatialFiltersResolution: number | undefined;
363
- if (spatialFilter && source.spatialDataType !== 'geo') {
364
- spatialFiltersResolution = getSpatialFiltersResolution({
365
- source,
366
- viewState,
367
- });
368
- }
369
-
370
249
  // Make sure this is sync with the same constant in cloud-native/maps-api
371
250
  const HARD_LIMIT = 500;
372
251
 
@@ -374,12 +253,7 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
374
253
 
375
254
  return executeModel({
376
255
  model: 'scatterplot',
377
- source: {
378
- ...source,
379
- spatialFiltersResolution,
380
- spatialFiltersMode,
381
- spatialFilter,
382
- },
256
+ source: {...this.getModelSource(filterOwner), spatialFilter},
383
257
  params: {
384
258
  xAxisColumn,
385
259
  xAxisJoinOperation,
@@ -402,24 +276,8 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
402
276
  * sorting. Suitable for displaying tables and lists.
403
277
  */
404
278
  async getTable(options: TableRequestOptions): Promise<TableResponse> {
405
- const {
406
- filterOwner,
407
- spatialFilter,
408
- spatialFiltersMode,
409
- abortController,
410
- viewState,
411
- ...params
412
- } = options;
279
+ const {filterOwner, spatialFilter, abortController, ...params} = options;
413
280
  const {columns, sortBy, sortDirection, offset = 0, limit = 10} = params;
414
- const source = this.getModelSource(filterOwner);
415
-
416
- let spatialFiltersResolution: number | undefined;
417
- if (spatialFilter && source.spatialDataType !== 'geo') {
418
- spatialFiltersResolution = getSpatialFiltersResolution({
419
- source,
420
- viewState,
421
- });
422
- }
423
281
 
424
282
  type TableModelResponse = {
425
283
  rows: Record<string, number | string>[];
@@ -428,12 +286,7 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
428
286
 
429
287
  return executeModel({
430
288
  model: 'table',
431
- source: {
432
- ...source,
433
- spatialFiltersResolution,
434
- spatialFiltersMode,
435
- spatialFilter,
436
- },
289
+ source: {...this.getModelSource(filterOwner), spatialFilter},
437
290
  params: {
438
291
  column: columns,
439
292
  sortBy,
@@ -460,14 +313,7 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
460
313
  async getTimeSeries(
461
314
  options: TimeSeriesRequestOptions
462
315
  ): Promise<TimeSeriesResponse> {
463
- const {
464
- filterOwner,
465
- abortController,
466
- spatialFilter,
467
- spatialFiltersMode,
468
- viewState,
469
- ...params
470
- } = options;
316
+ const {filterOwner, abortController, spatialFilter, ...params} = options;
471
317
  const {
472
318
  column,
473
319
  operationColumn,
@@ -480,16 +326,6 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
480
326
  splitByCategoryValues,
481
327
  } = params;
482
328
 
483
- const source = this.getModelSource(filterOwner);
484
-
485
- let spatialFiltersResolution: number | undefined;
486
- if (spatialFilter && source.spatialDataType !== 'geo') {
487
- spatialFiltersResolution = getSpatialFiltersResolution({
488
- source,
489
- viewState,
490
- });
491
- }
492
-
493
329
  type TimeSeriesModelResponse = {
494
330
  rows: {name: string; value: number}[];
495
331
  metadata: {categories: string[]};
@@ -497,12 +333,7 @@ export abstract class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
497
333
 
498
334
  return executeModel({
499
335
  model: 'timeseries',
500
- source: {
501
- ...source,
502
- spatialFiltersResolution,
503
- spatialFiltersMode,
504
- spatialFilter,
505
- },
336
+ source: {...this.getModelSource(filterOwner), spatialFilter},
506
337
  params: {
507
338
  column,
508
339
  stepSize,
@@ -1,11 +0,0 @@
1
- import type { ModelSource } from './models/model';
2
- import type { AggregationOptions } from './sources/types';
3
- import type { ViewState } from './widget-sources';
4
- export declare function getSpatialFiltersResolution({ source, viewState, }: {
5
- source: Partial<ModelSource & AggregationOptions>;
6
- viewState?: ViewState;
7
- }): number | undefined;
8
- export declare function getHexagonResolution(viewport: {
9
- zoom: number;
10
- latitude: number;
11
- }, tileSize: number): number;
@@ -1,119 +0,0 @@
1
- import {
2
- DEFAULT_AGGREGATION_RES_LEVEL_H3,
3
- DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN,
4
- } from './constants-internal';
5
- import type {ModelSource} from './models/model';
6
- import type {AggregationOptions} from './sources/types';
7
- import {assert} from './utils';
8
- import type {ViewState} from './widget-sources';
9
-
10
- const DEFAULT_TILE_SIZE = 512;
11
- const QUADBIN_ZOOM_MAX_OFFSET = 4;
12
-
13
- export function getSpatialFiltersResolution({
14
- source,
15
- viewState,
16
- }: {
17
- source: Partial<ModelSource & AggregationOptions>;
18
- viewState?: ViewState;
19
- }) {
20
- assert(
21
- viewState,
22
- 'viewState prop is required to compute automatic spatialFiltersResolution when using spatialFilter with spatial indexes. Either pass a `spatialFiltersResolution` prop or a `viewState` prop to avoid this error'
23
- );
24
-
25
- const dataResolution = source.dataResolution ?? Number.MAX_VALUE;
26
-
27
- const aggregationResLevel =
28
- source.aggregationResLevel ??
29
- (source.spatialDataType === 'h3'
30
- ? DEFAULT_AGGREGATION_RES_LEVEL_H3
31
- : DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN);
32
-
33
- const aggregationResLevelOffset = Math.max(
34
- 0,
35
- Math.floor(aggregationResLevel)
36
- );
37
-
38
- const currentZoomInt = Math.ceil(viewState.zoom);
39
- if (source.spatialDataType === 'h3') {
40
- const tileSize = DEFAULT_TILE_SIZE;
41
- const maxResolutionForZoom =
42
- maxH3SpatialFiltersResolutions.find(
43
- ([zoom]) => zoom === currentZoomInt
44
- )?.[1] ?? Math.max(0, currentZoomInt - 3);
45
-
46
- const maxSpatialFiltersResolution = maxResolutionForZoom
47
- ? Math.min(dataResolution, maxResolutionForZoom)
48
- : dataResolution;
49
-
50
- const hexagonResolution =
51
- getHexagonResolution(viewState, tileSize) + aggregationResLevelOffset;
52
-
53
- return Math.min(hexagonResolution, maxSpatialFiltersResolution);
54
- }
55
-
56
- if (source.spatialDataType === 'quadbin') {
57
- const maxResolutionForZoom = currentZoomInt + QUADBIN_ZOOM_MAX_OFFSET;
58
- const maxSpatialFiltersResolution = Math.min(
59
- dataResolution,
60
- maxResolutionForZoom
61
- );
62
-
63
- const quadsResolution =
64
- Math.floor(viewState.zoom) + aggregationResLevelOffset;
65
- return Math.min(quadsResolution, maxSpatialFiltersResolution);
66
- }
67
-
68
- return undefined;
69
- }
70
-
71
- const maxH3SpatialFiltersResolutions = [
72
- [20, 14],
73
- [19, 13],
74
- [18, 12],
75
- [17, 11],
76
- [16, 10],
77
- [15, 9],
78
- [14, 8],
79
- [13, 7],
80
- [12, 7],
81
- [11, 7],
82
- [10, 6],
83
- [9, 6],
84
- [8, 5],
85
- [7, 4],
86
- [6, 4],
87
- [5, 3],
88
- [4, 2],
89
- [3, 1],
90
- [2, 1],
91
- [1, 0],
92
- ];
93
-
94
- // stolen from https://github.com/visgl/deck.gl/blob/master/modules/carto/src/layers/h3-tileset-2d.ts
95
-
96
- // Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
97
- const BIAS = 2;
98
-
99
- // Resolution conversion function. Takes a WebMercatorViewport and returns
100
- // a H3 resolution such that the screen space size of the hexagons is
101
- // similar
102
- export function getHexagonResolution(
103
- viewport: {zoom: number; latitude: number},
104
- tileSize: number
105
- ): number {
106
- // Difference in given tile size compared to deck's internal 512px tile size,
107
- // expressed as an offset to the viewport zoom.
108
- const zoomOffset = Math.log2(tileSize / DEFAULT_TILE_SIZE);
109
- const hexagonScaleFactor = (2 / 3) * (viewport.zoom - zoomOffset);
110
- const latitudeScaleFactor = Math.log(
111
- 1 / Math.cos((Math.PI * viewport.latitude) / 180)
112
- );
113
-
114
- // Clip and bias
115
- return Math.max(
116
- 0,
117
- Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS)
118
- );
119
- }