Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/CartoDB/carto-api-client in…
Browse files Browse the repository at this point in the history
…to feature/sc-454268/spatial-index-widgets
  • Loading branch information
juandjara committed Dec 12, 2024
2 parents 26b8948 + 7b73fe4 commit 898740a
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 14 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
# CHANGELOG

## Not released

## 0.4

### 0.4.1

- add cache control mechanism for sources and query APIs

### 0.4.0

- feat: Add Picking Model API
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"repository": "github:CartoDB/carto-api-client",
"author": "Don McCurdy <[email protected]>",
"packageManager": "[email protected]",
"version": "0.4.1-alpha.0",
"version": "0.4.1",
"license": "MIT",
"publishConfig": {
"access": "public",
Expand Down
2 changes: 2 additions & 0 deletions src/api/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const query = async function (
apiBaseUrl = SOURCE_DEFAULTS.apiBaseUrl,
clientId = SOURCE_DEFAULTS.clientId,
maxLengthURL = SOURCE_DEFAULTS.maxLengthURL,
localCache,
connectionName,
sqlQuery,
queryParameters,
Expand Down Expand Up @@ -51,5 +52,6 @@ export const query = async function (
headers,
errorContext,
maxLengthURL,
localCache,
});
};
38 changes: 34 additions & 4 deletions src/api/request-with-parameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,29 @@ import {CartoAPIError, APIErrorContext} from './carto-api-error';
import {V3_MINOR_VERSION} from '../constants-internal';
import {DEFAULT_MAX_LENGTH_URL} from '../constants-internal';
import {getClient} from '../client';
import {LocalCacheOptions} from '../sources/types';

const DEFAULT_HEADERS = {
Accept: 'application/json',
'Content-Type': 'application/json',
};

const REQUEST_CACHE = new Map<string, Promise<unknown>>();
const DEFAULT_REQUEST_CACHE = new Map<string, Promise<unknown>>();

