@carto/api-client 0.4.3 → 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.
@@ -831,41 +831,43 @@ function executeModel(props) {
831
831
  data,
832
832
  filters,
833
833
  filtersLogicalOperator = 'and',
834
- geoColumn = DEFAULT_GEO_COLUMN
834
+ spatialDataType = 'geo',
835
+ spatialFiltersMode = 'intersects',
836
+ spatialFiltersResolution = 0
835
837
  } = source;
836
- const queryParameters = source.queryParameters ? JSON.stringify(source.queryParameters) : '';
837
838
  const queryParams = {
838
839
  type,
839
840
  client: clientId,
840
841
  source: data,
841
- params: JSON.stringify(params),
842
- queryParameters,
843
- filters: JSON.stringify(filters),
842
+ params,
843
+ queryParameters: source.queryParameters || '',
844
+ filters,
844
845
  filtersLogicalOperator
845
846
  };
847
+ const spatialDataColumn = source.spatialDataColumn || DEFAULT_GEO_COLUMN;
846
848
  // Picking Model API requires 'spatialDataColumn'.
847
849
  if (model === 'pick') {
848
- queryParams.spatialDataColumn = geoColumn;
850
+ queryParams.spatialDataColumn = spatialDataColumn;
849
851
  }
850
- // API supports multiple filters, we apply it only to geoColumn
852
+ // API supports multiple filters, we apply it only to spatialDataColumn
851
853
  const spatialFilters = source.spatialFilter ? {
852
- [geoColumn]: source.spatialFilter
854
+ [spatialDataColumn]: source.spatialFilter
853
855
  } : undefined;
854
856
  if (spatialFilters) {
855
- queryParams.spatialFilters = JSON.stringify(spatialFilters);
857
+ queryParams.spatialFilters = spatialFilters;
858
+ queryParams.spatialDataColumn = spatialDataColumn;
859
+ queryParams.spatialDataType = spatialDataType;
860
+ }
861
+ if (spatialDataType !== 'geo') {
862
+ if (spatialFiltersResolution > 0) {
863
+ queryParams.spatialFiltersResolution = spatialFiltersResolution;
864
+ }
865
+ queryParams.spatialFiltersMode = spatialFiltersMode;
856
866
  }
857
- const urlWithSearchParams = url + '?' + new URLSearchParams(queryParams).toString();
867
+ const urlWithSearchParams = url + '?' + objectToURLSearchParams(queryParams).toString();
858
868
  const isGet = urlWithSearchParams.length <= REQUEST_GET_MAX_URL_LENGTH;
859
869
  if (isGet) {
860
870
  url = urlWithSearchParams;
861
- } else {
862
- // undo the JSON.stringify, @TODO find a better pattern
863
- queryParams.params = params;
864
- queryParams.filters = filters;
865
- queryParams.queryParameters = source.queryParameters;
866
- if (spatialFilters) {
867
- queryParams.spatialFilters = spatialFilters;
868
- }
869
871
  }
870
872
  return makeCall({
871
873
  url,
@@ -877,15 +879,71 @@ function executeModel(props) {
877
879
  })
878
880
  });
879
881
  }
882
+ function objectToURLSearchParams(object) {
883
+ const params = new URLSearchParams();
884
+ for (const key in object) {
885
+ if (isPureObject(object[key])) {
886
+ params.append(key, JSON.stringify(object[key]));
887
+ } else if (Array.isArray(object[key])) {
888
+ params.append(key, JSON.stringify(object[key]));
889
+ } else if (object[key] === null) {
890
+ params.append(key, 'null');
891
+ } else if (object[key] !== undefined) {
892
+ params.append(key, String(object[key]));
893
+ }
894
+ }
895
+ return params;
896
+ }
880
897
 
