From bb862c31988eeb053a892707bc00dffe23ff38e9 Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Thu, 30 Jul 2026 07:56:19 +0200 Subject: [PATCH] chore(parser): set "Async Capable" property when parsing text Since PG14, the property "Async Capable" is automatically set when using format JSON. With the current commit, we now also set it when parsing a plan in TEXT format. The "Async Capable" is then used for the node type shown in the UI. Fixes #902 --- src/enums.ts | 1 + src/interfaces.ts | 10 ++++ src/node.ts | 1 + src/services/__tests__/from-text/01-expect | 1 + src/services/__tests__/from-text/35-expect | 54 ++++++++++++++-------- src/services/help-service.ts | 1 + 6 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/enums.ts b/src/enums.ts index 7d2c16ce..789eaf28 100644 --- a/src/enums.ts +++ b/src/enums.ts @@ -57,6 +57,7 @@ export enum Property { ACTUAL_STARTUP_TIME = "Actual Startup Time", ACTUAL_TOTAL_TIME = "Actual Total Time", ALIAS = "Alias", + ASYNC_CAPABLE = "Async Capable", AVERAGE_IO_READ_SPEED = "*I/O Read Speed", AVERAGE_IO_WRITE_SPEED = "*I/O Write Speed", AVERAGE_LOCAL_IO_READ_SPEED = "*Local I/O Read Speed", diff --git a/src/interfaces.ts b/src/interfaces.ts index ea288593..9435eda3 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -85,6 +85,7 @@ export class Node { [Property.ACTUAL_ROWS_REVISED]!: number; [Property.ACTUAL_STARTUP_TIME]?: number; [Property.ACTUAL_TOTAL_TIME]?: number; + [Property.ASYNC_CAPABLE]: boolean = false; [Property.EXCLUSIVE_COST]!: number; [Property.EXCLUSIVE_DURATION]!: number; [Property.EXCLUSIVE_LOCAL_DIRTIED_BLOCKS]!: number; @@ -266,6 +267,15 @@ export class Node { this[Property.PARALLEL_AWARE] = true } + enum AsyncMatch { + NodeType = 2, + } + const asyncRegex = /^(Async\s+)(.*)/.exec(this[Property.NODE_TYPE]) + if (asyncRegex) { + this[Property.NODE_TYPE] = asyncRegex[AsyncMatch.NodeType] + this[Property.ASYNC_CAPABLE] = true + } + enum JoinMatch { NodeType = 1, } diff --git a/src/node.ts b/src/node.ts index 3d44c9a8..a53072b6 100644 --- a/src/node.ts +++ b/src/node.ts @@ -83,6 +83,7 @@ export default function useNode(node: Node, viewOptions: ViewOptions) { const nodeName = computed((): string => { let nodeName = isParallelAware.value ? "Parallel " : "" + nodeName += node[Property.ASYNC_CAPABLE] ? "Async " : "" nodeName += node[Property.PARTIAL_MODE] ? node[Property.PARTIAL_MODE] + " " : "" diff --git a/src/services/__tests__/from-text/01-expect b/src/services/__tests__/from-text/01-expect index a7798db5..a1fe9c3f 100644 --- a/src/services/__tests__/from-text/01-expect +++ b/src/services/__tests__/from-text/01-expect @@ -1,6 +1,7 @@ { "Plan": { "Node Type": "Seq Scan", + "Async Capable": false, "Parallel Aware": false, "Relation Name": "tenk1", "Startup Cost": 0, diff --git a/src/services/__tests__/from-text/35-expect b/src/services/__tests__/from-text/35-expect index c4b9d39f..65122a5e 100644 --- a/src/services/__tests__/from-text/35-expect +++ b/src/services/__tests__/from-text/35-expect @@ -14,7 +14,8 @@ "Actual Loops": 1, "Plans": [ { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frara", "Alias": "population_1", "Actual Startup Time": 0.724, @@ -23,7 +24,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frbfc", "Alias": "population_2", "Actual Startup Time": 0.799, @@ -32,7 +34,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frbre", "Alias": "population_3", "Actual Startup Time": 0.701, @@ -41,7 +44,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frcor", "Alias": "population_4", "Actual Startup Time": 0.622, @@ -50,7 +54,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frcvl", "Alias": "population_5", "Actual Startup Time": 0.61, @@ -59,7 +64,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frges", "Alias": "population_6", "Actual Startup Time": 0.74, @@ -68,7 +74,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frgua", "Alias": "population_7", "Actual Startup Time": 0.653, @@ -77,7 +84,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frguf", "Alias": "population_8", "Actual Startup Time": 13.221, @@ -86,7 +94,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frhdf", "Alias": "population_9", "Actual Startup Time": 3.847, @@ -95,7 +104,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_fridf", "Alias": "population_10", "Actual Startup Time": 0.667, @@ -104,7 +114,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frlre", "Alias": "population_11", "Actual Startup Time": 0.65, @@ -113,7 +124,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frmay", "Alias": "population_12", "Actual Startup Time": 1.321, @@ -122,7 +134,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frmtq", "Alias": "population_13", "Actual Startup Time": 0.911, @@ -131,7 +144,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frnaq", "Alias": "population_14", "Actual Startup Time": 0.695, @@ -140,7 +154,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frnor", "Alias": "population_15", "Actual Startup Time": 0.761, @@ -149,7 +164,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frocc", "Alias": "population_16", "Actual Startup Time": 9.212, @@ -158,7 +174,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frpac", "Alias": "population_17", "Actual Startup Time": 0.44, @@ -167,7 +184,8 @@ "Actual Loops": 1 }, { - "Node Type": "Async Foreign Scan", + "Node Type": "Foreign Scan", + "Async Capable": true, "Relation Name": "population_frpdl", "Alias": "population_18", "Actual Startup Time": 1.074, diff --git a/src/services/help-service.ts b/src/services/help-service.ts index 17600051..d1f2e3b0 100644 --- a/src/services/help-service.ts +++ b/src/services/help-service.ts @@ -398,6 +398,7 @@ const notMiscProperties: string[] = [ Property.ACTUAL_ROWS_FRACTIONAL, Property.DISABLED, Property.WORKER_NUMBER, + Property.ASYNC_CAPABLE, ] export function shouldShowProp(key: string, value: unknown): boolean {