export async function requestWithParameters<T = any>({
baseUrl,
parameters = {},
headers: customHeaders = {},
errorContext,
maxLengthURL = DEFAULT_MAX_LENGTH_URL,
localCache,
}: {
baseUrl: string;
parameters?: Record<string, unknown>;
headers?: Record<string, string>;
errorContext: APIErrorContext;
maxLengthURL?: number;
localCache?: LocalCacheOptions;
}): Promise<T> {
// Parameters added to all requests issued with `requestWithParameters()`.
// These parameters override parameters already in the base URL, but not
Expand All @@ -41,7 +44,14 @@ export async function requestWithParameters<T = any>({

baseUrl = excludeURLParameters(baseUrl, Object.keys(parameters));
const key = createCacheKey(baseUrl, parameters, customHeaders);
if (REQUEST_CACHE.has(key)) {

const {
cache: REQUEST_CACHE,
canReadCache,
canStoreInCache,
} = getCacheSettings(localCache);

if (canReadCache && REQUEST_CACHE.has(key)) {
return REQUEST_CACHE.get(key) as Promise<T>;
}

Expand Down Expand Up @@ -73,14 +83,34 @@ export async function requestWithParameters<T = any>({
return json;
})
.catch((error: Error) => {
REQUEST_CACHE.delete(key);
if (canStoreInCache) {
REQUEST_CACHE.delete(key);
}
throw new CartoAPIError(error, errorContext, response, responseJson);
});

REQUEST_CACHE.set(key, jsonPromise);
if (canStoreInCache) {
REQUEST_CACHE.set(key, jsonPromise);
}
return jsonPromise;
}

function getCacheSettings(localCache: LocalCacheOptions | undefined) {
const canReadCache = localCache?.cacheControl?.includes('no-cache')
? false
: true;
const canStoreInCache = localCache?.cacheControl?.includes('no-store')
? false
: true;
const cache = localCache?.cache || DEFAULT_REQUEST_CACHE;

return {
cache,
canReadCache,
canStoreInCache,
};
}

function createCacheKey(
baseUrl: string,
parameters: Record<string, unknown>,
Expand Down
5 changes: 4 additions & 1 deletion src/sources/base-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export async function baseSource<UrlParameters extends Record<string, unknown>>(
}
}
const baseUrl = buildSourceUrl(mergedOptions);
const {clientId, maxLengthURL, format} = mergedOptions;
const {clientId, maxLengthURL, format, localCache} = mergedOptions;
const headers = {
Authorization: `Bearer ${options.accessToken}`,
...options.headers,
Expand All @@ -65,6 +65,7 @@ export async function baseSource<UrlParameters extends Record<string, unknown>>(
headers,
errorContext,
maxLengthURL,
localCache,
});

const dataUrl = mapInstantiation[format].url[0];
Expand All @@ -82,6 +83,7 @@ export async function baseSource<UrlParameters extends Record<string, unknown>>(
headers,
errorContext,
maxLengthURL,
localCache,
});
if (accessToken) {
json.accessToken = accessToken;
Expand All @@ -94,5 +96,6 @@ export async function baseSource<UrlParameters extends Record<string, unknown>>(
headers,
errorContext,
maxLengthURL,
localCache,
});
}
5 changes: 5 additions & 0 deletions src/sources/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

export {SOURCE_DEFAULTS} from './base-source';
export type {
VectorLayer,
RasterMetadataBandStats,
RasterBandColorinterp,
RasterMetadataBand,
RasterMetadata,
TilejsonResult,
GeojsonResult,
JsonResult,
Expand Down
170 changes: 165 additions & 5 deletions src/sources/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,27 @@ export type SourceOptionalOptions = {
* - 4: 4096x4096
*/
tileResolution?: TileResolution;

/**
* By default, local in-memory caching is enabled.
*/
localCache?: LocalCacheOptions;
};

export type LocalCacheOptions = {
/**
* Map that stores requests and their responses.
*/
cache?: Map<string, Promise<unknown>>;

/**
* Cache control
* * `no-cache`: If present, the source will always fetch from original source.
* * `no-store`: If present, source will not store result in cache (for later reuse).
*
* See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#directives
*/
cacheControl?: ('no-cache' | 'no-store')[];
};

export type SourceOptions = SourceRequiredOptions &
Expand Down Expand Up @@ -187,16 +208,51 @@ export interface Tilejson {
attribution: string;
scheme: string;
tiles: string[];
properties_tiles: string[];
minresolution: number;
maxresolution: number;
minzoom: number;
maxzoom: number;
bounds: [number, number, number, number];
center: [number, number, number];
bounds: [left: number, bottom: number, right: number, top: number];
center: [longitute: number, latitude: number, zoom: number];
vector_layers: VectorLayer[];

//
// Carto additions over standard Tilejson properties
//

minresolution: number;
maxresolution: number;
properties_tiles: string[];
tilestats: Tilestats;
tileResolution?: TileResolution;

/**
* Resolution of data in spatial-index dataset (e.g. H3, Quadbin).
*
* @internal
*/
dataresolution?: number;

/**
* Array of ratios of dropped features per zoom level.
*
* Example: `[0,0,0.5]` - means that 50% of features are dropped at zoom 2 and bigger.
*
* @internal
*/
fraction_dropped_per_zoom?: number[];

/**
* Names of bands - rasters only.
*
* @internal
*/
raster_bands?: string[];

/**
* Raster metadata - rasters only.
*
* @internal
*/
raster_metadata?: RasterMetadata;
}

export interface Tilestats {
Expand All @@ -217,12 +273,116 @@ export interface Attribute {
}

export interface VectorLayer {
// tilejson standard
id: string;
minzoom: number;
maxzoom: number;
fields: Record<string, string>;

// Carto additions over standard Tilejson properties
geometry_type?: string;
}

export type RasterMetadataBandStats = {
approximated_stats?: boolean;
min: number;
max: number;
mean: number;
stddev: number;
sum: number;
sum_squares: number;
count: number;

/**
* Quantiles by number of buckets.
*
* Example:
* ```ts
* {
* // for 3 buckets, first 1/3 of items lies in range [min, 20], second 1/3 is in [20, 40], and last 1/3 is in [40, max]
* 3: [20, 40],
* 4: [20, 30, 50], for 4 buckets ...
* }
* ```
*/
quantiles?: Record<number, number[]>;

/**
* Top values by number of values.
*
* Key of dictionary is value, value is count.
* Key order is random.
*
* Example:
* ```
* {
* 3: 5, // means there are 5 pixels with value 3
* 11: 222,
* 12: 333, // means that 12 is most common value with count 333
* ... // (assuming 333 was largest value in dict)
* }
* ```
*/
top_values?: Record<number, number>;

/**
* Raster loader version.
*/
version?: string;
};

export enum RasterBandColorinterp {
Gray = 'gray',
Red = 'red',
Green = 'green',
Blue = 'blue',
Alpha = 'alpha',
Palette = 'palette',
}

export type RasterMetadataBand = {
type: string;
name: string;
stats: RasterMetadataBandStats;
/**
* Known values:
* * `palette`: use unique value and `colortable` ad default mapping
* * `red`, `green`, `blue`: use the band as color channel
* * `gray`: use the band as grayscale
*/
colorinterp?: string | RasterBandColorinterp; // use RasterBandColorinterp, but it's external value, so let's use string

/**
* Default color mapping for unique values (or if coloprinterp is `palette`)
*/
colortable?: Record<string, number[]>;

/**
* No value representation.
* Observed values:
* * `'nan'` for `NaN`
* * `number`: both as string as number, so parsing is needed
*/
nodata: string | number; // 255, '0', 'nan'
};

export type RasterMetadata = {
block_resolution: number;
minresolution: number;
maxresolution: number;
nodata: number | string;
bands: RasterMetadataBand[];
bounds: [left: number, bottom: number, right: number, top: number];
center: [longitute: number, latitude: number, zoom: number];
width: number;
height: number;
block_width: number;
block_height: number;
num_blocks: number;
num_pixels: number;
pixel_resolution: number;
};

export type TilejsonResult = Tilejson & {accessToken: string};
export type GeojsonResult = {type: 'FeatureCollection'; features: Feature[]};
export type JsonResult = any[];
Expand Down
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7202,11 +7202,11 @@ __metadata:
linkType: hard

"nanoid@npm:^3.3.7":
version: 3.3.7
resolution: "nanoid@npm:3.3.7"
version: 3.3.8
resolution: "nanoid@npm:3.3.8"
bin:
nanoid: bin/nanoid.cjs
checksum: 10c0/e3fb661aa083454f40500473bb69eedb85dc160e763150b9a2c567c7e9ff560ce028a9f833123b618a6ea742e311138b591910e795614a629029e86e180660f3
checksum: 10c0/4b1bb29f6cfebf3be3bc4ad1f1296fb0a10a3043a79f34fbffe75d1621b4318319211cd420549459018ea3592f0d2f159247a6f874911d6d26eaaadda2478120
languageName: node
linkType: hard

Expand Down

0 comments on commit 898740a

Please sign in to comment.