881
- const _excluded = ["filterOwner", "spatialFilter", "abortController"],
882
- _excluded2 = ["filterOwner", "spatialFilter", "abortController"],
883
- _excluded3 = ["filterOwner", "spatialFilter", "abortController", "operationExp"],
884
- _excluded4 = ["filterOwner", "spatialFilter", "abortController"],
885
- _excluded5 = ["filterOwner", "spatialFilter", "abortController"],
886
- _excluded6 = ["filterOwner", "spatialFilter", "abortController"],
887
- _excluded7 = ["filterOwner", "spatialFilter", "abortController"],
888
- _excluded8 = ["filterOwner", "abortController", "spatialFilter"];
898
+ const DEFAULT_TILE_SIZE = 512;
899
+ const QUADBIN_ZOOM_MAX_OFFSET = 4;
900
+ function getSpatialFiltersResolution(source, viewState) {
901
+ var _source$dataResolutio, _source$aggregationRe;
902
+ const dataResolution = (_source$dataResolutio = source.dataResolution) != null ? _source$dataResolutio : Number.MAX_VALUE;
903
+ const aggregationResLevel = (_source$aggregationRe = source.aggregationResLevel) != null ? _source$aggregationRe : source.spatialDataType === 'h3' ? DEFAULT_AGGREGATION_RES_LEVEL_H3 : DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN;
904
+ const aggregationResLevelOffset = Math.max(0, Math.floor(aggregationResLevel));
905
+ const currentZoomInt = Math.ceil(viewState.zoom);
906
+ if (source.spatialDataType === 'h3') {
907
+ var _maxH3SpatialFiltersR, _maxH3SpatialFiltersR2;
908
+ const tileSize = DEFAULT_TILE_SIZE;
909
+ const maxResolutionForZoom = (_maxH3SpatialFiltersR = (_maxH3SpatialFiltersR2 = maxH3SpatialFiltersResolutions.find(([zoom]) => zoom === currentZoomInt)) == null ? void 0 : _maxH3SpatialFiltersR2[1]) != null ? _maxH3SpatialFiltersR : Math.max(0, currentZoomInt - 3);
910
+ const maxSpatialFiltersResolution = maxResolutionForZoom ? Math.min(dataResolution, maxResolutionForZoom) : dataResolution;
911
+ const hexagonResolution = getHexagonResolution(viewState, tileSize) + aggregationResLevelOffset;
912
+ return Math.min(hexagonResolution, maxSpatialFiltersResolution);
913
+ }
914
+ if (source.spatialDataType === 'quadbin') {
915
+ const maxResolutionForZoom = currentZoomInt + QUADBIN_ZOOM_MAX_OFFSET;
916
+ const maxSpatialFiltersResolution = Math.min(dataResolution, maxResolutionForZoom);
917
+ const quadsResolution = Math.floor(viewState.zoom) + aggregationResLevelOffset;
918
+ return Math.min(quadsResolution, maxSpatialFiltersResolution);
919
+ }
920
+ return undefined;
921
+ }
922
+ 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]];
923
+ // stolen from https://github.com/visgl/deck.gl/blob/master/modules/carto/src/layers/h3-tileset-2d.ts
924
+ // Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
925
+ const BIAS = 2;
926
+ // Resolution conversion function. Takes a WebMercatorViewport and returns
927
+ // a H3 resolution such that the screen space size of the hexagons is
928
+ // similar
929
+ function getHexagonResolution(viewport, tileSize) {
930
+ // Difference in given tile size compared to deck's internal 512px tile size,
931
+ // expressed as an offset to the viewport zoom.
932
+ const zoomOffset = Math.log2(tileSize / DEFAULT_TILE_SIZE);
933
+ const hexagonScaleFactor = 2 / 3 * (viewport.zoom - zoomOffset);
934
+ const latitudeScaleFactor = Math.log(1 / Math.cos(Math.PI * viewport.latitude / 180));
935
+ // Clip and bias
936
+ return Math.max(0, Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS));
937
+ }
938
+
939
+ const _excluded = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
940
+ _excluded2 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
941
+ _excluded3 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController", "operationExp"],
942
+ _excluded4 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
943
+ _excluded5 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
944
+ _excluded6 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
945
+ _excluded7 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
946
+ _excluded8 = ["filterOwner", "abortController", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState"];
889
947
  /**
890
948
  * Source for Widget API requests on a data source defined by a SQL query.
891
949
  *
@@ -906,9 +964,21 @@ class WidgetBaseSource {
906
964
  connectionName: props.connectionName,
907
965
  filters: getApplicableFilters(owner, props.filters),
908
966
  filtersLogicalOperator: props.filtersLogicalOperator,
909
- geoColumn: props.geoColumn
967
+ spatialDataType: props.spatialDataType,
968
+ spatialDataColumn: props.spatialDataColumn,
969
+ dataResolution: props.dataResolution
910
970
  };
911
971
  }
972
+ _getSpatialFiltersResolution(source, spatialFilter, referenceViewState) {
973
+ // spatialFiltersResolution applies only to spatial index sources.
974
+ if (!spatialFilter || source.spatialDataType === 'geo') {
975
+ return;
976
+ }
977
+ if (!referenceViewState) {
978
+ throw new Error('Missing required option, "spatialIndexReferenceViewState".');
979
+ }
980
+ return getSpatialFiltersResolution(source, referenceViewState);
981
+ }
912
982
  /****************************************************************************
913
983
  * CATEGORIES
914
984
  */
@@ -920,6 +990,8 @@ class WidgetBaseSource {
920
990
  const {
921
991
  filterOwner,
922
992
  spatialFilter,
993
+ spatialFiltersMode,
994
+ spatialIndexReferenceViewState,
923
995
  abortController
924
996
  } = options,
925
997
  params = _objectWithoutPropertiesLoose(options, _excluded);
@@ -928,9 +1000,13 @@ class WidgetBaseSource {
928
1000
  operation,
929
1001
  operationColumn
930
1002
  } = params;
1003
+ const source = this.getModelSource(filterOwner);
1004
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
931
1005
  return executeModel({
932
1006
  model: 'category',
933
- source: _extends({}, this.getModelSource(filterOwner), {
1007
+ source: _extends({}, source, {
1008
+ spatialFiltersResolution,
1009
+ spatialFiltersMode,
934
1010
  spatialFilter
935
1011
  }),
936
1012
  params: {
@@ -958,6 +1034,8 @@ class WidgetBaseSource {
958
1034
  const {
959
1035
  filterOwner,
960
1036
  spatialFilter,
1037
+ spatialFiltersMode,
1038
+ spatialIndexReferenceViewState,
961
1039
  abortController
962
1040
  } = options,
963
1041
  params = _objectWithoutPropertiesLoose(options, _excluded2);
@@ -969,9 +1047,13 @@ class WidgetBaseSource {
969
1047
  limit,
970
1048
  tileResolution
971
1049
  } = params;
1050
+ const source = this.getModelSource(filterOwner);
1051
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
972
1052
  return executeModel({
973
1053
  model: 'pick',
974
- source: _extends({}, this.getModelSource(filterOwner), {
1054
+ source: _extends({}, source, {
1055
+ spatialFiltersResolution,
1056
+ spatialFiltersMode,
975
1057
  spatialFilter
976
1058
  }),
977
1059
  params: {
@@ -1003,6 +1085,8 @@ class WidgetBaseSource {
1003
1085
  const {
1004
1086
  filterOwner,
1005
1087
  spatialFilter,
1088
+ spatialFiltersMode,
1089
+ spatialIndexReferenceViewState,
1006
1090
  abortController,
1007
1091
  operationExp
1008
1092
  } = options,
@@ -1011,9 +1095,13 @@ class WidgetBaseSource {
1011
1095
  column,
1012
1096
  operation
1013
1097
  } = params;
1098
+ const source = this.getModelSource(filterOwner);
1099
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1014
1100
  return executeModel({
1015
1101
  model: 'formula',
1016
- source: _extends({}, this.getModelSource(filterOwner), {
1102
+ source: _extends({}, source, {
1103
+ spatialFiltersResolution,
1104
+ spatialFiltersMode,
1017
1105
  spatialFilter
1018
1106
  }),
1019
1107
  params: {
@@ -1037,6 +1125,8 @@ class WidgetBaseSource {
1037
1125
  const {
1038
1126
  filterOwner,
1039
1127
  spatialFilter,
1128
+ spatialFiltersMode,
1129
+ spatialIndexReferenceViewState,
1040
1130
  abortController
1041
1131
  } = options,
1042
1132
  params = _objectWithoutPropertiesLoose(options, _excluded4);
@@ -1045,9 +1135,13 @@ class WidgetBaseSource {
1045
1135
  operation,
1046
1136
  ticks
1047
1137
  } = params;
1138
+ const source = this.getModelSource(filterOwner);
1139
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1048
1140
  const data = await executeModel({
1049
1141
  model: 'histogram',
1050
- source: _extends({}, this.getModelSource(filterOwner), {
1142
+ source: _extends({}, source, {
1143
+ spatialFiltersResolution,
1144
+ spatialFiltersMode,
1051
1145
  spatialFilter
1052
1146
  }),
1053
1147
  params: {
@@ -1083,15 +1177,21 @@ class WidgetBaseSource {
1083
1177
  const {
1084
1178
  filterOwner,
1085
1179
  spatialFilter,
1180
+ spatialFiltersMode,
1181
+ spatialIndexReferenceViewState,
1086
1182
  abortController
1087
1183
  } = options,
1088
1184
  params = _objectWithoutPropertiesLoose(options, _excluded5);
1089
1185
  const {
1090
1186
  column
1091
1187
  } = params;
1188
+ const source = this.getModelSource(filterOwner);
1189
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1092
1190
  return executeModel({
1093
1191
  model: 'range',
1094
- source: _extends({}, this.getModelSource(filterOwner), {
1192
+ source: _extends({}, source, {
1193
+ spatialFiltersResolution,
1194
+ spatialFiltersMode,
1095
1195
  spatialFilter
1096
1196
  }),
1097
1197
  params: {
@@ -1113,6 +1213,8 @@ class WidgetBaseSource {
1113
1213
  const {
1114
1214
  filterOwner,
1115
1215
  spatialFilter,
1216
+ spatialFiltersMode,
1217
+ spatialIndexReferenceViewState,
1116
1218
  abortController
1117
1219
  } = options,
1118
1220
  params = _objectWithoutPropertiesLoose(options, _excluded6);
@@ -1122,11 +1224,15 @@ class WidgetBaseSource {
1122
1224
  yAxisColumn,
1123
1225
  yAxisJoinOperation
1124
1226
  } = params;
1227
+ const source = this.getModelSource(filterOwner);
1228
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1125
1229
  // Make sure this is sync with the same constant in cloud-native/maps-api
1126
1230
  const HARD_LIMIT = 500;
1127
1231
  return executeModel({
1128
1232
  model: 'scatterplot',
1129
- source: _extends({}, this.getModelSource(filterOwner), {
1233
+ source: _extends({}, source, {
1234
+ spatialFiltersResolution,
1235
+ spatialFiltersMode,
1130
1236
  spatialFilter
1131
1237
  }),
1132
1238
  params: {
@@ -1155,6 +1261,8 @@ class WidgetBaseSource {
1155
1261
  const {
1156
1262
  filterOwner,
1157
1263
  spatialFilter,
1264
+ spatialFiltersMode,
1265
+ spatialIndexReferenceViewState,
1158
1266
  abortController
1159
1267
  } = options,
1160
1268
  params = _objectWithoutPropertiesLoose(options, _excluded7);
@@ -1165,9 +1273,13 @@ class WidgetBaseSource {
1165
1273
  offset = 0,
1166
1274
  limit = 10
1167
1275
  } = params;
1276
+ const source = this.getModelSource(filterOwner);
1277
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1168
1278
  return executeModel({
1169
1279
  model: 'table',
1170
- source: _extends({}, this.getModelSource(filterOwner), {
1280
+ source: _extends({}, source, {
1281
+ spatialFiltersResolution,
1282
+ spatialFiltersMode,
1171
1283
  spatialFilter
1172
1284
  }),
1173
1285
  params: {
@@ -1200,7 +1312,9 @@ class WidgetBaseSource {
1200
1312
  const {
1201
1313
  filterOwner,
1202
1314
  abortController,
1203
- spatialFilter
1315
+ spatialFilter,
1316
+ spatialFiltersMode,
1317
+ spatialIndexReferenceViewState
1204
1318
  } = options,
1205
1319
  params = _objectWithoutPropertiesLoose(options, _excluded8);
1206
1320
  const {
@@ -1214,9 +1328,13 @@ class WidgetBaseSource {
1214
1328
  splitByCategoryLimit,
1215
1329
  splitByCategoryValues
1216
1330
  } = params;
1331
+ const source = this.getModelSource(filterOwner);
1332
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1217
1333
  return executeModel({
1218
1334
  model: 'timeseries',
1219
- source: _extends({}, this.getModelSource(filterOwner), {
1335
+ source: _extends({}, source, {
1336
+ spatialFiltersResolution,
1337
+ spatialFiltersMode,
1220
1338
  spatialFilter
1221
1339
  }),
1222
1340
  params: {
@@ -1247,8 +1365,7 @@ WidgetBaseSource.defaultProps = {
1247
1365
  apiBaseUrl: DEFAULT_API_BASE_URL,
1248
1366
  clientId: getClient(),
1249
1367
  filters: {},
1250
- filtersLogicalOperator: 'and',
1251
- geoColumn: DEFAULT_GEO_COLUMN
1368
+ filtersLogicalOperator: 'and'
1252
1369
  };
1253
1370
 
1254
1371
  /**
@@ -1339,7 +1456,11 @@ const h3QuerySource = async function h3QuerySource(options) {
1339
1456
  urlParameters.filters = filters;
1340
1457
  }
1341
1458
  return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
1342
- widgetSource: new WidgetQuerySource(options)
1459
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
1460
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
1461
+ spatialDataColumn,
1462
+ spatialDataType: 'h3'
1463
+ }))
1343
1464
  }));
1344
1465
  };
1345
1466
 
@@ -1364,7 +1485,11 @@ const h3TableSource = async function h3TableSource(options) {
1364
1485
  urlParameters.filters = filters;
1365
1486
  }
1366
1487
  return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
1367
- widgetSource: new WidgetTableSource(options)
1488
+ widgetSource: new WidgetTableSource(_extends({}, options, {
1489
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
1490
+ spatialDataColumn,
1491
+ spatialDataType: 'h3'
1492
+ }))
1368
1493
  }));
1369
1494
  };
1370
1495
 
@@ -1419,7 +1544,11 @@ const quadbinQuerySource = async function quadbinQuerySource(options) {
1419
1544
  urlParameters.filters = filters;
1420
1545
  }
1421
1546
  return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
1422
- widgetSource: new WidgetQuerySource(options)
1547
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
1548
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
1549
+ spatialDataColumn,
1550
+ spatialDataType: 'quadbin'
1551
+ }))
1423
1552
  }));
1424
1553
  };
1425
1554
 
@@ -1444,7 +1573,11 @@ const quadbinTableSource = async function quadbinTableSource(options) {
1444
1573
  urlParameters.filters = filters;
1445
1574
  }
1446
1575
  return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
1447
- widgetSource: new WidgetTableSource(options)
1576
+ widgetSource: new WidgetTableSource(_extends({}, options, {
1577
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
1578
+ spatialDataColumn,
1579
+ spatialDataType: 'quadbin'
1580
+ }))
1448
1581
  }));
1449
1582
  };
1450
1583
 
@@ -1488,7 +1621,9 @@ const vectorQuerySource = async function vectorQuerySource(options) {
1488
1621
  urlParameters.aggregationExp = aggregationExp;
1489
1622
  }
1490
1623
  return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
1491
- widgetSource: new WidgetQuerySource(options)
1624
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
1625
+ spatialDataType: 'geo'
1626
+ }))
1492
1627
  }));
1493
1628
  };
1494
1629
 
@@ -1517,7 +1652,9 @@ const vectorTableSource = async function vectorTableSource(options) {
1517
1652
  urlParameters.aggregationExp = aggregationExp;
1518
1653
  }
1519
1654
  return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
1520
- widgetSource: new WidgetTableSource(options)
1655
+ widgetSource: new WidgetTableSource(_extends({}, options, {
1656
+ spatialDataType: 'geo'
1657
+ }))
1521
1658
  }));
1522
1659
  };
1523
1660