@carto/api-client 0.4.1-alpha.1 → 0.4.2-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,9 @@ 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,
635
+ dataResolution: props.dataResolution
572
636
  };
573
637
  }
574
638
  /****************************************************************************
@@ -582,7 +646,9 @@ class WidgetBaseSource {
582
646
  const {
583
647
  filterOwner,
584
648
  spatialFilter,
585
- abortController
649
+ spatialFiltersMode,
650
+ abortController,
651
+ viewState
586
652
  } = options,
587
653
  params = _objectWithoutPropertiesLoose(options, _excluded$1);
588
654
  const {
@@ -590,9 +656,19 @@ class WidgetBaseSource {
590
656
  operation,
591
657
  operationColumn
592
658
  } = params;
659
+ const source = this.getModelSource(filterOwner);
660
+ let spatialFiltersResolution;
661
+ if (spatialFilter && source.spatialDataType !== 'geo') {
662
+ spatialFiltersResolution = getSpatialFiltersResolution({
663
+ source,
664
+ viewState
665
+ });
666
+ }
593
667
  return executeModel({
594
668
  model: 'category',
595
- source: _extends({}, this.getModelSource(filterOwner), {
669
+ source: _extends({}, source, {
670
+ spatialFiltersResolution,
671
+ spatialFiltersMode,
596
672
  spatialFilter
597
673
  }),
598
674
  params: {
@@ -620,7 +696,9 @@ class WidgetBaseSource {
620
696
  const {
621
697
  filterOwner,
622
698
  spatialFilter,
623
- abortController
699
+ spatialFiltersMode,
700
+ abortController,
701
+ viewState
624
702
  } = options,
625
703
  params = _objectWithoutPropertiesLoose(options, _excluded2);
626
704
  const {
@@ -631,9 +709,19 @@ class WidgetBaseSource {
631
709
  limit,
632
710
  tileResolution
633
711
  } = params;
712
+ const source = this.getModelSource(filterOwner);
713
+ let spatialFiltersResolution;
714
+ if (spatialFilter && source.spatialDataType !== 'geo') {
715
+ spatialFiltersResolution = getSpatialFiltersResolution({
716
+ source,
717
+ viewState
718
+ });
719
+ }
634
720
  return executeModel({
635
721
  model: 'pick',
636
- source: _extends({}, this.getModelSource(filterOwner), {
722
+ source: _extends({}, source, {
723
+ spatialFiltersResolution,
724
+ spatialFiltersMode,
637
725
  spatialFilter
638
726
  }),
639
727
  params: {
@@ -662,17 +750,29 @@ class WidgetBaseSource {
662
750
  const {
663
751
  filterOwner,
664
752
  spatialFilter,
753
+ spatialFiltersMode,
665
754
  abortController,
666
- operationExp
755
+ operationExp,
756
+ viewState
667
757
  } = options,
668
758
  params = _objectWithoutPropertiesLoose(options, _excluded3);
669
759
  const {
670
760
  column,
671
761
  operation
672
762
  } = params;
763
+ const source = this.getModelSource(filterOwner);
764
+ let spatialFiltersResolution;
765
+ if (spatialFilter && source.spatialDataType !== 'geo') {
766
+ spatialFiltersResolution = getSpatialFiltersResolution({
767
+ source,
768
+ viewState
769
+ });
770
+ }
673
771
  return executeModel({
674
772
  model: 'formula',
675
- source: _extends({}, this.getModelSource(filterOwner), {
773
+ source: _extends({}, source, {
774
+ spatialFiltersResolution,
775
+ spatialFiltersMode,
676
776
  spatialFilter
677
777
  }),
678
778
  params: {
@@ -696,7 +796,9 @@ class WidgetBaseSource {
696
796
  const {
697
797
  filterOwner,
698
798
  spatialFilter,
699
- abortController
799
+ spatialFiltersMode,
800
+ abortController,
801
+ viewState
700
802
  } = options,
701
803
  params = _objectWithoutPropertiesLoose(options, _excluded4);
702
804
  const {
@@ -704,9 +806,19 @@ class WidgetBaseSource {
704
806
  operation,
705
807
  ticks
706
808
  } = params;
809
+ const source = this.getModelSource(filterOwner);
810
+ let spatialFiltersResolution;
811
+ if (spatialFilter && source.spatialDataType !== 'geo') {
812
+ spatialFiltersResolution = getSpatialFiltersResolution({
813
+ source,
814
+ viewState
815
+ });
816
+ }
707
817
  const data = await executeModel({
708
818
  model: 'histogram',
709
- source: _extends({}, this.getModelSource(filterOwner), {
819
+ source: _extends({}, source, {
820
+ spatialFiltersResolution,
821
+ spatialFiltersMode,
710
822
  spatialFilter
711
823
  }),
712
824
  params: {
@@ -742,15 +854,27 @@ class WidgetBaseSource {
742
854
  const {
743
855
  filterOwner,
744
856
  spatialFilter,
745
- abortController
857
+ spatialFiltersMode,
858
+ abortController,
859
+ viewState
746
860
  } = options,
747
861
  params = _objectWithoutPropertiesLoose(options, _excluded5);
748
862
  const {
749
863
  column
750
864
  } = params;
865
+ const source = this.getModelSource(filterOwner);
866
+ let spatialFiltersResolution;
867
+ if (spatialFilter && source.spatialDataType !== 'geo') {
868
+ spatialFiltersResolution = getSpatialFiltersResolution({
869
+ source,
870
+ viewState
871
+ });
872
+ }
751
873
  return executeModel({
752
874
  model: 'range',
753
- source: _extends({}, this.getModelSource(filterOwner), {
875
+ source: _extends({}, source, {
876
+ spatialFiltersResolution,
877
+ spatialFiltersMode,
754
878
  spatialFilter
755
879
  }),
756
880
  params: {
@@ -772,7 +896,9 @@ class WidgetBaseSource {
772
896
  const {
773
897
  filterOwner,
774
898
  spatialFilter,
775
- abortController
899
+ spatialFiltersMode,
900
+ abortController,
901
+ viewState
776
902
  } = options,
777
903
  params = _objectWithoutPropertiesLoose(options, _excluded6);
778
904
  const {
@@ -781,11 +907,21 @@ class WidgetBaseSource {
781
907
  yAxisColumn,
782
908
  yAxisJoinOperation
783
909
  } = params;
910
+ const source = this.getModelSource(filterOwner);
911
+ let spatialFiltersResolution;
912
+ if (spatialFilter && source.spatialDataType !== 'geo') {
913
+ spatialFiltersResolution = getSpatialFiltersResolution({
914
+ source,
915
+ viewState
916
+ });
917
+ }
784
918
  // Make sure this is sync with the same constant in cloud-native/maps-api
785
919
  const HARD_LIMIT = 500;
786
920
  return executeModel({
787
921
  model: 'scatterplot',
788
- source: _extends({}, this.getModelSource(filterOwner), {
922
+ source: _extends({}, source, {
923
+ spatialFiltersResolution,
924
+ spatialFiltersMode,
789
925
  spatialFilter
790
926
  }),
791
927
  params: {
@@ -814,7 +950,9 @@ class WidgetBaseSource {
814
950
  const {
815
951
  filterOwner,
816
952
  spatialFilter,
817
- abortController
953
+ spatialFiltersMode,
954
+ abortController,
955
+ viewState
818
956
  } = options,
819
957
  params = _objectWithoutPropertiesLoose(options, _excluded7);
820
958
  const {
@@ -824,9 +962,19 @@ class WidgetBaseSource {
824
962
  offset = 0,
825
963
  limit = 10
826
964
  } = params;
965
+ const source = this.getModelSource(filterOwner);
966
+ let spatialFiltersResolution;
967
+ if (spatialFilter && source.spatialDataType !== 'geo') {
968
+ spatialFiltersResolution = getSpatialFiltersResolution({
969
+ source,
970
+ viewState
971
+ });
972
+ }
827
973
  return executeModel({
828
974
  model: 'table',
829
- source: _extends({}, this.getModelSource(filterOwner), {
975
+ source: _extends({}, source, {
976
+ spatialFiltersResolution,
977
+ spatialFiltersMode,
830
978
  spatialFilter
831
979
  }),
832
980
  params: {
@@ -859,7 +1007,9 @@ class WidgetBaseSource {
859
1007
  const {
860
1008
  filterOwner,
861
1009
  abortController,
862
- spatialFilter
1010
+ spatialFilter,
1011
+ spatialFiltersMode,
1012
+ viewState
863
1013
  } = options,
864
1014
  params = _objectWithoutPropertiesLoose(options, _excluded8);
865
1015
  const {
@@ -873,9 +1023,19 @@ class WidgetBaseSource {
873
1023
  splitByCategoryLimit,
874
1024
  splitByCategoryValues
875
1025
  } = params;
1026
+ const source = this.getModelSource(filterOwner);
1027
+ let spatialFiltersResolution;
1028
+ if (spatialFilter && source.spatialDataType !== 'geo') {
1029
+ spatialFiltersResolution = getSpatialFiltersResolution({
1030
+ source,
1031
+ viewState
1032
+ });
1033
+ }
876
1034
  return executeModel({
877
1035
  model: 'timeseries',
878
- source: _extends({}, this.getModelSource(filterOwner), {
1036
+ source: _extends({}, source, {
1037
+ spatialFiltersResolution,
1038
+ spatialFiltersMode,
879
1039
  spatialFilter
880
1040
  }),
881
1041
  params: {
@@ -906,8 +1066,7 @@ WidgetBaseSource.defaultProps = {
906
1066
  apiBaseUrl: DEFAULT_API_BASE_URL,
907
1067
  clientId: getClient(),
908
1068
  filters: {},
909
- filtersLogicalOperator: 'and',
910
- geoColumn: DEFAULT_GEO_COLUMN
1069
+ filtersLogicalOperator: 'and'
911
1070
  };
912
1071
 
913
1072
  /**
@@ -1336,7 +1495,11 @@ const h3QuerySource = async function h3QuerySource(options) {
1336
1495
  urlParameters.filters = filters;
1337
1496
  }
1338
1497
  return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
1339
- widgetSource: new WidgetQuerySource(options)
1498
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
1499
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
1500
+ spatialDataColumn,
1501
+ spatialDataType: 'h3'
1502
+ }))
1340
1503
  }));
1341
1504
  };
1342
1505
 
@@ -1361,7 +1524,11 @@ const h3TableSource = async function h3TableSource(options) {
1361
1524
  urlParameters.filters = filters;
1362
1525
  }
1363
1526
  return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
1364
- widgetSource: new WidgetTableSource(options)
1527
+ widgetSource: new WidgetTableSource(_extends({}, options, {
1528
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
1529
+ spatialDataColumn,
1530
+ spatialDataType: 'h3'
1531
+ }))
1365
1532
  }));
1366
1533
  };
1367
1534
 
@@ -1416,7 +1583,11 @@ const quadbinQuerySource = async function quadbinQuerySource(options) {
1416
1583
  urlParameters.filters = filters;
1417
1584
  }
1418
1585
  return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
1419
- widgetSource: new WidgetQuerySource(options)
1586
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
1587
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
1588
+ spatialDataColumn,
1589
+ spatialDataType: 'quadbin'
1590
+ }))
1420
1591
  }));
1421
1592
  };
1422
1593
 
@@ -1441,7 +1612,11 @@ const quadbinTableSource = async function quadbinTableSource(options) {
1441
1612
  urlParameters.filters = filters;
1442
1613
  }
1443
1614
  return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
1444
- widgetSource: new WidgetTableSource(options)
1615
+ widgetSource: new WidgetTableSource(_extends({}, options, {
1616
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
1617
+ spatialDataColumn,
1618
+ spatialDataType: 'quadbin'
1619
+ }))
1445
1620
  }));
1446
1621
  };
1447
1622
 
@@ -1481,7 +1656,9 @@ const vectorQuerySource = async function vectorQuerySource(options) {
1481
1656
  urlParameters.queryParameters = queryParameters;
1482
1657
  }
1483
1658
  return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
1484
- widgetSource: new WidgetQuerySource(options)
1659
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
1660
+ spatialDataType: 'geo'
1661
+ }))
1485
1662
  }));
1486
1663
  };
1487
1664
 
@@ -1506,7 +1683,9 @@ const vectorTableSource = async function vectorTableSource(options) {
1506
1683
  urlParameters.filters = filters;
1507
1684
  }
1508
1685
  return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
1509
- widgetSource: new WidgetTableSource(options)
1686
+ widgetSource: new WidgetTableSource(_extends({}, options, {
1687
+ spatialDataType: 'geo'
1688
+ }))
1510
1689
  }));
1511
1690
  };
1512
1691