Skip to content

Commit

Permalink
feat: use two promises in computing result from useClickedNode (#3715)
Browse files Browse the repository at this point in the history
* feat: return two promises from useClickedNode

---------

Co-authored-by: Savelii Novikov <45129444+Savokr@users.noreply.github.com>
  • Loading branch information
haakonflatval-cognite and Savokr authored Sep 22, 2023
1 parent 539068a commit 6c497d6
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import {
type ModelNodeIdKey,
type ModelRevisionToEdgeMap,
type ModelRevisionId,
type FdmKey
type FdmKey,
type FdmNodeDataPromises
} from './types';
import {
createFdmKey,
Expand Down Expand Up @@ -103,7 +104,7 @@ export class FdmNodeCache {
);

const mappings = createMapWithAccumulatedValues(
relevantCachedEdgeData.map((data) => [data.edge.startNode.externalId, data.node])
relevantCachedEdgeData.map((data) => [data.edge.startNode.externalId, data.cadNode])
);

return {
Expand Down Expand Up @@ -149,7 +150,7 @@ export class FdmNodeCache {
const relevantEdges = intersectWithStartNodeIdSet(edges, relevantFdmKeySet);

const externalIdToNodeMap = createMapWithAccumulatedValues(
relevantEdges.map((edge) => [edge.edge.startNode.externalId, edge.node])
relevantEdges.map((edge) => [edge.edge.startNode.externalId, edge.cadNode])
);

return {
Expand Down Expand Up @@ -217,7 +218,7 @@ export class FdmNodeCache {
const revisionCache = this.getOrCreateRevisionCache(modelId, revisionId);

data.forEach((edgeAndNode) => {
revisionCache.insertTreeIndexMappings(edgeAndNode.node.treeIndex, edgeAndNode);
revisionCache.insertTreeIndexMappings(edgeAndNode.cadNode.treeIndex, edgeAndNode);
});

this._completeRevisions.add(revisionKey);
Expand Down Expand Up @@ -246,14 +247,14 @@ export class FdmNodeCache {
return revisionToEdgesMap;
}

public async getClosestParentExternalId(
public getClosestParentDataPromises(
modelId: number,
revisionId: number,
treeIndex: number
): Promise<Array<Required<FdmEdgeWithNode>>> {
): FdmNodeDataPromises {
const revisionCache = this.getOrCreateRevisionCache(modelId, revisionId);

return await revisionCache.getClosestParentFdmData(treeIndex);
return revisionCache.getClosestParentFdmData(treeIndex);
}

private async getViewsForEdges(
Expand Down Expand Up @@ -361,7 +362,7 @@ function createFdmEdgeWithNode(
const node = modelNodeIdToNodeMap.get(revisionNodeIdKey);
assert(node !== undefined);

return { edge, node, view };
return { edge, cadNode: node, view };
}

function insertEdgeIntoMapList(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { type ReactElement, type ReactNode, createContext, useContext, useMemo }
import { FdmNodeCache } from './FdmNodeCache';
import { type UseQueryResult, useQuery } from '@tanstack/react-query';
import { useFdmSdk, useSDK } from '../RevealContainer/SDKProvider';
import { type FdmEdgeWithNode, type ModelRevisionToEdgeMap } from './types';
import { type FdmNodeDataPromises, type ModelRevisionToEdgeMap } from './types';

import assert from 'assert';
import { type DmsUniqueIdentifier } from '../../utilities/FdmSDK';
Expand Down Expand Up @@ -50,11 +50,11 @@ export const useMappedEdgesForRevisions = (
);
};

export const useFdm3dNodeData = (
export const useFdm3dNodeDataPromises = (
modelId: number | undefined,
revisionId: number | undefined,
treeIndex: number | undefined
): UseQueryResult<Array<Required<FdmEdgeWithNode>>> => {
): UseQueryResult<FdmNodeDataPromises> => {
const content = useFdmNodeCache();

const enableQuery =
Expand All @@ -67,7 +67,7 @@ export const useFdm3dNodeData = (
['reveal', 'react-components', 'tree-index-to-external-id', modelId, revisionId, treeIndex],
async () => {
assert(enableQuery);
return await content.cache.getClosestParentExternalId(modelId, revisionId, treeIndex);
return content.cache.getClosestParentDataPromises(modelId, revisionId, treeIndex);
},
{
enabled: enableQuery
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,15 @@
*/

import { type CogniteClient, type Node3D } from '@cognite/sdk';
import { type FdmSDK } from '../../utilities/FdmSDK';
import { type TreeIndex, type FdmEdgeWithNode, type FdmCadEdge } from './types';
import { type Source, type FdmSDK } from '../../utilities/FdmSDK';
import {
type TreeIndex,
type FdmEdgeWithNode,
type FdmCadEdge,
type FdmNodeDataPromises,
type CadNodeWithEdges,
type AncestorQueryResult
} from './types';

import {
fetchAncestorNodesForTreeIndex,
Expand Down Expand Up @@ -38,38 +45,105 @@ export class RevisionFdmNodeCache {
this._revisionId = revisionId;
}

public async getClosestParentFdmData(
searchTreeIndex: number
): Promise<Array<Required<FdmEdgeWithNode>>> {
public getClosestParentFdmData(searchTreeIndex: number): FdmNodeDataPromises {
const cachedFdmData = this._treeIndexToFdmEdges.get(searchTreeIndex);

if (checkDefinedView(cachedFdmData)) {
return cachedFdmData;
if (cachedFdmData === undefined) {
return this.findAndCacheNodeDataFromAncestors(searchTreeIndex);
}

if (cachedFdmData !== undefined) {
return await this.getDataWithViewsForFdmEdges(cachedFdmData, []);
if (cachedFdmData.length === 0) {
return {
cadAndFdmNodesPromise: Promise.resolve(undefined),
viewsPromise: Promise.resolve(undefined)
};
}

return await this.findNodeDataFromAncestors(searchTreeIndex);
const cadAndFdmNodesPromise = Promise.resolve({
cadNode: cachedFdmData[0].cadNode,
fdmIds: cachedFdmData.map((data) => data.edge.startNode)
});

const viewsPromise = this.assertOrFetchViewsForNodeData(searchTreeIndex, cachedFdmData);

return { cadAndFdmNodesPromise, viewsPromise };
}

private async findNodeDataFromAncestors(
treeIndex: TreeIndex
): Promise<Array<Required<FdmEdgeWithNode>>> {
const { edges, ancestorsWithSameMapping, firstMappedAncestorTreeIndex } =
await this.getClosestParentMapping(treeIndex);
private async assertOrFetchViewsForNodeData(
searchTreeIndex: number,
cachedFdmData: FdmEdgeWithNode[]
): Promise<Source[] | undefined> {
if (checkDefinedView(cachedFdmData)) {
return cachedFdmData.map((data) => data.view);
}

if (edges.length === 0) {
return [];
const cadNode = cachedFdmData[0].cadNode;
const cadNodeWithEdges = {
cadNode,
edges: cachedFdmData.map((data) => data.edge)
};

return await this.getAndCacheViewsPromiseForNodeData(cadNodeWithEdges, [
cadNode.treeIndex,
searchTreeIndex
]);
}

private findAndCacheNodeDataFromAncestors(treeIndex: TreeIndex): FdmNodeDataPromises {
const ancestorDataPromise = this.getClosestParentMapping(treeIndex);

const cadAndEdgesPromise = this.getCadAndEdgesPromiseForAncestorData(ancestorDataPromise);
const cadAndFdmNodesPromise = cadAndEdgesPromise.then((cadAndEdges) =>
cadAndEdges === undefined
? undefined
: { cadNode: cadAndEdges.cadNode, fdmIds: cadAndEdges.edges.map((edge) => edge.startNode) }
);

const viewsPromise = this.getViewsPromiseFromDataPromises(
cadAndEdgesPromise,
ancestorDataPromise
);

return { cadAndFdmNodesPromise, viewsPromise };
}

private async getViewsPromiseFromDataPromises(
cadAndEdgesPromise: Promise<CadNodeWithEdges | undefined>,
ancestorDataPromise: Promise<AncestorQueryResult>
): Promise<Source[] | undefined> {
const cadAndEdges = await cadAndEdgesPromise;
const { ancestorsWithSameMapping } = await ancestorDataPromise;
const ancestorTreeIndexes = ancestorsWithSameMapping.map((ancestor) => ancestor.treeIndex);

const cachedTreeIndexesDescending = ancestorTreeIndexes
.filter((treeIndex) => this._treeIndexToFdmEdges.has(treeIndex))
.sort((a, b) => b - a);

const cachedNodeData =
cachedTreeIndexesDescending.length !== 0
? this._treeIndexToFdmEdges.get(cachedTreeIndexesDescending[0])
: undefined;

if (checkDefinedView(cachedNodeData)) {
this.setCacheDataForTreeIndices(ancestorTreeIndexes, cachedNodeData);
return cachedNodeData.map((data) => data.view);
}

const cachedFdmData = this._treeIndexToFdmEdges.get(firstMappedAncestorTreeIndex);
return await this.getAndCacheViewsPromiseForNodeData(cadAndEdges, ancestorTreeIndexes);
}

if (checkDefinedView(cachedFdmData)) {
this.setSameCacheForNodes(ancestorsWithSameMapping, cachedFdmData);
private async getCadAndEdgesPromiseForAncestorData(
ancestorDataPromise: Promise<AncestorQueryResult>
): Promise<CadNodeWithEdges | undefined> {
const { edges, ancestorsWithSameMapping, firstMappedAncestorTreeIndex } =
await ancestorDataPromise;

return cachedFdmData;
if (edges.length === 0) {
this.setCacheDataForTreeIndices(
ancestorsWithSameMapping.map((a) => a.treeIndex),
[]
);
return undefined;
}

const firstMappedAncestor = ancestorsWithSameMapping.find(
Expand All @@ -78,43 +152,50 @@ export class RevisionFdmNodeCache {

assert(firstMappedAncestor !== undefined);

const nodeEdges = edges.map((edge) => ({ edge, node: firstMappedAncestor }));

return await this.getDataWithViewsForFdmEdges(nodeEdges, ancestorsWithSameMapping);
return { cadNode: firstMappedAncestor, edges };
}

private setSameCacheForNodes(nodes: Node3D[], nodeData: FdmEdgeWithNode[]): void {
nodes.forEach((node) => {
this._treeIndexToFdmEdges.set(node.treeIndex, nodeData);
private setCacheDataForTreeIndices(treeIndices: number[], nodeData: FdmEdgeWithNode[]): void {
treeIndices.forEach((treeIndex) => {
this._treeIndexToFdmEdges.set(treeIndex, nodeData);
});
}

private async getDataWithViewsForFdmEdges(
nodeEdges: Array<{ edge: FdmCadEdge; node: Node3D }>,
ancestorsWithSameMapping: Node3D[]
): Promise<Array<Required<FdmEdgeWithNode>>> {
private async getAndCacheViewsPromiseForNodeData(
cadAndFdmIds: CadNodeWithEdges | undefined,
ancestorIndicesWithSameMapping: TreeIndex[]
): Promise<Source[] | undefined> {
if (cadAndFdmIds === undefined) {
ancestorIndicesWithSameMapping.forEach((treeIndex) => {
this._treeIndexToFdmEdges.set(treeIndex, []);
});

return undefined;
}

const nodeInspectionResults = await inspectNodes(
this._fdmClient,
nodeEdges.map((edge) => edge.edge.startNode)
cadAndFdmIds.edges.map((edge) => edge.startNode)
);

const views = nodeInspectionResults.items.map(
(item) => item.inspectionResults.involvedViewsAndContainers.views[0]
);

const dataWithViews = nodeEdges.map((fdmEdgeWithNode, ind) => ({
...fdmEdgeWithNode,
const dataWithViews = cadAndFdmIds.edges.map((edge, ind) => ({
edge,
cadNode: cadAndFdmIds.cadNode,
view: nodeInspectionResults.items[ind].inspectionResults.involvedViewsAndContainers.views[0]
}));

ancestorsWithSameMapping.forEach((ancestor) => {
this._treeIndexToFdmEdges.set(ancestor.treeIndex, dataWithViews);
ancestorIndicesWithSameMapping.forEach((treeIndex) => {
this._treeIndexToFdmEdges.set(treeIndex, dataWithViews);
});

return dataWithViews;
return views;
}

private async getClosestParentMapping(treeIndex: number): Promise<{
edges: FdmCadEdge[];
ancestorsWithSameMapping: Node3D[];
firstMappedAncestorTreeIndex: number;
}> {
private async getClosestParentMapping(treeIndex: number): Promise<AncestorQueryResult> {
const ancestors: Node3D[] = await fetchAncestorNodesForTreeIndex(
this._modelId,
this._revisionId,
Expand Down Expand Up @@ -200,7 +281,7 @@ export class RevisionFdmNodeCache {
view: nodeInspectionResults.items[ind].inspectionResults.involvedViewsAndContainers.views[0]
};

this.insertTreeIndexMappings(edgeWithView.node.treeIndex, edgeWithView);
this.insertTreeIndexMappings(edgeWithView.cadNode.treeIndex, edgeWithView);
});
}

Expand All @@ -210,7 +291,7 @@ export class RevisionFdmNodeCache {
if (edgeArray === undefined) {
this._treeIndexToFdmEdges.set(treeIndex, [edge]);
} else {
const presentEdge = edgeArray?.find((e) => e.node.id === edge.node.id);
const presentEdge = edgeArray?.find((e) => e.cadNode.id === edge.cadNode.id);

if (presentEdge !== undefined) {
presentEdge.view = edge.view;
Expand Down Expand Up @@ -238,11 +319,7 @@ function getAncestorDataForTreeIndex(
treeIndex: TreeIndex,
edgesWithTreeIndex: Array<{ edge: FdmCadEdge; treeIndex: TreeIndex }>,
ancestors: Node3D[]
): {
edges: FdmCadEdge[];
ancestorsWithSameMapping: Node3D[];
firstMappedAncestorTreeIndex: number;
} {
): AncestorQueryResult {
const edgesForTreeIndex = edgesWithTreeIndex.filter(
(edgeAndTreeIndex) => edgeAndTreeIndex.treeIndex === treeIndex
);
Expand Down
15 changes: 14 additions & 1 deletion react-components/src/components/NodeCacheProvider/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,20 @@ import { type EdgeItem, type DmsUniqueIdentifier, type Source } from '../../util
import { type InModel3dEdgeProperties } from '../../utilities/globalDataModels';

export type FdmCadEdge = EdgeItem<InModel3dEdgeProperties>;
export type FdmEdgeWithNode = { edge: FdmCadEdge; node: Node3D; view?: Source };
export type FdmEdgeWithNode = { edge: FdmCadEdge; cadNode: Node3D; view?: Source };

export type CadNodeWithFdmIds = { cadNode: Node3D; fdmIds: DmsUniqueIdentifier[] };
export type CadNodeWithEdges = { cadNode: Node3D; edges: FdmCadEdge[] };
export type FdmNodeDataPromises = {
cadAndFdmNodesPromise: Promise<CadNodeWithFdmIds | undefined>;
viewsPromise: Promise<Source[] | undefined>;
};

export type AncestorQueryResult = {
edges: FdmCadEdge[];
ancestorsWithSameMapping: Node3D[];
firstMappedAncestorTreeIndex: number;
};

export type ModelId = number;
export type RevisionId = number;
Expand Down
2 changes: 1 addition & 1 deletion react-components/src/hooks/useCalculateModelsStyling.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ function getMappedStyleGroup(
mapped: NodeAppearance
): TreeIndexStylingGroup {
const treeIndices = edges.flatMap((edge) => {
const treeIndices = getNodeSubtreeIndices(edge.node);
const treeIndices = getNodeSubtreeIndices(edge.cadNode);
return treeIndices;
});
return { treeIndices, style: mapped };
Expand Down
Loading

0 comments on commit 6c497d6

Please sign in to comment.