@carto/api-client 0.4.6-0 → 0.4.6

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 (81) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/build/api-client.cjs +208 -2167
  3. package/build/api-client.cjs.map +1 -1
  4. package/build/api-client.modern.js +208 -2040
  5. package/build/api-client.modern.js.map +1 -1
  6. package/build/constants.d.ts +0 -22
  7. package/build/index.d.ts +1 -4
  8. package/build/models/index.d.ts +1 -1
  9. package/build/sources/h3-tileset-source.d.ts +1 -2
  10. package/build/sources/index.d.ts +1 -1
  11. package/build/sources/quadbin-tileset-source.d.ts +1 -2
  12. package/build/sources/vector-tileset-source.d.ts +1 -2
  13. package/build/spatial-index.d.ts +7 -1
  14. package/build/types-internal.d.ts +0 -4
  15. package/build/types.d.ts +1 -61
  16. package/build/widget-sources/index.d.ts +1 -3
  17. package/build/widget-sources/types.d.ts +22 -31
  18. package/build/widget-sources/{widget-source.d.ts → widget-base-source.d.ts} +38 -13
  19. package/build/widget-sources/widget-query-source.d.ts +2 -2
  20. package/build/widget-sources/widget-table-source.d.ts +2 -2
  21. package/package.json +11 -14
  22. package/src/constants.ts +0 -25
  23. package/src/index.ts +1 -5
  24. package/src/models/index.ts +1 -1
  25. package/src/sources/h3-tileset-source.ts +6 -18
  26. package/src/sources/index.ts +1 -1
  27. package/src/sources/quadbin-tileset-source.ts +6 -18
  28. package/src/sources/raster-source.ts +0 -1
  29. package/src/sources/vector-query-source.ts +2 -5
  30. package/src/sources/vector-table-source.ts +2 -5
  31. package/src/sources/vector-tileset-source.ts +6 -19
  32. package/src/spatial-index.ts +8 -5
  33. package/src/types-internal.ts +0 -6
  34. package/src/types.ts +2 -60
  35. package/src/widget-sources/index.ts +1 -3
  36. package/src/widget-sources/types.ts +22 -32
  37. package/src/widget-sources/{widget-remote-source.ts → widget-base-source.ts} +147 -12
  38. package/src/widget-sources/widget-query-source.ts +3 -6
  39. package/src/widget-sources/widget-table-source.ts +3 -6
  40. package/build/filters/Filter.d.ts +0 -13
  41. package/build/filters/FilterTypes.d.ts +0 -3
  42. package/build/filters/geosjonFeatures.d.ts +0 -8
  43. package/build/filters/index.d.ts +0 -6
  44. package/build/filters/tileFeatures.d.ts +0 -20
  45. package/build/filters/tileFeaturesGeometries.d.ts +0 -13
  46. package/build/filters/tileFeaturesSpatialIndex.d.ts +0 -10
  47. package/build/operations/aggregation.d.ts +0 -8
  48. package/build/operations/applySorting.d.ts +0 -20
  49. package/build/operations/groupBy.d.ts +0 -15
  50. package/build/operations/groupByDate.d.ts +0 -11
  51. package/build/operations/histogram.d.ts +0 -13
  52. package/build/operations/index.d.ts +0 -6
  53. package/build/operations/scatterPlot.d.ts +0 -14
  54. package/build/utils/dateUtils.d.ts +0 -10
  55. package/build/utils/getTileFormat.d.ts +0 -3
  56. package/build/utils/makeIntervalComplete.d.ts +0 -2
  57. package/build/utils/transformTileCoordsToWGS84.d.ts +0 -8
  58. package/build/utils/transformToTileCoords.d.ts +0 -9
  59. package/build/widget-sources/widget-remote-source.d.ts +0 -18
  60. package/build/widget-sources/widget-tileset-source.d.ts +0 -76
  61. package/src/filters/Filter.ts +0 -169
  62. package/src/filters/FilterTypes.ts +0 -109
  63. package/src/filters/geosjonFeatures.ts +0 -32
  64. package/src/filters/index.ts +0 -6
  65. package/src/filters/tileFeatures.ts +0 -56
  66. package/src/filters/tileFeaturesGeometries.ts +0 -444
  67. package/src/filters/tileFeaturesSpatialIndex.ts +0 -119
  68. package/src/operations/aggregation.ts +0 -154
  69. package/src/operations/applySorting.ts +0 -109
  70. package/src/operations/groupBy.ts +0 -59
  71. package/src/operations/groupByDate.ts +0 -98
  72. package/src/operations/histogram.ts +0 -66
  73. package/src/operations/index.ts +0 -6
  74. package/src/operations/scatterPlot.ts +0 -50
  75. package/src/utils/dateUtils.ts +0 -28
  76. package/src/utils/getTileFormat.ts +0 -9
  77. package/src/utils/makeIntervalComplete.ts +0 -17
  78. package/src/utils/transformTileCoordsToWGS84.ts +0 -77
  79. package/src/utils/transformToTileCoords.ts +0 -85
  80. package/src/widget-sources/widget-source.ts +0 -160
  81. package/src/widget-sources/widget-tileset-source.ts +0 -407
