@carto/api-client 0.4.0-alpha.6 → 0.4.1-alpha.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.
@@ -493,41 +493,43 @@ function executeModel(props) {
493
493
  data,
494
494
  filters,
495
495
  filtersLogicalOperator = 'and',
496
- geoColumn = DEFAULT_GEO_COLUMN
496
+ spatialDataType = 'geo',
497
+ spatialFiltersMode = 'intersects',
498
+ spatialFiltersResolution = 0
497
499
  } = source;
498
- const queryParameters = source.queryParameters ? JSON.stringify(source.queryParameters) : '';
499
500
  const queryParams = {
500
501
  type,
501
502
  client: clientId,
502
503
  source: data,
503
- params: JSON.stringify(params),
504
- queryParameters,
505
- filters: JSON.stringify(filters),
504
+ params,
505
+ queryParameters: source.queryParameters || '',
506
+ filters,
506
507
  filtersLogicalOperator
507
508
  };
509
+ const spatialDataColumn = source.spatialDataColumn || DEFAULT_GEO_COLUMN;
508
510
  // Picking Model API requires 'spatialDataColumn'.
509
511
  if (model === 'pick') {
510
- queryParams.spatialDataColumn = geoColumn;
512
+ queryParams.spatialDataColumn = spatialDataColumn;
511
513
  }
512
- // API supports multiple filters, we apply it only to geoColumn
514
+ // API supports multiple filters, we apply it only to spatialDataColumn
513
515
  const spatialFilters = source.spatialFilter ? {
514
- [geoColumn]: source.spatialFilter
516
+ [spatialDataColumn]: source.spatialFilter
515
517
  } : undefined;
516
518
  if (spatialFilters) {
517
- queryParams.spatialFilters = JSON.stringify(spatialFilters);
519
+ queryParams.spatialFilters = spatialFilters; // JSON.stringify(spatialFilters);
520
+ queryParams.spatialDataColumn = spatialDataColumn;
521
+ queryParams.spatialDataType = spatialDataType;
522
+ }
523
+ if (spatialDataType !== 'geo') {
524
+ if (spatialFiltersResolution > 0) {
525
+ queryParams.spatialFiltersResolution = spatialFiltersResolution;
526
+ }
527
+ queryParams.spatialFiltersMode = spatialFiltersMode;
518
528
  }
519
- const urlWithSearchParams = url + '?' + new URLSearchParams(queryParams).toString();
529
+ const urlWithSearchParams = url + '?' + objectToURLSearchParams(queryParams).toString();
520
530
  const isGet = urlWithSearchParams.length <= REQUEST_GET_MAX_URL_LENGTH;
521
531
  if (isGet) {
522
532
  url = urlWithSearchParams;
523
- } else {
524
- // undo the JSON.stringify, @TODO find a better pattern
525
- queryParams.params = params;
526
- queryParams.filters = filters;
527
- queryParams.queryParameters = source.queryParameters;
528
- if (spatialFilters) {
529
- queryParams.spatialFilters = spatialFilters;
530
- }
531
533
  }
532
534
  return makeCall({
533
535
  url,
@@ -539,15 +541,75 @@ function executeModel(props) {
539
541
  })
540
542
  });
541
543
  }
544
+ function objectToURLSearchParams(object) {
545
+ const params = new URLSearchParams();
546
+ for (const key in object) {
547
+ if (isPureObject(object[key])) {
548
+ params.append(key, JSON.stringify(object[key]));
549
+ } else if (Array.isArray(object[key])) {
550
+ params.append(key, JSON.stringify(object[key]));
551
+ } else if (object[key] === null) {
552
+ params.append(key, 'null');
553
+ } else if (object[key] !== undefined) {
554
+ params.append(key, String(object[key]));
555
+ }
556
+ }
557
+ return params;
558
+ }
542
559
 
