@here/olp-sdk-dataservice-read 3.0.0 → 3.1.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.
@@ -1,5 +1,6 @@
1
1
  import { HRN, OlpClientSettings } from "@here/olp-sdk-core";
2
2
  import { MetadataApi, QueryApi } from "@here/olp-sdk-dataservice-api";
3
+ import { TileResponse } from "../utils/getTile";
3
4
  import { DataRequest } from "./DataRequest";
4
5
  import { PartitionsRequest } from "./PartitionsRequest";
5
6
  import { QuadKeyPartitionsRequest } from "./QuadKeyPartitionsRequest";
@@ -55,6 +56,46 @@ export declare class VersionedLayerClient {
55
56
  * @return Tile data (if it exists) or the nearest parent tile data
56
57
  */
57
58
  getAggregatedData(request: TileRequest, abortSignal?: AbortSignal): Promise<Response>;
59
+ /**
60
+ * @brief Fetches data of a tile or its closest ancestor.
61
+ * Use this API for tile-tree structures where children tile data is aggregated and stored in parent tiles.
62
+ *
63
+ * @param request The `TileRequest` instance that contains a complete set
64
+ * of request parameters.
65
+ * @param abortSignal A signal object that allows you to communicate with a request (such as the `fetch` request)
66
+ * and, if required, abort it using the `AbortController` object.
67
+ * @param options An optional object that can include the `includeTileKey` flag to indicate whether the parent tile key should be included in the response.
68
+ *
69
+ * For more information, see the [`AbortController` documentation](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
70
+ *
71
+ * @return Tile data (if it exists) or the nearest parent tile data including the parent tile key
72
+ */
73
+ getAggregatedData(request: TileRequest, abortSignal: AbortSignal | undefined, options: {
74
+ includeTileKey: true;
75
+ }): Promise<TileResponse>;
76
+ /**
77
+ * @brief Fetches data of a tile or its closest ancestor.
78
+ *
79
+ * Same as the two-argument `getAggregatedData`, for callers that pass an
80
+ * options object with `includeTileKey` disabled or omitted.
81
+ *
82
+ * @return Tile data (if it exists) or the nearest parent tile data
83
+ */
84
+ getAggregatedData(request: TileRequest, abortSignal: AbortSignal | undefined, options: {
85
+ includeTileKey?: false;
86
+ }): Promise<Response>;
87
+ /**
88
+ * @brief Fetches data of a tile or its closest ancestor.
89
+ *
90
+ * Same as the two-argument `getAggregatedData`, for an `includeTileKey`
91
+ * flag whose value is only known at run time. Narrow the result before
92
+ * using it.
93
+ *
94
+ * @return A `TileResponse` if the flag was `true`, otherwise the tile data
95
+ */
96
+ getAggregatedData(request: TileRequest, abortSignal: AbortSignal | undefined, options: {
97
+ includeTileKey?: boolean;
98
+ }): Promise<Response | TileResponse>;
58
99
  /**
59
100
  * Fetches partition data using one of the following methods: ID, quadkey, or data handle.
60
101
  *
@@ -59,20 +59,7 @@ class VersionedLayerClient {
59
59
  this.version = params.version;
60
60
  }
61
61
  }
62
- /**
63
- * @brief Fetches data of a tile or its closest ancestor.
64
- * Use this API for tile-tree structures where children tile data is aggregated and stored in parent tiles.
65
- *
66
- * @param request The `TileRequest` instance that contains a complete set
67
- * of request parameters.
68
- * @param abortSignal A signal object that allows you to communicate with a request (such as the `fetch` request)
69
- * and, if required, abort it using the `AbortController` object.
70
- *
71
- * For more information, see the [`AbortController` documentation](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
72
- *
73
- * @return Tile data (if it exists) or the nearest parent tile data
74
- */
75
- async getAggregatedData(request, abortSignal) {
62
+ async getAggregatedData(request, abortSignal, options) {
76
63
  let catalogVersion = this.version;
77
64
  if (catalogVersion === undefined) {
78
65
  catalogVersion = await this.getLatestVersion(request.getBillingTag());
@@ -84,7 +71,10 @@ class VersionedLayerClient {
84
71
  settings: this.settings,
85
72
  catalogVersion
86
73
  };
87
- return (0, getTile_1.getTile)(request, params, abortSignal);
74
+ const tileResponse = await (0, getTile_1.getTile)(request, params, abortSignal, {
75
+ includeTileKey: true
76
+ });
77
+ return options?.includeTileKey ? tileResponse : tileResponse.response;
88
78
  }
89
79
  /**
90
80
  * Fetches partition data using one of the following methods: ID, quadkey, or data handle.
@@ -11,6 +11,10 @@ export interface GetTileParams {
11
11
  layerId: string;
12
12
  layerType: "versioned" | "volatile";
13
13
  }
14
+ export interface TileResponse {
15
+ response: Response;
16
+ parentTileKey: TileKey | undefined;
17
+ }
14
18
  /**
15
19
  * Fetches asynchronously data from a tile or from its nearest ancestor if not found.
16
20
  *
@@ -46,6 +50,37 @@ export interface GetTileParams {
46
50
  * @returns The blob of the requested tile or the blob of the closest parent Tile.
47
51
  */
48
52
  export declare function getTile(request: TileRequest, params: TileRequestParams, abortSignal?: AbortSignal): Promise<Response>;
53
+ /**
54
+ * Same as the three-argument [[getTile]], but also resolves the tile key of
55
+ * the parent whose data was actually returned.
56
+ *
57
+ * @param options Pass `{ includeTileKey: true }` to receive a [[TileResponse]]
58
+ * instead of a plain `Response`.
59
+ *
60
+ * @returns The blob of the requested tile or the blob of the closest parent
61
+ * tile, together with that tile's key.
62
+ */
63
+ export declare function getTile(request: TileRequest, params: TileRequestParams, abortSignal: AbortSignal | undefined, options: {
64
+ includeTileKey: true;
65
+ }): Promise<TileResponse>;
66
+ /**
67
+ * Same as the three-argument [[getTile]], for callers that pass an options
68
+ * object with `includeTileKey` disabled or omitted.
69
+ *
70
+ * @returns The blob of the requested tile or the blob of the closest parent Tile.
71
+ */
72
+ export declare function getTile(request: TileRequest, params: TileRequestParams, abortSignal: AbortSignal | undefined, options: {
73
+ includeTileKey?: false;
74
+ }): Promise<Response>;
75
+ /**
76
+ * Same as the three-argument [[getTile]], for an `includeTileKey` flag whose
77
+ * value is only known at run time. Narrow the result before using it.
78
+ *
79
+ * @returns A [[TileResponse]] if the flag was `true`, otherwise the plain blob.
80
+ */
81
+ export declare function getTile(request: TileRequest, params: TileRequestParams, abortSignal: AbortSignal | undefined, options: {
82
+ includeTileKey?: boolean;
83
+ }): Promise<Response | TileResponse>;
49
84
  /**
50
85
  * The function should request quad tree index for the parent tile with delta 4
51
86
  * and cache the responses in cache for later calls.
@@ -25,41 +25,14 @@ const olp_sdk_dataservice_api_1 = require("@here/olp-sdk-dataservice-api");
25
25
  const QuadTreeIndexCacheRepository_1 = require("../cache/QuadTreeIndexCacheRepository");
26
26
  const QuadTreeIndexRequest_1 = require("../client/QuadTreeIndexRequest");
27
27
  const QueryClient_1 = require("../client/QueryClient");
28
+ async function getTile(request, params, abortSignal, options) {
29
+ const tileResponse = await fetchTile(request, params, abortSignal);
30
+ return options?.includeTileKey ? tileResponse : tileResponse.response;
31
+ }
28
32
  /**
29
- * Fetches asynchronously data from a tile or from its nearest ancestor if not found.
30
- *
31
- * The tile is a geometric area represented as a HERE tile.
32
- * The quad tree metadata fetches the blob of needed tile from the HERE Query Service,
33
- * then caches it, and returns to the user.
34
- * To disable caching of metadata use `request.withFetchOption(FetchOptions.OnlineOnly)`.
35
- *
36
- * @param request Requests the [[TileRequest]] instance with the configured parameters.
37
- * @see [[TileRequest]]
38
- *
39
- * @param abortSignal The signal object that allows you to communicate with a request (such as the `fetch` request)
40
- * and, if required, abort it using the `AbortController` object.
41
- * @see the [`AbortController` documentation](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
42
- *
43
- * @example
44
- *
45
- * ```
46
- * const params: GetTileParams = {
47
- * settings: "% your `OlpClientSettings` instance % ",
48
- * catalogHrn: "% the HRN instance of your catalog %",
49
- * layerId: "% your layer ID %",
50
- * layerType: "% versioned or volatile %",
51
- * }
52
- *
53
- * const request = new TileRequest();
54
- *
55
- * const tile1 = await getTile(request.withTileKey(yourTileKey1), params);
56
- * const tile2 = await getTile(request.withTileKey(yourTileKey2), params);
57
- *
58
- * ```
59
- *
60
- * @returns The blob of the requested tile or the blob of the closest parent Tile.
33
+ * @hidden
61
34
  */
62
- async function getTile(request, params, abortSignal) {
35
+ async function fetchTile(request, params, abortSignal) {
63
36
  let catalogVersion;
64
37
  const quadKey = request.getTileKey();
65
38
  if (!quadKey) {
@@ -70,65 +43,86 @@ async function getTile(request, params, abortSignal) {
70
43
  }
71
44
  const blobType = params.layerType === "versioned" ? "blob" : "volatile-blob";
72
45
  const blobRequestBuilder = await olp_sdk_core_1.RequestFactory.create(blobType, "v1", params.settings, params.catalogHrn, abortSignal);
73
- const delta = 4;
46
+ const depth = 4;
74
47
  const requestedTileKey = olp_sdk_core_1.TileKey.fromRowColumnLevel(quadKey.row, quadKey.column, quadKey.level);
75
- let quadTreeIndex = null;
48
+ const quadTreeIndexRoot = requestedTileKey.changedLevelBy(-depth);
49
+ let quadTreeIndex;
76
50
  if (request.getFetchOption() !== olp_sdk_core_1.FetchOptions.OnlineOnly) {
77
51
  const cache = new QuadTreeIndexCacheRepository_1.QuadTreeIndexCacheRepository(params.settings.cache);
78
- for (let i = 1; i <= delta; i++) {
79
- const parentInCache = requestedTileKey.changedLevelBy(-i);
80
- const cachedTree = cache.get({
81
- hrn: params.catalogHrn.toString(),
82
- layerId: params.layerId,
83
- depth: delta,
84
- root: parentInCache,
85
- version: catalogVersion
86
- });
87
- if (cachedTree) {
88
- quadTreeIndex = cachedTree;
89
- }
90
- }
52
+ quadTreeIndex = cache.get({
53
+ hrn: params.catalogHrn.toString(),
54
+ layerId: params.layerId,
55
+ depth,
56
+ root: quadTreeIndexRoot,
57
+ version: catalogVersion
58
+ });
91
59
  }
92
- const parentTileKey = requestedTileKey.changedLevelBy(-delta);
93
60
  if (!quadTreeIndex) {
94
61
  quadTreeIndex = await fetchQuadTreeIndex({
95
62
  ...params,
96
63
  catalogVersion,
97
- depth: delta,
64
+ depth,
98
65
  fetchOptions: request.getFetchOption(),
99
- tileKey: parentTileKey,
66
+ tileKey: quadTreeIndexRoot,
100
67
  abortSignal,
101
68
  billingTag: request.getBillingTag()
102
69
  });
103
70
  }
104
- if (!quadTreeIndex.subQuads || !quadTreeIndex.subQuads.length) {
105
- return Promise.resolve(new Response(null, {
106
- status: 204,
107
- statusText: "No Content"
108
- }));
71
+ const subQuads = quadTreeIndex.subQuads ?? [];
72
+ const parentQuads = quadTreeIndex.parentQuads ?? [];
73
+ if (!subQuads.length && !parentQuads.length) {
74
+ return Promise.resolve({
75
+ response: new Response(null, {
76
+ status: 204,
77
+ statusText: "No Content"
78
+ }),
79
+ parentTileKey: undefined
80
+ });
109
81
  }
110
- // Return the data for the requested QuadKey or for the closest parent
111
- const subQuads = quadTreeIndex.subQuads;
112
- let currentTileKey = requestedTileKey;
113
- let currentDelta = delta;
114
- for (let level = currentTileKey.level; level >= parentTileKey.level; --level) {
115
- const metadata = subQuads.find((item) => item.subQuadKey === currentTileKey.getSubHereTile(currentDelta));
116
- if (metadata) {
117
- return olp_sdk_dataservice_api_1.BlobApi.getBlob(blobRequestBuilder, {
118
- dataHandle: metadata.dataHandle,
119
- layerId: params.layerId,
120
- billingTag: request.getBillingTag()
121
- });
122
- }
123
- try {
124
- currentTileKey = currentTileKey.parent();
125
- currentDelta = parentTileKey.level - currentTileKey.level;
82
+ const closestParent = findClosestParent(requestedTileKey, quadTreeIndex, quadTreeIndexRoot);
83
+ if (!closestParent) {
84
+ return Promise.reject(new Error(`Error getting blob for Tile: ${requestedTileKey.toHereTile()}`));
85
+ }
86
+ return {
87
+ response: await olp_sdk_dataservice_api_1.BlobApi.getBlob(blobRequestBuilder, {
88
+ dataHandle: closestParent.parentQuad.dataHandle,
89
+ layerId: params.layerId,
90
+ billingTag: request.getBillingTag()
91
+ }),
92
+ parentTileKey: closestParent.tileKey
93
+ };
94
+ }
95
+ /**
96
+ * Helper function to get the closest parent quad for a given tile key.
97
+ * @hidden
98
+ */
99
+ function findClosestParent(tileKey, quadTreeIndex, quadTreeIndexRoot) {
100
+ const subQuads = quadTreeIndex.subQuads ?? [];
101
+ const parentQuads = quadTreeIndex.parentQuads ?? [];
102
+ // First, iterate through the sub quad trees, starting from lowest level up to the quad tree index root
103
+ let currentTileKey = tileKey;
104
+ while (currentTileKey.level >= quadTreeIndexRoot.level) {
105
+ const currentDelta = currentTileKey.level - quadTreeIndexRoot.level;
106
+ const subHereTile = currentTileKey.getSubHereTile(currentDelta);
107
+ const subQuad = subQuads.find((item) => item.subQuadKey === subHereTile);
108
+ if (subQuad) {
109
+ return { parentQuad: subQuad, tileKey: currentTileKey };
126
110
  }
127
- catch (error) {
128
- continue;
111
+ // Stop before requesting the parent of the quad tree index root -
112
+ // that root can be the global root tile (level 0), whose parent()
113
+ // throws rather than returning another tile.
114
+ if (currentTileKey.level === quadTreeIndexRoot.level) {
115
+ break;
129
116
  }
117
+ currentTileKey = currentTileKey.parent();
130
118
  }
131
- return Promise.reject(new Error(`Error getting blob for Tile: ${JSON.stringify(quadKey)}`));
119
+ // not found? Find the closest parent quad
120
+ return parentQuads.reduce((closest, parentQuad) => {
121
+ const tileKey = olp_sdk_core_1.TileKey.fromHereTile(parentQuad.partition);
122
+ return !closest || tileKey.level > closest.tileKey.level
123
+ ? { parentQuad, tileKey }
124
+ : closest;
125
+ }, undefined);
132
126
  }
133
127
  /**
134
128
  * The function should request quad tree index for the parent tile with delta 4
@@ -146,7 +140,8 @@ async function fetchQuadTreeIndex(params) {
146
140
  }
147
141
  const quadTreeIndex = await queryClient.fetchQuadTreeIndex(quadTreeIndexRequest, params.abortSignal);
148
142
  if (params.fetchOptions !== olp_sdk_core_1.FetchOptions.OnlineOnly &&
149
- quadTreeIndex.subQuads) {
143
+ (quadTreeIndex.subQuads !== undefined ||
144
+ quadTreeIndex.parentQuads !== undefined)) {
150
145
  cache.put({
151
146
  hrn: params.catalogHrn.toString(),
152
147
  layerId: params.layerId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@here/olp-sdk-dataservice-read",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Wrapper around a subset of the HERE Open Location Platform Data REST API related to reading data from OLP catalogs",
5
5
  "main": "index.js",
6
6
  "browser": "index.web.js",