Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use two promises in computing result from useClickedNode #3715

Merged
merged 10 commits into from
Sep 22, 2023
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
Loading