@carto/api-client 0.0.1-0
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.
- package/README.md +24 -0
- package/build/api-client.cjs +1202 -0
- package/build/api-client.cjs.map +1 -0
- package/build/api-client.modern.js +1089 -0
- package/build/api-client.modern.js.map +1 -0
- package/build/client.d.ts +4 -0
- package/build/constants-internal.d.ts +21 -0
- package/build/constants.d.ts +33 -0
- package/build/index.d.ts +5 -0
- package/build/models/common.d.ts +25 -0
- package/build/models/index.d.ts +3 -0
- package/build/models/model.d.ts +17 -0
- package/build/sources/index.d.ts +5 -0
- package/build/sources/types.d.ts +80 -0
- package/build/sources/widget-base-source.d.ts +32 -0
- package/build/sources/widget-query-source.d.ts +8 -0
- package/build/sources/widget-table-source.d.ts +8 -0
- package/build/sources/wrappers.d.ts +47 -0
- package/build/types-internal.d.ts +7 -0
- package/build/types.d.ts +73 -0
- package/build/utils.d.ts +27 -0
- package/package.json +89 -0
- package/src/client.ts +17 -0
- package/src/constants-internal.ts +24 -0
- package/src/constants.ts +37 -0
- package/src/index.ts +5 -0
- package/src/models/common.ts +93 -0
- package/src/models/index.ts +3 -0
- package/src/models/model.ts +112 -0
- package/src/sources/index.ts +5 -0
- package/src/sources/types.ts +90 -0
- package/src/sources/widget-base-source.ts +255 -0
- package/src/sources/widget-query-source.ts +25 -0
- package/src/sources/widget-table-source.ts +25 -0
- package/src/sources/wrappers.ts +114 -0
- package/src/types-internal.ts +9 -0
- package/src/types.ts +76 -0
- package/src/utils.ts +84 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import {executeModel} from '../models/index.js';
|
|
2
|
+
import {
|
|
3
|
+
CategoryRequestOptions,
|
|
4
|
+
CategoryResponse,
|
|
5
|
+
FormulaRequestOptions,
|
|
6
|
+
FormulaResponse,
|
|
7
|
+
HistogramRequestOptions,
|
|
8
|
+
HistogramResponse,
|
|
9
|
+
RangeRequestOptions,
|
|
10
|
+
RangeResponse,
|
|
11
|
+
ScatterRequestOptions,
|
|
12
|
+
ScatterResponse,
|
|
13
|
+
TableRequestOptions,
|
|
14
|
+
TableResponse,
|
|
15
|
+
TimeSeriesRequestOptions,
|
|
16
|
+
TimeSeriesResponse,
|
|
17
|
+
} from './types.js';
|
|
18
|
+
import {Source, FilterLogicalOperator, Credentials, Filter} from '../types.js';
|
|
19
|
+
import {SourceOptions} from '@deck.gl/carto';
|
|
20
|
+
import {getApplicableFilters, normalizeObjectKeys} from '../utils.js';
|
|
21
|
+
import {ApiVersion, MapType} from '../constants.js';
|
|
22
|
+
import {
|
|
23
|
+
DEFAULT_API_BASE_URL,
|
|
24
|
+
DEFAULT_GEO_COLUMN,
|
|
25
|
+
} from '../constants-internal.js';
|
|
26
|
+
import {getClient} from '../client.js';
|
|
27
|
+
import {$TODO} from '../types-internal.js';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* TODO(cleanup): Consolidate {@link SourceOptions} and {@link Source}.
|
|
31
|
+
*/
|
|
32
|
+
export interface WidgetBaseSourceProps extends SourceOptions, Credentials {
|
|
33
|
+
type?: MapType;
|
|
34
|
+
filters?: Record<string, Filter>;
|
|
35
|
+
filtersLogicalOperator?: FilterLogicalOperator;
|
|
36
|
+
queryParameters?: unknown[];
|
|
37
|
+
provider?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type WidgetSource = WidgetBaseSource<WidgetBaseSourceProps>;
|
|
41
|
+
|
|
42
|
+
export class WidgetBaseSource<Props extends WidgetBaseSourceProps> {
|
|
43
|
+
readonly props: Props;
|
|
44
|
+
readonly credentials: Required<Credentials> & {clientId: string};
|
|
45
|
+
readonly connectionName: string;
|
|
46
|
+
|
|
47
|
+
static defaultProps: Partial<WidgetBaseSourceProps> = {
|
|
48
|
+
filters: {},
|
|
49
|
+
filtersLogicalOperator: 'and',
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
constructor(props: Props) {
|
|
53
|
+
this.props = {...WidgetBaseSource.defaultProps, ...props};
|
|
54
|
+
this.connectionName = props.connectionName;
|
|
55
|
+
this.credentials = {
|
|
56
|
+
apiVersion: props.apiVersion || ApiVersion.V3,
|
|
57
|
+
apiBaseUrl: props.apiBaseUrl || DEFAULT_API_BASE_URL,
|
|
58
|
+
clientId: props.clientId || getClient(),
|
|
59
|
+
accessToken: props.accessToken,
|
|
60
|
+
geoColumn: props.geoColumn || DEFAULT_GEO_COLUMN,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
protected getSource(owner?: string): Source {
|
|
65
|
+
return {
|
|
66
|
+
...(this.props as $TODO),
|
|
67
|
+
credentials: this.credentials,
|
|
68
|
+
connection: this.connectionName,
|
|
69
|
+
filters: getApplicableFilters(owner, this.props.filters),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async getFormula(props: FormulaRequestOptions): Promise<FormulaResponse> {
|
|
74
|
+
const {
|
|
75
|
+
filterOwner,
|
|
76
|
+
spatialFilter,
|
|
77
|
+
abortController,
|
|
78
|
+
operationExp,
|
|
79
|
+
...params
|
|
80
|
+
} = props;
|
|
81
|
+
const {column, operation} = params;
|
|
82
|
+
|
|
83
|
+
type FormulaModelResponse = {rows: {value: number}[]};
|
|
84
|
+
|
|
85
|
+
return executeModel({
|
|
86
|
+
model: 'formula',
|
|
87
|
+
source: this.getSource(filterOwner),
|
|
88
|
+
spatialFilter,
|
|
89
|
+
params: {column: column ?? '*', operation, operationExp},
|
|
90
|
+
opts: {abortController},
|
|
91
|
+
}).then((res: FormulaModelResponse) => normalizeObjectKeys(res.rows[0]));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async getCategories(
|
|
95
|
+
props: CategoryRequestOptions
|
|
96
|
+
): Promise<CategoryResponse> {
|
|
97
|
+
const {filterOwner, spatialFilter, abortController, ...params} = props;
|
|
98
|
+
const {column, operation, operationColumn} = params;
|
|
99
|
+
|
|
100
|
+
type CategoriesModelResponse = {rows: {name: string; value: number}[]};
|
|
101
|
+
|
|
102
|
+
return executeModel({
|
|
103
|
+
model: 'category',
|
|
104
|
+
source: this.getSource(filterOwner),
|
|
105
|
+
spatialFilter,
|
|
106
|
+
params: {
|
|
107
|
+
column,
|
|
108
|
+
operation,
|
|
109
|
+
operationColumn: operationColumn || column,
|
|
110
|
+
},
|
|
111
|
+
opts: {abortController},
|
|
112
|
+
}).then((res: CategoriesModelResponse) => normalizeObjectKeys(res.rows));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async getRange(props: RangeRequestOptions): Promise<RangeResponse> {
|
|
116
|
+
const {filterOwner, spatialFilter, abortController, ...params} = props;
|
|
117
|
+
const {column} = params;
|
|
118
|
+
|
|
119
|
+
type RangeModelResponse = {rows: {min: number; max: number}[]};
|
|
120
|
+
|
|
121
|
+
return executeModel({
|
|
122
|
+
model: 'range',
|
|
123
|
+
source: this.getSource(filterOwner),
|
|
124
|
+
spatialFilter,
|
|
125
|
+
params: {column},
|
|
126
|
+
opts: {abortController},
|
|
127
|
+
}).then((res: RangeModelResponse) => normalizeObjectKeys(res.rows[0]));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async getTable(props: TableRequestOptions): Promise<TableResponse> {
|
|
131
|
+
const {filterOwner, spatialFilter, abortController, ...params} = props;
|
|
132
|
+
const {columns, sortBy, sortDirection, page = 0, rowsPerPage = 10} = params;
|
|
133
|
+
|
|
134
|
+
type TableModelResponse = {
|
|
135
|
+
rows: Record<string, number | string>[];
|
|
136
|
+
metadata: {total: number};
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
return executeModel({
|
|
140
|
+
model: 'table',
|
|
141
|
+
source: this.getSource(filterOwner),
|
|
142
|
+
spatialFilter,
|
|
143
|
+
params: {
|
|
144
|
+
column: columns,
|
|
145
|
+
sortBy,
|
|
146
|
+
sortDirection,
|
|
147
|
+
limit: rowsPerPage,
|
|
148
|
+
offset: page * rowsPerPage,
|
|
149
|
+
},
|
|
150
|
+
opts: {abortController},
|
|
151
|
+
}).then((res: TableModelResponse) => ({
|
|
152
|
+
rows: normalizeObjectKeys(res.rows),
|
|
153
|
+
totalCount: res.metadata.total,
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async getScatter(props: ScatterRequestOptions): Promise<ScatterResponse> {
|
|
158
|
+
const {filterOwner, spatialFilter, abortController, ...params} = props;
|
|
159
|
+
const {xAxisColumn, xAxisJoinOperation, yAxisColumn, yAxisJoinOperation} =
|
|
160
|
+
params;
|
|
161
|
+
|
|
162
|
+
// Make sure this is sync with the same constant in cloud-native/maps-api
|
|
163
|
+
const HARD_LIMIT = 500;
|
|
164
|
+
|
|
165
|
+
type ScatterModelResponse = {rows: {x: number; y: number}[]};
|
|
166
|
+
|
|
167
|
+
return executeModel({
|
|
168
|
+
model: 'scatterplot',
|
|
169
|
+
source: this.getSource(filterOwner),
|
|
170
|
+
spatialFilter,
|
|
171
|
+
params: {
|
|
172
|
+
xAxisColumn,
|
|
173
|
+
xAxisJoinOperation,
|
|
174
|
+
yAxisColumn,
|
|
175
|
+
yAxisJoinOperation,
|
|
176
|
+
limit: HARD_LIMIT,
|
|
177
|
+
},
|
|
178
|
+
opts: {abortController},
|
|
179
|
+
})
|
|
180
|
+
.then((res: ScatterModelResponse) => normalizeObjectKeys(res.rows))
|
|
181
|
+
.then((res) => res.map(({x, y}: {x: number; y: number}) => [x, y]));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async getTimeSeries(
|
|
185
|
+
props: TimeSeriesRequestOptions
|
|
186
|
+
): Promise<TimeSeriesResponse> {
|
|
187
|
+
const {filterOwner, abortController, spatialFilter, ...params} = props;
|
|
188
|
+
const {
|
|
189
|
+
column,
|
|
190
|
+
operationColumn,
|
|
191
|
+
joinOperation,
|
|
192
|
+
operation,
|
|
193
|
+
stepSize,
|
|
194
|
+
stepMultiplier,
|
|
195
|
+
splitByCategory,
|
|
196
|
+
splitByCategoryLimit,
|
|
197
|
+
splitByCategoryValues,
|
|
198
|
+
} = params;
|
|
199
|
+
|
|
200
|
+
type TimeSeriesModelResponse = {
|
|
201
|
+
rows: {name: string; value: number}[];
|
|
202
|
+
metadata: {categories: string[]};
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
return executeModel({
|
|
206
|
+
model: 'timeseries',
|
|
207
|
+
source: this.getSource(filterOwner),
|
|
208
|
+
spatialFilter,
|
|
209
|
+
params: {
|
|
210
|
+
column,
|
|
211
|
+
stepSize,
|
|
212
|
+
stepMultiplier,
|
|
213
|
+
operationColumn: operationColumn || column,
|
|
214
|
+
joinOperation,
|
|
215
|
+
operation,
|
|
216
|
+
splitByCategory,
|
|
217
|
+
splitByCategoryLimit,
|
|
218
|
+
splitByCategoryValues,
|
|
219
|
+
},
|
|
220
|
+
opts: {abortController},
|
|
221
|
+
}).then((res: TimeSeriesModelResponse) => ({
|
|
222
|
+
rows: normalizeObjectKeys(res.rows),
|
|
223
|
+
categories: res.metadata?.categories,
|
|
224
|
+
}));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async getHistogram(
|
|
228
|
+
props: HistogramRequestOptions
|
|
229
|
+
): Promise<HistogramResponse> {
|
|
230
|
+
const {filterOwner, spatialFilter, abortController, ...params} = props;
|
|
231
|
+
const {column, operation, ticks} = params;
|
|
232
|
+
|
|
233
|
+
type HistogramModelResponse = {rows: {tick: number; value: number}[]};
|
|
234
|
+
|
|
235
|
+
const data = await executeModel({
|
|
236
|
+
model: 'histogram',
|
|
237
|
+
source: this.getSource(filterOwner),
|
|
238
|
+
spatialFilter,
|
|
239
|
+
params: {column, operation, ticks},
|
|
240
|
+
opts: {abortController},
|
|
241
|
+
}).then((res: HistogramModelResponse) => normalizeObjectKeys(res.rows));
|
|
242
|
+
|
|
243
|
+
if (data.length) {
|
|
244
|
+
// Given N ticks the API returns up to N+1 bins, omitting any empty bins. Bins
|
|
245
|
+
// include 1 bin below the lowest tick, N-1 between ticks, and 1 bin above the highest tick.
|
|
246
|
+
const result = Array(ticks.length + 1).fill(0);
|
|
247
|
+
data.forEach(
|
|
248
|
+
({tick, value}: {tick: number; value: number}) => (result[tick] = value)
|
|
249
|
+
);
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
H3QuerySourceOptions,
|
|
3
|
+
QuadbinQuerySourceOptions,
|
|
4
|
+
VectorQuerySourceOptions,
|
|
5
|
+
} from '@deck.gl/carto';
|
|
6
|
+
import {MapType} from '../constants.js';
|
|
7
|
+
import {WidgetBaseSource, WidgetBaseSourceProps} from './widget-base-source.js';
|
|
8
|
+
import {Source} from '../types.js';
|
|
9
|
+
|
|
10
|
+
type LayerQuerySourceOptions =
|
|
11
|
+
| VectorQuerySourceOptions
|
|
12
|
+
| H3QuerySourceOptions
|
|
13
|
+
| QuadbinQuerySourceOptions;
|
|
14
|
+
|
|
15
|
+
export class WidgetQuerySource extends WidgetBaseSource<
|
|
16
|
+
LayerQuerySourceOptions & WidgetBaseSourceProps
|
|
17
|
+
> {
|
|
18
|
+
protected override getSource(owner: string): Source {
|
|
19
|
+
return {
|
|
20
|
+
...super.getSource(owner),
|
|
21
|
+
type: MapType.QUERY,
|
|
22
|
+
data: this.props.sqlQuery,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
H3TableSourceOptions,
|
|
3
|
+
QuadbinTableSourceOptions,
|
|
4
|
+
VectorTableSourceOptions,
|
|
5
|
+
} from '@deck.gl/carto';
|
|
6
|
+
import {WidgetBaseSource, WidgetBaseSourceProps} from './widget-base-source.js';
|
|
7
|
+
import {MapType} from '../constants.js';
|
|
8
|
+
import {Source} from '../types.js';
|
|
9
|
+
|
|
10
|
+
type LayerTableSourceOptions =
|
|
11
|
+
| VectorTableSourceOptions
|
|
12
|
+
| H3TableSourceOptions
|
|
13
|
+
| QuadbinTableSourceOptions;
|
|
14
|
+
|
|
15
|
+
export class WidgetTableSource extends WidgetBaseSource<
|
|
16
|
+
LayerTableSourceOptions & WidgetBaseSourceProps
|
|
17
|
+
> {
|
|
18
|
+
protected override getSource(owner: string): Source {
|
|
19
|
+
return {
|
|
20
|
+
...super.getSource(owner),
|
|
21
|
+
type: MapType.TABLE,
|
|
22
|
+
data: this.props.tableName,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import {
|
|
2
|
+
h3TableSource as _h3TableSource,
|
|
3
|
+
h3QuerySource as _h3QuerySource,
|
|
4
|
+
vectorTableSource as _vectorTableSource,
|
|
5
|
+
vectorQuerySource as _vectorQuerySource,
|
|
6
|
+
quadbinTableSource as _quadbinTableSource,
|
|
7
|
+
quadbinQuerySource as _quadbinQuerySource,
|
|
8
|
+
VectorTableSourceOptions,
|
|
9
|
+
VectorQuerySourceOptions,
|
|
10
|
+
H3TableSourceOptions,
|
|
11
|
+
H3QuerySourceOptions,
|
|
12
|
+
QuadbinQuerySourceOptions,
|
|
13
|
+
QuadbinTableSourceOptions,
|
|
14
|
+
} from '@deck.gl/carto';
|
|
15
|
+
import {WidgetBaseSourceProps} from './widget-base-source.js';
|
|
16
|
+
import {WidgetQuerySource} from './widget-query-source.js';
|
|
17
|
+
import {WidgetTableSource} from './widget-table-source.js';
|
|
18
|
+
|
|
19
|
+
/******************************************************************************
|
|
20
|
+
* RESPONSE OBJECTS
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
type WidgetTableSourceResponse = {widgetSource: WidgetTableSource};
|
|
24
|
+
type WidgetQuerySourceResponse = {widgetSource: WidgetQuerySource};
|
|
25
|
+
|
|
26
|
+
export type VectorTableSourceResponse = WidgetTableSourceResponse &
|
|
27
|
+
Awaited<ReturnType<typeof _vectorTableSource>>;
|
|
28
|
+
export type VectorQuerySourceResponse = WidgetQuerySourceResponse &
|
|
29
|
+
Awaited<ReturnType<typeof _vectorQuerySource>>;
|
|
30
|
+
|
|
31
|
+
export type H3TableSourceResponse = WidgetTableSourceResponse &
|
|
32
|
+
Awaited<ReturnType<typeof _h3TableSource>>;
|
|
33
|
+
export type H3QuerySourceResponse = WidgetQuerySourceResponse &
|
|
34
|
+
Awaited<ReturnType<typeof _h3QuerySource>>;
|
|
35
|
+
|
|
36
|
+
export type QuadbinTableSourceResponse = WidgetTableSourceResponse &
|
|
37
|
+
Awaited<ReturnType<typeof _quadbinTableSource>>;
|
|
38
|
+
export type QuadbinQuerySourceResponse = WidgetQuerySourceResponse &
|
|
39
|
+
Awaited<ReturnType<typeof _quadbinQuerySource>>;
|
|
40
|
+
|
|
41
|
+
/******************************************************************************
|
|
42
|
+
* VECTOR SOURCES
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/** Wrapper adding widget support to {@link _vectorTableSource}. */
|
|
46
|
+
export async function vectorTableSource(
|
|
47
|
+
props: VectorTableSourceOptions & WidgetBaseSourceProps
|
|
48
|
+
): Promise<VectorTableSourceResponse> {
|
|
49
|
+
const response = await _vectorTableSource(props);
|
|
50
|
+
return {...response, widgetSource: new WidgetTableSource(props)};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Wrapper adding widget support to {@link _vectorQuerySource}. */
|
|
54
|
+
export async function vectorQuerySource(
|
|
55
|
+
props: VectorQuerySourceOptions & WidgetBaseSourceProps
|
|
56
|
+
): Promise<VectorQuerySourceResponse> {
|
|
57
|
+
const response = await _vectorQuerySource(props);
|
|
58
|
+
return {...response, widgetSource: new WidgetQuerySource(props)};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Wrapper adding widget support to {@link _vectorTilesetSource}. */
|
|
62
|
+
export async function vectorTilesetSource() {
|
|
63
|
+
throw new Error('not implemented');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/******************************************************************************
|
|
67
|
+
* H3 SOURCES
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
/** Wrapper adding widget support to {@link _h3TableSource}. */
|
|
71
|
+
export async function h3TableSource(
|
|
72
|
+
props: H3TableSourceOptions & WidgetBaseSourceProps
|
|
73
|
+
): Promise<H3TableSourceResponse> {
|
|
74
|
+
const response = await _h3TableSource(props);
|
|
75
|
+
return {...response, widgetSource: new WidgetTableSource(props)};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Wrapper adding widget support to {@link _h3QuerySource}. */
|
|
79
|
+
export async function h3QuerySource(
|
|
80
|
+
props: H3QuerySourceOptions & WidgetBaseSourceProps
|
|
81
|
+
): Promise<H3QuerySourceResponse> {
|
|
82
|
+
const response = await _h3QuerySource(props);
|
|
83
|
+
return {...response, widgetSource: new WidgetQuerySource(props)};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Wrapper adding widget support to {@link _h3TilesetSource}. */
|
|
87
|
+
export async function h3TilesetSource() {
|
|
88
|
+
throw new Error('not implemented');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/******************************************************************************
|
|
92
|
+
* QUADBIN SOURCES
|
|
93
|
+
*/
|
|
94
|
+
|
|
95
|
+
/** Wrapper adding widget support to {@link _quadbinTableSource}. */
|
|
96
|
+
export async function quadbinTableSource(
|
|
97
|
+
props: QuadbinTableSourceOptions & WidgetBaseSourceProps
|
|
98
|
+
): Promise<QuadbinTableSourceResponse> {
|
|
99
|
+
const response = await _quadbinTableSource(props);
|
|
100
|
+
return {...response, widgetSource: new WidgetTableSource(props)};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Wrapper adding widget support to {@link _quadbinQuerySource}. */
|
|
104
|
+
export async function quadbinQuerySource(
|
|
105
|
+
props: QuadbinQuerySourceOptions & WidgetBaseSourceProps
|
|
106
|
+
): Promise<QuadbinQuerySourceResponse> {
|
|
107
|
+
const response = await _quadbinQuerySource(props);
|
|
108
|
+
return {...response, widgetSource: new WidgetQuerySource(props)};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Wrapper adding widget support to {@link _quadbinTilesetSource}. */
|
|
112
|
+
export async function quadbinTilesetSource() {
|
|
113
|
+
throw new Error('not implemented');
|
|
114
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type {ApiVersion, MapType, FilterType} from './constants';
|
|
2
|
+
|
|
3
|
+
/******************************************************************************
|
|
4
|
+
* AUTHENTICATION
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** @internalRemarks Source: @carto/react-api */
|
|
8
|
+
export type Credentials = {
|
|
9
|
+
apiVersion?: ApiVersion;
|
|
10
|
+
apiBaseUrl?: string;
|
|
11
|
+
geoColumn?: string;
|
|
12
|
+
accessToken: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/******************************************************************************
|
|
16
|
+
* SOURCES
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** @internalRemarks Source: @carto/react-api */
|
|
20
|
+
export type Source = {
|
|
21
|
+
type: MapType;
|
|
22
|
+
connection: string;
|
|
23
|
+
credentials: Credentials;
|
|
24
|
+
data: string;
|
|
25
|
+
geoColumn?: string;
|
|
26
|
+
queryParameters?: unknown[];
|
|
27
|
+
filters?: Record<string, Filter>;
|
|
28
|
+
filtersLogicalOperator?: 'and' | 'or';
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/******************************************************************************
|
|
32
|
+
* AGGREGATION
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Enum for the different types of aggregations available for widgets
|
|
37
|
+
* @enum {string}
|
|
38
|
+
* @readonly
|
|
39
|
+
* @internalRemarks Source: @carto/constants
|
|
40
|
+
* @internalRemarks Converted from enum to type union, for improved declarative API.
|
|
41
|
+
*/
|
|
42
|
+
export type AggregationType =
|
|
43
|
+
| 'count'
|
|
44
|
+
| 'avg'
|
|
45
|
+
| 'min'
|
|
46
|
+
| 'max'
|
|
47
|
+
| 'sum'
|
|
48
|
+
| 'custom';
|
|
49
|
+
|
|
50
|
+
/******************************************************************************
|
|
51
|
+
* FILTERS
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/** @internalRemarks Source: @carto/react-api */
|
|
55
|
+
export type SpatialFilter = GeoJSON.Polygon | GeoJSON.MultiPolygon;
|
|
56
|
+
|
|
57
|
+
/** @internalRemarks Source: @carto/react-api, @deck.gl/carto */
|
|
58
|
+
export interface Filter {
|
|
59
|
+
[FilterType.IN]?: {owner?: string; values: number[]};
|
|
60
|
+
/** [a, b] both are included. */
|
|
61
|
+
[FilterType.BETWEEN]?: {owner?: string; values: number[][]};
|
|
62
|
+
/** [a, b) a is included, b is not. */
|
|
63
|
+
[FilterType.CLOSED_OPEN]?: {owner?: string; values: number[][]};
|
|
64
|
+
[FilterType.TIME]?: {owner?: string; values: number[][]};
|
|
65
|
+
[FilterType.STRING_SEARCH]?: {owner?: string; values: string[]};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** @internalRemarks Source: @carto/react-core */
|
|
69
|
+
export type FilterLogicalOperator = 'and' | 'or';
|
|
70
|
+
|
|
71
|
+
/******************************************************************************
|
|
72
|
+
* SORTING
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
export type SortDirection = 'asc' | 'desc';
|
|
76
|
+
export type SortColumnType = 'number' | 'string' | 'date';
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {Filter} from './types.js';
|
|
2
|
+
import {FilterType} from './constants.js';
|
|
3
|
+
import {$TODO} from './types-internal.js';
|
|
4
|
+
|
|
5
|
+
const FILTER_TYPES = new Set(Object.values(FilterType));
|
|
6
|
+
const isFilterType = (type: string): type is FilterType =>
|
|
7
|
+
FILTER_TYPES.has(type as FilterType);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @privateRemarks Source: @carto/react-widgets
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export function getApplicableFilters(
|
|
14
|
+
owner?: string,
|
|
15
|
+
filters?: Record<string, Filter>
|
|
16
|
+
): Record<string, Filter> {
|
|
17
|
+
if (!filters) return {};
|
|
18
|
+
|
|
19
|
+
const applicableFilters: Record<string, Filter> = {};
|
|
20
|
+
|
|
21
|
+
for (const column in filters) {
|
|
22
|
+
for (const type in filters[column]) {
|
|
23
|
+
if (!isFilterType(type)) continue;
|
|
24
|
+
|
|
25
|
+
const filter = filters[column][type];
|
|
26
|
+
if (filter && filter.owner !== owner) {
|
|
27
|
+
applicableFilters[column] ||= {};
|
|
28
|
+
applicableFilters[column][type] = filter as $TODO;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return applicableFilters;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type Row<T> = Record<string, T> | Record<string, T>[] | T[] | T;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Due to each data warehouse having its own behavior with columns,
|
|
40
|
+
* we need to normalize them and transform every key to lowercase.
|
|
41
|
+
*
|
|
42
|
+
* @internalRemarks Source: @carto/react-widgets
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
export function normalizeObjectKeys<T, R extends Row<T>>(el: R): R {
|
|
46
|
+
if (Array.isArray(el)) {
|
|
47
|
+
return el.map((value) => normalizeObjectKeys(value)) as R;
|
|
48
|
+
} else if (typeof el !== 'object') {
|
|
49
|
+
return el;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return Object.entries(el as Record<string, T>).reduce((acc, [key, value]) => {
|
|
53
|
+
acc[key.toLowerCase()] =
|
|
54
|
+
typeof value === 'object' && value ? normalizeObjectKeys(value) : value;
|
|
55
|
+
return acc;
|
|
56
|
+
}, {} as Record<string, T>) as R;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** @internalRemarks Source: @carto/react-core */
|
|
60
|
+
export function assert(condition: unknown, message: string) {
|
|
61
|
+
if (!condition) {
|
|
62
|
+
throw new Error(message);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @internalRemarks Source: @carto/react-core
|
|
68
|
+
* @internal
|
|
69
|
+
*/
|
|
70
|
+
export class InvalidColumnError extends Error {
|
|
71
|
+
protected static readonly NAME = 'InvalidColumnError';
|
|
72
|
+
|
|
73
|
+
constructor(message: string) {
|
|
74
|
+
super(`${InvalidColumnError.NAME}: ${message}`);
|
|
75
|
+
this.name = InvalidColumnError.NAME;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static is(error: unknown) {
|
|
79
|
+
return (
|
|
80
|
+
error instanceof InvalidColumnError ||
|
|
81
|
+
(error as Error).message?.includes(InvalidColumnError.NAME)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|