@@ -1,85 +0,0 @@
1
- import {lngLatToWorld} from '@math.gl/web-mercator';
2
- import {BBox, GeoJsonGeometryTypes, Geometry, Position} from 'geojson';
3
-
4
- type TransformFn = (coordinates: any[], bbox: Position[]) => any[];
5
-
6
- const TRANSFORM_FN: Record<
7
- Exclude<GeoJsonGeometryTypes, 'GeometryCollection'>,
8
- TransformFn
9
- > = {
10
- Point: transformPoint,
11
- MultiPoint: transformMultiPoint,
12
- LineString: transformLineString,
13
- MultiLineString: transformMultiLineString,
14
- Polygon: transformPolygon,
15
- MultiPolygon: transformMultiPolygon,
16
- };
17
-
18
- /**
19
- * Transform WGS84 coordinates to tile coords.
20
- * It's the inverse of deck.gl coordinate-transform (https://github.com/visgl/deck.gl/blob/master/modules/geo-layers/src/mvt-layer/coordinate-transform.js)
21
- *
22
- * @param geometry - any valid geojson geometry
23
- * @param bbox - geojson bbox
24
- */
25
- export function transformToTileCoords<T extends Geometry>(
26
- geometry: T,
27
- bbox: BBox
28
- ): T {
29
- const [west, south, east, north] = bbox;
30
- const nw = projectFlat([west, north]);
31
- const se = projectFlat([east, south]);
32
- const projectedBbox = [nw, se];
33
-
34
- if (geometry.type === 'GeometryCollection') {
35
- throw new Error('Unsupported geometry type GeometryCollection');
36
- }
37
-
38
- const transformFn = TRANSFORM_FN[geometry.type];
39
- const coordinates = transformFn(geometry.coordinates, projectedBbox);
40
- return {...geometry, coordinates};
41
- }
42
-
43
- function transformPoint([pointX, pointY]: Position, [nw, se]: Position[]) {
44
- const x = inverseLerp(nw[0], se[0], pointX);
45
- const y = inverseLerp(nw[1], se[1], pointY);
46
-
47
- return [x, y];
48
- }
49
-
50
- function getPoints(geometry: Position[], bbox: Position[]) {
51
- return geometry.map((g) => transformPoint(projectFlat(g), bbox));
52
- }
53
-
54
- function transformMultiPoint(multiPoint: Position[], bbox: Position[]) {
55
- return getPoints(multiPoint, bbox);
56
- }
57
-
58
- function transformLineString(line: Position[], bbox: Position[]) {
59
- return getPoints(line, bbox);
60
- }
61
-
62
- function transformMultiLineString(
63
- multiLineString: Position[][],
64
- bbox: Position[]
65
- ) {
66
- return multiLineString.map((lineString) =>
67
- transformLineString(lineString, bbox)
68
- );
69
- }
70
-
71
- function transformPolygon(polygon: Position[][], bbox: Position[]) {
72
- return polygon.map((polygonRing) => getPoints(polygonRing, bbox));
73
- }
74
-
75
- function transformMultiPolygon(multiPolygon: Position[][][], bbox: Position[]) {
76
- return multiPolygon.map((polygon) => transformPolygon(polygon, bbox));
77
- }
78
-
79
- function projectFlat(xyz: Position): Position {
80
- return lngLatToWorld(xyz);
81
- }
82
-
83
- function inverseLerp(a: number, b: number, x: number): number {
84
- return (x - a) / (b - a);
85
- }
@@ -1,160 +0,0 @@
1
- import {
2
- CategoryRequestOptions,
3
- CategoryResponse,
4
- FeaturesRequestOptions,
5
- FeaturesResponse,
6
- FormulaRequestOptions,
7
- FormulaResponse,
8
- HistogramRequestOptions,
9
- HistogramResponse,
10
- RangeRequestOptions,
11
- RangeResponse,
12
- ScatterRequestOptions,
13
- ScatterResponse,
14
- TableRequestOptions,
15
- TableResponse,
16
- TimeSeriesRequestOptions,
17
- TimeSeriesResponse,
18
- ViewState,
19
- } from './types.js';
20
- import {FilterLogicalOperator, Filter, SpatialFilter} from '../types.js';
21
- import {getApplicableFilters} from '../utils.js';
22
- import {getClient} from '../client.js';
23
- import {ModelSource} from '../models/model.js';
24
- import {SourceOptions} from '../sources/index.js';
25
- import {ApiVersion, DEFAULT_API_BASE_URL} from '../constants.js';
26
- import {getSpatialFiltersResolution} from '../spatial-index.js';
27
- import {AggregationOptions} from '../sources/types.js';
28
-
29
- export interface WidgetSourceProps extends Omit<SourceOptions, 'filters'> {
30
- apiVersion?: ApiVersion;
31
- filters?: Record<string, Filter>;
32
- filtersLogicalOperator?: FilterLogicalOperator;
33
- }
34
-
35
- /**
36
- * Source for Widget API requests on a data source defined by a SQL query.
37
- *
38
- * Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
39
- */
40
- export abstract class WidgetSource<Props extends WidgetSourceProps> {
41
- readonly props: Props;
42
-
43
- static defaultProps: Partial<WidgetSourceProps> = {
44
- apiVersion: ApiVersion.V3,
45
- apiBaseUrl: DEFAULT_API_BASE_URL,
46
- clientId: getClient(),
47
- filters: {},
48
- filtersLogicalOperator: 'and',
49
- };
50
-
51
- constructor(props: Props) {
52
- this.props = {...WidgetSource.defaultProps, ...props};
53
- }
54
-
55
- /**
56
- * Subclasses of {@link WidgetRemoteSource} must implement this method, calling
57
- * {@link WidgetRemoteSource.prototype._getModelSource} for common source
58
- * properties, and adding additional required properties including 'type' and
59
- * 'data'.
60
- */
61
- protected abstract getModelSource(owner: string | undefined): ModelSource;
62
-
63
- protected _getModelSource(
64
- owner?: string
65
- ): Omit<ModelSource, 'type' | 'data'> {
66
- const props = this.props;
67
- return {
68
- apiVersion: props.apiVersion as ApiVersion,
69
- apiBaseUrl: props.apiBaseUrl as string,
70
- clientId: props.clientId as string,
71
- accessToken: props.accessToken,
72
- connectionName: props.connectionName,
73
- filters: getApplicableFilters(owner, props.filters),
74
- filtersLogicalOperator: props.filtersLogicalOperator,
75
- spatialDataType: props.spatialDataType,
76
- spatialDataColumn: props.spatialDataColumn,
77
- dataResolution: (props as Partial<AggregationOptions>).dataResolution,
78
- };
79
- }
80
-
81
- protected _getSpatialFiltersResolution(
82
- source: Omit<ModelSource, 'type' | 'data'>,
83
- spatialFilter?: SpatialFilter,
84
- referenceViewState?: ViewState
85
- ): number | undefined {
86
- // spatialFiltersResolution applies only to spatial index sources.
87
- if (!spatialFilter || source.spatialDataType === 'geo') {
88
- return;
89
- }
90
-
91
- if (!referenceViewState) {
92
- throw new Error(
93
- 'Missing required option, "spatialIndexReferenceViewState".'
94
- );
95
- }
96
-
97
- return getSpatialFiltersResolution(source, referenceViewState);
98
- }
99
-
100
- /**
101
- * Returns a list of labeled datapoints for categorical data. Suitable for
102
- * charts including grouped bar charts, pie charts, and tree charts.
103
- */
104
- abstract getCategories(
105
- options: CategoryRequestOptions
106
- ): Promise<CategoryResponse>;
107
-
108
- /**
109
- * Given a list of feature IDs (as found in `_carto_feature_id`) returns all
110
- * matching features. In datasets containing features with duplicate geometries,
111
- * feature IDs may be duplicated (IDs are a hash of geometry) and so more
112
- * results may be returned than IDs in the request.
113
- * @internal
114
- * @experimental
115
- */
116
- abstract getFeatures(
117
- options: FeaturesRequestOptions
118
- ): Promise<FeaturesResponse>;
119
-
120
- /**
121
- * Returns a scalar numerical statistic over all matching data. Suitable
122
- * for 'headline' or 'scorecard' figures such as counts and sums.
123
- */
124
- abstract getFormula(options: FormulaRequestOptions): Promise<FormulaResponse>;
125
-
126
- /**
127
- * Returns a list of labeled datapoints for 'bins' of data defined as ticks
128
- * over a numerical range. Suitable for histogram charts.
129
- */
130
- abstract getHistogram(
131
- options: HistogramRequestOptions
132
- ): Promise<HistogramResponse>;
133
-
134
- /**
135
- * Returns a range (min and max) for a numerical column of matching rows.
136
- * Suitable for displaying certain 'headline' or 'scorecard' statistics,
137
- * or rendering a range slider UI for filtering.
138
- */
139
- abstract getRange(options: RangeRequestOptions): Promise<RangeResponse>;
140
-
141
- /**
142
- * Returns a list of bivariate datapoints defined as numerical 'x' and 'y'
143
- * values. Suitable for rendering scatter plots.
144
- */
145
- abstract getScatter(options: ScatterRequestOptions): Promise<ScatterResponse>;
146
-
147
- /**
148
- * Returns a list of arbitrary data rows, with support for pagination and
149
- * sorting. Suitable for displaying tables and lists.
150
- */
151
- abstract getTable(options: TableRequestOptions): Promise<TableResponse>;
152
-
153
- /**
154
- * Returns a series of labeled numerical values, grouped into equally-sized
155
- * time intervals. Suitable for rendering time series charts.
156
- */
157
- abstract getTimeSeries(
158
- options: TimeSeriesRequestOptions
159
- ): Promise<TimeSeriesResponse>;
160
- }
@@ -1,407 +0,0 @@
1
- import {TilesetSourceOptions} from '../sources/index.js';
2
- import type {ModelSource} from '../models/index.js';
3
- import {
4
- CategoryRequestOptions,
5
- CategoryResponse,
6
- FeaturesRequestOptions,
7
- FeaturesResponse,
8
- FormulaRequestOptions,
9
- FormulaResponse,
10
- HistogramRequestOptions,
11
- HistogramResponse,
12
- RangeRequestOptions,
13
- RangeResponse,
14
- ScatterRequestOptions,
15
- ScatterResponse,
16
- TableRequestOptions,
17
- TableResponse,
18
- TimeSeriesRequestOptions,
19
- TimeSeriesResponse,
20
- } from './types.js';
21
- import {InvalidColumnError, getApplicableFilters} from '../utils.js';
22
- import {TileFormat} from '../constants.js';
23
- 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';
39
- import {FeatureCollection} from 'geojson';
40
- import {SpatialDataType} from '../sources/types.js';
41
- 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
47
-
48
- export type WidgetTilesetSourceProps = WidgetSourceProps &
49
- Omit<TilesetSourceOptions, 'filters'> & {
50
- tileFormat: TileFormat;
51
- spatialDataType: SpatialDataType;
52
- };
53
-
54
- export type WidgetTilesetSourceResult = {widgetSource: WidgetTilesetSource};
55
-
56
- /**
57
- * Source for Widget API requests on a data source defined by a tileset.
58
- *
59
- * Generally not intended to be constructed directly. Instead, call
60
- * {@link vectorTilesetSource}, {@link h3TilesetSource}, or {@link quadbinTilesetSource},
61
- * which can be shared with map layers. Sources contain a `widgetSource`
62
- * property, for use by widget implementations.
63
- *
64
- * Example:
65
- *
66
- * ```javascript
67
- * import { vectorTilesetSource } from '@carto/api-client';
68
- *
69
- * const data = vectorTilesetSource({
70
- * accessToken: '••••',
71
- * connectionName: 'carto_dw',
72
- * tableName: 'carto-demo-data.demo_rasters.my_tileset_source'
73
- * });
74
- *
75
- * const { widgetSource } = await data;
76
- * ```
77
- */
78
- 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
- }
89
-
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
- }
98
-
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
- }
125
-
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
- }
142
-
143
- override async getFeatures(
144
- options: FeaturesRequestOptions
145
- ): Promise<FeaturesResponse> {
146
- throw new Error('getFeatures not supported for tilesets');
147
- }
148
-
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
- }
158
-
159
- if (!this._features.length) {
160
- return {value: null};
161
- }
162
-
163
- // Column is required except when operation is 'count'.
164
- if ((column && column !== '*') || operation !== 'count') {
165
- assertColumn(this._features, column);
166
- }
167
-
168
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
169
-
170
- if (filteredFeatures.length === 0 && operation !== 'count') {
171
- return {value: null};
172
- }
173
-
174
- const targetOperation = aggregationFunctions[operation];
175
- return {
176
- value: targetOperation(
177
- filteredFeatures as FeatureData[],
178
- column,
179
- joinOperation
180
- ),
181
- };
182
- }
183
-
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 [];
193
- }
194
-
195
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
196
-
197
- assertColumn(this._features, column);
198
-
199
- return histogram({
200
- data: filteredFeatures,
201
- valuesColumns: normalizeColumns(column),
202
- joinOperation,
203
- ticks,
204
- operation,
205
- });
206
- }
207
-
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 [];
217
- }
218
-
219
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
220
-
221
- assertColumn(this._features, column as string, operationColumn as string);
222
-
223
- const groups = groupValuesByColumn({
224
- data: filteredFeatures,
225
- valuesColumns: normalizeColumns(operationColumn || column),
226
- joinOperation,
227
- keysColumn: column,
228
- operation,
229
- });
230
-
231
- return groups || [];
232
- }
233
-
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 [];
243
- }
244
-
245
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
246
-
247
- assertColumn(this._features, xAxisColumn, yAxisColumn);
248
-
249
- return scatterPlot({
250
- data: filteredFeatures,
251
- xAxisColumns: normalizeColumns(xAxisColumn),
252
- xAxisJoinOperation,
253
- yAxisColumns: normalizeColumns(yAxisColumn),
254
- yAxisJoinOperation,
255
- });
256
- }
257
-
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
- );
290
- }
291
-
292
- // Sort.
293
- let rows = applySorting(filteredFeatures, {
294
- sortBy,
295
- sortByDirection: sortDirection,
296
- sortByColumnType,
297
- });
298
- const totalCount = rows.length;
299
-
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;
313
- });
314
-
315
- return {rows, totalCount} as TableResponse;
316
- }
317
-
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: []};
328
- }
329
-
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
- }) || [];
343
-
344
- return {rows};
345
- }
346
-
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);
358
-
359
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
360
- return {
361
- min: aggregationFunctions.min(filteredFeatures, column),
362
- max: aggregationFunctions.max(filteredFeatures, column),
363
- };
364
- }
365
-
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
- );
376
- }
377
- }
378
-
379
- function assertColumn(
380
- features: FeatureData[],
381
- ...columnArgs: string[] | string[][]
382
- ) {
383
- // TODO(cleanup): Can drop support for multiple column shapes here?
384
-
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()));
387
-
388
- const featureKeys = Object.keys(features[0]);
389
-
390
- const invalidColumns = columns.filter(
391
- (column) => !featureKeys.includes(column)
392
- );
393
-
394
- if (invalidColumns.length) {
395
- throw new InvalidColumnError(
396
- `Missing column(s): ${invalidColumns.join(', ')}`
397
- );
398
- }
399
- }
400
-
401
- function normalizeColumns(columns: string | string[]): string[] {
402
- return Array.isArray(columns)
403
- ? columns
404
- : typeof columns === 'string'
405
- ? [columns]
406
- : [];
407
- }