543
- const _excluded$1 = ["filterOwner", "spatialFilter", "abortController"],
544
- _excluded2 = ["filterOwner", "spatialFilter", "abortController"],
545
- _excluded3 = ["filterOwner", "spatialFilter", "abortController", "operationExp"],
546
- _excluded4 = ["filterOwner", "spatialFilter", "abortController"],
547
- _excluded5 = ["filterOwner", "spatialFilter", "abortController"],
548
- _excluded6 = ["filterOwner", "spatialFilter", "abortController"],
549
- _excluded7 = ["filterOwner", "spatialFilter", "abortController"],
550
- _excluded8 = ["filterOwner", "abortController", "spatialFilter"];
560
+ const DEFAULT_TILE_SIZE = 512;
561
+ const QUADBIN_ZOOM_MAX_OFFSET = 4;
562
+ function getSpatialFiltersResolution({
563
+ source,
564
+ viewState
565
+ }) {
566
+ var _source$dataResolutio, _source$aggregationRe;
567
+ assert(viewState, 'viewState prop is required to compute automatic spatialFiltersResolution when using spatialFilter with spatial indexes. Either pass a `spatialFiltersResolution` prop or a `viewState` prop to avoid this error');
568
+ const dataResolution = (_source$dataResolutio = source.dataResolution) != null ? _source$dataResolutio : Number.MAX_VALUE;
569
+ const aggregationResLevel = (_source$aggregationRe = source.aggregationResLevel) != null ? _source$aggregationRe : source.spatialDataType === 'h3' ? DEFAULT_AGGREGATION_RES_LEVEL_H3 : DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN;
570
+ const aggregationResLevelOffset = Math.max(0, Math.floor(aggregationResLevel));
571
+ const currentZoomInt = Math.ceil(viewState.zoom);
572
+ if (source.spatialDataType === 'h3') {
573
+ var _maxH3SpatialFiltersR, _maxH3SpatialFiltersR2;
574
+ const tileSize = DEFAULT_TILE_SIZE;
575
+ const maxResolutionForZoom = (_maxH3SpatialFiltersR = (_maxH3SpatialFiltersR2 = maxH3SpatialFiltersResolutions.find(([zoom]) => zoom === currentZoomInt)) == null ? void 0 : _maxH3SpatialFiltersR2[1]) != null ? _maxH3SpatialFiltersR : Math.max(0, currentZoomInt - 3);
576
+ const maxSpatialFiltersResolution = maxResolutionForZoom ? Math.min(dataResolution, maxResolutionForZoom) : dataResolution;
577
+ const hexagonResolution = getHexagonResolution(viewState, tileSize) + aggregationResLevelOffset;
578
+ return Math.min(hexagonResolution, maxSpatialFiltersResolution);
579
+ }
580
+ if (source.spatialDataType === 'quadbin') {
581
+ const maxResolutionForZoom = currentZoomInt + QUADBIN_ZOOM_MAX_OFFSET;
582
+ const maxSpatialFiltersResolution = Math.min(dataResolution, maxResolutionForZoom);
583
+ const quadsResolution = Math.floor(viewState.zoom) + aggregationResLevelOffset;
584
+ return Math.min(quadsResolution, maxSpatialFiltersResolution);
585
+ }
586
+ return undefined;
587
+ }
588
+ 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]];
589
+ // stolen from https://github.com/visgl/deck.gl/blob/master/modules/carto/src/layers/h3-tileset-2d.ts
590
+ // Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
591
+ const BIAS = 2;
592
+ // Resolution conversion function. Takes a WebMercatorViewport and returns
593
+ // a H3 resolution such that the screen space size of the hexagons is
594
+ // similar
595
+ function getHexagonResolution(viewport, tileSize) {
596
+ // Difference in given tile size compared to deck's internal 512px tile size,
597
+ // expressed as an offset to the viewport zoom.
598
+ const zoomOffset = Math.log2(tileSize / DEFAULT_TILE_SIZE);
599
+ const hexagonScaleFactor = 2 / 3 * (viewport.zoom - zoomOffset);
600
+ const latitudeScaleFactor = Math.log(1 / Math.cos(Math.PI * viewport.latitude / 180));
601
+ // Clip and bias
602
+ return Math.max(0, Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS));
603
+ }
604
+
605
+ const _excluded$1 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "abortController", "viewState"],
606
+ _excluded2 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "abortController", "viewState"],
607
+ _excluded3 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "abortController", "operationExp", "viewState"],
608
+ _excluded4 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "abortController", "viewState"],
609
+ _excluded5 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "abortController", "viewState"],
610
+ _excluded6 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "abortController", "viewState"],
611
+ _excluded7 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "abortController", "viewState"],
612
+ _excluded8 = ["filterOwner", "abortController", "spatialFilter", "spatialFiltersMode", "viewState"];
551
613
  /**
552
614
  * Source for Widget API requests on a data source defined by a SQL query.
553
615
  *
@@ -568,7 +630,8 @@ class WidgetBaseSource {
568
630
  connectionName: props.connectionName,
569
631
  filters: getApplicableFilters(owner, props.filters),
570
632
  filtersLogicalOperator: props.filtersLogicalOperator,
571
- geoColumn: props.geoColumn
633
+ spatialDataType: props.spatialDataType,
634
+ spatialDataColumn: props.spatialDataColumn
572
635
  };
573
636
  }
574
637
  /****************************************************************************
@@ -582,7 +645,9 @@ class WidgetBaseSource {
582
645
  const {
583
646
  filterOwner,
584
647
  spatialFilter,
585
- abortController
648
+ spatialFiltersMode,
649
+ abortController,
650
+ viewState
586
651
  } = options,
587
652
  params = _objectWithoutPropertiesLoose(options, _excluded$1);
588
653
  const {
@@ -590,9 +655,19 @@ class WidgetBaseSource {
590
655
  operation,
591
656
  operationColumn
592
657
  } = params;
658
+ const source = this.getModelSource(filterOwner);
659
+ let spatialFiltersResolution;
660
+ if (spatialFilter && source.spatialDataType !== 'geo') {
661
+ spatialFiltersResolution = getSpatialFiltersResolution({
662
+ source,
663
+ viewState
664
+ });
665
+ }
593
666
  return executeModel({
594
667
  model: 'category',
595
- source: _extends({}, this.getModelSource(filterOwner), {
668
+ source: _extends({}, source, {
669
+ spatialFiltersResolution,
670
+ spatialFiltersMode,
596
671
  spatialFilter
597
672
  }),
598
673
  params: {
@@ -620,7 +695,9 @@ class WidgetBaseSource {
620
695
  const {
621
696
  filterOwner,
622
697
  spatialFilter,
623
- abortController
698
+ spatialFiltersMode,
699
+ abortController,
700
+ viewState
624
701
  } = options,
625
702
  params = _objectWithoutPropertiesLoose(options, _excluded2);
626
703
  const {
@@ -631,9 +708,19 @@ class WidgetBaseSource {
631
708
  limit,
632
709
  tileResolution
633
710
  } = params;
711
+ const source = this.getModelSource(filterOwner);
712
+ let spatialFiltersResolution;
713
+ if (spatialFilter && source.spatialDataType !== 'geo') {
714
+ spatialFiltersResolution = getSpatialFiltersResolution({
715
+ source,
716
+ viewState
717
+ });
718
+ }
634
719
  return executeModel({
635
720
  model: 'pick',
636
- source: _extends({}, this.getModelSource(filterOwner), {
721
+ source: _extends({}, source, {
722
+ spatialFiltersResolution,
723
+ spatialFiltersMode,
637
724
  spatialFilter
638
725
  }),
639
726
  params: {
@@ -662,17 +749,29 @@ class WidgetBaseSource {
662
749
  const {
663
750
  filterOwner,
664
751
  spatialFilter,
752
+ spatialFiltersMode,
665
753
  abortController,
666
- operationExp
754
+ operationExp,
755
+ viewState
667
756
  } = options,
668
757
  params = _objectWithoutPropertiesLoose(options, _excluded3);
669
758
  const {
670
759
  column,
671
760
  operation
672
761
  } = params;
762
+ const source = this.getModelSource(filterOwner);
763
+ let spatialFiltersResolution;
764
+ if (spatialFilter && source.spatialDataType !== 'geo') {
765
+ spatialFiltersResolution = getSpatialFiltersResolution({
766
+ source,
767
+ viewState
768
+ });
769
+ }
673
770
  return executeModel({
674
771
  model: 'formula',
675
- source: _extends({}, this.getModelSource(filterOwner), {
772
+ source: _extends({}, source, {
773
+ spatialFiltersResolution,
774
+ spatialFiltersMode,
676
775
  spatialFilter
677
776
  }),
678
777
  params: {
@@ -696,7 +795,9 @@ class WidgetBaseSource {
696
795
  const {
697
796
  filterOwner,
698
797
  spatialFilter,
699
- abortController
798
+ spatialFiltersMode,
799
+ abortController,
800
+ viewState
700
801
  } = options,
701
802
  params = _objectWithoutPropertiesLoose(options, _excluded4);
702
803
  const {
@@ -704,9 +805,19 @@ class WidgetBaseSource {
704
805
  operation,
705
806
  ticks
706
807
  } = params;
808
+ const source = this.getModelSource(filterOwner);
809
+ let spatialFiltersResolution;
810
+ if (spatialFilter && source.spatialDataType !== 'geo') {
811
+ spatialFiltersResolution = getSpatialFiltersResolution({
812
+ source,
813
+ viewState
814
+ });
815
+ }
707
816
  const data = await executeModel({
708
817
  model: 'histogram',
709
- source: _extends({}, this.getModelSource(filterOwner), {
818
+ source: _extends({}, source, {
819
+ spatialFiltersResolution,
820
+ spatialFiltersMode,
710
821
  spatialFilter
711
822
  }),
712
823
  params: {
@@ -742,15 +853,27 @@ class WidgetBaseSource {
742
853
  const {
743
854
  filterOwner,
744
855
  spatialFilter,
745
- abortController
856
+ spatialFiltersMode,
857
+ abortController,
858
+ viewState
746
859
  } = options,
747
860
  params = _objectWithoutPropertiesLoose(options, _excluded5);
748
861
  const {
749
862
  column
750
863
  } = params;
864
+ const source = this.getModelSource(filterOwner);
865
+ let spatialFiltersResolution;
866
+ if (spatialFilter && source.spatialDataType !== 'geo') {
867
+ spatialFiltersResolution = getSpatialFiltersResolution({
868
+ source,
869
+ viewState
870
+ });
871
+ }
751
872
  return executeModel({
752
873
  model: 'range',
753
- source: _extends({}, this.getModelSource(filterOwner), {
874
+ source: _extends({}, source, {
875
+ spatialFiltersResolution,
876
+ spatialFiltersMode,
754
877
  spatialFilter
755
878
  }),
756
879
  params: {
@@ -772,7 +895,9 @@ class WidgetBaseSource {
772
895
  const {
773
896
  filterOwner,
774
897
  spatialFilter,
775
- abortController
898
+ spatialFiltersMode,
899
+ abortController,
900
+ viewState
776
901
  } = options,
777
902
  params = _objectWithoutPropertiesLoose(options, _excluded6);
778
903
  const {
@@ -781,11 +906,21 @@ class WidgetBaseSource {
781
906
  yAxisColumn,
782
907
  yAxisJoinOperation
783
908
  } = params;
909
+ const source = this.getModelSource(filterOwner);
910
+ let spatialFiltersResolution;
911
+ if (spatialFilter && source.spatialDataType !== 'geo') {
912
+ spatialFiltersResolution = getSpatialFiltersResolution({
913
+ source,
914
+ viewState
915
+ });
916
+ }
784
917
  // Make sure this is sync with the same constant in cloud-native/maps-api
785
918
  const HARD_LIMIT = 500;
786
919
  return executeModel({
787
920
  model: 'scatterplot',
788
- source: _extends({}, this.getModelSource(filterOwner), {
921
+ source: _extends({}, source, {
922
+ spatialFiltersResolution,
923
+ spatialFiltersMode,
789
924
  spatialFilter
790
925
  }),
791
926
  params: {
@@ -814,7 +949,9 @@ class WidgetBaseSource {
814
949
  const {
815
950
  filterOwner,
816
951
  spatialFilter,
817
- abortController
952
+ spatialFiltersMode,
953
+ abortController,
954
+ viewState
818
955
  } = options,
819
956
  params = _objectWithoutPropertiesLoose(options, _excluded7);
820
957
  const {
@@ -824,9 +961,19 @@ class WidgetBaseSource {
824
961
  offset = 0,
825
962
  limit = 10
826
963
  } = params;
964
+ const source = this.getModelSource(filterOwner);
965
+ let spatialFiltersResolution;
966
+ if (spatialFilter && source.spatialDataType !== 'geo') {
967
+ spatialFiltersResolution = getSpatialFiltersResolution({
968
+ source,
969
+ viewState
970
+ });
971
+ }
827
972
  return executeModel({
828
973
  model: 'table',
829
- source: _extends({}, this.getModelSource(filterOwner), {
974
+ source: _extends({}, source, {
975
+ spatialFiltersResolution,
976
+ spatialFiltersMode,
830
977
  spatialFilter
831
978
  }),
832
979
  params: {
@@ -859,7 +1006,9 @@ class WidgetBaseSource {
859
1006
  const {
860
1007
  filterOwner,
861
1008
  abortController,
862
- spatialFilter
1009
+ spatialFilter,
1010
+ spatialFiltersMode,
1011
+ viewState
863
1012
  } = options,
864
1013
  params = _objectWithoutPropertiesLoose(options, _excluded8);
865
1014
  const {
@@ -873,9 +1022,19 @@ class WidgetBaseSource {
873
1022
  splitByCategoryLimit,
874
1023
  splitByCategoryValues
875
1024
  } = params;
1025
+ const source = this.getModelSource(filterOwner);
1026
+ let spatialFiltersResolution;
1027
+ if (spatialFilter && source.spatialDataType !== 'geo') {
1028
+ spatialFiltersResolution = getSpatialFiltersResolution({
1029
+ source,
1030
+ viewState
1031
+ });
1032
+ }
876
1033
  return executeModel({
877
1034
  model: 'timeseries',
878
- source: _extends({}, this.getModelSource(filterOwner), {
1035
+ source: _extends({}, source, {
1036
+ spatialFiltersResolution,
1037
+ spatialFiltersMode,
879
1038
  spatialFilter
880
1039
  }),
881
1040
  params: {
@@ -906,8 +1065,7 @@ WidgetBaseSource.defaultProps = {
906
1065
  apiBaseUrl: DEFAULT_API_BASE_URL,
907
1066
  clientId: getClient(),
908
1067
  filters: {},
909
- filtersLogicalOperator: 'and',
910
- geoColumn: DEFAULT_GEO_COLUMN
1068
+ filtersLogicalOperator: 'and'
911
1069
  };
912
1070
 
913
1071
  /**
@@ -1311,7 +1469,11 @@ const h3QuerySource = async function h3QuerySource(options) {
1311
1469
  urlParameters.filters = filters;
1312
1470
  }
1313
1471
  return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
1314
- widgetSource: new WidgetQuerySource(options)
1472
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
1473
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
1474
+ spatialDataColumn,
1475
+ spatialDataType: 'h3'
1476
+ }))
1315
1477
  }));
1316
1478
  };
1317
1479
 
@@ -1336,7 +1498,11 @@ const h3TableSource = async function h3TableSource(options) {
1336
1498
  urlParameters.filters = filters;
1337
1499
  }
1338
1500
  return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
1339
- widgetSource: new WidgetTableSource(options)
1501
+ widgetSource: new WidgetTableSource(_extends({}, options, {
1502
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
1503
+ spatialDataColumn,
1504
+ spatialDataType: 'h3'
1505
+ }))
1340
1506
  }));
1341
1507
  };
1342
1508
 
@@ -1391,7 +1557,11 @@ const quadbinQuerySource = async function quadbinQuerySource(options) {
1391
1557
  urlParameters.filters = filters;
1392
1558
  }
1393
1559
  return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
1394
- widgetSource: new WidgetQuerySource(options)
1560
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
1561
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
1562
+ spatialDataColumn,
1563
+ spatialDataType: 'quadbin'
1564
+ }))
1395
1565
  }));
1396
1566
  };
1397
1567
 
@@ -1416,7 +1586,11 @@ const quadbinTableSource = async function quadbinTableSource(options) {
1416
1586
  urlParameters.filters = filters;
1417
1587
  }
1418
1588
  return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
1419
- widgetSource: new WidgetTableSource(options)
1589
+ widgetSource: new WidgetTableSource(_extends({}, options, {
1590
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
1591
+ spatialDataColumn,
1592
+ spatialDataType: 'quadbin'
1593
+ }))
1420
1594
  }));
1421
1595
  };
1422
1596
 
@@ -1456,7 +1630,9 @@ const vectorQuerySource = async function vectorQuerySource(options) {
1456
1630
  urlParameters.queryParameters = queryParameters;
1457
1631
  }
1458
1632
  return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
1459
- widgetSource: new WidgetQuerySource(options)
1633
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
1634
+ spatialDataType: 'geo'
1635
+ }))
1460
1636
  }));
1461
1637
  };
1462
1638
 
@@ -1481,7 +1657,9 @@ const vectorTableSource = async function vectorTableSource(options) {
1481
1657
  urlParameters.filters = filters;
1482
1658
  }
1483
1659
  return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
1484
- widgetSource: new WidgetTableSource(options)
1660
+ widgetSource: new WidgetTableSource(_extends({}, options, {
1661
+ spatialDataType: 'geo'
1662
+ }))
1485
1663
  }));
1486
1664
  };
1487
1665