@carto/api-client 0.4.2 → 0.4.4
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/CHANGELOG.md +8 -0
- package/build/api/query.d.ts +1 -1
- package/build/api-client.cjs +1136 -984
- package/build/api-client.cjs.map +1 -1
- package/build/api-client.modern.js +1014 -869
- package/build/api-client.modern.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/models/model.d.ts +7 -1
- package/build/sources/boundary-query-source.d.ts +2 -1
- package/build/sources/boundary-table-source.d.ts +2 -1
- package/build/sources/h3-query-source.d.ts +2 -1
- package/build/sources/h3-table-source.d.ts +2 -1
- package/build/sources/h3-tileset-source.d.ts +2 -1
- package/build/sources/index.d.ts +13 -14
- package/build/sources/quadbin-query-source.d.ts +2 -1
- package/build/sources/quadbin-table-source.d.ts +2 -1
- package/build/sources/quadbin-tileset-source.d.ts +2 -1
- package/build/sources/raster-source.d.ts +2 -1
- package/build/sources/types.d.ts +48 -37
- package/build/sources/vector-query-source.d.ts +2 -1
- package/build/sources/vector-table-source.d.ts +2 -1
- package/build/sources/vector-tileset-source.d.ts +2 -1
- package/build/spatial-index.d.ts +8 -0
- package/build/utils.d.ts +1 -1
- package/build/widget-sources/types.d.ts +9 -1
- package/build/widget-sources/widget-base-source.d.ts +3 -3
- package/package.json +1 -1
- package/src/api/query.ts +1 -2
- package/src/index.ts +1 -36
- package/src/models/model.ts +47 -24
- package/src/sources/boundary-query-source.ts +4 -2
- package/src/sources/boundary-table-source.ts +4 -2
- package/src/sources/h3-query-source.ts +10 -2
- package/src/sources/h3-table-source.ts +9 -2
- package/src/sources/h3-tileset-source.ts +4 -2
- package/src/sources/index.ts +54 -24
- package/src/sources/quadbin-query-source.ts +10 -2
- package/src/sources/quadbin-table-source.ts +10 -2
- package/src/sources/quadbin-tileset-source.ts +4 -2
- package/src/sources/raster-source.ts +4 -2
- package/src/sources/types.ts +54 -40
- package/src/sources/vector-query-source.ts +13 -2
- package/src/sources/vector-table-source.ts +14 -2
- package/src/sources/vector-tileset-source.ts +4 -2
- package/src/spatial-index.ts +111 -0
- package/src/utils.ts +1 -1
- package/src/widget-sources/types.ts +10 -1
- package/src/widget-sources/widget-base-source.ts +183 -23
package/build/api-client.cjs
CHANGED
|
@@ -381,1051 +381,1169 @@ const DEFAULT_AGGREGATION_RES_LEVEL_H3 = 4;
|
|
|
381
381
|
*/
|
|
382
382
|
const DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN = 6;
|
|
383
383
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
/** @internalRemarks Source: @carto/react-api */
|
|
390
|
-
|
|
391
|
-
function _catch(body, recover) {
|
|
392
|
-
try {
|
|
393
|
-
var result = body();
|
|
394
|
-
} catch (e) {
|
|
395
|
-
return recover(e);
|
|
396
|
-
}
|
|
397
|
-
if (result && result.then) {
|
|
398
|
-
return result.then(void 0, recover);
|
|
399
|
-
}
|
|
400
|
-
return result;
|
|
384
|
+
// deck.gl
|
|
385
|
+
// SPDX-License-Identifier: MIT
|
|
386
|
+
// Copyright (c) vis.gl contributors
|
|
387
|
+
function joinPath() {
|
|
388
|
+
return [].slice.call(arguments).map(part => part.endsWith('/') ? part.slice(0, -1) : part).join('/');
|
|
401
389
|
}
|
|
402
|
-
|
|
390
|
+
function buildV3Path(apiBaseUrl, version, endpoint) {
|
|
391
|
+
return joinPath(apiBaseUrl, version, endpoint, ...[].slice.call(arguments, 3));
|
|
392
|
+
}
|
|
393
|
+
/** @internal Required by fetchMap(). */
|
|
394
|
+
function buildPublicMapUrl(_ref) {
|
|
403
395
|
let {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
396
|
+
apiBaseUrl,
|
|
397
|
+
cartoMapId
|
|
398
|
+
} = _ref;
|
|
399
|
+
return buildV3Path(apiBaseUrl, 'v3', 'maps', 'public', cartoMapId);
|
|
400
|
+
}
|
|
401
|
+
/** @internal Required by fetchMap(). */
|
|
402
|
+
function buildStatsUrl(_ref2) {
|
|
403
|
+
let {
|
|
404
|
+
attribute,
|
|
405
|
+
apiBaseUrl,
|
|
406
|
+
connectionName,
|
|
407
|
+
source,
|
|
408
|
+
type
|
|
407
409
|
} = _ref2;
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
function _temp2(_result) {
|
|
411
|
-
if (_exit) ;
|
|
412
|
-
if (!response.ok) {
|
|
413
|
-
dealWithApiError({
|
|
414
|
-
response,
|
|
415
|
-
data
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
return data;
|
|
419
|
-
}
|
|
420
|
-
let response;
|
|
421
|
-
let data;
|
|
422
|
-
const isPost = opts?.method === 'POST';
|
|
423
|
-
const _temp = _catch(function () {
|
|
424
|
-
return Promise.resolve(fetch(url.toString(), {
|
|
425
|
-
headers: {
|
|
426
|
-
Authorization: `Bearer ${accessToken}`,
|
|
427
|
-
...(isPost && {
|
|
428
|
-
'Content-Type': 'application/json'
|
|
429
|
-
})
|
|
430
|
-
},
|
|
431
|
-
...(isPost && {
|
|
432
|
-
method: opts?.method,
|
|
433
|
-
body: opts?.body
|
|
434
|
-
}),
|
|
435
|
-
signal: opts?.abortController?.signal,
|
|
436
|
-
...opts?.otherOptions
|
|
437
|
-
})).then(function (_fetch) {
|
|
438
|
-
response = _fetch;
|
|
439
|
-
return Promise.resolve(response.json()).then(function (_response$json) {
|
|
440
|
-
data = _response$json;
|
|
441
|
-
});
|
|
442
|
-
});
|
|
443
|
-
}, function (error) {
|
|
444
|
-
if (error.name === 'AbortError') throw error;
|
|
445
|
-
throw new Error(`Failed request: ${error}`);
|
|
446
|
-
});
|
|
447
|
-
return Promise.resolve(_temp && _temp.then ? _temp.then(_temp2) : _temp2(_temp));
|
|
448
|
-
} catch (e) {
|
|
449
|
-
return Promise.reject(e);
|
|
410
|
+
if (type === 'query') {
|
|
411
|
+
return buildV3Path(apiBaseUrl, 'v3', 'stats', connectionName, attribute);
|
|
450
412
|
}
|
|
451
|
-
|
|
452
|
-
|
|
413
|
+
// type === 'table'
|
|
414
|
+
return buildV3Path(apiBaseUrl, 'v3', 'stats', connectionName, source, attribute);
|
|
415
|
+
}
|
|
416
|
+
function buildSourceUrl(_ref3) {
|
|
453
417
|
let {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
case 403:
|
|
467
|
-
throw new Error('Forbidden access to the requested data');
|
|
468
|
-
default:
|
|
469
|
-
const msg = data && data.error && typeof data.error === 'string' ? data.error : JSON.stringify(data?.hint || data.error?.[0]);
|
|
470
|
-
throw new Error(msg);
|
|
471
|
-
}
|
|
418
|
+
apiBaseUrl,
|
|
419
|
+
connectionName,
|
|
420
|
+
endpoint
|
|
421
|
+
} = _ref3;
|
|
422
|
+
return buildV3Path(apiBaseUrl, 'v3', 'maps', connectionName, endpoint);
|
|
423
|
+
}
|
|
424
|
+
function buildQueryUrl(_ref4) {
|
|
425
|
+
let {
|
|
426
|
+
apiBaseUrl,
|
|
427
|
+
connectionName
|
|
428
|
+
} = _ref4;
|
|
429
|
+
return buildV3Path(apiBaseUrl, 'v3', 'sql', connectionName, 'query');
|
|
472
430
|
}
|
|
473
431
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
V3
|
|
478
|
-
} = exports.ApiVersion;
|
|
479
|
-
const REQUEST_GET_MAX_URL_LENGTH = 2048;
|
|
432
|
+
// deck.gl
|
|
433
|
+
// SPDX-License-Identifier: MIT
|
|
434
|
+
// Copyright (c) vis.gl contributors
|
|
480
435
|
/**
|
|
481
|
-
*
|
|
482
|
-
*
|
|
436
|
+
*
|
|
437
|
+
* Custom error for reported errors in CARTO Maps API.
|
|
438
|
+
* Provides useful debugging information in console and context for applications.
|
|
439
|
+
*
|
|
483
440
|
*/
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
accessToken,
|
|
500
|
-
connectionName,
|
|
501
|
-
clientId
|
|
502
|
-
} = source;
|
|
503
|
-
assert(apiBaseUrl, 'executeModel: missing apiBaseUrl');
|
|
504
|
-
assert(accessToken, 'executeModel: missing accessToken');
|
|
505
|
-
assert(apiVersion === V3, 'executeModel: SQL Model API requires CARTO 3+');
|
|
506
|
-
assert(type !== 'tileset', 'executeModel: Tilesets not supported');
|
|
507
|
-
let url = `${apiBaseUrl}/v3/sql/${connectionName}/model/${model}`;
|
|
508
|
-
const {
|
|
509
|
-
data,
|
|
510
|
-
filters,
|
|
511
|
-
filtersLogicalOperator = 'and',
|
|
512
|
-
geoColumn = DEFAULT_GEO_COLUMN
|
|
513
|
-
} = source;
|
|
514
|
-
const queryParameters = source.queryParameters ? JSON.stringify(source.queryParameters) : '';
|
|
515
|
-
const queryParams = {
|
|
516
|
-
type,
|
|
517
|
-
client: clientId,
|
|
518
|
-
source: data,
|
|
519
|
-
params: JSON.stringify(params),
|
|
520
|
-
queryParameters,
|
|
521
|
-
filters: JSON.stringify(filters),
|
|
522
|
-
filtersLogicalOperator
|
|
523
|
-
};
|
|
524
|
-
// Picking Model API requires 'spatialDataColumn'.
|
|
525
|
-
if (model === 'pick') {
|
|
526
|
-
queryParams.spatialDataColumn = geoColumn;
|
|
527
|
-
}
|
|
528
|
-
// API supports multiple filters, we apply it only to geoColumn
|
|
529
|
-
const spatialFilters = source.spatialFilter ? {
|
|
530
|
-
[geoColumn]: source.spatialFilter
|
|
531
|
-
} : undefined;
|
|
532
|
-
if (spatialFilters) {
|
|
533
|
-
queryParams.spatialFilters = JSON.stringify(spatialFilters);
|
|
534
|
-
}
|
|
535
|
-
const urlWithSearchParams = url + '?' + new URLSearchParams(queryParams).toString();
|
|
536
|
-
const isGet = urlWithSearchParams.length <= REQUEST_GET_MAX_URL_LENGTH;
|
|
537
|
-
if (isGet) {
|
|
538
|
-
url = urlWithSearchParams;
|
|
539
|
-
} else {
|
|
540
|
-
// undo the JSON.stringify, @TODO find a better pattern
|
|
541
|
-
queryParams.params = params;
|
|
542
|
-
queryParams.filters = filters;
|
|
543
|
-
queryParams.queryParameters = source.queryParameters;
|
|
544
|
-
if (spatialFilters) {
|
|
545
|
-
queryParams.spatialFilters = spatialFilters;
|
|
441
|
+
class CartoAPIError extends Error {
|
|
442
|
+
constructor(error, errorContext, response, responseJson) {
|
|
443
|
+
let responseString = 'Failed to connect';
|
|
444
|
+
if (response) {
|
|
445
|
+
responseString = 'Server returned: ';
|
|
446
|
+
if (response.status === 400) {
|
|
447
|
+
responseString += 'Bad request';
|
|
448
|
+
} else if (response.status === 401 || response.status === 403) {
|
|
449
|
+
responseString += 'Unauthorized access';
|
|
450
|
+
} else if (response.status === 404) {
|
|
451
|
+
responseString += 'Not found';
|
|
452
|
+
} else {
|
|
453
|
+
responseString += 'Error';
|
|
454
|
+
}
|
|
455
|
+
responseString += ` (${response.status}):`;
|
|
546
456
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
method: isGet ? 'GET' : 'POST',
|
|
554
|
-
...(!isGet && {
|
|
555
|
-
body: JSON.stringify(queryParams)
|
|
556
|
-
})
|
|
457
|
+
responseString += ` ${error.message || error}`;
|
|
458
|
+
let message = `${errorContext.requestType} API request failed`;
|
|
459
|
+
message += `\n${responseString}`;
|
|
460
|
+
for (const key of Object.keys(errorContext)) {
|
|
461
|
+
if (key === 'requestType') continue;
|
|
462
|
+
message += `\n${formatErrorKey(key)}: ${errorContext[key]}`;
|
|
557
463
|
}
|
|
558
|
-
|
|
464
|
+
message += '\n';
|
|
465
|
+
super(message);
|
|
466
|
+
/** Source error from server */
|
|
467
|
+
this.error = void 0;
|
|
468
|
+
/** Context (API call & parameters) in which error occured */
|
|
469
|
+
this.errorContext = void 0;
|
|
470
|
+
/** Response from server */
|
|
471
|
+
this.response = void 0;
|
|
472
|
+
/** JSON Response from server */
|
|
473
|
+
this.responseJson = void 0;
|
|
474
|
+
this.name = 'CartoAPIError';
|
|
475
|
+
this.response = response;
|
|
476
|
+
this.responseJson = responseJson;
|
|
477
|
+
this.error = error;
|
|
478
|
+
this.errorContext = errorContext;
|
|
479
|
+
}
|
|
559
480
|
}
|
|
560
|
-
|
|
561
481
|
/**
|
|
562
|
-
*
|
|
563
|
-
*
|
|
564
|
-
* Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
|
|
482
|
+
* Converts camelCase to Camel Case
|
|
565
483
|
*/
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
484
|
+
function formatErrorKey(key) {
|
|
485
|
+
return key.replace(/([A-Z])/g, ' $1').replace(/^./, s => s.toUpperCase());
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// deck.gl
|
|
489
|
+
const requestWithParameters = function (_ref) {
|
|
490
|
+
let {
|
|
491
|
+
baseUrl,
|
|
492
|
+
parameters = {},
|
|
493
|
+
headers: customHeaders = {},
|
|
494
|
+
errorContext,
|
|
495
|
+
maxLengthURL = DEFAULT_MAX_LENGTH_URL,
|
|
496
|
+
localCache
|
|
497
|
+
} = _ref;
|
|
498
|
+
try {
|
|
499
|
+
// Parameters added to all requests issued with `requestWithParameters()`.
|
|
500
|
+
// These parameters override parameters already in the base URL, but not
|
|
501
|
+
// user-provided parameters.
|
|
502
|
+
parameters = {
|
|
503
|
+
v: V3_MINOR_VERSION,
|
|
504
|
+
client: getClient(),
|
|
505
|
+
...(typeof deck !== 'undefined' && deck.VERSION && {
|
|
506
|
+
deckglVersion: deck.VERSION
|
|
507
|
+
}),
|
|
508
|
+
...parameters
|
|
585
509
|
};
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
510
|
+
baseUrl = excludeURLParameters(baseUrl, Object.keys(parameters));
|
|
511
|
+
const key = createCacheKey(baseUrl, parameters, customHeaders);
|
|
512
|
+
const {
|
|
513
|
+
cache: REQUEST_CACHE,
|
|
514
|
+
canReadCache,
|
|
515
|
+
canStoreInCache
|
|
516
|
+
} = getCacheSettings(localCache);
|
|
517
|
+
if (canReadCache && REQUEST_CACHE.has(key)) {
|
|
518
|
+
return Promise.resolve(REQUEST_CACHE.get(key));
|
|
519
|
+
}
|
|
520
|
+
const url = createURLWithParameters(baseUrl, parameters);
|
|
521
|
+
const headers = {
|
|
522
|
+
...DEFAULT_HEADERS,
|
|
523
|
+
...customHeaders
|
|
524
|
+
};
|
|
525
|
+
/* global fetch */
|
|
526
|
+
const fetchPromise = url.length > maxLengthURL ? fetch(baseUrl, {
|
|
527
|
+
method: 'POST',
|
|
528
|
+
body: JSON.stringify(parameters),
|
|
529
|
+
headers
|
|
530
|
+
}) : fetch(url, {
|
|
531
|
+
headers
|
|
532
|
+
});
|
|
533
|
+
let response;
|
|
534
|
+
let responseJson;
|
|
535
|
+
const jsonPromise = fetchPromise.then(_response => {
|
|
536
|
+
response = _response;
|
|
537
|
+
return response.json();
|
|
538
|
+
}).then(json => {
|
|
539
|
+
responseJson = json;
|
|
540
|
+
if (!response || !response.ok) {
|
|
541
|
+
throw new Error(json.error);
|
|
542
|
+
}
|
|
543
|
+
return json;
|
|
544
|
+
}).catch(error => {
|
|
545
|
+
if (canStoreInCache) {
|
|
546
|
+
REQUEST_CACHE.delete(key);
|
|
547
|
+
}
|
|
548
|
+
throw new CartoAPIError(error, errorContext, response, responseJson);
|
|
549
|
+
});
|
|
550
|
+
if (canStoreInCache) {
|
|
551
|
+
REQUEST_CACHE.set(key, jsonPromise);
|
|
625
552
|
}
|
|
553
|
+
return Promise.resolve(jsonPromise);
|
|
554
|
+
} catch (e) {
|
|
555
|
+
return Promise.reject(e);
|
|
626
556
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
// Avoid `normalizeObjectKeys()`, which changes column names.
|
|
673
|
-
}).then(_ref => {
|
|
674
|
-
let {
|
|
675
|
-
rows
|
|
676
|
-
} = _ref;
|
|
677
|
-
return {
|
|
678
|
-
rows
|
|
679
|
-
};
|
|
680
|
-
}));
|
|
681
|
-
} catch (e) {
|
|
682
|
-
return Promise.reject(e);
|
|
557
|
+
};
|
|
558
|
+
const DEFAULT_HEADERS = {
|
|
559
|
+
Accept: 'application/json',
|
|
560
|
+
'Content-Type': 'application/json'
|
|
561
|
+
};
|
|
562
|
+
const DEFAULT_REQUEST_CACHE = new Map();
|
|
563
|
+
function getCacheSettings(localCache) {
|
|
564
|
+
const canReadCache = localCache?.cacheControl?.includes('no-cache') ? false : true;
|
|
565
|
+
const canStoreInCache = localCache?.cacheControl?.includes('no-store') ? false : true;
|
|
566
|
+
const cache = localCache?.cache || DEFAULT_REQUEST_CACHE;
|
|
567
|
+
return {
|
|
568
|
+
cache,
|
|
569
|
+
canReadCache,
|
|
570
|
+
canStoreInCache
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
function createCacheKey(baseUrl, parameters, headers) {
|
|
574
|
+
const parameterEntries = Object.entries(parameters).sort((_ref2, _ref3) => {
|
|
575
|
+
let [a] = _ref2;
|
|
576
|
+
let [b] = _ref3;
|
|
577
|
+
return a > b ? 1 : -1;
|
|
578
|
+
});
|
|
579
|
+
const headerEntries = Object.entries(headers).sort((_ref4, _ref5) => {
|
|
580
|
+
let [a] = _ref4;
|
|
581
|
+
let [b] = _ref5;
|
|
582
|
+
return a > b ? 1 : -1;
|
|
583
|
+
});
|
|
584
|
+
return JSON.stringify({
|
|
585
|
+
baseUrl,
|
|
586
|
+
parameters: parameterEntries,
|
|
587
|
+
headers: headerEntries
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Appends query string parameters to a URL. Existing URL parameters are kept,
|
|
592
|
+
* unless there is a conflict, in which case the new parameters override
|
|
593
|
+
* those already in the URL.
|
|
594
|
+
*/
|
|
595
|
+
function createURLWithParameters(baseUrlString, parameters) {
|
|
596
|
+
const baseUrl = new URL(baseUrlString);
|
|
597
|
+
for (const [key, value] of Object.entries(parameters)) {
|
|
598
|
+
if (isPureObject(value) || Array.isArray(value)) {
|
|
599
|
+
baseUrl.searchParams.set(key, JSON.stringify(value));
|
|
600
|
+
} else {
|
|
601
|
+
baseUrl.searchParams.set(key, value.toString());
|
|
683
602
|
}
|
|
684
603
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
const {
|
|
696
|
-
filterOwner,
|
|
697
|
-
spatialFilter,
|
|
698
|
-
abortController,
|
|
699
|
-
operationExp,
|
|
700
|
-
...params
|
|
701
|
-
} = options;
|
|
702
|
-
const {
|
|
703
|
-
column,
|
|
704
|
-
operation
|
|
705
|
-
} = params;
|
|
706
|
-
return Promise.resolve(executeModel({
|
|
707
|
-
model: 'formula',
|
|
708
|
-
source: {
|
|
709
|
-
..._this3.getModelSource(filterOwner),
|
|
710
|
-
spatialFilter
|
|
711
|
-
},
|
|
712
|
-
params: {
|
|
713
|
-
column: column ?? '*',
|
|
714
|
-
operation,
|
|
715
|
-
operationExp
|
|
716
|
-
},
|
|
717
|
-
opts: {
|
|
718
|
-
abortController
|
|
719
|
-
}
|
|
720
|
-
}).then(res => normalizeObjectKeys(res.rows[0])));
|
|
721
|
-
} catch (e) {
|
|
722
|
-
return Promise.reject(e);
|
|
604
|
+
return baseUrl.toString();
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Deletes query string parameters from a URL.
|
|
608
|
+
*/
|
|
609
|
+
function excludeURLParameters(baseUrlString, parameters) {
|
|
610
|
+
const baseUrl = new URL(baseUrlString);
|
|
611
|
+
for (const param of parameters) {
|
|
612
|
+
if (baseUrl.searchParams.has(param)) {
|
|
613
|
+
baseUrl.searchParams.delete(param);
|
|
723
614
|
}
|
|
724
615
|
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
model: 'histogram',
|
|
748
|
-
source: {
|
|
749
|
-
..._this4.getModelSource(filterOwner),
|
|
750
|
-
spatialFilter
|
|
751
|
-
},
|
|
752
|
-
params: {
|
|
753
|
-
column,
|
|
754
|
-
operation,
|
|
755
|
-
ticks
|
|
756
|
-
},
|
|
757
|
-
opts: {
|
|
758
|
-
abortController
|
|
759
|
-
}
|
|
760
|
-
}).then(res => normalizeObjectKeys(res.rows))).then(function (data) {
|
|
761
|
-
if (data.length) {
|
|
762
|
-
// Given N ticks the API returns up to N+1 bins, omitting any empty bins. Bins
|
|
763
|
-
// include 1 bin below the lowest tick, N-1 between ticks, and 1 bin above the highest tick.
|
|
764
|
-
const result = Array(ticks.length + 1).fill(0);
|
|
765
|
-
data.forEach(_ref2 => {
|
|
766
|
-
let {
|
|
767
|
-
tick,
|
|
768
|
-
value
|
|
769
|
-
} = _ref2;
|
|
770
|
-
return result[tick] = value;
|
|
771
|
-
});
|
|
772
|
-
return result;
|
|
773
|
-
}
|
|
774
|
-
return [];
|
|
775
|
-
});
|
|
776
|
-
} catch (e) {
|
|
777
|
-
return Promise.reject(e);
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
/****************************************************************************
|
|
781
|
-
* RANGE
|
|
782
|
-
*/
|
|
783
|
-
/**
|
|
784
|
-
* Returns a range (min and max) for a numerical column of matching rows.
|
|
785
|
-
* Suitable for displaying certain 'headline' or 'scorecard' statistics,
|
|
786
|
-
* or rendering a range slider UI for filtering.
|
|
787
|
-
*/
|
|
788
|
-
getRange(options) {
|
|
789
|
-
try {
|
|
790
|
-
const _this5 = this;
|
|
791
|
-
const {
|
|
792
|
-
filterOwner,
|
|
793
|
-
spatialFilter,
|
|
794
|
-
abortController,
|
|
795
|
-
...params
|
|
796
|
-
} = options;
|
|
797
|
-
const {
|
|
798
|
-
column
|
|
799
|
-
} = params;
|
|
800
|
-
return Promise.resolve(executeModel({
|
|
801
|
-
model: 'range',
|
|
802
|
-
source: {
|
|
803
|
-
..._this5.getModelSource(filterOwner),
|
|
804
|
-
spatialFilter
|
|
805
|
-
},
|
|
806
|
-
params: {
|
|
807
|
-
column
|
|
808
|
-
},
|
|
809
|
-
opts: {
|
|
810
|
-
abortController
|
|
811
|
-
}
|
|
812
|
-
}).then(res => normalizeObjectKeys(res.rows[0])));
|
|
813
|
-
} catch (e) {
|
|
814
|
-
return Promise.reject(e);
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
/****************************************************************************
|
|
818
|
-
* SCATTER
|
|
819
|
-
*/
|
|
820
|
-
/**
|
|
821
|
-
* Returns a list of bivariate datapoints defined as numerical 'x' and 'y'
|
|
822
|
-
* values. Suitable for rendering scatter plots.
|
|
823
|
-
*/
|
|
824
|
-
getScatter(options) {
|
|
825
|
-
try {
|
|
826
|
-
const _this6 = this;
|
|
827
|
-
const {
|
|
828
|
-
filterOwner,
|
|
829
|
-
spatialFilter,
|
|
830
|
-
abortController,
|
|
831
|
-
...params
|
|
832
|
-
} = options;
|
|
833
|
-
const {
|
|
834
|
-
xAxisColumn,
|
|
835
|
-
xAxisJoinOperation,
|
|
836
|
-
yAxisColumn,
|
|
837
|
-
yAxisJoinOperation
|
|
838
|
-
} = params;
|
|
839
|
-
// Make sure this is sync with the same constant in cloud-native/maps-api
|
|
840
|
-
const HARD_LIMIT = 500;
|
|
841
|
-
return Promise.resolve(executeModel({
|
|
842
|
-
model: 'scatterplot',
|
|
843
|
-
source: {
|
|
844
|
-
..._this6.getModelSource(filterOwner),
|
|
845
|
-
spatialFilter
|
|
846
|
-
},
|
|
847
|
-
params: {
|
|
848
|
-
xAxisColumn,
|
|
849
|
-
xAxisJoinOperation,
|
|
850
|
-
yAxisColumn,
|
|
851
|
-
yAxisJoinOperation,
|
|
852
|
-
limit: HARD_LIMIT
|
|
853
|
-
},
|
|
854
|
-
opts: {
|
|
855
|
-
abortController
|
|
856
|
-
}
|
|
857
|
-
}).then(res => normalizeObjectKeys(res.rows)).then(res => res.map(_ref3 => {
|
|
858
|
-
let {
|
|
859
|
-
x,
|
|
860
|
-
y
|
|
861
|
-
} = _ref3;
|
|
862
|
-
return [x, y];
|
|
863
|
-
})));
|
|
864
|
-
} catch (e) {
|
|
865
|
-
return Promise.reject(e);
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
/****************************************************************************
|
|
869
|
-
* TABLE
|
|
870
|
-
*/
|
|
871
|
-
/**
|
|
872
|
-
* Returns a list of arbitrary data rows, with support for pagination and
|
|
873
|
-
* sorting. Suitable for displaying tables and lists.
|
|
874
|
-
*/
|
|
875
|
-
getTable(options) {
|
|
876
|
-
try {
|
|
877
|
-
const _this7 = this;
|
|
878
|
-
const {
|
|
879
|
-
filterOwner,
|
|
880
|
-
spatialFilter,
|
|
881
|
-
abortController,
|
|
882
|
-
...params
|
|
883
|
-
} = options;
|
|
884
|
-
const {
|
|
885
|
-
columns,
|
|
886
|
-
sortBy,
|
|
887
|
-
sortDirection,
|
|
888
|
-
offset = 0,
|
|
889
|
-
limit = 10
|
|
890
|
-
} = params;
|
|
891
|
-
return Promise.resolve(executeModel({
|
|
892
|
-
model: 'table',
|
|
893
|
-
source: {
|
|
894
|
-
..._this7.getModelSource(filterOwner),
|
|
895
|
-
spatialFilter
|
|
896
|
-
},
|
|
897
|
-
params: {
|
|
898
|
-
column: columns,
|
|
899
|
-
sortBy,
|
|
900
|
-
sortDirection,
|
|
901
|
-
limit,
|
|
902
|
-
offset
|
|
903
|
-
},
|
|
904
|
-
opts: {
|
|
905
|
-
abortController
|
|
906
|
-
}
|
|
907
|
-
}).then(res => ({
|
|
908
|
-
// Avoid `normalizeObjectKeys()`, which changes column names.
|
|
909
|
-
rows: res.rows ?? res.ROWS,
|
|
910
|
-
totalCount: res.metadata?.total ?? res.METADATA?.TOTAL
|
|
911
|
-
})));
|
|
912
|
-
} catch (e) {
|
|
913
|
-
return Promise.reject(e);
|
|
616
|
+
return baseUrl.toString();
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// deck.gl
|
|
620
|
+
const baseSource = function (endpoint, options, urlParameters) {
|
|
621
|
+
try {
|
|
622
|
+
const {
|
|
623
|
+
accessToken,
|
|
624
|
+
connectionName,
|
|
625
|
+
cache,
|
|
626
|
+
...optionalOptions
|
|
627
|
+
} = options;
|
|
628
|
+
const mergedOptions = {
|
|
629
|
+
...SOURCE_DEFAULTS,
|
|
630
|
+
accessToken,
|
|
631
|
+
connectionName,
|
|
632
|
+
endpoint
|
|
633
|
+
};
|
|
634
|
+
for (const key in optionalOptions) {
|
|
635
|
+
if (optionalOptions[key]) {
|
|
636
|
+
mergedOptions[key] = optionalOptions[key];
|
|
637
|
+
}
|
|
914
638
|
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
639
|
+
const baseUrl = buildSourceUrl(mergedOptions);
|
|
640
|
+
const {
|
|
641
|
+
clientId,
|
|
642
|
+
maxLengthURL,
|
|
643
|
+
format,
|
|
644
|
+
localCache
|
|
645
|
+
} = mergedOptions;
|
|
646
|
+
const headers = {
|
|
647
|
+
Authorization: `Bearer ${options.accessToken}`,
|
|
648
|
+
...options.headers
|
|
649
|
+
};
|
|
650
|
+
const parameters = {
|
|
651
|
+
client: clientId,
|
|
652
|
+
...urlParameters
|
|
653
|
+
};
|
|
654
|
+
const errorContext = {
|
|
655
|
+
requestType: 'Map instantiation',
|
|
656
|
+
connection: options.connectionName,
|
|
657
|
+
type: endpoint,
|
|
658
|
+
source: JSON.stringify(parameters, undefined, 2)
|
|
659
|
+
};
|
|
660
|
+
return Promise.resolve(requestWithParameters({
|
|
661
|
+
baseUrl,
|
|
662
|
+
parameters,
|
|
663
|
+
headers,
|
|
664
|
+
errorContext,
|
|
665
|
+
maxLengthURL,
|
|
666
|
+
localCache
|
|
667
|
+
})).then(function (mapInstantiation) {
|
|
668
|
+
let _exit;
|
|
669
|
+
function _temp2(_result) {
|
|
670
|
+
return _exit ? _result : Promise.resolve(requestWithParameters({
|
|
671
|
+
baseUrl: dataUrl,
|
|
672
|
+
headers,
|
|
673
|
+
errorContext,
|
|
674
|
+
maxLengthURL,
|
|
675
|
+
localCache
|
|
676
|
+
}));
|
|
677
|
+
}
|
|
678
|
+
const dataUrl = mapInstantiation[format].url[0];
|
|
679
|
+
if (cache) {
|
|
680
|
+
cache.value = parseInt(new URL(dataUrl).searchParams.get('cache') || '', 10);
|
|
681
|
+
}
|
|
682
|
+
errorContext.requestType = 'Map data';
|
|
683
|
+
const _temp = function () {
|
|
684
|
+
if (format === 'tilejson') {
|
|
685
|
+
return Promise.resolve(requestWithParameters({
|
|
686
|
+
baseUrl: dataUrl,
|
|
687
|
+
headers,
|
|
688
|
+
errorContext,
|
|
689
|
+
maxLengthURL,
|
|
690
|
+
localCache
|
|
691
|
+
})).then(function (json) {
|
|
692
|
+
if (accessToken) {
|
|
693
|
+
json.accessToken = accessToken;
|
|
694
|
+
}
|
|
695
|
+
_exit = 1;
|
|
696
|
+
return json;
|
|
697
|
+
});
|
|
962
698
|
}
|
|
963
|
-
})
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
return Promise.reject(e);
|
|
969
|
-
}
|
|
699
|
+
}();
|
|
700
|
+
return _temp && _temp.then ? _temp.then(_temp2) : _temp2(_temp);
|
|
701
|
+
});
|
|
702
|
+
} catch (e) {
|
|
703
|
+
return Promise.reject(e);
|
|
970
704
|
}
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
apiVersion: exports.ApiVersion.V3,
|
|
705
|
+
};
|
|
706
|
+
const SOURCE_DEFAULTS = {
|
|
974
707
|
apiBaseUrl: DEFAULT_API_BASE_URL,
|
|
975
708
|
clientId: getClient(),
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
709
|
+
format: 'tilejson',
|
|
710
|
+
headers: {},
|
|
711
|
+
maxLengthURL: DEFAULT_MAX_LENGTH_URL
|
|
979
712
|
};
|
|
980
713
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
* const data = vectorQuerySource({
|
|
995
|
-
* accessToken: '••••',
|
|
996
|
-
* connectionName: 'carto_dw',
|
|
997
|
-
* sqlQuery: 'SELECT * FROM carto-demo-data.demo_tables.retail_stores'
|
|
998
|
-
* });
|
|
999
|
-
*
|
|
1000
|
-
* const { widgetSource } = await data;
|
|
1001
|
-
* ```
|
|
1002
|
-
*/
|
|
1003
|
-
class WidgetQuerySource extends WidgetBaseSource {
|
|
1004
|
-
getModelSource(owner) {
|
|
1005
|
-
return {
|
|
1006
|
-
...super._getModelSource(owner),
|
|
1007
|
-
type: 'query',
|
|
1008
|
-
data: this.props.sqlQuery,
|
|
1009
|
-
queryParameters: this.props.queryParameters
|
|
714
|
+
// deck.gl
|
|
715
|
+
const boundaryQuerySource = function (options) {
|
|
716
|
+
try {
|
|
717
|
+
const {
|
|
718
|
+
columns,
|
|
719
|
+
filters,
|
|
720
|
+
tilesetTableName,
|
|
721
|
+
propertiesSqlQuery,
|
|
722
|
+
queryParameters
|
|
723
|
+
} = options;
|
|
724
|
+
const urlParameters = {
|
|
725
|
+
tilesetTableName,
|
|
726
|
+
propertiesSqlQuery
|
|
1010
727
|
};
|
|
728
|
+
if (columns) {
|
|
729
|
+
urlParameters.columns = columns.join(',');
|
|
730
|
+
}
|
|
731
|
+
if (filters) {
|
|
732
|
+
urlParameters.filters = filters;
|
|
733
|
+
}
|
|
734
|
+
if (queryParameters) {
|
|
735
|
+
urlParameters.queryParameters = queryParameters;
|
|
736
|
+
}
|
|
737
|
+
return Promise.resolve(baseSource('boundary', options, urlParameters));
|
|
738
|
+
} catch (e) {
|
|
739
|
+
return Promise.reject(e);
|
|
1011
740
|
}
|
|
1012
|
-
}
|
|
741
|
+
};
|
|
1013
742
|
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
*
|
|
1027
|
-
* const data = vectorTableSource({
|
|
1028
|
-
* accessToken: '••••',
|
|
1029
|
-
* connectionName: 'carto_dw',
|
|
1030
|
-
* tableName: 'carto-demo-data.demo_tables.retail_stores'
|
|
1031
|
-
* });
|
|
1032
|
-
*
|
|
1033
|
-
* const { widgetSource } = await data;
|
|
1034
|
-
* ```
|
|
1035
|
-
*/
|
|
1036
|
-
class WidgetTableSource extends WidgetBaseSource {
|
|
1037
|
-
getModelSource(owner) {
|
|
1038
|
-
return {
|
|
1039
|
-
...super._getModelSource(owner),
|
|
1040
|
-
type: 'table',
|
|
1041
|
-
data: this.props.tableName
|
|
743
|
+
// deck.gl
|
|
744
|
+
const boundaryTableSource = function (options) {
|
|
745
|
+
try {
|
|
746
|
+
const {
|
|
747
|
+
filters,
|
|
748
|
+
tilesetTableName,
|
|
749
|
+
columns,
|
|
750
|
+
propertiesTableName
|
|
751
|
+
} = options;
|
|
752
|
+
const urlParameters = {
|
|
753
|
+
tilesetTableName,
|
|
754
|
+
propertiesTableName
|
|
1042
755
|
};
|
|
756
|
+
if (columns) {
|
|
757
|
+
urlParameters.columns = columns.join(',');
|
|
758
|
+
}
|
|
759
|
+
if (filters) {
|
|
760
|
+
urlParameters.filters = filters;
|
|
761
|
+
}
|
|
762
|
+
return Promise.resolve(baseSource('boundary', options, urlParameters));
|
|
763
|
+
} catch (e) {
|
|
764
|
+
return Promise.reject(e);
|
|
1043
765
|
}
|
|
1044
|
-
}
|
|
766
|
+
};
|
|
1045
767
|
|
|
1046
|
-
// deck.gl
|
|
1047
|
-
// SPDX-License-Identifier: MIT
|
|
1048
|
-
// Copyright (c) vis.gl contributors
|
|
1049
768
|
/**
|
|
1050
|
-
*
|
|
1051
|
-
*
|
|
1052
|
-
* Provides useful debugging information in console and context for applications.
|
|
1053
|
-
*
|
|
769
|
+
* Return more descriptive error from API
|
|
770
|
+
* @internalRemarks Source: @carto/react-api
|
|
1054
771
|
*/
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
772
|
+
|
|
773
|
+
/** @internalRemarks Source: @carto/react-api */
|
|
774
|
+
|
|
775
|
+
function _catch(body, recover) {
|
|
776
|
+
try {
|
|
777
|
+
var result = body();
|
|
778
|
+
} catch (e) {
|
|
779
|
+
return recover(e);
|
|
780
|
+
}
|
|
781
|
+
if (result && result.then) {
|
|
782
|
+
return result.then(void 0, recover);
|
|
783
|
+
}
|
|
784
|
+
return result;
|
|
785
|
+
}
|
|
786
|
+
const makeCall = function (_ref2) {
|
|
787
|
+
let {
|
|
788
|
+
url,
|
|
789
|
+
accessToken,
|
|
790
|
+
opts
|
|
791
|
+
} = _ref2;
|
|
792
|
+
try {
|
|
793
|
+
let _exit;
|
|
794
|
+
function _temp2(_result) {
|
|
795
|
+
if (_exit) ;
|
|
796
|
+
if (!response.ok) {
|
|
797
|
+
dealWithApiError({
|
|
798
|
+
response,
|
|
799
|
+
data
|
|
800
|
+
});
|
|
1068
801
|
}
|
|
1069
|
-
|
|
1070
|
-
}
|
|
1071
|
-
responseString += ` ${error.message || error}`;
|
|
1072
|
-
let message = `${errorContext.requestType} API request failed`;
|
|
1073
|
-
message += `\n${responseString}`;
|
|
1074
|
-
for (const key of Object.keys(errorContext)) {
|
|
1075
|
-
if (key === 'requestType') continue;
|
|
1076
|
-
message += `\n${formatErrorKey(key)}: ${errorContext[key]}`;
|
|
802
|
+
return data;
|
|
1077
803
|
}
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
804
|
+
let response;
|
|
805
|
+
let data;
|
|
806
|
+
const isPost = opts?.method === 'POST';
|
|
807
|
+
const _temp = _catch(function () {
|
|
808
|
+
return Promise.resolve(fetch(url.toString(), {
|
|
809
|
+
headers: {
|
|
810
|
+
Authorization: `Bearer ${accessToken}`,
|
|
811
|
+
...(isPost && {
|
|
812
|
+
'Content-Type': 'application/json'
|
|
813
|
+
})
|
|
814
|
+
},
|
|
815
|
+
...(isPost && {
|
|
816
|
+
method: opts?.method,
|
|
817
|
+
body: opts?.body
|
|
818
|
+
}),
|
|
819
|
+
signal: opts?.abortController?.signal,
|
|
820
|
+
...opts?.otherOptions
|
|
821
|
+
})).then(function (_fetch) {
|
|
822
|
+
response = _fetch;
|
|
823
|
+
return Promise.resolve(response.json()).then(function (_response$json) {
|
|
824
|
+
data = _response$json;
|
|
825
|
+
});
|
|
826
|
+
});
|
|
827
|
+
}, function (error) {
|
|
828
|
+
if (error.name === 'AbortError') throw error;
|
|
829
|
+
throw new Error(`Failed request: ${error}`);
|
|
830
|
+
});
|
|
831
|
+
return Promise.resolve(_temp && _temp.then ? _temp.then(_temp2) : _temp2(_temp));
|
|
832
|
+
} catch (e) {
|
|
833
|
+
return Promise.reject(e);
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
function dealWithApiError(_ref) {
|
|
837
|
+
let {
|
|
838
|
+
response,
|
|
839
|
+
data
|
|
840
|
+
} = _ref;
|
|
841
|
+
if (data.error === 'Column not found') {
|
|
842
|
+
throw new InvalidColumnError(`${data.error} ${data.column_name}`);
|
|
843
|
+
}
|
|
844
|
+
if (typeof data.error === 'string' && data.error?.includes('Missing columns')) {
|
|
845
|
+
throw new InvalidColumnError(data.error);
|
|
846
|
+
}
|
|
847
|
+
switch (response.status) {
|
|
848
|
+
case 401:
|
|
849
|
+
throw new Error('Unauthorized access. Invalid credentials');
|
|
850
|
+
case 403:
|
|
851
|
+
throw new Error('Forbidden access to the requested data');
|
|
852
|
+
default:
|
|
853
|
+
const msg = data && data.error && typeof data.error === 'string' ? data.error : JSON.stringify(data?.hint || data.error?.[0]);
|
|
854
|
+
throw new Error(msg);
|
|
1093
855
|
}
|
|
1094
856
|
}
|
|
857
|
+
|
|
858
|
+
/** @internalRemarks Source: @carto/react-api */
|
|
859
|
+
const AVAILABLE_MODELS = ['category', 'histogram', 'formula', 'pick', 'timeseries', 'range', 'scatterplot', 'table'];
|
|
860
|
+
const {
|
|
861
|
+
V3
|
|
862
|
+
} = exports.ApiVersion;
|
|
863
|
+
const REQUEST_GET_MAX_URL_LENGTH = 2048;
|
|
1095
864
|
/**
|
|
1096
|
-
*
|
|
865
|
+
* Execute a SQL model request.
|
|
866
|
+
* @internalRemarks Source: @carto/react-api
|
|
1097
867
|
*/
|
|
1098
|
-
function
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
function buildPublicMapUrl(_ref) {
|
|
1113
|
-
let {
|
|
868
|
+
function executeModel(props) {
|
|
869
|
+
assert(props.source, 'executeModel: missing source');
|
|
870
|
+
assert(props.model, 'executeModel: missing model');
|
|
871
|
+
assert(props.params, 'executeModel: missing params');
|
|
872
|
+
assert(AVAILABLE_MODELS.includes(props.model), `executeModel: model provided isn't valid. Available models: ${AVAILABLE_MODELS.join(', ')}`);
|
|
873
|
+
const {
|
|
874
|
+
model,
|
|
875
|
+
source,
|
|
876
|
+
params,
|
|
877
|
+
opts
|
|
878
|
+
} = props;
|
|
879
|
+
const {
|
|
880
|
+
type,
|
|
881
|
+
apiVersion,
|
|
1114
882
|
apiBaseUrl,
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
883
|
+
accessToken,
|
|
884
|
+
connectionName,
|
|
885
|
+
clientId
|
|
886
|
+
} = source;
|
|
887
|
+
assert(apiBaseUrl, 'executeModel: missing apiBaseUrl');
|
|
888
|
+
assert(accessToken, 'executeModel: missing accessToken');
|
|
889
|
+
assert(apiVersion === V3, 'executeModel: SQL Model API requires CARTO 3+');
|
|
890
|
+
assert(type !== 'tileset', 'executeModel: Tilesets not supported');
|
|
891
|
+
let url = `${apiBaseUrl}/v3/sql/${connectionName}/model/${model}`;
|
|
892
|
+
const {
|
|
893
|
+
data,
|
|
894
|
+
filters,
|
|
895
|
+
filtersLogicalOperator = 'and',
|
|
896
|
+
spatialDataType = 'geo',
|
|
897
|
+
spatialFiltersMode = 'intersects',
|
|
898
|
+
spatialFiltersResolution = 0
|
|
899
|
+
} = source;
|
|
900
|
+
const queryParams = {
|
|
901
|
+
type,
|
|
902
|
+
client: clientId,
|
|
903
|
+
source: data,
|
|
904
|
+
params,
|
|
905
|
+
queryParameters: source.queryParameters || '',
|
|
906
|
+
filters,
|
|
907
|
+
filtersLogicalOperator
|
|
908
|
+
};
|
|
909
|
+
const spatialDataColumn = source.spatialDataColumn || DEFAULT_GEO_COLUMN;
|
|
910
|
+
// Picking Model API requires 'spatialDataColumn'.
|
|
911
|
+
if (model === 'pick') {
|
|
912
|
+
queryParams.spatialDataColumn = spatialDataColumn;
|
|
913
|
+
}
|
|
914
|
+
// API supports multiple filters, we apply it only to spatialDataColumn
|
|
915
|
+
const spatialFilters = source.spatialFilter ? {
|
|
916
|
+
[spatialDataColumn]: source.spatialFilter
|
|
917
|
+
} : undefined;
|
|
918
|
+
if (spatialFilters) {
|
|
919
|
+
queryParams.spatialFilters = spatialFilters;
|
|
920
|
+
queryParams.spatialDataColumn = spatialDataColumn;
|
|
921
|
+
queryParams.spatialDataType = spatialDataType;
|
|
922
|
+
}
|
|
923
|
+
if (spatialDataType !== 'geo') {
|
|
924
|
+
if (spatialFiltersResolution > 0) {
|
|
925
|
+
queryParams.spatialFiltersResolution = spatialFiltersResolution;
|
|
926
|
+
}
|
|
927
|
+
queryParams.spatialFiltersMode = spatialFiltersMode;
|
|
928
|
+
}
|
|
929
|
+
const urlWithSearchParams = url + '?' + objectToURLSearchParams(queryParams).toString();
|
|
930
|
+
const isGet = urlWithSearchParams.length <= REQUEST_GET_MAX_URL_LENGTH;
|
|
931
|
+
if (isGet) {
|
|
932
|
+
url = urlWithSearchParams;
|
|
933
|
+
}
|
|
934
|
+
return makeCall({
|
|
935
|
+
url,
|
|
936
|
+
accessToken: source.accessToken,
|
|
937
|
+
opts: {
|
|
938
|
+
...opts,
|
|
939
|
+
method: isGet ? 'GET' : 'POST',
|
|
940
|
+
...(!isGet && {
|
|
941
|
+
body: JSON.stringify(queryParams)
|
|
942
|
+
})
|
|
943
|
+
}
|
|
944
|
+
});
|
|
1118
945
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
946
|
+
function objectToURLSearchParams(object) {
|
|
947
|
+
const params = new URLSearchParams();
|
|
948
|
+
for (const key in object) {
|
|
949
|
+
if (isPureObject(object[key])) {
|
|
950
|
+
params.append(key, JSON.stringify(object[key]));
|
|
951
|
+
} else if (Array.isArray(object[key])) {
|
|
952
|
+
params.append(key, JSON.stringify(object[key]));
|
|
953
|
+
} else if (object[key] === null) {
|
|
954
|
+
params.append(key, 'null');
|
|
955
|
+
} else if (object[key] !== undefined) {
|
|
956
|
+
params.append(key, String(object[key]));
|
|
957
|
+
}
|
|
1130
958
|
}
|
|
1131
|
-
|
|
1132
|
-
return buildV3Path(apiBaseUrl, 'v3', 'stats', connectionName, source, attribute);
|
|
959
|
+
return params;
|
|
1133
960
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
961
|
+
|
|
962
|
+
const DEFAULT_TILE_SIZE = 512;
|
|
963
|
+
const QUADBIN_ZOOM_MAX_OFFSET = 4;
|
|
964
|
+
function getSpatialFiltersResolution(source, viewState) {
|
|
965
|
+
const dataResolution = source.dataResolution ?? Number.MAX_VALUE;
|
|
966
|
+
const aggregationResLevel = source.aggregationResLevel ?? (source.spatialDataType === 'h3' ? DEFAULT_AGGREGATION_RES_LEVEL_H3 : DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN);
|
|
967
|
+
const aggregationResLevelOffset = Math.max(0, Math.floor(aggregationResLevel));
|
|
968
|
+
const currentZoomInt = Math.ceil(viewState.zoom);
|
|
969
|
+
if (source.spatialDataType === 'h3') {
|
|
970
|
+
const tileSize = DEFAULT_TILE_SIZE;
|
|
971
|
+
const maxResolutionForZoom = maxH3SpatialFiltersResolutions.find(_ref => {
|
|
972
|
+
let [zoom] = _ref;
|
|
973
|
+
return zoom === currentZoomInt;
|
|
974
|
+
})?.[1] ?? Math.max(0, currentZoomInt - 3);
|
|
975
|
+
const maxSpatialFiltersResolution = maxResolutionForZoom ? Math.min(dataResolution, maxResolutionForZoom) : dataResolution;
|
|
976
|
+
const hexagonResolution = getHexagonResolution(viewState, tileSize) + aggregationResLevelOffset;
|
|
977
|
+
return Math.min(hexagonResolution, maxSpatialFiltersResolution);
|
|
978
|
+
}
|
|
979
|
+
if (source.spatialDataType === 'quadbin') {
|
|
980
|
+
const maxResolutionForZoom = currentZoomInt + QUADBIN_ZOOM_MAX_OFFSET;
|
|
981
|
+
const maxSpatialFiltersResolution = Math.min(dataResolution, maxResolutionForZoom);
|
|
982
|
+
const quadsResolution = Math.floor(viewState.zoom) + aggregationResLevelOffset;
|
|
983
|
+
return Math.min(quadsResolution, maxSpatialFiltersResolution);
|
|
984
|
+
}
|
|
985
|
+
return undefined;
|
|
1141
986
|
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
987
|
+
const maxH3SpatialFiltersResolutions = [[20, 14], [19, 13], [18, 12], [17, 11], [16, 10], [15, 9], [14, 8], [13, 7], [12, 7], [11, 7], [10, 6], [9, 6], [8, 5], [7, 4], [6, 4], [5, 3], [4, 2], [3, 1], [2, 1], [1, 0]];
|
|
988
|
+
// stolen from https://github.com/visgl/deck.gl/blob/master/modules/carto/src/layers/h3-tileset-2d.ts
|
|
989
|
+
// Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
|
|
990
|
+
const BIAS = 2;
|
|
991
|
+
// Resolution conversion function. Takes a WebMercatorViewport and returns
|
|
992
|
+
// a H3 resolution such that the screen space size of the hexagons is
|
|
993
|
+
// similar
|
|
994
|
+
function getHexagonResolution(viewport, tileSize) {
|
|
995
|
+
// Difference in given tile size compared to deck's internal 512px tile size,
|
|
996
|
+
// expressed as an offset to the viewport zoom.
|
|
997
|
+
const zoomOffset = Math.log2(tileSize / DEFAULT_TILE_SIZE);
|
|
998
|
+
const hexagonScaleFactor = 2 / 3 * (viewport.zoom - zoomOffset);
|
|
999
|
+
const latitudeScaleFactor = Math.log(1 / Math.cos(Math.PI * viewport.latitude / 180));
|
|
1000
|
+
// Clip and bias
|
|
1001
|
+
return Math.max(0, Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS));
|
|
1148
1002
|
}
|
|
1149
1003
|
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
// Parameters added to all requests issued with `requestWithParameters()`.
|
|
1162
|
-
// These parameters override parameters already in the base URL, but not
|
|
1163
|
-
// user-provided parameters.
|
|
1164
|
-
parameters = {
|
|
1165
|
-
v: V3_MINOR_VERSION,
|
|
1166
|
-
client: getClient(),
|
|
1167
|
-
...(typeof deck !== 'undefined' && deck.VERSION && {
|
|
1168
|
-
deckglVersion: deck.VERSION
|
|
1169
|
-
}),
|
|
1170
|
-
...parameters
|
|
1004
|
+
/**
|
|
1005
|
+
* Source for Widget API requests on a data source defined by a SQL query.
|
|
1006
|
+
*
|
|
1007
|
+
* Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
|
|
1008
|
+
*/
|
|
1009
|
+
class WidgetBaseSource {
|
|
1010
|
+
constructor(props) {
|
|
1011
|
+
this.props = void 0;
|
|
1012
|
+
this.props = {
|
|
1013
|
+
...WidgetBaseSource.defaultProps,
|
|
1014
|
+
...props
|
|
1171
1015
|
};
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
const
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1016
|
+
}
|
|
1017
|
+
_getModelSource(owner) {
|
|
1018
|
+
const props = this.props;
|
|
1019
|
+
return {
|
|
1020
|
+
apiVersion: props.apiVersion,
|
|
1021
|
+
apiBaseUrl: props.apiBaseUrl,
|
|
1022
|
+
clientId: props.clientId,
|
|
1023
|
+
accessToken: props.accessToken,
|
|
1024
|
+
connectionName: props.connectionName,
|
|
1025
|
+
filters: getApplicableFilters(owner, props.filters),
|
|
1026
|
+
filtersLogicalOperator: props.filtersLogicalOperator,
|
|
1027
|
+
spatialDataType: props.spatialDataType,
|
|
1028
|
+
spatialDataColumn: props.spatialDataColumn,
|
|
1029
|
+
dataResolution: props.dataResolution
|
|
1186
1030
|
};
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1031
|
+
}
|
|
1032
|
+
_getSpatialFiltersResolution(source, spatialFilter, referenceViewState) {
|
|
1033
|
+
// spatialFiltersResolution applies only to spatial index sources.
|
|
1034
|
+
if (!spatialFilter || source.spatialDataType === 'geo') {
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
if (!referenceViewState) {
|
|
1038
|
+
throw new Error('Missing required option, "spatialIndexReferenceViewState".');
|
|
1039
|
+
}
|
|
1040
|
+
return getSpatialFiltersResolution(source, referenceViewState);
|
|
1041
|
+
}
|
|
1042
|
+
/****************************************************************************
|
|
1043
|
+
* CATEGORIES
|
|
1044
|
+
*/
|
|
1045
|
+
/**
|
|
1046
|
+
* Returns a list of labeled datapoints for categorical data. Suitable for
|
|
1047
|
+
* charts including grouped bar charts, pie charts, and tree charts.
|
|
1048
|
+
*/
|
|
1049
|
+
getCategories(options) {
|
|
1050
|
+
try {
|
|
1051
|
+
const _this = this;
|
|
1052
|
+
const {
|
|
1053
|
+
filterOwner,
|
|
1054
|
+
spatialFilter,
|
|
1055
|
+
spatialFiltersMode,
|
|
1056
|
+
spatialIndexReferenceViewState,
|
|
1057
|
+
abortController,
|
|
1058
|
+
...params
|
|
1059
|
+
} = options;
|
|
1060
|
+
const {
|
|
1061
|
+
column,
|
|
1062
|
+
operation,
|
|
1063
|
+
operationColumn
|
|
1064
|
+
} = params;
|
|
1065
|
+
const source = _this.getModelSource(filterOwner);
|
|
1066
|
+
const spatialFiltersResolution = _this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1067
|
+
return Promise.resolve(executeModel({
|
|
1068
|
+
model: 'category',
|
|
1069
|
+
source: {
|
|
1070
|
+
...source,
|
|
1071
|
+
spatialFiltersResolution,
|
|
1072
|
+
spatialFiltersMode,
|
|
1073
|
+
spatialFilter
|
|
1074
|
+
},
|
|
1075
|
+
params: {
|
|
1076
|
+
column,
|
|
1077
|
+
operation,
|
|
1078
|
+
operationColumn: operationColumn || column
|
|
1079
|
+
},
|
|
1080
|
+
opts: {
|
|
1081
|
+
abortController
|
|
1082
|
+
}
|
|
1083
|
+
}).then(res => normalizeObjectKeys(res.rows)));
|
|
1084
|
+
} catch (e) {
|
|
1085
|
+
return Promise.reject(e);
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
/****************************************************************************
|
|
1089
|
+
* FEATURES
|
|
1090
|
+
*/
|
|
1091
|
+
/**
|
|
1092
|
+
* Given a list of feature IDs (as found in `_carto_feature_id`) returns all
|
|
1093
|
+
* matching features. In datasets containing features with duplicate geometries,
|
|
1094
|
+
* feature IDs may be duplicated (IDs are a hash of geometry) and so more
|
|
1095
|
+
* results may be returned than IDs in the request.
|
|
1096
|
+
* @internal
|
|
1097
|
+
* @experimental
|
|
1098
|
+
*/
|
|
1099
|
+
getFeatures(options) {
|
|
1100
|
+
try {
|
|
1101
|
+
const _this2 = this;
|
|
1102
|
+
const {
|
|
1103
|
+
filterOwner,
|
|
1104
|
+
spatialFilter,
|
|
1105
|
+
spatialFiltersMode,
|
|
1106
|
+
spatialIndexReferenceViewState,
|
|
1107
|
+
abortController,
|
|
1108
|
+
...params
|
|
1109
|
+
} = options;
|
|
1110
|
+
const {
|
|
1111
|
+
columns,
|
|
1112
|
+
dataType,
|
|
1113
|
+
featureIds,
|
|
1114
|
+
z,
|
|
1115
|
+
limit,
|
|
1116
|
+
tileResolution
|
|
1117
|
+
} = params;
|
|
1118
|
+
const source = _this2.getModelSource(filterOwner);
|
|
1119
|
+
const spatialFiltersResolution = _this2._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1120
|
+
return Promise.resolve(executeModel({
|
|
1121
|
+
model: 'pick',
|
|
1122
|
+
source: {
|
|
1123
|
+
...source,
|
|
1124
|
+
spatialFiltersResolution,
|
|
1125
|
+
spatialFiltersMode,
|
|
1126
|
+
spatialFilter
|
|
1127
|
+
},
|
|
1128
|
+
params: {
|
|
1129
|
+
columns,
|
|
1130
|
+
dataType,
|
|
1131
|
+
featureIds,
|
|
1132
|
+
z,
|
|
1133
|
+
limit: limit || 1000,
|
|
1134
|
+
tileResolution: tileResolution || DEFAULT_TILE_RESOLUTION
|
|
1135
|
+
},
|
|
1136
|
+
opts: {
|
|
1137
|
+
abortController
|
|
1138
|
+
}
|
|
1139
|
+
// Avoid `normalizeObjectKeys()`, which changes column names.
|
|
1140
|
+
}).then(_ref => {
|
|
1141
|
+
let {
|
|
1142
|
+
rows
|
|
1143
|
+
} = _ref;
|
|
1144
|
+
return {
|
|
1145
|
+
rows
|
|
1146
|
+
};
|
|
1147
|
+
}));
|
|
1148
|
+
} catch (e) {
|
|
1149
|
+
return Promise.reject(e);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
/****************************************************************************
|
|
1153
|
+
* FORMULA
|
|
1154
|
+
*/
|
|
1155
|
+
/**
|
|
1156
|
+
* Returns a scalar numerical statistic over all matching data. Suitable
|
|
1157
|
+
* for 'headline' or 'scorecard' figures such as counts and sums.
|
|
1158
|
+
*/
|
|
1159
|
+
getFormula(options) {
|
|
1160
|
+
try {
|
|
1161
|
+
const _this3 = this;
|
|
1162
|
+
const {
|
|
1163
|
+
filterOwner,
|
|
1164
|
+
spatialFilter,
|
|
1165
|
+
spatialFiltersMode,
|
|
1166
|
+
spatialIndexReferenceViewState,
|
|
1167
|
+
abortController,
|
|
1168
|
+
operationExp,
|
|
1169
|
+
...params
|
|
1170
|
+
} = options;
|
|
1171
|
+
const {
|
|
1172
|
+
column,
|
|
1173
|
+
operation
|
|
1174
|
+
} = params;
|
|
1175
|
+
const source = _this3.getModelSource(filterOwner);
|
|
1176
|
+
const spatialFiltersResolution = _this3._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1177
|
+
return Promise.resolve(executeModel({
|
|
1178
|
+
model: 'formula',
|
|
1179
|
+
source: {
|
|
1180
|
+
...source,
|
|
1181
|
+
spatialFiltersResolution,
|
|
1182
|
+
spatialFiltersMode,
|
|
1183
|
+
spatialFilter
|
|
1184
|
+
},
|
|
1185
|
+
params: {
|
|
1186
|
+
column: column ?? '*',
|
|
1187
|
+
operation,
|
|
1188
|
+
operationExp
|
|
1189
|
+
},
|
|
1190
|
+
opts: {
|
|
1191
|
+
abortController
|
|
1192
|
+
}
|
|
1193
|
+
}).then(res => normalizeObjectKeys(res.rows[0])));
|
|
1194
|
+
} catch (e) {
|
|
1195
|
+
return Promise.reject(e);
|
|
1214
1196
|
}
|
|
1215
|
-
return Promise.resolve(jsonPromise);
|
|
1216
|
-
} catch (e) {
|
|
1217
|
-
return Promise.reject(e);
|
|
1218
1197
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1198
|
+
/****************************************************************************
|
|
1199
|
+
* HISTOGRAM
|
|
1200
|
+
*/
|
|
1201
|
+
/**
|
|
1202
|
+
* Returns a list of labeled datapoints for 'bins' of data defined as ticks
|
|
1203
|
+
* over a numerical range. Suitable for histogram charts.
|
|
1204
|
+
*/
|
|
1205
|
+
getHistogram(options) {
|
|
1206
|
+
try {
|
|
1207
|
+
const _this4 = this;
|
|
1208
|
+
const {
|
|
1209
|
+
filterOwner,
|
|
1210
|
+
spatialFilter,
|
|
1211
|
+
spatialFiltersMode,
|
|
1212
|
+
spatialIndexReferenceViewState,
|
|
1213
|
+
abortController,
|
|
1214
|
+
...params
|
|
1215
|
+
} = options;
|
|
1216
|
+
const {
|
|
1217
|
+
column,
|
|
1218
|
+
operation,
|
|
1219
|
+
ticks
|
|
1220
|
+
} = params;
|
|
1221
|
+
const source = _this4.getModelSource(filterOwner);
|
|
1222
|
+
const spatialFiltersResolution = _this4._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1223
|
+
return Promise.resolve(executeModel({
|
|
1224
|
+
model: 'histogram',
|
|
1225
|
+
source: {
|
|
1226
|
+
...source,
|
|
1227
|
+
spatialFiltersResolution,
|
|
1228
|
+
spatialFiltersMode,
|
|
1229
|
+
spatialFilter
|
|
1230
|
+
},
|
|
1231
|
+
params: {
|
|
1232
|
+
column,
|
|
1233
|
+
operation,
|
|
1234
|
+
ticks
|
|
1235
|
+
},
|
|
1236
|
+
opts: {
|
|
1237
|
+
abortController
|
|
1238
|
+
}
|
|
1239
|
+
}).then(res => normalizeObjectKeys(res.rows))).then(function (data) {
|
|
1240
|
+
if (data.length) {
|
|
1241
|
+
// Given N ticks the API returns up to N+1 bins, omitting any empty bins. Bins
|
|
1242
|
+
// include 1 bin below the lowest tick, N-1 between ticks, and 1 bin above the highest tick.
|
|
1243
|
+
const result = Array(ticks.length + 1).fill(0);
|
|
1244
|
+
data.forEach(_ref2 => {
|
|
1245
|
+
let {
|
|
1246
|
+
tick,
|
|
1247
|
+
value
|
|
1248
|
+
} = _ref2;
|
|
1249
|
+
return result[tick] = value;
|
|
1250
|
+
});
|
|
1251
|
+
return result;
|
|
1252
|
+
}
|
|
1253
|
+
return [];
|
|
1254
|
+
});
|
|
1255
|
+
} catch (e) {
|
|
1256
|
+
return Promise.reject(e);
|
|
1264
1257
|
}
|
|
1265
1258
|
}
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1259
|
+
/****************************************************************************
|
|
1260
|
+
* RANGE
|
|
1261
|
+
*/
|
|
1262
|
+
/**
|
|
1263
|
+
* Returns a range (min and max) for a numerical column of matching rows.
|
|
1264
|
+
* Suitable for displaying certain 'headline' or 'scorecard' statistics,
|
|
1265
|
+
* or rendering a range slider UI for filtering.
|
|
1266
|
+
*/
|
|
1267
|
+
getRange(options) {
|
|
1268
|
+
try {
|
|
1269
|
+
const _this5 = this;
|
|
1270
|
+
const {
|
|
1271
|
+
filterOwner,
|
|
1272
|
+
spatialFilter,
|
|
1273
|
+
spatialFiltersMode,
|
|
1274
|
+
spatialIndexReferenceViewState,
|
|
1275
|
+
abortController,
|
|
1276
|
+
...params
|
|
1277
|
+
} = options;
|
|
1278
|
+
const {
|
|
1279
|
+
column
|
|
1280
|
+
} = params;
|
|
1281
|
+
const source = _this5.getModelSource(filterOwner);
|
|
1282
|
+
const spatialFiltersResolution = _this5._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1283
|
+
return Promise.resolve(executeModel({
|
|
1284
|
+
model: 'range',
|
|
1285
|
+
source: {
|
|
1286
|
+
...source,
|
|
1287
|
+
spatialFiltersResolution,
|
|
1288
|
+
spatialFiltersMode,
|
|
1289
|
+
spatialFilter
|
|
1290
|
+
},
|
|
1291
|
+
params: {
|
|
1292
|
+
column
|
|
1293
|
+
},
|
|
1294
|
+
opts: {
|
|
1295
|
+
abortController
|
|
1296
|
+
}
|
|
1297
|
+
}).then(res => normalizeObjectKeys(res.rows[0])));
|
|
1298
|
+
} catch (e) {
|
|
1299
|
+
return Promise.reject(e);
|
|
1276
1300
|
}
|
|
1277
1301
|
}
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1302
|
+
/****************************************************************************
|
|
1303
|
+
* SCATTER
|
|
1304
|
+
*/
|
|
1305
|
+
/**
|
|
1306
|
+
* Returns a list of bivariate datapoints defined as numerical 'x' and 'y'
|
|
1307
|
+
* values. Suitable for rendering scatter plots.
|
|
1308
|
+
*/
|
|
1309
|
+
getScatter(options) {
|
|
1310
|
+
try {
|
|
1311
|
+
const _this6 = this;
|
|
1312
|
+
const {
|
|
1313
|
+
filterOwner,
|
|
1314
|
+
spatialFilter,
|
|
1315
|
+
spatialFiltersMode,
|
|
1316
|
+
spatialIndexReferenceViewState,
|
|
1317
|
+
abortController,
|
|
1318
|
+
...params
|
|
1319
|
+
} = options;
|
|
1320
|
+
const {
|
|
1321
|
+
xAxisColumn,
|
|
1322
|
+
xAxisJoinOperation,
|
|
1323
|
+
yAxisColumn,
|
|
1324
|
+
yAxisJoinOperation
|
|
1325
|
+
} = params;
|
|
1326
|
+
const source = _this6.getModelSource(filterOwner);
|
|
1327
|
+
const spatialFiltersResolution = _this6._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1328
|
+
// Make sure this is sync with the same constant in cloud-native/maps-api
|
|
1329
|
+
const HARD_LIMIT = 500;
|
|
1330
|
+
return Promise.resolve(executeModel({
|
|
1331
|
+
model: 'scatterplot',
|
|
1332
|
+
source: {
|
|
1333
|
+
...source,
|
|
1334
|
+
spatialFiltersResolution,
|
|
1335
|
+
spatialFiltersMode,
|
|
1336
|
+
spatialFilter
|
|
1337
|
+
},
|
|
1338
|
+
params: {
|
|
1339
|
+
xAxisColumn,
|
|
1340
|
+
xAxisJoinOperation,
|
|
1341
|
+
yAxisColumn,
|
|
1342
|
+
yAxisJoinOperation,
|
|
1343
|
+
limit: HARD_LIMIT
|
|
1344
|
+
},
|
|
1345
|
+
opts: {
|
|
1346
|
+
abortController
|
|
1347
|
+
}
|
|
1348
|
+
}).then(res => normalizeObjectKeys(res.rows)).then(res => res.map(_ref3 => {
|
|
1349
|
+
let {
|
|
1350
|
+
x,
|
|
1351
|
+
y
|
|
1352
|
+
} = _ref3;
|
|
1353
|
+
return [x, y];
|
|
1354
|
+
})));
|
|
1355
|
+
} catch (e) {
|
|
1356
|
+
return Promise.reject(e);
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
/****************************************************************************
|
|
1360
|
+
* TABLE
|
|
1361
|
+
*/
|
|
1362
|
+
/**
|
|
1363
|
+
* Returns a list of arbitrary data rows, with support for pagination and
|
|
1364
|
+
* sorting. Suitable for displaying tables and lists.
|
|
1365
|
+
*/
|
|
1366
|
+
getTable(options) {
|
|
1367
|
+
try {
|
|
1368
|
+
const _this7 = this;
|
|
1369
|
+
const {
|
|
1370
|
+
filterOwner,
|
|
1371
|
+
spatialFilter,
|
|
1372
|
+
spatialFiltersMode,
|
|
1373
|
+
spatialIndexReferenceViewState,
|
|
1374
|
+
abortController,
|
|
1375
|
+
...params
|
|
1376
|
+
} = options;
|
|
1377
|
+
const {
|
|
1378
|
+
columns,
|
|
1379
|
+
sortBy,
|
|
1380
|
+
sortDirection,
|
|
1381
|
+
offset = 0,
|
|
1382
|
+
limit = 10
|
|
1383
|
+
} = params;
|
|
1384
|
+
const source = _this7.getModelSource(filterOwner);
|
|
1385
|
+
const spatialFiltersResolution = _this7._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1386
|
+
return Promise.resolve(executeModel({
|
|
1387
|
+
model: 'table',
|
|
1388
|
+
source: {
|
|
1389
|
+
...source,
|
|
1390
|
+
spatialFiltersResolution,
|
|
1391
|
+
spatialFiltersMode,
|
|
1392
|
+
spatialFilter
|
|
1393
|
+
},
|
|
1394
|
+
params: {
|
|
1395
|
+
column: columns,
|
|
1396
|
+
sortBy,
|
|
1397
|
+
sortDirection,
|
|
1398
|
+
limit,
|
|
1399
|
+
offset
|
|
1400
|
+
},
|
|
1401
|
+
opts: {
|
|
1402
|
+
abortController
|
|
1403
|
+
}
|
|
1404
|
+
}).then(res => ({
|
|
1405
|
+
// Avoid `normalizeObjectKeys()`, which changes column names.
|
|
1406
|
+
rows: res.rows ?? res.ROWS,
|
|
1407
|
+
totalCount: res.metadata?.total ?? res.METADATA?.TOTAL
|
|
1408
|
+
})));
|
|
1409
|
+
} catch (e) {
|
|
1410
|
+
return Promise.reject(e);
|
|
1300
1411
|
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
if (accessToken) {
|
|
1355
|
-
json.accessToken = accessToken;
|
|
1356
|
-
}
|
|
1357
|
-
_exit = 1;
|
|
1358
|
-
return json;
|
|
1359
|
-
});
|
|
1412
|
+
}
|
|
1413
|
+
/****************************************************************************
|
|
1414
|
+
* TIME SERIES
|
|
1415
|
+
*/
|
|
1416
|
+
/**
|
|
1417
|
+
* Returns a series of labeled numerical values, grouped into equally-sized
|
|
1418
|
+
* time intervals. Suitable for rendering time series charts.
|
|
1419
|
+
*/
|
|
1420
|
+
getTimeSeries(options) {
|
|
1421
|
+
try {
|
|
1422
|
+
const _this8 = this;
|
|
1423
|
+
const {
|
|
1424
|
+
filterOwner,
|
|
1425
|
+
abortController,
|
|
1426
|
+
spatialFilter,
|
|
1427
|
+
spatialFiltersMode,
|
|
1428
|
+
spatialIndexReferenceViewState,
|
|
1429
|
+
...params
|
|
1430
|
+
} = options;
|
|
1431
|
+
const {
|
|
1432
|
+
column,
|
|
1433
|
+
operationColumn,
|
|
1434
|
+
joinOperation,
|
|
1435
|
+
operation,
|
|
1436
|
+
stepSize,
|
|
1437
|
+
stepMultiplier,
|
|
1438
|
+
splitByCategory,
|
|
1439
|
+
splitByCategoryLimit,
|
|
1440
|
+
splitByCategoryValues
|
|
1441
|
+
} = params;
|
|
1442
|
+
const source = _this8.getModelSource(filterOwner);
|
|
1443
|
+
const spatialFiltersResolution = _this8._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1444
|
+
return Promise.resolve(executeModel({
|
|
1445
|
+
model: 'timeseries',
|
|
1446
|
+
source: {
|
|
1447
|
+
...source,
|
|
1448
|
+
spatialFiltersResolution,
|
|
1449
|
+
spatialFiltersMode,
|
|
1450
|
+
spatialFilter
|
|
1451
|
+
},
|
|
1452
|
+
params: {
|
|
1453
|
+
column,
|
|
1454
|
+
stepSize,
|
|
1455
|
+
stepMultiplier,
|
|
1456
|
+
operationColumn: operationColumn || column,
|
|
1457
|
+
joinOperation,
|
|
1458
|
+
operation,
|
|
1459
|
+
splitByCategory,
|
|
1460
|
+
splitByCategoryLimit,
|
|
1461
|
+
splitByCategoryValues
|
|
1462
|
+
},
|
|
1463
|
+
opts: {
|
|
1464
|
+
abortController
|
|
1360
1465
|
}
|
|
1361
|
-
}(
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1466
|
+
}).then(res => ({
|
|
1467
|
+
rows: normalizeObjectKeys(res.rows),
|
|
1468
|
+
categories: res.metadata?.categories
|
|
1469
|
+
})));
|
|
1470
|
+
} catch (e) {
|
|
1471
|
+
return Promise.reject(e);
|
|
1472
|
+
}
|
|
1366
1473
|
}
|
|
1367
|
-
}
|
|
1368
|
-
|
|
1474
|
+
}
|
|
1475
|
+
WidgetBaseSource.defaultProps = {
|
|
1476
|
+
apiVersion: exports.ApiVersion.V3,
|
|
1369
1477
|
apiBaseUrl: DEFAULT_API_BASE_URL,
|
|
1370
1478
|
clientId: getClient(),
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
maxLengthURL: DEFAULT_MAX_LENGTH_URL
|
|
1479
|
+
filters: {},
|
|
1480
|
+
filtersLogicalOperator: 'and'
|
|
1374
1481
|
};
|
|
1375
1482
|
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1483
|
+
/**
|
|
1484
|
+
* Source for Widget API requests on a data source defined by a SQL query.
|
|
1485
|
+
*
|
|
1486
|
+
* Generally not intended to be constructed directly. Instead, call
|
|
1487
|
+
* {@link vectorQuerySource}, {@link h3QuerySource}, or {@link quadbinQuerySource},
|
|
1488
|
+
* which can be shared with map layers. Sources contain a `widgetSource` property,
|
|
1489
|
+
* for use by widget implementations.
|
|
1490
|
+
*
|
|
1491
|
+
* Example:
|
|
1492
|
+
*
|
|
1493
|
+
* ```javascript
|
|
1494
|
+
* import { vectorQuerySource } from '@carto/api-client';
|
|
1495
|
+
*
|
|
1496
|
+
* const data = vectorQuerySource({
|
|
1497
|
+
* accessToken: '••••',
|
|
1498
|
+
* connectionName: 'carto_dw',
|
|
1499
|
+
* sqlQuery: 'SELECT * FROM carto-demo-data.demo_tables.retail_stores'
|
|
1500
|
+
* });
|
|
1501
|
+
*
|
|
1502
|
+
* const { widgetSource } = await data;
|
|
1503
|
+
* ```
|
|
1504
|
+
*/
|
|
1505
|
+
class WidgetQuerySource extends WidgetBaseSource {
|
|
1506
|
+
getModelSource(owner) {
|
|
1507
|
+
return {
|
|
1508
|
+
...super._getModelSource(owner),
|
|
1509
|
+
type: 'query',
|
|
1510
|
+
data: this.props.sqlQuery,
|
|
1511
|
+
queryParameters: this.props.queryParameters
|
|
1389
1512
|
};
|
|
1390
|
-
if (columns) {
|
|
1391
|
-
urlParameters.columns = columns.join(',');
|
|
1392
|
-
}
|
|
1393
|
-
if (filters) {
|
|
1394
|
-
urlParameters.filters = filters;
|
|
1395
|
-
}
|
|
1396
|
-
if (queryParameters) {
|
|
1397
|
-
urlParameters.queryParameters = queryParameters;
|
|
1398
|
-
}
|
|
1399
|
-
return Promise.resolve(baseSource('boundary', options, urlParameters));
|
|
1400
|
-
} catch (e) {
|
|
1401
|
-
return Promise.reject(e);
|
|
1402
1513
|
}
|
|
1403
|
-
}
|
|
1514
|
+
}
|
|
1404
1515
|
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1516
|
+
/**
|
|
1517
|
+
* Source for Widget API requests on a data source defined as a table.
|
|
1518
|
+
*
|
|
1519
|
+
* Generally not intended to be constructed directly. Instead, call
|
|
1520
|
+
* {@link vectorTableSource}, {@link h3TableSource}, or {@link quadbinTableSource},
|
|
1521
|
+
* which can be shared with map layers. Sources contain a `widgetSource` property,
|
|
1522
|
+
* for use by widget implementations.
|
|
1523
|
+
*
|
|
1524
|
+
* Example:
|
|
1525
|
+
*
|
|
1526
|
+
* ```javascript
|
|
1527
|
+
* import { vectorTableSource } from '@carto/api-client';
|
|
1528
|
+
*
|
|
1529
|
+
* const data = vectorTableSource({
|
|
1530
|
+
* accessToken: '••••',
|
|
1531
|
+
* connectionName: 'carto_dw',
|
|
1532
|
+
* tableName: 'carto-demo-data.demo_tables.retail_stores'
|
|
1533
|
+
* });
|
|
1534
|
+
*
|
|
1535
|
+
* const { widgetSource } = await data;
|
|
1536
|
+
* ```
|
|
1537
|
+
*/
|
|
1538
|
+
class WidgetTableSource extends WidgetBaseSource {
|
|
1539
|
+
getModelSource(owner) {
|
|
1540
|
+
return {
|
|
1541
|
+
...super._getModelSource(owner),
|
|
1542
|
+
type: 'table',
|
|
1543
|
+
data: this.props.tableName
|
|
1417
1544
|
};
|
|
1418
|
-
if (columns) {
|
|
1419
|
-
urlParameters.columns = columns.join(',');
|
|
1420
|
-
}
|
|
1421
|
-
if (filters) {
|
|
1422
|
-
urlParameters.filters = filters;
|
|
1423
|
-
}
|
|
1424
|
-
return Promise.resolve(baseSource('boundary', options, urlParameters));
|
|
1425
|
-
} catch (e) {
|
|
1426
|
-
return Promise.reject(e);
|
|
1427
1545
|
}
|
|
1428
|
-
}
|
|
1546
|
+
}
|
|
1429
1547
|
|
|
1430
1548
|
// deck.gl
|
|
1431
1549
|
const h3QuerySource = function (options) {
|
|
@@ -1455,7 +1573,12 @@ const h3QuerySource = function (options) {
|
|
|
1455
1573
|
}
|
|
1456
1574
|
return Promise.resolve(baseSource('query', options, urlParameters).then(result => ({
|
|
1457
1575
|
...result,
|
|
1458
|
-
widgetSource: new WidgetQuerySource(
|
|
1576
|
+
widgetSource: new WidgetQuerySource({
|
|
1577
|
+
...options,
|
|
1578
|
+
// NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
|
|
1579
|
+
spatialDataColumn,
|
|
1580
|
+
spatialDataType: 'h3'
|
|
1581
|
+
})
|
|
1459
1582
|
})));
|
|
1460
1583
|
} catch (e) {
|
|
1461
1584
|
return Promise.reject(e);
|
|
@@ -1486,7 +1609,12 @@ const h3TableSource = function (options) {
|
|
|
1486
1609
|
}
|
|
1487
1610
|
return Promise.resolve(baseSource('table', options, urlParameters).then(result => ({
|
|
1488
1611
|
...result,
|
|
1489
|
-
widgetSource: new WidgetTableSource(
|
|
1612
|
+
widgetSource: new WidgetTableSource({
|
|
1613
|
+
...options,
|
|
1614
|
+
// NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
|
|
1615
|
+
spatialDataColumn,
|
|
1616
|
+
spatialDataType: 'h3'
|
|
1617
|
+
})
|
|
1490
1618
|
})));
|
|
1491
1619
|
} catch (e) {
|
|
1492
1620
|
return Promise.reject(e);
|
|
@@ -1555,7 +1683,12 @@ const quadbinQuerySource = function (options) {
|
|
|
1555
1683
|
}
|
|
1556
1684
|
return Promise.resolve(baseSource('query', options, urlParameters).then(result => ({
|
|
1557
1685
|
...result,
|
|
1558
|
-
widgetSource: new WidgetQuerySource(
|
|
1686
|
+
widgetSource: new WidgetQuerySource({
|
|
1687
|
+
...options,
|
|
1688
|
+
// NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
|
|
1689
|
+
spatialDataColumn,
|
|
1690
|
+
spatialDataType: 'quadbin'
|
|
1691
|
+
})
|
|
1559
1692
|
})));
|
|
1560
1693
|
} catch (e) {
|
|
1561
1694
|
return Promise.reject(e);
|
|
@@ -1586,7 +1719,12 @@ const quadbinTableSource = function (options) {
|
|
|
1586
1719
|
}
|
|
1587
1720
|
return Promise.resolve(baseSource('table', options, urlParameters).then(result => ({
|
|
1588
1721
|
...result,
|
|
1589
|
-
widgetSource: new WidgetTableSource(
|
|
1722
|
+
widgetSource: new WidgetTableSource({
|
|
1723
|
+
...options,
|
|
1724
|
+
// NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
|
|
1725
|
+
spatialDataColumn,
|
|
1726
|
+
spatialDataType: 'quadbin'
|
|
1727
|
+
})
|
|
1590
1728
|
})));
|
|
1591
1729
|
} catch (e) {
|
|
1592
1730
|
return Promise.reject(e);
|
|
@@ -1617,7 +1755,8 @@ const vectorQuerySource = function (options) {
|
|
|
1617
1755
|
spatialDataColumn = 'geom',
|
|
1618
1756
|
sqlQuery,
|
|
1619
1757
|
tileResolution = DEFAULT_TILE_RESOLUTION,
|
|
1620
|
-
queryParameters
|
|
1758
|
+
queryParameters,
|
|
1759
|
+
aggregationExp
|
|
1621
1760
|
} = options;
|
|
1622
1761
|
const urlParameters = {
|
|
1623
1762
|
spatialDataColumn,
|
|
@@ -1634,9 +1773,15 @@ const vectorQuerySource = function (options) {
|
|
|
1634
1773
|
if (queryParameters) {
|
|
1635
1774
|
urlParameters.queryParameters = queryParameters;
|
|
1636
1775
|
}
|
|
1776
|
+
if (aggregationExp) {
|
|
1777
|
+
urlParameters.aggregationExp = aggregationExp;
|
|
1778
|
+
}
|
|
1637
1779
|
return Promise.resolve(baseSource('query', options, urlParameters).then(result => ({
|
|
1638
1780
|
...result,
|
|
1639
|
-
widgetSource: new WidgetQuerySource(
|
|
1781
|
+
widgetSource: new WidgetQuerySource({
|
|
1782
|
+
...options,
|
|
1783
|
+
spatialDataType: 'geo'
|
|
1784
|
+
})
|
|
1640
1785
|
})));
|
|
1641
1786
|
} catch (e) {
|
|
1642
1787
|
return Promise.reject(e);
|
|
@@ -1651,7 +1796,8 @@ const vectorTableSource = function (options) {
|
|
|
1651
1796
|
filters,
|
|
1652
1797
|
spatialDataColumn = 'geom',
|
|
1653
1798
|
tableName,
|
|
1654
|
-
tileResolution = DEFAULT_TILE_RESOLUTION
|
|
1799
|
+
tileResolution = DEFAULT_TILE_RESOLUTION,
|
|
1800
|
+
aggregationExp
|
|
1655
1801
|
} = options;
|
|
1656
1802
|
const urlParameters = {
|
|
1657
1803
|
name: tableName,
|
|
@@ -1665,9 +1811,15 @@ const vectorTableSource = function (options) {
|
|
|
1665
1811
|
if (filters) {
|
|
1666
1812
|
urlParameters.filters = filters;
|
|
1667
1813
|
}
|
|
1814
|
+
if (aggregationExp) {
|
|
1815
|
+
urlParameters.aggregationExp = aggregationExp;
|
|
1816
|
+
}
|
|
1668
1817
|
return Promise.resolve(baseSource('table', options, urlParameters).then(result => ({
|
|
1669
1818
|
...result,
|
|
1670
|
-
widgetSource: new WidgetTableSource(
|
|
1819
|
+
widgetSource: new WidgetTableSource({
|
|
1820
|
+
...options,
|
|
1821
|
+
spatialDataType: 'geo'
|
|
1822
|
+
})
|
|
1671
1823
|
})));
|
|
1672
1824
|
} catch (e) {
|
|
1673
1825
|
return Promise.reject(e);
|