import { Elements } from 'react-flow-renderer' ; import { PlanNode , ExplainJson , Thresholds } from '../types' ; import { planNodeWidth , planNodeHeight } from '../style-variables' ; import createLayout , { SizedNode , Graph } from './planLayout' ; export type TypedElements = Elements < { plan : PlanNode ; } > ; export type SizedPlanNode = PlanNode & SizedNode ; export interface Totals { time : number ; } /**
 * Convert dagree layout to react-flow elements
 */ const dagreToFlow = ( graphElements , totals , thresholds , nodeType , edgeType ) : TypedElements => { const nodes = graphElements . nodes . map ( ( node ) => ( { id : node . id , data : { plan : node . nodeData , totals , thresholds } , position : { x : node . x , y : node . y } , type : nodeType , } ) ) ; const edges = graphElements . edges . map ( ( edge ) => ( { id : `${ edge . nodes . from }-${ edge . nodes . to }` , source : edge . nodes . from , target : edge . nodes . to , type : edgeType , animated : true , } ) ) ; return nodes . concat ( edges ) ; } ; const traverse = ( root , idGenerator , cb ) => { const node = { ... root , id : idGenerator ( ) , width : parseInt ( planNodeWidth , 10 ) , height : parseInt ( planNodeHeight , 10 ) , } ; node . children = root . Plans ?. map ( ( child ) => traverse ( child , idGenerator , cb ) ) ; cb ( node ) ; return node ; } ; /**
 * Flatten node tree and inject id and card sizes into each node
 */ const getSizedNodes = ( root ) => { /**
     * Build id from timestamp of this calculation and sequence that starts at 0
     * id is later used for memoizing renders of PlanCards so they must always be unique
     * to different results, but consistent across renders of the same results
     * Declared here so ids always start at 0 for every traversal
     */ const idGen = ( ( ) => { let counter = - 1 ; const runId = Date . now ( ) . toString ( ) ; return ( ) => { counter += 1 ; return `${ runId }_${ counter }` ; } ; } ) ( ) ; const nodes = [ ] ; traverse ( root , idGen , ( node ) => nodes . push ( node ) ) ; return nodes ; } ; /**
 * Builds an array of React-Flow elements from a tree of PlanNodes
 * Uses planNodeWidth and planNodeHeight values from style-variables for the calculation
 * of each node's size in the graph in the layout
 */ const buildFlowGraph = ( explain , thresholds , nodeComponent , edgeType ) : TypedElements => { const sizedNodes = getSizedNodes ( explain . Plan ) ; const totals = { time : explain [ 'Execution Time' ] } ; const layout = createLayout < PlanNode > ( sizedNodes ) ; return dagreToFlow ( layout , totals , thresholds , nodeComponent , edgeType ) ; } ; export default buildFlowGraph ;