diff --git a/modules/carto/src/api/endpoints.ts b/modules/carto/src/api/endpoints.ts index e967155b226..49f51c6e6d5 100644 --- a/modules/carto/src/api/endpoints.ts +++ b/modules/carto/src/api/endpoints.ts @@ -2,37 +2,68 @@ import {MapType} from './types'; export type V3Endpoint = 'maps' | 'stats' | 'sql'; -function buildUrlFromBase(apiBaseUrl: string, endpoint: V3Endpoint) { - let suffix = `/v3/${endpoint}`; - if (apiBaseUrl.endsWith('/')) { - suffix = suffix.substring(1); - } - - return `${apiBaseUrl}${suffix}`; +function joinPath(...args: string[]): string { + return args.map(part => (part.endsWith('/') ? part.slice(0, -1) : part)).join('/'); } -export function buildMapsUrlFromBase(apiBaseUrl: string): string { - return buildUrlFromBase(apiBaseUrl, 'maps'); +function buildV3Path( + apiBaseUrl: string, + version: 'v3', + endpoint: V3Endpoint, + ...rest: string[] +): string { + return joinPath(apiBaseUrl, version, endpoint, ...rest); } -export function buildStatsUrlFromBase(apiBaseUrl: string): string { - return buildUrlFromBase(apiBaseUrl, 'stats'); +export function buildPublicMapUrl({ + apiBaseUrl, + cartoMapId +}: { + apiBaseUrl: string; + cartoMapId: string; +}): string { + return buildV3Path(apiBaseUrl, 'v3', 'maps', 'public', cartoMapId); } -export function buildQueryUrlFromBase(apiBaseUrl: string): string { - return buildUrlFromBase(apiBaseUrl, 'sql'); +export function buildStatsUrl({ + attribute, + apiBaseUrl, + connectionName, + source, + type +}: { + attribute: string; + apiBaseUrl: string; + connectionName: string; + source: string; + type: MapType; +}): string { + if (type === 'query') { + return buildV3Path(apiBaseUrl, 'v3', 'stats', connectionName, attribute); + } + + // type === 'table' + return buildV3Path(apiBaseUrl, 'v3', 'stats', connectionName, source, attribute); } export function buildSourceUrl({ apiBaseUrl, connectionName, - endpoint, - mapsUrl + endpoint }: { apiBaseUrl: string; connectionName: string; endpoint: MapType; - mapsUrl?: string; }): string { - return `${mapsUrl || buildMapsUrlFromBase(apiBaseUrl)}/${connectionName}/${endpoint}`; + return buildV3Path(apiBaseUrl, 'v3', 'maps', connectionName, endpoint); +} + +export function buildQueryUrl({ + apiBaseUrl, + connectionName +}: { + apiBaseUrl: string; + connectionName: string; +}): string { + return buildV3Path(apiBaseUrl, 'v3', 'sql', connectionName, 'query'); } diff --git a/modules/carto/src/api/fetch-map.ts b/modules/carto/src/api/fetch-map.ts index 6c3a685a8d8..929eeae983f 100644 --- a/modules/carto/src/api/fetch-map.ts +++ b/modules/carto/src/api/fetch-map.ts @@ -4,7 +4,7 @@ */ import {CartoAPIError} from './carto-api-error'; import {DEFAULT_API_BASE_URL, DEFAULT_CLIENT} from './common'; -import {buildMapsUrlFromBase, buildStatsUrlFromBase} from './endpoints'; +import {buildPublicMapUrl, buildStatsUrl} from './endpoints'; import { GeojsonResult, JsonResult, @@ -108,26 +108,23 @@ async function _fetchMapDataset( } async function _fetchTilestats( - attribute, + attribute: string, dataset: Dataset, accessToken: string, apiBaseUrl: string ) { - const {connectionName: connection, data, id, source, type, queryParameters} = dataset; - const errorContext: APIErrorContext = {requestType: 'Tile stats', connection, type, source}; + const {connectionName, data, id, source, type, queryParameters} = dataset; + const errorContext: APIErrorContext = { + requestType: 'Tile stats', + connection: connectionName, + type, + source + }; if (!('tilestats' in data)) { throw new CartoAPIError(new Error(`Invalid dataset for tilestats: ${id}`), errorContext); } - const statsUrl = buildStatsUrlFromBase(apiBaseUrl); - let baseUrl = `${statsUrl}/${connection}/`; - if (type === 'query') { - baseUrl += attribute; - } else { - // MAP_TYPE.TABLE - baseUrl += `${source}/${attribute}`; - } - + const baseUrl = buildStatsUrl({attribute, apiBaseUrl, ...dataset}); const headers = {Authorization: `Bearer ${accessToken}`}; const parameters: Record = {}; if (type === 'query') { @@ -166,7 +163,7 @@ async function fillInTileStats( {datasets, keplerMapConfig, token}: {datasets: Dataset[]; keplerMapConfig: any; token: string}, apiBaseUrl: string ) { - const attributes: {attribute?: string; dataset?: any}[] = []; + const attributes: {attribute: string; dataset: any}[] = []; const {layers} = keplerMapConfig.config.visState; for (const layer of layers) { for (const channel of Object.keys(layer.visualChannels)) { @@ -181,7 +178,7 @@ async function fillInTileStats( } } // Remove duplicates to avoid repeated requests - const filteredAttributes: {attribute?: string; dataset?: any}[] = []; + const filteredAttributes: {attribute: string; dataset: any}[] = []; for (const a of attributes) { if ( !filteredAttributes.find( @@ -203,7 +200,6 @@ export type FetchMapOptions = { cartoMapId: string; clientId?: string; headers?: Record; - mapsUrl?: string; autoRefresh?: number; onNewData?: (map: any) => void; }; @@ -214,7 +210,6 @@ export async function fetchMap({ cartoMapId, clientId = DEFAULT_CLIENT, headers = {}, - mapsUrl, autoRefresh, onNewData }: FetchMapOptions) { @@ -230,7 +225,7 @@ export async function fetchMap({ ); } - const baseUrl = `${mapsUrl || buildMapsUrlFromBase(apiBaseUrl)}/public/${cartoMapId}`; + const baseUrl = buildPublicMapUrl({apiBaseUrl, cartoMapId}); const errorContext: APIErrorContext = {requestType: 'Public map', mapId: cartoMapId}; const map = await requestWithParameters({baseUrl, headers, errorContext}); diff --git a/modules/carto/src/api/query.ts b/modules/carto/src/api/query.ts index 9bc3e7c7b32..4aa7eb580db 100644 --- a/modules/carto/src/api/query.ts +++ b/modules/carto/src/api/query.ts @@ -1,6 +1,6 @@ import {SOURCE_DEFAULTS} from '../sources'; import type {SourceOptions, QuerySourceOptions, QueryResult} from '../sources/types'; -import {buildQueryUrlFromBase} from './endpoints'; +import {buildQueryUrl} from './endpoints'; import {requestWithParameters} from './request-with-parameters'; import {APIErrorContext} from './types'; @@ -8,15 +8,19 @@ export type QueryOptions = SourceOptions & Omit { - const {apiBaseUrl, connectionName, sqlQuery, queryParameters} = options; + const { + apiBaseUrl = SOURCE_DEFAULTS.apiBaseUrl, + connectionName, + sqlQuery, + queryParameters + } = options; const urlParameters: UrlParameters = {q: sqlQuery}; if (queryParameters) { urlParameters.queryParameters = JSON.stringify(queryParameters); } - const queryUrl = buildQueryUrlFromBase(apiBaseUrl || SOURCE_DEFAULTS.apiBaseUrl); - const baseUrl = `${queryUrl}/${connectionName}/query`; + const baseUrl = buildQueryUrl({apiBaseUrl, connectionName}); const headers = {Authorization: `Bearer ${options.accessToken}`, ...options.headers}; const errorContext: APIErrorContext = { diff --git a/modules/carto/src/sources/types.ts b/modules/carto/src/sources/types.ts index e1bb270aa55..0cad3f1ffb2 100644 --- a/modules/carto/src/sources/types.ts +++ b/modules/carto/src/sources/types.ts @@ -13,7 +13,6 @@ export type SourceOptionalOptions = { /** @deprecated use `query` instead **/ format: Format; headers: Record; - mapsUrl?: string; }; export type SourceOptions = SourceRequiredOptions & Partial; diff --git a/test/apps/carto-dynamic-tile/app.tsx b/test/apps/carto-dynamic-tile/app.tsx index 8ed5057db17..02226889d21 100644 --- a/test/apps/carto-dynamic-tile/app.tsx +++ b/test/apps/carto-dynamic-tile/app.tsx @@ -71,15 +71,22 @@ function Root() { } function useBoundaryLayer(datasource) { - const {getFillColor, source, boundaryId, columns, matchingColumn, sqlQuery, tableName} = - datasource; + const { + getFillColor, + source, + tilesetTableName, + columns, + matchingColumn, + propertiesSqlQuery, + propertiesTableName + } = datasource; const tilejson = source({ ...globalOptions, - boundaryId, + tilesetTableName, columns, matchingColumn, - tableName, - sqlQuery + propertiesTableName, + propertiesSqlQuery }); return new VectorTileLayer({ diff --git a/test/apps/carto-dynamic-tile/datasets.ts b/test/apps/carto-dynamic-tile/datasets.ts index b53ab267585..cdbeb4e2d6c 100644 --- a/test/apps/carto-dynamic-tile/datasets.ts +++ b/test/apps/carto-dynamic-tile/datasets.ts @@ -1,7 +1,6 @@ import { boundaryQuerySource, boundaryTableSource, - boundaryTilesetSource, h3TilesetSource, h3TableSource, h3QuerySource, @@ -18,9 +17,9 @@ import { export default { 'boundary-query': { source: boundaryQuerySource, - boundaryId: 'usa_pos4', + tilesetTableName: 'carto-boundaries.us.usa_zip_code_v1', matchingColumn: 'geoid', - sqlQuery: + propertiesSqlQuery: 'select * from `cartodb-on-gcp-backend-team.juanra.geography_usa_zcta5_2019_clustered`', getFillColor: colorBins({ // TODO remove parseFloat, only needed as binary format encodes as strings @@ -31,25 +30,16 @@ export default { }, 'boundary-table': { source: boundaryTableSource, - boundaryId: 'usa_pos4', + tilesetTableName: 'carto-boundaries.us.usa_zip_code_v1', matchingColumn: 'geoid', columns: ['do_label', 'do_perimeter'], - tableName: 'cartodb-on-gcp-backend-team.juanra.geography_usa_zcta5_2019_clustered', + propertiesTableName: 'cartodb-on-gcp-backend-team.juanra.geography_usa_zcta5_2019_clustered', getFillColor: colorBins({ attr: d => parseFloat(d!.properties!['do_perimeter']), domain: [0, 1, 5, 10, 25, 50, 100].map(n => 10000 * n), colors: 'Purp' }) }, - 'boundary-tileset': { - source: boundaryTilesetSource, - boundaryId: 'usa_pos4', - getFillColor: colorBins({ - attr: d => parseFloat(d!.properties!['do_perimeter']), - domain: [0, 1, 5, 10, 25, 50, 100].map(n => 10000 * n), - colors: 'Burg' - }) - }, 'h3-query': { source: h3QuerySource, sqlQuery: