From 72a7895acbeb40e7599d1b4992fc3f3728c1e589 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 20 Feb 2024 15:52:50 +0000 Subject: [PATCH 01/48] Add test --- grafast/grafast/__tests__/unaryDeps-test.ts | 287 ++++++++++++++++++++ grafast/grafast/package.json | 1 + yarn.lock | 150 +++++++++- 3 files changed, 434 insertions(+), 4 deletions(-) create mode 100644 grafast/grafast/__tests__/unaryDeps-test.ts diff --git a/grafast/grafast/__tests__/unaryDeps-test.ts b/grafast/grafast/__tests__/unaryDeps-test.ts new file mode 100644 index 0000000000..7e5b18e8a5 --- /dev/null +++ b/grafast/grafast/__tests__/unaryDeps-test.ts @@ -0,0 +1,287 @@ +/* eslint-disable graphile-export/exhaustive-deps, graphile-export/export-methods, graphile-export/export-instances, graphile-export/export-subclasses, graphile-export/no-nested */ +import { expect } from "chai"; +import type { AsyncExecutionResult, ExecutionResult } from "graphql"; +import { it } from "mocha"; +import sqlite3 from "sqlite3"; + +import type { + ExecutionExtra, + GrafastResultsList, + GrafastValuesList, +} from "../dist/index.js"; +import { + access, + context, + ExecutableStep, + grafast, + makeGrafastSchema, +} from "../dist/index.js"; + +declare global { + namespace Grafast { + interface Context { + db: sqlite3.Database; + } + } +} + +function query(db: sqlite3.Database, sql: string, values: any[] = []) { + return new Promise((resolve, reject) => { + return db.all(sql, values, function (err, rows) { + if (err) { + reject(err); + } else { + resolve(rows); + } + }); + }); +} + +function run(db: sqlite3.Database, sql: string, values: any[] = []) { + return new Promise((resolve, reject) => { + return db.run(sql, values, function (err) { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); +} + +class GetRecordsStep> extends ExecutableStep { + depIdByIdentifier: Record; + dbDepId: string | number; + constructor( + private tableName: string, + identifiers: Record = Object.create(null), + ) { + super(); + this.dbDepId = this.addUnaryDependency(context().get("db")); + this.depIdByIdentifier = Object.fromEntries( + Object.entries(identifiers).map(([col, $step]) => [ + col, + this.addDependency($step), + ]), + ); + } + + // Unary Dep Id + private firstUDI: string | number; + setFirst($first: ExecutableStep) { + this.firstUDI = this.addUnaryDependency($first); + } + + async executeV2( + count: number, + values: GrafastValuesList, + extra: ExecutionExtra, + ): Promise> { + const db = extra.unaries[this.dbDepId] as sqlite3.Database; + const first = this.firstUDI != null ? extra.unaries[this.firstUDI] : null; + + const identifierCols = Object.keys(this.depIdByIdentifier); + + // Note: This SQL is not safe from SQL injection, it makes no effort to + // escape table or column names. Do not use this in production, this is a + // test file! + const otherOrders = []; + const otherConditions = []; + const orderBy = `${[...identifierCols, ...otherOrders].join(", ")}`; + const sql = `\ +select * +from ${this.tableName} t +where +${ + identifierCols.length > 0 + ? `( + ( + ${identifierCols.join(", ")} + ) in ( + select ${identifierCols + .map((ident) => `value->>'${ident}' as ${ident}`) + .join(", ")} + from json_each(?) + ) +)` + : true +} +${ + first != null && identifierCols.length > 0 + ? ` +and ( + row_number() over ( + partition by ${identifierCols.join(", ")} + order by ${orderBy} + ) <= ${first} +)` + : `` +} +${otherConditions.length ? `and (${otherConditions.join(")\nand (")})` : ``} +${orderBy ? `order by ${orderBy}` : ""} +`; + const sqlValues: any[] = []; + if (identifierCols.length > 0) { + const json: any[] = []; + for (let i = 0; i < count; i++) { + const obj = Object.fromEntries( + Object.entries(this.depIdByIdentifier).map(([col, depId]) => [ + col, + values[depId][i], + ]), + ); + json.push(obj); + } + sqlValues.push(JSON.stringify(json)); + } + const dbResults = await query(db, sql, sqlValues); + const results: T[][] = []; + for (let i = 0; i < count; i++) { + // This could be more optimal by leveraging they're already in order + results[i] = dbResults.filter((r) => { + return Object.entries(this.depIdByIdentifier).every( + ([col, depId]) => r[col] === values[depId][i], + ); + }); + } + return results; + } + listItem($item: ExecutableStep) { + return access($item); + } +} + +const makeSchema = () => { + return makeGrafastSchema({ + typeDefs: /* GraphQL */ ` + type Query { + allPeople: [Person] + } + type Person { + name: String + pets(first: Int): [Pet] + } + type Pet { + name: String + } + `, + plans: { + Query: { + allPeople(_) { + return getRecords("people"); + }, + }, + Person: { + pets($owner, { $first }) { + const $ownerId = $owner.get("id"); + const $pets = getRecords("pets", { owner_id: $ownerId }); + $pets.setFirst($first); + return $pets; + }, + }, + }, + enableDeferStream: false, + }); +}; + +function getRecords( + tableName: string, + identifiers?: Record, +) { + return new GetRecordsStep(tableName, identifiers); +} + +async function withDb(callback: (db: sqlite3.Database) => Promise) { + const db = new sqlite3.Database(":memory:"); + try { + await run(db, `drop table if exists pets;`); + await run(db, `drop table if exists people;`); + await run( + db, + `create table people ( + id serial primary key, + name text +);`, + ); + await run( + db, + `create table pets ( + id serial primary key, + name text, + owner_id int +);`, + ); + await run( + db, + `insert into people (id, name) values + (1, 'Alice'), + (2, 'Fred'), + (3, 'Kat');`, + ); + await run( + db, + `insert into pets (id, owner_id, name) values + (1, 1, 'Animal 1'), + (2, 1, 'Animal 2'), + (3, 1, 'Animal 3'), + (4, 2, 'Fox 1'), + (5, 2, 'Fox 2'), + (6, 3, 'Cat 1'), + (7, 3, 'Cat 2'), + (8, 3, 'Cat 3'); +`, + ); + return await callback(db); + } finally { + db.close(); + } +} + +it("works", () => + withDb(async (db) => { + const schema = makeSchema(); + const source = /* GraphQL */ ` + query Q { + allPeople { + name + pets { + name + } + } + } + `; + const variableValues = {}; + const result = (await grafast( + { + schema, + source, + variableValues, + contextValue: { + db, + }, + }, + {}, + {}, + )) as ExecutionResult; + expect(result.errors).to.be.undefined; + expect(result.data).to.deep.equal({ + allPeople: [ + { + name: "Alice", + pets: [ + { name: "Animal 1" }, + { name: "Animal 2" }, + { name: "Animal 3" }, + ], + }, + { + name: "Fred", + pets: [{ name: "Fox 1" }, { name: "Fox 2" }], + }, + { + name: "Kat", + pets: [{ name: "Cat 1" }, { name: "Cat 2" }, { name: "Cat 3" }], + }, + ], + }); + })); diff --git a/grafast/grafast/package.json b/grafast/grafast/package.json index a74fcb0ae8..8ec712d244 100644 --- a/grafast/grafast/package.json +++ b/grafast/grafast/package.json @@ -107,6 +107,7 @@ "nodemon": "^3.0.1", "pg-sql2": "workspace:^", "spec-md": "^3.1.0", + "sqlite3": "^5.1.7", "ts-node": "^10.9.1", "typescript": "^5.2.2", "zx": "^7.2.3" diff --git a/yarn.lock b/yarn.lock index 85e462711a..3409528fdf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7482,6 +7482,15 @@ __metadata: languageName: node linkType: hard +"bindings@npm:^1.5.0": + version: 1.5.0 + resolution: "bindings@npm:1.5.0" + dependencies: + file-uri-to-path: "npm:1.0.0" + checksum: 17581455207d7f731dfef93e18aebe1f4402e760a45e7fa02585ba6ccaf7bd0e91723d5587e01e222d5d890cd1c7958c69050b9d86d4256a5b7e4f108aebb669 + languageName: node + linkType: hard + "bl@npm:^4.0.3": version: 4.1.0 resolution: "bl@npm:4.1.0" @@ -9539,6 +9548,15 @@ __metadata: languageName: node linkType: hard +"decompress-response@npm:^6.0.0": + version: 6.0.0 + resolution: "decompress-response@npm:6.0.0" + dependencies: + mimic-response: "npm:^3.1.0" + checksum: b4575b109e38fe4bc10a8dc1a9167490da2efc07449bdc2ac9e3444592ee892e84fa89974448639388ad1f56f3a16e95606f3ab9d0c3dbdb84f1cbe432252b9f + languageName: node + linkType: hard + "dedent@npm:^1.0.0": version: 1.5.1 resolution: "dedent@npm:1.5.1" @@ -10767,6 +10785,13 @@ __metadata: languageName: node linkType: hard +"expand-template@npm:^2.0.3": + version: 2.0.3 + resolution: "expand-template@npm:2.0.3" + checksum: 11824d593f92f9ea6b8b29574db3bf904d1d910570176e5abbaba6e891a052784a0131f67d1d7c0831d9ea21630cf649d5aa661f21c22e0b2536635cfb6cb1a8 + languageName: node + linkType: hard + "expect@npm:^29.0.0, expect@npm:^29.6.4": version: 29.6.4 resolution: "expect@npm:29.6.4" @@ -11169,6 +11194,13 @@ __metadata: languageName: node linkType: hard +"file-uri-to-path@npm:1.0.0": + version: 1.0.0 + resolution: "file-uri-to-path@npm:1.0.0" + checksum: 38ecb8791c47805252036ab44cf946719e55b879548d2fe7305cc02a6b492b6ff37e0b92db42d9ba3fcc95a82d3fd5ef99b03b9289019ca4c0a067126467075b + languageName: node + linkType: hard + "filesize@npm:^8.0.6": version: 8.0.7 resolution: "filesize@npm:8.0.7" @@ -11716,6 +11748,13 @@ __metadata: languageName: node linkType: hard +"github-from-package@npm:0.0.0": + version: 0.0.0 + resolution: "github-from-package@npm:0.0.0" + checksum: 5ef16dcb4ca336ddff2c479227ea252c808d785608f2851826d880e1c63c3e03855ffbf90f2f97f88a1858cba8c23e0687eba094da9b4f9fddde843bb7ca7502 + languageName: node + linkType: hard + "github-slugger@npm:^1.4.0": version: 1.5.0 resolution: "github-slugger@npm:1.5.0" @@ -11946,6 +11985,7 @@ __metadata: nodemon: "npm:^3.0.1" pg-sql2: "workspace:^" spec-md: "npm:^3.1.0" + sqlite3: "npm:^5.1.7" tamedevil: "workspace:^" ts-node: "npm:^10.9.1" tslib: "npm:^2.6.2" @@ -15749,6 +15789,13 @@ __metadata: languageName: node linkType: hard +"mimic-response@npm:^3.1.0": + version: 3.1.0 + resolution: "mimic-response@npm:3.1.0" + checksum: 1d485ca418ab93d27d5a90b0ad701eee79fdf6a7dfd0342f7c83e1f2b421703eadadf9d1c968bff4749dcb42bb2148dc4b6bce795b7b357b46d47731353b7077 + languageName: node + linkType: hard + "min-indent@npm:^1.0.0": version: 1.0.1 resolution: "min-indent@npm:1.0.1" @@ -15821,7 +15868,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.8": +"minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.8": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 8598f846f2b7546b22b01ce486df27da216a302367afe17f2a032da12fcb8d33bfbf2c523051230864abf0b806748bd60d4cd0863fae35fe104da1ff6194a185 @@ -15941,7 +15988,7 @@ __metadata: languageName: node linkType: hard -"mkdirp-classic@npm:^0.5.2": +"mkdirp-classic@npm:^0.5.2, mkdirp-classic@npm:^0.5.3": version: 0.5.3 resolution: "mkdirp-classic@npm:0.5.3" checksum: 5afc1f004d905d299db7f58035f77a23b8703802e89486f09635971be0e6d09f409c2c862fe4c9a5bcba563675e831840fd0fd8b5c2f5bd41f6aa5a9e4b3bb3a @@ -16068,6 +16115,13 @@ __metadata: languageName: node linkType: hard +"napi-build-utils@npm:^1.0.1": + version: 1.0.2 + resolution: "napi-build-utils@npm:1.0.2" + checksum: f8135037d1e07905c414f8bfbd40e6cc28473c6b24becee470dde4599eb2e431e248f5cb2af9af3f6cc92dc82a3158de739550c24e32c8a13d2441df23b3536a + languageName: node + linkType: hard + "natural-compare@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare@npm:1.4.0" @@ -16099,6 +16153,15 @@ __metadata: languageName: node linkType: hard +"node-abi@npm:^3.3.0": + version: 3.54.0 + resolution: "node-abi@npm:3.54.0" + dependencies: + semver: "npm:^7.3.5" + checksum: 7e23916c8f18cddfd4bfa5e163839c26d43f9f8ff42b90bc8e0f89dbbccb8906966dc31ebaa9ff2737e1b840aa62c94fb79549efff485684c473d490de3ce2ce + languageName: node + linkType: hard + "node-addon-api@npm:^4.2.0": version: 4.3.0 resolution: "node-addon-api@npm:4.3.0" @@ -16108,6 +16171,15 @@ __metadata: languageName: node linkType: hard +"node-addon-api@npm:^7.0.0": + version: 7.1.0 + resolution: "node-addon-api@npm:7.1.0" + dependencies: + node-gyp: "npm:latest" + checksum: 6867cc84e868db76a7b3fc8f88e5e20f611e6b332541335f04a1ebbabbf3860153a4207f15c8392b770413d096879ad2e6a95aea26a216a75a631838084cd918 + languageName: node + linkType: hard + "node-domexception@npm:^1.0.0": version: 1.0.0 resolution: "node-domexception@npm:1.0.0" @@ -17776,6 +17848,28 @@ __metadata: languageName: node linkType: hard +"prebuild-install@npm:^7.1.1": + version: 7.1.1 + resolution: "prebuild-install@npm:7.1.1" + dependencies: + detect-libc: "npm:^2.0.0" + expand-template: "npm:^2.0.3" + github-from-package: "npm:0.0.0" + minimist: "npm:^1.2.3" + mkdirp-classic: "npm:^0.5.3" + napi-build-utils: "npm:^1.0.1" + node-abi: "npm:^3.3.0" + pump: "npm:^3.0.0" + rc: "npm:^1.2.7" + simple-get: "npm:^4.0.0" + tar-fs: "npm:^2.0.0" + tunnel-agent: "npm:^0.6.0" + bin: + prebuild-install: bin.js + checksum: 3ad2c49cbd7e7d52a6c6967ee3ca6f3f333f301a70866f21accadb9e29dbbf905e76ac543cfe3a1911fbd583bbe39f05b944278439e6ae402f0e9df768c3a0ee + languageName: node + linkType: hard + "preferred-pm@npm:^3.0.0": version: 3.1.1 resolution: "preferred-pm@npm:3.1.1" @@ -18187,7 +18281,7 @@ __metadata: languageName: node linkType: hard -"rc@npm:1.2.8, rc@npm:^1.2.8": +"rc@npm:1.2.8, rc@npm:^1.2.7, rc@npm:^1.2.8": version: 1.2.8 resolution: "rc@npm:1.2.8" dependencies: @@ -19628,6 +19722,24 @@ __metadata: languageName: node linkType: hard +"simple-concat@npm:^1.0.0": + version: 1.0.1 + resolution: "simple-concat@npm:1.0.1" + checksum: 1a041737314d8b49247072adf25990fa56430c2f71f3c129013fa275e0d725d935c2e2ca33bd10c22f1391047a8a94e01db3c149bda30b8e2480a833c99b9a30 + languageName: node + linkType: hard + +"simple-get@npm:^4.0.0": + version: 4.0.1 + resolution: "simple-get@npm:4.0.1" + dependencies: + decompress-response: "npm:^6.0.0" + once: "npm:^1.3.1" + simple-concat: "npm:^1.0.0" + checksum: f44b953899a2df12012150e834cc1d731d366e3e7b72f6e5d04d48d6750098afd21b7813a7e7aa1f8dcbf24915c80730df63c6c27c1b0f851b9245211cf8f0a2 + languageName: node + linkType: hard + "simple-html-tokenizer@npm:^0.1.1": version: 0.1.1 resolution: "simple-html-tokenizer@npm:0.1.1" @@ -20011,6 +20123,27 @@ __metadata: languageName: node linkType: hard +"sqlite3@npm:^5.1.7": + version: 5.1.7 + resolution: "sqlite3@npm:5.1.7" + dependencies: + bindings: "npm:^1.5.0" + node-addon-api: "npm:^7.0.0" + node-gyp: "npm:8.x" + prebuild-install: "npm:^7.1.1" + tar: "npm:^6.1.11" + peerDependencies: + node-gyp: 8.x + dependenciesMeta: + node-gyp: + optional: true + peerDependenciesMeta: + node-gyp: + optional: true + checksum: 6400bb0b6a8bc3a65f22bb28fdb45d6f7da0012ce3eecd1b5908d791e1fb6a883844ea96769aba6d536e14b507441bd40f630df0380aff16ca8a0d6c2135ea00 + languageName: node + linkType: hard + "ssri@npm:^10.0.0": version: 10.0.5 resolution: "ssri@npm:10.0.5" @@ -20476,7 +20609,7 @@ __metadata: languageName: node linkType: hard -"tar-fs@npm:2.1.1": +"tar-fs@npm:2.1.1, tar-fs@npm:^2.0.0": version: 2.1.1 resolution: "tar-fs@npm:2.1.1" dependencies: @@ -20921,6 +21054,15 @@ __metadata: languageName: node linkType: hard +"tunnel-agent@npm:^0.6.0": + version: 0.6.0 + resolution: "tunnel-agent@npm:0.6.0" + dependencies: + safe-buffer: "npm:^5.0.1" + checksum: 04bb1f31a4f757d78547536d3c58bf7d24645735ecc5af75536cf9ee46e8d4d8c802518a16062d9c07f78874946dd2ea600d2df42e5c538cdd9a414994bce54d + languageName: node + linkType: hard + "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" From 2c063e4e75c889744645b6a39a4569f8d00f58a9 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 20 Feb 2024 15:53:31 +0000 Subject: [PATCH 02/48] Handle errors in toStringMeta --- grafast/grafast/src/step.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/grafast/grafast/src/step.ts b/grafast/grafast/src/step.ts index 811c65d544..77b44892c1 100644 --- a/grafast/grafast/src/step.ts +++ b/grafast/grafast/src/step.ts @@ -312,7 +312,13 @@ export /* abstract */ class ExecutableStep extends BaseStep { } public toString(): string { - const meta = this.toStringMeta(); + let meta; + try { + // If we log out too early, the meta function might fail. + meta = this.toStringMeta(); + } catch (e) { + // Ignore + } return chalk.bold.blue( `${this.constructor.name.replace(/Step$/, "")}${ this.layerPlan.id === 0 ? "" : chalk.grey(`{${this.layerPlan.id}}`) From 23c8b9d760c2e59da5dfbeca72740387204d7bb8 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 20 Feb 2024 15:54:15 +0000 Subject: [PATCH 03/48] Allow wrapping any step with access without path --- grafast/grafast/src/steps/access.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grafast/grafast/src/steps/access.ts b/grafast/grafast/src/steps/access.ts index 817f325172..561c7ef138 100644 --- a/grafast/grafast/src/steps/access.ts +++ b/grafast/grafast/src/steps/access.ts @@ -231,12 +231,12 @@ export class AccessStep extends UnbatchedExecutableStep { */ export function access( parentPlan: ExecutableStep, - path: (string | number | symbol)[] | string | number | symbol, + path?: (string | number | symbol)[] | string | number | symbol, fallback?: any, ): AccessStep { return new AccessStep( parentPlan, - Array.isArray(path) ? path : [path], + Array.isArray(path) ? path : path != null ? [path] : [], fallback, ); } From 9b1c0fbcb9468407fbbe72a62e94764d30bf6189 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 21 Feb 2024 15:59:10 +0000 Subject: [PATCH 04/48] Unary dependencies almost working --- .../src/steps/pgClassExpression.ts | 4 +- grafast/dataplan-pg/src/steps/pgCursor.ts | 7 +- .../dataplan-pg/src/steps/pgPolymorphic.ts | 4 +- .../dataplan-pg/src/steps/pgSelectSingle.ts | 8 +- grafast/dataplan-pg/src/steps/toPg.ts | 4 +- grafast/grafast/__tests__/unaryDeps-test.ts | 21 +- grafast/grafast/src/bucket.ts | 5 + grafast/grafast/src/engine/LayerPlan.ts | 198 ++++++++++---- grafast/grafast/src/engine/OperationPlan.ts | 17 +- grafast/grafast/src/engine/OutputPlan.ts | 2 +- grafast/grafast/src/engine/StepTracker.ts | 23 ++ grafast/grafast/src/engine/executeBucket.ts | 254 ++++++++++++------ .../src/engine/lib/withGlobalLayerPlan.ts | 5 + grafast/grafast/src/index.ts | 5 + grafast/grafast/src/interfaces.ts | 7 +- grafast/grafast/src/prepare.ts | 80 ++++-- grafast/grafast/src/step.ts | 58 +++- .../grafast/src/steps/__inputDynamicScalar.ts | 4 +- grafast/grafast/src/steps/__inputObject.ts | 4 +- grafast/grafast/src/steps/__item.ts | 2 + grafast/grafast/src/steps/__trackedValue.ts | 4 +- grafast/grafast/src/steps/access.ts | 4 +- grafast/grafast/src/steps/applyTransforms.ts | 36 ++- grafast/grafast/src/steps/connection.ts | 8 +- grafast/grafast/src/steps/first.ts | 4 +- grafast/grafast/src/steps/graphqlResolver.ts | 3 +- grafast/grafast/src/steps/lambda.ts | 7 +- grafast/grafast/src/steps/last.ts | 4 +- grafast/grafast/src/steps/list.ts | 4 +- grafast/grafast/src/steps/listTransform.ts | 30 ++- grafast/grafast/src/steps/load.ts | 2 +- grafast/grafast/src/steps/node.ts | 4 +- grafast/grafast/src/steps/object.ts | 8 +- grafast/grafast/src/steps/proxy.ts | 4 +- grafast/grafast/src/steps/remapKeys.ts | 4 +- grafast/grafast/src/steps/reverse.ts | 4 +- grafast/grafast/src/steps/sideEffect.ts | 7 +- grafast/website/src/pages/errors/ud.mdx | 3 + utils/tamedevil/src/index.ts | 18 ++ 39 files changed, 634 insertions(+), 236 deletions(-) create mode 100644 grafast/website/src/pages/errors/ud.mdx diff --git a/grafast/dataplan-pg/src/steps/pgClassExpression.ts b/grafast/dataplan-pg/src/steps/pgClassExpression.ts index 9ace5a877f..8f43d61e25 100644 --- a/grafast/dataplan-pg/src/steps/pgClassExpression.ts +++ b/grafast/dataplan-pg/src/steps/pgClassExpression.ts @@ -1,4 +1,4 @@ -import type { ExecutionExtra } from "grafast"; +import type { UnbatchedExecutionExtra } from "grafast"; import { access, exportAs, UnbatchedExecutableStep } from "grafast"; import type { SQL } from "pg-sql2"; import sql from "pg-sql2"; @@ -226,7 +226,7 @@ export class PgClassExpressionStep< return this; } - public unbatchedExecute(_extra: ExecutionExtra, v: any): any { + public unbatchedExecute(_extra: UnbatchedExecutionExtra, v: any): any { if (v == null) { return null; } diff --git a/grafast/dataplan-pg/src/steps/pgCursor.ts b/grafast/dataplan-pg/src/steps/pgCursor.ts index 25a0e4437e..20ec862eff 100644 --- a/grafast/dataplan-pg/src/steps/pgCursor.ts +++ b/grafast/dataplan-pg/src/steps/pgCursor.ts @@ -1,4 +1,4 @@ -import type { ExecutionExtra } from "grafast"; +import type { UnbatchedExecutionExtra } from "grafast"; import { UnbatchedExecutableStep } from "grafast"; import { PgSelectSingleStep } from "./pgSelectSingle.js"; @@ -40,7 +40,10 @@ export class PgCursorStep< return plan as TStep; } - unbatchedExecute(_extra: ExecutionExtra, v: any[] | null): string | null { + unbatchedExecute( + _extra: UnbatchedExecutionExtra, + v: any[] | null, + ): string | null { return v == null || v!.every((v) => v == null) ? null : Buffer.from(JSON.stringify([this.digest, ...v]), "utf8").toString( diff --git a/grafast/dataplan-pg/src/steps/pgPolymorphic.ts b/grafast/dataplan-pg/src/steps/pgPolymorphic.ts index 787c15fdad..b461f452d7 100644 --- a/grafast/dataplan-pg/src/steps/pgPolymorphic.ts +++ b/grafast/dataplan-pg/src/steps/pgPolymorphic.ts @@ -1,8 +1,8 @@ import type { ExecutableStep, - ExecutionExtra, PolymorphicData, PolymorphicStep, + UnbatchedExecutionExtra, } from "grafast"; import { exportAs, @@ -123,7 +123,7 @@ export class PgPolymorphicStep< } unbatchedExecute( - _extra: ExecutionExtra, + _extra: UnbatchedExecutionExtra, _item: any, specifier: any, ): PolymorphicData | null { diff --git a/grafast/dataplan-pg/src/steps/pgSelectSingle.ts b/grafast/dataplan-pg/src/steps/pgSelectSingle.ts index 143b7fc60c..161dcad10b 100644 --- a/grafast/dataplan-pg/src/steps/pgSelectSingle.ts +++ b/grafast/dataplan-pg/src/steps/pgSelectSingle.ts @@ -1,4 +1,8 @@ -import type { EdgeCapableStep, ExecutableStep, ExecutionExtra } from "grafast"; +import type { + EdgeCapableStep, + ExecutableStep, + UnbatchedExecutionExtra, +} from "grafast"; import { exportAs, list, @@ -581,7 +585,7 @@ export class PgSelectSingleStep< handlePolymorphism?: (result: any) => any; unbatchedExecute( - _extra: ExecutionExtra, + _extra: UnbatchedExecutionExtra, result: ObjectFromPgCodecAttributes>, ): unknown[] { if (result == null) { diff --git a/grafast/dataplan-pg/src/steps/toPg.ts b/grafast/dataplan-pg/src/steps/toPg.ts index 2f002d460a..cc46a21b08 100644 --- a/grafast/dataplan-pg/src/steps/toPg.ts +++ b/grafast/dataplan-pg/src/steps/toPg.ts @@ -1,4 +1,4 @@ -import type { ExecutableStep, ExecutionExtra } from "grafast"; +import type { ExecutableStep, UnbatchedExecutionExtra } from "grafast"; import { UnbatchedExecutableStep } from "grafast"; import type { PgCodec } from "../interfaces.js"; @@ -28,7 +28,7 @@ export class ToPgStep extends UnbatchedExecutableStep { return peers.filter((peer) => peer.codec === this.codec); } - unbatchedExecute(_extra: ExecutionExtra, v: any) { + unbatchedExecute(_extra: UnbatchedExecutionExtra, v: any) { return v == null ? null : this.codec.toPg(v); } } diff --git a/grafast/grafast/__tests__/unaryDeps-test.ts b/grafast/grafast/__tests__/unaryDeps-test.ts index 7e5b18e8a5..feb5235853 100644 --- a/grafast/grafast/__tests__/unaryDeps-test.ts +++ b/grafast/grafast/__tests__/unaryDeps-test.ts @@ -1,6 +1,6 @@ /* eslint-disable graphile-export/exhaustive-deps, graphile-export/export-methods, graphile-export/export-instances, graphile-export/export-subclasses, graphile-export/no-nested */ import { expect } from "chai"; -import type { AsyncExecutionResult, ExecutionResult } from "graphql"; +import type { ExecutionResult } from "graphql"; import { it } from "mocha"; import sqlite3 from "sqlite3"; @@ -66,6 +66,16 @@ class GetRecordsStep> extends ExecutableStep { ); } + toStringMeta(): string | null { + const entries = Object.entries(this.depIdByIdentifier); + return ( + this.tableName + + (entries.length > 0 + ? `{${entries.map(([k, v]) => `${k}=${this.getDep(v)}`).join(",")}}` + : "") + ); + } + // Unary Dep Id private firstUDI: string | number; setFirst($first: ExecutableStep) { @@ -127,7 +137,7 @@ ${orderBy ? `order by ${orderBy}` : ""} const obj = Object.fromEntries( Object.entries(this.depIdByIdentifier).map(([col, depId]) => [ col, - values[depId][i], + values[depId] ? values[depId][i] : extra.unaries[depId], ]), ); json.push(obj); @@ -136,11 +146,14 @@ ${orderBy ? `order by ${orderBy}` : ""} } const dbResults = await query(db, sql, sqlValues); const results: T[][] = []; + const entries = Object.entries(this.depIdByIdentifier); for (let i = 0; i < count; i++) { // This could be more optimal by leveraging they're already in order results[i] = dbResults.filter((r) => { - return Object.entries(this.depIdByIdentifier).every( - ([col, depId]) => r[col] === values[depId][i], + return entries.every( + ([col, depId]) => + r[col] === + (values[depId] ? values[depId][i] : extra.unaries[depId]), ); }); } diff --git a/grafast/grafast/src/bucket.ts b/grafast/grafast/src/bucket.ts index 2710311001..41105f1043 100644 --- a/grafast/grafast/src/bucket.ts +++ b/grafast/grafast/src/bucket.ts @@ -90,6 +90,11 @@ export interface Bucket { */ store: Map; + /** + * For "unary dependencies", we only need to store the value once per step id. + */ + unaryStore: Map; + /** * Set this true when the bucket is fully executed. * diff --git a/grafast/grafast/src/engine/LayerPlan.ts b/grafast/grafast/src/engine/LayerPlan.ts index 45a8b2ad3d..7b62e00f96 100644 --- a/grafast/grafast/src/engine/LayerPlan.ts +++ b/grafast/grafast/src/engine/LayerPlan.ts @@ -4,6 +4,7 @@ import te from "tamedevil"; import * as assert from "../assert.js"; import type { Bucket } from "../bucket.js"; +import { isDev } from "../dev.js"; import type { GrafastError } from "../error.js"; import { isGrafastError } from "../error.js"; import { inspect } from "../inspect.js"; @@ -228,13 +229,21 @@ export class LayerPlan { public readonly rootStep: ExecutableStep | null = null; /** - * Which plans the results for which are available in a parent bucket need to - * be "copied across" to this bucket because plans in this bucket still - * reference them? + * Which steps the results for which are available in a parent bucket need to + * be "copied across" to this bucket because steps in this bucket still + * reference them? Batch steps only. * * @internal */ - public copyStepIds: number[] = []; + public copyBatchStepIds: number[] = []; + /** + * Which steps the results for which are available in a parent bucket need to + * be "copied across" to this bucket because steps in this bucket still + * reference them? Unary steps only. + * + * @internal + */ + public copyUnaryStepIds: number[] = []; /** @internal */ public children: LayerPlan[] = []; @@ -323,7 +332,9 @@ export class LayerPlan { this.reason.type === "polymorphic" ? `{${this.reason.typeNames.join(",")}}` : ""; - const deps = this.copyStepIds.length > 0 ? `%${this.copyStepIds}` : ""; + const deps = + (this.copyUnaryStepIds.length > 0 ? `/${this.copyUnaryStepIds}` : "") + + (this.copyBatchStepIds.length > 0 ? `%${this.copyBatchStepIds}` : ""); return `LayerPlan<${this.id}${chain}?${this.reason.type}${reasonExtra}!${ this.rootStep?.id ?? "x" }${deps}>`; @@ -361,16 +372,18 @@ export class LayerPlan { this.reason.type === "nullableBoundary" || this.reason.type === "listItem" ) { - const n = this.copyStepIds.length; - const signature = this.reason.type[0] + n; - withNewBucketFactory(signature, n, this.reason.type, (fn) => { - this.newBucket = fn(this.copyStepIds); + const u = this.copyUnaryStepIds.length; + const b = this.copyBatchStepIds.length; + const signature = `${this.reason.type[0]}_${u}_${b}`; + withNewBucketFactory(signature, u, b, this.reason.type, (fn) => { + this.newBucket = fn(this.copyUnaryStepIds, this.copyBatchStepIds); }); } } public newBucket(parentBucket: Bucket): Bucket | null { - const copyStepIds = this.copyStepIds; + const { copyUnaryStepIds, copyBatchStepIds } = this; + const unaryStore = new Map(); const store: Bucket["store"] = new Map(); const polymorphicPathList: (string | null)[] = this.reason.type === "mutationField" @@ -382,29 +395,52 @@ export class LayerPlan { let size = 0; switch (this.reason.type) { case "nullableBoundary": { - const itemStepId = this.rootStep?.id; - assert.ok( - itemStepId != null, - "GrafastInternalError: nullableStepStore layer plan has no rootStepId", - ); - const nullableStepStore = parentBucket.store.get(itemStepId); - if (!nullableStepStore) { + if (this.rootStep == null) { throw new Error( - `GrafastInternalError<017dc8bf-1db1-4983-a41e-e69c6652e4c7>: could not find entry '${itemStepId}' (${parentBucket.layerPlan.operationPlan.dangerouslyGetStep( - itemStepId, - )}) in store for ${parentBucket.layerPlan}`, + "GrafastInternalError: nullableStepStore layer plan has no rootStepId", ); } + const itemStepId = this.rootStep.id; // PERF: if parent bucket has no nulls/errors in `itemStepId` // then we can just copy everything wholesale rather than building // new arrays and looping. const hasNoNullsOrErrors = false; - if (hasNoNullsOrErrors) { - store.set(itemStepId, nullableStepStore); - for (const planId of copyStepIds) { - store.set(planId, parentBucket.store.get(planId)!); + if (this.rootStep._isUnary) { + assert.ok( + parentBucket.size == 1, + "GrafastInternalError<8c26e449-26ad-4192-b95d-170c59a024a4>: unary step must be in bucket of size 1 (otherwise it's not unary...)", + ); + unaryStore.set(itemStepId, parentBucket.unaryStore.get(itemStepId)); + for (const stepId of copyUnaryStepIds) { + unaryStore.set(stepId, parentBucket.unaryStore.get(stepId)!); + } + for (const stepId of copyBatchStepIds) { + store.set(stepId, parentBucket.store.get(stepId)!); + } + map.set(0, 0); + polymorphicPathList[0] = parentBucket.polymorphicPathList[0]; + iterators[0] = parentBucket.iterators[0]; + } else if (hasNoNullsOrErrors) { + if (this.rootStep._isUnary) { + unaryStore.set(itemStepId, parentBucket.unaryStore.get(itemStepId)); + } else { + const nullableStepStore = parentBucket.store.get(itemStepId); + if (!nullableStepStore) { + throw new Error( + `GrafastInternalError<017dc8bf-1db1-4983-a41e-e69c6652e4c7>: could not find entry '${itemStepId}' (${parentBucket.layerPlan.operationPlan.dangerouslyGetStep( + itemStepId, + )}) in store for ${parentBucket.layerPlan}`, + ); + } + store.set(itemStepId, nullableStepStore); + } + for (const stepId of copyUnaryStepIds) { + unaryStore.set(stepId, parentBucket.unaryStore.get(stepId)!); + } + for (const stepId of copyBatchStepIds) { + store.set(stepId, parentBucket.store.get(stepId)!); } for ( let originalIndex = 0; @@ -421,9 +457,21 @@ export class LayerPlan { const itemStepIdList: any[] = []; store.set(itemStepId, itemStepIdList); + for (const stepId of copyUnaryStepIds) { + unaryStore.set(stepId, parentBucket.unaryStore.get(stepId)); + } // Prepare store with an empty list for each copyPlanId - for (const planId of copyStepIds) { - store.set(planId, []); + for (const stepId of copyBatchStepIds) { + store.set(stepId, []); + } + + const nullableStepStore = parentBucket.store.get(itemStepId); + if (!nullableStepStore) { + throw new Error( + `GrafastInternalError<017dc8bf-1db1-4983-a41e-e69c6652e4c7>: could not find entry '${itemStepId}' (${parentBucket.layerPlan.operationPlan.dangerouslyGetStep( + itemStepId, + )}) in store for ${parentBucket.layerPlan}`, + ); } // We'll typically be creating fewer nullableBoundary bucket entries @@ -444,9 +492,9 @@ export class LayerPlan { polymorphicPathList[newIndex] = parentBucket.polymorphicPathList[originalIndex]; iterators[newIndex] = parentBucket.iterators[originalIndex]; - for (const planId of copyStepIds) { - store.get(planId)![newIndex] = - parentBucket.store.get(planId)![originalIndex]; + for (const stepId of copyBatchStepIds) { + store.get(stepId)![newIndex] = + parentBucket.store.get(stepId)![originalIndex]; } } } @@ -456,7 +504,9 @@ export class LayerPlan { } case "listItem": { const listStepId = this.reason.parentStep.id; - const listStepStore = parentBucket.store.get(listStepId); + const listStepStore = this.reason.parentStep._isUnary + ? [parentBucket.unaryStore.get(listStepId)] + : parentBucket.store.get(listStepId); if (!listStepStore) { throw new Error( `GrafastInternalError<314865b0-f7e8-4e81-b966-56e5a0de562e>: could not find entry '${listStepId}' (${parentBucket.layerPlan.operationPlan.dangerouslyGetStep( @@ -471,11 +521,15 @@ export class LayerPlan { "GrafastInternalError: listItem layer plan has no rootStepId", ); } + // Item steps are **NOT** unary store.set(itemStepId, []); + for (const stepId of copyUnaryStepIds) { + unaryStore.set(stepId, parentBucket.unaryStore.get(stepId)); + } // Prepare store with an empty list for each copyPlanId - for (const planId of copyStepIds) { - store.set(planId, []); + for (const stepId of copyBatchStepIds) { + store.set(stepId, []); } // We'll typically be creating more listItem bucket entries than we @@ -498,9 +552,9 @@ export class LayerPlan { polymorphicPathList[newIndex] = parentBucket.polymorphicPathList[originalIndex]; iterators[newIndex] = parentBucket.iterators[originalIndex]; - for (const planId of copyStepIds) { - store.get(planId)![newIndex] = - parentBucket.store.get(planId)![originalIndex]; + for (const stepId of copyBatchStepIds) { + store.get(stepId)![newIndex] = + parentBucket.store.get(stepId)![originalIndex]; } } } @@ -514,15 +568,20 @@ export class LayerPlan { for (let i = 0; i < parentBucket.size; i++) { map.set(i, i); } - for (const planId of copyStepIds) { - store.set(planId, parentBucket.store.get(planId)!); + for (const stepId of copyUnaryStepIds) { + unaryStore.set(stepId, parentBucket.unaryStore.get(stepId)!); + } + for (const stepId of copyBatchStepIds) { + store.set(stepId, parentBucket.store.get(stepId)!); } break; } case "polymorphic": { const polymorphicPlanId = this.reason.parentStep.id; - const polymorphicPlanStore = parentBucket.store.get(polymorphicPlanId); + const polymorphicPlanStore = this.reason.parentStep._isUnary + ? [parentBucket.unaryStore.get(polymorphicPlanId)] + : parentBucket.store.get(polymorphicPlanId); if (!polymorphicPlanStore) { throw new Error( `GrafastInternalError: Entry for '${parentBucket.layerPlan.operationPlan.dangerouslyGetStep( @@ -535,12 +594,15 @@ export class LayerPlan { // they may end up being null, but that's okay) const targetTypeNames = this.reason.typeNames; - for (const planId of copyStepIds) { - store.set(planId, []); - if (!parentBucket.store.has(planId)) { + for (const stepId of copyUnaryStepIds) { + unaryStore.set(stepId, parentBucket.unaryStore.get(stepId)); + } + for (const stepId of copyBatchStepIds) { + store.set(stepId, []); + if (isDev && !parentBucket.store.has(stepId)) { throw new Error( `GrafastInternalError<548f0d84-4556-4189-8655-fb16aa3345a6>: new bucket for ${this} wants to copy ${this.operationPlan.dangerouslyGetStep( - planId, + stepId, )}, but bucket for ${ parentBucket.layerPlan } doesn't contain that plan`, @@ -575,7 +637,7 @@ export class LayerPlan { polymorphicPathList[newIndex] = newPolymorphicPath; iterators[newIndex] = parentBucket.iterators[originalIndex]; - for (const planId of copyStepIds) { + for (const planId of copyBatchStepIds) { store.get(planId)![newIndex] = parentBucket.store.get(planId)![originalIndex]; } @@ -616,6 +678,7 @@ export class LayerPlan { layerPlan: this, size, store, + unaryStore, // PERF: not necessarily, if we don't copy the errors, we don't have the errors. hasErrors: parentBucket.hasErrors, polymorphicPathList, @@ -635,7 +698,10 @@ export class LayerPlan { } } -type Factory = (copyPlanIds: number[]) => typeof LayerPlan.prototype.newBucket; +type Factory = ( + copyUnaryStepIds: number[], + copyBatchStepIds: number[], +) => typeof LayerPlan.prototype.newBucket; const makeNewBucketCache = new LRU({ maxLength: 1000, @@ -654,8 +720,9 @@ function makeNewBucketExpression( reasonType: "nullableBoundary" | "listItem" | "mutationField", inner: TE, ): TE { - return te`\ + const expr = te`\ (function ${te.identifier(`newBucket_${signature}`)}(parentBucket) { + const unaryStore = new Map(); const store = new Map(); const polymorphicPathList = ${ reasonType === "mutationField" @@ -689,11 +756,14 @@ ${inner} return null; } })`; + te.debug(expr); + return expr; } function newBucketFactoryInnerExpression( signature: string, - copyCount: number, + unaryCopyCount: number, + batchCopyCount: number, reasonType: "nullableBoundary" | "listItem", ) { if (reasonType === "nullableBoundary") { @@ -703,15 +773,23 @@ function newBucketFactoryInnerExpression( const blocks: TE[] = []; const copyBlocks: TE[] = []; - for (let i = 0; i < copyCount; i++) { + for (let i = 0; i < unaryCopyCount; i++) { + const te_i = te.lit(i); + blocks.push( + te`\ + unaryStore.set(copyUnaryStepIds[${te_i}], parentBucket.unaryStore.get(copyUnaryStepIds[${te_i}])); +`, + ); + } + for (let i = 0; i < batchCopyCount; i++) { const te_source = te.identifier(`source${i}`); const te_target = te.identifier(`target${i}`); const te_i = te.lit(i); blocks.push( te`\ - const ${te_source} = parentBucket.store.get(copyPlanIds[${te_i}]); + const ${te_source} = parentBucket.store.get(copyBatchStepIds[${te_i}]); const ${te_target} = []; - store.set(copyPlanIds[${te_i}], ${te_target}); + store.set(copyBatchStepIds[${te_i}], ${te_target}); `, ); copyBlocks.push( @@ -758,15 +836,23 @@ ${te.join(copyBlocks, "")} } else if (reasonType === "listItem") { const blocks: TE[] = []; const copyBlocks: TE[] = []; - for (let i = 0; i < copyCount; i++) { + for (let i = 0; i < unaryCopyCount; i++) { + const te_i = te.lit(i); + blocks.push( + te`\ + unaryStore.set(copyUnaryStepIds[${te_i}], parentBucket.store.get(copyUnaryStepIds[${te_i}])); + `, + ); + } + for (let i = 0; i < batchCopyCount; i++) { const te_source = te.identifier(`source${i}`); const te_target = te.identifier(`target${i}`); const te_i = te.lit(i); blocks.push( te`\ - const ${te_source} = parentBucket.store.get(copyPlanIds[${te_i}]); + const ${te_source} = parentBucket.store.get(copyBatchStepIds[${te_i}]); const ${te_target} = []; - store.set(copyPlanIds[${te_i}], ${te_target}); + store.set(copyBatchStepIds[${te_i}], ${te_target}); `, ); copyBlocks.push(te`\ @@ -818,7 +904,8 @@ ${te.join(copyBlocks, "")} function withNewBucketFactory( signature: string, - copyCount: number, + unaryCopyCount: number, + batchCopyCount: number, reasonType: "nullableBoundary" | "listItem", callback: (factory: Factory) => void, ) { @@ -837,14 +924,15 @@ function withNewBucketFactory( const executorExpression = newBucketFactoryInnerExpression( signature, - copyCount, + unaryCopyCount, + batchCopyCount, reasonType, ); const factoryExpression = te`\ function ${te.identifier( `layerPlanNewBucketFactory_${signature}`, - )}(copyPlanIds) { + )}(copyUnaryStepIds, copyBatchStepIds) { return ${executorExpression}; }`; te.runInBatch(factoryExpression, (factory) => { diff --git a/grafast/grafast/src/engine/OperationPlan.ts b/grafast/grafast/src/engine/OperationPlan.ts index a595469619..dd608985cf 100644 --- a/grafast/grafast/src/engine/OperationPlan.ts +++ b/grafast/grafast/src/engine/OperationPlan.ts @@ -3079,17 +3079,26 @@ export class OperationPlan { let currentLayerPlan: LayerPlan | null = layerPlan; while (dep.layerPlan !== currentLayerPlan) { - if (currentLayerPlan.copyStepIds.includes(dep.id)) { + if ( + currentLayerPlan.copyBatchStepIds.includes(dep.id) || + currentLayerPlan.copyUnaryStepIds.includes(dep.id) + ) { break; } - if (isDev && this.stepTracker.getStepById(dep.id) !== dep) { + const targetStep = this.stepTracker.getStepById(dep.id); + if (isDev && targetStep !== dep) { throw new Error( `GrafastInternalError: Plan mismatch; are we using a replaced step? Step ID: ${ dep.id }; step: ${dep}; stepById: ${this.stepTracker.getStepById(dep.id)}`, ); } - currentLayerPlan.copyStepIds.push(dep.id); + if (targetStep._isUnary) { + targetStep._isUnaryLocked = true; + currentLayerPlan.copyUnaryStepIds.push(dep.id); + } else { + currentLayerPlan.copyBatchStepIds.push(dep.id); + } currentLayerPlan = currentLayerPlan.parentLayerPlan; if (!currentLayerPlan) { throw new Error( @@ -3416,7 +3425,7 @@ export class OperationPlan { return { id: lp.id, reason: printBucketReason(lp.reason), - copyStepIds: lp.copyStepIds, + copyStepIds: [...lp.copyUnaryStepIds, ...lp.copyBatchStepIds], phases: lp.phases.map(printPhase), steps: lp.steps.map(printStep), children: lp.children.map(printBucket), diff --git a/grafast/grafast/src/engine/OutputPlan.ts b/grafast/grafast/src/engine/OutputPlan.ts index 24a243ff66..18fecbef49 100644 --- a/grafast/grafast/src/engine/OutputPlan.ts +++ b/grafast/grafast/src/engine/OutputPlan.ts @@ -829,7 +829,7 @@ function makeExecutorExpression( mutablePath, bucket, bucketIndex, - rawBucketRootValue = bucket.store.get(this.rootStep.id)[bucketIndex] + rawBucketRootValue = this.rootStep._isUnary ? bucket.unaryStore.get(this.rootStep.id) : bucket.store.get(this.rootStep.id)[bucketIndex] ) { const bucketRootValue = this.processRoot !== null ? this.processRoot(rawBucketRootValue) : rawBucketRootValue; ${preamble}\ diff --git a/grafast/grafast/src/engine/StepTracker.ts b/grafast/grafast/src/engine/StepTracker.ts index 111927f3f1..3264cdb675 100644 --- a/grafast/grafast/src/engine/StepTracker.ts +++ b/grafast/grafast/src/engine/StepTracker.ts @@ -294,9 +294,32 @@ export class StepTracker { step: $dependent, dependencyIndex, }); + if (!$dependency._isUnary) { + if ($dependent._isUnary) { + if ($dependent._isUnaryLocked) { + throw new Error( + `Attempted to add non-unary step ${$dependency} as a dependency of ${$dependent}; but the latter is unary, so it cannot depend on batch steps`, + ); + } + $dependent._isUnary = false; + } + } return dependencyIndex; } + public addStepUnaryDependency( + $dependent: ExecutableStep, + $dependency: ExecutableStep, + ): number { + if (!$dependency._isUnary) { + throw new Error( + `${$dependent} attempted to create a unary step dependency on ${$dependency}, but that step is not unary. You may use \`.addDependency()\` instead of \`.addUnaryDependency()\`.`, + ); + } + $dependency._isUnaryLocked = true; + return this.addStepDependency($dependent, $dependency); + } + public setOutputPlanRootStep( outputPlan: OutputPlan, $dependency: ExecutableStep, diff --git a/grafast/grafast/src/engine/executeBucket.ts b/grafast/grafast/src/engine/executeBucket.ts index d12b3e127f..8a0ceff7b5 100644 --- a/grafast/grafast/src/engine/executeBucket.ts +++ b/grafast/grafast/src/engine/executeBucket.ts @@ -17,10 +17,11 @@ import type { GrafastResultStreamList, PromiseOrDirect, StreamMaybeMoreableArray, + UnbatchedExecutionExtra, } from "../interfaces.js"; import { $$streamMore, $$timeout } from "../interfaces.js"; import type { ExecutableStep, UnbatchedExecutableStep } from "../step.js"; -import { isStreamableStep } from "../step.js"; +import { isStreamableStep, isStreamV2ableStep } from "../step.js"; import { __ItemStep } from "../steps/__item.js"; import { __ValueStep } from "../steps/__value.js"; import { timeSource } from "../timeSource.js"; @@ -71,14 +72,15 @@ function mergeErrorsBackIn( resultCount: number, ): any[] { const finalResults: any[] = []; + /** The index within `results`, which is shorter than `resultCount` */ let resultIndex = 0; - for (let i = 0; i < resultCount; i++) { - const error = errors[i]; + for (let finalIndex = 0; finalIndex < resultCount; finalIndex++) { + const error = errors[finalIndex]; if (error !== undefined) { - finalResults[i] = error; + finalResults[finalIndex] = error; } else { - finalResults[i] = results[resultIndex++]; + finalResults[finalIndex] = results[resultIndex++]; } } return finalResults; @@ -100,6 +102,7 @@ export function executeBucket( metaByMetaKey, size, store, + unaryStore, layerPlan: { phases, children: childLayerPlans }, } = bucket; @@ -243,7 +246,11 @@ export function executeBucket( `Result array from ${finishedStep} should have length ${size}, instead it had length ${result.length}`, ); } - bucket.store.set(finishedStep.id, arrayOfLength(size)); + if (finishedStep._isUnary) { + bucket.unaryStore.set(finishedStep.id, null); // TODO: what placeholder value should we use? + } else { + bucket.store.set(finishedStep.id, arrayOfLength(size)); + } } // Need to complete promises, check for errors, etc. @@ -264,10 +271,23 @@ export function executeBucket( const success = ( finishedStep: ExecutableStep, - finalResult: any[], + bucket: Bucket, resultIndex: number, value: unknown, ) => { + if (finishedStep._isUnary) { + if (resultIndex !== 0) { + throw new Error( + `GrafastInternalError<631aafcc-c40c-4fe2-948e-3f06298eb40c>: A unary step must have exactly one result, but ${finishedStep}'s ${resultIndex}th value is ${inspect( + value, + )}`, + ); + } + // TODO: handle streams/etc + bucket.unaryStore.set(finishedStep.id, value); + return; + } + const finalResult = bucket.store.get(finishedStep.id)!; let proto: any; if ( // Fast-lane for non-objects @@ -369,11 +389,10 @@ export function executeBucket( for (const allStepsIndex of indexesToProcess) { const step = _allSteps[allStepsIndex]; const result = results[allStepsIndex]!; - const storeEntry = bucket.store.get(step.id)!; for (let dataIndex = 0; dataIndex < size; dataIndex++) { const val = result[dataIndex]; if (step.isSyncAndSafe || !isPromiseLike(val)) { - success(step, storeEntry, dataIndex, val); + success(step, bucket, dataIndex, val); } else { if (!pendingPromises) { pendingPromises = [val]; @@ -398,20 +417,20 @@ export function executeBucket( const { s: allStepsIndex, i: dataIndex } = pendingPromiseIndexes![i]; const finishedStep = _allSteps[allStepsIndex]; - const storeEntry = bucket.store.get(finishedStep.id)!; if (settledResult.status === "fulfilled") { - success( - finishedStep, - storeEntry, - dataIndex, - settledResult.value, - ); + success(finishedStep, bucket, dataIndex, settledResult.value); } else { bucket.hasErrors = true; - storeEntry[dataIndex] = newGrafastError( + const error = newGrafastError( settledResult.reason, finishedStep.id, ); + if (finishedStep._isUnary) { + bucket.unaryStore.set(finishedStep.id, error); + } else { + const storeEntry = bucket.store.get(finishedStep.id)!; + storeEntry[dataIndex] = error; + } } } if (bucket.hasErrors && sideEffectSteps) { @@ -464,7 +483,7 @@ export function executeBucket( return next(); } const allStepsLength = _allSteps.length; - const extras: ExecutionExtra[] = []; + const extras: UnbatchedExecutionExtra[] = []; for ( let allStepsIndex = executedLength; allStepsIndex < allStepsLength; @@ -519,24 +538,40 @@ export function executeBucket( const step = sudo( _allSteps[allStepsIndex] as UnbatchedExecutableStep, ); - const storeEntry = bucket.store.get(step.id)!; try { const deps: any = []; + const extra = extras[allStepsIndex]; for (const $dep of step.dependencies) { - const depVal = bucket.store.get($dep.id)![dataIndex]; + const depVal = $dep._isUnary + ? bucket.unaryStore.get($dep.id) + : bucket.store.get($dep.id)![dataIndex]; if (bucket.hasErrors && isGrafastError(depVal)) { - storeEntry[dataIndex] = depVal; + if (step._isUnary) { + bucket.unaryStore.set(step.id, depVal); + } else { + const storeEntry = bucket.store.get(step.id)!; + storeEntry[dataIndex] = depVal; + } continue stepLoop; } deps.push(depVal); } - storeEntry[dataIndex] = step.unbatchedExecute( - extras[allStepsIndex], - ...deps, - ); + const stepResult = step.unbatchedExecute(extra, ...deps); + if (step._isUnary) { + bucket.unaryStore.set(step.id, stepResult); + } else { + const storeEntry = bucket.store.get(step.id)!; + storeEntry[dataIndex] = stepResult; + } } catch (e) { bucket.hasErrors = true; - storeEntry[dataIndex] = newGrafastError(e, step.id); + const error = newGrafastError(e, step.id); + if (step._isUnary) { + bucket.unaryStore.set(step.id, error); + } else { + const storeEntry = bucket.store.get(step.id)!; + storeEntry[dataIndex] = error; + } } } } @@ -587,14 +622,26 @@ export function executeBucket( // Function definitions below here function executeOrStream( + size: number, step: ExecutableStep, - dependencies: ReadonlyArray[], + dependencies: Array | null>, extra: ExecutionExtra, ): PromiseOrDirect | GrafastResultStreamList> { - if (step._stepOptions.stream && isStreamableStep(step)) { - return step.stream(size, dependencies, extra, step._stepOptions.stream); + if (step._stepOptions.stream && isStreamV2ableStep(step)) { + return step.streamV2(size, dependencies, extra, step._stepOptions.stream); + } else if (step._stepOptions.stream && isStreamableStep(step)) { + // Backwards compatibility + const backfilledValues = dependencies.map((v, i) => + v === null ? arrayOfLength(size, extra.unaries[i]) : v, + ); + return step.stream( + size, + backfilledValues, + extra, + step._stepOptions.stream, + ); } else { - return step.execute(size, dependencies, extra); + return step.executeV2(size, dependencies, extra); } } @@ -606,27 +653,36 @@ export function executeBucket( */ function reallyExecuteStepWithErrorsOrSelective( step: ExecutableStep, - dependenciesIncludingSideEffects: ReadonlyArray[], + dependenciesIncludingSideEffects: Array | null>, polymorphicPathList: readonly (string | null)[], extra: ExecutionExtra, ): PromiseOrDirect | GrafastResultStreamList> { const errors: { [index: number]: GrafastError | undefined } = - Object.create(null); + arrayOfLength(size); /** If there's errors, we must manipulate the arrays being passed into the step execution */ let foundErrors = false; /** If all we see is errors, there's no need to execute! */ - let needsNoExecution = true; + let newSize = 0; const stepPolymorphicPaths = step.polymorphicPaths; + const legitDepsCount = sudo(step).dependencies.length; + let dependencies = ( + sideEffectStepsWithErrors + ? dependenciesIncludingSideEffects.slice(0, legitDepsCount) + : dependenciesIncludingSideEffects + ) as (any[] | null)[]; + + // OPTIM: if extra.unaries.some(isGrafastError) then shortcut execution because everything fails - for (let index = 0, l = polymorphicPathList.length; index < l; index++) { + // for (let index = 0, l = polymorphicPathList.length; index < l; index++) { + for (let index = 0; index < size; index++) { + let indexError: GrafastError | null = null; const polymorphicPath = polymorphicPathList[index]; if ( stepPolymorphicPaths !== null && !stepPolymorphicPaths.has(polymorphicPath as string) ) { - foundErrors = true; const e = isDev && DEBUG_POLYMORPHISM ? Object.assign( @@ -644,61 +700,76 @@ export function executeBucket( ) : POLY_SKIPPED; - errors[index] = e; + indexError = e; } else if (extra._bucket.hasErrors) { - let noError = true; - for (const depList of dependenciesIncludingSideEffects) { - const v = depList[index]; + for ( + let i = 0, l = dependenciesIncludingSideEffects.length; + i < l; + i++ + ) { + const depList = dependenciesIncludingSideEffects[i]; + const v = depList ? depList[index] : extra.unaries[i]; if (isGrafastError(v)) { - if (!errors[index]) { - noError = false; - foundErrors = true; - errors[index] = v; - break; - } + indexError = v; + break; } } - if (noError) { - needsNoExecution = false; + } else { + // All good + } + if (indexError) { + if (!foundErrors) { + foundErrors = true; + // Clone up until this point, make mutable, don't add self + dependencies = dependencies.map((depList) => + depList ? depList.slice(0, index) : depList, + ); } + errors[index] = indexError; } else { - needsNoExecution = false; + newSize++; + if (foundErrors) { + // dependenciesWithoutErrors has limited content; add this non-error value + for ( + let depListIndex = 0; + depListIndex < legitDepsCount; + depListIndex++ + ) { + const depList = dependencies[depListIndex]; + if (depList) { + depList.push( + dependenciesIncludingSideEffects[depListIndex]![index], + ); + } + } + } } } // Trim the side-effect dependencies back out again - const dependencies = sideEffectStepsWithErrors - ? dependenciesIncludingSideEffects.slice( - 0, - sudo(step).dependencies.length, - ) - : dependenciesIncludingSideEffects; - - if (needsNoExecution) { + if (sideEffectStepsWithErrors) { + extra.unaries = extra.unaries.slice(0, legitDepsCount); + } + + if (newSize === 0) { // Everything is errors; we can skip execution return Object.values(errors); } else if (foundErrors) { - const dependenciesWithoutErrors = dependencies.map((depList) => - depList.filter((_, index) => !errors[index]), - ); const resultWithoutErrors = executeOrStream( + newSize, step, - dependenciesWithoutErrors, + dependencies, extra, ); if (isPromiseLike(resultWithoutErrors)) { return resultWithoutErrors.then((r) => - mergeErrorsBackIn(r, errors, dependencies[0].length), + mergeErrorsBackIn(r, errors, size), ); } else { - return mergeErrorsBackIn( - resultWithoutErrors, - errors, - dependencies[0].length, - ); + return mergeErrorsBackIn(resultWithoutErrors, errors, size); } } else { - return reallyExecuteStepWithNoErrors(step, dependencies, extra); + return reallyExecuteStepWithNoErrors(size, step, dependencies, extra); } } @@ -711,28 +782,47 @@ export function executeBucket( try { const meta = step.metaKey !== undefined ? metaByMetaKey[step.metaKey] : undefined; + const unaries: Array = []; const extra: ExecutionExtra = { + unaries, stopTime, meta, eventEmitter, _bucket: bucket, _requestContext: requestContext, }; - const dependencies: ReadonlyArray[] = []; + const dependencies: Array | null> = []; const sstep = sudo(step); const depCount = sstep.dependencies.length; if (depCount > 0 || sideEffectStepsWithErrors !== null) { for (let i = 0, l = depCount; i < l; i++) { const $dep = sstep.dependencies[i]; - dependencies[i] = store.get($dep.id)!; + if ($dep._isUnary) { + dependencies[i] = null; + unaries[i] = unaryStore.get($dep.id); + } else { + dependencies[i] = store.get($dep.id)!; + unaries[i] = null; + } } if (sideEffectStepsWithErrors !== null) { if (sstep.polymorphicPaths) { for (const path of sstep.polymorphicPaths) { for (const sideEffectStep of sideEffectStepsWithErrors[path]) { - const sideEffectStoreEntry = store.get(sideEffectStep.id)!; - if (!dependencies.includes(sideEffectStoreEntry)) { - dependencies.push(sideEffectStoreEntry); + if (sideEffectStep._isUnary) { + const sideEffectStoreEntry = unaryStore.get( + sideEffectStep.id, + )!; + if (!unaries.includes(sideEffectStoreEntry)) { + dependencies.push(null); + unaries.push(sideEffectStoreEntry); + } + } else { + const sideEffectStoreEntry = store.get(sideEffectStep.id)!; + if (!dependencies.includes(sideEffectStoreEntry)) { + dependencies.push(sideEffectStoreEntry); + unaries.push(null); + } } } } @@ -740,9 +830,18 @@ export function executeBucket( for (const sideEffectStep of sideEffectStepsWithErrors[ NO_POLY_PATH ]) { - const sideEffectStoreEntry = store.get(sideEffectStep.id)!; - if (!dependencies.includes(sideEffectStoreEntry)) { - dependencies.push(sideEffectStoreEntry); + if (sideEffectStep._isUnary) { + const sideEffectStoreEntry = unaryStore.get(sideEffectStep.id)!; + if (!unaries.includes(sideEffectStoreEntry)) { + dependencies.push(null); + unaries.push(sideEffectStoreEntry); + } + } else { + const sideEffectStoreEntry = store.get(sideEffectStep.id)!; + if (!dependencies.includes(sideEffectStoreEntry)) { + dependencies.push(sideEffectStoreEntry); + unaries.push(null); + } } } } @@ -769,7 +868,7 @@ export function executeBucket( bucket.polymorphicPathList, extra, ) - : reallyExecuteStepWithNoErrors(step, dependencies, extra); + : reallyExecuteStepWithNoErrors(size, step, dependencies, extra); if (isPromiseLike(result)) { return result.then(null, (error) => { // bucket.hasErrors = true; @@ -868,6 +967,7 @@ export function newBucket( Bucket, | "layerPlan" | "store" + | "unaryStore" | "size" | "hasErrors" | "polymorphicPathList" @@ -925,12 +1025,12 @@ export function newBucket( // Copy from spec layerPlan: spec.layerPlan, store: spec.store, + unaryStore: spec.unaryStore, size: spec.size, hasErrors: spec.hasErrors, polymorphicPathList: spec.polymorphicPathList, iterators: spec.iterators, metaByMetaKey, - isComplete: false, children: Object.create(null), }; diff --git a/grafast/grafast/src/engine/lib/withGlobalLayerPlan.ts b/grafast/grafast/src/engine/lib/withGlobalLayerPlan.ts index bc1e1b0ac9..437c2da342 100644 --- a/grafast/grafast/src/engine/lib/withGlobalLayerPlan.ts +++ b/grafast/grafast/src/engine/lib/withGlobalLayerPlan.ts @@ -1,3 +1,4 @@ +import type { ExecutableStep } from "../.."; import type { LayerPlan } from "../LayerPlan"; let globalData_layerPlan: LayerPlan | undefined = undefined; @@ -45,3 +46,7 @@ export function currentPolymorphicPaths(): ReadonlySet | null { } return globalData_polymorphicPaths; } + +export function isUnaryStep($step: ExecutableStep): boolean { + return $step._isUnary; +} diff --git a/grafast/grafast/src/index.ts b/grafast/grafast/src/index.ts index 58baa2e19c..cf766adf29 100644 --- a/grafast/grafast/src/index.ts +++ b/grafast/grafast/src/index.ts @@ -33,6 +33,7 @@ debugFactory.formatters.c = grafastPrint; import { defer, Deferred } from "./deferred.js"; // Handy for debugging import { isDev, noop } from "./dev.js"; +import { isUnaryStep } from "./engine/lib/withGlobalLayerPlan.js"; import { OperationPlan } from "./engine/OperationPlan.js"; import { GrafastError, @@ -97,6 +98,7 @@ import { StepOptimizeOptions, StepStreamOptions, TypedEventEmitter, + UnbatchedExecutionExtra, } from "./interfaces.js"; import { polymorphicWrap } from "./polymorphic.js"; import { @@ -346,6 +348,7 @@ export { isPromiseLike, isSafeError, isStreamableStep, + isUnaryStep, JSONArray, JSONObject, JSONValue, @@ -436,6 +439,7 @@ export { trackedRootValue, TypedEventEmitter, UnbatchedExecutableStep, + UnbatchedExecutionExtra, }; exportAsMany("grafast", { @@ -548,6 +552,7 @@ exportAsMany("grafast", { LoadStep, isSafeError, SafeError, + isUnaryStep, }); export { hookArgs } from "./args.js"; diff --git a/grafast/grafast/src/interfaces.ts b/grafast/grafast/src/interfaces.ts index 154a711109..23b522cea0 100644 --- a/grafast/grafast/src/interfaces.ts +++ b/grafast/grafast/src/interfaces.ts @@ -757,7 +757,7 @@ export type ExecutionEventMap = { export type ExecutionEventEmitter = TypedEventEmitter; -export interface ExecutionExtra { +export interface ExecutionExtraBase { /** The `performance.now()` at which your step should stop executing */ stopTime: number | null; /** If you have set a `metaKey` on your step, the relevant meta object which you can write into (e.g. for caching) */ @@ -771,6 +771,11 @@ export interface ExecutionExtra { /** @internal */ _requestContext: RequestTools; } +export interface ExecutionExtra extends ExecutionExtraBase { + /** The results for the unary dependencies the step used */ + unaries: Record; +} +export interface UnbatchedExecutionExtra extends ExecutionExtraBase {} export interface LocationDetails { node: ASTNode | readonly ASTNode[]; diff --git a/grafast/grafast/src/prepare.ts b/grafast/grafast/src/prepare.ts index 7b68963441..113790768e 100644 --- a/grafast/grafast/src/prepare.ts +++ b/grafast/grafast/src/prepare.ts @@ -293,31 +293,25 @@ function executePreemptive( ): PromiseOrDirect< ExecutionResult | AsyncGenerator > { - // PERF: batch this method so it can process multiple GraphQL requests in parallel - - // TODO: when we batch, we need to change `rootBucketIndex` and `size`, and make sure that we only batch where `executionTimeout` is the same. const rootBucketIndex = 0; const size = 1; - const requestIndex = [0]; - const vars = [variableValues]; - const ctxs = [context]; - const rvs = [rootValue]; const polymorphicPathList = [POLYMORPHIC_ROOT_PATH]; const iterators: Array | Iterator>> = [new Set()]; const store: Bucket["store"] = new Map(); - store.set(-1, requestIndex); - store.set(operationPlan.rootLayerPlan.rootStep!.id, requestIndex); - store.set(operationPlan.variableValuesStep.id, vars); - store.set(operationPlan.contextStep.id, ctxs); - store.set(operationPlan.rootValueStep.id, rvs); + const unaryStore = new Map(); + unaryStore.set(operationPlan.rootLayerPlan.rootStep!.id, 0); + unaryStore.set(operationPlan.variableValuesStep.id, variableValues); + unaryStore.set(operationPlan.contextStep.id, context); + unaryStore.set(operationPlan.rootValueStep.id, rootValue); const rootBucket = newBucket( { layerPlan: operationPlan.rootLayerPlan, size, store, + unaryStore, hasErrors: false, polymorphicPathList, iterators, @@ -346,16 +340,21 @@ function executePreemptive( index: number, ): PromiseOrDirect> { const layerPlan = subscriptionLayerPlan!; + const { copyUnaryStepIds, copyBatchStepIds, rootStep } = layerPlan; // PERF: we could consider batching this. const store: Bucket["store"] = new Map(); + const unaryStore = new Map(); const subscriptionBucketIndex = 0; - for (const depId of layerPlan.copyStepIds) { + for (const depId of layerPlan.copyUnaryStepIds) { + unaryStore.set(depId, rootBucket.unaryStore.get(depId)); + } + for (const depId of layerPlan.copyBatchStepIds) { store.set(depId, []); } - store.set(layerPlan.rootStep!.id, [payload]); - for (const depId of layerPlan.copyStepIds) { + store.set(rootStep!.id, [payload]); + for (const depId of layerPlan.copyBatchStepIds) { store.get(depId)![subscriptionBucketIndex] = rootBucket.store.get(depId)![rootBucketIndex]; } @@ -364,6 +363,7 @@ function executePreemptive( { layerPlan, store, + unaryStore, hasErrors: rootBucket.hasErrors, polymorphicPathList: [POLYMORPHIC_ROOT_PATH], iterators: [new Set()], @@ -504,9 +504,7 @@ function executePreemptive( rootBucketIndex, requestContext, [], - rootBucket.store.get(operationPlan.variableValuesStep.id)![ - rootBucketIndex - ], + rootBucket.unaryStore.get(operationPlan.variableValuesStep.id), outputDataAsString, ); return finalize( @@ -732,6 +730,7 @@ async function processStream( const _processQueue = (entries: ResultTuple[]) => { const size = entries.length; const store: Bucket["store"] = new Map(); + const unaryStore = new Map(); const polymorphicPathList: (string | null)[] = []; const iterators: Array | Iterator>> = []; @@ -750,8 +749,11 @@ async function processStream( const listItemStepIdList: any[] = []; store.set(listItemStepId, listItemStepIdList); - for (const copyPlanId of directLayerPlanChild.copyStepIds) { - store.set(copyPlanId, []); + for (const copyStepId of directLayerPlanChild.copyUnaryStepIds) { + unaryStore.set(copyStepId, spec.bucket.unaryStore.get(copyStepId)); + } + for (const copyStepId of directLayerPlanChild.copyBatchStepIds) { + store.set(copyStepId, []); } let bucketIndex = 0; @@ -762,15 +764,15 @@ async function processStream( polymorphicPathList[bucketIndex] = spec.bucket.polymorphicPathList[spec.bucketIndex]; iterators[bucketIndex] = new Set(); - for (const copyPlanId of directLayerPlanChild.copyStepIds) { - const list = spec.bucket.store.get(copyPlanId); + for (const copyStepId of directLayerPlanChild.copyBatchStepIds) { + const list = spec.bucket.store.get(copyStepId); if (!list) { throw new Error( - `GrafastInternalError<2db7b749-399f-486b-bd12-7ca337b937e4>: ${spec.bucket.layerPlan} doesn't seem to include ${copyPlanId} (required by ${directLayerPlanChild} via ${spec.outputPlan})`, + `GrafastInternalError<2db7b749-399f-486b-bd12-7ca337b937e4>: ${spec.bucket.layerPlan} doesn't seem to include ${copyStepId} (required by ${directLayerPlanChild} via ${spec.outputPlan})`, ); } // PERF: optimize away these .get calls - store.get(copyPlanId)![bucketIndex] = list[spec.bucketIndex]; + store.get(copyStepId)![bucketIndex] = list[spec.bucketIndex]; } // PERF: we should be able to optimize this bucketIndex++; @@ -789,6 +791,7 @@ async function processStream( layerPlan: directLayerPlanChild, size, store, + unaryStore, hasErrors: false, polymorphicPathList, iterators, @@ -917,11 +920,29 @@ function processSingleDeferred( ) { const size = specs.length; const store: Bucket["store"] = new Map(); + + const unaryStore = new Map(); + const polymorphicPathList: (string | null)[] = []; const iterators: Array | Iterator>> = []; - for (const copyPlanId of outputPlan.layerPlan.copyStepIds) { - store.set(copyPlanId, []); + // HACK: when we re-write stream/defer this needs fixing. + const firstBucket = specs[0][1].bucket; + if (isDev) { + for (const spec of specs) { + if (spec[1].bucket !== firstBucket) { + throw new Error( + `GrafastInternalError<>: sorry, it seems the unary dependencies feature broke our incremental delivery support. This incremental delivery is going to be fully rewritten at some point anyway, so we recommend you avoid using it for now (the spec itself has changed since we implemented it).`, + ); + } + } + } + + for (const copyStepId of outputPlan.layerPlan.copyUnaryStepIds) { + unaryStore.set(copyStepId, firstBucket.unaryStore.get(copyStepId)); + } + for (const copyStepId of outputPlan.layerPlan.copyBatchStepIds) { + store.set(copyStepId, []); } let bucketIndex = 0; @@ -929,9 +950,9 @@ function processSingleDeferred( polymorphicPathList[bucketIndex] = spec.bucket.polymorphicPathList[spec.bucketIndex]; iterators[bucketIndex] = new Set(); - for (const copyPlanId of outputPlan.layerPlan.copyStepIds) { - store.get(copyPlanId)![bucketIndex] = - spec.bucket.store.get(copyPlanId)![spec.bucketIndex]; + for (const copyStepId of outputPlan.layerPlan.copyBatchStepIds) { + store.get(copyStepId)![bucketIndex] = + spec.bucket.store.get(copyStepId)![spec.bucketIndex]; } // PERF: we should be able to optimize this bucketIndex++; @@ -950,6 +971,7 @@ function processSingleDeferred( layerPlan: outputPlan.layerPlan, size, store, + unaryStore, hasErrors: false, polymorphicPathList, iterators, diff --git a/grafast/grafast/src/step.ts b/grafast/grafast/src/step.ts index 77b44892c1..a9b4adcede 100644 --- a/grafast/grafast/src/step.ts +++ b/grafast/grafast/src/step.ts @@ -26,10 +26,12 @@ import type { PromiseOrDirect, StepOptimizeOptions, StepOptions, + UnbatchedExecutionExtra, } from "./interfaces.js"; import { $$subroutine } from "./interfaces.js"; import type { __ItemStep } from "./steps/index.js"; import { __ListTransformStep } from "./steps/index.js"; +import { arrayOfLength } from "./utils.js"; /** * @internal @@ -121,6 +123,10 @@ export abstract class BaseStep { public [$$subroutine]: LayerPlan | null = null; public isArgumentsFinalized: boolean; public isFinalized: boolean; + /** @internal */ + public _isUnary: boolean; + /** @internal */ + public _isUnaryLocked: boolean; public debug: boolean; // ENHANCE: change hasSideEffects to getter/setter, forbid setting after a @@ -139,6 +145,8 @@ export abstract class BaseStep { const layerPlan = currentLayerPlan(); this.layerPlan = layerPlan; this.operationPlan = layerPlan.operationPlan; + this._isUnary = true; + this._isUnaryLocked = false; } public toString(): string { @@ -347,6 +355,11 @@ export /* abstract */ class ExecutableStep extends BaseStep { )}'`, ); } + if (this._isUnaryLocked && this._isUnary && !step._isUnary) { + throw new Error( + `${this} is a unary step, so cannot add non-unary step ${step} as a dependency`, + ); + } if (isDev) { // Check that we can actually add this as a dependency if (!this.layerPlan.ancestry.includes(step.layerPlan)) { @@ -371,6 +384,15 @@ export /* abstract */ class ExecutableStep extends BaseStep { return this.operationPlan.stepTracker.addStepDependency(this, step); } + /** + * Adds "unary" dependencies; in `execute(count, values, extra)` you'll + * be able to access the value via `extra.unaries[key]` where `key` is the + * return value of this function. + */ + protected addUnaryDependency(step: ExecutableStep): string | number { + return this.operationPlan.stepTracker.addStepUnaryDependency(this, step); + } + /** * Given a list of "peer" steps, return a list of these `peers` that are * equivalent to this step. @@ -451,7 +473,23 @@ export /* abstract */ class ExecutableStep extends BaseStep { count; values; extra; - throw new Error(`${this} has not implemented an 'execute' method`); + throw new Error( + `${this} has not implemented an 'executeV2' or 'execute' method`, + ); + } + + // This executeV2 method implements backwards compatibility with the old + // execute method; you should instead override this in your own step + // classes. + executeV2( + count: number, + values: ReadonlyArray | null>, + extra: ExecutionExtra, + ): PromiseOrDirect> { + const backfilledValues = values.map((v, i) => + v === null ? arrayOfLength(count, extra.unaries[i]) : v, + ); + return this.execute(count, backfilledValues, extra); } public destroy(): void { @@ -590,7 +628,7 @@ export abstract class UnbatchedExecutableStep< } abstract unbatchedExecute( - extra: ExecutionExtra, + extra: UnbatchedExecutionExtra, ...tuple: any[] ): PromiseOrDirect; } @@ -673,6 +711,16 @@ export type StreamableStep = ExecutableStep> & { }, ): PromiseOrDirect>; }; +export type StreamV2ableStep = ExecutableStep> & { + streamV2( + count: number, + values: ReadonlyArray | null>, + extra: ExecutionExtra, + streamOptions: { + initialCount: number; + }, + ): PromiseOrDirect>; +}; export function isStreamableStep( plan: ExecutableStep>, @@ -680,6 +728,12 @@ export function isStreamableStep( return typeof (plan as StreamableStep).stream === "function"; } +export function isStreamV2ableStep( + plan: ExecutableStep>, +): plan is StreamV2ableStep { + return typeof (plan as StreamV2ableStep).streamV2 === "function"; +} + export type PolymorphicStep = ExecutableStep & { planForType(objectType: GraphQLObjectType): ExecutableStep; }; diff --git a/grafast/grafast/src/steps/__inputDynamicScalar.ts b/grafast/grafast/src/steps/__inputDynamicScalar.ts index 60f55187ca..eec67a990e 100644 --- a/grafast/grafast/src/steps/__inputDynamicScalar.ts +++ b/grafast/grafast/src/steps/__inputDynamicScalar.ts @@ -7,7 +7,7 @@ import type { import * as graphql from "graphql"; import { SafeError } from "../error.js"; -import type { ExecutionExtra } from "../interfaces.js"; +import type { UnbatchedExecutionExtra } from "../interfaces.js"; import { UnbatchedExecutableStep } from "../step.js"; import type { __TrackedValueStep } from "./__trackedValue.js"; @@ -122,7 +122,7 @@ export class __InputDynamicScalarStep< } unbatchedExecute = ( - _extra: ExecutionExtra, + _extra: UnbatchedExecutionExtra, ...variableValues: any[] ): TLeaf => { const converted = this.valueFromValues(variableValues); diff --git a/grafast/grafast/src/steps/__inputObject.ts b/grafast/grafast/src/steps/__inputObject.ts index 85ff826e39..0a198a1ec0 100644 --- a/grafast/grafast/src/steps/__inputObject.ts +++ b/grafast/grafast/src/steps/__inputObject.ts @@ -3,9 +3,9 @@ import te from "tamedevil"; import { inputStep } from "../input.js"; import type { - ExecutionExtra, InputStep, NotVariableValueNode, + UnbatchedExecutionExtra, } from "../interfaces.js"; import { UnbatchedExecutableStep } from "../step.js"; import { defaultValueToValueNode } from "../utils.js"; @@ -102,7 +102,7 @@ export class __InputObjectStep< super.finalize(); } - unbatchedExecute(_extra: ExecutionExtra, ...values: any[]) { + unbatchedExecute(_extra: UnbatchedExecutionExtra, ...values: any[]) { const resultValues = Object.create(null); for (const inputFieldName in this.inputFields) { const dependencyIndex = this.inputFields[inputFieldName].dependencyIndex; diff --git a/grafast/grafast/src/steps/__item.ts b/grafast/grafast/src/steps/__item.ts index e51e7006ca..9fdd8d7452 100644 --- a/grafast/grafast/src/steps/__item.ts +++ b/grafast/grafast/src/steps/__item.ts @@ -28,6 +28,8 @@ export class __ItemStep extends UnbatchedExecutableStep { ) { super(); this.addDependency(parentPlan); + this._isUnary = false; + this._isUnaryLocked = true; } toStringMeta(): string { diff --git a/grafast/grafast/src/steps/__trackedValue.ts b/grafast/grafast/src/steps/__trackedValue.ts index 11686aa360..95fc5809b1 100644 --- a/grafast/grafast/src/steps/__trackedValue.ts +++ b/grafast/grafast/src/steps/__trackedValue.ts @@ -16,9 +16,9 @@ import { import type { Constraint } from "../constraints.js"; import { __ListTransformStep } from "../index.js"; import type { - ExecutionExtra, GrafastResultsList, GrafastValuesList, + UnbatchedExecutionExtra, } from "../interfaces.js"; import { UnbatchedExecutableStep } from "../step.js"; import type { __ValueStep } from "./__value.js"; @@ -159,7 +159,7 @@ export class __TrackedValueStep< return values[0]; } - unbatchedExecute(_extra: ExecutionExtra, v: TData): TData { + unbatchedExecute(_extra: UnbatchedExecutionExtra, v: TData): TData { return v; } diff --git a/grafast/grafast/src/steps/access.ts b/grafast/grafast/src/steps/access.ts index 561c7ef138..f765428135 100644 --- a/grafast/grafast/src/steps/access.ts +++ b/grafast/grafast/src/steps/access.ts @@ -4,7 +4,7 @@ import type { TE } from "tamedevil"; import te from "tamedevil"; import { inspect } from "../inspect.js"; -import type { ExecutionExtra } from "../interfaces.js"; +import type { ExecutionExtra, UnbatchedExecutionExtra } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; import { UnbatchedExecutableStep } from "../step.js"; @@ -204,7 +204,7 @@ export class AccessStep extends UnbatchedExecutableStep { super.finalize(); } - unbatchedExecute(_extra: ExecutionExtra, ..._values: any[]): any { + unbatchedExecute(_extra: UnbatchedExecutionExtra, ..._values: any[]): any { throw new Error( `${this}: should have had unbatchedExecute method replaced`, ); diff --git a/grafast/grafast/src/steps/applyTransforms.ts b/grafast/grafast/src/steps/applyTransforms.ts index 4e187ba402..8c3529d1e4 100644 --- a/grafast/grafast/src/steps/applyTransforms.ts +++ b/grafast/grafast/src/steps/applyTransforms.ts @@ -81,9 +81,10 @@ export class ApplyTransformsStep extends ExecutableStep { const bucket = extra._bucket; const childLayerPlan = this.subroutineLayer; - const copyStepIds = childLayerPlan.copyStepIds; + const { copyBatchStepIds, copyUnaryStepIds, rootStep } = childLayerPlan; const store: Bucket["store"] = new Map(); + const unaryStore = new Map(); const polymorphicPathList: (string | null)[] = []; const iterators: Array | Iterator>> = []; const map: Map = new Map(); @@ -100,14 +101,24 @@ export class ApplyTransformsStep extends ExecutableStep { } store.set(itemStepId, []); - // Prepare store with an empty list for each copyPlanId - for (const planId of copyStepIds) { - store.set(planId, []); - if (!bucket.store.has(planId)) { + for (const stepId of copyUnaryStepIds) { + unaryStore.set(stepId, bucket.unaryStore.get(stepId)); + if (isDev && !bucket.unaryStore.has(stepId)) { throw new Error( - `GrafastInternalError<14f2b4c6-f951-44d6-ad6b-2eace3330b84>: plan '${planId}' (${this.operationPlan.dangerouslyGetStep( - planId, - )}) listed in copyStepIds but not available in parent bucket for ${this}`, + `GrafastInternalError<68675bbd-bc15-4c4a-902a-61c0de616325>: unary step '${stepId}' (${this.operationPlan.dangerouslyGetStep( + stepId, + )}) listed in copyUnaryStepIds but not available in parent bucket for ${this}`, + ); + } + } + // Prepare store with an empty list for each copyBatchPlanId + for (const stepId of copyBatchStepIds) { + store.set(stepId, []); + if (isDev && !bucket.store.has(stepId)) { + throw new Error( + `GrafastInternalError<14f2b4c6-f951-44d6-ad6b-2eace3330b84>: step '${stepId}' (${this.operationPlan.dangerouslyGetStep( + stepId, + )}) listed in copyBatchStepIds but not available in parent bucket for ${this}`, ); } } @@ -134,9 +145,9 @@ export class ApplyTransformsStep extends ExecutableStep { // so we need to ensure any streams are cleaned up. iterators[newIndex] = bucket.iterators[originalIndex]; store.get(itemStepId)![newIndex] = list[j]; - for (const planId of copyStepIds) { - store.get(planId)![newIndex] = - bucket.store.get(planId)![originalIndex]; + for (const stepId of copyBatchStepIds) { + store.get(stepId)![newIndex] = + bucket.store.get(stepId)![originalIndex]; } } } @@ -148,6 +159,7 @@ export class ApplyTransformsStep extends ExecutableStep { layerPlan: childLayerPlan, size, store, + unaryStore, hasErrors: bucket.hasErrors, polymorphicPathList, iterators, @@ -157,7 +169,7 @@ export class ApplyTransformsStep extends ExecutableStep { await executeBucket(childBucket, extra._requestContext); } - const depResults = store.get(childLayerPlan.rootStep!.id)!; + const depResults = store.get(rootStep!.id)!; return listValues.map((list: any, originalIndex: number) => { if (list == null) { diff --git a/grafast/grafast/src/steps/connection.ts b/grafast/grafast/src/steps/connection.ts index d7caae44d5..4eee7adc2d 100644 --- a/grafast/grafast/src/steps/connection.ts +++ b/grafast/grafast/src/steps/connection.ts @@ -1,8 +1,8 @@ import * as assert from "../assert.js"; import type { - ExecutionExtra, GrafastResultsList, InputStep, + UnbatchedExecutionExtra, } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; import { UnbatchedExecutableStep } from "../step.js"; @@ -452,7 +452,11 @@ export class EdgeStep< } } - unbatchedExecute(_extra: ExecutionExtra, record: any, cursor: any): any { + unbatchedExecute( + _extra: UnbatchedExecutionExtra, + record: any, + cursor: any, + ): any { // Handle nulls; everything else comes from the child plans return record == null && (this.cursorDepId == null || cursor == null) ? null diff --git a/grafast/grafast/src/steps/first.ts b/grafast/grafast/src/steps/first.ts index 6a90599d41..3a262be6ae 100644 --- a/grafast/grafast/src/steps/first.ts +++ b/grafast/grafast/src/steps/first.ts @@ -1,7 +1,7 @@ import type { - ExecutionExtra, GrafastResultsList, GrafastValuesList, + UnbatchedExecutionExtra, } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; import { UnbatchedExecutableStep } from "../step.js"; @@ -32,7 +32,7 @@ export class FirstStep extends UnbatchedExecutableStep { return result; } - unbatchedExecute(_extra: ExecutionExtra, list: any[]) { + unbatchedExecute(_extra: UnbatchedExecutionExtra, list: any[]) { return list?.[0]; } diff --git a/grafast/grafast/src/steps/graphqlResolver.ts b/grafast/grafast/src/steps/graphqlResolver.ts index b40c0d5c2d..4bf683211f 100644 --- a/grafast/grafast/src/steps/graphqlResolver.ts +++ b/grafast/grafast/src/steps/graphqlResolver.ts @@ -14,6 +14,7 @@ import type { GrafastResultsList, GrafastResultStreamList, GrafastValuesList, + UnbatchedExecutionExtra, } from "../interfaces.js"; import { polymorphicWrap } from "../polymorphic.js"; import type { PolymorphicStep } from "../step.js"; @@ -112,7 +113,7 @@ export class GraphQLResolverStep extends UnbatchedExecutableStep { } unbatchedExecute( - _extra: ExecutionExtra, + _extra: UnbatchedExecutionExtra, source: any, args: any, context: any, diff --git a/grafast/grafast/src/steps/lambda.ts b/grafast/grafast/src/steps/lambda.ts index 1426dda492..1885fc118f 100644 --- a/grafast/grafast/src/steps/lambda.ts +++ b/grafast/grafast/src/steps/lambda.ts @@ -1,6 +1,6 @@ import type { - ExecutionExtra, PromiseOrDirect, + UnbatchedExecutionExtra, UnwrapPlanTuple, } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; @@ -47,7 +47,10 @@ export class LambdaStep extends UnbatchedExecutableStep { return peers.filter((peer) => peer.fn === this.fn); } - unbatchedExecute(_extra: ExecutionExtra, value: TIn): PromiseOrDirect { + unbatchedExecute( + _extra: UnbatchedExecutionExtra, + value: TIn, + ): PromiseOrDirect { return this.fn(value); } } diff --git a/grafast/grafast/src/steps/last.ts b/grafast/grafast/src/steps/last.ts index f5d0a4504a..cb3ca63ff4 100644 --- a/grafast/grafast/src/steps/last.ts +++ b/grafast/grafast/src/steps/last.ts @@ -1,4 +1,4 @@ -import type { ExecutionExtra } from "../interfaces.js"; +import type { UnbatchedExecutionExtra } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; import { UnbatchedExecutableStep } from "../step.js"; import { ListStep } from "./list.js"; @@ -17,7 +17,7 @@ export class LastStep extends UnbatchedExecutableStep { } unbatchedExecute = ( - _extra: ExecutionExtra, + _extra: UnbatchedExecutionExtra, list: ReadonlyArray, ): TData => { return list?.[list?.length - 1]; diff --git a/grafast/grafast/src/steps/list.ts b/grafast/grafast/src/steps/list.ts index b15b94d255..6122ac5f52 100644 --- a/grafast/grafast/src/steps/list.ts +++ b/grafast/grafast/src/steps/list.ts @@ -1,6 +1,6 @@ import type { - ExecutionExtra, StepOptimizeOptions, + UnbatchedExecutionExtra, UnwrapPlanTuple, } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; @@ -41,7 +41,7 @@ export class ListStep< } unbatchedExecute( - _extra: ExecutionExtra, + _extra: UnbatchedExecutionExtra, ...values: any[] //UnwrapPlanTuple, ): UnwrapPlanTuple { return values as any; diff --git a/grafast/grafast/src/steps/listTransform.ts b/grafast/grafast/src/steps/listTransform.ts index e20a56f409..bb898d833b 100644 --- a/grafast/grafast/src/steps/listTransform.ts +++ b/grafast/grafast/src/steps/listTransform.ts @@ -204,9 +204,10 @@ export class __ListTransformStep< const bucket = extra._bucket; const childLayerPlan = this.subroutineLayer; - const copyStepIds = childLayerPlan.copyStepIds; + const { copyUnaryStepIds, copyBatchStepIds, rootStep } = childLayerPlan; const store: Bucket["store"] = new Map(); + const unaryStore = new Map(); const polymorphicPathList: (string | null)[] = []; const iterators: Array | Iterator>> = []; const map: Map = new Map(); @@ -223,14 +224,24 @@ export class __ListTransformStep< } store.set(itemStepId, []); + for (const stepId of copyUnaryStepIds) { + unaryStore.set(stepId, bucket.unaryStore.get(stepId)); + if (isDev && !bucket.unaryStore.has(stepId)) { + throw new Error( + `GrafastInternalError<2be5c2c6-a7f8-4002-93a0-6ace5a89a962>: unary step '${stepId}' (${this.operationPlan.dangerouslyGetStep( + stepId, + )}) listed in copyUnaryStepIds but not available in parent bucket for ${this}`, + ); + } + } // Prepare store with an empty list for each copyPlanId - for (const planId of copyStepIds) { - store.set(planId, []); - if (!bucket.store.has(planId)) { + for (const stepId of copyBatchStepIds) { + store.set(stepId, []); + if (isDev && !bucket.store.has(stepId)) { throw new Error( - `GrafastInternalError<14f2b4c6-f951-44d6-ad6b-2eace3330b84>: plan '${planId}' (${this.operationPlan.dangerouslyGetStep( - planId, - )}) listed in copyStepIds but not available in parent bucket for ${this}`, + `GrafastInternalError<26f20f5a-a38a-4f0d-8889-f04bc56d95b3>: step '${stepId}' (${this.operationPlan.dangerouslyGetStep( + stepId, + )}) listed in copyBatchStepIds but not available in parent bucket for ${this}`, ); } } @@ -257,7 +268,7 @@ export class __ListTransformStep< // so we need to ensure any streams are cleaned up. iterators[newIndex] = bucket.iterators[originalIndex]; store.get(itemStepId)![newIndex] = list[j]; - for (const planId of copyStepIds) { + for (const planId of copyBatchStepIds) { store.get(planId)![newIndex] = bucket.store.get(planId)![originalIndex]; } @@ -271,6 +282,7 @@ export class __ListTransformStep< layerPlan: childLayerPlan, size, store, + unaryStore, hasErrors: bucket.hasErrors, polymorphicPathList, iterators, @@ -280,7 +292,7 @@ export class __ListTransformStep< await executeBucket(childBucket, extra._requestContext); } - const depResults = store.get(childLayerPlan.rootStep!.id)!; + const depResults = store.get(rootStep!.id)!; return listValues.map((list: any, originalIndex: number) => { if (list == null) { diff --git a/grafast/grafast/src/steps/load.ts b/grafast/grafast/src/steps/load.ts index b5e99e407d..4675da2c43 100644 --- a/grafast/grafast/src/steps/load.ts +++ b/grafast/grafast/src/steps/load.ts @@ -222,7 +222,7 @@ export class LoadStep< ); } } - listItem($item: __ItemStep) { + listItem($item: __ItemStep) { return new LoadedRecordStep( $item, false, diff --git a/grafast/grafast/src/steps/node.ts b/grafast/grafast/src/steps/node.ts index dca9df4746..3fef483e49 100644 --- a/grafast/grafast/src/steps/node.ts +++ b/grafast/grafast/src/steps/node.ts @@ -4,9 +4,9 @@ import { isDev } from "../dev.js"; import { inspect } from "../inspect.js"; import type { AnyInputStep, - ExecutionExtra, NodeIdHandler, PolymorphicData, + UnbatchedExecutionExtra, } from "../interfaces.js"; import { polymorphicWrap } from "../polymorphic.js"; import type { ExecutableStep, PolymorphicStep } from "../step.js"; @@ -74,7 +74,7 @@ export class NodeStep } unbatchedExecute = ( - _extra: ExecutionExtra, + _extra: UnbatchedExecutionExtra, specifier: any, ): PolymorphicData> | null => { const typeName = specifier diff --git a/grafast/grafast/src/steps/object.ts b/grafast/grafast/src/steps/object.ts index 210abd4a87..d50880fb2d 100644 --- a/grafast/grafast/src/steps/object.ts +++ b/grafast/grafast/src/steps/object.ts @@ -2,7 +2,11 @@ import te, { isSafeObjectPropertyName } from "tamedevil"; -import type { ExecutionExtra, StepOptimizeOptions } from "../interfaces.js"; +import type { + ExecutionExtra, + StepOptimizeOptions, + UnbatchedExecutionExtra, +} from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; import { UnbatchedExecutableStep } from "../step.js"; import { constant, ConstantStep } from "./constant.js"; @@ -223,7 +227,7 @@ ${inner} return result; } - unbatchedExecute(_extra: ExecutionExtra, ..._values: any[]): any { + unbatchedExecute(_extra: UnbatchedExecutionExtra, ..._values: any[]): any { throw new Error(`${this} didn't finalize? No unbatchedExecute method.`); } diff --git a/grafast/grafast/src/steps/proxy.ts b/grafast/grafast/src/steps/proxy.ts index 2e1f770e90..7868a92a15 100644 --- a/grafast/grafast/src/steps/proxy.ts +++ b/grafast/grafast/src/steps/proxy.ts @@ -1,5 +1,5 @@ import type { GrafastResultsList, GrafastValuesList } from "../index.js"; -import type { ExecutionExtra } from "../interfaces.js"; +import type { UnbatchedExecutionExtra } from "../interfaces.js"; import { $$proxy } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; import { UnbatchedExecutableStep } from "../step.js"; @@ -35,7 +35,7 @@ export class ProxyStep extends UnbatchedExecutableStep { ): GrafastResultsList { return values[0]; } - unbatchedExecute(_extra: ExecutionExtra, value: T): T { + unbatchedExecute(_extra: UnbatchedExecutionExtra, value: T): T { return value; } // Do not proxy stream requests diff --git a/grafast/grafast/src/steps/remapKeys.ts b/grafast/grafast/src/steps/remapKeys.ts index 7921b98fdf..e1ad7ec6da 100644 --- a/grafast/grafast/src/steps/remapKeys.ts +++ b/grafast/grafast/src/steps/remapKeys.ts @@ -3,9 +3,9 @@ import chalk from "chalk"; import te, { isSafeObjectPropertyName } from "tamedevil"; import type { - ExecutionExtra, GrafastResultsList, GrafastValuesList, + UnbatchedExecutionExtra, } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; import { UnbatchedExecutableStep } from "../step.js"; @@ -106,7 +106,7 @@ export class RemapKeysStep extends UnbatchedExecutableStep { return values[0].map(this.mapper); } - unbatchedExecute(_extra: ExecutionExtra, value: any): any { + unbatchedExecute(_extra: UnbatchedExecutionExtra, value: any): any { return this.mapper(value); } diff --git a/grafast/grafast/src/steps/reverse.ts b/grafast/grafast/src/steps/reverse.ts index 4bd6d76c98..cb261ec5b4 100644 --- a/grafast/grafast/src/steps/reverse.ts +++ b/grafast/grafast/src/steps/reverse.ts @@ -1,7 +1,7 @@ import type { - ExecutionExtra, GrafastResultsList, GrafastValuesList, + UnbatchedExecutionExtra, } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; import { UnbatchedExecutableStep } from "../step.js"; @@ -48,7 +48,7 @@ export class ReverseStep extends UnbatchedExecutableStep< return values[0].map((arr) => (arr == null ? arr : reverseArray(arr))); } - unbatchedExecute(_extra: ExecutionExtra, arr: TData[]): TData[] { + unbatchedExecute(_extra: UnbatchedExecutionExtra, arr: TData[]): TData[] { return arr == null ? arr : reverseArray(arr); } diff --git a/grafast/grafast/src/steps/sideEffect.ts b/grafast/grafast/src/steps/sideEffect.ts index 7beffe532a..0980bd9f85 100644 --- a/grafast/grafast/src/steps/sideEffect.ts +++ b/grafast/grafast/src/steps/sideEffect.ts @@ -1,6 +1,6 @@ import type { - ExecutionExtra, PromiseOrDirect, + UnbatchedExecutionExtra, UnwrapPlanTuple, } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; @@ -32,7 +32,10 @@ export class SideEffectStep extends UnbatchedExecutableStep { return (this.fn as any).displayName || this.fn.name; } - unbatchedExecute(_extra: ExecutionExtra, value: TIn): PromiseOrDirect { + unbatchedExecute( + _extra: UnbatchedExecutionExtra, + value: TIn, + ): PromiseOrDirect { return this.fn(value); } } diff --git a/grafast/website/src/pages/errors/ud.mdx b/grafast/website/src/pages/errors/ud.mdx new file mode 100644 index 0000000000..dc510acf12 --- /dev/null +++ b/grafast/website/src/pages/errors/ud.mdx @@ -0,0 +1,3 @@ +# Unary dependencies + +TODO: detail this error code diff --git a/utils/tamedevil/src/index.ts b/utils/tamedevil/src/index.ts index 3d5592189d..2b9da1ad33 100644 --- a/utils/tamedevil/src/index.ts +++ b/utils/tamedevil/src/index.ts @@ -143,6 +143,21 @@ function isTE(node: unknown): node is TE { ); } +function debug(expression: TE) { + const result = te.compile(expression); + const argNames = Object.keys(result.refs); + const fn = newFunction(...argNames, result.string); + const string = fn.toString(); + const lines = string.split(/\r?\n/); + const maxLineLength = String(lines.length).length; + const output = lines.map( + (line, i) => `${String(i + 1).padStart(maxLineLength, " ")}: ${line}`, + ); + console.log(`Outputting expression from tamedevil:`); + console.dir(result.refs); + console.log(output.join("\n")); +} + /** * If the given node is a valid TE node it will be returned, otherwise an error * will be thrown. @@ -1122,6 +1137,7 @@ export { /** @deprecated Use safeKeyOrThrow instead */ safeKeyOrThrow as dangerousKey, dangerouslyIncludeRawCode, + debug, run as eval, get, identifier, @@ -1184,6 +1200,7 @@ export interface TamedEvil { undefined: TE; blank: TE; isTE: typeof isTE; + debug: typeof debug; dangerouslyIncludeRawCode: typeof dangerouslyIncludeRawCode; } @@ -1216,6 +1233,7 @@ const attributes = { undefined: undefinedNode, blank: blankNode, isTE, + debug, dangerouslyIncludeRawCode, }; From a87c024413f411b7344f175da0307a3323f02f97 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 21 Feb 2024 16:55:08 +0000 Subject: [PATCH 05/48] Fix LayerPlan optimized --- grafast/grafast/src/engine/LayerPlan.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/grafast/grafast/src/engine/LayerPlan.ts b/grafast/grafast/src/engine/LayerPlan.ts index 7b62e00f96..c2b04bbfd2 100644 --- a/grafast/grafast/src/engine/LayerPlan.ts +++ b/grafast/grafast/src/engine/LayerPlan.ts @@ -369,7 +369,7 @@ export class LayerPlan { public finalize(): void { if ( - this.reason.type === "nullableBoundary" || + // this.reason.type === "nullableBoundary" || this.reason.type === "listItem" ) { const u = this.copyUnaryStepIds.length; @@ -522,7 +522,8 @@ export class LayerPlan { ); } // Item steps are **NOT** unary - store.set(itemStepId, []); + const itemStepIdList: any[] = []; + store.set(itemStepId, itemStepIdList); for (const stepId of copyUnaryStepIds) { unaryStore.set(stepId, parentBucket.unaryStore.get(stepId)); @@ -547,7 +548,7 @@ export class LayerPlan { for (let j = 0, l = list.length; j < l; j++) { const newIndex = size++; newIndexes.push(newIndex); - store.get(itemStepId)![newIndex] = list[j]; + itemStepIdList[newIndex] = list[j]; polymorphicPathList[newIndex] = parentBucket.polymorphicPathList[originalIndex]; @@ -743,6 +744,7 @@ ${inner} layerPlan: this, size, store, + unaryStore, // PERF: not necessarily, if we don't copy the errors, we don't have the errors. hasErrors: parentBucket.hasErrors, polymorphicPathList, @@ -756,7 +758,7 @@ ${inner} return null; } })`; - te.debug(expr); + // te.debug(expr); return expr; } @@ -767,6 +769,9 @@ function newBucketFactoryInnerExpression( reasonType: "nullableBoundary" | "listItem", ) { if (reasonType === "nullableBoundary") { + if (Math.random() < 2) { + throw new Error("This code no longer works since we added unary steps."); + } // PERF: if parent bucket has no nulls/errors in itemStepId // then we can just copy everything wholesale rather than building // new arrays and looping. @@ -840,7 +845,7 @@ ${te.join(copyBlocks, "")} const te_i = te.lit(i); blocks.push( te`\ - unaryStore.set(copyUnaryStepIds[${te_i}], parentBucket.store.get(copyUnaryStepIds[${te_i}])); + unaryStore.set(copyUnaryStepIds[${te_i}], parentBucket.unaryStore.get(copyUnaryStepIds[${te_i}])); `, ); } @@ -863,7 +868,11 @@ ${te.join(copyBlocks, "")} signature, reasonType, te`\ - const listStepStore = parentBucket.store.get(this.reason.parentStep.id); + const listStepId = this.reason.parentStep.id; + const listStepStore = + this.reason.parentStep._isUnary + ? [parentBucket.unaryStore.get(listStepId)] + : parentBucket.store.get(listStepId); const itemStepIdList = []; store.set(this.rootStep.id, itemStepIdList); From 085c4aa112ec40cd2d7ab4591aaeff8c1b6a2e97 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 22 Feb 2024 10:04:38 +0000 Subject: [PATCH 06/48] =?UTF-8?q?Not=20sure=20that=20this=20is=20really=20?= =?UTF-8?q?needed,=20and=20it=20is=20expensive...=20But=20=F0=9F=A4=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- grafast/grafast/src/steps/graphqlResolver.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/grafast/grafast/src/steps/graphqlResolver.ts b/grafast/grafast/src/steps/graphqlResolver.ts index 4bf683211f..9f3ac094c9 100644 --- a/grafast/grafast/src/steps/graphqlResolver.ts +++ b/grafast/grafast/src/steps/graphqlResolver.ts @@ -42,7 +42,11 @@ function dcr( if (data == null) { return data; } - return { data, context, resolveInfo }; + if (Array.isArray(data) && data.some(isPromiseLike)) { + return Promise.all(data).then((data) => ({ data, context, resolveInfo })); + } else { + return { data, context, resolveInfo }; + } } /** From fbb3a7711402ab5b36bf2afa336b4fd54ef37bc5 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 22 Feb 2024 10:20:21 +0000 Subject: [PATCH 07/48] Fix storing errors from unary steps --- grafast/grafast/src/engine/executeBucket.ts | 74 +++++++++++++++------ 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/grafast/grafast/src/engine/executeBucket.ts b/grafast/grafast/src/engine/executeBucket.ts index 8a0ceff7b5..eeaf88897c 100644 --- a/grafast/grafast/src/engine/executeBucket.ts +++ b/grafast/grafast/src/engine/executeBucket.ts @@ -275,26 +275,25 @@ export function executeBucket( resultIndex: number, value: unknown, ) => { - if (finishedStep._isUnary) { - if (resultIndex !== 0) { - throw new Error( - `GrafastInternalError<631aafcc-c40c-4fe2-948e-3f06298eb40c>: A unary step must have exactly one result, but ${finishedStep}'s ${resultIndex}th value is ${inspect( - value, - )}`, - ); - } - // TODO: handle streams/etc - bucket.unaryStore.set(finishedStep.id, value); - return; + if (isDev && finishedStep._isUnary && resultIndex !== 0) { + throw new Error( + `GrafastInternalError<631aafcc-c40c-4fe2-948e-3f06298eb40c>: A unary step must have exactly one result, but ${finishedStep}'s ${resultIndex}th value is ${inspect( + value, + )}`, + ); } - const finalResult = bucket.store.get(finishedStep.id)!; let proto: any; if ( // Fast-lane for non-objects typeof value !== "object" || value === null ) { - finalResult[resultIndex] = value; + if (finishedStep._isUnary) { + bucket.unaryStore.set(finishedStep.id, value); + } else { + const finalResult = bucket.store.get(finishedStep.id)!; + finalResult[resultIndex] = value; + } return; } let valueIsAsyncIterable; @@ -326,7 +325,12 @@ export function executeBucket( // Optimization - defer everything const arr: StreamMaybeMoreableArray = []; arr[$$streamMore] = iterator; - finalResult[resultIndex] = arr; + if (finishedStep._isUnary) { + bucket.unaryStore.set(finishedStep.id, arr); + } else { + const finalResult = bucket.store.get(finishedStep.id)!; + finalResult[resultIndex] = arr; + } } else { // Evaluate the first initialCount entries, rest is streamed. const promise = (async () => { @@ -345,11 +349,11 @@ export function executeBucket( | Promise> | IteratorResult; while ((resultPromise = iterator.next())) { - const finalResult = await resultPromise; - if (finalResult.done) { + const resolvedResult = await resultPromise; + if (resolvedResult.done) { break; } - arr.push(await finalResult.value); + arr.push(await resolvedResult.value); if (++valuesSeen >= initialCount) { // This is safe to do in the `while` since we checked // the `0` entries condition in the optimization @@ -359,10 +363,21 @@ export function executeBucket( } } - finalResult[resultIndex] = arr; + if (finishedStep._isUnary) { + bucket.unaryStore.set(finishedStep.id, arr); + } else { + const finalResult = bucket.store.get(finishedStep.id)!; + finalResult[resultIndex] = arr; + } } catch (e) { bucket.hasErrors = true; - finalResult[resultIndex] = newGrafastError(e, finishedStep.id); + const error = newGrafastError(e, finishedStep.id); + if (finishedStep._isUnary) { + bucket.unaryStore.set(finishedStep.id, error); + } else { + const finalResult = bucket.store.get(finishedStep.id)!; + finalResult[resultIndex] = error; + } } })(); if (!promises) { @@ -375,14 +390,29 @@ export function executeBucket( (proto = Object.getPrototypeOf(value)) === null || proto === Object.prototype ) { - finalResult[resultIndex] = value; + if (finishedStep._isUnary) { + bucket.unaryStore.set(finishedStep.id, value); + } else { + const finalResult = bucket.store.get(finishedStep.id)!; + finalResult[resultIndex] = value; + } } else if (value instanceof Error) { const e = $$error in value ? value : newGrafastError(value, finishedStep.id); - finalResult[resultIndex] = e; + if (finishedStep._isUnary) { + bucket.unaryStore.set(finishedStep.id, e); + } else { + const finalResult = bucket.store.get(finishedStep.id)!; + finalResult[resultIndex] = e; + } bucket.hasErrors = true; } else { - finalResult[resultIndex] = value; + if (finishedStep._isUnary) { + bucket.unaryStore.set(finishedStep.id, value); + } else { + const finalResult = bucket.store.get(finishedStep.id)!; + finalResult[resultIndex] = value; + } } }; From b03673a6277ad3fdda40a1706916b75f22b87f59 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 22 Feb 2024 11:57:11 +0000 Subject: [PATCH 08/48] Add missing size=1 --- grafast/grafast/src/engine/LayerPlan.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/grafast/grafast/src/engine/LayerPlan.ts b/grafast/grafast/src/engine/LayerPlan.ts index c2b04bbfd2..1afd8888cf 100644 --- a/grafast/grafast/src/engine/LayerPlan.ts +++ b/grafast/grafast/src/engine/LayerPlan.ts @@ -412,6 +412,7 @@ export class LayerPlan { parentBucket.size == 1, "GrafastInternalError<8c26e449-26ad-4192-b95d-170c59a024a4>: unary step must be in bucket of size 1 (otherwise it's not unary...)", ); + size = 1; unaryStore.set(itemStepId, parentBucket.unaryStore.get(itemStepId)); for (const stepId of copyUnaryStepIds) { unaryStore.set(stepId, parentBucket.unaryStore.get(stepId)!); From fe7613a3045735d62cb69c903f34b22ef43c8b48 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 22 Feb 2024 12:01:10 +0000 Subject: [PATCH 09/48] More unary stuff --- grafast/grafast/src/engine/LayerPlan.ts | 16 ++++++--- grafast/grafast/src/engine/executeBucket.ts | 27 ++++++++++++---- grafast/grafast/src/prepare.ts | 36 +++++++++++++++------ 3 files changed, 60 insertions(+), 19 deletions(-) diff --git a/grafast/grafast/src/engine/LayerPlan.ts b/grafast/grafast/src/engine/LayerPlan.ts index 1afd8888cf..39ce7ac4f2 100644 --- a/grafast/grafast/src/engine/LayerPlan.ts +++ b/grafast/grafast/src/engine/LayerPlan.ts @@ -516,15 +516,19 @@ export class LayerPlan { ); } - const itemStepId = this.rootStep?.id; - if (itemStepId == null) { + if (this.rootStep == null) { throw new Error( "GrafastInternalError: listItem layer plan has no rootStepId", ); } + const itemStepId = this.rootStep.id; // Item steps are **NOT** unary const itemStepIdList: any[] = []; - store.set(itemStepId, itemStepIdList); + if (this.rootStep._isUnary) { + // handled later + } else { + store.set(itemStepId, itemStepIdList); + } for (const stepId of copyUnaryStepIds) { unaryStore.set(stepId, parentBucket.unaryStore.get(stepId)); @@ -549,7 +553,11 @@ export class LayerPlan { for (let j = 0, l = list.length; j < l; j++) { const newIndex = size++; newIndexes.push(newIndex); - itemStepIdList[newIndex] = list[j]; + if (this.rootStep._isUnary) { + unaryStore.set(itemStepId, list[j]); + } else { + itemStepIdList[newIndex] = list[j]; + } polymorphicPathList[newIndex] = parentBucket.polymorphicPathList[originalIndex]; diff --git a/grafast/grafast/src/engine/executeBucket.ts b/grafast/grafast/src/engine/executeBucket.ts index eeaf88897c..1f192f642d 100644 --- a/grafast/grafast/src/engine/executeBucket.ts +++ b/grafast/grafast/src/engine/executeBucket.ts @@ -483,13 +483,18 @@ export function executeBucket( const { s: allStepsIndex, i: dataIndex } = pendingPromiseIndexes![i]; const finishedStep = _allSteps[allStepsIndex]; - const storeEntry = bucket.store.get(finishedStep.id)!; - storeEntry[dataIndex] = newGrafastError( + const error = newGrafastError( new Error( `GrafastInternalError<1e9731b4-005e-4b0e-bc61-43baa62e6444>: error occurred whilst performing completedStep(${finishedStep.id})`, ), finishedStep.id, ); + if (finishedStep._isUnary) { + bucket.unaryStore.set(finishedStep.id, error); + } else { + const storeEntry = bucket.store.get(finishedStep.id)!; + storeEntry[dataIndex] = error; + } } }); } else { @@ -529,7 +534,11 @@ export function executeBucket( _bucket: bucket, _requestContext: requestContext, }; - bucket.store.set(step.id, arrayOfLength(size)); + if (step._isUnary) { + // Handled later + } else { + bucket.store.set(step.id, arrayOfLength(size)); + } } outerLoop: for (let dataIndex = 0; dataIndex < size; dataIndex++) { if (sideEffectStepsWithErrors) { @@ -537,7 +546,9 @@ export function executeBucket( for (const dep of sideEffectStepsWithErrors[ currentPolymorphicPath ?? NO_POLY_PATH ]) { - const depVal = bucket.store.get(dep.id)![dataIndex]; + const depVal = dep._isUnary + ? bucket.unaryStore.get(dep.id) + : bucket.store.get(dep.id)![dataIndex]; if ( depVal === POLY_SKIPPED || (isDev && depVal?.$$error === POLY_SKIPPED) @@ -552,8 +563,12 @@ export function executeBucket( const step = _allSteps[ allStepsIndex ] as UnbatchedExecutableStep; - const storeEntry = bucket.store.get(step.id)!; - storeEntry[dataIndex] = depVal; + if (step._isUnary) { + bucket.unaryStore.set(step.id, depVal); + } else { + const storeEntry = bucket.store.get(step.id)!; + storeEntry[dataIndex] = depVal; + } } continue outerLoop; } diff --git a/grafast/grafast/src/prepare.ts b/grafast/grafast/src/prepare.ts index 113790768e..5562047908 100644 --- a/grafast/grafast/src/prepare.ts +++ b/grafast/grafast/src/prepare.ts @@ -353,7 +353,11 @@ function executePreemptive( store.set(depId, []); } - store.set(rootStep!.id, [payload]); + if (rootStep!._isUnary) { + unaryStore.set(rootStep!.id, payload); + } else { + store.set(rootStep!.id, [payload]); + } for (const depId of layerPlan.copyBatchStepIds) { store.get(depId)![subscriptionBucketIndex] = rootBucket.store.get(depId)![rootBucketIndex]; @@ -379,9 +383,11 @@ function executePreemptive( subscriptionBucketIndex, requestContext, [], - rootBucket.store.get(operationPlan.variableValuesStep.id)![ - rootBucketIndex - ], + operationPlan.variableValuesStep._isUnary + ? rootBucket.unaryStore.get(operationPlan.variableValuesStep.id) + : rootBucket.store.get(operationPlan.variableValuesStep.id)![ + rootBucketIndex + ], outputDataAsString, ); return finalize( @@ -402,11 +408,14 @@ function executePreemptive( // Later we'll need to loop // If it's a subscription we need to use the stream - const rootValueList = + const bucketRootValue = rootBucket.layerPlan.rootStep!.id != null - ? rootBucket.store.get(rootBucket.layerPlan.rootStep!.id) + ? rootBucket.layerPlan.rootStep!._isUnary + ? rootBucket.unaryStore.get(rootBucket.layerPlan.rootStep!.id) + : rootBucket.store.get(rootBucket.layerPlan.rootStep!.id)![ + rootBucketIndex + ] : null; - const bucketRootValue = rootValueList?.[rootBucketIndex]; if (isGrafastError(bucketRootValue)) { releaseUnusedIterators(rootBucket, rootBucketIndex, null); // Something major went wrong! @@ -747,7 +756,11 @@ async function processStream( const listItemStepId = directLayerPlanChild.rootStep!.id; const listItemStepIdList: any[] = []; - store.set(listItemStepId, listItemStepIdList); + if (directLayerPlanChild.rootStep?._isUnary) { + // handled later + } else { + store.set(listItemStepId, listItemStepIdList); + } for (const copyStepId of directLayerPlanChild.copyUnaryStepIds) { unaryStore.set(copyStepId, spec.bucket.unaryStore.get(copyStepId)); @@ -759,7 +772,12 @@ async function processStream( let bucketIndex = 0; for (const entry of entries) { const [result] = entry; - listItemStepIdList[bucketIndex] = result; + if (directLayerPlanChild.rootStep?._isUnary) { + assert.ok(bucketIndex === 0, "Unary step should only have one index"); + unaryStore.set(listItemStepId, result); + } else { + listItemStepIdList[bucketIndex] = result; + } polymorphicPathList[bucketIndex] = spec.bucket.polymorphicPathList[spec.bucketIndex]; From 4d9f83dc6af5af94ead017b2c06a63bb5e55b3b7 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 22 Feb 2024 12:04:47 +0000 Subject: [PATCH 10/48] Don't log warnings in test --- grafast/grafast/src/dev.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/grafast/grafast/src/dev.ts b/grafast/grafast/src/dev.ts index 761f02cd14..3b2cb03794 100644 --- a/grafast/grafast/src/dev.ts +++ b/grafast/grafast/src/dev.ts @@ -5,13 +5,12 @@ const graphileEnv = typeof process !== "undefined" ? process.env.GRAPHILE_ENV : undefined; const nodeEnv = typeof process !== "undefined" ? process.env.NODE_ENV : undefined; +const mode = graphileEnv !== undefined ? graphileEnv : nodeEnv; /** * @internal */ -export const isDev = - graphileEnv !== undefined - ? graphileEnv === "development" || graphileEnv === "test" - : nodeEnv === "development" || nodeEnv === "test"; +export const isDev = mode === "development" || mode === "test"; +export const isTest = mode === "test"; export function noop(): void {} if ( @@ -22,7 +21,7 @@ if ( console.warn( `The GRAPHILE_ENV environmental variable is not set; Grafast will run in production mode. In your development environments, it's recommended that you set \`GRAPHILE_ENV=development\` to opt in to additional checks that will provide guidance and help you to catch issues in your code earlier, and other changes such as formatting to improve your development experience.`, ); -} else if (isDev) { +} else if (isDev && !isTest) { console.warn( `Grafast is running in development mode due to \`${ graphileEnv !== undefined From 3d805f7f804a3339e8d0c494157687417d6031ce Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 22 Feb 2024 12:04:55 +0000 Subject: [PATCH 11/48] Improve error message --- grafast/grafast/src/engine/LayerPlan.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/grafast/grafast/src/engine/LayerPlan.ts b/grafast/grafast/src/engine/LayerPlan.ts index 39ce7ac4f2..e1344638b0 100644 --- a/grafast/grafast/src/engine/LayerPlan.ts +++ b/grafast/grafast/src/engine/LayerPlan.ts @@ -408,10 +408,11 @@ export class LayerPlan { const hasNoNullsOrErrors = false; if (this.rootStep._isUnary) { - assert.ok( - parentBucket.size == 1, - "GrafastInternalError<8c26e449-26ad-4192-b95d-170c59a024a4>: unary step must be in bucket of size 1 (otherwise it's not unary...)", - ); + if (parentBucket.size !== 1) { + throw new Error( + `GrafastInternalError<8c26e449-26ad-4192-b95d-170c59a024a4>: unary step '${this.rootStep}' must be in bucket of size 1 (otherwise it's not unary...), but bucket for ${parentBucket.layerPlan} has size ${parentBucket.size}`, + ); + } size = 1; unaryStore.set(itemStepId, parentBucket.unaryStore.get(itemStepId)); for (const stepId of copyUnaryStepIds) { From b552551858b4f0405cdf49f7c3d41d90528118d6 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 22 Feb 2024 12:18:32 +0000 Subject: [PATCH 12/48] Fix new bucket with unary root step --- grafast/grafast/src/engine/LayerPlan.ts | 52 ++++++++++++------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/grafast/grafast/src/engine/LayerPlan.ts b/grafast/grafast/src/engine/LayerPlan.ts index e1344638b0..062f0d150e 100644 --- a/grafast/grafast/src/engine/LayerPlan.ts +++ b/grafast/grafast/src/engine/LayerPlan.ts @@ -408,36 +408,34 @@ export class LayerPlan { const hasNoNullsOrErrors = false; if (this.rootStep._isUnary) { - if (parentBucket.size !== 1) { - throw new Error( - `GrafastInternalError<8c26e449-26ad-4192-b95d-170c59a024a4>: unary step '${this.rootStep}' must be in bucket of size 1 (otherwise it's not unary...), but bucket for ${parentBucket.layerPlan} has size ${parentBucket.size}`, - ); - } - size = 1; - unaryStore.set(itemStepId, parentBucket.unaryStore.get(itemStepId)); - for (const stepId of copyUnaryStepIds) { - unaryStore.set(stepId, parentBucket.unaryStore.get(stepId)!); - } - for (const stepId of copyBatchStepIds) { - store.set(stepId, parentBucket.store.get(stepId)!); - } - map.set(0, 0); - polymorphicPathList[0] = parentBucket.polymorphicPathList[0]; - iterators[0] = parentBucket.iterators[0]; - } else if (hasNoNullsOrErrors) { - if (this.rootStep._isUnary) { - unaryStore.set(itemStepId, parentBucket.unaryStore.get(itemStepId)); + const fieldValue = parentBucket.unaryStore.get(itemStepId); + if (fieldValue == null) { + size = 0; } else { - const nullableStepStore = parentBucket.store.get(itemStepId); - if (!nullableStepStore) { - throw new Error( - `GrafastInternalError<017dc8bf-1db1-4983-a41e-e69c6652e4c7>: could not find entry '${itemStepId}' (${parentBucket.layerPlan.operationPlan.dangerouslyGetStep( - itemStepId, - )}) in store for ${parentBucket.layerPlan}`, - ); + size = parentBucket.size; + unaryStore.set(itemStepId, fieldValue); + for (const stepId of copyUnaryStepIds) { + unaryStore.set(stepId, parentBucket.unaryStore.get(stepId)!); + } + for (const stepId of copyBatchStepIds) { + store.set(stepId, parentBucket.store.get(stepId)!); } - store.set(itemStepId, nullableStepStore); + for (let i = 0; i < size; i++) { + map.set(i, i); + polymorphicPathList[i] = parentBucket.polymorphicPathList[i]; + iterators[i] = parentBucket.iterators[i]; + } + } + } else if (hasNoNullsOrErrors) { + const nullableStepStore = parentBucket.store.get(itemStepId); + if (!nullableStepStore) { + throw new Error( + `GrafastInternalError<017dc8bf-1db1-4983-a41e-e69c6652e4c7>: could not find entry '${itemStepId}' (${parentBucket.layerPlan.operationPlan.dangerouslyGetStep( + itemStepId, + )}) in store for ${parentBucket.layerPlan}`, + ); } + store.set(itemStepId, nullableStepStore); for (const stepId of copyUnaryStepIds) { unaryStore.set(stepId, parentBucket.unaryStore.get(stepId)!); } From 3736539f462b00980048b739ead4b965dbea613e Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 22 Feb 2024 12:46:21 +0000 Subject: [PATCH 13/48] Update mermaid plans --- ...-forum-inherited-messages.defer-1.deopt.mermaid | 10 +++++----- ...chived-forum-inherited-messages.defer-1.mermaid | 6 +++--- ...-forum-inherited-messages.defer-2.deopt.mermaid | 10 +++++----- ...chived-forum-inherited-messages.defer-2.mermaid | 6 +++--- ...-forum-inherited-messages.defer-3.deopt.mermaid | 10 +++++----- ...chived-forum-inherited-messages.defer-3.mermaid | 6 +++--- ...-forum-inherited-messages.defer-4.deopt.mermaid | 10 +++++----- ...chived-forum-inherited-messages.defer-4.mermaid | 8 ++++---- ...-forum-inherited-messages.defer-5.deopt.mermaid | 8 ++++---- ...chived-forum-inherited-messages.defer-5.mermaid | 4 ++-- ...-forum-inherited-messages.defer-6.deopt.mermaid | 12 ++++++------ ...chived-forum-inherited-messages.defer-6.mermaid | 12 ++++++------ ...-forum-inherited-messages.defer-7.deopt.mermaid | 14 +++++++------- ...chived-forum-inherited-messages.defer-7.mermaid | 14 +++++++------- ...archived-forum-inherited-messages.deopt.mermaid | 8 ++++---- .../archived-forum-inherited-messages.mermaid | 4 ++-- ...forum-inherited-messages.stream-1.deopt.mermaid | 6 +++--- ...hived-forum-inherited-messages.stream-1.mermaid | 4 ++-- ...forum-inherited-messages.stream-2.deopt.mermaid | 8 ++++---- ...hived-forum-inherited-messages.stream-2.mermaid | 4 ++-- ...forum-inherited-messages.stream-3.deopt.mermaid | 6 +++--- ...hived-forum-inherited-messages.stream-3.mermaid | 4 ++-- ...forum-inherited-messages.stream-4.deopt.mermaid | 6 +++--- ...hived-forum-inherited-messages.stream-4.mermaid | 4 ++-- ...forum-inherited-messages.stream-5.deopt.mermaid | 6 +++--- ...hived-forum-inherited-messages.stream-5.mermaid | 4 ++-- .../conditions/basics-with-author.deopt.mermaid | 4 ++-- .../queries/conditions/basics.deopt.mermaid | 2 +- .../conditions/complex-filter.deopt.mermaid | 2 +- ...ndition-featured-messages-minimal.deopt.mermaid | 4 ++-- .../condition-featured-messages-minimal.mermaid | 2 +- .../condition-featured-messages.deopt.mermaid | 8 ++++---- .../conditions/condition-featured-messages.mermaid | 4 ++-- .../exclusively-archived-messages.deopt.mermaid | 8 ++++---- .../exclusively-archived-messages.mermaid | 4 ++-- .../conditions/include-all-archived.deopt.mermaid | 4 ++-- .../connections/basics-limit3.deopt.mermaid | 2 +- .../queries/connections/basics.deopt.mermaid | 2 +- .../queries/connections/empty.deopt.mermaid | 2 +- .../__tests__/queries/connections/empty.mermaid | 2 +- .../queries/connections/order.deopt.mermaid | 2 +- .../connections/pagination-after.deopt.mermaid | 2 +- .../pagination-before-end-last.deopt.mermaid | 2 +- .../pagination-before-end.deopt.mermaid | 2 +- .../pagination-before-last.deopt.mermaid | 2 +- .../connections/pagination-before.deopt.mermaid | 2 +- ...when-inlined-backwards-nodes-only.deopt.mermaid | 6 +++--- ...ation-when-inlined-backwards-nodes-only.mermaid | 4 ++-- ...pagination-when-inlined-backwards.deopt.mermaid | 8 ++++---- .../pagination-when-inlined-backwards.mermaid | 4 ++-- .../pagination-when-inlined.deopt.mermaid | 8 ++++---- .../connections/pagination-when-inlined.mermaid | 4 ++-- ...d-column-forums-messages-list-set.deopt.mermaid | 2 +- ...ssages-with-many-transforms.defer.deopt.mermaid | 2 +- ...ums-messages-with-many-transforms.defer.mermaid | 2 +- ...ums-messages-with-many-transforms.deopt.mermaid | 2 +- ...mn-forums-messages-with-many-transforms.mermaid | 2 +- .../basics-with-fragments.deopt.mermaid | 2 +- .../basics-with-fragments.mermaid | 2 +- .../interfaces-relational/basics.deopt.mermaid | 2 +- .../queries/interfaces-relational/basics.mermaid | 2 +- .../nested-more-fragments.deopt.mermaid | 2 +- .../nested-more-fragments.mermaid | 2 +- .../nested-more.deopt.mermaid | 2 +- .../interfaces-relational/nested-more.mermaid | 2 +- .../interfaces-relational/nested.deopt.mermaid | 2 +- .../queries/interfaces-relational/nested.mermaid | 2 +- .../basics-with-fragments.deopt.mermaid | 2 +- .../interfaces-single-table/basics.deopt.mermaid | 2 +- .../nested-more-fragments.deopt.mermaid | 2 +- .../nested-more-fragments.mermaid | 2 +- .../nested-more.deopt.mermaid | 2 +- .../interfaces-single-table/nested-more.mermaid | 2 +- .../interfaces-single-table/nested.deopt.mermaid | 2 +- .../queries/interfaces-single-table/nested.mermaid | 2 +- .../vulnerabilities.deopt.mermaid | 2 +- .../vulnerabilities.mermaid | 2 +- .../vulnerabilitiesConnection.after1.deopt.mermaid | 4 ++-- .../vulnerabilitiesConnection.after1.mermaid | 4 ++-- ...vulnerabilitiesConnection.before1.deopt.mermaid | 4 ++-- .../vulnerabilitiesConnection.before1.mermaid | 4 ++-- .../vulnerabilitiesConnection.deopt.mermaid | 4 ++-- .../vulnerabilitiesConnection.mermaid | 4 ++-- .../queries/unions-table/bookmarks.deopt.mermaid | 2 +- .../queries/unions-table/bookmarks.mermaid | 2 +- .../basics/forum-messages.deopt.mermaid | 4 ++-- .../subscriptions/basics/forum-messages.mermaid | 2 +- .../forum-single-message-evolve.deopt.mermaid | 4 ++-- .../basics/forum-single-message-evolve.mermaid | 2 +- 89 files changed, 190 insertions(+), 190 deletions(-) diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-1.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-1.deopt.mermaid index 3fdc1d012b..72d796ce72 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-1.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-1.deopt.mermaid @@ -81,25 +81,25 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (defer)
Deps: 16, 14, 28"):::bucket + Bucket3("Bucket 3 (defer)
Deps: 14, 28, 16"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29 bucket3 - Bucket4("Bucket 4 (nullableBoundary)
Deps: 14, 23, 29, 28

ROOT Connectionᐸ24ᐳ[28]"):::bucket + Bucket4("Bucket 4 (nullableBoundary)
Deps: 14, 28, 23, 29

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgSelect30 bucket4 Bucket5("Bucket 5 (listItem)
Deps: 14

ROOT __Item{5}ᐸ30ᐳ[31]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,__Item31,PgSelectSingle32 bucket5 - Bucket6("Bucket 6 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket6("Bucket 6 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression33,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket6 Bucket7("Bucket 7 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{6}ᐸusersᐳ[40]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgClassExpression41,PgClassExpression42 bucket7 - Bucket8("Bucket 8 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]
1:
ᐳ: 46, 48, 49, 47, 45
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket + Bucket8("Bucket 8 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]
1:
ᐳ: 46, 48, 49, 47, 45
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,PgCursor45,PgClassExpression46,List47,PgClassExpression48,PgClassExpression49,PgSelect50,First54,PgSelectSingle55 bucket8 Bucket9("Bucket 9 (nullableBoundary)
Deps: 55

ROOT PgSelectSingle{8}ᐸusersᐳ[55]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-1.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-1.mermaid index 0cb04ea505..38b43cd1e6 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-1.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-1.mermaid @@ -73,13 +73,13 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (defer)
Deps: 16, 14, 28"):::bucket + Bucket3("Bucket 3 (defer)
Deps: 14, 28, 16"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29 bucket3 - Bucket4("Bucket 4 (nullableBoundary)
Deps: 14, 23, 29, 28

ROOT Connectionᐸ24ᐳ[28]"):::bucket + Bucket4("Bucket 4 (nullableBoundary)
Deps: 14, 28, 23, 29

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgSelect30 bucket4 Bucket5("Bucket 5 (listItem)
ROOT __Item{5}ᐸ30ᐳ[31]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-2.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-2.deopt.mermaid index 0d4d340fe5..79650b8190 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-2.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-2.deopt.mermaid @@ -81,25 +81,25 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28, 14

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 14

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 14, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 28, 14

ROOT Connectionᐸ24ᐳ[28]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 14, 16

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29 bucket3 - Bucket4("Bucket 4 (defer)
Deps: 14, 23, 29, 28"):::bucket + Bucket4("Bucket 4 (defer)
Deps: 14, 28, 23, 29"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgSelect30 bucket4 Bucket5("Bucket 5 (listItem)
Deps: 14

ROOT __Item{5}ᐸ30ᐳ[31]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,__Item31,PgSelectSingle32 bucket5 - Bucket6("Bucket 6 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket6("Bucket 6 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression33,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket6 Bucket7("Bucket 7 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{6}ᐸusersᐳ[40]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgClassExpression41,PgClassExpression42 bucket7 - Bucket8("Bucket 8 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]
1:
ᐳ: 46, 48, 49, 47, 45
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket + Bucket8("Bucket 8 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]
1:
ᐳ: 46, 48, 49, 47, 45
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,PgCursor45,PgClassExpression46,List47,PgClassExpression48,PgClassExpression49,PgSelect50,First54,PgSelectSingle55 bucket8 Bucket9("Bucket 9 (nullableBoundary)
Deps: 55

ROOT PgSelectSingle{8}ᐸusersᐳ[55]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-2.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-2.mermaid index de093efb4e..d3bc60a3d3 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-2.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-2.mermaid @@ -73,13 +73,13 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28, 14

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 14

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 14, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 28, 14

ROOT Connectionᐸ24ᐳ[28]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 14, 16

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29 bucket3 - Bucket4("Bucket 4 (defer)
Deps: 14, 23, 29, 28"):::bucket + Bucket4("Bucket 4 (defer)
Deps: 14, 28, 23, 29"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgSelect30 bucket4 Bucket5("Bucket 5 (listItem)
ROOT __Item{5}ᐸ30ᐳ[31]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-3.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-3.deopt.mermaid index c9181c1e04..693903008d 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-3.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-3.deopt.mermaid @@ -87,31 +87,31 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28, 14

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 14

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 14, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17,PgClassExpression23,PgClassExpression29 bucket2 Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 14, 23, 29

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3 bucket3 - Bucket4("Bucket 4 (defer)
Deps: 14, 23, 29, 28"):::bucket + Bucket4("Bucket 4 (defer)
Deps: 14, 28, 23, 29"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgSelect30 bucket4 Bucket5("Bucket 5 (listItem)
Deps: 14

ROOT __Item{5}ᐸ30ᐳ[31]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,__Item31,PgSelectSingle32 bucket5 - Bucket6("Bucket 6 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket6("Bucket 6 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression33,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket6 Bucket7("Bucket 7 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{6}ᐸusersᐳ[40]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgClassExpression41,PgClassExpression42 bucket7 - Bucket8("Bucket 8 (defer)
Deps: 14, 23, 29, 28"):::bucket + Bucket8("Bucket 8 (defer)
Deps: 14, 28, 23, 29"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,PgSelect43 bucket8 Bucket9("Bucket 9 (listItem)
Deps: 14

ROOT __Item{9}ᐸ43ᐳ[44]"):::bucket classDef bucket9 stroke:#ff0000 class Bucket9,__Item44,PgSelectSingle45 bucket9 - Bucket10("Bucket 10 (nullableBoundary)
Deps: 45, 14

ROOT PgSelectSingle{9}ᐸmessagesᐳ[45]
1:
ᐳ: 47, 49, 50, 48, 46
2: PgSelect[51]
ᐳ: First[55], PgSelectSingle[56]"):::bucket + Bucket10("Bucket 10 (nullableBoundary)
Deps: 14, 45

ROOT PgSelectSingle{9}ᐸmessagesᐳ[45]
1:
ᐳ: 47, 49, 50, 48, 46
2: PgSelect[51]
ᐳ: First[55], PgSelectSingle[56]"):::bucket classDef bucket10 stroke:#ffff00 class Bucket10,PgCursor46,PgClassExpression47,List48,PgClassExpression49,PgClassExpression50,PgSelect51,First55,PgSelectSingle56 bucket10 Bucket11("Bucket 11 (nullableBoundary)
Deps: 56

ROOT PgSelectSingle{10}ᐸusersᐳ[56]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-3.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-3.mermaid index 1ec10feed0..be62cecf05 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-3.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-3.mermaid @@ -79,13 +79,13 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28, 14

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 14

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 14, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17,PgClassExpression23,PgClassExpression29 bucket2 Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 14, 23, 29

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3 bucket3 - Bucket4("Bucket 4 (defer)
Deps: 14, 23, 29, 28"):::bucket + Bucket4("Bucket 4 (defer)
Deps: 14, 28, 23, 29"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgSelect30 bucket4 Bucket5("Bucket 5 (listItem)
ROOT __Item{5}ᐸ30ᐳ[31]"):::bucket @@ -97,7 +97,7 @@ graph TD Bucket7("Bucket 7 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{6}ᐸusersᐳ[40]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgClassExpression41,PgClassExpression42 bucket7 - Bucket8("Bucket 8 (defer)
Deps: 14, 23, 29, 28"):::bucket + Bucket8("Bucket 8 (defer)
Deps: 14, 28, 23, 29"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,PgSelect43 bucket8 Bucket9("Bucket 9 (listItem)
ROOT __Item{9}ᐸ43ᐳ[44]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-4.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-4.deopt.mermaid index e3598a8cd7..c90bc3d732 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-4.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-4.deopt.mermaid @@ -112,25 +112,25 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant59 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28, 59

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 59, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28, 59

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29, 58
2: PgSelect[30], PgSelect[73]
ᐳ: 62, 63, 65, 66, 68, 69, 71, 72, 74, 75, 76, 64, 70"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 59, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29, 58
2: PgSelect[30], PgSelect[73]
ᐳ: 62, 63, 65, 66, 68, 69, 71, 72, 74, 75, 76, 64, 70"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgSelect30,PgPageInfo58,First62,PgSelectSingle63,PgCursor64,PgClassExpression65,List66,Last68,PgSelectSingle69,PgCursor70,PgClassExpression71,List72,PgSelect73,First74,PgSelectSingle75,PgClassExpression76 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ30ᐳ[31]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item31,PgSelectSingle32 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5 bucket5 - Bucket6("Bucket 6 (defer)
Deps: 32, 14

1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket6("Bucket 6 (defer)
Deps: 14, 32

1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression33,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket6 Bucket7("Bucket 7 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{6}ᐸusersᐳ[40]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgClassExpression41,PgClassExpression42 bucket7 - Bucket8("Bucket 8 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 46, 48, 49, 47, 45
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket + Bucket8("Bucket 8 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 46, 48, 49, 47, 45
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,PgCursor45,PgClassExpression46,List47,PgClassExpression48,PgClassExpression49,PgSelect50,First54,PgSelectSingle55 bucket8 Bucket9("Bucket 9 (nullableBoundary)
Deps: 55

ROOT PgSelectSingle{8}ᐸusersᐳ[55]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-4.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-4.mermaid index b1576fd2b3..ec096c43b9 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-4.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-4.mermaid @@ -104,19 +104,19 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28, 14

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant59 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 15, 14, 59

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 14, 59, 16, 15

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 15, 14, 59

ROOT Connectionᐸ24ᐳ[28]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 14, 59, 15

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgPageInfo58,First62,PgSelectSingle63,PgCursor64,PgClassExpression65,List66,Last68,PgSelectSingle69,PgCursor70,PgClassExpression71,List72,First74,PgSelectSingle75,PgClassExpression76,Access79,Access80 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ79ᐳ[31]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item31,PgSelectSingle32 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5 bucket5 - Bucket6("Bucket 6 (defer)
Deps: 32, 14

1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket6("Bucket 6 (defer)
Deps: 14, 32

1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression33,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket6 Bucket7("Bucket 7 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{6}ᐸusersᐳ[40]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-5.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-5.deopt.mermaid index 3c6e4ee8c7..c7a5575dee 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-5.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-5.deopt.mermaid @@ -92,22 +92,22 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant59 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28, 59

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 59, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28, 59

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29, 58
2: PgSelect[30], PgSelect[61]
ᐳ: 62, 63, 64"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 59, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29, 58
2: PgSelect[30], PgSelect[61]
ᐳ: 62, 63, 64"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgSelect30,PgPageInfo58,PgSelect61,First62,PgSelectSingle63,PgClassExpression64 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ30ᐳ[31]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item31,PgSelectSingle32 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression33,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket5 Bucket6("Bucket 6 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{5}ᐸusersᐳ[40]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression41,PgClassExpression42 bucket6 - Bucket7("Bucket 7 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 45, 46
2: PgSelect[47]
ᐳ: First[51], PgSelectSingle[52]"):::bucket + Bucket7("Bucket 7 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 45, 46
2: PgSelect[47]
ᐳ: First[51], PgSelectSingle[52]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgClassExpression45,PgClassExpression46,PgSelect47,First51,PgSelectSingle52 bucket7 Bucket8("Bucket 8 (nullableBoundary)
Deps: 52

ROOT PgSelectSingle{7}ᐸusersᐳ[52]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-5.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-5.mermaid index b58919ab81..5a61f42ce0 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-5.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-5.mermaid @@ -80,10 +80,10 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant59 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 15, 59

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 59, 16, 15

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 15, 59

ROOT Connectionᐸ24ᐳ[28]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 59, 15

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgPageInfo58,First62,PgSelectSingle63,PgClassExpression64,Access69,Access70 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ69ᐳ[31]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-6.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-6.deopt.mermaid index 770c84be17..18f6398dda 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-6.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-6.deopt.mermaid @@ -81,28 +81,28 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgSelect30 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ30ᐳ[31]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item31,PgSelectSingle32 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression33 bucket5 - Bucket6("Bucket 6 (defer)
Deps: 32, 14

1:
ᐳ: PgClassExpression[34]
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket6("Bucket 6 (defer)
Deps: 14, 32

1:
ᐳ: PgClassExpression[34]
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket6 Bucket7("Bucket 7 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{6}ᐸusersᐳ[40]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgClassExpression41,PgClassExpression42 bucket7 - Bucket8("Bucket 8 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]"):::bucket + Bucket8("Bucket 8 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,PgCursor45,PgClassExpression46,List47,PgClassExpression48 bucket8 - Bucket9("Bucket 9 (defer)
Deps: 32, 14

1:
ᐳ: PgClassExpression[49]
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket + Bucket9("Bucket 9 (defer)
Deps: 14, 32

1:
ᐳ: PgClassExpression[49]
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket classDef bucket9 stroke:#ff0000 class Bucket9,PgClassExpression49,PgSelect50,First54,PgSelectSingle55 bucket9 Bucket10("Bucket 10 (nullableBoundary)
Deps: 55

ROOT PgSelectSingle{9}ᐸusersᐳ[55]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-6.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-6.mermaid index 9670be30c7..ef588a6e47 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-6.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-6.mermaid @@ -77,28 +77,28 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28, 14

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 15, 28, 14

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 14, 16, 15

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 15, 28, 14

ROOT Connectionᐸ24ᐳ[28]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 14, 15

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,Access58 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ58ᐳ[31]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item31,PgSelectSingle32 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression33 bucket5 - Bucket6("Bucket 6 (defer)
Deps: 32, 14

1:
ᐳ: PgClassExpression[34]
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket6("Bucket 6 (defer)
Deps: 14, 32

1:
ᐳ: PgClassExpression[34]
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket6 Bucket7("Bucket 7 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{6}ᐸusersᐳ[40]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgClassExpression41,PgClassExpression42 bucket7 - Bucket8("Bucket 8 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]"):::bucket + Bucket8("Bucket 8 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,PgCursor45,PgClassExpression46,List47,PgClassExpression48 bucket8 - Bucket9("Bucket 9 (defer)
Deps: 32, 14

1:
ᐳ: PgClassExpression[49]
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket + Bucket9("Bucket 9 (defer)
Deps: 14, 32

1:
ᐳ: PgClassExpression[49]
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket classDef bucket9 stroke:#ff0000 class Bucket9,PgClassExpression49,PgSelect50,First54,PgSelectSingle55 bucket9 Bucket10("Bucket 10 (nullableBoundary)
Deps: 55

ROOT PgSelectSingle{9}ᐸusersᐳ[55]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-7.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-7.deopt.mermaid index 1195c3b4d0..1dd5f3e5c4 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-7.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-7.deopt.mermaid @@ -81,31 +81,31 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (defer)
Deps: 16, 14, 28"):::bucket + Bucket3("Bucket 3 (defer)
Deps: 14, 28, 16"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29 bucket3 - Bucket4("Bucket 4 (nullableBoundary)
Deps: 14, 23, 29, 28

ROOT Connectionᐸ24ᐳ[28]"):::bucket + Bucket4("Bucket 4 (nullableBoundary)
Deps: 14, 28, 23, 29

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgSelect30 bucket4 Bucket5("Bucket 5 (listItem)
Deps: 14

ROOT __Item{5}ᐸ30ᐳ[31]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,__Item31,PgSelectSingle32 bucket5 - Bucket6("Bucket 6 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]"):::bucket + Bucket6("Bucket 6 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression33 bucket6 - Bucket7("Bucket 7 (defer)
Deps: 32, 14

1:
ᐳ: PgClassExpression[34]
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket7("Bucket 7 (defer)
Deps: 14, 32

1:
ᐳ: PgClassExpression[34]
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket7 Bucket8("Bucket 8 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{7}ᐸusersᐳ[40]"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,PgClassExpression41,PgClassExpression42 bucket8 - Bucket9("Bucket 9 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]"):::bucket + Bucket9("Bucket 9 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]"):::bucket classDef bucket9 stroke:#ff0000 class Bucket9,PgCursor45,PgClassExpression46,List47,PgClassExpression48 bucket9 - Bucket10("Bucket 10 (defer)
Deps: 32, 14

1:
ᐳ: PgClassExpression[49]
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket + Bucket10("Bucket 10 (defer)
Deps: 14, 32

1:
ᐳ: PgClassExpression[49]
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket classDef bucket10 stroke:#ffff00 class Bucket10,PgClassExpression49,PgSelect50,First54,PgSelectSingle55 bucket10 Bucket11("Bucket 11 (nullableBoundary)
Deps: 55

ROOT PgSelectSingle{10}ᐸusersᐳ[55]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-7.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-7.mermaid index 1195c3b4d0..1dd5f3e5c4 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-7.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.defer-7.mermaid @@ -81,31 +81,31 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (defer)
Deps: 16, 14, 28"):::bucket + Bucket3("Bucket 3 (defer)
Deps: 14, 28, 16"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29 bucket3 - Bucket4("Bucket 4 (nullableBoundary)
Deps: 14, 23, 29, 28

ROOT Connectionᐸ24ᐳ[28]"):::bucket + Bucket4("Bucket 4 (nullableBoundary)
Deps: 14, 28, 23, 29

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgSelect30 bucket4 Bucket5("Bucket 5 (listItem)
Deps: 14

ROOT __Item{5}ᐸ30ᐳ[31]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,__Item31,PgSelectSingle32 bucket5 - Bucket6("Bucket 6 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]"):::bucket + Bucket6("Bucket 6 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression33 bucket6 - Bucket7("Bucket 7 (defer)
Deps: 32, 14

1:
ᐳ: PgClassExpression[34]
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket7("Bucket 7 (defer)
Deps: 14, 32

1:
ᐳ: PgClassExpression[34]
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket7 Bucket8("Bucket 8 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{7}ᐸusersᐳ[40]"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,PgClassExpression41,PgClassExpression42 bucket8 - Bucket9("Bucket 9 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]"):::bucket + Bucket9("Bucket 9 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{5}ᐸmessagesᐳ[32]"):::bucket classDef bucket9 stroke:#ff0000 class Bucket9,PgCursor45,PgClassExpression46,List47,PgClassExpression48 bucket9 - Bucket10("Bucket 10 (defer)
Deps: 32, 14

1:
ᐳ: PgClassExpression[49]
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket + Bucket10("Bucket 10 (defer)
Deps: 14, 32

1:
ᐳ: PgClassExpression[49]
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket classDef bucket10 stroke:#ffff00 class Bucket10,PgClassExpression49,PgSelect50,First54,PgSelectSingle55 bucket10 Bucket11("Bucket 11 (nullableBoundary)
Deps: 55

ROOT PgSelectSingle{10}ᐸusersᐳ[55]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.deopt.mermaid index cf90120ee3..d597fc7cb9 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.deopt.mermaid @@ -112,22 +112,22 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant59 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28, 59

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 59, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28, 59

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29, 58
2: PgSelect[30], PgSelect[73]
ᐳ: 62, 63, 65, 66, 68, 69, 71, 72, 74, 75, 76, 64, 70"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 59, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29, 58
2: PgSelect[30], PgSelect[73]
ᐳ: 62, 63, 65, 66, 68, 69, 71, 72, 74, 75, 76, 64, 70"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgSelect30,PgPageInfo58,First62,PgSelectSingle63,PgCursor64,PgClassExpression65,List66,Last68,PgSelectSingle69,PgCursor70,PgClassExpression71,List72,PgSelect73,First74,PgSelectSingle75,PgClassExpression76 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ30ᐳ[31]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item31,PgSelectSingle32 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression33,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket5 Bucket6("Bucket 6 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{5}ᐸusersᐳ[40]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression41,PgClassExpression42 bucket6 - Bucket7("Bucket 7 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 46, 48, 49, 47, 45
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket + Bucket7("Bucket 7 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 46, 48, 49, 47, 45
2: PgSelect[50]
ᐳ: First[54], PgSelectSingle[55]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgCursor45,PgClassExpression46,List47,PgClassExpression48,PgClassExpression49,PgSelect50,First54,PgSelectSingle55 bucket7 Bucket8("Bucket 8 (nullableBoundary)
Deps: 55

ROOT PgSelectSingle{7}ᐸusersᐳ[55]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.mermaid index 841b9e1c2a..e8cc470179 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.mermaid @@ -100,10 +100,10 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant59 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 15, 59

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 59, 16, 15

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 15, 59

ROOT Connectionᐸ24ᐳ[28]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 59, 15

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgPageInfo58,First62,PgSelectSingle63,PgCursor64,PgClassExpression65,List66,Last68,PgSelectSingle69,PgCursor70,PgClassExpression71,List72,First74,PgSelectSingle75,PgClassExpression76,Access81,Access82 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ81ᐳ[31]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-1.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-1.deopt.mermaid index 954d4d43e2..a4e8f59044 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-1.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-1.deopt.mermaid @@ -61,16 +61,16 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgSelect30 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ30ᐳ[31]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item31,PgSelectSingle32 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression33,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket5 Bucket6("Bucket 6 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{5}ᐸusersᐳ[40]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-1.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-1.mermaid index 139c972697..b9eaf0b21f 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-1.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-1.mermaid @@ -57,10 +57,10 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgSelect30 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ30ᐳ[31]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-2.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-2.deopt.mermaid index 33ef310282..c0f40d0d27 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-2.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-2.deopt.mermaid @@ -98,16 +98,16 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant60 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28, 60

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 60, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28, 60

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29, 59
2: 30, 43, 62
ᐳ: 63, 64, 65"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 60, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29, 59
2: 30, 43, 62
ᐳ: 63, 64, 65"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgSelect30,PgSelect43,PgPageInfo59,PgSelect62,First63,PgSelectSingle64,PgClassExpression65 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ30ᐳ[31]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item31,PgSelectSingle32 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression33,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket5 Bucket6("Bucket 6 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{5}ᐸusersᐳ[40]"):::bucket @@ -116,7 +116,7 @@ graph TD Bucket7("Bucket 7 (listItem)
Deps: 14

ROOT __Item{7}ᐸ43ᐳ[44]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,__Item44,PgSelectSingle45 bucket7 - Bucket8("Bucket 8 (nullableBoundary)
Deps: 45, 14

ROOT PgSelectSingle{7}ᐸmessagesᐳ[45]
1:
ᐳ: 47, 49, 50, 48, 46
2: PgSelect[51]
ᐳ: First[55], PgSelectSingle[56]"):::bucket + Bucket8("Bucket 8 (nullableBoundary)
Deps: 14, 45

ROOT PgSelectSingle{7}ᐸmessagesᐳ[45]
1:
ᐳ: 47, 49, 50, 48, 46
2: PgSelect[51]
ᐳ: First[55], PgSelectSingle[56]"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,PgCursor46,PgClassExpression47,List48,PgClassExpression49,PgClassExpression50,PgSelect51,First55,PgSelectSingle56 bucket8 Bucket9("Bucket 9 (nullableBoundary)
Deps: 56

ROOT PgSelectSingle{8}ᐸusersᐳ[56]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-2.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-2.mermaid index 21bff38a67..0aa6d096bf 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-2.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-2.mermaid @@ -90,10 +90,10 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant60 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28, 15, 60

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 60, 16, 15

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28, 15, 60

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29, 59, 70, 63, 64, 65
2: PgSelect[30], PgSelect[43]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 60, 16, 15

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29, 59, 70, 63, 64, 65
2: PgSelect[30], PgSelect[43]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgSelect30,PgSelect43,PgPageInfo59,First63,PgSelectSingle64,PgClassExpression65,Access70 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ30ᐳ[31]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-3.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-3.deopt.mermaid index 7c1d2bb3ad..73c4039b1a 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-3.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-3.deopt.mermaid @@ -61,16 +61,16 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgSelect30 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ30ᐳ[31]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item31,PgSelectSingle32 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression33,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket5 Bucket6("Bucket 6 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{5}ᐸusersᐳ[40]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-3.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-3.mermaid index eb774c03e4..43aa651fa6 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-3.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-3.mermaid @@ -57,10 +57,10 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgSelect30 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ30ᐳ[31]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-4.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-4.deopt.mermaid index 6ffebd264f..2e19edd903 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-4.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-4.deopt.mermaid @@ -61,16 +61,16 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgSelect30 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ30ᐳ[31]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item31,PgSelectSingle32 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression33,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket5 Bucket6("Bucket 6 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{5}ᐸusersᐳ[40]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-4.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-4.mermaid index 0387c5274e..06a3bab177 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-4.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-4.mermaid @@ -57,10 +57,10 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgSelect30 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ30ᐳ[31]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-5.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-5.deopt.mermaid index 890ea1b9d8..a7db02afb9 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-5.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-5.deopt.mermaid @@ -63,16 +63,16 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgSelect30 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ30ᐳ[31]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item31,PgSelectSingle32 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 32, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 32

ROOT PgSelectSingle{4}ᐸmessagesᐳ[32]
1:
ᐳ: 33, 34
2: PgSelect[35]
ᐳ: First[39], PgSelectSingle[40]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression33,PgClassExpression34,PgSelect35,First39,PgSelectSingle40 bucket5 Bucket6("Bucket 6 (nullableBoundary)
Deps: 40

ROOT PgSelectSingle{5}ᐸusersᐳ[40]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-5.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-5.mermaid index 1af1be5558..eaf467ab46 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-5.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/archived-forum-inherited-messages.stream-5.mermaid @@ -59,10 +59,10 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29
2: PgSelect[30]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgSelect30 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ30ᐳ[31]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/basics-with-author.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/basics-with-author.deopt.mermaid index b23760175c..b5e05177e9 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/basics-with-author.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/basics-with-author.deopt.mermaid @@ -60,13 +60,13 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]
1:
ᐳ: 17, 22, 27
2: PgSelect[23]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]
1:
ᐳ: 17, 22, 27
2: PgSelect[23]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17,PgClassExpression22,PgSelect23,PgClassExpression27 bucket2 Bucket3("Bucket 3 (listItem)
Deps: 14

ROOT __Item{3}ᐸ23ᐳ[28]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,__Item28,PgSelectSingle29 bucket3 - Bucket4("Bucket 4 (nullableBoundary)
Deps: 29, 14

ROOT PgSelectSingle{3}ᐸmessagesᐳ[29]
1:
ᐳ: 30, 31
2: PgSelect[32]
ᐳ: First[36], PgSelectSingle[37]"):::bucket + Bucket4("Bucket 4 (nullableBoundary)
Deps: 14, 29

ROOT PgSelectSingle{3}ᐸmessagesᐳ[29]
1:
ᐳ: 30, 31
2: PgSelect[32]
ᐳ: First[36], PgSelectSingle[37]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgClassExpression30,PgClassExpression31,PgSelect32,First36,PgSelectSingle37 bucket4 Bucket5("Bucket 5 (nullableBoundary)
Deps: 37

ROOT PgSelectSingle{4}ᐸusersᐳ[37]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/basics.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/basics.deopt.mermaid index 00d7b5856a..55715f9229 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/basics.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/basics.deopt.mermaid @@ -48,7 +48,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]
1:
ᐳ: 17, 22, 27
2: PgSelect[23]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]
1:
ᐳ: 17, 22, 27
2: PgSelect[23]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17,PgClassExpression22,PgSelect23,PgClassExpression27 bucket2 Bucket3("Bucket 3 (listItem)
ROOT __Item{3}ᐸ23ᐳ[28]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/complex-filter.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/complex-filter.deopt.mermaid index 0386f91f76..cb13ed1f27 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/complex-filter.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/complex-filter.deopt.mermaid @@ -51,7 +51,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 19, 40

ROOT __Item{1}ᐸ16ᐳ[20]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item20,PgSelectSingle21 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 21, 19, 40

ROOT PgSelectSingle{1}ᐸforumsᐳ[21]
1:
ᐳ: 22, 30, 35
2: PgSelect[31]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 19, 40, 21

ROOT PgSelectSingle{1}ᐸforumsᐳ[21]
1:
ᐳ: 22, 30, 35
2: PgSelect[31]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression22,PgClassExpression30,PgSelect31,PgClassExpression35 bucket2 Bucket3("Bucket 3 (listItem)
ROOT __Item{3}ᐸ31ᐳ[36]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages-minimal.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages-minimal.deopt.mermaid index 0e0ab16f2d..d2e84745f9 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages-minimal.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages-minimal.deopt.mermaid @@ -56,10 +56,10 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28, 14

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant38 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 14, 38

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 14, 38, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 28, 14, 38

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29, 30
2: PgSelect[31], PgSelect[33]
ᐳ: 32, 34, 35, 36"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 14, 38, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: 23, 29, 30
2: PgSelect[31], PgSelect[33]
ᐳ: 32, 34, 35, 36"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression29,PgPageInfo30,PgSelect31,Access32,PgSelect33,First34,PgSelectSingle35,PgClassExpression36 bucket3 Bucket0 --> Bucket1 diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages-minimal.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages-minimal.mermaid index 590964d77c..9ed4a72fc2 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages-minimal.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages-minimal.mermaid @@ -54,7 +54,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 15

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 16, 15

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2 bucket2 Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 15

ROOT Connectionᐸ24ᐳ[28]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages.deopt.mermaid index 7a702606b8..4dd1e7ed24 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages.deopt.mermaid @@ -117,22 +117,22 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 29

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant62,Constant80 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 80, 29, 62

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 80, 29, 62, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 80, 29, 62

ROOT Connectionᐸ25ᐳ[29]
1:
ᐳ: 24, 30, 59
2: PgSelect[31], PgSelect[75]
ᐳ: 61, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 78, 66, 72"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 80, 29, 62, 16

ROOT Connectionᐸ25ᐳ[29]
1:
ᐳ: 24, 30, 59
2: PgSelect[31], PgSelect[75]
ᐳ: 61, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 78, 66, 72"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression24,PgClassExpression30,PgSelect31,PgPageInfo59,Access61,First64,PgSelectSingle65,PgCursor66,PgClassExpression67,List68,Last70,PgSelectSingle71,PgCursor72,PgClassExpression73,List74,PgSelect75,First76,PgSelectSingle77,PgClassExpression78 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ31ᐳ[32]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item32,PgSelectSingle33 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 33, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[33]
1:
ᐳ: 34, 35
2: PgSelect[36]
ᐳ: First[40], PgSelectSingle[41]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 33

ROOT PgSelectSingle{4}ᐸmessagesᐳ[33]
1:
ᐳ: 34, 35
2: PgSelect[36]
ᐳ: First[40], PgSelectSingle[41]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression34,PgClassExpression35,PgSelect36,First40,PgSelectSingle41 bucket5 Bucket6("Bucket 6 (nullableBoundary)
Deps: 41

ROOT PgSelectSingle{5}ᐸusersᐳ[41]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression42,PgClassExpression43 bucket6 - Bucket7("Bucket 7 (nullableBoundary)
Deps: 33, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[33]
1:
ᐳ: 47, 49, 50, 48, 46
2: PgSelect[51]
ᐳ: First[55], PgSelectSingle[56]"):::bucket + Bucket7("Bucket 7 (nullableBoundary)
Deps: 14, 33

ROOT PgSelectSingle{4}ᐸmessagesᐳ[33]
1:
ᐳ: 47, 49, 50, 48, 46
2: PgSelect[51]
ᐳ: First[55], PgSelectSingle[56]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgCursor46,PgClassExpression47,List48,PgClassExpression49,PgClassExpression50,PgSelect51,First55,PgSelectSingle56 bucket7 Bucket8("Bucket 8 (nullableBoundary)
Deps: 56

ROOT PgSelectSingle{7}ᐸusersᐳ[56]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages.mermaid index 3a86c44bc5..45e34900dc 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/condition-featured-messages.mermaid @@ -107,10 +107,10 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 29

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant62 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 29, 15, 62

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 29, 62, 16, 15

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 29, 15, 62

ROOT Connectionᐸ25ᐳ[29]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 29, 62, 15

ROOT Connectionᐸ25ᐳ[29]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgPageInfo59,Access61,First64,PgSelectSingle65,PgCursor66,PgClassExpression67,List68,Last70,PgSelectSingle71,PgCursor72,PgClassExpression73,List74,First76,PgSelectSingle77,PgClassExpression78,Access83,Lambda84,Access85 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ84ᐳ[32]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/exclusively-archived-messages.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/exclusively-archived-messages.deopt.mermaid index 804ec4ca6c..0605e003ba 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/exclusively-archived-messages.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/exclusively-archived-messages.deopt.mermaid @@ -114,22 +114,22 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant60 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28, 60

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 60, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28, 60

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: PgClassExpression[23], PgPageInfo[57]
2: PgSelect[29], PgSelect[73]
ᐳ: 59, 62, 63, 65, 66, 68, 69, 71, 72, 74, 75, 76, 64, 70"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 60, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: PgClassExpression[23], PgPageInfo[57]
2: PgSelect[29], PgSelect[73]
ᐳ: 59, 62, 63, 65, 66, 68, 69, 71, 72, 74, 75, 76, 64, 70"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgSelect29,PgPageInfo57,Access59,First62,PgSelectSingle63,PgCursor64,PgClassExpression65,List66,Last68,PgSelectSingle69,PgCursor70,PgClassExpression71,List72,PgSelect73,First74,PgSelectSingle75,PgClassExpression76 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ29ᐳ[30]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item30,PgSelectSingle31 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 31, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[31]
1:
ᐳ: 32, 33
2: PgSelect[34]
ᐳ: First[38], PgSelectSingle[39]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 31

ROOT PgSelectSingle{4}ᐸmessagesᐳ[31]
1:
ᐳ: 32, 33
2: PgSelect[34]
ᐳ: First[38], PgSelectSingle[39]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression32,PgClassExpression33,PgSelect34,First38,PgSelectSingle39 bucket5 Bucket6("Bucket 6 (nullableBoundary)
Deps: 39

ROOT PgSelectSingle{5}ᐸusersᐳ[39]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression40,PgClassExpression41 bucket6 - Bucket7("Bucket 7 (nullableBoundary)
Deps: 31, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[31]
1:
ᐳ: 45, 47, 48, 46, 44
2: PgSelect[49]
ᐳ: First[53], PgSelectSingle[54]"):::bucket + Bucket7("Bucket 7 (nullableBoundary)
Deps: 14, 31

ROOT PgSelectSingle{4}ᐸmessagesᐳ[31]
1:
ᐳ: 45, 47, 48, 46, 44
2: PgSelect[49]
ᐳ: First[53], PgSelectSingle[54]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgCursor44,PgClassExpression45,List46,PgClassExpression47,PgClassExpression48,PgSelect49,First53,PgSelectSingle54 bucket7 Bucket8("Bucket 8 (nullableBoundary)
Deps: 54

ROOT PgSelectSingle{7}ᐸusersᐳ[54]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/exclusively-archived-messages.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/exclusively-archived-messages.mermaid index a86176851f..d474a3b971 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/exclusively-archived-messages.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/exclusively-archived-messages.mermaid @@ -106,10 +106,10 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant60 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 15, 60

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 60, 16, 15

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 15, 60

ROOT Connectionᐸ24ᐳ[28]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 60, 15

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgPageInfo57,Access59,First62,PgSelectSingle63,PgCursor64,PgClassExpression65,List66,Last68,PgSelectSingle69,PgCursor70,PgClassExpression71,List72,First74,PgSelectSingle75,PgClassExpression76,Access81,Lambda82,Access83 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ82ᐳ[30]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/conditions/include-all-archived.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/conditions/include-all-archived.deopt.mermaid index 3a64c5fa4d..73612df946 100644 --- a/grafast/dataplan-pg/__tests__/queries/conditions/include-all-archived.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/conditions/include-all-archived.deopt.mermaid @@ -58,13 +58,13 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]
1:
ᐳ: 17, 22
2: PgSelect[23]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]
1:
ᐳ: 17, 22
2: PgSelect[23]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17,PgClassExpression22,PgSelect23 bucket2 Bucket3("Bucket 3 (listItem)
Deps: 14

ROOT __Item{3}ᐸ23ᐳ[27]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,__Item27,PgSelectSingle28 bucket3 - Bucket4("Bucket 4 (nullableBoundary)
Deps: 28, 14

ROOT PgSelectSingle{3}ᐸmessagesᐳ[28]
1:
ᐳ: 29, 30
2: PgSelect[31]
ᐳ: First[35], PgSelectSingle[36]"):::bucket + Bucket4("Bucket 4 (nullableBoundary)
Deps: 14, 28

ROOT PgSelectSingle{3}ᐸmessagesᐳ[28]
1:
ᐳ: 29, 30
2: PgSelect[31]
ᐳ: First[35], PgSelectSingle[36]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgClassExpression29,PgClassExpression30,PgSelect31,First35,PgSelectSingle36 bucket4 Bucket5("Bucket 5 (nullableBoundary)
Deps: 36

ROOT PgSelectSingle{4}ᐸusersᐳ[36]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/basics-limit3.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/basics-limit3.deopt.mermaid index 1794ca17c7..1905904094 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/basics-limit3.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/basics-limit3.deopt.mermaid @@ -93,7 +93,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 18

ROOT PgSelectSingle{2}ᐸmessagesᐳ[22]
1:
ᐳ: 24, 26, 27, 25, 23
2: PgSelect[28]
ᐳ: First[32], PgSelectSingle[33]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 22

ROOT PgSelectSingle{2}ᐸmessagesᐳ[22]
1:
ᐳ: 24, 26, 27, 25, 23
2: PgSelect[28]
ᐳ: First[32], PgSelectSingle[33]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor23,PgClassExpression24,List25,PgClassExpression26,PgClassExpression27,PgSelect28,First32,PgSelectSingle33 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 33

ROOT PgSelectSingle{3}ᐸusersᐳ[33]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/basics.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/basics.deopt.mermaid index bf8d690c36..4b70b78e47 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/basics.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/basics.deopt.mermaid @@ -89,7 +89,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 18

ROOT PgSelectSingle{2}ᐸmessagesᐳ[22]
1:
ᐳ: 24, 26, 27, 25, 23
2: PgSelect[28]
ᐳ: First[32], PgSelectSingle[33]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 22

ROOT PgSelectSingle{2}ᐸmessagesᐳ[22]
1:
ᐳ: 24, 26, 27, 25, 23
2: PgSelect[28]
ᐳ: First[32], PgSelectSingle[33]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor23,PgClassExpression24,List25,PgClassExpression26,PgClassExpression27,PgSelect28,First32,PgSelectSingle33 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 33

ROOT PgSelectSingle{3}ᐸusersᐳ[33]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/empty.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/empty.deopt.mermaid index 90f92ed364..6875e797fc 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/empty.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/empty.deopt.mermaid @@ -40,7 +40,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant31 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 31

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 31, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 31

ROOT Connectionᐸ24ᐳ[28]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/empty.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/empty.mermaid index 90f92ed364..6875e797fc 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/empty.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/empty.mermaid @@ -40,7 +40,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant31 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 31

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 31, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 31

ROOT Connectionᐸ24ᐳ[28]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/order.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/order.deopt.mermaid index 03481e5321..21afd3532b 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/order.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/order.deopt.mermaid @@ -105,7 +105,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 20

ROOT __Item{2}ᐸ22ᐳ[23]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item23,PgSelectSingle24 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 24, 20

ROOT PgSelectSingle{2}ᐸmessagesᐳ[24]
1:
ᐳ: 26, 27, 28, 30, 31, 29, 25
2: PgSelect[32]
ᐳ: First[36], PgSelectSingle[37]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 20, 24

ROOT PgSelectSingle{2}ᐸmessagesᐳ[24]
1:
ᐳ: 26, 27, 28, 30, 31, 29, 25
2: PgSelect[32]
ᐳ: First[36], PgSelectSingle[37]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor25,PgClassExpression26,PgClassExpression27,PgClassExpression28,List29,PgClassExpression30,PgClassExpression31,PgSelect32,First36,PgSelectSingle37 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 37

ROOT PgSelectSingle{3}ᐸusersᐳ[37]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/pagination-after.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/pagination-after.deopt.mermaid index 8ac3ec07e5..a34cec8d0a 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/pagination-after.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/pagination-after.deopt.mermaid @@ -100,7 +100,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ21ᐳ[24]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item24,PgSelectSingle25 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 25, 18

ROOT PgSelectSingle{2}ᐸmessagesᐳ[25]
1:
ᐳ: 27, 29, 30, 28, 26
2: PgSelect[31]
ᐳ: First[35], PgSelectSingle[36]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 25

ROOT PgSelectSingle{2}ᐸmessagesᐳ[25]
1:
ᐳ: 27, 29, 30, 28, 26
2: PgSelect[31]
ᐳ: First[35], PgSelectSingle[36]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor26,PgClassExpression27,List28,PgClassExpression29,PgClassExpression30,PgSelect31,First35,PgSelectSingle36 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 36

ROOT PgSelectSingle{3}ᐸusersᐳ[36]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/pagination-before-end-last.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/pagination-before-end-last.deopt.mermaid index 7b538a41fc..f66cbc8342 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/pagination-before-end-last.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/pagination-before-end-last.deopt.mermaid @@ -100,7 +100,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ21ᐳ[24]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item24,PgSelectSingle25 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 25, 18

ROOT PgSelectSingle{2}ᐸmessagesᐳ[25]
1:
ᐳ: 27, 29, 30, 28, 26
2: PgSelect[31]
ᐳ: First[35], PgSelectSingle[36]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 25

ROOT PgSelectSingle{2}ᐸmessagesᐳ[25]
1:
ᐳ: 27, 29, 30, 28, 26
2: PgSelect[31]
ᐳ: First[35], PgSelectSingle[36]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor26,PgClassExpression27,List28,PgClassExpression29,PgClassExpression30,PgSelect31,First35,PgSelectSingle36 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 36

ROOT PgSelectSingle{3}ᐸusersᐳ[36]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/pagination-before-end.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/pagination-before-end.deopt.mermaid index bc3e189c85..da3ae6b113 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/pagination-before-end.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/pagination-before-end.deopt.mermaid @@ -100,7 +100,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ21ᐳ[24]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item24,PgSelectSingle25 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 25, 18

ROOT PgSelectSingle{2}ᐸmessagesᐳ[25]
1:
ᐳ: 27, 29, 30, 28, 26
2: PgSelect[31]
ᐳ: First[35], PgSelectSingle[36]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 25

ROOT PgSelectSingle{2}ᐸmessagesᐳ[25]
1:
ᐳ: 27, 29, 30, 28, 26
2: PgSelect[31]
ᐳ: First[35], PgSelectSingle[36]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor26,PgClassExpression27,List28,PgClassExpression29,PgClassExpression30,PgSelect31,First35,PgSelectSingle36 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 36

ROOT PgSelectSingle{3}ᐸusersᐳ[36]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/pagination-before-last.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/pagination-before-last.deopt.mermaid index 5f921c1ef9..9925b79476 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/pagination-before-last.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/pagination-before-last.deopt.mermaid @@ -100,7 +100,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ21ᐳ[24]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item24,PgSelectSingle25 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 25, 18

ROOT PgSelectSingle{2}ᐸmessagesᐳ[25]
1:
ᐳ: 27, 29, 30, 28, 26
2: PgSelect[31]
ᐳ: First[35], PgSelectSingle[36]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 25

ROOT PgSelectSingle{2}ᐸmessagesᐳ[25]
1:
ᐳ: 27, 29, 30, 28, 26
2: PgSelect[31]
ᐳ: First[35], PgSelectSingle[36]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor26,PgClassExpression27,List28,PgClassExpression29,PgClassExpression30,PgSelect31,First35,PgSelectSingle36 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 36

ROOT PgSelectSingle{3}ᐸusersᐳ[36]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/pagination-before.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/pagination-before.deopt.mermaid index dba641f039..4abff41bd3 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/pagination-before.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/pagination-before.deopt.mermaid @@ -100,7 +100,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ21ᐳ[24]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item24,PgSelectSingle25 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 25, 18

ROOT PgSelectSingle{2}ᐸmessagesᐳ[25]
1:
ᐳ: 27, 29, 30, 28, 26
2: PgSelect[31]
ᐳ: First[35], PgSelectSingle[36]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 25

ROOT PgSelectSingle{2}ᐸmessagesᐳ[25]
1:
ᐳ: 27, 29, 30, 28, 26
2: PgSelect[31]
ᐳ: First[35], PgSelectSingle[36]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor26,PgClassExpression27,List28,PgClassExpression29,PgClassExpression30,PgSelect31,First35,PgSelectSingle36 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 36

ROOT PgSelectSingle{3}ᐸusersᐳ[36]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards-nodes-only.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards-nodes-only.deopt.mermaid index 142fe72d51..f668e7d552 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards-nodes-only.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards-nodes-only.deopt.mermaid @@ -94,16 +94,16 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant43 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28, 43

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 43, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28, 43

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: PgClassExpression[23], PgPageInfo[42]
2: PgSelect[29], PgSelect[58]
ᐳ: 45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 61, 49, 55"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 43, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: PgClassExpression[23], PgPageInfo[42]
2: PgSelect[29], PgSelect[58]
ᐳ: 45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 61, 49, 55"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgSelect29,PgPageInfo42,Access45,First47,PgSelectSingle48,PgCursor49,PgClassExpression50,List51,Last53,PgSelectSingle54,PgCursor55,PgClassExpression56,List57,PgSelect58,First59,PgSelectSingle60,PgClassExpression61 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ29ᐳ[30]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item30,PgSelectSingle31 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 31, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[31]
1:
ᐳ: 32, 33
2: PgSelect[34]
ᐳ: First[38], PgSelectSingle[39]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 31

ROOT PgSelectSingle{4}ᐸmessagesᐳ[31]
1:
ᐳ: 32, 33
2: PgSelect[34]
ᐳ: First[38], PgSelectSingle[39]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression32,PgClassExpression33,PgSelect34,First38,PgSelectSingle39 bucket5 Bucket6("Bucket 6 (nullableBoundary)
Deps: 39

ROOT PgSelectSingle{5}ᐸusersᐳ[39]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards-nodes-only.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards-nodes-only.mermaid index 41a8e06b63..622210873c 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards-nodes-only.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards-nodes-only.mermaid @@ -90,10 +90,10 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant43 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 15, 43

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 43, 16, 15

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 15, 43

ROOT Connectionᐸ24ᐳ[28]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 43, 15

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgPageInfo42,Access45,First47,PgSelectSingle48,PgCursor49,PgClassExpression50,List51,Last53,PgSelectSingle54,PgCursor55,PgClassExpression56,List57,First59,PgSelectSingle60,PgClassExpression61,Access64,Lambda65,Access66 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ65ᐳ[30]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards.deopt.mermaid index a4cad36465..c01e7be17d 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards.deopt.mermaid @@ -114,22 +114,22 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant58 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28, 58

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 58, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28, 58

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: PgClassExpression[23], PgPageInfo[57]
2: PgSelect[29], PgSelect[73]
ᐳ: 60, 62, 63, 65, 66, 68, 69, 71, 72, 74, 75, 76, 64, 70"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 58, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: PgClassExpression[23], PgPageInfo[57]
2: PgSelect[29], PgSelect[73]
ᐳ: 60, 62, 63, 65, 66, 68, 69, 71, 72, 74, 75, 76, 64, 70"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgSelect29,PgPageInfo57,Access60,First62,PgSelectSingle63,PgCursor64,PgClassExpression65,List66,Last68,PgSelectSingle69,PgCursor70,PgClassExpression71,List72,PgSelect73,First74,PgSelectSingle75,PgClassExpression76 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ29ᐳ[30]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item30,PgSelectSingle31 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 31, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[31]
1:
ᐳ: 32, 33
2: PgSelect[34]
ᐳ: First[38], PgSelectSingle[39]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 31

ROOT PgSelectSingle{4}ᐸmessagesᐳ[31]
1:
ᐳ: 32, 33
2: PgSelect[34]
ᐳ: First[38], PgSelectSingle[39]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression32,PgClassExpression33,PgSelect34,First38,PgSelectSingle39 bucket5 Bucket6("Bucket 6 (nullableBoundary)
Deps: 39

ROOT PgSelectSingle{5}ᐸusersᐳ[39]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression40,PgClassExpression41 bucket6 - Bucket7("Bucket 7 (nullableBoundary)
Deps: 31, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[31]
1:
ᐳ: 45, 47, 48, 46, 44
2: PgSelect[49]
ᐳ: First[53], PgSelectSingle[54]"):::bucket + Bucket7("Bucket 7 (nullableBoundary)
Deps: 14, 31

ROOT PgSelectSingle{4}ᐸmessagesᐳ[31]
1:
ᐳ: 45, 47, 48, 46, 44
2: PgSelect[49]
ᐳ: First[53], PgSelectSingle[54]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgCursor44,PgClassExpression45,List46,PgClassExpression47,PgClassExpression48,PgSelect49,First53,PgSelectSingle54 bucket7 Bucket8("Bucket 8 (nullableBoundary)
Deps: 54

ROOT PgSelectSingle{7}ᐸusersᐳ[54]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards.mermaid index bf6661b189..2b21afa5e0 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined-backwards.mermaid @@ -106,10 +106,10 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant58 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 15, 58

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 58, 16, 15

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 15, 58

ROOT Connectionᐸ24ᐳ[28]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 58, 15

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgPageInfo57,Access60,First62,PgSelectSingle63,PgCursor64,PgClassExpression65,List66,Last68,PgSelectSingle69,PgCursor70,PgClassExpression71,List72,First74,PgSelectSingle75,PgClassExpression76,Access81,Lambda82,Access83 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ82ᐳ[30]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined.deopt.mermaid index 91b266efe8..092d4cd097 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined.deopt.mermaid @@ -114,22 +114,22 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14, 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant60 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14, 28, 60

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 28, 60, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 16, 14, 28, 60

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: PgClassExpression[23], PgPageInfo[57]
2: PgSelect[29], PgSelect[73]
ᐳ: 59, 62, 63, 65, 66, 68, 69, 71, 72, 74, 75, 76, 64, 70"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 14, 28, 60, 16

ROOT Connectionᐸ24ᐳ[28]
1:
ᐳ: PgClassExpression[23], PgPageInfo[57]
2: PgSelect[29], PgSelect[73]
ᐳ: 59, 62, 63, 65, 66, 68, 69, 71, 72, 74, 75, 76, 64, 70"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgSelect29,PgPageInfo57,Access59,First62,PgSelectSingle63,PgCursor64,PgClassExpression65,List66,Last68,PgSelectSingle69,PgCursor70,PgClassExpression71,List72,PgSelect73,First74,PgSelectSingle75,PgClassExpression76 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 14

ROOT __Item{4}ᐸ29ᐳ[30]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item30,PgSelectSingle31 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 31, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[31]
1:
ᐳ: 32, 33
2: PgSelect[34]
ᐳ: First[38], PgSelectSingle[39]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 14, 31

ROOT PgSelectSingle{4}ᐸmessagesᐳ[31]
1:
ᐳ: 32, 33
2: PgSelect[34]
ᐳ: First[38], PgSelectSingle[39]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression32,PgClassExpression33,PgSelect34,First38,PgSelectSingle39 bucket5 Bucket6("Bucket 6 (nullableBoundary)
Deps: 39

ROOT PgSelectSingle{5}ᐸusersᐳ[39]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression40,PgClassExpression41 bucket6 - Bucket7("Bucket 7 (nullableBoundary)
Deps: 31, 14

ROOT PgSelectSingle{4}ᐸmessagesᐳ[31]
1:
ᐳ: 45, 47, 48, 46, 44
2: PgSelect[49]
ᐳ: First[53], PgSelectSingle[54]"):::bucket + Bucket7("Bucket 7 (nullableBoundary)
Deps: 14, 31

ROOT PgSelectSingle{4}ᐸmessagesᐳ[31]
1:
ᐳ: 45, 47, 48, 46, 44
2: PgSelect[49]
ᐳ: First[53], PgSelectSingle[54]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgCursor44,PgClassExpression45,List46,PgClassExpression47,PgClassExpression48,PgSelect49,First53,PgSelectSingle54 bucket7 Bucket8("Bucket 8 (nullableBoundary)
Deps: 54

ROOT PgSelectSingle{7}ᐸusersᐳ[54]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined.mermaid b/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined.mermaid index 8f9b4a0694..1febcb4fe3 100644 --- a/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/connections/pagination-when-inlined.mermaid @@ -106,10 +106,10 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 28

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16,Constant60 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 28, 15, 60

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 28, 60, 16, 15

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 15, 60

ROOT Connectionᐸ24ᐳ[28]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 28, 60, 15

ROOT Connectionᐸ24ᐳ[28]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgPageInfo57,Access59,First62,PgSelectSingle63,PgCursor64,PgClassExpression65,List66,Last68,PgSelectSingle69,PgCursor70,PgClassExpression71,List72,First74,PgSelectSingle75,PgClassExpression76,Access81,Lambda82,Access83 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ82ᐳ[30]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-list-set.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-list-set.deopt.mermaid index 8c378e6eed..450f78af59 100644 --- a/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-list-set.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-list-set.deopt.mermaid @@ -56,7 +56,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]
1:
ᐳ: PgClassExpression[17]
2: PgSelect[18]
3: __ListTransform[22]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]
1:
ᐳ: PgClassExpression[17]
2: PgSelect[18]
3: __ListTransform[22]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17,PgSelect18,__ListTransform22 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgClassExpression{3}ᐸ__forums_m..._set_idx__ᐳ[25]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.defer.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.defer.deopt.mermaid index 72888875d7..2def36c812 100644 --- a/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.defer.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.defer.deopt.mermaid @@ -72,7 +72,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17,PgClassExpression26 bucket2 Bucket3("Bucket 3 (defer)
Deps: 14, 16, 26

1: PgSelect[18]
2: __ListTransform[22]
3: __ListTransform[29]
ᐳ: Lambda[33]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.defer.mermaid b/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.defer.mermaid index 72888875d7..2def36c812 100644 --- a/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.defer.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.defer.mermaid @@ -72,7 +72,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 14

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 14

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 14, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17,PgClassExpression26 bucket2 Bucket3("Bucket 3 (defer)
Deps: 14, 16, 26

1: PgSelect[18]
2: __ListTransform[22]
3: __ListTransform[29]
ᐳ: Lambda[33]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.deopt.mermaid index 7893acbfa6..32aca8a68c 100644 --- a/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.deopt.mermaid @@ -72,7 +72,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 18

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 18

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]
1:
ᐳ: 17, 26
2: __ListTransform[22]
3: __ListTransform[29]
ᐳ: Lambda[33]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 18, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]
1:
ᐳ: 17, 26
2: __ListTransform[22]
3: __ListTransform[29]
ᐳ: Lambda[33]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17,__ListTransform22,PgClassExpression26,__ListTransform29,Lambda33 bucket2 Bucket3("Bucket 3 (subroutine)
Deps: 26

ROOT Lambda{3}[28]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.mermaid b/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.mermaid index 7893acbfa6..32aca8a68c 100644 --- a/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/functions/computed-column-forums-messages-with-many-transforms.mermaid @@ -72,7 +72,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 18

ROOT __Item{1}ᐸ11ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgSelectSingle16 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 16, 18

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]
1:
ᐳ: 17, 26
2: __ListTransform[22]
3: __ListTransform[29]
ᐳ: Lambda[33]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 18, 16

ROOT PgSelectSingle{1}ᐸforumsᐳ[16]
1:
ᐳ: 17, 26
2: __ListTransform[22]
3: __ListTransform[29]
ᐳ: Lambda[33]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression17,__ListTransform22,PgClassExpression26,__ListTransform29,Lambda33 bucket2 Bucket3("Bucket 3 (subroutine)
Deps: 26

ROOT Lambda{3}[28]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics-with-fragments.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics-with-fragments.deopt.mermaid index 4fa3296a05..48a411abe9 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics-with-fragments.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics-with-fragments.deopt.mermaid @@ -116,7 +116,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,PgClassExpression14,PgSelect15,__ListTransform19 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸrelational_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics-with-fragments.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics-with-fragments.mermaid index 6a0c24c349..8f16281e43 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics-with-fragments.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics-with-fragments.mermaid @@ -114,7 +114,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 11, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[110]
2: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12, 11

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[110]
2: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,__ListTransform19,Access110 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸrelational_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics.deopt.mermaid index 0e767c1a4a..673dcd3564 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics.deopt.mermaid @@ -98,7 +98,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,PgClassExpression14,PgSelect15,__ListTransform19 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸrelational_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics.mermaid index 2ad6dab6b5..e689216f2b 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/basics.mermaid @@ -96,7 +96,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 11, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[101]
2: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12, 11

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[101]
2: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,__ListTransform19,Access101 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸrelational_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more-fragments.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more-fragments.deopt.mermaid index d039f349d8..8b3ce2dc26 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more-fragments.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more-fragments.deopt.mermaid @@ -210,7 +210,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,PgClassExpression14,PgSelect15,__ListTransform19 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸrelational_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more-fragments.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more-fragments.mermaid index 2672bf5753..2b0da0c807 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more-fragments.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more-fragments.mermaid @@ -208,7 +208,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 11, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[815]
2: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12, 11

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[815]
2: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,__ListTransform19,Access815 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸrelational_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more.deopt.mermaid index 4057fe6ba1..c601a1c787 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more.deopt.mermaid @@ -174,7 +174,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,PgClassExpression14,PgSelect15,__ListTransform19 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸrelational_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more.mermaid index acaecc90dc..f092800a99 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested-more.mermaid @@ -172,7 +172,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 11, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[761]
2: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12, 11

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[761]
2: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,__ListTransform19,Access761 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸrelational_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested.deopt.mermaid index 33ec03e5a2..d0dec2cede 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested.deopt.mermaid @@ -134,7 +134,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,PgClassExpression14,PgSelect15,__ListTransform19 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸrelational_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested.mermaid index 73bd5a1c4a..7793ffc62c 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-relational/nested.mermaid @@ -132,7 +132,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 11, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[371]
2: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12, 11

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[371]
2: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,__ListTransform19,Access371 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸrelational_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/basics-with-fragments.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/basics-with-fragments.deopt.mermaid index 22cf07185a..f6c3daee87 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/basics-with-fragments.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/basics-with-fragments.deopt.mermaid @@ -78,7 +78,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,PgClassExpression14,PgSelect15,__ListTransform19 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸsingle_table_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/basics.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/basics.deopt.mermaid index 54473e5133..0eeb13fb2b 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/basics.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/basics.deopt.mermaid @@ -70,7 +70,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,PgClassExpression14,PgSelect15,__ListTransform19 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸsingle_table_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more-fragments.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more-fragments.deopt.mermaid index d984a62bb8..6a470f478e 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more-fragments.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more-fragments.deopt.mermaid @@ -132,7 +132,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,PgClassExpression14,PgSelect15,__ListTransform19 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸsingle_table_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more-fragments.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more-fragments.mermaid index b5ccbe4595..f86aec181c 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more-fragments.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more-fragments.mermaid @@ -130,7 +130,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 11, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[611]
2: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12, 11

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[611]
2: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,__ListTransform19,Access611 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸsingle_table_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more.deopt.mermaid index 3b19481742..1e9ee69f0b 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more.deopt.mermaid @@ -116,7 +116,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,PgClassExpression14,PgSelect15,__ListTransform19 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸsingle_table_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more.mermaid index 6ee3189e78..babd4c2c2e 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested-more.mermaid @@ -114,7 +114,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 11, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[557]
2: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12, 11

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[557]
2: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,__ListTransform19,Access557 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸsingle_table_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested.deopt.mermaid index 886a1b9afd..d77f2fec8c 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested.deopt.mermaid @@ -76,7 +76,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: 13, 14
2: PgSelect[15]
3: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,PgClassExpression14,PgSelect15,__ListTransform19 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸsingle_table_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested.mermaid index 5f65d2cb43..6def18bfe1 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-single-table/nested.mermaid @@ -74,7 +74,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 10

ROOT __Item{1}ᐸ7ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,PgSelectSingle12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 11, 10

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[167]
2: __ListTransform[19]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 10, 12, 11

ROOT PgSelectSingle{1}ᐸpeopleᐳ[12]
1:
ᐳ: PgClassExpression[13], Access[167]
2: __ListTransform[19]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,PgClassExpression13,__ListTransform19,Access167 bucket2 Bucket3("Bucket 3 (subroutine)
ROOT PgSelectSingle{3}ᐸsingle_table_itemsᐳ[21]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilities.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilities.deopt.mermaid index f52f12931a..b00bc46593 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilities.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilities.deopt.mermaid @@ -73,7 +73,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 12

ROOT __Item{1}ᐸ9ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgUnionAllSingle16,Access17 bucket1 - Bucket2("Bucket 2 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 17, 12, 16
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[18], JSONParse[31]
ᐳ: Access[19], Access[32]
2: PgSelect[20], PgSelect[33]
ᐳ: 24, 25, 26, 27, 28, 29, 37, 38, 39, 40, 41, 42"):::bucket + Bucket2("Bucket 2 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 12, 17, 16
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[18], JSONParse[31]
ᐳ: Access[19], Access[32]
2: PgSelect[20], PgSelect[33]
ᐳ: 24, 25, 26, 27, 28, 29, 37, 38, 39, 40, 41, 42"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,JSONParse18,Access19,PgSelect20,First24,PgSelectSingle25,PgClassExpression26,PgClassExpression27,PgClassExpression28,PgClassExpression29,JSONParse31,Access32,PgSelect33,First37,PgSelectSingle38,PgClassExpression39,PgClassExpression40,PgClassExpression41,PgClassExpression42 bucket2 Bucket0 --> Bucket1 diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilities.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilities.mermaid index f52f12931a..b00bc46593 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilities.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilities.mermaid @@ -73,7 +73,7 @@ graph TD Bucket1("Bucket 1 (listItem)
Deps: 12

ROOT __Item{1}ᐸ9ᐳ[15]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item15,PgUnionAllSingle16,Access17 bucket1 - Bucket2("Bucket 2 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 17, 12, 16
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[18], JSONParse[31]
ᐳ: Access[19], Access[32]
2: PgSelect[20], PgSelect[33]
ᐳ: 24, 25, 26, 27, 28, 29, 37, 38, 39, 40, 41, 42"):::bucket + Bucket2("Bucket 2 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 12, 17, 16
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[18], JSONParse[31]
ᐳ: Access[19], Access[32]
2: PgSelect[20], PgSelect[33]
ᐳ: 24, 25, 26, 27, 28, 29, 37, 38, 39, 40, 41, 42"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,JSONParse18,Access19,PgSelect20,First24,PgSelectSingle25,PgClassExpression26,PgClassExpression27,PgClassExpression28,PgClassExpression29,JSONParse31,Access32,PgSelect33,First37,PgSelectSingle38,PgClassExpression39,PgClassExpression40,PgClassExpression41,PgClassExpression42 bucket2 Bucket0 --> Bucket1 diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.after1.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.after1.deopt.mermaid index f71d4d61ac..ea0c4cc3d9 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.after1.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.after1.deopt.mermaid @@ -101,10 +101,10 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ21ᐳ[22]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item22,PgUnionAllSingle23 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 23, 18

ROOT PgUnionAllSingle{2}[23]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 23

ROOT PgUnionAllSingle{2}[23]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor24,Access31,Access32,Access33,List34 bucket3 - Bucket4("Bucket 4 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 33, 18, 23
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[36], JSONParse[49]
ᐳ: Access[37], Access[50]
2: PgSelect[38], PgSelect[51]
ᐳ: 42, 43, 44, 45, 46, 47, 55, 56, 57, 58, 59, 60"):::bucket + Bucket4("Bucket 4 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 18, 33, 23
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[36], JSONParse[49]
ᐳ: Access[37], Access[50]
2: PgSelect[38], PgSelect[51]
ᐳ: 42, 43, 44, 45, 46, 47, 55, 56, 57, 58, 59, 60"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,JSONParse36,Access37,PgSelect38,First42,PgSelectSingle43,PgClassExpression44,PgClassExpression45,PgClassExpression46,PgClassExpression47,JSONParse49,Access50,PgSelect51,First55,PgSelectSingle56,PgClassExpression57,PgClassExpression58,PgClassExpression59,PgClassExpression60 bucket4 Bucket0 --> Bucket1 diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.after1.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.after1.mermaid index f71d4d61ac..ea0c4cc3d9 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.after1.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.after1.mermaid @@ -101,10 +101,10 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ21ᐳ[22]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item22,PgUnionAllSingle23 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 23, 18

ROOT PgUnionAllSingle{2}[23]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 23

ROOT PgUnionAllSingle{2}[23]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor24,Access31,Access32,Access33,List34 bucket3 - Bucket4("Bucket 4 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 33, 18, 23
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[36], JSONParse[49]
ᐳ: Access[37], Access[50]
2: PgSelect[38], PgSelect[51]
ᐳ: 42, 43, 44, 45, 46, 47, 55, 56, 57, 58, 59, 60"):::bucket + Bucket4("Bucket 4 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 18, 33, 23
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[36], JSONParse[49]
ᐳ: Access[37], Access[50]
2: PgSelect[38], PgSelect[51]
ᐳ: 42, 43, 44, 45, 46, 47, 55, 56, 57, 58, 59, 60"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,JSONParse36,Access37,PgSelect38,First42,PgSelectSingle43,PgClassExpression44,PgClassExpression45,PgClassExpression46,PgClassExpression47,JSONParse49,Access50,PgSelect51,First55,PgSelectSingle56,PgClassExpression57,PgClassExpression58,PgClassExpression59,PgClassExpression60 bucket4 Bucket0 --> Bucket1 diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.before1.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.before1.deopt.mermaid index 1c0c18a45d..7ed3cafbe3 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.before1.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.before1.deopt.mermaid @@ -101,10 +101,10 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ21ᐳ[22]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item22,PgUnionAllSingle23 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 23, 18

ROOT PgUnionAllSingle{2}[23]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 23

ROOT PgUnionAllSingle{2}[23]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor24,Access31,Access32,Access33,List34 bucket3 - Bucket4("Bucket 4 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 33, 18, 23
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[36], JSONParse[49]
ᐳ: Access[37], Access[50]
2: PgSelect[38], PgSelect[51]
ᐳ: 42, 43, 44, 45, 46, 47, 55, 56, 57, 58, 59, 60"):::bucket + Bucket4("Bucket 4 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 18, 33, 23
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[36], JSONParse[49]
ᐳ: Access[37], Access[50]
2: PgSelect[38], PgSelect[51]
ᐳ: 42, 43, 44, 45, 46, 47, 55, 56, 57, 58, 59, 60"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,JSONParse36,Access37,PgSelect38,First42,PgSelectSingle43,PgClassExpression44,PgClassExpression45,PgClassExpression46,PgClassExpression47,JSONParse49,Access50,PgSelect51,First55,PgSelectSingle56,PgClassExpression57,PgClassExpression58,PgClassExpression59,PgClassExpression60 bucket4 Bucket0 --> Bucket1 diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.before1.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.before1.mermaid index 1c0c18a45d..7ed3cafbe3 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.before1.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.before1.mermaid @@ -101,10 +101,10 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ21ᐳ[22]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item22,PgUnionAllSingle23 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 23, 18

ROOT PgUnionAllSingle{2}[23]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 23

ROOT PgUnionAllSingle{2}[23]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor24,Access31,Access32,Access33,List34 bucket3 - Bucket4("Bucket 4 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 33, 18, 23
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[36], JSONParse[49]
ᐳ: Access[37], Access[50]
2: PgSelect[38], PgSelect[51]
ᐳ: 42, 43, 44, 45, 46, 47, 55, 56, 57, 58, 59, 60"):::bucket + Bucket4("Bucket 4 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 18, 33, 23
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[36], JSONParse[49]
ᐳ: Access[37], Access[50]
2: PgSelect[38], PgSelect[51]
ᐳ: 42, 43, 44, 45, 46, 47, 55, 56, 57, 58, 59, 60"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,JSONParse36,Access37,PgSelect38,First42,PgSelectSingle43,PgClassExpression44,PgClassExpression45,PgClassExpression46,PgClassExpression47,JSONParse49,Access50,PgSelect51,First55,PgSelectSingle56,PgClassExpression57,PgClassExpression58,PgClassExpression59,PgClassExpression60 bucket4 Bucket0 --> Bucket1 diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.deopt.mermaid index 0b335948f4..11ad8120fa 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.deopt.mermaid @@ -84,10 +84,10 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgUnionAllSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 18

ROOT PgUnionAllSingle{2}[22]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 22

ROOT PgUnionAllSingle{2}[22]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor23,Access24,Access25,Access26,List27 bucket3 - Bucket4("Bucket 4 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 26, 18, 22
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[29], JSONParse[42]
ᐳ: Access[30], Access[43]
2: PgSelect[31], PgSelect[44]
ᐳ: 35, 36, 37, 38, 39, 40, 48, 49, 50, 51, 52, 53"):::bucket + Bucket4("Bucket 4 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 18, 26, 22
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[29], JSONParse[42]
ᐳ: Access[30], Access[43]
2: PgSelect[31], PgSelect[44]
ᐳ: 35, 36, 37, 38, 39, 40, 48, 49, 50, 51, 52, 53"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,JSONParse29,Access30,PgSelect31,First35,PgSelectSingle36,PgClassExpression37,PgClassExpression38,PgClassExpression39,PgClassExpression40,JSONParse42,Access43,PgSelect44,First48,PgSelectSingle49,PgClassExpression50,PgClassExpression51,PgClassExpression52,PgClassExpression53 bucket4 Bucket0 --> Bucket1 diff --git a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.mermaid b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.mermaid index 0b335948f4..11ad8120fa 100644 --- a/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/interfaces-via-union-all/vulnerabilitiesConnection.mermaid @@ -84,10 +84,10 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgUnionAllSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 18

ROOT PgUnionAllSingle{2}[22]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 22

ROOT PgUnionAllSingle{2}[22]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor23,Access24,Access25,Access26,List27 bucket3 - Bucket4("Bucket 4 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 26, 18, 22
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[29], JSONParse[42]
ᐳ: Access[30], Access[43]
2: PgSelect[31], PgSelect[44]
ᐳ: 35, 36, 37, 38, 39, 40, 48, 49, 50, 51, 52, 53"):::bucket + Bucket4("Bucket 4 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 18, 26, 22
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[29], JSONParse[42]
ᐳ: Access[30], Access[43]
2: PgSelect[31], PgSelect[44]
ᐳ: 35, 36, 37, 38, 39, 40, 48, 49, 50, 51, 52, 53"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,JSONParse29,Access30,PgSelect31,First35,PgSelectSingle36,PgClassExpression37,PgClassExpression38,PgClassExpression39,PgClassExpression40,JSONParse42,Access43,PgSelect44,First48,PgSelectSingle49,PgClassExpression50,PgClassExpression51,PgClassExpression52,PgClassExpression53 bucket4 Bucket0 --> Bucket1 diff --git a/grafast/dataplan-pg/__tests__/queries/unions-table/bookmarks.deopt.mermaid b/grafast/dataplan-pg/__tests__/queries/unions-table/bookmarks.deopt.mermaid index de6b62f319..4273a5446d 100644 --- a/grafast/dataplan-pg/__tests__/queries/unions-table/bookmarks.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/unions-table/bookmarks.deopt.mermaid @@ -132,7 +132,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 11

ROOT __Item{2}ᐸ86ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 11

ROOT PgSelectSingle{2}ᐸperson_bookmarksᐳ[22]
1:
ᐳ: 23, 24, 32, 33, 34, 35, 36, 37
2: PgSelect[25]
ᐳ: First[29], PgSelectSingle[30]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 11, 22

ROOT PgSelectSingle{2}ᐸperson_bookmarksᐳ[22]
1:
ᐳ: 23, 24, 32, 33, 34, 35, 36, 37
2: PgSelect[25]
ᐳ: First[29], PgSelectSingle[30]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression24,PgSelect25,First29,PgSelectSingle30,PgClassExpression32,PgClassExpression33,PgClassExpression34,PgClassExpression35,List36,PgPolymorphic37 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 30

ROOT PgSelectSingle{3}ᐸpeopleᐳ[30]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/queries/unions-table/bookmarks.mermaid b/grafast/dataplan-pg/__tests__/queries/unions-table/bookmarks.mermaid index 5d69b235bd..951e06c931 100644 --- a/grafast/dataplan-pg/__tests__/queries/unions-table/bookmarks.mermaid +++ b/grafast/dataplan-pg/__tests__/queries/unions-table/bookmarks.mermaid @@ -116,7 +116,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 11

ROOT __Item{2}ᐸ94ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 11

ROOT PgSelectSingle{2}ᐸperson_bookmarksᐳ[22]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 11, 22

ROOT PgSelectSingle{2}ᐸperson_bookmarksᐳ[22]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgSelectSingle30,PgClassExpression32,PgClassExpression33,PgClassExpression34,PgClassExpression35,List36,PgPolymorphic37,RemapKeys86 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 30

ROOT PgSelectSingle{3}ᐸpeopleᐳ[30]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-messages.deopt.mermaid b/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-messages.deopt.mermaid index b82e2f28c8..23381b808a 100644 --- a/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-messages.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-messages.deopt.mermaid @@ -82,10 +82,10 @@ graph TD Bucket1("Bucket 1 (subscription)
Deps: 20, 5

ROOT __Item{1}ᐸ10ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,JSONParse12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 20

ROOT JSONParse{1}ᐸ11ᐳ[12]
1:
ᐳ: Access[14], Access[16], Lambda[15]
2: PgSelect[17]
ᐳ: First[21], PgSelectSingle[22]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 20, 12

ROOT JSONParse{1}ᐸ11ᐳ[12]
1:
ᐳ: Access[14], Access[16], Lambda[15]
2: PgSelect[17]
ᐳ: First[21], PgSelectSingle[22]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,Access14,Lambda15,Access16,PgSelect17,First21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 20

ROOT PgSelectSingle{2}ᐸmessagesᐳ[22]
1:
ᐳ: 23, 24, 25, 26, 27, 38
2: PgSelect[28], PgSelect[39]
ᐳ: 32, 33, 43, 44"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 20, 22

ROOT PgSelectSingle{2}ᐸmessagesᐳ[22]
1:
ᐳ: 23, 24, 25, 26, 27, 38
2: PgSelect[28], PgSelect[39]
ᐳ: 32, 33, 43, 44"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression24,PgClassExpression25,PgClassExpression26,PgClassExpression27,PgSelect28,First32,PgSelectSingle33,PgClassExpression38,PgSelect39,First43,PgSelectSingle44 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 33, 27

ROOT PgSelectSingle{3}ᐸforumsᐳ[33]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-messages.mermaid b/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-messages.mermaid index 950709cfc8..8f00a3e1a1 100644 --- a/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-messages.mermaid +++ b/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-messages.mermaid @@ -76,7 +76,7 @@ graph TD Bucket1("Bucket 1 (subscription)
Deps: 3, 5

ROOT __Item{1}ᐸ10ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,JSONParse12,Access18,Access19,Object20 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 20

ROOT JSONParse{1}ᐸ11ᐳ[12]
1:
ᐳ: Access[14], Access[16], Lambda[15]
2: PgSelect[17]
ᐳ: First[21], PgSelectSingle[22]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 20, 12

ROOT JSONParse{1}ᐸ11ᐳ[12]
1:
ᐳ: Access[14], Access[16], Lambda[15]
2: PgSelect[17]
ᐳ: First[21], PgSelectSingle[22]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,Access14,Lambda15,Access16,PgSelect17,First21,PgSelectSingle22 bucket2 Bucket3("Bucket 3 (nullableBoundary)
Deps: 22

ROOT PgSelectSingle{2}ᐸmessagesᐳ[22]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-single-message-evolve.deopt.mermaid b/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-single-message-evolve.deopt.mermaid index 5e1744bbc1..14db8effee 100644 --- a/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-single-message-evolve.deopt.mermaid +++ b/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-single-message-evolve.deopt.mermaid @@ -82,10 +82,10 @@ graph TD Bucket1("Bucket 1 (subscription)
Deps: 20, 5

ROOT __Item{1}ᐸ10ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,JSONParse12 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 20

ROOT JSONParse{1}ᐸ11ᐳ[12]
1:
ᐳ: Access[14], Access[16], Lambda[15]
2: PgSelect[17]
ᐳ: First[21], PgSelectSingle[22]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 20, 12

ROOT JSONParse{1}ᐸ11ᐳ[12]
1:
ᐳ: Access[14], Access[16], Lambda[15]
2: PgSelect[17]
ᐳ: First[21], PgSelectSingle[22]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,Access14,Lambda15,Access16,PgSelect17,First21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 20

ROOT PgSelectSingle{2}ᐸmessagesᐳ[22]
1:
ᐳ: 23, 24, 25, 26, 27, 38
2: PgSelect[28], PgSelect[39]
ᐳ: 32, 33, 43, 44"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 20, 22

ROOT PgSelectSingle{2}ᐸmessagesᐳ[22]
1:
ᐳ: 23, 24, 25, 26, 27, 38
2: PgSelect[28], PgSelect[39]
ᐳ: 32, 33, 43, 44"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression24,PgClassExpression25,PgClassExpression26,PgClassExpression27,PgSelect28,First32,PgSelectSingle33,PgClassExpression38,PgSelect39,First43,PgSelectSingle44 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 33, 27

ROOT PgSelectSingle{3}ᐸforumsᐳ[33]"):::bucket diff --git a/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-single-message-evolve.mermaid b/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-single-message-evolve.mermaid index 4d3fe5b065..ef0a902c78 100644 --- a/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-single-message-evolve.mermaid +++ b/grafast/dataplan-pg/__tests__/subscriptions/basics/forum-single-message-evolve.mermaid @@ -76,7 +76,7 @@ graph TD Bucket1("Bucket 1 (subscription)
Deps: 3, 5

ROOT __Item{1}ᐸ10ᐳ[11]"):::bucket classDef bucket1 stroke:#00bfff class Bucket1,__Item11,JSONParse12,Access18,Access19,Object20 bucket1 - Bucket2("Bucket 2 (nullableBoundary)
Deps: 12, 20

ROOT JSONParse{1}ᐸ11ᐳ[12]
1:
ᐳ: Access[14], Access[16], Lambda[15]
2: PgSelect[17]
ᐳ: First[21], PgSelectSingle[22]"):::bucket + Bucket2("Bucket 2 (nullableBoundary)
Deps: 20, 12

ROOT JSONParse{1}ᐸ11ᐳ[12]
1:
ᐳ: Access[14], Access[16], Lambda[15]
2: PgSelect[17]
ᐳ: First[21], PgSelectSingle[22]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,Access14,Lambda15,Access16,PgSelect17,First21,PgSelectSingle22 bucket2 Bucket3("Bucket 3 (nullableBoundary)
Deps: 22

ROOT PgSelectSingle{2}ᐸmessagesᐳ[22]"):::bucket From 7b6a4e4895f8c4b3a65a19a671e41541ebab9525 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 22 Feb 2024 12:46:53 +0000 Subject: [PATCH 14/48] Use test mode; use pretty SQL in test mode --- grafast/dataplan-pg/package.json | 2 +- jest.config.base.js | 2 +- utils/pg-sql2/src/index.ts | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/grafast/dataplan-pg/package.json b/grafast/dataplan-pg/package.json index 8a5f2dffd1..64ec96d0c6 100644 --- a/grafast/dataplan-pg/package.json +++ b/grafast/dataplan-pg/package.json @@ -20,7 +20,7 @@ "scripts": { "update-schema": "ts-node ./__tests__/exampleSchema.ts", "test:install-schema": "psql -X1v ON_ERROR_STOP=1 -f __tests__/schema.sql -f __tests__/sequence_reset.sql \"${TEST_DATABASE_URL:-graphile_crystal}\"", - "test": "yarn test:install-schema && jest -i", + "test": "GRAPHILE_ENV=test yarn test:install-schema && jest -i", "posttest": "yarn test:exportSchema:graphql-js && yarn test:exportSchema:typeDefs", "test:exportSchema:graphql-js": "ENABLE_DEFER_STREAM=1 ts-node ./scripts/exportExampleSchema.ts graphql-js && node ./scripts/runExampleSchema.mjs", "test:exportSchema:typeDefs": "ENABLE_DEFER_STREAM=1 ts-node ./scripts/exportExampleSchema.ts typeDefs && node ./scripts/runExampleSchema.mjs", diff --git a/jest.config.base.js b/jest.config.base.js index 9a5b2e3b18..32f06cd2bb 100644 --- a/jest.config.base.js +++ b/jest.config.base.js @@ -1,5 +1,5 @@ if (!("GRAPHILE_ENV" in process.env)) { - process.env.GRAPHILE_ENV = "development"; + process.env.GRAPHILE_ENV = "test"; } module.exports = (dir) => { const packageJson = require(`${dir}/package.json`); diff --git a/utils/pg-sql2/src/index.ts b/utils/pg-sql2/src/index.ts index b3adeef739..9a11f52e98 100644 --- a/utils/pg-sql2/src/index.ts +++ b/utils/pg-sql2/src/index.ts @@ -24,7 +24,9 @@ function exportAs(thing: T, exportName: string) { export const $$symbolToIdentifier = Symbol("symbolToIdentifier"); const isDev = - typeof process !== "undefined" && process.env.GRAPHILE_ENV === "development"; + typeof process !== "undefined" && + (process.env.GRAPHILE_ENV === "development" || + process.env.GRAPHILE_ENV === "test"); /** * Represents raw SQL, the text will be output verbatim into the compiled query. From b09c19d8d0d232aaee308778c966729387ffb00d Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 22 Feb 2024 13:05:10 +0000 Subject: [PATCH 15/48] Prevent defer hang --- grafast/grafast/src/engine/executeBucket.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/grafast/grafast/src/engine/executeBucket.ts b/grafast/grafast/src/engine/executeBucket.ts index 1f192f642d..25c0d0f4ed 100644 --- a/grafast/grafast/src/engine/executeBucket.ts +++ b/grafast/grafast/src/engine/executeBucket.ts @@ -269,19 +269,14 @@ export function executeBucket( }> | undefined; + // TODO: it seems that if this throws an error it results in a permanent + // hang of defers? In the mean time... Don't throw any errors here! const success = ( finishedStep: ExecutableStep, bucket: Bucket, resultIndex: number, value: unknown, ) => { - if (isDev && finishedStep._isUnary && resultIndex !== 0) { - throw new Error( - `GrafastInternalError<631aafcc-c40c-4fe2-948e-3f06298eb40c>: A unary step must have exactly one result, but ${finishedStep}'s ${resultIndex}th value is ${inspect( - value, - )}`, - ); - } let proto: any; if ( // Fast-lane for non-objects From fcdcc9470cdcf6f68cc6688ae8491d7d367a41c3 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 22 Feb 2024 14:22:59 +0000 Subject: [PATCH 16/48] Fix comparison of errors --- grafast/dataplan-pg/__tests__/helpers.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/grafast/dataplan-pg/__tests__/helpers.ts b/grafast/dataplan-pg/__tests__/helpers.ts index 6d6375a750..2947be0567 100644 --- a/grafast/dataplan-pg/__tests__/helpers.ts +++ b/grafast/dataplan-pg/__tests__/helpers.ts @@ -569,5 +569,9 @@ export const assertErrorsMatch = async ( ): Promise => { const { errors: errors1 } = await result1; const { errors: errors2 } = await result2; - expect(errors2).toEqual(errors1); + const toJSON = (obj) => + typeof obj.toJSON === "function" ? obj.toJSON() : obj; + const jsonified1 = errors1 ? errors1.map(toJSON) : errors1; + const jsonified2 = errors2 ? errors2.map(toJSON) : errors2; + expect(jsonified1).toEqual(jsonified2); }; From d72a8697db9ea74aca39f73e0a177188ac304ee0 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 22 Feb 2024 15:26:37 +0000 Subject: [PATCH 17/48] Fix the bug --- grafast/grafast/src/engine/executeBucket.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/grafast/grafast/src/engine/executeBucket.ts b/grafast/grafast/src/engine/executeBucket.ts index 25c0d0f4ed..ad60329e49 100644 --- a/grafast/grafast/src/engine/executeBucket.ts +++ b/grafast/grafast/src/engine/executeBucket.ts @@ -414,7 +414,8 @@ export function executeBucket( for (const allStepsIndex of indexesToProcess) { const step = _allSteps[allStepsIndex]; const result = results[allStepsIndex]!; - for (let dataIndex = 0; dataIndex < size; dataIndex++) { + const count = step._isUnary ? 1 : size; + for (let dataIndex = 0; dataIndex < count; dataIndex++) { const val = result[dataIndex]; if (step.isSyncAndSafe || !isPromiseLike(val)) { success(step, bucket, dataIndex, val); From 432ee9db478078b36905bf7edbc02d27a3b2e070 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 22 Feb 2024 15:30:41 +0000 Subject: [PATCH 18/48] Various unary fixes --- grafast/grafast/src/engine/executeBucket.ts | 23 ++++++++++++++---- grafast/grafast/src/prepare.ts | 2 +- grafast/grafast/src/steps/applyTransforms.ts | 23 ++++++++++++------ grafast/grafast/src/steps/listTransform.ts | 25 ++++++++++++++------ 4 files changed, 53 insertions(+), 20 deletions(-) diff --git a/grafast/grafast/src/engine/executeBucket.ts b/grafast/grafast/src/engine/executeBucket.ts index ad60329e49..3a49bc8ba6 100644 --- a/grafast/grafast/src/engine/executeBucket.ts +++ b/grafast/grafast/src/engine/executeBucket.ts @@ -233,7 +233,8 @@ export function executeBucket( const result = results[allStepsIndex]; const finishedStep = _allSteps[allStepsIndex]; const resultLength = result?.length; - if (resultLength !== size) { + const expectedSize = finishedStep._isUnary ? 1 : size; + if (resultLength !== expectedSize) { if (!Array.isArray(result)) { throw new Error( `Result from ${finishedStep} should be an array, instead received ${inspect( @@ -243,11 +244,13 @@ export function executeBucket( ); } throw new Error( - `Result array from ${finishedStep} should have length ${size}, instead it had length ${result.length}`, + `Result array from ${finishedStep} should have length ${expectedSize}${ + finishedStep._isUnary ? " (because it's unary)" : "" + }, instead it had length ${result.length}`, ); } if (finishedStep._isUnary) { - bucket.unaryStore.set(finishedStep.id, null); // TODO: what placeholder value should we use? + // Handled later } else { bucket.store.set(finishedStep.id, arrayOfLength(size)); } @@ -668,6 +671,11 @@ export function executeBucket( dependencies: Array | null>, extra: ExecutionExtra, ): PromiseOrDirect | GrafastResultStreamList> { + if (isDev && step._isUnary && size !== 1) { + throw new Error( + `GrafastInternalError<84a6cdfa-e8fe-4dea-85fe-9426a6a78027>: ${step} is a unary step, but we're attempting to pass it ${size} (!= 1) values`, + ); + } if (step._stepOptions.stream && isStreamV2ableStep(step)) { return step.streamV2(size, dependencies, extra, step._stepOptions.stream); } else if (step._stepOptions.stream && isStreamableStep(step)) { @@ -810,7 +818,7 @@ export function executeBucket( return mergeErrorsBackIn(resultWithoutErrors, errors, size); } } else { - return reallyExecuteStepWithNoErrors(size, step, dependencies, extra); + return reallyExecuteStepWithNoErrors(newSize, step, dependencies, extra); } } @@ -909,7 +917,12 @@ export function executeBucket( bucket.polymorphicPathList, extra, ) - : reallyExecuteStepWithNoErrors(size, step, dependencies, extra); + : reallyExecuteStepWithNoErrors( + step._isUnary ? 1 : size, + step, + dependencies, + extra, + ); if (isPromiseLike(result)) { return result.then(null, (error) => { // bucket.hasErrors = true; diff --git a/grafast/grafast/src/prepare.ts b/grafast/grafast/src/prepare.ts index 5562047908..76de312011 100644 --- a/grafast/grafast/src/prepare.ts +++ b/grafast/grafast/src/prepare.ts @@ -950,7 +950,7 @@ function processSingleDeferred( for (const spec of specs) { if (spec[1].bucket !== firstBucket) { throw new Error( - `GrafastInternalError<>: sorry, it seems the unary dependencies feature broke our incremental delivery support. This incremental delivery is going to be fully rewritten at some point anyway, so we recommend you avoid using it for now (the spec itself has changed since we implemented it).`, + `GrafastInternalError: sorry, it seems the unary dependencies feature broke our incremental delivery support. This incremental delivery is going to be fully rewritten at some point anyway, so we recommend you avoid using it for now (the spec itself has changed since we implemented it).`, ); } } diff --git a/grafast/grafast/src/steps/applyTransforms.ts b/grafast/grafast/src/steps/applyTransforms.ts index 8c3529d1e4..5409b49dbe 100644 --- a/grafast/grafast/src/steps/applyTransforms.ts +++ b/grafast/grafast/src/steps/applyTransforms.ts @@ -91,15 +91,18 @@ export class ApplyTransformsStep extends ExecutableStep { let size = 0; // ENHANCE: do this better! - const itemStepId = this.operationPlan.dangerouslyGetStep( - this.itemStepId, - ).id; + const itemStep = this.operationPlan.dangerouslyGetStep(this.itemStepId); + const itemStepId = itemStep.id; if (itemStepId == null) { throw new Error( "GrafastInternalError: listItem layer plan has no rootStepId", ); } - store.set(itemStepId, []); + if (itemStep._isUnary) { + // Handled later + } else { + store.set(itemStepId, []); + } for (const stepId of copyUnaryStepIds) { unaryStore.set(stepId, bucket.unaryStore.get(stepId)); @@ -144,7 +147,11 @@ export class ApplyTransformsStep extends ExecutableStep { // Copying across the iterators because we do NOT call outputBucket, // so we need to ensure any streams are cleaned up. iterators[newIndex] = bucket.iterators[originalIndex]; - store.get(itemStepId)![newIndex] = list[j]; + if (itemStep._isUnary) { + unaryStore.set(itemStepId, list[j]); + } else { + store.get(itemStepId)![newIndex] = list[j]; + } for (const stepId of copyBatchStepIds) { store.get(stepId)![newIndex] = bucket.store.get(stepId)![originalIndex]; @@ -169,7 +176,9 @@ export class ApplyTransformsStep extends ExecutableStep { await executeBucket(childBucket, extra._requestContext); } - const depResults = store.get(rootStep!.id)!; + const [depResults, unaryResult] = rootStep?._isUnary + ? [null, unaryStore.get(rootStep.id)] + : [store.get(rootStep!.id)!, null]; return listValues.map((list: any, originalIndex: number) => { if (list == null) { @@ -184,7 +193,7 @@ export class ApplyTransformsStep extends ExecutableStep { return null; } const values = indexes.map((idx) => { - const val = depResults[idx]; + const val = depResults === null ? unaryResult : depResults[idx]; if (val instanceof Error) { throw val; } diff --git a/grafast/grafast/src/steps/listTransform.ts b/grafast/grafast/src/steps/listTransform.ts index bb898d833b..65350d0934 100644 --- a/grafast/grafast/src/steps/listTransform.ts +++ b/grafast/grafast/src/steps/listTransform.ts @@ -214,15 +214,18 @@ export class __ListTransformStep< let size = 0; // ENHANCE: do this better! - const itemStepId = this.operationPlan.dangerouslyGetStep( - this.itemStepId, - ).id; + const itemStep = this.operationPlan.dangerouslyGetStep(this.itemStepId)!; + const itemStepId = itemStep.id; if (itemStepId == null) { throw new Error( "GrafastInternalError: listItem layer plan has no rootStepId", ); } - store.set(itemStepId, []); + if (itemStep._isUnary) { + // handled later + } else { + store.set(itemStepId, []); + } for (const stepId of copyUnaryStepIds) { unaryStore.set(stepId, bucket.unaryStore.get(stepId)); @@ -267,7 +270,11 @@ export class __ListTransformStep< // Copying across the iterators because we do NOT call outputBucket, // so we need to ensure any streams are cleaned up. iterators[newIndex] = bucket.iterators[originalIndex]; - store.get(itemStepId)![newIndex] = list[j]; + if (itemStep._isUnary) { + unaryStore.set(itemStepId, list[j]); + } else { + store.get(itemStepId)![newIndex] = list[j]; + } for (const planId of copyBatchStepIds) { store.get(planId)![newIndex] = bucket.store.get(planId)![originalIndex]; @@ -292,7 +299,9 @@ export class __ListTransformStep< await executeBucket(childBucket, extra._requestContext); } - const depResults = store.get(rootStep!.id)!; + const [depResults, unaryResult] = rootStep?._isUnary + ? [null, unaryStore.get(rootStep!.id)] + : [store.get(rootStep!.id)!, null]; return listValues.map((list: any, originalIndex: number) => { if (list == null) { @@ -306,7 +315,9 @@ export class __ListTransformStep< ); return null; } - const values = indexes.map((idx) => depResults[idx]); + const values = indexes.map((idx) => + depResults === null ? unaryResult : depResults[idx], + ); if (isDev) { assert.strictEqual( list.length, From 1a0a4cb4334faae4470804293682de3e51cf9ce6 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 22 Feb 2024 15:44:34 +0000 Subject: [PATCH 19/48] Update mermaid plans --- .../v4/mutation-return-types.mermaid | 10 +++--- .../mutations/v4/procedure-mutation.mermaid | 2 +- .../__tests__/mutations/v4/types.mermaid | 4 +-- .../queries/polymorphic/only.mermaid | 6 ++-- .../person-app-vulns.app-condition.mermaid | 6 ++-- .../person-app-vulns.app-order.mermaid | 6 ++-- .../person-app-vulns.app-page-2.mermaid | 14 ++++---- .../person-app-vulns.app-totalCount.mermaid | 2 +- ...rson-app-vulns.app-vuln-totalCount.mermaid | 4 +-- .../polymorphic/person-app-vulns.mermaid | 24 ++++++------- .../relay.polyroot_with_related_poly.mermaid | 6 ++-- .../polymorphic/simple-log-entries.mermaid | 4 +-- ...mple-single-table-items-root-topic.mermaid | 2 +- .../queries/polymorphic/vulns.mermaid | 6 ++-- .../polymorphic/vulns.union_owners.mermaid | 34 +++++++++--------- .../vulns.union_owners.simple.mermaid | 6 ++-- .../queries/v4/badlyBehavedFunction.mermaid | 6 ++-- .../__tests__/queries/v4/classic-ids.mermaid | 2 +- .../queries/v4/composite_domains.mermaid | 2 +- .../queries/v4/connections-totalCount.mermaid | 2 +- .../__tests__/queries/v4/connections.mermaid | 2 +- .../queries/v4/function-return-types.mermaid | 12 +++---- .../queries/v4/json-overflow-nested.mermaid | 2 +- .../queries/v4/large_bigint.issue491.mermaid | 2 +- .../queries/v4/nested_arrays.select.mermaid | 2 +- .../__tests__/queries/v4/node.mermaid | 4 +-- .../queries/v4/one-to-one-backward.mermaid | 6 ++-- .../queries/v4/orderByNullsLast.mermaid | 4 +-- .../__tests__/queries/v4/posts.mermaid | 4 +-- .../v4/procedure-computed-fields.mermaid | 6 ++-- .../__tests__/queries/v4/rbac.basic.mermaid | 8 ++--- .../queries/v4/relation-head-tail.mermaid | 4 +-- .../simple-procedure-computed-fields.mermaid | 12 +++---- .../v4/smart_comment_relations.houses.mermaid | 36 +++++++++---------- .../__tests__/queries/v4/streamLoads.mermaid | 2 +- 35 files changed, 127 insertions(+), 127 deletions(-) diff --git a/postgraphile/postgraphile/__tests__/mutations/v4/mutation-return-types.mermaid b/postgraphile/postgraphile/__tests__/mutations/v4/mutation-return-types.mermaid index 970d7a4d04..4a0c768e43 100644 --- a/postgraphile/postgraphile/__tests__/mutations/v4/mutation-return-types.mermaid +++ b/postgraphile/postgraphile/__tests__/mutations/v4/mutation-return-types.mermaid @@ -442,7 +442,7 @@ graph TD Bucket12("Bucket 12 (listItem)
Deps: 92

ROOT __Item{12}ᐸ291ᐳ[90]"):::bucket classDef bucket12 stroke:#4169e1 class Bucket12,__Item90,PgSelectSingle91 bucket12 - Bucket13("Bucket 13 (nullableBoundary)
Deps: 91, 92

ROOT PgSelectSingle{12}ᐸpostᐳ[91]"):::bucket + Bucket13("Bucket 13 (nullableBoundary)
Deps: 92, 91

ROOT PgSelectSingle{12}ᐸpostᐳ[91]"):::bucket classDef bucket13 stroke:#3cb371 class Bucket13,PgClassExpression93,List94,Lambda95 bucket13 Bucket14("Bucket 14 (mutationField)
Deps: 296, 297, 3

1: Access[102]
2: Access[103]
3: Object[104]
4: PgSelect[101]
5:
ᐳ: Object[105]"):::bucket @@ -454,19 +454,19 @@ graph TD Bucket16("Bucket 16 (listItem)
Deps: 104

ROOT __Item{16}ᐸ101ᐳ[106]"):::bucket classDef bucket16 stroke:#f5deb3 class Bucket16,__Item106,PgSelectSingle107,Constant126,Connection145,Constant149 bucket16 - Bucket17("Bucket 17 (nullableBoundary)
Deps: 107, 104, 126, 149, 145

ROOT PgSelectSingle{16}ᐸmutation_out_complex_setofᐳ[107]
1:
ᐳ: 108, 109, 119
2: PgSelect[110], PgSelect[120]
ᐳ: 114, 115, 124, 125"):::bucket + Bucket17("Bucket 17 (nullableBoundary)
Deps: 104, 126, 149, 145, 107

ROOT PgSelectSingle{16}ᐸmutation_out_complex_setofᐳ[107]
1:
ᐳ: 108, 109, 119
2: PgSelect[110], PgSelect[120]
ᐳ: 114, 115, 124, 125"):::bucket classDef bucket17 stroke:#696969 class Bucket17,PgClassExpression108,PgClassExpression109,PgSelect110,First114,PgSelectSingle115,PgClassExpression119,PgSelect120,First124,PgSelectSingle125 bucket17 Bucket18("Bucket 18 (nullableBoundary)
Deps: 115

ROOT PgSelectSingle{17}ᐸfrmcdc_compoundTypeᐳ[115]"):::bucket classDef bucket18 stroke:#00bfff class Bucket18,PgClassExpression116,PgClassExpression117,PgClassExpression118 bucket18 - Bucket19("Bucket 19 (nullableBoundary)
Deps: 125, 126, 124, 149, 145

ROOT PgSelectSingle{17}ᐸpersonᐳ[125]"):::bucket + Bucket19("Bucket 19 (nullableBoundary)
Deps: 126, 149, 145, 125, 124

ROOT PgSelectSingle{17}ᐸpersonᐳ[125]"):::bucket classDef bucket19 stroke:#7f007f class Bucket19,PgClassExpression127,List128,Lambda129,PgClassExpression131,Access292 bucket19 Bucket20("Bucket 20 (listItem)
Deps: 149

ROOT __Item{20}ᐸ292ᐳ[147]"):::bucket classDef bucket20 stroke:#ffa500 class Bucket20,__Item147,PgSelectSingle148 bucket20 - Bucket21("Bucket 21 (nullableBoundary)
Deps: 148, 149

ROOT PgSelectSingle{20}ᐸpostᐳ[148]"):::bucket + Bucket21("Bucket 21 (nullableBoundary)
Deps: 149, 148

ROOT PgSelectSingle{20}ᐸpostᐳ[148]"):::bucket classDef bucket21 stroke:#0000ff class Bucket21,PgClassExpression150,List151,Lambda152 bucket21 Bucket22("Bucket 22 (mutationField)
Deps: 3

1: Access[157]
2: Access[158]
3: Object[159]
4: PgSelect[156]
5:
ᐳ: 160, 161, 162"):::bucket @@ -538,7 +538,7 @@ graph TD Bucket44("Bucket 44 (listItem)
ROOT __Item{44}ᐸ234ᐳ[239]"):::bucket classDef bucket44 stroke:#ffff00 class Bucket44,__Item239,PgSelectSingle240,Constant241 bucket44 - Bucket45("Bucket 45 (nullableBoundary)
Deps: 240, 241

ROOT PgSelectSingle{44}ᐸmutation_out_table_setofᐳ[240]"):::bucket + Bucket45("Bucket 45 (nullableBoundary)
Deps: 241, 240

ROOT PgSelectSingle{44}ᐸmutation_out_table_setofᐳ[240]"):::bucket classDef bucket45 stroke:#00ffff class Bucket45,PgClassExpression242,List243,Lambda244 bucket45 Bucket46("Bucket 46 (mutationField)
Deps: 3

1: Access[249]
2: Access[250]
3: Object[251]
4: PgSelect[248]
5:
ᐳ: 252, 253, 254, 255"):::bucket diff --git a/postgraphile/postgraphile/__tests__/mutations/v4/procedure-mutation.mermaid b/postgraphile/postgraphile/__tests__/mutations/v4/procedure-mutation.mermaid index c49786b07d..10484a9dc4 100644 --- a/postgraphile/postgraphile/__tests__/mutations/v4/procedure-mutation.mermaid +++ b/postgraphile/postgraphile/__tests__/mutations/v4/procedure-mutation.mermaid @@ -1015,7 +1015,7 @@ graph TD Bucket78("Bucket 78 (listItem)
Deps: 536

ROOT __Item{78}ᐸ533ᐳ[538]"):::bucket classDef bucket78 stroke:#ffff00 class Bucket78,__Item538,PgSelectSingle539 bucket78 - Bucket79("Bucket 79 (nullableBoundary)
Deps: 539, 536

ROOT PgSelectSingle{78}ᐸpost_manyᐳ[539]
1:
ᐳ: 540, 541, 542
2: PgSelect[543]"):::bucket + Bucket79("Bucket 79 (nullableBoundary)
Deps: 536, 539

ROOT PgSelectSingle{78}ᐸpost_manyᐳ[539]
1:
ᐳ: 540, 541, 542
2: PgSelect[543]"):::bucket classDef bucket79 stroke:#00ffff class Bucket79,PgClassExpression540,PgClassExpression541,PgClassExpression542,PgSelect543 bucket79 Bucket80("Bucket 80 (listItem)
ROOT __Item{80}ᐸ543ᐳ[547]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/mutations/v4/types.mermaid b/postgraphile/postgraphile/__tests__/mutations/v4/types.mermaid index d82e391606..24c36623e0 100644 --- a/postgraphile/postgraphile/__tests__/mutations/v4/types.mermaid +++ b/postgraphile/postgraphile/__tests__/mutations/v4/types.mermaid @@ -1590,7 +1590,7 @@ graph TD Bucket32("Bucket 32 (listItem)
Deps: 232

ROOT __Item{32}ᐸ229ᐳ[234]"):::bucket classDef bucket32 stroke:#ff00ff class Bucket32,__Item234,PgSelectSingle235 bucket32 - Bucket33("Bucket 33 (nullableBoundary)
Deps: 235, 232

ROOT PgSelectSingle{32}ᐸtype_function_list_mutationᐳ[235]
1:
ᐳ: 236, 237, 238, 239, 240, 241, 242, 243, 244, 246, 247, 248, 250, 251, 252, 259, 266, 273, 280, 281, 282, 283, 284, 285, 292, 300, 301, 315, 351, 365, 401, 404, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 420, 422, 423, 443, 444, 260, 263, 267, 270, 274, 277
2: 302, 316, 352, 366, 426, 435
ᐳ: 306, 307, 308, 309, 310, 311, 312, 313, 314, 320, 321, 328, 350, 356, 357, 370, 371, 430, 431, 439, 440, 1378, 342"):::bucket + Bucket33("Bucket 33 (nullableBoundary)
Deps: 232, 235

ROOT PgSelectSingle{32}ᐸtype_function_list_mutationᐳ[235]
1:
ᐳ: 236, 237, 238, 239, 240, 241, 242, 243, 244, 246, 247, 248, 250, 251, 252, 259, 266, 273, 280, 281, 282, 283, 284, 285, 292, 300, 301, 315, 351, 365, 401, 404, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 420, 422, 423, 443, 444, 260, 263, 267, 270, 274, 277
2: 302, 316, 352, 366, 426, 435
ᐳ: 306, 307, 308, 309, 310, 311, 312, 313, 314, 320, 321, 328, 350, 356, 357, 370, 371, 430, 431, 439, 440, 1378, 342"):::bucket classDef bucket33 stroke:#f5deb3 class Bucket33,PgClassExpression236,PgClassExpression237,PgClassExpression238,PgClassExpression239,PgClassExpression240,PgClassExpression241,PgClassExpression242,PgClassExpression243,PgClassExpression244,PgClassExpression246,PgClassExpression247,PgClassExpression248,PgClassExpression250,PgClassExpression251,PgClassExpression252,PgClassExpression259,Access260,Access263,PgClassExpression266,Access267,Access270,PgClassExpression273,Access274,Access277,PgClassExpression280,PgClassExpression281,PgClassExpression282,PgClassExpression283,PgClassExpression284,PgClassExpression285,PgClassExpression292,PgClassExpression300,PgClassExpression301,PgSelect302,First306,PgSelectSingle307,PgClassExpression308,PgClassExpression309,PgClassExpression310,PgClassExpression311,PgClassExpression312,PgClassExpression313,PgClassExpression314,PgClassExpression315,PgSelect316,First320,PgSelectSingle321,PgSelectSingle328,PgSelectSingle342,PgClassExpression350,PgClassExpression351,PgSelect352,First356,PgSelectSingle357,PgClassExpression365,PgSelect366,First370,PgSelectSingle371,PgClassExpression401,PgClassExpression404,PgClassExpression407,PgClassExpression408,PgClassExpression409,PgClassExpression410,PgClassExpression411,PgClassExpression412,PgClassExpression413,PgClassExpression414,PgClassExpression415,PgClassExpression416,PgClassExpression417,PgClassExpression418,PgClassExpression420,PgClassExpression422,PgClassExpression423,PgSelect426,First430,PgSelectSingle431,PgSelect435,First439,PgSelectSingle440,PgClassExpression443,PgClassExpression444,RemapKeys1378 bucket33 Bucket34("Bucket 34 (listItem)
ROOT __Item{34}ᐸ244ᐳ[245]"):::bucket @@ -1680,7 +1680,7 @@ graph TD Bucket62("Bucket 62 (listItem)
Deps: 451

ROOT __Item{62}ᐸ448ᐳ[453]"):::bucket classDef bucket62 stroke:#00ffff class Bucket62,__Item453,PgSelectSingle454 bucket62 - Bucket63("Bucket 63 (nullableBoundary)
Deps: 454, 451

ROOT PgSelectSingle{62}ᐸtype_function_connection_mutationᐳ[454]
1:
ᐳ: 455, 456, 457, 458, 459, 460, 461, 462, 463, 465, 466, 467, 469, 470, 471, 478, 485, 492, 499, 500, 501, 502, 503, 504, 511, 519, 520, 534, 570, 584, 620, 623, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 639, 641, 642, 662, 663, 479, 482, 486, 489, 493, 496
2: 521, 535, 571, 585, 645, 654
ᐳ: 525, 526, 527, 528, 529, 530, 531, 532, 533, 539, 540, 547, 569, 575, 576, 589, 590, 649, 650, 658, 659, 1386, 561"):::bucket + Bucket63("Bucket 63 (nullableBoundary)
Deps: 451, 454

ROOT PgSelectSingle{62}ᐸtype_function_connection_mutationᐳ[454]
1:
ᐳ: 455, 456, 457, 458, 459, 460, 461, 462, 463, 465, 466, 467, 469, 470, 471, 478, 485, 492, 499, 500, 501, 502, 503, 504, 511, 519, 520, 534, 570, 584, 620, 623, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 639, 641, 642, 662, 663, 479, 482, 486, 489, 493, 496
2: 521, 535, 571, 585, 645, 654
ᐳ: 525, 526, 527, 528, 529, 530, 531, 532, 533, 539, 540, 547, 569, 575, 576, 589, 590, 649, 650, 658, 659, 1386, 561"):::bucket classDef bucket63 stroke:#4169e1 class Bucket63,PgClassExpression455,PgClassExpression456,PgClassExpression457,PgClassExpression458,PgClassExpression459,PgClassExpression460,PgClassExpression461,PgClassExpression462,PgClassExpression463,PgClassExpression465,PgClassExpression466,PgClassExpression467,PgClassExpression469,PgClassExpression470,PgClassExpression471,PgClassExpression478,Access479,Access482,PgClassExpression485,Access486,Access489,PgClassExpression492,Access493,Access496,PgClassExpression499,PgClassExpression500,PgClassExpression501,PgClassExpression502,PgClassExpression503,PgClassExpression504,PgClassExpression511,PgClassExpression519,PgClassExpression520,PgSelect521,First525,PgSelectSingle526,PgClassExpression527,PgClassExpression528,PgClassExpression529,PgClassExpression530,PgClassExpression531,PgClassExpression532,PgClassExpression533,PgClassExpression534,PgSelect535,First539,PgSelectSingle540,PgSelectSingle547,PgSelectSingle561,PgClassExpression569,PgClassExpression570,PgSelect571,First575,PgSelectSingle576,PgClassExpression584,PgSelect585,First589,PgSelectSingle590,PgClassExpression620,PgClassExpression623,PgClassExpression626,PgClassExpression627,PgClassExpression628,PgClassExpression629,PgClassExpression630,PgClassExpression631,PgClassExpression632,PgClassExpression633,PgClassExpression634,PgClassExpression635,PgClassExpression636,PgClassExpression637,PgClassExpression639,PgClassExpression641,PgClassExpression642,PgSelect645,First649,PgSelectSingle650,PgSelect654,First658,PgSelectSingle659,PgClassExpression662,PgClassExpression663,RemapKeys1386 bucket63 Bucket64("Bucket 64 (listItem)
ROOT __Item{64}ᐸ463ᐳ[464]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/polymorphic/only.mermaid b/postgraphile/postgraphile/__tests__/queries/polymorphic/only.mermaid index 384d3b163e..bd1296b123 100644 --- a/postgraphile/postgraphile/__tests__/queries/polymorphic/only.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/polymorphic/only.mermaid @@ -150,19 +150,19 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 20

ROOT __Item{2}ᐸ22ᐳ[23]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item23,PgUnionAllSingle24,Access25 bucket2 - Bucket3("Bucket 3 (polymorphic)
AwsApplication,GcpApplication
Deps: 25, 20, 24
ᐳAwsApplication
ᐳGcpApplication
1: JSONParse[26], JSONParse[79]
ᐳ: 50, 103, 27, 80
2: PgSelect[28], PgSelect[81]
ᐳ: 32, 33, 34, 44, 85, 86, 87, 97
3: PgUnionAll[51], PgUnionAll[104]"):::bucket + Bucket3("Bucket 3 (polymorphic)
AwsApplication,GcpApplication
Deps: 20, 25, 24
ᐳAwsApplication
ᐳGcpApplication
1: JSONParse[26], JSONParse[79]
ᐳ: 50, 103, 27, 80
2: PgSelect[28], PgSelect[81]
ᐳ: 32, 33, 34, 44, 85, 86, 87, 97
3: PgUnionAll[51], PgUnionAll[104]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,JSONParse26,Access27,PgSelect28,First32,PgSelectSingle33,PgClassExpression34,PgClassExpression44,Connection50,PgUnionAll51,JSONParse79,Access80,PgSelect81,First85,PgSelectSingle86,PgClassExpression87,PgClassExpression97,Connection103,PgUnionAll104 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 20

ROOT __Item{4}ᐸ51ᐳ[52]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item52,PgUnionAllSingle53,Access54 bucket4 - Bucket5("Bucket 5 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 54, 20, 53
ᐳAwsApplicationᐳFirstPartyVulnerability
ᐳAwsApplicationᐳThirdPartyVulnerability
1: JSONParse[55], JSONParse[67]
ᐳ: Access[56], Access[68]
2: PgSelect[57], PgSelect[69]
ᐳ: 61, 62, 63, 64, 65, 73, 74, 75, 76, 77"):::bucket + Bucket5("Bucket 5 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 20, 54, 53
ᐳAwsApplicationᐳFirstPartyVulnerability
ᐳAwsApplicationᐳThirdPartyVulnerability
1: JSONParse[55], JSONParse[67]
ᐳ: Access[56], Access[68]
2: PgSelect[57], PgSelect[69]
ᐳ: 61, 62, 63, 64, 65, 73, 74, 75, 76, 77"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,JSONParse55,Access56,PgSelect57,First61,PgSelectSingle62,PgClassExpression63,PgClassExpression64,PgClassExpression65,JSONParse67,Access68,PgSelect69,First73,PgSelectSingle74,PgClassExpression75,PgClassExpression76,PgClassExpression77 bucket5 Bucket6("Bucket 6 (listItem)
Deps: 20

ROOT __Item{6}ᐸ104ᐳ[105]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,__Item105,PgUnionAllSingle106,Access107 bucket6 - Bucket7("Bucket 7 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 107, 20, 106
ᐳGcpApplicationᐳFirstPartyVulnerability
ᐳGcpApplicationᐳThirdPartyVulnerability
1: JSONParse[108], JSONParse[120]
ᐳ: Access[109], Access[121]
2: PgSelect[110], PgSelect[122]
ᐳ: 114, 115, 116, 117, 118, 126, 127, 128, 129, 130"):::bucket + Bucket7("Bucket 7 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 20, 107, 106
ᐳGcpApplicationᐳFirstPartyVulnerability
ᐳGcpApplicationᐳThirdPartyVulnerability
1: JSONParse[108], JSONParse[120]
ᐳ: Access[109], Access[121]
2: PgSelect[110], PgSelect[122]
ᐳ: 114, 115, 116, 117, 118, 126, 127, 128, 129, 130"):::bucket classDef bucket7 stroke:#808000 class Bucket7,JSONParse108,Access109,PgSelect110,First114,PgSelectSingle115,PgClassExpression116,PgClassExpression117,PgClassExpression118,JSONParse120,Access121,PgSelect122,First126,PgSelectSingle127,PgClassExpression128,PgClassExpression129,PgClassExpression130 bucket7 Bucket0 --> Bucket1 diff --git a/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-condition.mermaid b/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-condition.mermaid index 9024396e53..c0f7f4b587 100644 --- a/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-condition.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-condition.mermaid @@ -101,16 +101,16 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18, 80, 42, 43, 50, 51

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 18, 80, 42, 43, 50, 51

ROOT PgSelectSingle{2}ᐸpeopleᐳ[22]
1:
ᐳ: 23, 24
2: PgUnionAll[44]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 80, 42, 43, 50, 51, 22

ROOT PgSelectSingle{2}ᐸpeopleᐳ[22]
1:
ᐳ: 23, 24
2: PgUnionAll[44]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression24,PgUnionAll44 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 18

ROOT __Item{4}ᐸ44ᐳ[45]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item45,PgUnionAllSingle46 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 46, 18

ROOT PgUnionAllSingle{4}[46]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 18, 46

ROOT PgUnionAllSingle{4}[46]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgCursor47,Access52,Access53,List54 bucket5 - Bucket6("Bucket 6 (polymorphic)
AwsApplication,GcpApplication
Deps: 53, 18, 46
ᐳAwsApplication
ᐳGcpApplication
1: JSONParse[56], JSONParse[67]
ᐳ: Access[57], Access[68]
2: PgSelect[58], PgSelect[69]
ᐳ: 62, 63, 64, 65, 73, 74, 75, 76"):::bucket + Bucket6("Bucket 6 (polymorphic)
AwsApplication,GcpApplication
Deps: 18, 53, 46
ᐳAwsApplication
ᐳGcpApplication
1: JSONParse[56], JSONParse[67]
ᐳ: Access[57], Access[68]
2: PgSelect[58], PgSelect[69]
ᐳ: 62, 63, 64, 65, 73, 74, 75, 76"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,JSONParse56,Access57,PgSelect58,First62,PgSelectSingle63,PgClassExpression64,PgClassExpression65,JSONParse67,Access68,PgSelect69,First73,PgSelectSingle74,PgClassExpression75,PgClassExpression76 bucket6 Bucket0 --> Bucket1 diff --git a/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-order.mermaid b/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-order.mermaid index 76eaca89dc..e8153832d0 100644 --- a/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-order.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-order.mermaid @@ -95,16 +95,16 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18, 41

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 18, 41

ROOT PgSelectSingle{2}ᐸpeopleᐳ[22]
1:
ᐳ: 23, 24
2: PgUnionAll[42]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 41, 22

ROOT PgSelectSingle{2}ᐸpeopleᐳ[22]
1:
ᐳ: 23, 24
2: PgUnionAll[42]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression24,PgUnionAll42 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 18

ROOT __Item{4}ᐸ42ᐳ[43]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item43,PgUnionAllSingle44 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 44, 18

ROOT PgUnionAllSingle{4}[44]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 18, 44

ROOT PgUnionAllSingle{4}[44]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgCursor45,Access46,Access47,Access48,Access49,List50 bucket5 - Bucket6("Bucket 6 (polymorphic)
AwsApplication,GcpApplication
Deps: 49, 18, 44
ᐳAwsApplication
ᐳGcpApplication
1: JSONParse[52], JSONParse[64]
ᐳ: Access[53], Access[65]
2: PgSelect[54], PgSelect[66]
ᐳ: 58, 59, 60, 61, 62, 70, 71, 72, 73, 74"):::bucket + Bucket6("Bucket 6 (polymorphic)
AwsApplication,GcpApplication
Deps: 18, 49, 44
ᐳAwsApplication
ᐳGcpApplication
1: JSONParse[52], JSONParse[64]
ᐳ: Access[53], Access[65]
2: PgSelect[54], PgSelect[66]
ᐳ: 58, 59, 60, 61, 62, 70, 71, 72, 73, 74"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,JSONParse52,Access53,PgSelect54,First58,PgSelectSingle59,PgClassExpression60,PgClassExpression61,PgClassExpression62,JSONParse64,Access65,PgSelect66,First70,PgSelectSingle71,PgClassExpression72,PgClassExpression73,PgClassExpression74 bucket6 Bucket0 --> Bucket1 diff --git a/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-page-2.mermaid b/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-page-2.mermaid index d90275b6b6..aa7c8287c6 100644 --- a/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-page-2.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-page-2.mermaid @@ -176,34 +176,34 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18, 39, 40, 47, 48, 157

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 18, 39, 40, 47, 48, 157

ROOT PgSelectSingle{2}ᐸpeopleᐳ[22]
1:
ᐳ: 23, 24
2: PgUnionAll[41]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 39, 40, 47, 48, 157, 22

ROOT PgSelectSingle{2}ᐸpeopleᐳ[22]
1:
ᐳ: 23, 24
2: PgUnionAll[41]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression24,PgUnionAll41 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 18, 157

ROOT __Item{4}ᐸ41ᐳ[42]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item42,PgUnionAllSingle43 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 43, 18, 157

ROOT PgUnionAllSingle{4}[43]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 18, 157, 43

ROOT PgUnionAllSingle{4}[43]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgCursor44,Access49,Access50,List51 bucket5 - Bucket6("Bucket 6 (polymorphic)
AwsApplication,GcpApplication
Deps: 50, 18, 157, 43
ᐳAwsApplication
ᐳGcpApplication
1: JSONParse[53], JSONParse[105]
ᐳ: 76, 128, 54, 106
2: PgSelect[55], PgSelect[107]
ᐳ: 59, 60, 61, 111, 112, 113
3: PgUnionAll[77], PgUnionAll[129]"):::bucket + Bucket6("Bucket 6 (polymorphic)
AwsApplication,GcpApplication
Deps: 18, 157, 50, 43
ᐳAwsApplication
ᐳGcpApplication
1: JSONParse[53], JSONParse[105]
ᐳ: 76, 128, 54, 106
2: PgSelect[55], PgSelect[107]
ᐳ: 59, 60, 61, 111, 112, 113
3: PgUnionAll[77], PgUnionAll[129]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,JSONParse53,Access54,PgSelect55,First59,PgSelectSingle60,PgClassExpression61,Connection76,PgUnionAll77,JSONParse105,Access106,PgSelect107,First111,PgSelectSingle112,PgClassExpression113,Connection128,PgUnionAll129 bucket6 Bucket7("Bucket 7 (listItem)
Deps: 18

ROOT __Item{7}ᐸ77ᐳ[78]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,__Item78,PgUnionAllSingle79 bucket7 - Bucket8("Bucket 8 (nullableBoundary)
Deps: 79, 18

ROOT PgUnionAllSingle{7}[79]"):::bucket + Bucket8("Bucket 8 (nullableBoundary)
Deps: 18, 79

ROOT PgUnionAllSingle{7}[79]"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,PgCursor80,Access81,Access82,List83 bucket8 - Bucket9("Bucket 9 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 82, 18, 79
ᐳAwsApplicationᐳFirstPartyVulnerability
ᐳAwsApplicationᐳThirdPartyVulnerability
1: JSONParse[85], JSONParse[95]
ᐳ: Access[86], Access[96]
2: PgSelect[87], PgSelect[97]
ᐳ: 91, 92, 93, 101, 102, 103"):::bucket + Bucket9("Bucket 9 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 18, 82, 79
ᐳAwsApplicationᐳFirstPartyVulnerability
ᐳAwsApplicationᐳThirdPartyVulnerability
1: JSONParse[85], JSONParse[95]
ᐳ: Access[86], Access[96]
2: PgSelect[87], PgSelect[97]
ᐳ: 91, 92, 93, 101, 102, 103"):::bucket classDef bucket9 stroke:#ff0000 class Bucket9,JSONParse85,Access86,PgSelect87,First91,PgSelectSingle92,PgClassExpression93,JSONParse95,Access96,PgSelect97,First101,PgSelectSingle102,PgClassExpression103 bucket9 Bucket10("Bucket 10 (listItem)
Deps: 18

ROOT __Item{10}ᐸ129ᐳ[130]"):::bucket classDef bucket10 stroke:#ffff00 class Bucket10,__Item130,PgUnionAllSingle131 bucket10 - Bucket11("Bucket 11 (nullableBoundary)
Deps: 131, 18

ROOT PgUnionAllSingle{10}[131]"):::bucket + Bucket11("Bucket 11 (nullableBoundary)
Deps: 18, 131

ROOT PgUnionAllSingle{10}[131]"):::bucket classDef bucket11 stroke:#00ffff class Bucket11,PgCursor132,Access133,Access134,List135 bucket11 - Bucket12("Bucket 12 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 134, 18, 131
ᐳGcpApplicationᐳFirstPartyVulnerability
ᐳGcpApplicationᐳThirdPartyVulnerability
1: JSONParse[137], JSONParse[147]
ᐳ: Access[138], Access[148]
2: PgSelect[139], PgSelect[149]
ᐳ: 143, 144, 145, 153, 154, 155"):::bucket + Bucket12("Bucket 12 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 18, 134, 131
ᐳGcpApplicationᐳFirstPartyVulnerability
ᐳGcpApplicationᐳThirdPartyVulnerability
1: JSONParse[137], JSONParse[147]
ᐳ: Access[138], Access[148]
2: PgSelect[139], PgSelect[149]
ᐳ: 143, 144, 145, 153, 154, 155"):::bucket classDef bucket12 stroke:#4169e1 class Bucket12,JSONParse137,Access138,PgSelect139,First143,PgSelectSingle144,PgClassExpression145,JSONParse147,Access148,PgSelect149,First153,PgSelectSingle154,PgClassExpression155 bucket12 Bucket0 --> Bucket1 diff --git a/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-totalCount.mermaid b/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-totalCount.mermaid index 586d7e488f..7ac71b0981 100644 --- a/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-totalCount.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-totalCount.mermaid @@ -53,7 +53,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18, 39

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 18, 39

ROOT PgSelectSingle{2}ᐸpeopleᐳ[22]
1:
ᐳ: 23, 24
2: PgUnionAll[40]
ᐳ: First[41]
3: PgUnionAllSingle[42]
ᐳ: PgClassExpression[43]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 39, 22

ROOT PgSelectSingle{2}ᐸpeopleᐳ[22]
1:
ᐳ: 23, 24
2: PgUnionAll[40]
ᐳ: First[41]
3: PgUnionAllSingle[42]
ᐳ: PgClassExpression[43]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression24,PgUnionAll40,First41,PgUnionAllSingle42,PgClassExpression43 bucket3 Bucket0 --> Bucket1 diff --git a/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-vuln-totalCount.mermaid b/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-vuln-totalCount.mermaid index aa13ab4d56..976d1c12e2 100644 --- a/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-vuln-totalCount.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.app-vuln-totalCount.mermaid @@ -95,13 +95,13 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18, 39

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 18, 39

ROOT PgSelectSingle{2}ᐸpeopleᐳ[22]
1:
ᐳ: 23, 24
2: PgUnionAll[40]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 39, 22

ROOT PgSelectSingle{2}ᐸpeopleᐳ[22]
1:
ᐳ: 23, 24
2: PgUnionAll[40]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression24,PgUnionAll40 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 18

ROOT __Item{4}ᐸ40ᐳ[41]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item41,PgUnionAllSingle42,Access43 bucket4 - Bucket5("Bucket 5 (polymorphic)
AwsApplication,GcpApplication
Deps: 43, 18, 42
ᐳAwsApplication
ᐳGcpApplication
1: JSONParse[44], JSONParse[72]
ᐳ: 66, 94, 45, 73
2: PgSelect[46], PgSelect[74]
ᐳ: 50, 51, 60, 78, 79, 88
3: PgUnionAll[67], PgUnionAll[95]
ᐳ: First[68], First[96]
4: 69, 97
ᐳ: 70, 98"):::bucket + Bucket5("Bucket 5 (polymorphic)
AwsApplication,GcpApplication
Deps: 18, 43, 42
ᐳAwsApplication
ᐳGcpApplication
1: JSONParse[44], JSONParse[72]
ᐳ: 66, 94, 45, 73
2: PgSelect[46], PgSelect[74]
ᐳ: 50, 51, 60, 78, 79, 88
3: PgUnionAll[67], PgUnionAll[95]
ᐳ: First[68], First[96]
4: 69, 97
ᐳ: 70, 98"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,JSONParse44,Access45,PgSelect46,First50,PgSelectSingle51,PgClassExpression60,Connection66,PgUnionAll67,First68,PgUnionAllSingle69,PgClassExpression70,JSONParse72,Access73,PgSelect74,First78,PgSelectSingle79,PgClassExpression88,Connection94,PgUnionAll95,First96,PgUnionAllSingle97,PgClassExpression98 bucket5 Bucket0 --> Bucket1 diff --git a/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.mermaid b/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.mermaid index df8e17c2c9..520b870d63 100644 --- a/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/polymorphic/person-app-vulns.mermaid @@ -409,58 +409,58 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18, 39

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 18, 39

ROOT PgSelectSingle{2}ᐸpeopleᐳ[22]
1:
ᐳ: 23, 24
2: 40, 44, 71
ᐳ: First[41]
3: PgUnionAllSingle[42]
ᐳ: PgClassExpression[43]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 39, 22

ROOT PgSelectSingle{2}ᐸpeopleᐳ[22]
1:
ᐳ: 23, 24
2: 40, 44, 71
ᐳ: First[41]
3: PgUnionAllSingle[42]
ᐳ: PgClassExpression[43]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression24,PgUnionAll40,First41,PgUnionAllSingle42,PgClassExpression43,PgUnionAll44,PgUnionAll71 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 18

ROOT __Item{4}ᐸ44ᐳ[45]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item45,PgUnionAllSingle46 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 46, 18

ROOT PgUnionAllSingle{4}[46]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 18, 46

ROOT PgUnionAllSingle{4}[46]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgCursor47,Access48,Access49,List50 bucket5 - Bucket6("Bucket 6 (polymorphic)
AwsApplication,GcpApplication
Deps: 49, 18, 46
ᐳAwsApplication
ᐳGcpApplication
1: JSONParse[52], JSONParse[62]
ᐳ: Access[53], Access[63]
2: PgSelect[54], PgSelect[64]
ᐳ: 58, 59, 60, 68, 69, 70"):::bucket + Bucket6("Bucket 6 (polymorphic)
AwsApplication,GcpApplication
Deps: 18, 49, 46
ᐳAwsApplication
ᐳGcpApplication
1: JSONParse[52], JSONParse[62]
ᐳ: Access[53], Access[63]
2: PgSelect[54], PgSelect[64]
ᐳ: 58, 59, 60, 68, 69, 70"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,JSONParse52,Access53,PgSelect54,First58,PgSelectSingle59,PgClassExpression60,JSONParse62,Access63,PgSelect64,First68,PgSelectSingle69,PgClassExpression70 bucket6 Bucket7("Bucket 7 (listItem)
Deps: 18

ROOT __Item{7}ᐸ71ᐳ[72]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,__Item72,PgUnionAllSingle73,Access74 bucket7 - Bucket8("Bucket 8 (polymorphic)
AwsApplication,GcpApplication
Deps: 74, 18, 73
ᐳAwsApplication
ᐳGcpApplication
1: JSONParse[75], JSONParse[206]
ᐳ: 169, 300, 76, 207
2: PgSelect[77], PgSelect[208]
ᐳ: 81, 82, 83, 84, 85, 86, 87, 212, 213, 214, 215, 216, 217, 218
3: 88, 123, 170, 174, 219, 254, 301, 305
ᐳ: 92, 171, 223, 302
4: 93, 172, 224, 303
ᐳ: 94, 173, 225, 304"):::bucket + Bucket8("Bucket 8 (polymorphic)
AwsApplication,GcpApplication
Deps: 18, 74, 73
ᐳAwsApplication
ᐳGcpApplication
1: JSONParse[75], JSONParse[206]
ᐳ: 169, 300, 76, 207
2: PgSelect[77], PgSelect[208]
ᐳ: 81, 82, 83, 84, 85, 86, 87, 212, 213, 214, 215, 216, 217, 218
3: 88, 123, 170, 174, 219, 254, 301, 305
ᐳ: 92, 171, 223, 302
4: 93, 172, 224, 303
ᐳ: 94, 173, 225, 304"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,JSONParse75,Access76,PgSelect77,First81,PgSelectSingle82,PgClassExpression83,PgClassExpression84,PgClassExpression85,PgClassExpression86,PgClassExpression87,PgUnionAll88,First92,PgUnionAllSingle93,Access94,PgUnionAll123,Connection169,PgUnionAll170,First171,PgUnionAllSingle172,PgClassExpression173,PgUnionAll174,JSONParse206,Access207,PgSelect208,First212,PgSelectSingle213,PgClassExpression214,PgClassExpression215,PgClassExpression216,PgClassExpression217,PgClassExpression218,PgUnionAll219,First223,PgUnionAllSingle224,Access225,PgUnionAll254,Connection300,PgUnionAll301,First302,PgUnionAllSingle303,PgClassExpression304,PgUnionAll305 bucket8 - Bucket9("Bucket 9 (polymorphic)
Organization,Person
Deps: 94, 18, 93
ᐳAwsApplicationᐳOrganization
ᐳAwsApplicationᐳPerson
1: JSONParse[95], JSONParse[106]
ᐳ: Access[96], Access[107]
2: PgSelect[97], PgSelect[108]
ᐳ: 101, 102, 103, 104, 112, 113, 114, 115"):::bucket + Bucket9("Bucket 9 (polymorphic)
Organization,Person
Deps: 18, 94, 93
ᐳAwsApplicationᐳOrganization
ᐳAwsApplicationᐳPerson
1: JSONParse[95], JSONParse[106]
ᐳ: Access[96], Access[107]
2: PgSelect[97], PgSelect[108]
ᐳ: 101, 102, 103, 104, 112, 113, 114, 115"):::bucket classDef bucket9 stroke:#ff0000 class Bucket9,JSONParse95,Access96,PgSelect97,First101,PgSelectSingle102,PgClassExpression103,PgClassExpression104,JSONParse106,Access107,PgSelect108,First112,PgSelectSingle113,PgClassExpression114,PgClassExpression115 bucket9 Bucket10("Bucket 10 (listItem)
Deps: 18

ROOT __Item{10}ᐸ123ᐳ[127]"):::bucket classDef bucket10 stroke:#ffff00 class Bucket10,__Item127,PgUnionAllSingle128,Access129 bucket10 - Bucket11("Bucket 11 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 129, 18, 128
ᐳAwsApplicationᐳFirstPartyVulnerability
ᐳAwsApplicationᐳThirdPartyVulnerability
1: JSONParse[130], JSONParse[143]
ᐳ: Access[131], Access[144]
2: PgSelect[132], PgSelect[145]
ᐳ: 136, 137, 138, 139, 140, 141, 149, 150, 151, 152, 153, 154"):::bucket + Bucket11("Bucket 11 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 18, 129, 128
ᐳAwsApplicationᐳFirstPartyVulnerability
ᐳAwsApplicationᐳThirdPartyVulnerability
1: JSONParse[130], JSONParse[143]
ᐳ: Access[131], Access[144]
2: PgSelect[132], PgSelect[145]
ᐳ: 136, 137, 138, 139, 140, 141, 149, 150, 151, 152, 153, 154"):::bucket classDef bucket11 stroke:#00ffff class Bucket11,JSONParse130,Access131,PgSelect132,First136,PgSelectSingle137,PgClassExpression138,PgClassExpression139,PgClassExpression140,PgClassExpression141,JSONParse143,Access144,PgSelect145,First149,PgSelectSingle150,PgClassExpression151,PgClassExpression152,PgClassExpression153,PgClassExpression154 bucket11 Bucket12("Bucket 12 (listItem)
Deps: 18

ROOT __Item{12}ᐸ174ᐳ[175]"):::bucket classDef bucket12 stroke:#4169e1 class Bucket12,__Item175,PgUnionAllSingle176 bucket12 - Bucket13("Bucket 13 (nullableBoundary)
Deps: 176, 18

ROOT PgUnionAllSingle{12}[176]"):::bucket + Bucket13("Bucket 13 (nullableBoundary)
Deps: 18, 176

ROOT PgUnionAllSingle{12}[176]"):::bucket classDef bucket13 stroke:#3cb371 class Bucket13,PgCursor177,Access178,Access179,List180 bucket13 - Bucket14("Bucket 14 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 179, 18, 176
ᐳAwsApplicationᐳFirstPartyVulnerability
ᐳAwsApplicationᐳThirdPartyVulnerability
1: JSONParse[182], JSONParse[194]
ᐳ: Access[183], Access[195]
2: PgSelect[184], PgSelect[196]
ᐳ: 188, 189, 190, 191, 192, 200, 201, 202, 203, 204"):::bucket + Bucket14("Bucket 14 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 18, 179, 176
ᐳAwsApplicationᐳFirstPartyVulnerability
ᐳAwsApplicationᐳThirdPartyVulnerability
1: JSONParse[182], JSONParse[194]
ᐳ: Access[183], Access[195]
2: PgSelect[184], PgSelect[196]
ᐳ: 188, 189, 190, 191, 192, 200, 201, 202, 203, 204"):::bucket classDef bucket14 stroke:#a52a2a class Bucket14,JSONParse182,Access183,PgSelect184,First188,PgSelectSingle189,PgClassExpression190,PgClassExpression191,PgClassExpression192,JSONParse194,Access195,PgSelect196,First200,PgSelectSingle201,PgClassExpression202,PgClassExpression203,PgClassExpression204 bucket14 - Bucket15("Bucket 15 (polymorphic)
Organization,Person
Deps: 225, 18, 224
ᐳGcpApplicationᐳOrganization
ᐳGcpApplicationᐳPerson
1: JSONParse[226], JSONParse[237]
ᐳ: Access[227], Access[238]
2: PgSelect[228], PgSelect[239]
ᐳ: 232, 233, 234, 235, 243, 244, 245, 246"):::bucket + Bucket15("Bucket 15 (polymorphic)
Organization,Person
Deps: 18, 225, 224
ᐳGcpApplicationᐳOrganization
ᐳGcpApplicationᐳPerson
1: JSONParse[226], JSONParse[237]
ᐳ: Access[227], Access[238]
2: PgSelect[228], PgSelect[239]
ᐳ: 232, 233, 234, 235, 243, 244, 245, 246"):::bucket classDef bucket15 stroke:#ff00ff class Bucket15,JSONParse226,Access227,PgSelect228,First232,PgSelectSingle233,PgClassExpression234,PgClassExpression235,JSONParse237,Access238,PgSelect239,First243,PgSelectSingle244,PgClassExpression245,PgClassExpression246 bucket15 Bucket16("Bucket 16 (listItem)
Deps: 18

ROOT __Item{16}ᐸ254ᐳ[258]"):::bucket classDef bucket16 stroke:#f5deb3 class Bucket16,__Item258,PgUnionAllSingle259,Access260 bucket16 - Bucket17("Bucket 17 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 260, 18, 259
ᐳGcpApplicationᐳFirstPartyVulnerability
ᐳGcpApplicationᐳThirdPartyVulnerability
1: JSONParse[261], JSONParse[274]
ᐳ: Access[262], Access[275]
2: PgSelect[263], PgSelect[276]
ᐳ: 267, 268, 269, 270, 271, 272, 280, 281, 282, 283, 284, 285"):::bucket + Bucket17("Bucket 17 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 18, 260, 259
ᐳGcpApplicationᐳFirstPartyVulnerability
ᐳGcpApplicationᐳThirdPartyVulnerability
1: JSONParse[261], JSONParse[274]
ᐳ: Access[262], Access[275]
2: PgSelect[263], PgSelect[276]
ᐳ: 267, 268, 269, 270, 271, 272, 280, 281, 282, 283, 284, 285"):::bucket classDef bucket17 stroke:#696969 class Bucket17,JSONParse261,Access262,PgSelect263,First267,PgSelectSingle268,PgClassExpression269,PgClassExpression270,PgClassExpression271,PgClassExpression272,JSONParse274,Access275,PgSelect276,First280,PgSelectSingle281,PgClassExpression282,PgClassExpression283,PgClassExpression284,PgClassExpression285 bucket17 Bucket18("Bucket 18 (listItem)
Deps: 18

ROOT __Item{18}ᐸ305ᐳ[306]"):::bucket classDef bucket18 stroke:#00bfff class Bucket18,__Item306,PgUnionAllSingle307 bucket18 - Bucket19("Bucket 19 (nullableBoundary)
Deps: 307, 18

ROOT PgUnionAllSingle{18}[307]"):::bucket + Bucket19("Bucket 19 (nullableBoundary)
Deps: 18, 307

ROOT PgUnionAllSingle{18}[307]"):::bucket classDef bucket19 stroke:#7f007f class Bucket19,PgCursor308,Access309,Access310,List311 bucket19 - Bucket20("Bucket 20 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 310, 18, 307
ᐳGcpApplicationᐳFirstPartyVulnerability
ᐳGcpApplicationᐳThirdPartyVulnerability
1: JSONParse[313], JSONParse[325]
ᐳ: Access[314], Access[326]
2: PgSelect[315], PgSelect[327]
ᐳ: 319, 320, 321, 322, 323, 331, 332, 333, 334, 335"):::bucket + Bucket20("Bucket 20 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 18, 310, 307
ᐳGcpApplicationᐳFirstPartyVulnerability
ᐳGcpApplicationᐳThirdPartyVulnerability
1: JSONParse[313], JSONParse[325]
ᐳ: Access[314], Access[326]
2: PgSelect[315], PgSelect[327]
ᐳ: 319, 320, 321, 322, 323, 331, 332, 333, 334, 335"):::bucket classDef bucket20 stroke:#ffa500 class Bucket20,JSONParse313,Access314,PgSelect315,First319,PgSelectSingle320,PgClassExpression321,PgClassExpression322,PgClassExpression323,JSONParse325,Access326,PgSelect327,First331,PgSelectSingle332,PgClassExpression333,PgClassExpression334,PgClassExpression335 bucket20 Bucket0 --> Bucket1 diff --git a/postgraphile/postgraphile/__tests__/queries/polymorphic/relay.polyroot_with_related_poly.mermaid b/postgraphile/postgraphile/__tests__/queries/polymorphic/relay.polyroot_with_related_poly.mermaid index af96c37457..ad18af6234 100644 --- a/postgraphile/postgraphile/__tests__/queries/polymorphic/relay.polyroot_with_related_poly.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/polymorphic/relay.polyroot_with_related_poly.mermaid @@ -861,7 +861,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22,PgClassExpression24,PgClassExpression27,PgClassExpression28 bucket2 - Bucket3("Bucket 3 (polymorphic)
SingleTableTopic,SingleTablePost,SingleTableDivider,SingleTableChecklist,SingleTableChecklistItem
Deps: 24, 18, 28, 22, 27
ᐳSingleTableTopic
ᐳSingleTablePost
ᐳSingleTableDivider
ᐳSingleTableChecklist
ᐳSingleTableChecklistItem"):::bucket + Bucket3("Bucket 3 (polymorphic)
SingleTableTopic,SingleTablePost,SingleTableDivider,SingleTableChecklist,SingleTableChecklistItem
Deps: 18, 24, 28, 22, 27
ᐳSingleTableTopic
ᐳSingleTablePost
ᐳSingleTableDivider
ᐳSingleTableChecklist
ᐳSingleTableChecklistItem"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,Constant23,List25,Lambda26,PgSelect29,First33,PgSelectSingle34,PgClassExpression36,PgClassExpression39,Constant60,List62,Lambda63,Constant97,List99,Lambda100,Constant134,List136,Lambda137,Constant171,List173,Lambda174 bucket3 Bucket4("Bucket 4 (polymorphic)
SingleTableTopic,SingleTablePost,SingleTableDivider,SingleTableChecklist,SingleTableChecklistItem
Deps: 36, 34, 39
ᐳSingleTableTopicᐳSingleTableTopic
ᐳSingleTableTopicᐳSingleTablePost
ᐳSingleTableTopicᐳSingleTableDivider
ᐳSingleTableTopicᐳSingleTableChecklist
ᐳSingleTableTopicᐳSingleTableChecklistItem
ᐳSingleTablePostᐳSingleTableTopic
ᐳSingleTablePostᐳSingleTablePost
ᐳSingleTablePostᐳSingleTableDivider
ᐳSingleTablePostᐳSingleTableChecklist
ᐳSingleTablePostᐳSingleTableChecklistItem
ᐳSingleTableDividerᐳSingleTableTopic
ᐳSingleTableDividerᐳSingleTablePost
ᐳSingleTableDividerᐳSingleTableDivider
ᐳSingleTableDividerᐳSingleTableChecklist
ᐳSingleTableDividerᐳSingleTableChecklistItem
ᐳSingleTableChecklistᐳSingleTableTopic
ᐳSingleTableChecklistᐳSingleTablePost
ᐳSingleTableChecklistᐳSingleTableDivider
ᐳSingleTableChecklistᐳSingleTableChecklist
ᐳSingleTableChecklistᐳSingleTableChecklistItem
ᐳSingleTableChecklistItemᐳSingleTableTopic
ᐳSingleTableChecklistItemᐳSingleTablePost
ᐳSingleTableChecklistItemᐳSingleTableDivider
ᐳSingleTableChecklistItemᐳSingleTableChecklist
ᐳSingleTableChecklistItemᐳSingleTableChecklistItem"):::bucket @@ -897,7 +897,7 @@ graph TD Bucket14("Bucket 14 (listItem)
Deps: 666

ROOT __Item{14}ᐸ663ᐳ[664]"):::bucket classDef bucket14 stroke:#a52a2a class Bucket14,__Item664,PgSelectSingle665 bucket14 - Bucket15("Bucket 15 (nullableBoundary)
Deps: 665, 666

ROOT PgSelectSingle{14}ᐸsingle_table_item_relationsᐳ[665]"):::bucket + Bucket15("Bucket 15 (nullableBoundary)
Deps: 666, 665

ROOT PgSelectSingle{14}ᐸsingle_table_item_relationsᐳ[665]"):::bucket classDef bucket15 stroke:#ff00ff class Bucket15,PgClassExpression667,List668,Lambda669,PgSelectSingle676,PgClassExpression678,PgClassExpression681,PgSelectSingle708,PgClassExpression710,PgClassExpression713,RemapKeys919,RemapKeys921 bucket15 Bucket16("Bucket 16 (polymorphic)
SingleTableTopic,SingleTablePost,SingleTableDivider,SingleTableChecklist,SingleTableChecklistItem
Deps: 678, 676, 681
ᐳSingleTableTopic
ᐳSingleTablePost
ᐳSingleTableDivider
ᐳSingleTableChecklist
ᐳSingleTableChecklistItem"):::bucket @@ -912,7 +912,7 @@ graph TD Bucket19("Bucket 19 (listItem)
Deps: 781, 18

ROOT __Item{19}ᐸ778ᐳ[779]"):::bucket classDef bucket19 stroke:#7f007f class Bucket19,__Item779,PgSelectSingle780 bucket19 - Bucket20("Bucket 20 (nullableBoundary)
Deps: 780, 781, 18

ROOT PgSelectSingle{19}ᐸrelational_item_relationsᐳ[780]"):::bucket + Bucket20("Bucket 20 (nullableBoundary)
Deps: 781, 18, 780

ROOT PgSelectSingle{19}ᐸrelational_item_relationsᐳ[780]"):::bucket classDef bucket20 stroke:#ffa500 class Bucket20,PgClassExpression782,List783,Lambda784,PgSelectSingle791,PgClassExpression792,PgClassExpression803,PgSelectSingle858,PgClassExpression859,PgClassExpression870,RemapKeys923,RemapKeys925 bucket20 Bucket21("Bucket 21 (polymorphic)
RelationalTopic,RelationalPost,RelationalDivider,RelationalChecklist,RelationalChecklistItem
Deps: 18, 792, 791, 803
ᐳRelationalTopic
ᐳRelationalPost
ᐳRelationalDivider
ᐳRelationalChecklist
ᐳRelationalChecklistItem"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/polymorphic/simple-log-entries.mermaid b/postgraphile/postgraphile/__tests__/queries/polymorphic/simple-log-entries.mermaid index 94c3725beb..9ef0bc3a40 100644 --- a/postgraphile/postgraphile/__tests__/queries/polymorphic/simple-log-entries.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/polymorphic/simple-log-entries.mermaid @@ -76,10 +76,10 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 18

ROOT PgSelectSingle{2}ᐸlog_entriesᐳ[22]
1:
ᐳ: 23, 24, 25
2: PgUnionAll[26]
ᐳ: First[30]
3: PgUnionAllSingle[31]
ᐳ: Access[32]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 22

ROOT PgSelectSingle{2}ᐸlog_entriesᐳ[22]
1:
ᐳ: 23, 24, 25
2: PgUnionAll[26]
ᐳ: First[30]
3: PgUnionAllSingle[31]
ᐳ: Access[32]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression24,PgClassExpression25,PgUnionAll26,First30,PgUnionAllSingle31,Access32 bucket3 - Bucket4("Bucket 4 (polymorphic)
Organization,Person
Deps: 32, 18, 31
ᐳOrganization
ᐳPerson
1: JSONParse[33], JSONParse[43]
ᐳ: Access[34], Access[44]
2: PgSelect[35], PgSelect[45]
ᐳ: 39, 40, 41, 49, 50, 51"):::bucket + Bucket4("Bucket 4 (polymorphic)
Organization,Person
Deps: 18, 32, 31
ᐳOrganization
ᐳPerson
1: JSONParse[33], JSONParse[43]
ᐳ: Access[34], Access[44]
2: PgSelect[35], PgSelect[45]
ᐳ: 39, 40, 41, 49, 50, 51"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,JSONParse33,Access34,PgSelect35,First39,PgSelectSingle40,PgClassExpression41,JSONParse43,Access44,PgSelect45,First49,PgSelectSingle50,PgClassExpression51 bucket4 Bucket0 --> Bucket1 diff --git a/postgraphile/postgraphile/__tests__/queries/polymorphic/simple-single-table-items-root-topic.mermaid b/postgraphile/postgraphile/__tests__/queries/polymorphic/simple-single-table-items-root-topic.mermaid index c9dc880d90..9bbf089573 100644 --- a/postgraphile/postgraphile/__tests__/queries/polymorphic/simple-single-table-items-root-topic.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/polymorphic/simple-single-table-items-root-topic.mermaid @@ -244,7 +244,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22,PgClassExpression23,PgClassExpression28,PgClassExpression29 bucket2 - Bucket3("Bucket 3 (polymorphic)
SingleTableTopic,SingleTablePost,SingleTableDivider,SingleTableChecklist,SingleTableChecklistItem
Deps: 23, 18, 29, 22, 28
ᐳSingleTableTopic
ᐳSingleTablePost
ᐳSingleTableDivider
ᐳSingleTableChecklist
ᐳSingleTableChecklistItem"):::bucket + Bucket3("Bucket 3 (polymorphic)
SingleTableTopic,SingleTablePost,SingleTableDivider,SingleTableChecklist,SingleTableChecklistItem
Deps: 18, 23, 29, 22, 28
ᐳSingleTableTopic
ᐳSingleTablePost
ᐳSingleTableDivider
ᐳSingleTableChecklist
ᐳSingleTableChecklistItem"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,Constant24,List26,Lambda27,PgSelect31,First35,PgSelectSingle36,Constant40,List42,Lambda43,Constant56,List58,Lambda59,Constant72,List74,Lambda75,Constant88,List90,Lambda91 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 36

ROOT PgSelectSingle{3}ᐸsingle_table_itemsᐳ[36]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/polymorphic/vulns.mermaid b/postgraphile/postgraphile/__tests__/queries/polymorphic/vulns.mermaid index 92a2aecd44..a5e203906d 100644 --- a/postgraphile/postgraphile/__tests__/queries/polymorphic/vulns.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/polymorphic/vulns.mermaid @@ -188,16 +188,16 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 19

ROOT __Item{2}ᐸ22ᐳ[23]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item23,PgUnionAllSingle24 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 24, 19

ROOT PgUnionAllSingle{2}[24]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 19, 24

ROOT PgUnionAllSingle{2}[24]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor25,Access32,Access33,Access34,List35 bucket3 - Bucket4("Bucket 4 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 34, 19, 24
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[37], JSONParse[49]
ᐳ: Access[38], Access[50]
2: PgSelect[39], PgSelect[51]
ᐳ: 43, 44, 45, 46, 47, 55, 56, 57, 58, 59, 60"):::bucket + Bucket4("Bucket 4 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 19, 34, 24
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[37], JSONParse[49]
ᐳ: Access[38], Access[50]
2: PgSelect[39], PgSelect[51]
ᐳ: 43, 44, 45, 46, 47, 55, 56, 57, 58, 59, 60"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,JSONParse37,Access38,PgSelect39,First43,PgSelectSingle44,PgClassExpression45,PgClassExpression46,PgClassExpression47,JSONParse49,Access50,PgSelect51,First55,PgSelectSingle56,PgClassExpression57,PgClassExpression58,PgClassExpression59,PgClassExpression60 bucket4 Bucket5("Bucket 5 (listItem)
Deps: 19

ROOT __Item{5}ᐸ103ᐳ[107]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,__Item107,PgUnionAllSingle108,Access109 bucket5 - Bucket6("Bucket 6 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 109, 19, 108
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[110], JSONParse[122]
ᐳ: Access[111], Access[123]
2: PgSelect[112], PgSelect[124]
ᐳ: 116, 117, 118, 119, 120, 128, 129, 130, 131, 132, 133"):::bucket + Bucket6("Bucket 6 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 19, 109, 108
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[110], JSONParse[122]
ᐳ: Access[111], Access[123]
2: PgSelect[112], PgSelect[124]
ᐳ: 116, 117, 118, 119, 120, 128, 129, 130, 131, 132, 133"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,JSONParse110,Access111,PgSelect112,First116,PgSelectSingle117,PgClassExpression118,PgClassExpression119,PgClassExpression120,JSONParse122,Access123,PgSelect124,First128,PgSelectSingle129,PgClassExpression130,PgClassExpression131,PgClassExpression132,PgClassExpression133 bucket6 Bucket0 --> Bucket1 & Bucket5 diff --git a/postgraphile/postgraphile/__tests__/queries/polymorphic/vulns.union_owners.mermaid b/postgraphile/postgraphile/__tests__/queries/polymorphic/vulns.union_owners.mermaid index 452a65b26c..6c3a79f5ef 100644 --- a/postgraphile/postgraphile/__tests__/queries/polymorphic/vulns.union_owners.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/polymorphic/vulns.union_owners.mermaid @@ -852,79 +852,79 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgUnionAllSingle22,Access23 bucket2 - Bucket3("Bucket 3 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 23, 18, 22
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[24], JSONParse[347]
ᐳ: 32, 51, 276, 355, 374, 599, 25, 348
2: PgSelect[26], PgSelect[349]
ᐳ: 30, 31, 33, 34, 35, 36, 353, 354, 356, 357, 358, 359
3: 52, 162, 277, 312, 375, 485, 600, 635"):::bucket + Bucket3("Bucket 3 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 18, 23, 22
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[24], JSONParse[347]
ᐳ: 32, 51, 276, 355, 374, 599, 25, 348
2: PgSelect[26], PgSelect[349]
ᐳ: 30, 31, 33, 34, 35, 36, 353, 354, 356, 357, 358, 359
3: 52, 162, 277, 312, 375, 485, 600, 635"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,JSONParse24,Access25,PgSelect26,First30,PgSelectSingle31,Constant32,PgClassExpression33,List34,Lambda35,PgClassExpression36,Connection51,PgUnionAll52,PgUnionAll162,Connection276,PgUnionAll277,PgUnionAll312,JSONParse347,Access348,PgSelect349,First353,PgSelectSingle354,Constant355,PgClassExpression356,List357,Lambda358,PgClassExpression359,Connection374,PgUnionAll375,PgUnionAll485,Connection599,PgUnionAll600,PgUnionAll635 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 18

ROOT __Item{4}ᐸ52ᐳ[53]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item53,PgUnionAllSingle54,Access55 bucket4 - Bucket5("Bucket 5 (polymorphic)
AwsApplication,GcpApplication
Deps: 55, 18, 54
ᐳFirstPartyVulnerabilityᐳAwsApplication
ᐳFirstPartyVulnerabilityᐳGcpApplication
1: JSONParse[56], JSONParse[106]
ᐳ: 64, 114, 57, 107
2: PgSelect[58], PgSelect[108]
ᐳ: 62, 63, 65, 66, 67, 68, 69, 70, 112, 113, 115, 116, 117, 118, 119, 120
3: PgUnionAll[71], PgUnionAll[121]
ᐳ: First[75], First[125]
4: 76, 126
ᐳ: Access[77], Access[127]"):::bucket + Bucket5("Bucket 5 (polymorphic)
AwsApplication,GcpApplication
Deps: 18, 55, 54
ᐳFirstPartyVulnerabilityᐳAwsApplication
ᐳFirstPartyVulnerabilityᐳGcpApplication
1: JSONParse[56], JSONParse[106]
ᐳ: 64, 114, 57, 107
2: PgSelect[58], PgSelect[108]
ᐳ: 62, 63, 65, 66, 67, 68, 69, 70, 112, 113, 115, 116, 117, 118, 119, 120
3: PgUnionAll[71], PgUnionAll[121]
ᐳ: First[75], First[125]
4: 76, 126
ᐳ: Access[77], Access[127]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,JSONParse56,Access57,PgSelect58,First62,PgSelectSingle63,Constant64,PgClassExpression65,List66,Lambda67,PgClassExpression68,PgClassExpression69,PgClassExpression70,PgUnionAll71,First75,PgUnionAllSingle76,Access77,JSONParse106,Access107,PgSelect108,First112,PgSelectSingle113,Constant114,PgClassExpression115,List116,Lambda117,PgClassExpression118,PgClassExpression119,PgClassExpression120,PgUnionAll121,First125,PgUnionAllSingle126,Access127 bucket5 - Bucket6("Bucket 6 (polymorphic)
Organization,Person
Deps: 77, 18, 76
ᐳFirstPartyVulnerabilityᐳAwsApplicationᐳOrganization
ᐳFirstPartyVulnerabilityᐳAwsApplicationᐳPerson
1: JSONParse[78], JSONParse[92]
ᐳ: 86, 100, 79, 93
2: PgSelect[80], PgSelect[94]
ᐳ: 84, 85, 87, 88, 89, 90, 98, 99, 101, 102, 103, 104"):::bucket + Bucket6("Bucket 6 (polymorphic)
Organization,Person
Deps: 18, 77, 76
ᐳFirstPartyVulnerabilityᐳAwsApplicationᐳOrganization
ᐳFirstPartyVulnerabilityᐳAwsApplicationᐳPerson
1: JSONParse[78], JSONParse[92]
ᐳ: 86, 100, 79, 93
2: PgSelect[80], PgSelect[94]
ᐳ: 84, 85, 87, 88, 89, 90, 98, 99, 101, 102, 103, 104"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,JSONParse78,Access79,PgSelect80,First84,PgSelectSingle85,Constant86,PgClassExpression87,List88,Lambda89,PgClassExpression90,JSONParse92,Access93,PgSelect94,First98,PgSelectSingle99,Constant100,PgClassExpression101,List102,Lambda103,PgClassExpression104 bucket6 - Bucket7("Bucket 7 (polymorphic)
Organization,Person
Deps: 127, 18, 126
ᐳFirstPartyVulnerabilityᐳGcpApplicationᐳOrganization
ᐳFirstPartyVulnerabilityᐳGcpApplicationᐳPerson
1: JSONParse[128], JSONParse[142]
ᐳ: 136, 150, 129, 143
2: PgSelect[130], PgSelect[144]
ᐳ: 134, 135, 137, 138, 139, 140, 148, 149, 151, 152, 153, 154"):::bucket + Bucket7("Bucket 7 (polymorphic)
Organization,Person
Deps: 18, 127, 126
ᐳFirstPartyVulnerabilityᐳGcpApplicationᐳOrganization
ᐳFirstPartyVulnerabilityᐳGcpApplicationᐳPerson
1: JSONParse[128], JSONParse[142]
ᐳ: 136, 150, 129, 143
2: PgSelect[130], PgSelect[144]
ᐳ: 134, 135, 137, 138, 139, 140, 148, 149, 151, 152, 153, 154"):::bucket classDef bucket7 stroke:#808000 class Bucket7,JSONParse128,Access129,PgSelect130,First134,PgSelectSingle135,Constant136,PgClassExpression137,List138,Lambda139,PgClassExpression140,JSONParse142,Access143,PgSelect144,First148,PgSelectSingle149,Constant150,PgClassExpression151,List152,Lambda153,PgClassExpression154 bucket7 Bucket8("Bucket 8 (listItem)
Deps: 18

ROOT __Item{8}ᐸ162ᐳ[166]"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,__Item166,PgUnionAllSingle167,Access168 bucket8 - Bucket9("Bucket 9 (polymorphic)
AwsApplication,GcpApplication
Deps: 168, 18, 167
ᐳFirstPartyVulnerabilityᐳAwsApplication
ᐳFirstPartyVulnerabilityᐳGcpApplication
1: JSONParse[169], JSONParse[219]
ᐳ: 177, 227, 170, 220
2: PgSelect[171], PgSelect[221]
ᐳ: 175, 176, 178, 179, 180, 181, 182, 183, 225, 226, 228, 229, 230, 231, 232, 233
3: PgUnionAll[184], PgUnionAll[234]
ᐳ: First[188], First[238]
4: 189, 239
ᐳ: Access[190], Access[240]"):::bucket + Bucket9("Bucket 9 (polymorphic)
AwsApplication,GcpApplication
Deps: 18, 168, 167
ᐳFirstPartyVulnerabilityᐳAwsApplication
ᐳFirstPartyVulnerabilityᐳGcpApplication
1: JSONParse[169], JSONParse[219]
ᐳ: 177, 227, 170, 220
2: PgSelect[171], PgSelect[221]
ᐳ: 175, 176, 178, 179, 180, 181, 182, 183, 225, 226, 228, 229, 230, 231, 232, 233
3: PgUnionAll[184], PgUnionAll[234]
ᐳ: First[188], First[238]
4: 189, 239
ᐳ: Access[190], Access[240]"):::bucket classDef bucket9 stroke:#ff0000 class Bucket9,JSONParse169,Access170,PgSelect171,First175,PgSelectSingle176,Constant177,PgClassExpression178,List179,Lambda180,PgClassExpression181,PgClassExpression182,PgClassExpression183,PgUnionAll184,First188,PgUnionAllSingle189,Access190,JSONParse219,Access220,PgSelect221,First225,PgSelectSingle226,Constant227,PgClassExpression228,List229,Lambda230,PgClassExpression231,PgClassExpression232,PgClassExpression233,PgUnionAll234,First238,PgUnionAllSingle239,Access240 bucket9 - Bucket10("Bucket 10 (polymorphic)
Organization,Person
Deps: 190, 18, 189
ᐳFirstPartyVulnerabilityᐳAwsApplicationᐳOrganization
ᐳFirstPartyVulnerabilityᐳAwsApplicationᐳPerson
1: JSONParse[191], JSONParse[205]
ᐳ: 199, 213, 192, 206
2: PgSelect[193], PgSelect[207]
ᐳ: 197, 198, 200, 201, 202, 203, 211, 212, 214, 215, 216, 217"):::bucket + Bucket10("Bucket 10 (polymorphic)
Organization,Person
Deps: 18, 190, 189
ᐳFirstPartyVulnerabilityᐳAwsApplicationᐳOrganization
ᐳFirstPartyVulnerabilityᐳAwsApplicationᐳPerson
1: JSONParse[191], JSONParse[205]
ᐳ: 199, 213, 192, 206
2: PgSelect[193], PgSelect[207]
ᐳ: 197, 198, 200, 201, 202, 203, 211, 212, 214, 215, 216, 217"):::bucket classDef bucket10 stroke:#ffff00 class Bucket10,JSONParse191,Access192,PgSelect193,First197,PgSelectSingle198,Constant199,PgClassExpression200,List201,Lambda202,PgClassExpression203,JSONParse205,Access206,PgSelect207,First211,PgSelectSingle212,Constant213,PgClassExpression214,List215,Lambda216,PgClassExpression217 bucket10 - Bucket11("Bucket 11 (polymorphic)
Organization,Person
Deps: 240, 18, 239
ᐳFirstPartyVulnerabilityᐳGcpApplicationᐳOrganization
ᐳFirstPartyVulnerabilityᐳGcpApplicationᐳPerson
1: JSONParse[241], JSONParse[255]
ᐳ: 249, 263, 242, 256
2: PgSelect[243], PgSelect[257]
ᐳ: 247, 248, 250, 251, 252, 253, 261, 262, 264, 265, 266, 267"):::bucket + Bucket11("Bucket 11 (polymorphic)
Organization,Person
Deps: 18, 240, 239
ᐳFirstPartyVulnerabilityᐳGcpApplicationᐳOrganization
ᐳFirstPartyVulnerabilityᐳGcpApplicationᐳPerson
1: JSONParse[241], JSONParse[255]
ᐳ: 249, 263, 242, 256
2: PgSelect[243], PgSelect[257]
ᐳ: 247, 248, 250, 251, 252, 253, 261, 262, 264, 265, 266, 267"):::bucket classDef bucket11 stroke:#00ffff class Bucket11,JSONParse241,Access242,PgSelect243,First247,PgSelectSingle248,Constant249,PgClassExpression250,List251,Lambda252,PgClassExpression253,JSONParse255,Access256,PgSelect257,First261,PgSelectSingle262,Constant263,PgClassExpression264,List265,Lambda266,PgClassExpression267 bucket11 Bucket12("Bucket 12 (listItem)
Deps: 18

ROOT __Item{12}ᐸ277ᐳ[278]"):::bucket classDef bucket12 stroke:#4169e1 class Bucket12,__Item278,PgUnionAllSingle279,Access280 bucket12 - Bucket13("Bucket 13 (polymorphic)
Organization,Person
Deps: 280, 18, 279
ᐳFirstPartyVulnerabilityᐳOrganization
ᐳFirstPartyVulnerabilityᐳPerson
1: JSONParse[281], JSONParse[295]
ᐳ: 289, 303, 282, 296
2: PgSelect[283], PgSelect[297]
ᐳ: 287, 288, 290, 291, 292, 293, 301, 302, 304, 305, 306, 307"):::bucket + Bucket13("Bucket 13 (polymorphic)
Organization,Person
Deps: 18, 280, 279
ᐳFirstPartyVulnerabilityᐳOrganization
ᐳFirstPartyVulnerabilityᐳPerson
1: JSONParse[281], JSONParse[295]
ᐳ: 289, 303, 282, 296
2: PgSelect[283], PgSelect[297]
ᐳ: 287, 288, 290, 291, 292, 293, 301, 302, 304, 305, 306, 307"):::bucket classDef bucket13 stroke:#3cb371 class Bucket13,JSONParse281,Access282,PgSelect283,First287,PgSelectSingle288,Constant289,PgClassExpression290,List291,Lambda292,PgClassExpression293,JSONParse295,Access296,PgSelect297,First301,PgSelectSingle302,Constant303,PgClassExpression304,List305,Lambda306,PgClassExpression307 bucket13 Bucket14("Bucket 14 (listItem)
Deps: 18

ROOT __Item{14}ᐸ312ᐳ[316]"):::bucket classDef bucket14 stroke:#a52a2a class Bucket14,__Item316,PgUnionAllSingle317,Access318 bucket14 - Bucket15("Bucket 15 (polymorphic)
Organization,Person
Deps: 318, 18, 317
ᐳFirstPartyVulnerabilityᐳOrganization
ᐳFirstPartyVulnerabilityᐳPerson
1: JSONParse[319], JSONParse[333]
ᐳ: 327, 341, 320, 334
2: PgSelect[321], PgSelect[335]
ᐳ: 325, 326, 328, 329, 330, 331, 339, 340, 342, 343, 344, 345"):::bucket + Bucket15("Bucket 15 (polymorphic)
Organization,Person
Deps: 18, 318, 317
ᐳFirstPartyVulnerabilityᐳOrganization
ᐳFirstPartyVulnerabilityᐳPerson
1: JSONParse[319], JSONParse[333]
ᐳ: 327, 341, 320, 334
2: PgSelect[321], PgSelect[335]
ᐳ: 325, 326, 328, 329, 330, 331, 339, 340, 342, 343, 344, 345"):::bucket classDef bucket15 stroke:#ff00ff class Bucket15,JSONParse319,Access320,PgSelect321,First325,PgSelectSingle326,Constant327,PgClassExpression328,List329,Lambda330,PgClassExpression331,JSONParse333,Access334,PgSelect335,First339,PgSelectSingle340,Constant341,PgClassExpression342,List343,Lambda344,PgClassExpression345 bucket15 Bucket16("Bucket 16 (listItem)
Deps: 18

ROOT __Item{16}ᐸ375ᐳ[376]"):::bucket classDef bucket16 stroke:#f5deb3 class Bucket16,__Item376,PgUnionAllSingle377,Access378 bucket16 - Bucket17("Bucket 17 (polymorphic)
AwsApplication,GcpApplication
Deps: 378, 18, 377
ᐳThirdPartyVulnerabilityᐳAwsApplication
ᐳThirdPartyVulnerabilityᐳGcpApplication
1: JSONParse[379], JSONParse[429]
ᐳ: 387, 437, 380, 430
2: PgSelect[381], PgSelect[431]
ᐳ: 385, 386, 388, 389, 390, 391, 392, 393, 435, 436, 438, 439, 440, 441, 442, 443
3: PgUnionAll[394], PgUnionAll[444]
ᐳ: First[398], First[448]
4: 399, 449
ᐳ: Access[400], Access[450]"):::bucket + Bucket17("Bucket 17 (polymorphic)
AwsApplication,GcpApplication
Deps: 18, 378, 377
ᐳThirdPartyVulnerabilityᐳAwsApplication
ᐳThirdPartyVulnerabilityᐳGcpApplication
1: JSONParse[379], JSONParse[429]
ᐳ: 387, 437, 380, 430
2: PgSelect[381], PgSelect[431]
ᐳ: 385, 386, 388, 389, 390, 391, 392, 393, 435, 436, 438, 439, 440, 441, 442, 443
3: PgUnionAll[394], PgUnionAll[444]
ᐳ: First[398], First[448]
4: 399, 449
ᐳ: Access[400], Access[450]"):::bucket classDef bucket17 stroke:#696969 class Bucket17,JSONParse379,Access380,PgSelect381,First385,PgSelectSingle386,Constant387,PgClassExpression388,List389,Lambda390,PgClassExpression391,PgClassExpression392,PgClassExpression393,PgUnionAll394,First398,PgUnionAllSingle399,Access400,JSONParse429,Access430,PgSelect431,First435,PgSelectSingle436,Constant437,PgClassExpression438,List439,Lambda440,PgClassExpression441,PgClassExpression442,PgClassExpression443,PgUnionAll444,First448,PgUnionAllSingle449,Access450 bucket17 - Bucket18("Bucket 18 (polymorphic)
Organization,Person
Deps: 400, 18, 399
ᐳThirdPartyVulnerabilityᐳAwsApplicationᐳOrganization
ᐳThirdPartyVulnerabilityᐳAwsApplicationᐳPerson
1: JSONParse[401], JSONParse[415]
ᐳ: 409, 423, 402, 416
2: PgSelect[403], PgSelect[417]
ᐳ: 407, 408, 410, 411, 412, 413, 421, 422, 424, 425, 426, 427"):::bucket + Bucket18("Bucket 18 (polymorphic)
Organization,Person
Deps: 18, 400, 399
ᐳThirdPartyVulnerabilityᐳAwsApplicationᐳOrganization
ᐳThirdPartyVulnerabilityᐳAwsApplicationᐳPerson
1: JSONParse[401], JSONParse[415]
ᐳ: 409, 423, 402, 416
2: PgSelect[403], PgSelect[417]
ᐳ: 407, 408, 410, 411, 412, 413, 421, 422, 424, 425, 426, 427"):::bucket classDef bucket18 stroke:#00bfff class Bucket18,JSONParse401,Access402,PgSelect403,First407,PgSelectSingle408,Constant409,PgClassExpression410,List411,Lambda412,PgClassExpression413,JSONParse415,Access416,PgSelect417,First421,PgSelectSingle422,Constant423,PgClassExpression424,List425,Lambda426,PgClassExpression427 bucket18 - Bucket19("Bucket 19 (polymorphic)
Organization,Person
Deps: 450, 18, 449
ᐳThirdPartyVulnerabilityᐳGcpApplicationᐳOrganization
ᐳThirdPartyVulnerabilityᐳGcpApplicationᐳPerson
1: JSONParse[451], JSONParse[465]
ᐳ: 459, 473, 452, 466
2: PgSelect[453], PgSelect[467]
ᐳ: 457, 458, 460, 461, 462, 463, 471, 472, 474, 475, 476, 477"):::bucket + Bucket19("Bucket 19 (polymorphic)
Organization,Person
Deps: 18, 450, 449
ᐳThirdPartyVulnerabilityᐳGcpApplicationᐳOrganization
ᐳThirdPartyVulnerabilityᐳGcpApplicationᐳPerson
1: JSONParse[451], JSONParse[465]
ᐳ: 459, 473, 452, 466
2: PgSelect[453], PgSelect[467]
ᐳ: 457, 458, 460, 461, 462, 463, 471, 472, 474, 475, 476, 477"):::bucket classDef bucket19 stroke:#7f007f class Bucket19,JSONParse451,Access452,PgSelect453,First457,PgSelectSingle458,Constant459,PgClassExpression460,List461,Lambda462,PgClassExpression463,JSONParse465,Access466,PgSelect467,First471,PgSelectSingle472,Constant473,PgClassExpression474,List475,Lambda476,PgClassExpression477 bucket19 Bucket20("Bucket 20 (listItem)
Deps: 18

ROOT __Item{20}ᐸ485ᐳ[489]"):::bucket classDef bucket20 stroke:#ffa500 class Bucket20,__Item489,PgUnionAllSingle490,Access491 bucket20 - Bucket21("Bucket 21 (polymorphic)
AwsApplication,GcpApplication
Deps: 491, 18, 490
ᐳThirdPartyVulnerabilityᐳAwsApplication
ᐳThirdPartyVulnerabilityᐳGcpApplication
1: JSONParse[492], JSONParse[542]
ᐳ: 500, 550, 493, 543
2: PgSelect[494], PgSelect[544]
ᐳ: 498, 499, 501, 502, 503, 504, 505, 506, 548, 549, 551, 552, 553, 554, 555, 556
3: PgUnionAll[507], PgUnionAll[557]
ᐳ: First[511], First[561]
4: 512, 562
ᐳ: Access[513], Access[563]"):::bucket + Bucket21("Bucket 21 (polymorphic)
AwsApplication,GcpApplication
Deps: 18, 491, 490
ᐳThirdPartyVulnerabilityᐳAwsApplication
ᐳThirdPartyVulnerabilityᐳGcpApplication
1: JSONParse[492], JSONParse[542]
ᐳ: 500, 550, 493, 543
2: PgSelect[494], PgSelect[544]
ᐳ: 498, 499, 501, 502, 503, 504, 505, 506, 548, 549, 551, 552, 553, 554, 555, 556
3: PgUnionAll[507], PgUnionAll[557]
ᐳ: First[511], First[561]
4: 512, 562
ᐳ: Access[513], Access[563]"):::bucket classDef bucket21 stroke:#0000ff class Bucket21,JSONParse492,Access493,PgSelect494,First498,PgSelectSingle499,Constant500,PgClassExpression501,List502,Lambda503,PgClassExpression504,PgClassExpression505,PgClassExpression506,PgUnionAll507,First511,PgUnionAllSingle512,Access513,JSONParse542,Access543,PgSelect544,First548,PgSelectSingle549,Constant550,PgClassExpression551,List552,Lambda553,PgClassExpression554,PgClassExpression555,PgClassExpression556,PgUnionAll557,First561,PgUnionAllSingle562,Access563 bucket21 - Bucket22("Bucket 22 (polymorphic)
Organization,Person
Deps: 513, 18, 512
ᐳThirdPartyVulnerabilityᐳAwsApplicationᐳOrganization
ᐳThirdPartyVulnerabilityᐳAwsApplicationᐳPerson
1: JSONParse[514], JSONParse[528]
ᐳ: 522, 536, 515, 529
2: PgSelect[516], PgSelect[530]
ᐳ: 520, 521, 523, 524, 525, 526, 534, 535, 537, 538, 539, 540"):::bucket + Bucket22("Bucket 22 (polymorphic)
Organization,Person
Deps: 18, 513, 512
ᐳThirdPartyVulnerabilityᐳAwsApplicationᐳOrganization
ᐳThirdPartyVulnerabilityᐳAwsApplicationᐳPerson
1: JSONParse[514], JSONParse[528]
ᐳ: 522, 536, 515, 529
2: PgSelect[516], PgSelect[530]
ᐳ: 520, 521, 523, 524, 525, 526, 534, 535, 537, 538, 539, 540"):::bucket classDef bucket22 stroke:#7fff00 class Bucket22,JSONParse514,Access515,PgSelect516,First520,PgSelectSingle521,Constant522,PgClassExpression523,List524,Lambda525,PgClassExpression526,JSONParse528,Access529,PgSelect530,First534,PgSelectSingle535,Constant536,PgClassExpression537,List538,Lambda539,PgClassExpression540 bucket22 - Bucket23("Bucket 23 (polymorphic)
Organization,Person
Deps: 563, 18, 562
ᐳThirdPartyVulnerabilityᐳGcpApplicationᐳOrganization
ᐳThirdPartyVulnerabilityᐳGcpApplicationᐳPerson
1: JSONParse[564], JSONParse[578]
ᐳ: 572, 586, 565, 579
2: PgSelect[566], PgSelect[580]
ᐳ: 570, 571, 573, 574, 575, 576, 584, 585, 587, 588, 589, 590"):::bucket + Bucket23("Bucket 23 (polymorphic)
Organization,Person
Deps: 18, 563, 562
ᐳThirdPartyVulnerabilityᐳGcpApplicationᐳOrganization
ᐳThirdPartyVulnerabilityᐳGcpApplicationᐳPerson
1: JSONParse[564], JSONParse[578]
ᐳ: 572, 586, 565, 579
2: PgSelect[566], PgSelect[580]
ᐳ: 570, 571, 573, 574, 575, 576, 584, 585, 587, 588, 589, 590"):::bucket classDef bucket23 stroke:#ff1493 class Bucket23,JSONParse564,Access565,PgSelect566,First570,PgSelectSingle571,Constant572,PgClassExpression573,List574,Lambda575,PgClassExpression576,JSONParse578,Access579,PgSelect580,First584,PgSelectSingle585,Constant586,PgClassExpression587,List588,Lambda589,PgClassExpression590 bucket23 Bucket24("Bucket 24 (listItem)
Deps: 18

ROOT __Item{24}ᐸ600ᐳ[601]"):::bucket classDef bucket24 stroke:#808000 class Bucket24,__Item601,PgUnionAllSingle602,Access603 bucket24 - Bucket25("Bucket 25 (polymorphic)
Organization,Person
Deps: 603, 18, 602
ᐳThirdPartyVulnerabilityᐳOrganization
ᐳThirdPartyVulnerabilityᐳPerson
1: JSONParse[604], JSONParse[618]
ᐳ: 612, 626, 605, 619
2: PgSelect[606], PgSelect[620]
ᐳ: 610, 611, 613, 614, 615, 616, 624, 625, 627, 628, 629, 630"):::bucket + Bucket25("Bucket 25 (polymorphic)
Organization,Person
Deps: 18, 603, 602
ᐳThirdPartyVulnerabilityᐳOrganization
ᐳThirdPartyVulnerabilityᐳPerson
1: JSONParse[604], JSONParse[618]
ᐳ: 612, 626, 605, 619
2: PgSelect[606], PgSelect[620]
ᐳ: 610, 611, 613, 614, 615, 616, 624, 625, 627, 628, 629, 630"):::bucket classDef bucket25 stroke:#dda0dd class Bucket25,JSONParse604,Access605,PgSelect606,First610,PgSelectSingle611,Constant612,PgClassExpression613,List614,Lambda615,PgClassExpression616,JSONParse618,Access619,PgSelect620,First624,PgSelectSingle625,Constant626,PgClassExpression627,List628,Lambda629,PgClassExpression630 bucket25 Bucket26("Bucket 26 (listItem)
Deps: 18

ROOT __Item{26}ᐸ635ᐳ[639]"):::bucket classDef bucket26 stroke:#ff0000 class Bucket26,__Item639,PgUnionAllSingle640,Access641 bucket26 - Bucket27("Bucket 27 (polymorphic)
Organization,Person
Deps: 641, 18, 640
ᐳThirdPartyVulnerabilityᐳOrganization
ᐳThirdPartyVulnerabilityᐳPerson
1: JSONParse[642], JSONParse[656]
ᐳ: 650, 664, 643, 657
2: PgSelect[644], PgSelect[658]
ᐳ: 648, 649, 651, 652, 653, 654, 662, 663, 665, 666, 667, 668"):::bucket + Bucket27("Bucket 27 (polymorphic)
Organization,Person
Deps: 18, 641, 640
ᐳThirdPartyVulnerabilityᐳOrganization
ᐳThirdPartyVulnerabilityᐳPerson
1: JSONParse[642], JSONParse[656]
ᐳ: 650, 664, 643, 657
2: PgSelect[644], PgSelect[658]
ᐳ: 648, 649, 651, 652, 653, 654, 662, 663, 665, 666, 667, 668"):::bucket classDef bucket27 stroke:#ffff00 class Bucket27,JSONParse642,Access643,PgSelect644,First648,PgSelectSingle649,Constant650,PgClassExpression651,List652,Lambda653,PgClassExpression654,JSONParse656,Access657,PgSelect658,First662,PgSelectSingle663,Constant664,PgClassExpression665,List666,Lambda667,PgClassExpression668 bucket27 Bucket0 --> Bucket1 diff --git a/postgraphile/postgraphile/__tests__/queries/polymorphic/vulns.union_owners.simple.mermaid b/postgraphile/postgraphile/__tests__/queries/polymorphic/vulns.union_owners.simple.mermaid index efd5281bef..308427eba9 100644 --- a/postgraphile/postgraphile/__tests__/queries/polymorphic/vulns.union_owners.simple.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/polymorphic/vulns.union_owners.simple.mermaid @@ -174,19 +174,19 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgUnionAllSingle22,Access23 bucket2 - Bucket3("Bucket 3 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 23, 18, 22
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[24], JSONParse[78]
ᐳ: 32, 45, 86, 99, 25, 79
2: PgSelect[26], PgSelect[80]
ᐳ: 30, 31, 33, 34, 35, 36, 84, 85, 87, 88, 89, 90
3: PgUnionAll[46], PgUnionAll[100]"):::bucket + Bucket3("Bucket 3 (polymorphic)
FirstPartyVulnerability,ThirdPartyVulnerability
Deps: 18, 23, 22
ᐳFirstPartyVulnerability
ᐳThirdPartyVulnerability
1: JSONParse[24], JSONParse[78]
ᐳ: 32, 45, 86, 99, 25, 79
2: PgSelect[26], PgSelect[80]
ᐳ: 30, 31, 33, 34, 35, 36, 84, 85, 87, 88, 89, 90
3: PgUnionAll[46], PgUnionAll[100]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,JSONParse24,Access25,PgSelect26,First30,PgSelectSingle31,Constant32,PgClassExpression33,List34,Lambda35,PgClassExpression36,Connection45,PgUnionAll46,JSONParse78,Access79,PgSelect80,First84,PgSelectSingle85,Constant86,PgClassExpression87,List88,Lambda89,PgClassExpression90,Connection99,PgUnionAll100 bucket3 Bucket4("Bucket 4 (listItem)
Deps: 18

ROOT __Item{4}ᐸ46ᐳ[47]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item47,PgUnionAllSingle48,Access49 bucket4 - Bucket5("Bucket 5 (polymorphic)
Organization,Person
Deps: 49, 18, 48
ᐳFirstPartyVulnerabilityᐳOrganization
ᐳFirstPartyVulnerabilityᐳPerson
1: JSONParse[50], JSONParse[64]
ᐳ: 58, 72, 51, 65
2: PgSelect[52], PgSelect[66]
ᐳ: 56, 57, 59, 60, 61, 62, 70, 71, 73, 74, 75, 76"):::bucket + Bucket5("Bucket 5 (polymorphic)
Organization,Person
Deps: 18, 49, 48
ᐳFirstPartyVulnerabilityᐳOrganization
ᐳFirstPartyVulnerabilityᐳPerson
1: JSONParse[50], JSONParse[64]
ᐳ: 58, 72, 51, 65
2: PgSelect[52], PgSelect[66]
ᐳ: 56, 57, 59, 60, 61, 62, 70, 71, 73, 74, 75, 76"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,JSONParse50,Access51,PgSelect52,First56,PgSelectSingle57,Constant58,PgClassExpression59,List60,Lambda61,PgClassExpression62,JSONParse64,Access65,PgSelect66,First70,PgSelectSingle71,Constant72,PgClassExpression73,List74,Lambda75,PgClassExpression76 bucket5 Bucket6("Bucket 6 (listItem)
Deps: 18

ROOT __Item{6}ᐸ100ᐳ[101]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,__Item101,PgUnionAllSingle102,Access103 bucket6 - Bucket7("Bucket 7 (polymorphic)
Organization,Person
Deps: 103, 18, 102
ᐳThirdPartyVulnerabilityᐳOrganization
ᐳThirdPartyVulnerabilityᐳPerson
1: JSONParse[104], JSONParse[118]
ᐳ: 112, 126, 105, 119
2: PgSelect[106], PgSelect[120]
ᐳ: 110, 111, 113, 114, 115, 116, 124, 125, 127, 128, 129, 130"):::bucket + Bucket7("Bucket 7 (polymorphic)
Organization,Person
Deps: 18, 103, 102
ᐳThirdPartyVulnerabilityᐳOrganization
ᐳThirdPartyVulnerabilityᐳPerson
1: JSONParse[104], JSONParse[118]
ᐳ: 112, 126, 105, 119
2: PgSelect[106], PgSelect[120]
ᐳ: 110, 111, 113, 114, 115, 116, 124, 125, 127, 128, 129, 130"):::bucket classDef bucket7 stroke:#808000 class Bucket7,JSONParse104,Access105,PgSelect106,First110,PgSelectSingle111,Constant112,PgClassExpression113,List114,Lambda115,PgClassExpression116,JSONParse118,Access119,PgSelect120,First124,PgSelectSingle125,Constant126,PgClassExpression127,List128,Lambda129,PgClassExpression130 bucket7 Bucket0 --> Bucket1 diff --git a/postgraphile/postgraphile/__tests__/queries/v4/badlyBehavedFunction.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/badlyBehavedFunction.mermaid index 5a124663c9..8898529be2 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/badlyBehavedFunction.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/badlyBehavedFunction.mermaid @@ -82,7 +82,7 @@ graph TD Bucket3("Bucket 3 (listItem)
Deps: 23

ROOT __Item{3}ᐸ18ᐳ[21]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,__Item21,PgSelectSingle22 bucket3 - Bucket4("Bucket 4 (nullableBoundary)
Deps: 22, 23

ROOT PgSelectSingle{3}ᐸbadly_behaved_functionᐳ[22]"):::bucket + Bucket4("Bucket 4 (nullableBoundary)
Deps: 23, 22

ROOT PgSelectSingle{3}ᐸbadly_behaved_functionᐳ[22]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgClassExpression24,List25,Lambda26,PgClassExpression29 bucket4 Bucket5("Bucket 5 (subroutine)
ROOT PgSelectSingle{5}ᐸbadly_behaved_functionᐳ[33]"):::bucket @@ -91,10 +91,10 @@ graph TD Bucket6("Bucket 6 (listItem)
Deps: 16, 23

ROOT __Item{6}ᐸ31ᐳ[34]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,__Item34,PgSelectSingle35,Edge36,PgCursor37,PgClassExpression38,List39 bucket6 - Bucket7("Bucket 7 (nullableBoundary)
Deps: 36, 35, 23, 37

ROOT Edge{6}[36]"):::bucket + Bucket7("Bucket 7 (nullableBoundary)
Deps: 23, 36, 35, 37

ROOT Edge{6}[36]"):::bucket classDef bucket7 stroke:#808000 class Bucket7 bucket7 - Bucket8("Bucket 8 (nullableBoundary)
Deps: 35, 23

ROOT PgSelectSingle{6}ᐸbadly_behaved_functionᐳ[35]"):::bucket + Bucket8("Bucket 8 (nullableBoundary)
Deps: 23, 35

ROOT PgSelectSingle{6}ᐸbadly_behaved_functionᐳ[35]"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,PgClassExpression41,List42,Lambda43,PgClassExpression46 bucket8 Bucket0 --> Bucket1 diff --git a/postgraphile/postgraphile/__tests__/queries/v4/classic-ids.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/classic-ids.mermaid index a791520d46..b6877c158d 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/classic-ids.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/classic-ids.mermaid @@ -58,7 +58,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 30

ROOT __Item{2}ᐸ27ᐳ[28]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item28,PgSelectSingle29 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 29, 30

ROOT PgSelectSingle{2}ᐸpostᐳ[29]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 30, 29

ROOT PgSelectSingle{2}ᐸpostᐳ[29]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression31,List32,Lambda33,PgClassExpression35 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 25, 51

ROOT Connectionᐸ47ᐳ[51]
1:
ᐳ: Constant[57]
2: PgSelect[52]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/composite_domains.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/composite_domains.mermaid index a9f9250cf3..b61dcc5783 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/composite_domains.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/composite_domains.mermaid @@ -86,7 +86,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 21, 18

ROOT PgSelectSingle{2}ᐸpostsᐳ[22]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 22, 21

ROOT PgSelectSingle{2}ᐸpostsᐳ[22]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression24,PgSelectSingle31,PgClassExpression32,PgClassExpression33,PgClassExpression65,RemapKeys66,Access68 bucket3 Bucket5("Bucket 5 (listItem)
Deps: 18

ROOT __Item{5}ᐸ33ᐳ[36]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/connections-totalCount.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/connections-totalCount.mermaid index 335b6dd524..ce448f555b 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/connections-totalCount.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/connections-totalCount.mermaid @@ -68,7 +68,7 @@ graph TD Bucket3("Bucket 3 (listItem)
Deps: 51

ROOT __Item{3}ᐸ37ᐳ[38]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,__Item38,PgSelectSingle39 bucket3 - Bucket4("Bucket 4 (nullableBoundary)
Deps: 38, 39, 51

ROOT PgSelectSingle{3}ᐸpersonᐳ[39]"):::bucket + Bucket4("Bucket 4 (nullableBoundary)
Deps: 51, 38, 39

ROOT PgSelectSingle{3}ᐸpersonᐳ[39]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,First53,PgSelectSingle54,PgClassExpression55,Access72 bucket4 Bucket5("Bucket 5 (nullableBoundary)
Deps: 18, 67

ROOT Connectionᐸ63ᐳ[67]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/connections.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/connections.mermaid index 8eca90ddb4..aa44e09af5 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/connections.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/connections.mermaid @@ -1455,7 +1455,7 @@ graph TD Bucket67("Bucket 67 (nullableBoundary)
Deps: 996

ROOT PgSelectSingle{66}ᐸpersonᐳ[996]"):::bucket classDef bucket67 stroke:#f5deb3 class Bucket67,PgClassExpression997,PgClassExpression1006 bucket67 - Bucket68("Bucket 68 (nullableBoundary)
Deps: 988, 1009

ROOT PgSelectSingle{65}ᐸpostᐳ[988]"):::bucket + Bucket68("Bucket 68 (nullableBoundary)
Deps: 1009, 988

ROOT PgSelectSingle{65}ᐸpostᐳ[988]"):::bucket classDef bucket68 stroke:#696969 class Bucket68,PgClassExpression1010,List1011,Lambda1012 bucket68 Bucket69("Bucket 69 (nullableBoundary)
Deps: 1037, 18, 33

ROOT Connectionᐸ1033ᐳ[1037]
1:
ᐳ: PgPageInfo[1038], Constant[1170]
2: PgSelect[1039], PgSelect[1053]
ᐳ: 1040, 1041, 1043, 1044, 1046, 1047, 1049, 1050, 1054, 1055, 1056, 1042, 1048"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/function-return-types.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/function-return-types.mermaid index 6bd3372513..35488dcd7f 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/function-return-types.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/function-return-types.mermaid @@ -579,7 +579,7 @@ graph TD Bucket4("Bucket 4 (listItem)
Deps: 80

ROOT __Item{4}ᐸ601ᐳ[78]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,__Item78,PgSelectSingle79 bucket4 - Bucket5("Bucket 5 (nullableBoundary)
Deps: 79, 80

ROOT PgSelectSingle{4}ᐸpostᐳ[79]"):::bucket + Bucket5("Bucket 5 (nullableBoundary)
Deps: 80, 79

ROOT PgSelectSingle{4}ᐸpostᐳ[79]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression81,List82,Lambda83 bucket5 Bucket6("Bucket 6 (nullableBoundary)
Deps: 12, 655, 656, 96, 57, 80

ROOT Connectionᐸ92ᐳ[96]
1: PgSelect[97], PgSelect[149]
ᐳ: 140, 150, 151, 152
2: __ListTransform[98]"):::bucket @@ -591,19 +591,19 @@ graph TD Bucket8("Bucket 8 (listItem)
Deps: 57, 80, 140

ROOT __Item{8}ᐸ98ᐳ[101]"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,__Item101,PgSelectSingle102 bucket8 - Bucket9("Bucket 9 (nullableBoundary)
Deps: 102, 57, 80, 140

ROOT PgSelectSingle{8}ᐸfunc_out_complex_setofᐳ[102]"):::bucket + Bucket9("Bucket 9 (nullableBoundary)
Deps: 57, 80, 140, 102

ROOT PgSelectSingle{8}ᐸfunc_out_complex_setofᐳ[102]"):::bucket classDef bucket9 stroke:#ff0000 class Bucket9,PgClassExpression103,PgSelectSingle110,PgSelectSingle120,RemapKeys604,RemapKeys607 bucket9 Bucket10("Bucket 10 (nullableBoundary)
Deps: 110

ROOT PgSelectSingle{9}ᐸfrmcdc_compoundTypeᐳ[110]"):::bucket classDef bucket10 stroke:#ffff00 class Bucket10,PgClassExpression111,PgClassExpression112,PgClassExpression113 bucket10 - Bucket11("Bucket 11 (nullableBoundary)
Deps: 120, 57, 607, 80, 140

ROOT PgSelectSingle{9}ᐸpersonᐳ[120]"):::bucket + Bucket11("Bucket 11 (nullableBoundary)
Deps: 57, 80, 140, 120, 607

ROOT PgSelectSingle{9}ᐸpersonᐳ[120]"):::bucket classDef bucket11 stroke:#00ffff class Bucket11,PgClassExpression122,List123,Lambda124,PgClassExpression126,Access606 bucket11 Bucket12("Bucket 12 (listItem)
Deps: 80

ROOT __Item{12}ᐸ606ᐳ[142]"):::bucket classDef bucket12 stroke:#4169e1 class Bucket12,__Item142,PgSelectSingle143 bucket12 - Bucket13("Bucket 13 (nullableBoundary)
Deps: 143, 80

ROOT PgSelectSingle{12}ᐸpostᐳ[143]"):::bucket + Bucket13("Bucket 13 (nullableBoundary)
Deps: 80, 143

ROOT PgSelectSingle{12}ᐸpostᐳ[143]"):::bucket classDef bucket13 stroke:#3cb371 class Bucket13,PgClassExpression145,List146,Lambda147 bucket13 Bucket14("Bucket 14 (nullableBoundary)
Deps: 158

ROOT PgSelectSingleᐸfunc_out_outᐳ[158]"):::bucket @@ -651,7 +651,7 @@ graph TD Bucket28("Bucket 28 (listItem)
Deps: 57

ROOT __Item{28}ᐸ253ᐳ[256]"):::bucket classDef bucket28 stroke:#00ffff class Bucket28,__Item256,PgSelectSingle257 bucket28 - Bucket29("Bucket 29 (nullableBoundary)
Deps: 257, 57

ROOT PgSelectSingle{28}ᐸfunc_out_table_setofᐳ[257]"):::bucket + Bucket29("Bucket 29 (nullableBoundary)
Deps: 57, 257

ROOT PgSelectSingle{28}ᐸfunc_out_table_setofᐳ[257]"):::bucket classDef bucket29 stroke:#4169e1 class Bucket29,PgClassExpression259,List260,Lambda261 bucket29 Bucket30("Bucket 30 (nullableBoundary)
Deps: 279

ROOT PgSelectSingleᐸfunc_out_unnamed_out_out_unnamedᐳ[279]"):::bucket @@ -693,7 +693,7 @@ graph TD Bucket42("Bucket 42 (listItem)
Deps: 80

ROOT __Item{42}ᐸ613ᐳ[390]"):::bucket classDef bucket42 stroke:#dda0dd class Bucket42,__Item390,PgSelectSingle391 bucket42 - Bucket43("Bucket 43 (nullableBoundary)
Deps: 391, 80

ROOT PgSelectSingle{42}ᐸpostᐳ[391]"):::bucket + Bucket43("Bucket 43 (nullableBoundary)
Deps: 80, 391

ROOT PgSelectSingle{42}ᐸpostᐳ[391]"):::bucket classDef bucket43 stroke:#ff0000 class Bucket43,PgClassExpression393,List394,Lambda395 bucket43 Bucket44("Bucket 44 (nullableBoundary)
Deps: 403

ROOT PgSelectSingle{38}ᐸperson_computed_first_arg_inoutᐳ[403]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/json-overflow-nested.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/json-overflow-nested.mermaid index d57dad4d90..cfb6fce5ed 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/json-overflow-nested.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/json-overflow-nested.mermaid @@ -360,7 +360,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 37

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 21, 37

ROOT PgSelectSingle{2}ᐸpersonᐳ[22]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 37, 22, 21

ROOT PgSelectSingle{2}ᐸpersonᐳ[22]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,Access454 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ454ᐳ[39]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/large_bigint.issue491.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/large_bigint.issue491.mermaid index 9230ace7a5..97208ce25b 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/large_bigint.issue491.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/large_bigint.issue491.mermaid @@ -85,7 +85,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 23

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 23

ROOT PgSelectSingle{2}ᐸlarge_node_idᐳ[22]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 23, 22

ROOT PgSelectSingle{2}ᐸlarge_node_idᐳ[22]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression24,List25,Lambda26,PgClassExpression28 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 37, 23

ROOT PgSelectSingleᐸlarge_node_idᐳ[37]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/nested_arrays.select.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/nested_arrays.select.mermaid index 3649fddd3a..555893c7a2 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/nested_arrays.select.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/nested_arrays.select.mermaid @@ -58,7 +58,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 18

ROOT PgSelectSingle{2}ᐸtᐳ[22]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 22

ROOT PgSelectSingle{2}ᐸtᐳ[22]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression24 bucket3 Bucket5("Bucket 5 (listItem)
Deps: 18

ROOT __Item{5}ᐸ24ᐳ[27]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/node.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/node.mermaid index 2ea5268072..b5b2206a7d 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/node.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/node.mermaid @@ -2319,7 +2319,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 23

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 23

ROOT PgSelectSingle{2}ᐸpersonᐳ[22]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 23, 22

ROOT PgSelectSingle{2}ᐸpersonᐳ[22]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression24,List25,Lambda26,PgClassExpression28 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 18, 41, 45

ROOT Connectionᐸ37ᐳ[41]"):::bucket @@ -2328,7 +2328,7 @@ graph TD Bucket5("Bucket 5 (listItem)
Deps: 45

ROOT __Item{5}ᐸ42ᐳ[43]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,__Item43,PgSelectSingle44 bucket5 - Bucket6("Bucket 6 (nullableBoundary)
Deps: 44, 45

ROOT PgSelectSingle{5}ᐸcompound_keyᐳ[44]"):::bucket + Bucket6("Bucket 6 (nullableBoundary)
Deps: 45, 44

ROOT PgSelectSingle{5}ᐸcompound_keyᐳ[44]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression46,PgClassExpression47,List48,Lambda49 bucket6 Bucket7("Bucket 7 (polymorphic)
Query,Input,Patch,Reserved,ReservedPatchRecord,ReservedInputRecord,DefaultValue,CompoundKey,Person,Post,Type,PersonSecret,LeftArm,MyTable,ViewTable,SimilarTable1,SimilarTable2,NullTestRecord,Issue756
Deps: 18, 54, 53, 5
ᐳQuery
ᐳInput
ᐳPatch
ᐳReserved
ᐳReservedPatchRecord
ᐳReservedInputRecord
ᐳDefaultValue
ᐳCompoundKey
ᐳPerson
ᐳPost
ᐳType
ᐳPersonSecret
ᐳLeftArm
ᐳMyTable
ᐳViewTable
ᐳSimilarTable1
ᐳSimilarTable2
ᐳNullTestRecord
ᐳIssue756
1:
ᐳ: 56, 66, 78, 90, 102, 114, 126, 139, 154, 168, 180, 192, 204, 216, 228, 240, 256, 272, 284, 2070, 2071, 57
2: 60, 72, 84, 96, 108, 120, 133, 148, 162, 174, 186, 198, 210, 222, 234, 250, 266, 278
ᐳ: 64, 65, 67, 68, 69, 76, 77, 79, 80, 81, 88, 89, 91, 92, 93, 100, 101, 103, 104, 105, 112, 113, 115, 116, 117, 124, 125, 127, 128, 129, 137, 138, 140, 141, 142, 143, 152, 153, 155, 156, 157, 159, 166, 167, 169, 170, 171, 178, 179, 181, 182, 183, 190, 191, 193, 194, 195, 202, 203, 205, 206, 207, 214, 215, 217, 218, 219, 226, 227, 229, 230, 231, 238, 239, 241, 242, 243, 245, 246, 247, 254, 255, 257, 258, 259, 261, 262, 263, 270, 271, 273, 274, 275, 282, 283, 285, 286, 287"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/one-to-one-backward.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/one-to-one-backward.mermaid index b0b14de411..6d499bfb64 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/one-to-one-backward.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/one-to-one-backward.mermaid @@ -92,16 +92,16 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 37, 62

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 37, 62

ROOT PgSelectSingle{2}ᐸpersonᐳ[22]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 37, 62, 22

ROOT PgSelectSingle{2}ᐸpersonᐳ[22]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor23,PgClassExpression24,List25,PgClassExpression27,PgClassExpression29,PgSelectSingle36,PgSelectSingle61,RemapKeys85 bucket3 - Bucket4("Bucket 4 (nullableBoundary)
Deps: 36, 37

ROOT PgSelectSingle{3}ᐸleft_armᐳ[36]"):::bucket + Bucket4("Bucket 4 (nullableBoundary)
Deps: 37, 36

ROOT PgSelectSingle{3}ᐸleft_armᐳ[36]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgClassExpression38,List39,Lambda40,PgClassExpression42,PgSelectSingle49,PgClassExpression54,RemapKeys79 bucket4 Bucket5("Bucket 5 (nullableBoundary)
Deps: 49

ROOT PgSelectSingle{4}ᐸpersonᐳ[49]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,PgClassExpression50,PgClassExpression51,PgClassExpression53 bucket5 - Bucket6("Bucket 6 (nullableBoundary)
Deps: 61, 62

ROOT PgSelectSingle{3}ᐸperson_secretᐳ[61]"):::bucket + Bucket6("Bucket 6 (nullableBoundary)
Deps: 62, 61

ROOT PgSelectSingle{3}ᐸperson_secretᐳ[61]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression63,List64,Lambda65,PgSelectSingle73,PgClassExpression78 bucket6 Bucket7("Bucket 7 (nullableBoundary)
Deps: 73

ROOT PgSelectSingle{6}ᐸpersonᐳ[73]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/orderByNullsLast.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/orderByNullsLast.mermaid index 19213043f3..9cb9358d8f 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/orderByNullsLast.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/orderByNullsLast.mermaid @@ -62,7 +62,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 23

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 23

ROOT PgSelectSingle{2}ᐸsimilar_table_1ᐳ[22]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 23, 22

ROOT PgSelectSingle{2}ᐸsimilar_table_1ᐳ[22]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression24,List25,Lambda26,PgClassExpression27 bucket3 Bucket4("Bucket 4 (nullableBoundary)
Deps: 18, 40, 23

ROOT Connectionᐸ36ᐳ[40]"):::bucket @@ -71,7 +71,7 @@ graph TD Bucket5("Bucket 5 (listItem)
Deps: 23

ROOT __Item{5}ᐸ41ᐳ[42]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,__Item42,PgSelectSingle43 bucket5 - Bucket6("Bucket 6 (nullableBoundary)
Deps: 43, 23

ROOT PgSelectSingle{5}ᐸsimilar_table_1ᐳ[43]"):::bucket + Bucket6("Bucket 6 (nullableBoundary)
Deps: 23, 43

ROOT PgSelectSingle{5}ᐸsimilar_table_1ᐳ[43]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression45,List46,Lambda47,PgClassExpression48 bucket6 Bucket0 --> Bucket1 & Bucket4 diff --git a/postgraphile/postgraphile/__tests__/queries/v4/posts.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/posts.mermaid index c24717d804..fddcf07d3e 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/posts.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/posts.mermaid @@ -117,10 +117,10 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 78, 93

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 78, 93

ROOT PgSelectSingle{2}ᐸpostᐳ[22]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 78, 93, 22

ROOT PgSelectSingle{2}ᐸpostᐳ[22]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgCursor23,PgClassExpression24,List25,PgClassExpression27,PgClassExpression31,PgSelectSingle38,RemapKeys106 bucket3 - Bucket4("Bucket 4 (nullableBoundary)
Deps: 38, 106, 78, 93

ROOT PgSelectSingle{3}ᐸpersonᐳ[38]
1:
ᐳ: 39, 40, 42, 102, 104, 105, 49, 90, 91, 92, 95, 96, 98, 99, 97
2: __ListTransform[80]"):::bucket + Bucket4("Bucket 4 (nullableBoundary)
Deps: 78, 93, 38, 106

ROOT PgSelectSingle{3}ᐸpersonᐳ[38]
1:
ᐳ: 39, 40, 42, 102, 104, 105, 49, 90, 91, 92, 95, 96, 98, 99, 97
2: __ListTransform[80]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgClassExpression39,PgClassExpression40,PgClassExpression42,PgSelectSingle49,__ListTransform80,First90,PgSelectSingle91,PgClassExpression92,First95,PgSelectSingle96,PgCursor97,PgClassExpression98,List99,RemapKeys102,Access104,Access105 bucket4 Bucket5("Bucket 5 (nullableBoundary)
Deps: 49

ROOT PgSelectSingle{4}ᐸperson_first_postᐳ[49]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/procedure-computed-fields.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/procedure-computed-fields.mermaid index 84e7c95bf7..0ba435a1dc 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/procedure-computed-fields.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/procedure-computed-fields.mermaid @@ -304,7 +304,7 @@ graph TD Bucket11("Bucket 11 (listItem)
Deps: 18, 387, 224

ROOT __Item{11}ᐸ116ᐳ[117]"):::bucket classDef bucket11 stroke:#00ffff class Bucket11,__Item117,PgSelectSingle118 bucket11 - Bucket12("Bucket 12 (nullableBoundary)
Deps: 118, 18, 387, 117, 224

ROOT PgSelectSingle{11}ᐸpostᐳ[118]
1:
ᐳ: 119, 123, 127, 131, 135, 139, 143, 159, 203, 206, 360, 362, 364, 153, 155, 183, 184
2: 185, 226, 240"):::bucket + Bucket12("Bucket 12 (nullableBoundary)
Deps: 18, 387, 224, 118, 117

ROOT PgSelectSingle{11}ᐸpostᐳ[118]
1:
ᐳ: 119, 123, 127, 131, 135, 139, 143, 159, 203, 206, 360, 362, 364, 153, 155, 183, 184
2: 185, 226, 240"):::bucket classDef bucket12 stroke:#4169e1 class Bucket12,PgClassExpression119,PgClassExpression123,PgClassExpression127,PgClassExpression131,PgClassExpression135,PgClassExpression139,PgClassExpression143,PgSelectSingle153,PgClassExpression155,PgClassExpression159,PgSelectSingle183,PgClassExpression184,PgSelect185,PgClassExpression203,PgClassExpression206,__ListTransform226,__ListTransform240,RemapKeys360,RemapKeys362,Access364 bucket12 Bucket13("Bucket 13 (listItem)
ROOT __Item{13}ᐸ185ᐳ[189]"):::bucket @@ -352,7 +352,7 @@ graph TD Bucket27("Bucket 27 (listItem)
Deps: 284, 305

ROOT __Item{27}ᐸ267ᐳ[268]"):::bucket classDef bucket27 stroke:#ffff00 class Bucket27,__Item268,PgSelectSingle269 bucket27 - Bucket28("Bucket 28 (nullableBoundary)
Deps: 269, 268, 284, 305

ROOT PgSelectSingle{27}ᐸpersonᐳ[269]
1:
ᐳ: 270, 272, 366, 367, 321
2: __ListTransform[286]"):::bucket + Bucket28("Bucket 28 (nullableBoundary)
Deps: 284, 305, 269, 268

ROOT PgSelectSingle{27}ᐸpersonᐳ[269]
1:
ᐳ: 270, 272, 366, 367, 321
2: __ListTransform[286]"):::bucket classDef bucket28 stroke:#00ffff class Bucket28,PgClassExpression270,PgClassExpression272,__ListTransform286,PgSelectSingle321,Access366,RemapKeys367 bucket28 Bucket29("Bucket 29 (subroutine)
ROOT PgSelectSingle{29}ᐸperson_friendsᐳ[288]"):::bucket @@ -361,7 +361,7 @@ graph TD Bucket30("Bucket 30 (listItem)
Deps: 305

ROOT __Item{30}ᐸ286ᐳ[289]"):::bucket classDef bucket30 stroke:#3cb371 class Bucket30,__Item289,PgSelectSingle290 bucket30 - Bucket31("Bucket 31 (nullableBoundary)
Deps: 290, 289, 305

ROOT PgSelectSingle{30}ᐸperson_friendsᐳ[290]
1:
ᐳ: 291, 293, 365
2: __ListTransform[307]"):::bucket + Bucket31("Bucket 31 (nullableBoundary)
Deps: 305, 290, 289

ROOT PgSelectSingle{30}ᐸperson_friendsᐳ[290]
1:
ᐳ: 291, 293, 365
2: __ListTransform[307]"):::bucket classDef bucket31 stroke:#a52a2a class Bucket31,PgClassExpression291,PgClassExpression293,__ListTransform307,Access365 bucket31 Bucket32("Bucket 32 (subroutine)
ROOT PgSelectSingle{32}ᐸperson_friendsᐳ[309]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/rbac.basic.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/rbac.basic.mermaid index 0a9ffea053..8811de31b7 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/rbac.basic.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/rbac.basic.mermaid @@ -262,7 +262,7 @@ graph TD Bucket3("Bucket 3 (listItem)
Deps: 14

ROOT __Item{3}ᐸ33ᐳ[34]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,__Item34,PgSelectSingle35 bucket3 - Bucket4("Bucket 4 (nullableBoundary)
Deps: 35, 14

ROOT PgSelectSingle{3}ᐸperson_secretᐳ[35]"):::bucket + Bucket4("Bucket 4 (nullableBoundary)
Deps: 14, 35

ROOT PgSelectSingle{3}ᐸperson_secretᐳ[35]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgClassExpression37,List38,Lambda39,PgClassExpression41 bucket4 Bucket5("Bucket 5 (nullableBoundary)
Deps: 48, 49, 14

ROOT PgSelectSingleᐸpersonᐳ[48]"):::bucket @@ -286,7 +286,7 @@ graph TD Bucket11("Bucket 11 (listItem)
Deps: 99

ROOT __Item{11}ᐸ120ᐳ[121]"):::bucket classDef bucket11 stroke:#00ffff class Bucket11,__Item121,PgSelectSingle122 bucket11 - Bucket12("Bucket 12 (nullableBoundary)
Deps: 122, 99

ROOT PgSelectSingle{11}ᐸleft_armᐳ[122]"):::bucket + Bucket12("Bucket 12 (nullableBoundary)
Deps: 99, 122

ROOT PgSelectSingle{11}ᐸleft_armᐳ[122]"):::bucket classDef bucket12 stroke:#4169e1 class Bucket12,PgClassExpression124,List125,Lambda126,PgClassExpression128,PgClassExpression129,PgClassExpression130 bucket12 Bucket13("Bucket 13 (nullableBoundary)
Deps: 137, 49, 99

ROOT PgSelectSingleᐸpersonᐳ[137]"):::bucket @@ -304,7 +304,7 @@ graph TD Bucket17("Bucket 17 (listItem)
Deps: 164

ROOT __Item{17}ᐸ185ᐳ[186]"):::bucket classDef bucket17 stroke:#696969 class Bucket17,__Item186,PgSelectSingle187 bucket17 - Bucket18("Bucket 18 (nullableBoundary)
Deps: 187, 164

ROOT PgSelectSingle{17}ᐸpostᐳ[187]"):::bucket + Bucket18("Bucket 18 (nullableBoundary)
Deps: 164, 187

ROOT PgSelectSingle{17}ᐸpostᐳ[187]"):::bucket classDef bucket18 stroke:#00bfff class Bucket18,PgClassExpression189,List190,Lambda191,PgClassExpression193,PgClassExpression194,PgClassExpression195 bucket18 Bucket19("Bucket 19 (nullableBoundary)
Deps: 202, 49, 201, 164

ROOT PgSelectSingleᐸpersonᐳ[202]"):::bucket @@ -313,7 +313,7 @@ graph TD Bucket20("Bucket 20 (listItem)
Deps: 164

ROOT __Item{20}ᐸ246ᐳ[222]"):::bucket classDef bucket20 stroke:#ffa500 class Bucket20,__Item222,PgSelectSingle223 bucket20 - Bucket21("Bucket 21 (nullableBoundary)
Deps: 223, 164

ROOT PgSelectSingle{20}ᐸpostᐳ[223]"):::bucket + Bucket21("Bucket 21 (nullableBoundary)
Deps: 164, 223

ROOT PgSelectSingle{20}ᐸpostᐳ[223]"):::bucket classDef bucket21 stroke:#0000ff class Bucket21,PgClassExpression225,List226,Lambda227,PgClassExpression229,PgClassExpression230,PgClassExpression231 bucket21 Bucket22("Bucket 22 (nullableBoundary)
Deps: 237

ROOT PgSelectSingleᐸreturn_table_without_grantsᐳ[237]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/relation-head-tail.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/relation-head-tail.mermaid index 93dca5c073..825d3ec202 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/relation-head-tail.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/relation-head-tail.mermaid @@ -115,7 +115,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 38, 64, 83, 102

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 21, 38, 64, 83, 102

ROOT PgSelectSingle{2}ᐸpersonᐳ[22]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 38, 64, 83, 102, 22, 21

ROOT PgSelectSingle{2}ᐸpersonᐳ[22]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgClassExpression24,Access147,Reverse148,Access149,Access150,Access151 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ148ᐳ[40]"):::bucket @@ -148,7 +148,7 @@ graph TD Bucket13("Bucket 13 (listItem)
Deps: 140

ROOT __Item{13}ᐸ121ᐳ[122]"):::bucket classDef bucket13 stroke:#3cb371 class Bucket13,__Item122,PgSelectSingle123 bucket13 - Bucket14("Bucket 14 (nullableBoundary)
Deps: 123, 122, 140

ROOT PgSelectSingle{13}ᐸcompound_keyᐳ[123]"):::bucket + Bucket14("Bucket 14 (nullableBoundary)
Deps: 140, 123, 122

ROOT PgSelectSingle{13}ᐸcompound_keyᐳ[123]"):::bucket classDef bucket14 stroke:#a52a2a class Bucket14,PgClassExpression124,PgClassExpression125,Access152 bucket14 Bucket15("Bucket 15 (listItem)
ROOT __Item{15}ᐸ152ᐳ[142]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/simple-procedure-computed-fields.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/simple-procedure-computed-fields.mermaid index 5ad2599b91..0f3b574888 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/simple-procedure-computed-fields.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/simple-procedure-computed-fields.mermaid @@ -493,7 +493,7 @@ graph TD Bucket3("Bucket 3 (listItem)
Deps: 52

ROOT __Item{3}ᐸ33ᐳ[36]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,__Item36,PgSelectSingle37 bucket3 - Bucket4("Bucket 4 (nullableBoundary)
Deps: 37, 36, 52

ROOT PgSelectSingle{3}ᐸperson_friendsᐳ[37]
1:
ᐳ: 38, 40, 645
2: __ListTransform[54]"):::bucket + Bucket4("Bucket 4 (nullableBoundary)
Deps: 52, 37, 36

ROOT PgSelectSingle{3}ᐸperson_friendsᐳ[37]
1:
ᐳ: 38, 40, 645
2: __ListTransform[54]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgClassExpression38,PgClassExpression40,__ListTransform54,Access645 bucket4 Bucket5("Bucket 5 (subroutine)
ROOT PgSelectSingle{5}ᐸperson_friendsᐳ[56]"):::bucket @@ -508,7 +508,7 @@ graph TD Bucket8("Bucket 8 (listItem)
Deps: 96

ROOT __Item{8}ᐸ650ᐳ[78]"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,__Item78,PgSelectSingle79 bucket8 - Bucket9("Bucket 9 (nullableBoundary)
Deps: 79, 78, 96

ROOT PgSelectSingle{8}ᐸpostᐳ[79]
1:
ᐳ: 80, 84, 85, 647, 648
2: __ListTransform[98]"):::bucket + Bucket9("Bucket 9 (nullableBoundary)
Deps: 96, 79, 78

ROOT PgSelectSingle{8}ᐸpostᐳ[79]
1:
ᐳ: 80, 84, 85, 647, 648
2: __ListTransform[98]"):::bucket classDef bucket9 stroke:#ff0000 class Bucket9,PgClassExpression80,PgClassExpression84,PgClassExpression85,__ListTransform98,Access647,Access648 bucket9 Bucket10("Bucket 10 (subroutine)
ROOT PgClassExpression{10}ᐸ__post_com...al_set__.vᐳ[101]"):::bucket @@ -547,7 +547,7 @@ graph TD Bucket21("Bucket 21 (listItem)
Deps: 205

ROOT __Item{21}ᐸ656ᐳ[187]"):::bucket classDef bucket21 stroke:#0000ff class Bucket21,__Item187,PgSelectSingle188 bucket21 - Bucket22("Bucket 22 (nullableBoundary)
Deps: 188, 187, 205

ROOT PgSelectSingle{21}ᐸpostᐳ[188]
1:
ᐳ: 189, 193, 194, 654, 655
2: __ListTransform[207]"):::bucket + Bucket22("Bucket 22 (nullableBoundary)
Deps: 205, 188, 187

ROOT PgSelectSingle{21}ᐸpostᐳ[188]
1:
ᐳ: 189, 193, 194, 654, 655
2: __ListTransform[207]"):::bucket classDef bucket22 stroke:#7fff00 class Bucket22,PgClassExpression189,PgClassExpression193,PgClassExpression194,__ListTransform207,Access654,Access655 bucket22 Bucket23("Bucket 23 (subroutine)
ROOT PgClassExpression{23}ᐸ__post_com...al_set__.vᐳ[210]"):::bucket @@ -607,13 +607,13 @@ graph TD Bucket41("Bucket 41 (listItem)
Deps: 376, 396, 444, 485, 505, 560, 594, 613

ROOT __Item{41}ᐸ358ᐳ[359]"):::bucket classDef bucket41 stroke:#808000 class Bucket41,__Item359,PgSelectSingle360 bucket41 - Bucket42("Bucket 42 (nullableBoundary)
Deps: 360, 359, 376, 396, 444, 485, 505, 560, 594, 613

ROOT PgSelectSingle{41}ᐸpersonᐳ[360]"):::bucket + Bucket42("Bucket 42 (nullableBoundary)
Deps: 376, 396, 444, 485, 505, 560, 594, 613, 360, 359

ROOT PgSelectSingle{41}ᐸpersonᐳ[360]"):::bucket classDef bucket42 stroke:#dda0dd class Bucket42,PgClassExpression361,PgClassExpression362,Access666,Reverse667,Access670,Access673,Access676,Access677,Access678,Access679,Access680 bucket42 Bucket43("Bucket 43 (listItem)
Deps: 396

ROOT __Item{43}ᐸ667ᐳ[378]"):::bucket classDef bucket43 stroke:#ff0000 class Bucket43,__Item378,PgSelectSingle379 bucket43 - Bucket44("Bucket 44 (nullableBoundary)
Deps: 379, 378, 396

ROOT PgSelectSingle{43}ᐸpostᐳ[379]
1:
ᐳ: 380, 384, 385, 664, 665
2: __ListTransform[398]"):::bucket + Bucket44("Bucket 44 (nullableBoundary)
Deps: 396, 379, 378

ROOT PgSelectSingle{43}ᐸpostᐳ[379]
1:
ᐳ: 380, 384, 385, 664, 665
2: __ListTransform[398]"):::bucket classDef bucket44 stroke:#ffff00 class Bucket44,PgClassExpression380,PgClassExpression384,PgClassExpression385,__ListTransform398,Access664,Access665 bucket44 Bucket45("Bucket 45 (subroutine)
ROOT PgClassExpression{45}ᐸ__post_com...al_set__.vᐳ[401]"):::bucket @@ -652,7 +652,7 @@ graph TD Bucket56("Bucket 56 (listItem)
Deps: 505

ROOT __Item{56}ᐸ673ᐳ[487]"):::bucket classDef bucket56 stroke:#7fff00 class Bucket56,__Item487,PgSelectSingle488 bucket56 - Bucket57("Bucket 57 (nullableBoundary)
Deps: 488, 487, 505

ROOT PgSelectSingle{56}ᐸpostᐳ[488]
1:
ᐳ: 489, 493, 494, 671, 672
2: __ListTransform[507]"):::bucket + Bucket57("Bucket 57 (nullableBoundary)
Deps: 505, 488, 487

ROOT PgSelectSingle{56}ᐸpostᐳ[488]
1:
ᐳ: 489, 493, 494, 671, 672
2: __ListTransform[507]"):::bucket classDef bucket57 stroke:#ff1493 class Bucket57,PgClassExpression489,PgClassExpression493,PgClassExpression494,__ListTransform507,Access671,Access672 bucket57 Bucket58("Bucket 58 (subroutine)
ROOT PgClassExpression{58}ᐸ__post_com...al_set__.vᐳ[510]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/smart_comment_relations.houses.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/smart_comment_relations.houses.mermaid index 877e34d2eb..d693c08362 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/smart_comment_relations.houses.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/smart_comment_relations.houses.mermaid @@ -333,76 +333,76 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 23, 41, 64, 128, 60, 111, 161, 211, 258, 308

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 23, 41, 64, 128, 60, 111, 161, 211, 258, 308

ROOT PgSelectSingle{2}ᐸhousesᐳ[22]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 23, 41, 64, 128, 60, 111, 161, 211, 258, 308, 22

ROOT PgSelectSingle{2}ᐸhousesᐳ[22]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression24,PgClassExpression25,List26,Lambda27,PgClassExpression28,PgClassExpression29,PgClassExpression30,PgClassExpression32,PgSelectSingle40,PgSelectSingle76,PgSelectSingle177,PgSelectSingle228,RemapKeys363,RemapKeys368,RemapKeys378 bucket3 - Bucket4("Bucket 4 (nullableBoundary)
Deps: 40, 41, 22, 64, 60

ROOT PgSelectSingle{3}ᐸstreetsᐳ[40]"):::bucket + Bucket4("Bucket 4 (nullableBoundary)
Deps: 41, 64, 60, 40, 22

ROOT PgSelectSingle{3}ᐸstreetsᐳ[40]"):::bucket classDef bucket4 stroke:#0000ff class Bucket4,PgClassExpression42,List43,Lambda44,PgClassExpression46,Access352 bucket4 Bucket5("Bucket 5 (listItem)
Deps: 64

ROOT __Item{5}ᐸ352ᐳ[62]"):::bucket classDef bucket5 stroke:#7fff00 class Bucket5,__Item62,PgSelectSingle63 bucket5 - Bucket6("Bucket 6 (nullableBoundary)
Deps: 63, 64

ROOT PgSelectSingle{5}ᐸbuildingsᐳ[63]"):::bucket + Bucket6("Bucket 6 (nullableBoundary)
Deps: 64, 63

ROOT PgSelectSingle{5}ᐸbuildingsᐳ[63]"):::bucket classDef bucket6 stroke:#ff1493 class Bucket6,PgClassExpression65,List66,Lambda67,PgClassExpression69 bucket6 - Bucket7("Bucket 7 (nullableBoundary)
Deps: 76, 64, 41, 128, 111, 161

ROOT PgSelectSingle{3}ᐸbuildingsᐳ[76]"):::bucket + Bucket7("Bucket 7 (nullableBoundary)
Deps: 64, 41, 128, 111, 161, 76

ROOT PgSelectSingle{3}ᐸbuildingsᐳ[76]"):::bucket classDef bucket7 stroke:#808000 class Bucket7,PgClassExpression78,List79,Lambda80,PgClassExpression82,PgClassExpression83,PgClassExpression84,PgSelectSingle91,PgSelectSingle127,RemapKeys371,RemapKeys376 bucket7 - Bucket8("Bucket 8 (nullableBoundary)
Deps: 91, 41, 371, 64, 111

ROOT PgSelectSingle{7}ᐸstreetsᐳ[91]"):::bucket + Bucket8("Bucket 8 (nullableBoundary)
Deps: 41, 64, 111, 91, 371

ROOT PgSelectSingle{7}ᐸstreetsᐳ[91]"):::bucket classDef bucket8 stroke:#dda0dd class Bucket8,PgClassExpression93,List94,Lambda95,PgClassExpression97,Access370 bucket8 Bucket9("Bucket 9 (listItem)
Deps: 64

ROOT __Item{9}ᐸ370ᐳ[113]"):::bucket classDef bucket9 stroke:#ff0000 class Bucket9,__Item113,PgSelectSingle114 bucket9 - Bucket10("Bucket 10 (nullableBoundary)
Deps: 114, 64

ROOT PgSelectSingle{9}ᐸbuildingsᐳ[114]"):::bucket + Bucket10("Bucket 10 (nullableBoundary)
Deps: 64, 114

ROOT PgSelectSingle{9}ᐸbuildingsᐳ[114]"):::bucket classDef bucket10 stroke:#ffff00 class Bucket10,PgClassExpression116,List117,Lambda118,PgClassExpression120 bucket10 - Bucket11("Bucket 11 (nullableBoundary)
Deps: 127, 128, 41, 64, 161

ROOT PgSelectSingle{7}ᐸpropertiesᐳ[127]"):::bucket + Bucket11("Bucket 11 (nullableBoundary)
Deps: 128, 41, 64, 161, 127

ROOT PgSelectSingle{7}ᐸpropertiesᐳ[127]"):::bucket classDef bucket11 stroke:#00ffff class Bucket11,PgClassExpression129,List130,Lambda131,PgClassExpression133,PgClassExpression134,PgSelectSingle141,RemapKeys374 bucket11 - Bucket12("Bucket 12 (nullableBoundary)
Deps: 141, 41, 374, 64, 161

ROOT PgSelectSingle{11}ᐸstreetsᐳ[141]"):::bucket + Bucket12("Bucket 12 (nullableBoundary)
Deps: 41, 64, 161, 141, 374

ROOT PgSelectSingle{11}ᐸstreetsᐳ[141]"):::bucket classDef bucket12 stroke:#4169e1 class Bucket12,PgClassExpression143,List144,Lambda145,PgClassExpression147,Access373 bucket12 Bucket13("Bucket 13 (listItem)
Deps: 64

ROOT __Item{13}ᐸ373ᐳ[163]"):::bucket classDef bucket13 stroke:#3cb371 class Bucket13,__Item163,PgSelectSingle164 bucket13 - Bucket14("Bucket 14 (nullableBoundary)
Deps: 164, 64

ROOT PgSelectSingle{13}ᐸbuildingsᐳ[164]"):::bucket + Bucket14("Bucket 14 (nullableBoundary)
Deps: 64, 164

ROOT PgSelectSingle{13}ᐸbuildingsᐳ[164]"):::bucket classDef bucket14 stroke:#a52a2a class Bucket14,PgClassExpression166,List167,Lambda168,PgClassExpression170 bucket14 - Bucket15("Bucket 15 (nullableBoundary)
Deps: 177, 128, 41, 64, 211

ROOT PgSelectSingle{3}ᐸpropertiesᐳ[177]"):::bucket + Bucket15("Bucket 15 (nullableBoundary)
Deps: 128, 41, 64, 211, 177

ROOT PgSelectSingle{3}ᐸpropertiesᐳ[177]"):::bucket classDef bucket15 stroke:#ff00ff class Bucket15,PgClassExpression179,List180,Lambda181,PgClassExpression183,PgClassExpression184,PgSelectSingle191,RemapKeys366 bucket15 - Bucket16("Bucket 16 (nullableBoundary)
Deps: 191, 41, 366, 64, 211

ROOT PgSelectSingle{15}ᐸstreetsᐳ[191]"):::bucket + Bucket16("Bucket 16 (nullableBoundary)
Deps: 41, 64, 211, 191, 366

ROOT PgSelectSingle{15}ᐸstreetsᐳ[191]"):::bucket classDef bucket16 stroke:#f5deb3 class Bucket16,PgClassExpression193,List194,Lambda195,PgClassExpression197,Access365 bucket16 Bucket17("Bucket 17 (listItem)
Deps: 64

ROOT __Item{17}ᐸ365ᐳ[213]"):::bucket classDef bucket17 stroke:#696969 class Bucket17,__Item213,PgSelectSingle214 bucket17 - Bucket18("Bucket 18 (nullableBoundary)
Deps: 214, 64

ROOT PgSelectSingle{17}ᐸbuildingsᐳ[214]"):::bucket + Bucket18("Bucket 18 (nullableBoundary)
Deps: 64, 214

ROOT PgSelectSingle{17}ᐸbuildingsᐳ[214]"):::bucket classDef bucket18 stroke:#00bfff class Bucket18,PgClassExpression216,List217,Lambda218,PgClassExpression220 bucket18 - Bucket19("Bucket 19 (nullableBoundary)
Deps: 228, 41, 64, 128, 258, 308

ROOT PgSelectSingle{3}ᐸstreet_propertyᐳ[228]"):::bucket + Bucket19("Bucket 19 (nullableBoundary)
Deps: 41, 64, 128, 258, 308, 228

ROOT PgSelectSingle{3}ᐸstreet_propertyᐳ[228]"):::bucket classDef bucket19 stroke:#7f007f class Bucket19,PgClassExpression229,PgClassExpression230,PgClassExpression231,PgSelectSingle238,PgSelectSingle274,RemapKeys361 bucket19 - Bucket20("Bucket 20 (nullableBoundary)
Deps: 238, 41, 228, 64, 258

ROOT PgSelectSingle{19}ᐸstreetsᐳ[238]"):::bucket + Bucket20("Bucket 20 (nullableBoundary)
Deps: 41, 64, 258, 238, 228

ROOT PgSelectSingle{19}ᐸstreetsᐳ[238]"):::bucket classDef bucket20 stroke:#ffa500 class Bucket20,PgClassExpression240,List241,Lambda242,PgClassExpression244,Access355 bucket20 Bucket21("Bucket 21 (listItem)
Deps: 64

ROOT __Item{21}ᐸ355ᐳ[260]"):::bucket classDef bucket21 stroke:#0000ff class Bucket21,__Item260,PgSelectSingle261 bucket21 - Bucket22("Bucket 22 (nullableBoundary)
Deps: 261, 64

ROOT PgSelectSingle{21}ᐸbuildingsᐳ[261]"):::bucket + Bucket22("Bucket 22 (nullableBoundary)
Deps: 64, 261

ROOT PgSelectSingle{21}ᐸbuildingsᐳ[261]"):::bucket classDef bucket22 stroke:#7fff00 class Bucket22,PgClassExpression263,List264,Lambda265,PgClassExpression267 bucket22 - Bucket23("Bucket 23 (nullableBoundary)
Deps: 274, 128, 41, 64, 308

ROOT PgSelectSingle{19}ᐸpropertiesᐳ[274]"):::bucket + Bucket23("Bucket 23 (nullableBoundary)
Deps: 128, 41, 64, 308, 274

ROOT PgSelectSingle{19}ᐸpropertiesᐳ[274]"):::bucket classDef bucket23 stroke:#ff1493 class Bucket23,PgClassExpression276,List277,Lambda278,PgClassExpression280,PgClassExpression281,PgSelectSingle288,RemapKeys359 bucket23 - Bucket24("Bucket 24 (nullableBoundary)
Deps: 288, 41, 359, 64, 308

ROOT PgSelectSingle{23}ᐸstreetsᐳ[288]"):::bucket + Bucket24("Bucket 24 (nullableBoundary)
Deps: 41, 64, 308, 288, 359

ROOT PgSelectSingle{23}ᐸstreetsᐳ[288]"):::bucket classDef bucket24 stroke:#808000 class Bucket24,PgClassExpression290,List291,Lambda292,PgClassExpression294,Access358 bucket24 Bucket25("Bucket 25 (listItem)
Deps: 64

ROOT __Item{25}ᐸ358ᐳ[310]"):::bucket classDef bucket25 stroke:#dda0dd class Bucket25,__Item310,PgSelectSingle311 bucket25 - Bucket26("Bucket 26 (nullableBoundary)
Deps: 311, 64

ROOT PgSelectSingle{25}ᐸbuildingsᐳ[311]"):::bucket + Bucket26("Bucket 26 (nullableBoundary)
Deps: 64, 311

ROOT PgSelectSingle{25}ᐸbuildingsᐳ[311]"):::bucket classDef bucket26 stroke:#ff0000 class Bucket26,PgClassExpression313,List314,Lambda315,PgClassExpression317 bucket26 Bucket27("Bucket 27 (nullableBoundary)
Deps: 325, 23

ROOT PgSelectSingleᐸhousesᐳ[325]"):::bucket diff --git a/postgraphile/postgraphile/__tests__/queries/v4/streamLoads.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/streamLoads.mermaid index 5b31e94d63..3dbaec5caa 100644 --- a/postgraphile/postgraphile/__tests__/queries/v4/streamLoads.mermaid +++ b/postgraphile/postgraphile/__tests__/queries/v4/streamLoads.mermaid @@ -52,7 +52,7 @@ graph TD Bucket2("Bucket 2 (listItem)
Deps: 18

ROOT __Item{2}ᐸ20ᐳ[21]"):::bucket classDef bucket2 stroke:#7f007f class Bucket2,__Item21,PgSelectSingle22 bucket2 - Bucket3("Bucket 3 (nullableBoundary)
Deps: 22, 18

ROOT PgSelectSingle{2}ᐸpersonᐳ[22]
1:
ᐳ: PgClassExpression[23]
2: PgSelect[29]"):::bucket + Bucket3("Bucket 3 (nullableBoundary)
Deps: 18, 22

ROOT PgSelectSingle{2}ᐸpersonᐳ[22]
1:
ᐳ: PgClassExpression[23]
2: PgSelect[29]"):::bucket classDef bucket3 stroke:#ffa500 class Bucket3,PgClassExpression23,PgSelect29 bucket3 Bucket4("Bucket 4 (listItem)
ROOT __Item{4}ᐸ29ᐳ[33]"):::bucket From a842b4c040c980857707cfbc8c3ac25bbacaeaf5 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 27 Feb 2024 10:14:05 +0000 Subject: [PATCH 20/48] Remove unused variables --- grafast/grafast/src/prepare.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grafast/grafast/src/prepare.ts b/grafast/grafast/src/prepare.ts index 76de312011..8471e095a0 100644 --- a/grafast/grafast/src/prepare.ts +++ b/grafast/grafast/src/prepare.ts @@ -340,7 +340,7 @@ function executePreemptive( index: number, ): PromiseOrDirect> { const layerPlan = subscriptionLayerPlan!; - const { copyUnaryStepIds, copyBatchStepIds, rootStep } = layerPlan; + const { rootStep } = layerPlan; // PERF: we could consider batching this. const store: Bucket["store"] = new Map(); const unaryStore = new Map(); From 45f609920e493da1cfdfe3d27897d6bd1bdc7915 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 27 Feb 2024 10:57:05 +0000 Subject: [PATCH 21/48] Unaries isn't a record, it's a list the same length as values --- grafast/grafast/src/interfaces.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grafast/grafast/src/interfaces.ts b/grafast/grafast/src/interfaces.ts index 23b522cea0..48b094397e 100644 --- a/grafast/grafast/src/interfaces.ts +++ b/grafast/grafast/src/interfaces.ts @@ -773,7 +773,7 @@ export interface ExecutionExtraBase { } export interface ExecutionExtra extends ExecutionExtraBase { /** The results for the unary dependencies the step used */ - unaries: Record; + unaries: any[]; } export interface UnbatchedExecutionExtra extends ExecutionExtraBase {} From f3bcd13c9105b9561aa00da1f302d2542ac32832 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 27 Feb 2024 12:01:50 +0000 Subject: [PATCH 22/48] Change executeV2 to have a single object argument --- grafast/grafast/src/engine/executeBucket.ts | 58 +++++++++++++-------- grafast/grafast/src/index.ts | 2 + grafast/grafast/src/interfaces.ts | 20 +++++-- grafast/grafast/src/step.ts | 24 ++++----- 4 files changed, 64 insertions(+), 40 deletions(-) diff --git a/grafast/grafast/src/engine/executeBucket.ts b/grafast/grafast/src/engine/executeBucket.ts index 3a49bc8ba6..7abac4f1bf 100644 --- a/grafast/grafast/src/engine/executeBucket.ts +++ b/grafast/grafast/src/engine/executeBucket.ts @@ -666,31 +666,34 @@ export function executeBucket( // Function definitions below here function executeOrStream( - size: number, + count: number, step: ExecutableStep, - dependencies: Array | null>, + values: Array | null>, + unaries: Array, extra: ExecutionExtra, ): PromiseOrDirect | GrafastResultStreamList> { - if (isDev && step._isUnary && size !== 1) { + if (isDev && step._isUnary && count !== 1) { throw new Error( - `GrafastInternalError<84a6cdfa-e8fe-4dea-85fe-9426a6a78027>: ${step} is a unary step, but we're attempting to pass it ${size} (!= 1) values`, + `GrafastInternalError<84a6cdfa-e8fe-4dea-85fe-9426a6a78027>: ${step} is a unary step, but we're attempting to pass it ${count} (!= 1) values`, ); } - if (step._stepOptions.stream && isStreamV2ableStep(step)) { - return step.streamV2(size, dependencies, extra, step._stepOptions.stream); - } else if (step._stepOptions.stream && isStreamableStep(step)) { - // Backwards compatibility - const backfilledValues = dependencies.map((v, i) => - v === null ? arrayOfLength(size, extra.unaries[i]) : v, - ); - return step.stream( - size, - backfilledValues, + const streamOptions = step._stepOptions.stream; + if (streamOptions && isStreamV2ableStep(step)) { + return step.streamV2({ + count, + values, + unaries, extra, - step._stepOptions.stream, + streamOptions, + }); + } else if (streamOptions && isStreamableStep(step)) { + // Backwards compatibility + const backfilledValues = values.map((v, i) => + v === null ? arrayOfLength(count, unaries[i]) : v, ); + return step.stream(count, backfilledValues, extra, streamOptions); } else { - return step.executeV2(size, dependencies, extra); + return step.executeV2({ count, values, unaries, extra }); } } @@ -703,6 +706,7 @@ export function executeBucket( function reallyExecuteStepWithErrorsOrSelective( step: ExecutableStep, dependenciesIncludingSideEffects: Array | null>, + unariesIncludingSideEffects: Array, polymorphicPathList: readonly (string | null)[], extra: ExecutionExtra, ): PromiseOrDirect | GrafastResultStreamList> { @@ -722,7 +726,7 @@ export function executeBucket( : dependenciesIncludingSideEffects ) as (any[] | null)[]; - // OPTIM: if extra.unaries.some(isGrafastError) then shortcut execution because everything fails + // OPTIM: if unariesIncludingSideEffects.some(isGrafastError) then shortcut execution because everything fails // for (let index = 0, l = polymorphicPathList.length; index < l; index++) { for (let index = 0; index < size; index++) { @@ -757,7 +761,7 @@ export function executeBucket( i++ ) { const depList = dependenciesIncludingSideEffects[i]; - const v = depList ? depList[index] : extra.unaries[i]; + const v = depList ? depList[index] : unariesIncludingSideEffects[i]; if (isGrafastError(v)) { indexError = v; break; @@ -796,9 +800,9 @@ export function executeBucket( } // Trim the side-effect dependencies back out again - if (sideEffectStepsWithErrors) { - extra.unaries = extra.unaries.slice(0, legitDepsCount); - } + const unaries = sideEffectStepsWithErrors + ? unariesIncludingSideEffects.slice(0, legitDepsCount) + : unariesIncludingSideEffects; if (newSize === 0) { // Everything is errors; we can skip execution @@ -808,6 +812,7 @@ export function executeBucket( newSize, step, dependencies, + unaries, extra, ); if (isPromiseLike(resultWithoutErrors)) { @@ -818,7 +823,13 @@ export function executeBucket( return mergeErrorsBackIn(resultWithoutErrors, errors, size); } } else { - return reallyExecuteStepWithNoErrors(newSize, step, dependencies, extra); + return reallyExecuteStepWithNoErrors( + newSize, + step, + dependencies, + unaries, + extra, + ); } } @@ -833,7 +844,6 @@ export function executeBucket( step.metaKey !== undefined ? metaByMetaKey[step.metaKey] : undefined; const unaries: Array = []; const extra: ExecutionExtra = { - unaries, stopTime, meta, eventEmitter, @@ -914,6 +924,7 @@ export function executeBucket( ? reallyExecuteStepWithErrorsOrSelective( step, dependencies, + unaries, bucket.polymorphicPathList, extra, ) @@ -921,6 +932,7 @@ export function executeBucket( step._isUnary ? 1 : size, step, dependencies, + unaries, extra, ); if (isPromiseLike(result)) { diff --git a/grafast/grafast/src/index.ts b/grafast/grafast/src/index.ts index cf766adf29..5a10d40d61 100644 --- a/grafast/grafast/src/index.ts +++ b/grafast/grafast/src/index.ts @@ -66,6 +66,7 @@ import { EnumValueApplyPlanResolver, EventCallback, EventMapKey, + ExecutionDetails, ExecutionEventEmitter, ExecutionEventMap, ExecutionExtra, @@ -291,6 +292,7 @@ export { EventMapKey, ExecutableStep, execute, + ExecutionDetails, ExecutionEventEmitter, ExecutionEventMap, ExecutionExtra, diff --git a/grafast/grafast/src/interfaces.ts b/grafast/grafast/src/interfaces.ts index 48b094397e..6238831897 100644 --- a/grafast/grafast/src/interfaces.ts +++ b/grafast/grafast/src/interfaces.ts @@ -771,12 +771,24 @@ export interface ExecutionExtraBase { /** @internal */ _requestContext: RequestTools; } -export interface ExecutionExtra extends ExecutionExtraBase { - /** The results for the unary dependencies the step used */ - unaries: any[]; -} +export interface ExecutionExtra extends ExecutionExtraBase {} export interface UnbatchedExecutionExtra extends ExecutionExtraBase {} +export interface ExecutionDetails { + count: number; + values: { + [DepIdx in keyof TDeps]: ReadonlyArray | null; + } & { length: TDeps["length"] }; + unaries: { + [DepIdx in keyof TDeps]: null | TDeps[DepIdx]; + } & { length: TDeps["length"] }; + extra: ExecutionExtra; +} +export interface StreamDetails + extends ExecutionDetails { + streamOptions: StepStreamOptions; +} + export interface LocationDetails { node: ASTNode | readonly ASTNode[]; /** This should only be null for the root selection */ diff --git a/grafast/grafast/src/step.ts b/grafast/grafast/src/step.ts index a9b4adcede..a923c849c9 100644 --- a/grafast/grafast/src/step.ts +++ b/grafast/grafast/src/step.ts @@ -18,6 +18,7 @@ import type { OperationPlan } from "./engine/OperationPlan.js"; import { getDebug } from "./global.js"; import { inspect } from "./inspect.js"; import type { + ExecutionDetails, ExecutionExtra, GrafastResultsList, GrafastResultStreamList, @@ -26,6 +27,7 @@ import type { PromiseOrDirect, StepOptimizeOptions, StepOptions, + StreamDetails, UnbatchedExecutionExtra, } from "./interfaces.js"; import { $$subroutine } from "./interfaces.js"; @@ -389,7 +391,7 @@ export /* abstract */ class ExecutableStep extends BaseStep { * be able to access the value via `extra.unaries[key]` where `key` is the * return value of this function. */ - protected addUnaryDependency(step: ExecutableStep): string | number { + protected addUnaryDependency(step: ExecutableStep): number { return this.operationPlan.stepTracker.addStepUnaryDependency(this, step); } @@ -481,13 +483,14 @@ export /* abstract */ class ExecutableStep extends BaseStep { // This executeV2 method implements backwards compatibility with the old // execute method; you should instead override this in your own step // classes. - executeV2( - count: number, - values: ReadonlyArray | null>, - extra: ExecutionExtra, - ): PromiseOrDirect> { + executeV2({ + count, + values, + unaries, + extra, + }: ExecutionDetails): PromiseOrDirect> { const backfilledValues = values.map((v, i) => - v === null ? arrayOfLength(count, extra.unaries[i]) : v, + v === null ? arrayOfLength(count, unaries[i]) : v, ); return this.execute(count, backfilledValues, extra); } @@ -713,12 +716,7 @@ export type StreamableStep = ExecutableStep> & { }; export type StreamV2ableStep = ExecutableStep> & { streamV2( - count: number, - values: ReadonlyArray | null>, - extra: ExecutionExtra, - streamOptions: { - initialCount: number; - }, + details: StreamDetails, ): PromiseOrDirect>; }; From 46eb1aa2cda4a23a3796b6018ad5d8c1f9732542 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 27 Feb 2024 12:08:04 +0000 Subject: [PATCH 23/48] New format of executeV2 --- .../grafast/__tests__/errorHandling-test.ts | 15 +++++++++++--- .../errorHandlingStreamTermination-test.ts | 15 +++++++++++--- grafast/grafast/__tests__/stream-test.ts | 19 +++++++++++++++--- grafast/grafast/__tests__/unaryDeps-test.ts | 20 +++++++++---------- grafast/grafast/src/step.ts | 1 + 5 files changed, 51 insertions(+), 19 deletions(-) diff --git a/grafast/grafast/__tests__/errorHandling-test.ts b/grafast/grafast/__tests__/errorHandling-test.ts index e5ceeca678..eb7a4e816c 100644 --- a/grafast/grafast/__tests__/errorHandling-test.ts +++ b/grafast/grafast/__tests__/errorHandling-test.ts @@ -3,7 +3,7 @@ import { expect } from "chai"; import type { AsyncExecutionResult } from "graphql"; import { it } from "mocha"; -import type { PromiseOrDirect } from "../dist/index.js"; +import type { ExecutionDetails, PromiseOrDirect } from "../dist/index.js"; import { constant, ExecutableStep, @@ -26,8 +26,17 @@ class SyncListCallbackStep< super(); this.addDependency($dep); } - execute(_count: number, [val]: [Array]): Array> { - return val.map((entry) => this.callback(entry)); + executeV2({ + count, + values: [values0], + unaries: [unaries0], + }: ExecutionDetails<[TIn]>): Array> { + let result: PromiseOrDirect[] = []; + for (let i = 0; i < count; i++) { + const entry = values0 !== null ? values0[i] : unaries0!; + result.push(this.callback(entry)); + } + return result; } async stream(_count: number, [val]: [Array]) { await sleep(0); diff --git a/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts b/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts index a22bbb94a0..a1104438d7 100644 --- a/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts +++ b/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts @@ -3,7 +3,7 @@ import { expect } from "chai"; import type { AsyncExecutionResult } from "graphql"; import { it } from "mocha"; -import type { PromiseOrDirect } from "../dist/index.js"; +import type { ExecutionDetails, PromiseOrDirect } from "../dist/index.js"; import { constant, ExecutableStep, @@ -28,8 +28,17 @@ class SyncListCallbackStep< super(); this.addDependency($dep); } - execute(_count: number, [val]: [Array]): Array> { - return val.map((entry) => this.callback(entry)); + executeV2({ + count, + values: [values0], + unaries: [unary0], + }: ExecutionDetails<[TIn]>): Array> { + let result: PromiseOrDirect[] = []; + for (let i = 0; i < count; i++) { + const entry = values0 !== null ? values0[i] : unary0!; + result.push(this.callback(entry)); + } + return result; } async stream(_count: number, [val]: [Array]) { await sleep(0); diff --git a/grafast/grafast/__tests__/stream-test.ts b/grafast/grafast/__tests__/stream-test.ts index 630711c5a5..d720490157 100644 --- a/grafast/grafast/__tests__/stream-test.ts +++ b/grafast/grafast/__tests__/stream-test.ts @@ -3,7 +3,11 @@ import { expect } from "chai"; import type { AsyncExecutionResult } from "graphql"; import { it } from "mocha"; -import type { PromiseOrDirect } from "../dist/index.js"; +import type { + ExecutionDetails, + ExecutionExtra, + PromiseOrDirect, +} from "../dist/index.js"; import { constant, ExecutableStep, @@ -24,8 +28,17 @@ class SyncListCallbackStep< super(); this.addDependency($dep); } - execute(_count: number, [val]: [Array]): Array> { - return val.map((entry) => this.callback(entry)); + executeV2({ + count, + values: [values0], + unaries: [unary0], + }: ExecutionDetails<[TIn]>): Array> { + let result: PromiseOrDirect[] = []; + for (let i = 0; i < count; i++) { + const entry = values0 !== null ? values0[i] : unary0!; + result.push(this.callback(entry)); + } + return result; } stream(_count: number, [val]: [Array]) { const { callback } = this; diff --git a/grafast/grafast/__tests__/unaryDeps-test.ts b/grafast/grafast/__tests__/unaryDeps-test.ts index feb5235853..405154e754 100644 --- a/grafast/grafast/__tests__/unaryDeps-test.ts +++ b/grafast/grafast/__tests__/unaryDeps-test.ts @@ -5,6 +5,7 @@ import { it } from "mocha"; import sqlite3 from "sqlite3"; import type { + ExecutionDetails, ExecutionExtra, GrafastResultsList, GrafastValuesList, @@ -82,13 +83,13 @@ class GetRecordsStep> extends ExecutableStep { this.firstUDI = this.addUnaryDependency($first); } - async executeV2( - count: number, - values: GrafastValuesList, - extra: ExecutionExtra, - ): Promise> { - const db = extra.unaries[this.dbDepId] as sqlite3.Database; - const first = this.firstUDI != null ? extra.unaries[this.firstUDI] : null; + async executeV2({ + count, + values, + unaries, + }: ExecutionDetails): Promise> { + const db = unaries[this.dbDepId] as sqlite3.Database; + const first = this.firstUDI != null ? unaries[this.firstUDI] : null; const identifierCols = Object.keys(this.depIdByIdentifier); @@ -137,7 +138,7 @@ ${orderBy ? `order by ${orderBy}` : ""} const obj = Object.fromEntries( Object.entries(this.depIdByIdentifier).map(([col, depId]) => [ col, - values[depId] ? values[depId][i] : extra.unaries[depId], + values[depId] ? values[depId][i] : unaries[depId], ]), ); json.push(obj); @@ -152,8 +153,7 @@ ${orderBy ? `order by ${orderBy}` : ""} results[i] = dbResults.filter((r) => { return entries.every( ([col, depId]) => - r[col] === - (values[depId] ? values[depId][i] : extra.unaries[depId]), + r[col] === (values[depId] ? values[depId][i] : unaries[depId]), ); }); } diff --git a/grafast/grafast/src/step.ts b/grafast/grafast/src/step.ts index a923c849c9..37a916bc6e 100644 --- a/grafast/grafast/src/step.ts +++ b/grafast/grafast/src/step.ts @@ -489,6 +489,7 @@ export /* abstract */ class ExecutableStep extends BaseStep { unaries, extra, }: ExecutionDetails): PromiseOrDirect> { + // TODO: warn that this class should implement executeV2 instead const backfilledValues = values.map((v, i) => v === null ? arrayOfLength(count, unaries[i]) : v, ); From 002bcc36bb1eaf7e1e401a2fb6c8e5f853708ded Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 27 Feb 2024 13:53:12 +0000 Subject: [PATCH 24/48] Convert various steps to use executeV2 --- grafast/dataplan-json/src/steps/jsonParse.ts | 13 ++-- grafast/dataplan-pg/src/steps/pgPageInfo.ts | 3 +- .../src/steps/pgSingleTablePolymorphic.ts | 15 ++-- grafast/dataplan-pg/src/steps/pgUnionAll.ts | 23 +++--- .../src/steps/pgValidateParsedCursor.ts | 78 +++++++++++-------- grafast/dataplan-pg/src/steps/withPgClient.ts | 40 ++++++---- grafast/grafast/__tests__/forbidden-test.ts | 6 +- grafast/grafast/src/interfaces.ts | 2 +- grafast/grafast/src/step.ts | 62 ++++++++++----- grafast/grafast/src/steps/__inputList.ts | 2 +- grafast/grafast/src/steps/__item.ts | 2 +- grafast/grafast/src/steps/__trackedValue.ts | 14 ++-- grafast/grafast/src/steps/__value.ts | 2 +- grafast/grafast/src/steps/constant.ts | 4 +- grafast/grafast/src/steps/error.ts | 4 +- grafast/grafast/src/steps/first.ts | 14 ++-- grafast/grafast/src/steps/graphqlResolver.ts | 69 +++++++++------- grafast/grafast/src/steps/list.ts | 10 ++- grafast/grafast/src/steps/listen.ts | 2 +- grafast/grafast/src/steps/load.ts | 30 +++---- grafast/grafast/src/steps/object.ts | 19 +++-- .../grafast/src/steps/polymorphicBranch.ts | 14 ++-- grafast/grafast/src/steps/proxy.ts | 18 +++-- grafast/grafast/src/steps/remapKeys.ts | 16 ++-- grafast/grafast/src/steps/reverse.ts | 17 ++-- 25 files changed, 290 insertions(+), 189 deletions(-) diff --git a/grafast/dataplan-json/src/steps/jsonParse.ts b/grafast/dataplan-json/src/steps/jsonParse.ts index 2e551f0843..0467b0d3e5 100644 --- a/grafast/dataplan-json/src/steps/jsonParse.ts +++ b/grafast/dataplan-json/src/steps/jsonParse.ts @@ -1,6 +1,7 @@ import chalk from "chalk"; import type { AccessStep, + ExecutionDetails, GrafastResultsList, GrafastValuesList, PromiseOrDirect, @@ -53,14 +54,14 @@ export class JSONParseStep< return access(this, [index]); } - execute( - count: number, - values: [GrafastValuesList], - ): GrafastResultsList { + executeV2({ + count, + values: [values0], + unaries: [unaries0], + }: ExecutionDetails<[string]>): GrafastResultsList { const result: Array> = []; // new Array(count); - const list = values[0]; for (let i = 0; i < count; i++) { - const v = list[i]; + const v = values0 !== null ? values0[i] : unaries0!; if (typeof v === "string") { try { result[i] = JSON.parse(v); diff --git a/grafast/dataplan-pg/src/steps/pgPageInfo.ts b/grafast/dataplan-pg/src/steps/pgPageInfo.ts index 518c21bfac..4fe7b6f7d1 100644 --- a/grafast/dataplan-pg/src/steps/pgPageInfo.ts +++ b/grafast/dataplan-pg/src/steps/pgPageInfo.ts @@ -1,5 +1,6 @@ import type { ExecutableStep, + ExecutionDetails, GrafastResultsList, PageInfoCapableStep, } from "grafast"; @@ -150,7 +151,7 @@ export class PgPageInfoStep< return $rows.row(last($rows)).cursor(); } - execute(count: number): GrafastResultsList { + executeV2({ count }: ExecutionDetails): GrafastResultsList { return new Array(count).fill(EMPTY_OBJECT); } diff --git a/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts b/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts index 3a4cc044c7..006bd41692 100644 --- a/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts +++ b/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts @@ -1,4 +1,5 @@ import type { + ExecutionDetails, GrafastResultsList, GrafastValuesList, PolymorphicData, @@ -56,19 +57,21 @@ export class PgSingleTablePolymorphicStep< return this.rowPlan(); } - execute( - count: number, - values: Array>, - ): GrafastResultsList > | null> { const result: Array< PromiseOrDirect> | null> > = []; - const list = values[this.typeStepId]; + const valuesList = values[this.typeStepId]; + const unaryList = unaries[this.typeStepId]; for (let i = 0; i < count; i++) { - const v = list[i]; + const v = valuesList === null ? unaryList : valuesList[i]; result[i] = v ? polymorphicWrap(v) : null; } return result; diff --git a/grafast/dataplan-pg/src/steps/pgUnionAll.ts b/grafast/dataplan-pg/src/steps/pgUnionAll.ts index 7c39603c1f..ec8fc9bb19 100644 --- a/grafast/dataplan-pg/src/steps/pgUnionAll.ts +++ b/grafast/dataplan-pg/src/steps/pgUnionAll.ts @@ -5,6 +5,7 @@ import type { ConnectionCapableStep, ConnectionStep, EdgeCapableStep, + ExecutionDetails, ExecutionExtra, GrafastResultsList, GrafastValuesList, @@ -15,6 +16,7 @@ import type { import { __ItemStep, access, + arrayOfLength, constant, ExecutableStep, exportAs, @@ -323,18 +325,21 @@ export class PgUnionAllSingleStep return sqlExpr`${fragment}`; } - execute( - _count: number, - values: [GrafastValuesList], - ): GrafastResultsList { + executeV2({ + count, + values: [values0], + unaries: [unaries0], + }: ExecutionDetails): GrafastResultsList { if (this.typeKey !== null) { const typeKey = this.typeKey; - return values[0].map((v) => { - const type = v[typeKey]; - return polymorphicWrap(type, v); - }); + return values0 === null + ? arrayOfLength(count, polymorphicWrap(unaries0[typeKey], unaries0)) + : values0.map((v) => { + const type = v[typeKey]; + return polymorphicWrap(type, v); + }); } else { - return values[0]; + return values0 === null ? arrayOfLength(count, unaries0) : values0; } } } diff --git a/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts b/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts index 449351c8d5..0bfd30c891 100644 --- a/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts +++ b/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts @@ -1,4 +1,8 @@ -import type { GrafastResultsList, GrafastValuesList } from "grafast"; +import type { + ExecutionDetails, + GrafastResultsList, + GrafastValuesList, +} from "grafast"; import { ExecutableStep, isDev, SafeError } from "grafast"; /** @@ -37,42 +41,52 @@ export class PgValidateParsedCursorStep extends ExecutableStep { ); } - execute( - _count: number, - values: [GrafastValuesList], - ): GrafastResultsList { - const parsedCursors = values[0]; - return parsedCursors.map((decoded) => { + executeV2({ + count, + values: [values0], + unaries: [unaries0], + }: ExecutionDetails<[string | null]>): GrafastResultsList { + const results: any[] = []; + for (let i = 0; i < count; i++) { + const decoded = values0 === null ? unaries0 : values0[i]; if (!decoded) { - return; - } - try { - const [cursorDigest, ...cursorParts] = decoded; - if (!cursorDigest || cursorDigest !== this.digest) { - throw new Error( - `Invalid cursor digest - '${cursorDigest}' !== '${this.digest}'`, - ); - } - if (cursorDigest === "natural") { - if (cursorParts.length !== 1 || typeof cursorParts[0] !== "number") { - throw new Error(`Invalid 'natural' cursor value - ${cursorParts}`); + results.push(undefined); + } else { + try { + const [cursorDigest, ...cursorParts] = decoded; + if (!cursorDigest || cursorDigest !== this.digest) { + throw new Error( + `Invalid cursor digest - '${cursorDigest}' !== '${this.digest}'`, + ); } - } else if (cursorParts.length !== this.orderCount) { - throw new Error( - `Invalid cursor length - ${cursorParts.length} !== ${this.orderCount}`, + if (cursorDigest === "natural") { + if ( + cursorParts.length !== 1 || + typeof cursorParts[0] !== "number" + ) { + throw new Error( + `Invalid 'natural' cursor value - ${cursorParts}`, + ); + } + } else if (cursorParts.length !== this.orderCount) { + throw new Error( + `Invalid cursor length - ${cursorParts.length} !== ${this.orderCount}`, + ); + } + results.push(undefined); + } catch (e) { + if (isDev) { + console.error("Invalid cursor:"); + console.error(e); + } + // TODO: we should push this error to `results`; but doing so would make it not syncAndSafe. + throw new SafeError( + `Invalid '${this.beforeOrAfter}' cursor - a cursor is only valid within a specific ordering, if you change the order then you'll need different cursors.`, ); } - return undefined; - } catch (e) { - if (isDev) { - console.error("Invalid cursor:"); - console.error(e); - } - throw new SafeError( - `Invalid '${this.beforeOrAfter}' cursor - a cursor is only valid within a specific ordering, if you change the order then you'll need different cursors.`, - ); } - }); + } + return results; } } diff --git a/grafast/dataplan-pg/src/steps/withPgClient.ts b/grafast/dataplan-pg/src/steps/withPgClient.ts index 1da633b35b..4efc18cba0 100644 --- a/grafast/dataplan-pg/src/steps/withPgClient.ts +++ b/grafast/dataplan-pg/src/steps/withPgClient.ts @@ -1,4 +1,8 @@ -import type { GrafastResultsList, GrafastValuesList } from "grafast"; +import type { + ExecutionDetails, + GrafastResultsList, + GrafastValuesList, +} from "grafast"; import { constant, ExecutableStep } from "grafast"; import type { PgClient, PgExecutor, WithPgClient } from "../executor"; @@ -52,19 +56,27 @@ export class WithPgClientStep< this.dataId = this.addDependency($data); } - execute( - _count: number, - values: [ - GrafastValuesList<{ pgSettings: any; withPgClient: WithPgClient }>, - GrafastValuesList, - ], - ): GrafastResultsList { - const contexts = values[this.contextId as 0]; - const datas = values[this.dataId as 1]; - return contexts.map(async ({ pgSettings, withPgClient }, i) => { - const data = datas[i]; - return withPgClient(pgSettings, (client) => this.callback(client, data)); - }); + executeV2({ + count, + values, + unaries, + }: ExecutionDetails< + [{ pgSettings: any; withPgClient: WithPgClient }, TData] + >): GrafastResultsList { + const contextValues = values[this.contextId as 0]; + const unaryContext = unaries[this.contextId as 0]; + const dataValues = values[this.dataId as 1]; + const dataUnary = unaries[this.dataId as 1]; + const promises: Promise[] = []; + for (let i = 0; i < count; i++) { + const context = contextValues === null ? unaryContext! : contextValues[i]; + const data = dataValues === null ? dataUnary! : dataValues[i]; + const { withPgClient, pgSettings } = context; + promises.push( + withPgClient(pgSettings, (client) => this.callback(client, data)), + ); + } + return promises; } } diff --git a/grafast/grafast/__tests__/forbidden-test.ts b/grafast/grafast/__tests__/forbidden-test.ts index 506ecd10b0..ed90b57e10 100644 --- a/grafast/grafast/__tests__/forbidden-test.ts +++ b/grafast/grafast/__tests__/forbidden-test.ts @@ -3,7 +3,7 @@ import { expect } from "chai"; import type { AsyncExecutionResult, ExecutionResult } from "graphql"; import { it } from "mocha"; -import type { PromiseOrDirect } from "../dist/index.js"; +import type { ExecutionDetails, PromiseOrDirect } from "../dist/index.js"; import { arrayOfLength, constant, @@ -60,8 +60,8 @@ class BadFinalizeStep extends ExecutableStep { $parent.finalize(); return this; } - execute(l: number) { - return arrayOfLength(l, 42); + executeV2({ count }: ExecutionDetails) { + return arrayOfLength(count, 42); } } diff --git a/grafast/grafast/src/interfaces.ts b/grafast/grafast/src/interfaces.ts index 6238831897..c61d11797d 100644 --- a/grafast/grafast/src/interfaces.ts +++ b/grafast/grafast/src/interfaces.ts @@ -777,7 +777,7 @@ export interface UnbatchedExecutionExtra extends ExecutionExtraBase {} export interface ExecutionDetails { count: number; values: { - [DepIdx in keyof TDeps]: ReadonlyArray | null; + [DepIdx in keyof TDeps]: GrafastValuesList | null; } & { length: TDeps["length"] }; unaries: { [DepIdx in keyof TDeps]: null | TDeps[DepIdx]; diff --git a/grafast/grafast/src/step.ts b/grafast/grafast/src/step.ts index 37a916bc6e..d7f98b9905 100644 --- a/grafast/grafast/src/step.ts +++ b/grafast/grafast/src/step.ts @@ -511,7 +511,7 @@ export /* abstract */ class ExecutableStep extends BaseStep { } } -function _buildOptimizedExecuteExpression( +function _buildOptimizedExecuteV2Expression( depCount: number, isSyncAndSafe: boolean, ) { @@ -533,18 +533,29 @@ function _buildOptimizedExecuteExpression( } }; return te`\ -(function execute(count, values, extra) { - const [ -${te.join( - depIndexes.map((i) => te` ${te.identifier(`list${i}`)},\n`), - "", -)}\ - ] = values; +(function execute({ + count, + values: [${te.join( + depIndexes.map((i) => te.identifier(`list${i}`)), + ", ", + )}\ + ], + unaries: [${te.join( + depIndexes.map((i) => te.identifier(`val${i}`)), + ", ", + )}], + extra, +}) { const results = []; for (let i = 0; i < count; i++) { ${tryOrNot(te`\ results[i] = this.unbatchedExecute(extra, ${te.join( - depIndexes.map((depIndex) => te`${te.identifier(`list${depIndex}`)}[i]`), + depIndexes.map( + (depIndex) => + te`${te.identifier(`list${depIndex}`)} === null ? ${te.identifier( + `val${depIndex}`, + )} : ${te.identifier(`list${depIndex}`)}[i]`, + ), ", ", )});\ `)} @@ -559,18 +570,21 @@ const safeCache: any[] = []; te.batch(() => { for (let i = 0; i <= MAX_DEPENDENCIES_TO_CACHE; i++) { const depCount = i; - const unsafeExpression = _buildOptimizedExecuteExpression(depCount, false); + const unsafeExpression = _buildOptimizedExecuteV2Expression( + depCount, + false, + ); te.runInBatch(unsafeExpression, (fn) => { unsafeCache[depCount] = fn; }); - const safeExpression = _buildOptimizedExecuteExpression(depCount, true); + const safeExpression = _buildOptimizedExecuteV2Expression(depCount, true); te.runInBatch(safeExpression, (fn) => { safeCache[depCount] = fn; }); } }); -function buildOptimizedExecute( +function buildOptimizedExecuteV2( depCount: number, isSyncAndSafe: boolean, callback: (fn: any) => void, @@ -583,7 +597,10 @@ function buildOptimizedExecute( } // Build it - const expression = _buildOptimizedExecuteExpression(depCount, isSyncAndSafe); + const expression = _buildOptimizedExecuteV2Expression( + depCount, + isSyncAndSafe, + ); te.runInBatch(expression, (fn) => { callback(fn); }); @@ -600,29 +617,32 @@ export abstract class UnbatchedExecutableStep< finalize() { // If they've not replaced 'execute', use our optimized form if (this.execute === UnbatchedExecutableStep.prototype.execute) { - buildOptimizedExecute( + buildOptimizedExecuteV2( this.dependencies.length, this.isSyncAndSafe, (fn) => { - this.execute = fn; + this.executeV2 = fn; }, ); } super.finalize(); } - execute( - count: number, - values: ReadonlyArray>, - extra: ExecutionExtra, - ): PromiseOrDirect> { + executeV2({ + count, + values, + unaries, + extra, + }: ExecutionDetails): PromiseOrDirect> { console.warn( `${this} didn't call 'super.finalize()' in the finalize method.`, ); const results = []; for (let i = 0; i < count; i++) { try { - const tuple = values.map((list) => list[i]); + const tuple = values.map((list, depIndex) => + list === null ? unaries[depIndex] : list[i], + ); results[i] = this.unbatchedExecute(extra, ...tuple); } catch (e) { results[i] = e instanceof Error ? (e as never) : Promise.reject(e); diff --git a/grafast/grafast/src/steps/__inputList.ts b/grafast/grafast/src/steps/__inputList.ts index ec27cdf136..80dc54e618 100644 --- a/grafast/grafast/src/steps/__inputList.ts +++ b/grafast/grafast/src/steps/__inputList.ts @@ -78,7 +78,7 @@ export class __InputListStep< } } - execute(): any[] { + executeV2(): any[] { throw new Error( "__InputListStep should never execute; it should have been optimized away.", ); diff --git a/grafast/grafast/src/steps/__item.ts b/grafast/grafast/src/steps/__item.ts index 9fdd8d7452..af562b2037 100644 --- a/grafast/grafast/src/steps/__item.ts +++ b/grafast/grafast/src/steps/__item.ts @@ -49,7 +49,7 @@ export class __ItemStep extends UnbatchedExecutableStep { return this.getDep(0); } - execute(): never { + executeV2(): never { throw new Error("__ItemStep must never execute"); } unbatchedExecute(): never { diff --git a/grafast/grafast/src/steps/__trackedValue.ts b/grafast/grafast/src/steps/__trackedValue.ts index 95fc5809b1..0eda909f13 100644 --- a/grafast/grafast/src/steps/__trackedValue.ts +++ b/grafast/grafast/src/steps/__trackedValue.ts @@ -14,8 +14,9 @@ import { } from "graphql"; import type { Constraint } from "../constraints.js"; -import { __ListTransformStep } from "../index.js"; +import { __ListTransformStep, arrayOfLength } from "../index.js"; import type { + ExecutionDetails, GrafastResultsList, GrafastValuesList, UnbatchedExecutionExtra, @@ -151,12 +152,13 @@ export class __TrackedValueStep< } } - execute( - _count: number, - values: [GrafastValuesList], - ): GrafastResultsList { + executeV2({ + count, + values: [values0], + unaries: [unaries0], + }: ExecutionDetails<[TData]>): GrafastResultsList { // We have only one dependency, return the value of that. - return values[0]; + return values0 === null ? arrayOfLength(count, unaries0) : values0; } unbatchedExecute(_extra: UnbatchedExecutionExtra, v: TData): TData { diff --git a/grafast/grafast/src/steps/__value.ts b/grafast/grafast/src/steps/__value.ts index 73241b0100..49b219db14 100644 --- a/grafast/grafast/src/steps/__value.ts +++ b/grafast/grafast/src/steps/__value.ts @@ -32,7 +32,7 @@ export class __ValueStep extends ExecutableStep { } } - execute(): never { + executeV2(): never { // This is still an "executable plan"; we just side-step execution internally. throw new Error( `GrafastInternalError<7696a514-f452-4d47-92d3-85aeb5b23f48>: ${this} is a __ValueStep and thus must never execute`, diff --git a/grafast/grafast/src/steps/constant.ts b/grafast/grafast/src/steps/constant.ts index 7ca5165c6d..b0d315d065 100644 --- a/grafast/grafast/src/steps/constant.ts +++ b/grafast/grafast/src/steps/constant.ts @@ -1,5 +1,5 @@ import { inspect } from "../inspect.js"; -import type { GrafastResultsList } from "../interfaces.js"; +import type { ExecutionDetails, GrafastResultsList } from "../interfaces.js"; import { UnbatchedExecutableStep } from "../step.js"; import { arrayOfLength } from "../utils.js"; @@ -32,7 +32,7 @@ export class ConstantStep extends UnbatchedExecutableStep { return peers.filter((p) => p.data === this.data); } - execute(count: number): GrafastResultsList { + executeV2({ count }: ExecutionDetails): GrafastResultsList { return arrayOfLength(count, this.data); } diff --git a/grafast/grafast/src/steps/error.ts b/grafast/grafast/src/steps/error.ts index 5f68f43d29..cc1fa3ee31 100644 --- a/grafast/grafast/src/steps/error.ts +++ b/grafast/grafast/src/steps/error.ts @@ -1,5 +1,5 @@ import { inspect } from "../inspect.js"; -import type { GrafastResultsList } from "../interfaces.js"; +import type { ExecutionDetails, GrafastResultsList } from "../interfaces.js"; import { UnbatchedExecutableStep } from "../step.js"; import { arrayOfLength } from "../utils.js"; @@ -20,7 +20,7 @@ export class ErrorStep< this.error = error; } - execute(count: number): GrafastResultsList { + executeV2({ count }: ExecutionDetails): GrafastResultsList { return arrayOfLength(count, this.error); } unbatchedExecute(): any { diff --git a/grafast/grafast/src/steps/first.ts b/grafast/grafast/src/steps/first.ts index 3a262be6ae..3a84639100 100644 --- a/grafast/grafast/src/steps/first.ts +++ b/grafast/grafast/src/steps/first.ts @@ -1,6 +1,6 @@ import type { + ExecutionDetails, GrafastResultsList, - GrafastValuesList, UnbatchedExecutionExtra, } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; @@ -20,14 +20,14 @@ export class FirstStep extends UnbatchedExecutableStep { this.addDependency(parentPlan); } - execute( - count: number, - values: GrafastValuesList<[ReadonlyArray]>, - ): GrafastResultsList { + executeV2({ + count, + values: [values0], + unaries: [unaries0], + }: ExecutionDetails<[TData[]]>): GrafastResultsList { const result: Array = []; - const dep = values[0]; for (let i = 0; i < count; i++) { - result[i] = dep[i]?.[0]; + result[i] = values0 === null ? unaries0?.[0]! : values0[i]?.[0]; } return result; } diff --git a/grafast/grafast/src/steps/graphqlResolver.ts b/grafast/grafast/src/steps/graphqlResolver.ts index 9f3ac094c9..12babc181f 100644 --- a/grafast/grafast/src/steps/graphqlResolver.ts +++ b/grafast/grafast/src/steps/graphqlResolver.ts @@ -7,7 +7,7 @@ import type { } from "graphql"; import * as graphql from "graphql"; -import type { __ItemStep, ObjectStep } from "../index.js"; +import type { __ItemStep, ExecutionDetails, ObjectStep } from "../index.js"; import { context, SafeError } from "../index.js"; import type { ExecutionExtra, @@ -312,45 +312,56 @@ export class GraphQLItemHandler return data.map((data) => dcr(data, context, resolveInfo)); } - execute( - _count: number, - values: [GrafastValuesList], - ): GrafastResultsList { + executeV2({ + count, + values: [values0], + unaries: [unaries0], + }: ExecutionDetails< + [Awaited>] + >): GrafastResultsList { if (this.abstractType !== undefined) { - return values[0].map((data) => { + const results: any[] = []; + for (let i = 0; i < count; i++) { + const data = values0 !== null ? values0[i] : unaries0; if (data == null) { - return data; - } - if (isPromiseLike(data.data)) { - return data.data.then((resolvedData: unknown) => - this.polymorphicWrapData( - resolvedData, - data.context, - data.resolveInfo, + results.push(data); + } else if (isPromiseLike(data.data)) { + results.push( + data.data.then((resolvedData: unknown) => + this.polymorphicWrapData( + resolvedData, + data.context, + data.resolveInfo, + ), ), ); } else { - return this.polymorphicWrapData( - data.data, - data.context, - data.resolveInfo, + results.push( + this.polymorphicWrapData(data.data, data.context, data.resolveInfo), ); } - }); + } + return results; } else if (this.nullableInnerType != null) { - return values[0].map((d) => { + const results: any[] = []; + for (let i = 0; i < count; i++) { + const d = values0 !== null ? values0[i] : unaries0; if (d == null) { - return null; - } - const { data, context, resolveInfo } = d; - if (isPromiseLike(data)) { - return data.then((data) => - this.wrapListData(data, context, resolveInfo), - ); + results.push(null); } else { - return this.wrapListData(data, context, resolveInfo); + const { data, context, resolveInfo } = d; + if (isPromiseLike(data)) { + results.push( + data.then((data) => + this.wrapListData(data, context, resolveInfo), + ), + ); + } else { + results.push(this.wrapListData(data, context, resolveInfo)); + } } - }); + } + return results; } else { throw new Error( `GrafastInternalError<6a3ed701-6b53-41e6-9a64-fbea57c76ae7>: has to be abstract or list`, diff --git a/grafast/grafast/src/steps/list.ts b/grafast/grafast/src/steps/list.ts index 6122ac5f52..fa1c9d3853 100644 --- a/grafast/grafast/src/steps/list.ts +++ b/grafast/grafast/src/steps/list.ts @@ -1,4 +1,5 @@ import type { + ExecutionDetails, StepOptimizeOptions, UnbatchedExecutionExtra, UnwrapPlanTuple, @@ -29,13 +30,14 @@ export class ListStep< return this.dependencies.map(($dep) => $dep.id).join(","); } - execute( - count: number, - values: any[][], //Array>, + executeV2( + { count, values, unaries }: ExecutionDetails, //UnwrapPlanTuple, ): Array> { const result: any[] = []; for (let i = 0; i < count; i++) { - result[i] = values.map((list) => list[i]); + result[i] = values.map((list, depIndex) => + list === null ? unaries[depIndex] : list[i], + ); } return result; } diff --git a/grafast/grafast/src/steps/listen.ts b/grafast/grafast/src/steps/listen.ts index 6bf819646b..1d12420594 100644 --- a/grafast/grafast/src/steps/listen.ts +++ b/grafast/grafast/src/steps/listen.ts @@ -59,7 +59,7 @@ export class ListenStep< this.topicDep = this.addDependency($topic); } - execute(): never { + executeV2(): never { throw new Error("ListenStep cannot be executed, it can only be streamed"); } diff --git a/grafast/grafast/src/steps/load.ts b/grafast/grafast/src/steps/load.ts index 4675da2c43..161ce1807a 100644 --- a/grafast/grafast/src/steps/load.ts +++ b/grafast/grafast/src/steps/load.ts @@ -1,4 +1,4 @@ -import type { __ItemStep, Deferred } from "../index.js"; +import type { __ItemStep, Deferred, ExecutionDetails } from "../index.js"; import { defer } from "../index.js"; import type { ExecutionExtra, @@ -8,7 +8,7 @@ import type { PromiseOrDirect, } from "../interfaces.js"; import { ExecutableStep, isListLikeStep, isObjectLikeStep } from "../step.js"; -import { canonicalJSONStringify } from "../utils.js"; +import { arrayOfLength, canonicalJSONStringify } from "../utils.js"; import { access } from "./access.js"; export interface LoadOptions> { @@ -154,11 +154,12 @@ export class LoadedRecordStep< return this.getDep(0); } // This'll never be called, due to `optimize` above. - execute( - _count: number, - [records]: [GrafastValuesList], - ): GrafastResultsList { - return records; + executeV2({ + count, + values: [values0], + unaries: [unaries0], + }: ExecutionDetails<[TItem]>): GrafastResultsList { + return values0 === null ? arrayOfLength(count, unaries0) : values0; } } @@ -286,11 +287,14 @@ export class LoadStep< super.finalize(); } - execute( - count: number, - [specs]: [GrafastValuesList], - extra: ExecutionExtra, - ): PromiseOrDirect>> { + executeV2({ + count, + values: [values0], + unaries: [unaries0], + extra, + }: ExecutionDetails<[TSpec]>): PromiseOrDirect< + GrafastResultsList> + > { const meta = extra.meta as LoadMeta; let cache = meta.cache; if (!cache) { @@ -301,7 +305,7 @@ export class LoadStep< const results: Array>> = []; for (let i = 0; i < count; i++) { - const spec = specs[i]; + const spec = values0 === null ? unaries0! : values0[i]; if (cache.has(spec)) { results.push(cache.get(spec)!); } else { diff --git a/grafast/grafast/src/steps/object.ts b/grafast/grafast/src/steps/object.ts index d50880fb2d..8c7ad12cdf 100644 --- a/grafast/grafast/src/steps/object.ts +++ b/grafast/grafast/src/steps/object.ts @@ -3,6 +3,7 @@ import te, { isSafeObjectPropertyName } from "tamedevil"; import type { + ExecutionDetails, ExecutionExtra, StepOptimizeOptions, UnbatchedExecutionExtra, @@ -215,14 +216,20 @@ ${inner} return super.finalize(); } - execute( - count: number, - values: Array[keyof TPlans]>>, - extra: ExecutionExtra, - ): Array> { + executeV2({ + count, + values, + unaries, + extra, + }: ExecutionDetails[keyof TPlans]>>): Array< + DataFromPlans + > { const result: Array> = []; for (let i = 0; i < count; i++) { - result[i] = this.unbatchedExecute!(extra, ...values.map((v) => v[i])); + result[i] = this.unbatchedExecute!( + extra, + ...values.map((v, depIndex) => (v === null ? unaries[depIndex] : v[i])), + ); } return result; } diff --git a/grafast/grafast/src/steps/polymorphicBranch.ts b/grafast/grafast/src/steps/polymorphicBranch.ts index a1b91e85cc..bd5b891d50 100644 --- a/grafast/grafast/src/steps/polymorphicBranch.ts +++ b/grafast/grafast/src/steps/polymorphicBranch.ts @@ -1,6 +1,7 @@ import type { GraphQLObjectType } from "graphql"; import type { + ExecutionDetails, ExecutionExtra, GrafastResultsList, GrafastValuesList, @@ -72,15 +73,14 @@ export class PolymorphicBranchStep } } - execute( - count: number, - values: ReadonlyArray>, - _extra: ExecutionExtra, - ): PromiseOrDirect> { + executeV2({ + count, + values: [values0], + unaries: [unaries0], + }: ExecutionDetails): PromiseOrDirect> { const results: any[] = []; - const objects = values[0]; for (let i = 0; i < count; i++) { - const obj = objects[i]; + const obj = values0 !== null ? values0[i] : unaries0!; let match: string | null = null; if (obj != null) { for (const typeName of this.typeNames) { diff --git a/grafast/grafast/src/steps/proxy.ts b/grafast/grafast/src/steps/proxy.ts index 7868a92a15..89b1b13c6c 100644 --- a/grafast/grafast/src/steps/proxy.ts +++ b/grafast/grafast/src/steps/proxy.ts @@ -1,4 +1,9 @@ -import type { GrafastResultsList, GrafastValuesList } from "../index.js"; +import { + arrayOfLength, + type ExecutionDetails, + type GrafastResultsList, + type GrafastValuesList, +} from "../index.js"; import type { UnbatchedExecutionExtra } from "../interfaces.js"; import { $$proxy } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; @@ -29,11 +34,12 @@ export class ProxyStep extends UnbatchedExecutableStep { public addDependency(step: ExecutableStep): number { return super.addDependency(step); } - execute( - _count: number, - values: [GrafastValuesList], - ): GrafastResultsList { - return values[0]; + executeV2({ + count, + values: [values0], + unaries: [unaries0], + }: ExecutionDetails<[T]>): GrafastResultsList { + return values0 === null ? arrayOfLength(count, unaries0) : values0; } unbatchedExecute(_extra: UnbatchedExecutionExtra, value: T): T { return value; diff --git a/grafast/grafast/src/steps/remapKeys.ts b/grafast/grafast/src/steps/remapKeys.ts index e1ad7ec6da..adbe683a53 100644 --- a/grafast/grafast/src/steps/remapKeys.ts +++ b/grafast/grafast/src/steps/remapKeys.ts @@ -3,6 +3,7 @@ import chalk from "chalk"; import te, { isSafeObjectPropertyName } from "tamedevil"; import type { + ExecutionDetails, GrafastResultsList, GrafastValuesList, UnbatchedExecutionExtra, @@ -99,11 +100,16 @@ export class RemapKeysStep extends UnbatchedExecutableStep { super.finalize(); } - execute( - _count: number, - values: GrafastValuesList, - ): GrafastResultsList { - return values[0].map(this.mapper); + executeV2({ + count, + values: [values0], + unaries: [unaries0], + }: ExecutionDetails): GrafastResultsList { + const results: any[] = []; + for (let i = 0; i < count; i++) { + results.push(this.mapper(values0 === null ? unaries0 : values0[i])); + } + return results; } unbatchedExecute(_extra: UnbatchedExecutionExtra, value: any): any { diff --git a/grafast/grafast/src/steps/reverse.ts b/grafast/grafast/src/steps/reverse.ts index cb261ec5b4..4315a570db 100644 --- a/grafast/grafast/src/steps/reverse.ts +++ b/grafast/grafast/src/steps/reverse.ts @@ -1,4 +1,5 @@ import type { + ExecutionDetails, GrafastResultsList, GrafastValuesList, UnbatchedExecutionExtra, @@ -41,11 +42,17 @@ export class ReverseStep extends UnbatchedExecutableStep< this.addDependency(plan); } - execute( - _count: number, - values: [GrafastValuesList], - ): GrafastResultsList { - return values[0].map((arr) => (arr == null ? arr : reverseArray(arr))); + executeV2({ + count, + values: [values0], + unaries: [unaries0], + }: ExecutionDetails<[TData[]]>): GrafastResultsList { + const results: any[] = []; + for (let i = 0; i < count; i++) { + const arr = values0 === null ? unaries0 : values0[i]; + results.push(arr == null ? arr : reverseArray(arr)); + } + return results; } unbatchedExecute(_extra: UnbatchedExecutionExtra, arr: TData[]): TData[] { From ba7b70cd5abffefe241bd5b9f66e7ac0da1cc58d Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 27 Feb 2024 13:56:43 +0000 Subject: [PATCH 25/48] A couple more executes --- grafast/grafast/src/step.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/grafast/grafast/src/step.ts b/grafast/grafast/src/step.ts index d7f98b9905..0b816e550b 100644 --- a/grafast/grafast/src/step.ts +++ b/grafast/grafast/src/step.ts @@ -505,7 +505,7 @@ export /* abstract */ class ExecutableStep extends BaseStep { this.deduplicatedWith = throwDestroyed; this.optimize = throwDestroyed; this.finalize = throwDestroyed; - this.execute = throwDestroyed; + this.executeV2 = throwDestroyed; super.destroy(); } @@ -616,7 +616,10 @@ export abstract class UnbatchedExecutableStep< finalize() { // If they've not replaced 'execute', use our optimized form - if (this.execute === UnbatchedExecutableStep.prototype.execute) { + if ( + this.executeV2 === UnbatchedExecutableStep.prototype.executeV2 && + this.execute === UnbatchedExecutableStep.prototype.execute + ) { buildOptimizedExecuteV2( this.dependencies.length, this.isSyncAndSafe, @@ -624,6 +627,11 @@ export abstract class UnbatchedExecutableStep< this.executeV2 = fn; }, ); + } else { + // TODO: only warn once per class + console.warn( + `It appears that you've replaced the execute or executeV2 method of ${this}; but since this is an UnbatchedExecuteableStep you should only replace unbatchedExecute`, + ); } super.finalize(); } From f03546dc4895648a0e8ccc6300bfea8840f179e4 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 27 Feb 2024 13:59:13 +0000 Subject: [PATCH 26/48] Catch another scenario --- grafast/grafast/src/step.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/grafast/grafast/src/step.ts b/grafast/grafast/src/step.ts index 0b816e550b..0fb5b895e6 100644 --- a/grafast/grafast/src/step.ts +++ b/grafast/grafast/src/step.ts @@ -615,11 +615,11 @@ export abstract class UnbatchedExecutableStep< }; finalize() { - // If they've not replaced 'execute', use our optimized form if ( this.executeV2 === UnbatchedExecutableStep.prototype.executeV2 && this.execute === UnbatchedExecutableStep.prototype.execute ) { + // If they've not replaced 'execute', use our optimized form buildOptimizedExecuteV2( this.dependencies.length, this.isSyncAndSafe, @@ -627,11 +627,12 @@ export abstract class UnbatchedExecutableStep< this.executeV2 = fn; }, ); - } else { - // TODO: only warn once per class - console.warn( - `It appears that you've replaced the execute or executeV2 method of ${this}; but since this is an UnbatchedExecuteableStep you should only replace unbatchedExecute`, - ); + } else if ( + this.executeV2 === UnbatchedExecutableStep.prototype.executeV2 && + this.execute !== UnbatchedExecutableStep.prototype.execute + ) { + // They've overridden `execute` so we should call that rather than using our optimized executeV2 + this.executeV2 = ExecutableStep.prototype.executeV2; } super.finalize(); } From ad2d10ba8fcc8f3fcecae503cee544bfdec7732f Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 27 Feb 2024 14:10:52 +0000 Subject: [PATCH 27/48] Stream to streamV2 --- grafast/grafast/__tests__/stream-test.ts | 24 +++++++++++++------ grafast/grafast/src/interfaces.ts | 10 ++++---- grafast/grafast/src/steps/listen.ts | 30 +++++++++++++----------- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/grafast/grafast/__tests__/stream-test.ts b/grafast/grafast/__tests__/stream-test.ts index d720490157..4a08f52185 100644 --- a/grafast/grafast/__tests__/stream-test.ts +++ b/grafast/grafast/__tests__/stream-test.ts @@ -15,6 +15,7 @@ import { lambda, makeGrafastSchema, } from "../dist/index.js"; +import { StreamDetails } from "../dist/interfaces.js"; class SyncListCallbackStep< TIn, @@ -40,14 +41,23 @@ class SyncListCallbackStep< } return result; } - stream(_count: number, [val]: [Array]) { + streamV2({ + count, + values: [values0], + unaries: [unaries0], + }: StreamDetails<[TIn]>) { const { callback } = this; - return val.map((entry) => - (async function* () { - const data = await callback(entry); - yield* data; - })(), - ); + let results: any[] = []; + for (let i = 0; i < count; i++) { + const entry = values0 === null ? unaries0! : values0[i]; + results.push( + (async function* () { + const data = await callback(entry); + yield* data; + })(), + ); + } + return results; } } diff --git a/grafast/grafast/src/interfaces.ts b/grafast/grafast/src/interfaces.ts index c61d11797d..1f8434c07d 100644 --- a/grafast/grafast/src/interfaces.ts +++ b/grafast/grafast/src/interfaces.ts @@ -774,7 +774,9 @@ export interface ExecutionExtraBase { export interface ExecutionExtra extends ExecutionExtraBase {} export interface UnbatchedExecutionExtra extends ExecutionExtraBase {} -export interface ExecutionDetails { +export interface ExecutionDetails< + TDeps extends readonly [...any[]] = readonly [...any[]], +> { count: number; values: { [DepIdx in keyof TDeps]: GrafastValuesList | null; @@ -784,8 +786,9 @@ export interface ExecutionDetails { } & { length: TDeps["length"] }; extra: ExecutionExtra; } -export interface StreamDetails - extends ExecutionDetails { +export interface StreamDetails< + TDeps extends readonly [...any[]] = readonly [...any[]], +> extends ExecutionDetails { streamOptions: StepStreamOptions; } @@ -817,7 +820,6 @@ export interface GrafastArgs extends GraphQLArgs { resolvedPreset?: GraphileConfig.ResolvedPreset; requestContext?: Partial; } - export type Maybe = T | null | undefined; export * from "./planJSONInterfaces.js"; diff --git a/grafast/grafast/src/steps/listen.ts b/grafast/grafast/src/steps/listen.ts index 1d12420594..cbe8a17a7c 100644 --- a/grafast/grafast/src/steps/listen.ts +++ b/grafast/grafast/src/steps/listen.ts @@ -3,9 +3,9 @@ import { SafeError } from "../index.js"; import type { GrafastResultStreamList, GrafastSubscriber, - GrafastValuesList, + StreamDetails, } from "../interfaces.js"; -import type { StreamableStep } from "../step.js"; +import type { StreamV2ableStep } from "../step.js"; import { ExecutableStep, isExecutableStep } from "../step.js"; import type { __ItemStep } from "./__item.js"; import { constant } from "./constant.js"; @@ -21,7 +21,7 @@ export class ListenStep< TPayloadStep extends ExecutableStep, > extends ExecutableStep - implements StreamableStep + implements StreamV2ableStep { static $$export = { moduleName: "grafast", @@ -63,18 +63,20 @@ export class ListenStep< throw new Error("ListenStep cannot be executed, it can only be streamed"); } - stream( - count: number, - values: readonly [ - GrafastValuesList>, - GrafastValuesList, - ], - ): GrafastResultStreamList { - const pubsubs = values[this.pubsubDep as 0]; - const topics = values[this.topicDep as 1]; + streamV2({ + count, + values, + unaries, + }: StreamDetails< + readonly [GrafastSubscriber, TTopic] + >): GrafastResultStreamList { + const pubsubValues = values[this.pubsubDep as 0]; + const pubsubUnary = unaries[this.pubsubDep as 0]; + const topicValues = values[this.topicDep as 1]; + const topicUnary = unaries[this.topicDep as 1]; const result = []; for (let i = 0; i < count; i++) { - const pubsub = pubsubs[i]; + const pubsub = pubsubValues === null ? pubsubUnary : pubsubValues[i]; if (!pubsub) { throw new SafeError( "Subscription not supported", @@ -87,7 +89,7 @@ export class ListenStep< : {}, ); } - const topic = topics[i]; + const topic = topicValues === null ? topicUnary! : topicValues[i]; result[i] = pubsub.subscribe(topic); } return result; From 6b384d7322c0f94f504d4a9b78a06e307407dae0 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 27 Feb 2024 14:19:01 +0000 Subject: [PATCH 28/48] Lint fixes --- grafast/dataplan-json/src/steps/jsonParse.ts | 1 - .../src/steps/pgSingleTablePolymorphic.ts | 1 - .../dataplan-pg/src/steps/pgValidateParsedCursor.ts | 6 +----- grafast/dataplan-pg/src/steps/withPgClient.ts | 6 +----- grafast/grafast/__tests__/stream-test.ts | 2 +- grafast/grafast/src/steps/__trackedValue.ts | 1 - grafast/grafast/src/steps/first.ts | 1 + grafast/grafast/src/steps/load.ts | 2 -- grafast/grafast/src/steps/polymorphicBranch.ts | 2 -- grafast/grafast/src/steps/proxy.ts | 13 ++++++------- grafast/grafast/src/steps/remapKeys.ts | 1 - grafast/grafast/src/steps/reverse.ts | 1 - 12 files changed, 10 insertions(+), 27 deletions(-) diff --git a/grafast/dataplan-json/src/steps/jsonParse.ts b/grafast/dataplan-json/src/steps/jsonParse.ts index 0467b0d3e5..9d0c96f032 100644 --- a/grafast/dataplan-json/src/steps/jsonParse.ts +++ b/grafast/dataplan-json/src/steps/jsonParse.ts @@ -3,7 +3,6 @@ import type { AccessStep, ExecutionDetails, GrafastResultsList, - GrafastValuesList, PromiseOrDirect, } from "grafast"; import { access, ExecutableStep, exportAs } from "grafast"; diff --git a/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts b/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts index 006bd41692..be63cd93aa 100644 --- a/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts +++ b/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts @@ -1,7 +1,6 @@ import type { ExecutionDetails, GrafastResultsList, - GrafastValuesList, PolymorphicData, PolymorphicStep, PromiseOrDirect, diff --git a/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts b/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts index 0bfd30c891..51b83d0b2f 100644 --- a/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts +++ b/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts @@ -1,8 +1,4 @@ -import type { - ExecutionDetails, - GrafastResultsList, - GrafastValuesList, -} from "grafast"; +import type { ExecutionDetails, GrafastResultsList } from "grafast"; import { ExecutableStep, isDev, SafeError } from "grafast"; /** diff --git a/grafast/dataplan-pg/src/steps/withPgClient.ts b/grafast/dataplan-pg/src/steps/withPgClient.ts index 4efc18cba0..9838dd31ac 100644 --- a/grafast/dataplan-pg/src/steps/withPgClient.ts +++ b/grafast/dataplan-pg/src/steps/withPgClient.ts @@ -1,8 +1,4 @@ -import type { - ExecutionDetails, - GrafastResultsList, - GrafastValuesList, -} from "grafast"; +import type { ExecutionDetails, GrafastResultsList } from "grafast"; import { constant, ExecutableStep } from "grafast"; import type { PgClient, PgExecutor, WithPgClient } from "../executor"; diff --git a/grafast/grafast/__tests__/stream-test.ts b/grafast/grafast/__tests__/stream-test.ts index 4a08f52185..7ee02baa3d 100644 --- a/grafast/grafast/__tests__/stream-test.ts +++ b/grafast/grafast/__tests__/stream-test.ts @@ -15,7 +15,7 @@ import { lambda, makeGrafastSchema, } from "../dist/index.js"; -import { StreamDetails } from "../dist/interfaces.js"; +import type { StreamDetails } from "../dist/interfaces.js"; class SyncListCallbackStep< TIn, diff --git a/grafast/grafast/src/steps/__trackedValue.ts b/grafast/grafast/src/steps/__trackedValue.ts index 0eda909f13..2056370f87 100644 --- a/grafast/grafast/src/steps/__trackedValue.ts +++ b/grafast/grafast/src/steps/__trackedValue.ts @@ -18,7 +18,6 @@ import { __ListTransformStep, arrayOfLength } from "../index.js"; import type { ExecutionDetails, GrafastResultsList, - GrafastValuesList, UnbatchedExecutionExtra, } from "../interfaces.js"; import { UnbatchedExecutableStep } from "../step.js"; diff --git a/grafast/grafast/src/steps/first.ts b/grafast/grafast/src/steps/first.ts index 3a84639100..8d6cd48f86 100644 --- a/grafast/grafast/src/steps/first.ts +++ b/grafast/grafast/src/steps/first.ts @@ -27,6 +27,7 @@ export class FirstStep extends UnbatchedExecutableStep { }: ExecutionDetails<[TData[]]>): GrafastResultsList { const result: Array = []; for (let i = 0; i < count; i++) { + // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain result[i] = values0 === null ? unaries0?.[0]! : values0[i]?.[0]; } return result; diff --git a/grafast/grafast/src/steps/load.ts b/grafast/grafast/src/steps/load.ts index 161ce1807a..9e258058b3 100644 --- a/grafast/grafast/src/steps/load.ts +++ b/grafast/grafast/src/steps/load.ts @@ -1,9 +1,7 @@ import type { __ItemStep, Deferred, ExecutionDetails } from "../index.js"; import { defer } from "../index.js"; import type { - ExecutionExtra, GrafastResultsList, - GrafastValuesList, Maybe, PromiseOrDirect, } from "../interfaces.js"; diff --git a/grafast/grafast/src/steps/polymorphicBranch.ts b/grafast/grafast/src/steps/polymorphicBranch.ts index bd5b891d50..d7662e1b12 100644 --- a/grafast/grafast/src/steps/polymorphicBranch.ts +++ b/grafast/grafast/src/steps/polymorphicBranch.ts @@ -2,9 +2,7 @@ import type { GraphQLObjectType } from "graphql"; import type { ExecutionDetails, - ExecutionExtra, GrafastResultsList, - GrafastValuesList, PromiseOrDirect, } from "../index.js"; import { polymorphicWrap } from "../index.js"; diff --git a/grafast/grafast/src/steps/proxy.ts b/grafast/grafast/src/steps/proxy.ts index 89b1b13c6c..e10df5fca2 100644 --- a/grafast/grafast/src/steps/proxy.ts +++ b/grafast/grafast/src/steps/proxy.ts @@ -1,13 +1,12 @@ -import { - arrayOfLength, - type ExecutionDetails, - type GrafastResultsList, - type GrafastValuesList, -} from "../index.js"; -import type { UnbatchedExecutionExtra } from "../interfaces.js"; +import type { + ExecutionDetails, + GrafastResultsList, + UnbatchedExecutionExtra, +} from "../interfaces.js"; import { $$proxy } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; import { UnbatchedExecutableStep } from "../step.js"; +import { arrayOfLength } from "../utils.js"; /** * @experimental diff --git a/grafast/grafast/src/steps/remapKeys.ts b/grafast/grafast/src/steps/remapKeys.ts index adbe683a53..d16e3bfca9 100644 --- a/grafast/grafast/src/steps/remapKeys.ts +++ b/grafast/grafast/src/steps/remapKeys.ts @@ -5,7 +5,6 @@ import te, { isSafeObjectPropertyName } from "tamedevil"; import type { ExecutionDetails, GrafastResultsList, - GrafastValuesList, UnbatchedExecutionExtra, } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; diff --git a/grafast/grafast/src/steps/reverse.ts b/grafast/grafast/src/steps/reverse.ts index 4315a570db..c7b261ffb1 100644 --- a/grafast/grafast/src/steps/reverse.ts +++ b/grafast/grafast/src/steps/reverse.ts @@ -1,7 +1,6 @@ import type { ExecutionDetails, GrafastResultsList, - GrafastValuesList, UnbatchedExecutionExtra, } from "../interfaces.js"; import type { ExecutableStep } from "../step.js"; From b788dd86849e703cc3aa863fd9190c36a087b865 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 27 Feb 2024 14:24:02 +0000 Subject: [PATCH 29/48] docs(changeset): Add te.debug helper for debugging a te expression via printing a formatted version. --- .changeset/curly-dingos-fix.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/curly-dingos-fix.md diff --git a/.changeset/curly-dingos-fix.md b/.changeset/curly-dingos-fix.md new file mode 100644 index 0000000000..fe7c16a7d7 --- /dev/null +++ b/.changeset/curly-dingos-fix.md @@ -0,0 +1,6 @@ +--- +"tamedevil": patch +--- + +Add te.debug helper for debugging a te expression via printing a formatted +version. From 94a05064ea05108685ff71174a9f871ab5b4c147 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 27 Feb 2024 14:25:05 +0000 Subject: [PATCH 30/48] docs(changeset): Fix processing of GRAPHILE_ENV to allow "test" --- .changeset/lemon-toys-wash.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/lemon-toys-wash.md diff --git a/.changeset/lemon-toys-wash.md b/.changeset/lemon-toys-wash.md new file mode 100644 index 0000000000..325c124b5b --- /dev/null +++ b/.changeset/lemon-toys-wash.md @@ -0,0 +1,5 @@ +--- +"pg-sql2": patch +--- + +Fix processing of GRAPHILE_ENV to allow "test" From a0e82b9c5f4e585f1af1e147299cd07944ece6f8 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 27 Feb 2024 14:26:18 +0000 Subject: [PATCH 31/48] docs(changeset): Add 'unary steps' concept to codebase and refactor to using new executeV2 execution method which leverages them. Backwards compatibility maintained, but users should move to executeV2. --- .changeset/rotten-shrimps-do.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .changeset/rotten-shrimps-do.md diff --git a/.changeset/rotten-shrimps-do.md b/.changeset/rotten-shrimps-do.md new file mode 100644 index 0000000000..124b0ca05e --- /dev/null +++ b/.changeset/rotten-shrimps-do.md @@ -0,0 +1,10 @@ +--- +"postgraphile": patch +"@dataplan/json": patch +"@dataplan/pg": patch +"grafast": patch +--- + +Add 'unary steps' concept to codebase and refactor to using new executeV2 +execution method which leverages them. Backwards compatibility maintained, but +users should move to executeV2. From caffbc2571c7145d6b3cb9c90575a7138f7a27f3 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 27 Feb 2024 17:33:25 +0000 Subject: [PATCH 32/48] Async execute -> async executeV2 --- .../dataplan-pg/src/steps/pgDeleteSingle.ts | 20 +++-- .../dataplan-pg/src/steps/pgInsertSingle.ts | 15 ++-- grafast/dataplan-pg/src/steps/pgSelect.ts | 69 +++++++++------- grafast/dataplan-pg/src/steps/pgUnionAll.ts | 80 ++++++++++--------- .../dataplan-pg/src/steps/pgUpdateSingle.ts | 67 +++++++++------- grafast/grafast/__tests__/forbidden-test.ts | 8 +- grafast/grafast/src/steps/applyTransforms.ts | 39 ++++----- grafast/grafast/src/steps/listTransform.ts | 44 +++++----- 8 files changed, 193 insertions(+), 149 deletions(-) diff --git a/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts b/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts index 6792b584de..c7b1055a02 100644 --- a/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts +++ b/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts @@ -1,4 +1,5 @@ import type { + ExecutionDetails, GrafastResultsList, GrafastValuesList, PromiseOrDirect, @@ -245,10 +246,11 @@ export class PgDeleteSingleStep< * NOTE: we don't know what the values being fed in are, we must feed them to * the plans stored in this.identifiers to get actual values we can use. */ - async execute( - count: number, - values: Array>, - ): Promise> { + async executeV2({ + count, + values, + unaries, + }: ExecutionDetails): Promise> { if (!this.finalizeResults) { throw new Error("Cannot execute PgSelectStep before finalizing it."); } @@ -259,9 +261,10 @@ export class PgDeleteSingleStep< // parallel. Note we return a list of promises, each may reject or resolve // without causing the others to reject. const result: Array> = []; - const list = values[this.contextId]; + const listValues = values[this.contextId]; + const listUnary = unaries[this.contextId]; for (let i = 0; i < count; i++) { - const context = list[i]; + const context = listValues === null ? listUnary : listValues[i]; const sqlValues = queryValueDetailsBySymbol.size ? rawSqlValues.map((v) => { if (typeof v === "symbol") { @@ -269,7 +272,9 @@ export class PgDeleteSingleStep< if (!details) { throw new Error(`Saw unexpected symbol '${inspect(v)}'`); } - const val = values[details.depId][i]; + const depValues = values[details.depId]; + const val = + depValues === null ? unaries[details.depId] : depValues[i]; return val == null ? null : details.processor(val); } else { return v; @@ -392,5 +397,4 @@ export function pgDeleteSingle< ): PgDeleteSingleStep { return new PgDeleteSingleStep(resource, getBy); } - exportAs("@dataplan/pg", pgDeleteSingle, "pgDeleteSingle"); diff --git a/grafast/dataplan-pg/src/steps/pgInsertSingle.ts b/grafast/dataplan-pg/src/steps/pgInsertSingle.ts index 3881d6d468..39bbf1844c 100644 --- a/grafast/dataplan-pg/src/steps/pgInsertSingle.ts +++ b/grafast/dataplan-pg/src/steps/pgInsertSingle.ts @@ -1,4 +1,5 @@ import type { + ExecutionDetails, GrafastResultsList, GrafastValuesList, PromiseOrDirect, @@ -281,10 +282,11 @@ export class PgInsertSingleStep< * NOTE: we don't know what the values being fed in are, we must feed them to * the plans stored in this.identifiers to get actual values we can use. */ - async execute( - count: number, - values: Array>, - ): Promise> { + async executeV2({ + count, + values, + unaries, + }: ExecutionDetails): Promise> { if (!this.finalizeResults) { throw new Error("Cannot execute PgSelectStep before finalizing it."); } @@ -296,7 +298,9 @@ export class PgInsertSingleStep< // without causing the others to reject. const result: Array> = []; for (let i = 0; i < count; i++) { - const value = values.map((v) => v[i]); + const value = values.map((v, depId) => + v === null ? unaries[depId] : v[i], + ); const sqlValues = queryValueDetailsBySymbol.size ? rawSqlValues.map((v) => { if (typeof v === "symbol") { @@ -423,5 +427,4 @@ export function pgInsertSingle< ): PgInsertSingleStep { return new PgInsertSingleStep(resource, attributes); } - exportAs("@dataplan/pg", pgInsertSingle, "pgInsertSingle"); diff --git a/grafast/dataplan-pg/src/steps/pgSelect.ts b/grafast/dataplan-pg/src/steps/pgSelect.ts index d412e3f538..96c06eab2c 100644 --- a/grafast/dataplan-pg/src/steps/pgSelect.ts +++ b/grafast/dataplan-pg/src/steps/pgSelect.ts @@ -2,6 +2,7 @@ import { createHash } from "crypto"; import debugFactory from "debug"; import type { ConnectionCapableStep, + ExecutionDetails, ExecutionExtra, GrafastResultsList, GrafastResultStreamList, @@ -46,6 +47,7 @@ import sql, { $$symbolToIdentifier, arraysMatch } from "pg-sql2"; import type { PgCodecAttributes } from "../codecs.js"; import { listOfCodec, TYPES } from "../codecs.js"; import type { PgResource, PgResourceUnique } from "../datasource.js"; +import type { PgExecutorInput } from "../executor.js"; import type { GetPgResourceAttributes, GetPgResourceCodec, @@ -1209,11 +1211,12 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} * NOTE: we don't know what the values being fed in are, we must feed them to * the plans stored in this.identifiers to get actual values we can use. */ - async execute( - count: number, - values: Array>, - { eventEmitter }: ExecutionExtra, - ): Promise>> { + async executeV2({ + count, + values, + unaries, + extra: { eventEmitter }, + }: ExecutionDetails): Promise>> { if (!this.finalizeResults) { throw new Error("Cannot execute PgSelectStep before finalizing it."); } @@ -1229,32 +1232,36 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} name, nameForSingle, } = this.finalizeResults; - - const executionResult = await this.resource.executeWithCache( - values[this.contextId].map((context, i) => { - return { - // The context is how we'd handle different connections with different claims - context, - queryValues: - identifierIndex != null - ? this.queryValues.map(({ dependencyIndex, codec }) => { - const val = values[dependencyIndex][i]; - return val == null ? null : codec.toPg(val); - }) - : EMPTY_ARRAY, - }; - }), - { - text, - textForSingle, - rawSqlValues, - identifierIndex, - name, - nameForSingle, - eventEmitter, - useTransaction: this.mode === "mutation", - }, - ); + const contextValues = values[this.contextId]; + const contextUnary = unaries[this.contextId]; + + const specs: Array> = []; + for (let i = 0; i < count; i++) { + const context = contextValues === null ? contextUnary : contextValues[i]; + specs.push({ + // The context is how we'd handle different connections with different claims + context, + queryValues: + identifierIndex != null + ? this.queryValues.map(({ dependencyIndex, codec }) => { + const depValues = values[dependencyIndex]; + const val = + depValues === null ? unaries[dependencyIndex] : depValues[i]; + return val == null ? null : codec.toPg(val); + }) + : EMPTY_ARRAY, + }); + } + const executionResult = await this.resource.executeWithCache(specs, { + text, + textForSingle, + rawSqlValues, + identifierIndex, + name, + nameForSingle, + eventEmitter, + useTransaction: this.mode === "mutation", + }); // debugExecute("%s; result: %c", this, executionResult); return executionResult.values.map((allVals) => { diff --git a/grafast/dataplan-pg/src/steps/pgUnionAll.ts b/grafast/dataplan-pg/src/steps/pgUnionAll.ts index ec8fc9bb19..76a24891d3 100644 --- a/grafast/dataplan-pg/src/steps/pgUnionAll.ts +++ b/grafast/dataplan-pg/src/steps/pgUnionAll.ts @@ -35,7 +35,7 @@ import { $$symbolToIdentifier, sql } from "pg-sql2"; import type { PgCodecAttributes } from "../codecs.js"; import { TYPES } from "../codecs.js"; import type { PgResource, PgResourceUnique } from "../datasource.js"; -import type { PgExecutor } from "../executor.js"; +import type { PgExecutor, PgExecutorInput } from "../executor.js"; import type { PgCodecRefPath, PgCodecRelation, PgGroupSpec } from "../index.js"; import type { PgCodec, @@ -1930,48 +1930,54 @@ ${lateralText};`; } // Be careful if we add streaming - ensure `shouldReverseOrder` is fine. - async execute( - _count: number, - values: Array>, - { eventEmitter }: ExecutionExtra, - ): Promise> { + async executeV2({ + count, + values, + unaries, + extra: { eventEmitter }, + }: ExecutionDetails): Promise> { const { text, rawSqlValues, identifierIndex, shouldReverseOrder, name } = this.finalizeResults!; - const contexts = values[this.contextId]; - if (!contexts) { + const contextValues = values[this.contextId]; + const contextUnary = unaries[this.contextId]; + if (contextValues === undefined) { throw new Error("We have no context dependency?"); } - const executionResult = await this.executor.executeWithCache( - contexts.map((context, i) => { - return { - // The context is how we'd handle different connections with different claims - context, - queryValues: - identifierIndex != null - ? this.queryValues.map( - ({ dependencyIndex, codec, alreadyEncoded }) => { - const val = values[dependencyIndex][i]; - return val == null - ? null - : alreadyEncoded - ? val - : codec.toPg(val); - }, - ) - : EMPTY_ARRAY, - }; - }), - { - text, - rawSqlValues, - identifierIndex, - name, - eventEmitter, - useTransaction: false, - }, - ); + const specs: Array> = []; + for (let i = 0; i < count; i++) { + const context = contextValues === null ? contextUnary : contextValues[i]; + specs.push({ + // The context is how we'd handle different connections with different claims + context, + queryValues: + identifierIndex != null + ? this.queryValues.map( + ({ dependencyIndex, codec, alreadyEncoded }) => { + const depValues = values[dependencyIndex]; + const val = + depValues === null + ? unaries[dependencyIndex] + : depValues[i]; + return val == null + ? null + : alreadyEncoded + ? val + : codec.toPg(val); + }, + ) + : EMPTY_ARRAY, + }); + } + const executionResult = await this.executor.executeWithCache(specs, { + text, + rawSqlValues, + identifierIndex, + name, + eventEmitter, + useTransaction: false, + }); // debugExecute("%s; result: %c", this, executionResult); return executionResult.values.map((allVals) => { diff --git a/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts b/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts index d2b58662ce..9d5c207332 100644 --- a/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts +++ b/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts @@ -1,4 +1,5 @@ import type { + ExecutionDetails, GrafastResultsList, GrafastValuesList, SetterStep, @@ -304,41 +305,54 @@ export class PgUpdateSingleStep< * NOTE: we don't know what the values being fed in are, we must feed them to * the plans stored in this.identifiers to get actual values we can use. */ - async execute( - _count: number, - values: Array>, - ): Promise> { + async executeV2({ + count, + values, + unaries, + }: ExecutionDetails): Promise> { if (!this.finalizeResults) { throw new Error("Cannot execute PgSelectStep before finalizing it."); } const { text, rawSqlValues, queryValueDetailsBySymbol } = this.finalizeResults; + const contextValues = values[this.contextId]; + const contextUnary = unaries[this.contextId]; // We must execute each mutation on its own, but we can at least do so in // parallel. Note we return a list of promises, each may reject or resolve // without causing the others to reject. - return values[this.contextId].map(async (context, i) => { - const sqlValues = queryValueDetailsBySymbol.size - ? rawSqlValues.map((v) => { - if (typeof v === "symbol") { - const details = queryValueDetailsBySymbol.get(v); - if (!details) { - throw new Error(`Saw unexpected symbol '${inspect(v)}'`); - } - const val = values[details.depId][i]; - return val == null ? null : details.processor(val); - } else { - return v; - } - }) - : rawSqlValues; - const { rows, rowCount } = await this.resource.executeMutation({ - context, - text, - values: sqlValues, - }); - return rows[0] ?? (rowCount === 0 ? null : Object.create(null)); - }); + const promises: Promise[] = []; + for (let i = 0; i < count; i++) { + promises.push( + (async () => { + const context = + contextValues === null ? contextUnary! : contextValues[i]; + const sqlValues = queryValueDetailsBySymbol.size + ? rawSqlValues.map((v) => { + if (typeof v === "symbol") { + const details = queryValueDetailsBySymbol.get(v); + if (!details) { + throw new Error(`Saw unexpected symbol '${inspect(v)}'`); + } + const depValues = values[details.depId]; + const val = + depValues === null ? unaries[details.depId] : depValues[i]; + return val == null ? null : details.processor(val); + } else { + return v; + } + }) + : rawSqlValues; + const { rows, rowCount } = await this.resource.executeMutation({ + context, + text, + values: sqlValues, + }); + return rows[0] ?? (rowCount === 0 ? null : Object.create(null)); + })(), + ); + } + return promises; } public finalize(): void { @@ -464,5 +478,4 @@ export function pgUpdateSingle< ): PgUpdateSingleStep { return new PgUpdateSingleStep(resource, getBy, attributes); } - exportAs("@dataplan/pg", pgUpdateSingle, "pgUpdateSingle"); diff --git a/grafast/grafast/__tests__/forbidden-test.ts b/grafast/grafast/__tests__/forbidden-test.ts index ed90b57e10..17e0abf4db 100644 --- a/grafast/grafast/__tests__/forbidden-test.ts +++ b/grafast/grafast/__tests__/forbidden-test.ts @@ -30,8 +30,8 @@ class SomeStep extends ExecutableStep { finalize(): void { super.finalize(); } - async execute(l: number) { - return arrayOfLength(l, 42); + async executeV2({ count }: ExecutionDetails) { + return arrayOfLength(count, 42); } } @@ -45,8 +45,8 @@ class BadOptimizeStep extends ExecutableStep { $parent.optimize?.({ meta: {}, stream: null }); return this; } - async execute(l: number) { - return arrayOfLength(l, 42); + async executeV2({ count }: ExecutionDetails) { + return arrayOfLength(count, 42); } } diff --git a/grafast/grafast/src/steps/applyTransforms.ts b/grafast/grafast/src/steps/applyTransforms.ts index 5409b49dbe..1d34662e87 100644 --- a/grafast/grafast/src/steps/applyTransforms.ts +++ b/grafast/grafast/src/steps/applyTransforms.ts @@ -7,6 +7,7 @@ import { LayerPlan } from "../engine/LayerPlan.js"; import { withGlobalLayerPlan } from "../engine/lib/withGlobalLayerPlan.js"; import type { GrafastError } from "../error.js"; import type { + ExecutionDetails, ExecutionExtra, GrafastResultsList, GrafastValuesList, @@ -73,11 +74,14 @@ export class ApplyTransformsStep extends ExecutableStep { this.operationPlan.finishSubroutine(this, this.subroutineLayer); } - async execute( - _count: number, - values: [GrafastValuesList], - extra: ExecutionExtra, - ): Promise> { + async executeV2({ + count, + values: [values0], + unaries: [unaries0], + extra, + }: ExecutionDetails<[any[] | null | undefined | GrafastError]>): Promise< + GrafastResultsList + > { const bucket = extra._bucket; const childLayerPlan = this.subroutineLayer; @@ -126,16 +130,10 @@ export class ApplyTransformsStep extends ExecutableStep { } } - const listValues = values[0]; - // We'll typically be creating more listItem bucket entries than we // have parent buckets, so we must "multiply up" the store entries. - for ( - let originalIndex = 0; - originalIndex < listValues.length; - originalIndex++ - ) { - const list = listValues[originalIndex]; + for (let originalIndex = 0; originalIndex < count; originalIndex++) { + const list = values0 === null ? unaries0! : values0[originalIndex]; if (Array.isArray(list)) { const newIndexes: number[] = []; map.set(originalIndex, newIndexes); @@ -180,9 +178,12 @@ export class ApplyTransformsStep extends ExecutableStep { ? [null, unaryStore.get(rootStep.id)] : [store.get(rootStep!.id)!, null]; - return listValues.map((list: any, originalIndex: number) => { + const results: any[] = []; + for (let originalIndex = 0; originalIndex < count; originalIndex++) { + const list = values0 === null ? unaries0! : values0[originalIndex]; if (list == null) { - return list; + results.push(list); + continue; } const indexes = map.get(originalIndex); if (!Array.isArray(list) || !Array.isArray(indexes)) { @@ -190,7 +191,8 @@ export class ApplyTransformsStep extends ExecutableStep { console.warn( `Either list or values was not an array when processing ${this}`, ); - return null; + results.push(null); + continue; } const values = indexes.map((idx) => { const val = depResults === null ? unaryResult : depResults[idx]; @@ -206,8 +208,9 @@ export class ApplyTransformsStep extends ExecutableStep { "GrafastInternalError<43cb302e-673b-4881-8c4c-f2d00fe5a3d7>: The list and values length must match for a ApplyTransformsStep", ); } - return values; - }); + results.push(values); + } + return results; } } diff --git a/grafast/grafast/src/steps/listTransform.ts b/grafast/grafast/src/steps/listTransform.ts index 65350d0934..a227c70f2d 100644 --- a/grafast/grafast/src/steps/listTransform.ts +++ b/grafast/grafast/src/steps/listTransform.ts @@ -6,7 +6,7 @@ import type { LayerPlanReasonSubroutine } from "../engine/LayerPlan.js"; import { LayerPlan } from "../engine/LayerPlan.js"; import { withGlobalLayerPlan } from "../engine/lib/withGlobalLayerPlan.js"; import type { GrafastError } from "../error.js"; -import type { ConnectionCapableStep } from "../index.js"; +import type { ConnectionCapableStep, ExecutionDetails } from "../index.js"; import type { ExecutionExtra, GrafastResultsList, @@ -196,11 +196,14 @@ export class __ListTransformStep< return this; } - async execute( - _count: number, - values: [GrafastValuesList], - extra: ExecutionExtra, - ): Promise> { + async executeV2({ + count, + values, + unaries, + extra, + }: ExecutionDetails<[any[] | null | undefined | GrafastError]>): Promise< + GrafastResultsList + > { const bucket = extra._bucket; const childLayerPlan = this.subroutineLayer; @@ -249,16 +252,14 @@ export class __ListTransformStep< } } - const listValues = values[this.listStepDepId]; + const listStepValues = values[this.listStepDepId]; + const listStepUnary = unaries[this.listStepDepId]; // We'll typically be creating more listItem bucket entries than we // have parent buckets, so we must "multiply up" the store entries. - for ( - let originalIndex = 0; - originalIndex < listValues.length; - originalIndex++ - ) { - const list = listValues[originalIndex]; + for (let originalIndex = 0; originalIndex < count; originalIndex++) { + const list = + listStepValues === null ? listStepUnary : listStepValues[originalIndex]; if (Array.isArray(list)) { const newIndexes: number[] = []; map.set(originalIndex, newIndexes); @@ -303,9 +304,14 @@ export class __ListTransformStep< ? [null, unaryStore.get(rootStep!.id)] : [store.get(rootStep!.id)!, null]; - return listValues.map((list: any, originalIndex: number) => { + const results: any[] = []; + for (let originalIndex = 0; originalIndex < count; originalIndex++) { + const list = + listStepValues === null ? listStepUnary : listStepValues[originalIndex]; + if (list == null) { - return list; + results.push(list); + continue; } const indexes = map.get(originalIndex); if (!Array.isArray(list) || !Array.isArray(indexes)) { @@ -313,7 +319,8 @@ export class __ListTransformStep< console.warn( `Either list or values was not an array when processing ${this}`, ); - return null; + results.push(null); + continue; } const values = indexes.map((idx) => depResults === null ? unaryResult : depResults[idx], @@ -334,8 +341,9 @@ export class __ListTransformStep< const finalResult = this.finalizeCallback ? this.finalizeCallback(reduceResult) : reduceResult; - return finalResult; - }); + results.push(finalResult); + } + return results; } } From 8ec9704278351f31d47c2447ea54e9d3d49357a8 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Tue, 27 Feb 2024 17:47:16 +0000 Subject: [PATCH 33/48] async stream -> async streamV2 --- grafast/dataplan-pg/src/steps/pgSelect.ts | 115 ++++++++++-------- .../grafast/__tests__/errorHandling-test.ts | 23 ++-- .../errorHandlingStreamTermination-test.ts | 34 ++++-- grafast/grafast/src/index.ts | 5 + grafast/grafast/src/steps/graphqlResolver.ts | 14 ++- 5 files changed, 114 insertions(+), 77 deletions(-) diff --git a/grafast/dataplan-pg/src/steps/pgSelect.ts b/grafast/dataplan-pg/src/steps/pgSelect.ts index 96c06eab2c..443917675b 100644 --- a/grafast/dataplan-pg/src/steps/pgSelect.ts +++ b/grafast/dataplan-pg/src/steps/pgSelect.ts @@ -3,16 +3,14 @@ import debugFactory from "debug"; import type { ConnectionCapableStep, ExecutionDetails, - ExecutionExtra, GrafastResultsList, GrafastResultStreamList, - GrafastValuesList, InputStep, LambdaStep, PromiseOrDirect, StepOptimizeOptions, StepStreamOptions, - StreamableStep, + StreamV2ableStep, } from "grafast"; import { __InputListStep, @@ -275,7 +273,7 @@ export class PgSelectStep< ReadonlyArray > implements - StreamableStep, + StreamV2ableStep, ConnectionCapableStep< PgSelectSingleStep, PgSelectParsedCursorStep @@ -1297,11 +1295,12 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} /** * Like `execute`, but stream the results via async iterables. */ - async stream( - _count: number, - values: ReadonlyArray>, - { eventEmitter }: ExecutionExtra, - ): Promise> { + async streamV2({ + count, + values, + unaries, + extra: { eventEmitter }, + }: ExecutionDetails): Promise> { if (!this.finalizeResults) { throw new Error("Cannot stream PgSelectStep before finalizing it."); } @@ -1322,54 +1321,66 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} throw new Error("declare query must exist for stream"); } - const initialFetchResult = text + const contextValues = values[this.contextId]; + const contextUnary = unaries[this.contextId]; + const specs: PgExecutorInput[] | null = text ? [] : null; + if (text) { + for (let i = 0; i < count; i++) { + const context = + contextValues === null ? contextUnary : contextValues[i]; + specs!.push({ + // The context is how we'd handle different connections with different claims + context, + queryValues: + identifierIndex != null + ? this.queryValues.map(({ dependencyIndex, codec }) => { + const depValues = values[dependencyIndex]; + const val = + depValues === null + ? unaries[dependencyIndex] + : depValues[i]; + return val == null ? null : codec.toPg(val); + }) + : EMPTY_ARRAY, + }); + } + } + const initialFetchResult = specs ? ( - await this.resource.executeWithoutCache( - values[this.contextId].map((context, i) => { - return { - // The context is how we'd handle different connections with different claims - context, - queryValues: - identifierIndex != null - ? this.queryValues.map(({ dependencyIndex, codec }) => { - const val = values[dependencyIndex][i]; - return val == null ? null : codec.toPg(val); - }) - : EMPTY_ARRAY, - }; - }), - { - text, - rawSqlValues, - identifierIndex, - eventEmitter, - }, - ) + await this.resource.executeWithoutCache(specs, { + text, + rawSqlValues, + identifierIndex, + eventEmitter, + }) ).values : null; + const streamSpecs: PgExecutorInput[] = []; + for (let i = 0; i < count; i++) { + const context = contextValues === null ? contextUnary : contextValues[i]; + + streamSpecs.push({ + // The context is how we'd handle different connections with different claims + context, + queryValues: + identifierIndex != null + ? this.queryValues.map(({ dependencyIndex, codec }) => { + const depValues = values[dependencyIndex]; + const val = + depValues === null ? unaries[dependencyIndex] : depValues[i]; + return val == null ? val : codec.toPg(val); + }) + : EMPTY_ARRAY, + }); + } const streams = ( - await this.resource.executeStream( - values[this.contextId].map((context, i) => { - return { - // The context is how we'd handle different connections with different claims - context, - queryValues: - identifierIndex != null - ? this.queryValues.map(({ dependencyIndex, codec }) => { - const val = values[dependencyIndex][i]; - return val == null ? val : codec.toPg(val); - }) - : EMPTY_ARRAY, - }; - }), - { - text: textForDeclare, - rawSqlValues: rawSqlValuesForDeclare, - identifierIndex, - eventEmitter, - }, - ) + await this.resource.executeStream(streamSpecs, { + text: textForDeclare, + rawSqlValues: rawSqlValuesForDeclare, + identifierIndex, + eventEmitter, + }) ).streams; if (initialFetchResult) { diff --git a/grafast/grafast/__tests__/errorHandling-test.ts b/grafast/grafast/__tests__/errorHandling-test.ts index eb7a4e816c..9d49e6e060 100644 --- a/grafast/grafast/__tests__/errorHandling-test.ts +++ b/grafast/grafast/__tests__/errorHandling-test.ts @@ -38,15 +38,24 @@ class SyncListCallbackStep< } return result; } - async stream(_count: number, [val]: [Array]) { + async streamV2({ + count, + values: [values0], + unaries: [unaries0], + }: ExecutionDetails<[TIn]>) { await sleep(0); const { callback } = this; - return val.map((entry) => - (async function* () { - const data = await callback(entry); - yield* data; - })(), - ); + const results: any[] = []; + for (let i = 0; i < count; i++) { + const entry = values0 === null ? unaries0! : values0[i]; + results.push( + (async function* () { + const data = await callback(entry); + yield* data; + })(), + ); + } + return results; } } diff --git a/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts b/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts index a1104438d7..8000536162 100644 --- a/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts +++ b/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts @@ -12,6 +12,7 @@ import { lambda, makeGrafastSchema, } from "../dist/index.js"; +import type { StreamDetails } from "../dist/interfaces.js"; const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); @@ -40,23 +41,32 @@ class SyncListCallbackStep< } return result; } - async stream(_count: number, [val]: [Array]) { + async streamV2({ + count, + values: [values0], + unaries: [unaries0], + }: StreamDetails<[TIn]>) { await sleep(0); const { callback, setStreaming } = this; - return val.map((entry) => { + const results: any[] = []; + for (let i = 0; i < count; i++) { + const entry = values0 === null ? unaries0! : values0[i]; setStreaming(true); - return (async function* () { - try { - const data = await callback(entry); - for (const item of data) { - yield item; + results.push( + (async function* () { + try { + const data = await callback(entry); + for (const item of data) { + yield item; + } + } finally { + setStreaming(false); } - } finally { - setStreaming(false); - } - })(); - }); + })(), + ); + } + return results; } } diff --git a/grafast/grafast/src/index.ts b/grafast/grafast/src/index.ts index 5a10d40d61..339eed7fbd 100644 --- a/grafast/grafast/src/index.ts +++ b/grafast/grafast/src/index.ts @@ -114,12 +114,14 @@ import { isModifierStep, isObjectLikeStep, isStreamableStep, + isStreamV2ableStep, ListCapableStep, ListLikeStep, ModifierStep, ObjectLikeStep, PolymorphicStep, StreamableStep, + StreamV2ableStep, UnbatchedExecutableStep, } from "./step.js"; import { @@ -350,6 +352,7 @@ export { isPromiseLike, isSafeError, isStreamableStep, + isStreamV2ableStep, isUnaryStep, JSONArray, JSONObject, @@ -434,6 +437,7 @@ export { stepsAreInSamePhase, StepStreamOptions, StreamableStep, + StreamV2ableStep, stringifyPayload, stripAnsi, subscribe, @@ -468,6 +472,7 @@ exportAsMany("grafast", { isObjectLikeStep, isListLikeStep, isStreamableStep, + isStreamV2ableStep, __ItemStep, __ListTransformStep, __TrackedValueStep, diff --git a/grafast/grafast/src/steps/graphqlResolver.ts b/grafast/grafast/src/steps/graphqlResolver.ts index 12babc181f..3307c1a906 100644 --- a/grafast/grafast/src/steps/graphqlResolver.ts +++ b/grafast/grafast/src/steps/graphqlResolver.ts @@ -185,18 +185,20 @@ export class GraphQLResolverStep extends UnbatchedExecutableStep { return data; } - async stream( - count: number, - values: ReadonlyArray>, - extra: ExecutionExtra, - ): Promise> { + async streamV2({ + count, + values, + unaries, + extra, + }: ExecutionDetails): Promise> { const results = []; const depCount = this.dependencies.length; for (let i = 0; i < count; i++) { try { const tuple = []; for (let j = 0; j < depCount; j++) { - tuple[j] = values[j][i]; + const depValue = values[j]; + tuple[j] = depValue === null ? unaries[j] : depValue[i]; } results[i] = (this.unbatchedStream as any)(extra, ...tuple); } catch (e) { From 6bb7ca2ad7a5b7b1344a06c6b232bfa503c121b7 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 28 Feb 2024 10:07:37 +0000 Subject: [PATCH 34/48] Smoosh unaries back into values again; add .at(i) accessor for ease --- grafast/dataplan-json/src/steps/jsonParse.ts | 5 +- .../dataplan-pg/src/steps/pgDeleteSingle.ts | 10 +- .../dataplan-pg/src/steps/pgInsertSingle.ts | 5 +- grafast/dataplan-pg/src/steps/pgSelect.ts | 29 ++---- .../src/steps/pgSingleTablePolymorphic.ts | 6 +- grafast/dataplan-pg/src/steps/pgUnionAll.ts | 30 +++--- .../dataplan-pg/src/steps/pgUpdateSingle.ts | 11 +-- .../src/steps/pgValidateParsedCursor.ts | 7 +- grafast/dataplan-pg/src/steps/withPgClient.ts | 11 +-- .../grafast/__tests__/errorHandling-test.ts | 11 +-- .../errorHandlingStreamTermination-test.ts | 11 +-- grafast/grafast/__tests__/stream-test.ts | 11 +-- grafast/grafast/__tests__/unaryDeps-test.ts | 14 +-- grafast/grafast/src/engine/executeBucket.ts | 99 ++++++++----------- grafast/grafast/src/interfaces.ts | 19 +++- grafast/grafast/src/step.ts | 36 ++----- grafast/grafast/src/steps/__trackedValue.ts | 5 +- grafast/grafast/src/steps/applyTransforms.ts | 9 +- grafast/grafast/src/steps/first.ts | 6 +- grafast/grafast/src/steps/graphqlResolver.ts | 9 +- grafast/grafast/src/steps/list.ts | 6 +- grafast/grafast/src/steps/listTransform.ts | 14 +-- grafast/grafast/src/steps/listen.ts | 15 +-- grafast/grafast/src/steps/load.ts | 8 +- grafast/grafast/src/steps/object.ts | 6 +- .../grafast/src/steps/polymorphicBranch.ts | 3 +- grafast/grafast/src/steps/proxy.ts | 5 +- grafast/grafast/src/steps/remapKeys.ts | 3 +- grafast/grafast/src/steps/reverse.ts | 3 +- 29 files changed, 165 insertions(+), 242 deletions(-) diff --git a/grafast/dataplan-json/src/steps/jsonParse.ts b/grafast/dataplan-json/src/steps/jsonParse.ts index 9d0c96f032..a7c857eedf 100644 --- a/grafast/dataplan-json/src/steps/jsonParse.ts +++ b/grafast/dataplan-json/src/steps/jsonParse.ts @@ -55,12 +55,11 @@ export class JSONParseStep< executeV2({ count, - values: [values0], - unaries: [unaries0], + values: [stringDep], }: ExecutionDetails<[string]>): GrafastResultsList { const result: Array> = []; // new Array(count); for (let i = 0; i < count; i++) { - const v = values0 !== null ? values0[i] : unaries0!; + const v = stringDep.at(i); if (typeof v === "string") { try { result[i] = JSON.parse(v); diff --git a/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts b/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts index c7b1055a02..85f1f1dbab 100644 --- a/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts +++ b/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts @@ -249,7 +249,6 @@ export class PgDeleteSingleStep< async executeV2({ count, values, - unaries, }: ExecutionDetails): Promise> { if (!this.finalizeResults) { throw new Error("Cannot execute PgSelectStep before finalizing it."); @@ -261,10 +260,9 @@ export class PgDeleteSingleStep< // parallel. Note we return a list of promises, each may reject or resolve // without causing the others to reject. const result: Array> = []; - const listValues = values[this.contextId]; - const listUnary = unaries[this.contextId]; + const contextDep = values[this.contextId]; for (let i = 0; i < count; i++) { - const context = listValues === null ? listUnary : listValues[i]; + const context = contextDep.at(i); const sqlValues = queryValueDetailsBySymbol.size ? rawSqlValues.map((v) => { if (typeof v === "symbol") { @@ -272,9 +270,7 @@ export class PgDeleteSingleStep< if (!details) { throw new Error(`Saw unexpected symbol '${inspect(v)}'`); } - const depValues = values[details.depId]; - const val = - depValues === null ? unaries[details.depId] : depValues[i]; + const val = values[details.depId].at(i); return val == null ? null : details.processor(val); } else { return v; diff --git a/grafast/dataplan-pg/src/steps/pgInsertSingle.ts b/grafast/dataplan-pg/src/steps/pgInsertSingle.ts index 39bbf1844c..4767f9da6a 100644 --- a/grafast/dataplan-pg/src/steps/pgInsertSingle.ts +++ b/grafast/dataplan-pg/src/steps/pgInsertSingle.ts @@ -285,7 +285,6 @@ export class PgInsertSingleStep< async executeV2({ count, values, - unaries, }: ExecutionDetails): Promise> { if (!this.finalizeResults) { throw new Error("Cannot execute PgSelectStep before finalizing it."); @@ -298,9 +297,7 @@ export class PgInsertSingleStep< // without causing the others to reject. const result: Array> = []; for (let i = 0; i < count; i++) { - const value = values.map((v, depId) => - v === null ? unaries[depId] : v[i], - ); + const value = values.map((v) => v.at(i)); const sqlValues = queryValueDetailsBySymbol.size ? rawSqlValues.map((v) => { if (typeof v === "symbol") { diff --git a/grafast/dataplan-pg/src/steps/pgSelect.ts b/grafast/dataplan-pg/src/steps/pgSelect.ts index 443917675b..b0b14719ea 100644 --- a/grafast/dataplan-pg/src/steps/pgSelect.ts +++ b/grafast/dataplan-pg/src/steps/pgSelect.ts @@ -1212,7 +1212,6 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} async executeV2({ count, values, - unaries, extra: { eventEmitter }, }: ExecutionDetails): Promise>> { if (!this.finalizeResults) { @@ -1230,21 +1229,18 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} name, nameForSingle, } = this.finalizeResults; - const contextValues = values[this.contextId]; - const contextUnary = unaries[this.contextId]; + const contextDep = values[this.contextId]; const specs: Array> = []; for (let i = 0; i < count; i++) { - const context = contextValues === null ? contextUnary : contextValues[i]; + const context = contextDep.at(i); specs.push({ // The context is how we'd handle different connections with different claims context, queryValues: identifierIndex != null ? this.queryValues.map(({ dependencyIndex, codec }) => { - const depValues = values[dependencyIndex]; - const val = - depValues === null ? unaries[dependencyIndex] : depValues[i]; + const val = values[dependencyIndex].at(i); return val == null ? null : codec.toPg(val); }) : EMPTY_ARRAY, @@ -1298,7 +1294,6 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} async streamV2({ count, values, - unaries, extra: { eventEmitter }, }: ExecutionDetails): Promise> { if (!this.finalizeResults) { @@ -1321,24 +1316,18 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} throw new Error("declare query must exist for stream"); } - const contextValues = values[this.contextId]; - const contextUnary = unaries[this.contextId]; + const contextDep = values[this.contextId]; const specs: PgExecutorInput[] | null = text ? [] : null; if (text) { for (let i = 0; i < count; i++) { - const context = - contextValues === null ? contextUnary : contextValues[i]; + const context = contextDep.at(i); specs!.push({ // The context is how we'd handle different connections with different claims context, queryValues: identifierIndex != null ? this.queryValues.map(({ dependencyIndex, codec }) => { - const depValues = values[dependencyIndex]; - const val = - depValues === null - ? unaries[dependencyIndex] - : depValues[i]; + const val = values[dependencyIndex].at(i); return val == null ? null : codec.toPg(val); }) : EMPTY_ARRAY, @@ -1358,7 +1347,7 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} const streamSpecs: PgExecutorInput[] = []; for (let i = 0; i < count; i++) { - const context = contextValues === null ? contextUnary : contextValues[i]; + const context = contextDep.at(i); streamSpecs.push({ // The context is how we'd handle different connections with different claims @@ -1366,9 +1355,7 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} queryValues: identifierIndex != null ? this.queryValues.map(({ dependencyIndex, codec }) => { - const depValues = values[dependencyIndex]; - const val = - depValues === null ? unaries[dependencyIndex] : depValues[i]; + const val = values[dependencyIndex].at(i); return val == null ? val : codec.toPg(val); }) : EMPTY_ARRAY, diff --git a/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts b/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts index be63cd93aa..9865e15742 100644 --- a/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts +++ b/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts @@ -59,7 +59,6 @@ export class PgSingleTablePolymorphicStep< executeV2({ count, values, - unaries, }: ExecutionDetails): GrafastResultsList @@ -67,10 +66,9 @@ export class PgSingleTablePolymorphicStep< const result: Array< PromiseOrDirect> | null> > = []; - const valuesList = values[this.typeStepId]; - const unaryList = unaries[this.typeStepId]; + const valuesDep = values[this.typeStepId]; for (let i = 0; i < count; i++) { - const v = valuesList === null ? unaryList : valuesList[i]; + const v = valuesDep.at(i); result[i] = v ? polymorphicWrap(v) : null; } return result; diff --git a/grafast/dataplan-pg/src/steps/pgUnionAll.ts b/grafast/dataplan-pg/src/steps/pgUnionAll.ts index 76a24891d3..917a4de0cd 100644 --- a/grafast/dataplan-pg/src/steps/pgUnionAll.ts +++ b/grafast/dataplan-pg/src/steps/pgUnionAll.ts @@ -328,18 +328,22 @@ export class PgUnionAllSingleStep executeV2({ count, values: [values0], - unaries: [unaries0], }: ExecutionDetails): GrafastResultsList { if (this.typeKey !== null) { const typeKey = this.typeKey; - return values0 === null - ? arrayOfLength(count, polymorphicWrap(unaries0[typeKey], unaries0)) - : values0.map((v) => { + return values0.isBatch + ? values0.entries.map((v) => { const type = v[typeKey]; return polymorphicWrap(type, v); - }); + }) + : arrayOfLength( + count, + polymorphicWrap(values0.value[typeKey], values0.value), + ); } else { - return values0 === null ? arrayOfLength(count, unaries0) : values0; + return values0.isBatch + ? values0.entries + : arrayOfLength(count, values0.value); } } } @@ -1933,21 +1937,19 @@ ${lateralText};`; async executeV2({ count, values, - unaries, extra: { eventEmitter }, }: ExecutionDetails): Promise> { const { text, rawSqlValues, identifierIndex, shouldReverseOrder, name } = this.finalizeResults!; - const contextValues = values[this.contextId]; - const contextUnary = unaries[this.contextId]; - if (contextValues === undefined) { + const contextDep = values[this.contextId]; + if (contextDep === undefined) { throw new Error("We have no context dependency?"); } const specs: Array> = []; for (let i = 0; i < count; i++) { - const context = contextValues === null ? contextUnary : contextValues[i]; + const context = contextDep.at(i); specs.push({ // The context is how we'd handle different connections with different claims context, @@ -1955,11 +1957,7 @@ ${lateralText};`; identifierIndex != null ? this.queryValues.map( ({ dependencyIndex, codec, alreadyEncoded }) => { - const depValues = values[dependencyIndex]; - const val = - depValues === null - ? unaries[dependencyIndex] - : depValues[i]; + const val = values[dependencyIndex].at(i); return val == null ? null : alreadyEncoded diff --git a/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts b/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts index 9d5c207332..1a91688879 100644 --- a/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts +++ b/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts @@ -308,15 +308,13 @@ export class PgUpdateSingleStep< async executeV2({ count, values, - unaries, }: ExecutionDetails): Promise> { if (!this.finalizeResults) { throw new Error("Cannot execute PgSelectStep before finalizing it."); } const { text, rawSqlValues, queryValueDetailsBySymbol } = this.finalizeResults; - const contextValues = values[this.contextId]; - const contextUnary = unaries[this.contextId]; + const contextDep = values[this.contextId]; // We must execute each mutation on its own, but we can at least do so in // parallel. Note we return a list of promises, each may reject or resolve @@ -325,8 +323,7 @@ export class PgUpdateSingleStep< for (let i = 0; i < count; i++) { promises.push( (async () => { - const context = - contextValues === null ? contextUnary! : contextValues[i]; + const context = contextDep.at(i); const sqlValues = queryValueDetailsBySymbol.size ? rawSqlValues.map((v) => { if (typeof v === "symbol") { @@ -334,9 +331,7 @@ export class PgUpdateSingleStep< if (!details) { throw new Error(`Saw unexpected symbol '${inspect(v)}'`); } - const depValues = values[details.depId]; - const val = - depValues === null ? unaries[details.depId] : depValues[i]; + const val = values[details.depId].at(i); return val == null ? null : details.processor(val); } else { return v; diff --git a/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts b/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts index 51b83d0b2f..2be581ee6d 100644 --- a/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts +++ b/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts @@ -39,12 +39,13 @@ export class PgValidateParsedCursorStep extends ExecutableStep { executeV2({ count, - values: [values0], - unaries: [unaries0], + values: [parsedCursorDep], }: ExecutionDetails<[string | null]>): GrafastResultsList { const results: any[] = []; for (let i = 0; i < count; i++) { - const decoded = values0 === null ? unaries0 : values0[i]; + const decoded = parsedCursorDep.isBatch + ? parsedCursorDep.entries[i] + : parsedCursorDep.value; if (!decoded) { results.push(undefined); } else { diff --git a/grafast/dataplan-pg/src/steps/withPgClient.ts b/grafast/dataplan-pg/src/steps/withPgClient.ts index 9838dd31ac..462c0ec766 100644 --- a/grafast/dataplan-pg/src/steps/withPgClient.ts +++ b/grafast/dataplan-pg/src/steps/withPgClient.ts @@ -55,18 +55,15 @@ export class WithPgClientStep< executeV2({ count, values, - unaries, }: ExecutionDetails< [{ pgSettings: any; withPgClient: WithPgClient }, TData] >): GrafastResultsList { - const contextValues = values[this.contextId as 0]; - const unaryContext = unaries[this.contextId as 0]; - const dataValues = values[this.dataId as 1]; - const dataUnary = unaries[this.dataId as 1]; + const contextDep = values[this.contextId as 0]; + const dataDep = values[this.dataId as 1]; const promises: Promise[] = []; for (let i = 0; i < count; i++) { - const context = contextValues === null ? unaryContext! : contextValues[i]; - const data = dataValues === null ? dataUnary! : dataValues[i]; + const context = contextDep.at(i); + const data = dataDep.at(i); const { withPgClient, pgSettings } = context; promises.push( withPgClient(pgSettings, (client) => this.callback(client, data)), diff --git a/grafast/grafast/__tests__/errorHandling-test.ts b/grafast/grafast/__tests__/errorHandling-test.ts index 9d49e6e060..9ec782068a 100644 --- a/grafast/grafast/__tests__/errorHandling-test.ts +++ b/grafast/grafast/__tests__/errorHandling-test.ts @@ -29,25 +29,20 @@ class SyncListCallbackStep< executeV2({ count, values: [values0], - unaries: [unaries0], }: ExecutionDetails<[TIn]>): Array> { let result: PromiseOrDirect[] = []; for (let i = 0; i < count; i++) { - const entry = values0 !== null ? values0[i] : unaries0!; + const entry = values0.at(i); result.push(this.callback(entry)); } return result; } - async streamV2({ - count, - values: [values0], - unaries: [unaries0], - }: ExecutionDetails<[TIn]>) { + async streamV2({ count, values: [values0] }: ExecutionDetails<[TIn]>) { await sleep(0); const { callback } = this; const results: any[] = []; for (let i = 0; i < count; i++) { - const entry = values0 === null ? unaries0! : values0[i]; + const entry = values0.at(i); results.push( (async function* () { const data = await callback(entry); diff --git a/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts b/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts index 8000536162..5d62917233 100644 --- a/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts +++ b/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts @@ -32,25 +32,20 @@ class SyncListCallbackStep< executeV2({ count, values: [values0], - unaries: [unary0], }: ExecutionDetails<[TIn]>): Array> { let result: PromiseOrDirect[] = []; for (let i = 0; i < count; i++) { - const entry = values0 !== null ? values0[i] : unary0!; + const entry = values0.at(i); result.push(this.callback(entry)); } return result; } - async streamV2({ - count, - values: [values0], - unaries: [unaries0], - }: StreamDetails<[TIn]>) { + async streamV2({ count, values: [values0] }: StreamDetails<[TIn]>) { await sleep(0); const { callback, setStreaming } = this; const results: any[] = []; for (let i = 0; i < count; i++) { - const entry = values0 === null ? unaries0! : values0[i]; + const entry = values0.at(i); setStreaming(true); results.push( diff --git a/grafast/grafast/__tests__/stream-test.ts b/grafast/grafast/__tests__/stream-test.ts index 7ee02baa3d..d244dbd68d 100644 --- a/grafast/grafast/__tests__/stream-test.ts +++ b/grafast/grafast/__tests__/stream-test.ts @@ -32,24 +32,19 @@ class SyncListCallbackStep< executeV2({ count, values: [values0], - unaries: [unary0], }: ExecutionDetails<[TIn]>): Array> { let result: PromiseOrDirect[] = []; for (let i = 0; i < count; i++) { - const entry = values0 !== null ? values0[i] : unary0!; + const entry = values0.at(i); result.push(this.callback(entry)); } return result; } - streamV2({ - count, - values: [values0], - unaries: [unaries0], - }: StreamDetails<[TIn]>) { + streamV2({ count, values: [values0] }: StreamDetails<[TIn]>) { const { callback } = this; let results: any[] = []; for (let i = 0; i < count; i++) { - const entry = values0 === null ? unaries0! : values0[i]; + const entry = values0.at(i); results.push( (async function* () { const data = await callback(entry); diff --git a/grafast/grafast/__tests__/unaryDeps-test.ts b/grafast/grafast/__tests__/unaryDeps-test.ts index 405154e754..7b200f9870 100644 --- a/grafast/grafast/__tests__/unaryDeps-test.ts +++ b/grafast/grafast/__tests__/unaryDeps-test.ts @@ -52,7 +52,7 @@ function run(db: sqlite3.Database, sql: string, values: any[] = []) { class GetRecordsStep> extends ExecutableStep { depIdByIdentifier: Record; - dbDepId: string | number; + dbDepId: number; constructor( private tableName: string, identifiers: Record = Object.create(null), @@ -86,10 +86,9 @@ class GetRecordsStep> extends ExecutableStep { async executeV2({ count, values, - unaries, }: ExecutionDetails): Promise> { - const db = unaries[this.dbDepId] as sqlite3.Database; - const first = this.firstUDI != null ? unaries[this.firstUDI] : null; + const db = values[this.dbDepId].value as sqlite3.Database; + const first = this.firstUDI != null ? values[this.firstUDI].value : null; const identifierCols = Object.keys(this.depIdByIdentifier); @@ -138,7 +137,7 @@ ${orderBy ? `order by ${orderBy}` : ""} const obj = Object.fromEntries( Object.entries(this.depIdByIdentifier).map(([col, depId]) => [ col, - values[depId] ? values[depId][i] : unaries[depId], + values[depId].at(i), ]), ); json.push(obj); @@ -151,10 +150,7 @@ ${orderBy ? `order by ${orderBy}` : ""} for (let i = 0; i < count; i++) { // This could be more optimal by leveraging they're already in order results[i] = dbResults.filter((r) => { - return entries.every( - ([col, depId]) => - r[col] === (values[depId] ? values[depId][i] : unaries[depId]), - ); + return entries.every(([col, depId]) => r[col] === values[depId].at(i)); }); } return results; diff --git a/grafast/grafast/src/engine/executeBucket.ts b/grafast/grafast/src/engine/executeBucket.ts index 7abac4f1bf..f74cbebed2 100644 --- a/grafast/grafast/src/engine/executeBucket.ts +++ b/grafast/grafast/src/engine/executeBucket.ts @@ -13,6 +13,7 @@ import { import { inspect } from "../inspect.js"; import type { ExecutionExtra, + ExecutionValue, GrafastResultsList, GrafastResultStreamList, PromiseOrDirect, @@ -668,8 +669,7 @@ export function executeBucket( function executeOrStream( count: number, step: ExecutableStep, - values: Array | null>, - unaries: Array, + values: Array, extra: ExecutionExtra, ): PromiseOrDirect | GrafastResultStreamList> { if (isDev && step._isUnary && count !== 1) { @@ -682,18 +682,17 @@ export function executeBucket( return step.streamV2({ count, values, - unaries, extra, streamOptions, }); } else if (streamOptions && isStreamableStep(step)) { // Backwards compatibility const backfilledValues = values.map((v, i) => - v === null ? arrayOfLength(count, unaries[i]) : v, + v.isBatch ? v.entries : arrayOfLength(count, v.value), ); return step.stream(count, backfilledValues, extra, streamOptions); } else { - return step.executeV2({ count, values, unaries, extra }); + return step.executeV2({ count, values, extra }); } } @@ -705,8 +704,7 @@ export function executeBucket( */ function reallyExecuteStepWithErrorsOrSelective( step: ExecutableStep, - dependenciesIncludingSideEffects: Array | null>, - unariesIncludingSideEffects: Array, + dependenciesIncludingSideEffects: Array, polymorphicPathList: readonly (string | null)[], extra: ExecutionExtra, ): PromiseOrDirect | GrafastResultStreamList> { @@ -720,11 +718,9 @@ export function executeBucket( let newSize = 0; const stepPolymorphicPaths = step.polymorphicPaths; const legitDepsCount = sudo(step).dependencies.length; - let dependencies = ( - sideEffectStepsWithErrors - ? dependenciesIncludingSideEffects.slice(0, legitDepsCount) - : dependenciesIncludingSideEffects - ) as (any[] | null)[]; + let dependencies = sideEffectStepsWithErrors + ? dependenciesIncludingSideEffects.slice(0, legitDepsCount) + : dependenciesIncludingSideEffects; // OPTIM: if unariesIncludingSideEffects.some(isGrafastError) then shortcut execution because everything fails @@ -760,8 +756,7 @@ export function executeBucket( i < l; i++ ) { - const depList = dependenciesIncludingSideEffects[i]; - const v = depList ? depList[index] : unariesIncludingSideEffects[i]; + const v = dependenciesIncludingSideEffects[i].at(index); if (isGrafastError(v)) { indexError = v; break; @@ -775,7 +770,9 @@ export function executeBucket( foundErrors = true; // Clone up until this point, make mutable, don't add self dependencies = dependencies.map((depList) => - depList ? depList.slice(0, index) : depList, + depList.isBatch + ? batchExecutionValue(depList.entries.slice(0, index)) + : depList, ); } errors[index] = indexError; @@ -789,21 +786,15 @@ export function executeBucket( depListIndex++ ) { const depList = dependencies[depListIndex]; - if (depList) { - depList.push( - dependenciesIncludingSideEffects[depListIndex]![index], - ); + if (depList.isBatch) { + const depVal = dependenciesIncludingSideEffects[depListIndex]; + (depList.entries as any[]).push(depVal.at(index)); } } } } } - // Trim the side-effect dependencies back out again - const unaries = sideEffectStepsWithErrors - ? unariesIncludingSideEffects.slice(0, legitDepsCount) - : unariesIncludingSideEffects; - if (newSize === 0) { // Everything is errors; we can skip execution return Object.values(errors); @@ -812,7 +803,6 @@ export function executeBucket( newSize, step, dependencies, - unaries, extra, ); if (isPromiseLike(resultWithoutErrors)) { @@ -823,13 +813,7 @@ export function executeBucket( return mergeErrorsBackIn(resultWithoutErrors, errors, size); } } else { - return reallyExecuteStepWithNoErrors( - newSize, - step, - dependencies, - unaries, - extra, - ); + return reallyExecuteStepWithNoErrors(newSize, step, dependencies, extra); } } @@ -842,7 +826,6 @@ export function executeBucket( try { const meta = step.metaKey !== undefined ? metaByMetaKey[step.metaKey] : undefined; - const unaries: Array = []; const extra: ExecutionExtra = { stopTime, meta, @@ -850,18 +833,16 @@ export function executeBucket( _bucket: bucket, _requestContext: requestContext, }; - const dependencies: Array | null> = []; + const dependencies: Array = []; const sstep = sudo(step); const depCount = sstep.dependencies.length; if (depCount > 0 || sideEffectStepsWithErrors !== null) { for (let i = 0, l = depCount; i < l; i++) { const $dep = sstep.dependencies[i]; if ($dep._isUnary) { - dependencies[i] = null; - unaries[i] = unaryStore.get($dep.id); + dependencies[i] = unaryExecutionValue(unaryStore.get($dep.id)); } else { - dependencies[i] = store.get($dep.id)!; - unaries[i] = null; + dependencies[i] = batchExecutionValue(store.get($dep.id)!); } } if (sideEffectStepsWithErrors !== null) { @@ -872,16 +853,10 @@ export function executeBucket( const sideEffectStoreEntry = unaryStore.get( sideEffectStep.id, )!; - if (!unaries.includes(sideEffectStoreEntry)) { - dependencies.push(null); - unaries.push(sideEffectStoreEntry); - } + dependencies.push(unaryExecutionValue(sideEffectStoreEntry)); } else { const sideEffectStoreEntry = store.get(sideEffectStep.id)!; - if (!dependencies.includes(sideEffectStoreEntry)) { - dependencies.push(sideEffectStoreEntry); - unaries.push(null); - } + dependencies.push(batchExecutionValue(sideEffectStoreEntry)); } } } @@ -891,16 +866,10 @@ export function executeBucket( ]) { if (sideEffectStep._isUnary) { const sideEffectStoreEntry = unaryStore.get(sideEffectStep.id)!; - if (!unaries.includes(sideEffectStoreEntry)) { - dependencies.push(null); - unaries.push(sideEffectStoreEntry); - } + dependencies.push(unaryExecutionValue(sideEffectStoreEntry)); } else { const sideEffectStoreEntry = store.get(sideEffectStep.id)!; - if (!dependencies.includes(sideEffectStoreEntry)) { - dependencies.push(sideEffectStoreEntry); - unaries.push(null); - } + dependencies.push(batchExecutionValue(sideEffectStoreEntry)); } } } @@ -924,7 +893,6 @@ export function executeBucket( ? reallyExecuteStepWithErrorsOrSelective( step, dependencies, - unaries, bucket.polymorphicPathList, extra, ) @@ -932,7 +900,6 @@ export function executeBucket( step._isUnary ? 1 : size, step, dependencies, - unaries, extra, ); if (isPromiseLike(result)) { @@ -1101,3 +1068,23 @@ export function newBucket( children: Object.create(null), }; } + +function batchExecutionValue(entries: TData[]): ExecutionValue { + return { + isBatch: true, + entries, + at(i) { + return entries[i]; + }, + }; +} + +function unaryExecutionValue(value: TData): ExecutionValue { + return { + isBatch: false, + value, + at() { + return value; + }, + }; +} diff --git a/grafast/grafast/src/interfaces.ts b/grafast/grafast/src/interfaces.ts index 1f8434c07d..2cbb41061c 100644 --- a/grafast/grafast/src/interfaces.ts +++ b/grafast/grafast/src/interfaces.ts @@ -774,16 +774,25 @@ export interface ExecutionExtraBase { export interface ExecutionExtra extends ExecutionExtraBase {} export interface UnbatchedExecutionExtra extends ExecutionExtraBase {} +export type ExecutionValue = + | { + isBatch: true; + entries: ReadonlyArray; + value?: never; + at(i: number): TData; + } + | { isBatch: false; value: TData; entries?: never; at(i: number): TData }; + export interface ExecutionDetails< TDeps extends readonly [...any[]] = readonly [...any[]], > { count: number; values: { - [DepIdx in keyof TDeps]: GrafastValuesList | null; - } & { length: TDeps["length"] }; - unaries: { - [DepIdx in keyof TDeps]: null | TDeps[DepIdx]; - } & { length: TDeps["length"] }; + [DepIdx in keyof TDeps]: ExecutionValue; + } & { + length: TDeps["length"]; + map: ReadonlyArray>["map"]; + }; extra: ExecutionExtra; } export interface StreamDetails< diff --git a/grafast/grafast/src/step.ts b/grafast/grafast/src/step.ts index 0fb5b895e6..3c25cc068f 100644 --- a/grafast/grafast/src/step.ts +++ b/grafast/grafast/src/step.ts @@ -387,9 +387,10 @@ export /* abstract */ class ExecutableStep extends BaseStep { } /** - * Adds "unary" dependencies; in `execute(count, values, extra)` you'll - * be able to access the value via `extra.unaries[key]` where `key` is the - * return value of this function. + * Adds "unary" dependencies; in `executeV2({count, values})` you'll receive a + * `values[index]` (where `index` is the return value of this function) with + * `isBatch = false` so you can use the `values[index].value` property + * directly. */ protected addUnaryDependency(step: ExecutableStep): number { return this.operationPlan.stepTracker.addStepUnaryDependency(this, step); @@ -486,12 +487,11 @@ export /* abstract */ class ExecutableStep extends BaseStep { executeV2({ count, values, - unaries, extra, }: ExecutionDetails): PromiseOrDirect> { // TODO: warn that this class should implement executeV2 instead const backfilledValues = values.map((v, i) => - v === null ? arrayOfLength(count, unaries[i]) : v, + v.isBatch ? v.entries[i] : arrayOfLength(count, v.value), ); return this.execute(count, backfilledValues, extra); } @@ -515,9 +515,9 @@ function _buildOptimizedExecuteV2Expression( depCount: number, isSyncAndSafe: boolean, ) { - const depIndexes = []; + const identifiers: TE[] = []; for (let i = 0; i < depCount; i++) { - depIndexes.push(i); + identifiers.push(te.identifier(`value${i}`)); } const tryOrNot = (inFrag: TE): TE => { if (isSyncAndSafe) { @@ -535,27 +535,14 @@ function _buildOptimizedExecuteV2Expression( return te`\ (function execute({ count, - values: [${te.join( - depIndexes.map((i) => te.identifier(`list${i}`)), - ", ", - )}\ - ], - unaries: [${te.join( - depIndexes.map((i) => te.identifier(`val${i}`)), - ", ", - )}], + values: [${te.join(identifiers, ", ")}], extra, }) { const results = []; for (let i = 0; i < count; i++) { ${tryOrNot(te`\ results[i] = this.unbatchedExecute(extra, ${te.join( - depIndexes.map( - (depIndex) => - te`${te.identifier(`list${depIndex}`)} === null ? ${te.identifier( - `val${depIndex}`, - )} : ${te.identifier(`list${depIndex}`)}[i]`, - ), + identifiers.map((identifier) => te`${identifier}.at(i)`), ", ", )});\ `)} @@ -640,7 +627,6 @@ export abstract class UnbatchedExecutableStep< executeV2({ count, values, - unaries, extra, }: ExecutionDetails): PromiseOrDirect> { console.warn( @@ -649,9 +635,7 @@ export abstract class UnbatchedExecutableStep< const results = []; for (let i = 0; i < count; i++) { try { - const tuple = values.map((list, depIndex) => - list === null ? unaries[depIndex] : list[i], - ); + const tuple = values.map((list) => list.at(i)); results[i] = this.unbatchedExecute(extra, ...tuple); } catch (e) { results[i] = e instanceof Error ? (e as never) : Promise.reject(e); diff --git a/grafast/grafast/src/steps/__trackedValue.ts b/grafast/grafast/src/steps/__trackedValue.ts index 2056370f87..9a43c6dab7 100644 --- a/grafast/grafast/src/steps/__trackedValue.ts +++ b/grafast/grafast/src/steps/__trackedValue.ts @@ -154,10 +154,11 @@ export class __TrackedValueStep< executeV2({ count, values: [values0], - unaries: [unaries0], }: ExecutionDetails<[TData]>): GrafastResultsList { // We have only one dependency, return the value of that. - return values0 === null ? arrayOfLength(count, unaries0) : values0; + return values0.isBatch + ? values0.entries + : arrayOfLength(count, values0.value); } unbatchedExecute(_extra: UnbatchedExecutionExtra, v: TData): TData { diff --git a/grafast/grafast/src/steps/applyTransforms.ts b/grafast/grafast/src/steps/applyTransforms.ts index 1d34662e87..24186d0e76 100644 --- a/grafast/grafast/src/steps/applyTransforms.ts +++ b/grafast/grafast/src/steps/applyTransforms.ts @@ -77,7 +77,6 @@ export class ApplyTransformsStep extends ExecutableStep { async executeV2({ count, values: [values0], - unaries: [unaries0], extra, }: ExecutionDetails<[any[] | null | undefined | GrafastError]>): Promise< GrafastResultsList @@ -133,7 +132,9 @@ export class ApplyTransformsStep extends ExecutableStep { // We'll typically be creating more listItem bucket entries than we // have parent buckets, so we must "multiply up" the store entries. for (let originalIndex = 0; originalIndex < count; originalIndex++) { - const list = values0 === null ? unaries0! : values0[originalIndex]; + const list = values0.isBatch + ? values0.entries[originalIndex] + : values0.value; if (Array.isArray(list)) { const newIndexes: number[] = []; map.set(originalIndex, newIndexes); @@ -180,7 +181,9 @@ export class ApplyTransformsStep extends ExecutableStep { const results: any[] = []; for (let originalIndex = 0; originalIndex < count; originalIndex++) { - const list = values0 === null ? unaries0! : values0[originalIndex]; + const list = values0.isBatch + ? values0.entries[originalIndex] + : values0.value; if (list == null) { results.push(list); continue; diff --git a/grafast/grafast/src/steps/first.ts b/grafast/grafast/src/steps/first.ts index 8d6cd48f86..e0f2e745f6 100644 --- a/grafast/grafast/src/steps/first.ts +++ b/grafast/grafast/src/steps/first.ts @@ -23,12 +23,12 @@ export class FirstStep extends UnbatchedExecutableStep { executeV2({ count, values: [values0], - unaries: [unaries0], }: ExecutionDetails<[TData[]]>): GrafastResultsList { const result: Array = []; for (let i = 0; i < count; i++) { - // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain - result[i] = values0 === null ? unaries0?.[0]! : values0[i]?.[0]; + result[i] = values0.isBatch + ? values0.entries[i]?.[0] + : values0.value?.[0]; } return result; } diff --git a/grafast/grafast/src/steps/graphqlResolver.ts b/grafast/grafast/src/steps/graphqlResolver.ts index 3307c1a906..d63c177a72 100644 --- a/grafast/grafast/src/steps/graphqlResolver.ts +++ b/grafast/grafast/src/steps/graphqlResolver.ts @@ -188,7 +188,6 @@ export class GraphQLResolverStep extends UnbatchedExecutableStep { async streamV2({ count, values, - unaries, extra, }: ExecutionDetails): Promise> { const results = []; @@ -197,8 +196,7 @@ export class GraphQLResolverStep extends UnbatchedExecutableStep { try { const tuple = []; for (let j = 0; j < depCount; j++) { - const depValue = values[j]; - tuple[j] = depValue === null ? unaries[j] : depValue[i]; + tuple[j] = values[j].at(i); } results[i] = (this.unbatchedStream as any)(extra, ...tuple); } catch (e) { @@ -317,14 +315,13 @@ export class GraphQLItemHandler executeV2({ count, values: [values0], - unaries: [unaries0], }: ExecutionDetails< [Awaited>] >): GrafastResultsList { if (this.abstractType !== undefined) { const results: any[] = []; for (let i = 0; i < count; i++) { - const data = values0 !== null ? values0[i] : unaries0; + const data = values0.at(i); if (data == null) { results.push(data); } else if (isPromiseLike(data.data)) { @@ -347,7 +344,7 @@ export class GraphQLItemHandler } else if (this.nullableInnerType != null) { const results: any[] = []; for (let i = 0; i < count; i++) { - const d = values0 !== null ? values0[i] : unaries0; + const d = values0.at(i); if (d == null) { results.push(null); } else { diff --git a/grafast/grafast/src/steps/list.ts b/grafast/grafast/src/steps/list.ts index fa1c9d3853..83085b64b0 100644 --- a/grafast/grafast/src/steps/list.ts +++ b/grafast/grafast/src/steps/list.ts @@ -31,13 +31,11 @@ export class ListStep< } executeV2( - { count, values, unaries }: ExecutionDetails, //UnwrapPlanTuple, + { count, values }: ExecutionDetails, //UnwrapPlanTuple, ): Array> { const result: any[] = []; for (let i = 0; i < count; i++) { - result[i] = values.map((list, depIndex) => - list === null ? unaries[depIndex] : list[i], - ); + result[i] = values.map((value) => value.at(i)); } return result; } diff --git a/grafast/grafast/src/steps/listTransform.ts b/grafast/grafast/src/steps/listTransform.ts index a227c70f2d..5e39f96288 100644 --- a/grafast/grafast/src/steps/listTransform.ts +++ b/grafast/grafast/src/steps/listTransform.ts @@ -199,7 +199,6 @@ export class __ListTransformStep< async executeV2({ count, values, - unaries, extra, }: ExecutionDetails<[any[] | null | undefined | GrafastError]>): Promise< GrafastResultsList @@ -252,14 +251,14 @@ export class __ListTransformStep< } } - const listStepValues = values[this.listStepDepId]; - const listStepUnary = unaries[this.listStepDepId]; + const listStepValue = values[this.listStepDepId]; // We'll typically be creating more listItem bucket entries than we // have parent buckets, so we must "multiply up" the store entries. for (let originalIndex = 0; originalIndex < count; originalIndex++) { - const list = - listStepValues === null ? listStepUnary : listStepValues[originalIndex]; + const list = listStepValue.isBatch + ? listStepValue.entries[originalIndex] + : listStepValue.value; if (Array.isArray(list)) { const newIndexes: number[] = []; map.set(originalIndex, newIndexes); @@ -306,8 +305,9 @@ export class __ListTransformStep< const results: any[] = []; for (let originalIndex = 0; originalIndex < count; originalIndex++) { - const list = - listStepValues === null ? listStepUnary : listStepValues[originalIndex]; + const list = listStepValue.isBatch + ? listStepValue.entries[originalIndex] + : listStepValue.value; if (list == null) { results.push(list); diff --git a/grafast/grafast/src/steps/listen.ts b/grafast/grafast/src/steps/listen.ts index cbe8a17a7c..77bf641040 100644 --- a/grafast/grafast/src/steps/listen.ts +++ b/grafast/grafast/src/steps/listen.ts @@ -66,17 +66,16 @@ export class ListenStep< streamV2({ count, values, - unaries, }: StreamDetails< readonly [GrafastSubscriber, TTopic] >): GrafastResultStreamList { - const pubsubValues = values[this.pubsubDep as 0]; - const pubsubUnary = unaries[this.pubsubDep as 0]; - const topicValues = values[this.topicDep as 1]; - const topicUnary = unaries[this.topicDep as 1]; + const pubsubValue = values[this.pubsubDep as 0]; + const topicValue = values[this.topicDep as 1]; const result = []; for (let i = 0; i < count; i++) { - const pubsub = pubsubValues === null ? pubsubUnary : pubsubValues[i]; + const pubsub = pubsubValue.isBatch + ? pubsubValue.entries[i] + : pubsubValue.value; if (!pubsub) { throw new SafeError( "Subscription not supported", @@ -89,7 +88,9 @@ export class ListenStep< : {}, ); } - const topic = topicValues === null ? topicUnary! : topicValues[i]; + const topic = topicValue.isBatch + ? topicValue.entries[i] + : topicValue.value; result[i] = pubsub.subscribe(topic); } return result; diff --git a/grafast/grafast/src/steps/load.ts b/grafast/grafast/src/steps/load.ts index 9e258058b3..4f34678fa5 100644 --- a/grafast/grafast/src/steps/load.ts +++ b/grafast/grafast/src/steps/load.ts @@ -155,9 +155,10 @@ export class LoadedRecordStep< executeV2({ count, values: [values0], - unaries: [unaries0], }: ExecutionDetails<[TItem]>): GrafastResultsList { - return values0 === null ? arrayOfLength(count, unaries0) : values0; + return values0.isBatch + ? values0.entries + : arrayOfLength(count, values0.value); } } @@ -288,7 +289,6 @@ export class LoadStep< executeV2({ count, values: [values0], - unaries: [unaries0], extra, }: ExecutionDetails<[TSpec]>): PromiseOrDirect< GrafastResultsList> @@ -303,7 +303,7 @@ export class LoadStep< const results: Array>> = []; for (let i = 0; i < count; i++) { - const spec = values0 === null ? unaries0! : values0[i]; + const spec = values0.at(i); if (cache.has(spec)) { results.push(cache.get(spec)!); } else { diff --git a/grafast/grafast/src/steps/object.ts b/grafast/grafast/src/steps/object.ts index 8c7ad12cdf..a75a6b5548 100644 --- a/grafast/grafast/src/steps/object.ts +++ b/grafast/grafast/src/steps/object.ts @@ -219,17 +219,13 @@ ${inner} executeV2({ count, values, - unaries, extra, }: ExecutionDetails[keyof TPlans]>>): Array< DataFromPlans > { const result: Array> = []; for (let i = 0; i < count; i++) { - result[i] = this.unbatchedExecute!( - extra, - ...values.map((v, depIndex) => (v === null ? unaries[depIndex] : v[i])), - ); + result[i] = this.unbatchedExecute!(extra, ...values.map((v) => v.at(i))); } return result; } diff --git a/grafast/grafast/src/steps/polymorphicBranch.ts b/grafast/grafast/src/steps/polymorphicBranch.ts index d7662e1b12..e25b248691 100644 --- a/grafast/grafast/src/steps/polymorphicBranch.ts +++ b/grafast/grafast/src/steps/polymorphicBranch.ts @@ -74,11 +74,10 @@ export class PolymorphicBranchStep executeV2({ count, values: [values0], - unaries: [unaries0], }: ExecutionDetails): PromiseOrDirect> { const results: any[] = []; for (let i = 0; i < count; i++) { - const obj = values0 !== null ? values0[i] : unaries0!; + const obj = values0.at(i); let match: string | null = null; if (obj != null) { for (const typeName of this.typeNames) { diff --git a/grafast/grafast/src/steps/proxy.ts b/grafast/grafast/src/steps/proxy.ts index e10df5fca2..29b7ad43a7 100644 --- a/grafast/grafast/src/steps/proxy.ts +++ b/grafast/grafast/src/steps/proxy.ts @@ -36,9 +36,10 @@ export class ProxyStep extends UnbatchedExecutableStep { executeV2({ count, values: [values0], - unaries: [unaries0], }: ExecutionDetails<[T]>): GrafastResultsList { - return values0 === null ? arrayOfLength(count, unaries0) : values0; + return values0.isBatch + ? values0.entries + : arrayOfLength(count, values0.value); } unbatchedExecute(_extra: UnbatchedExecutionExtra, value: T): T { return value; diff --git a/grafast/grafast/src/steps/remapKeys.ts b/grafast/grafast/src/steps/remapKeys.ts index d16e3bfca9..90e71db7d9 100644 --- a/grafast/grafast/src/steps/remapKeys.ts +++ b/grafast/grafast/src/steps/remapKeys.ts @@ -102,11 +102,10 @@ export class RemapKeysStep extends UnbatchedExecutableStep { executeV2({ count, values: [values0], - unaries: [unaries0], }: ExecutionDetails): GrafastResultsList { const results: any[] = []; for (let i = 0; i < count; i++) { - results.push(this.mapper(values0 === null ? unaries0 : values0[i])); + results.push(this.mapper(values0.at(i))); } return results; } diff --git a/grafast/grafast/src/steps/reverse.ts b/grafast/grafast/src/steps/reverse.ts index c7b261ffb1..c564536d0f 100644 --- a/grafast/grafast/src/steps/reverse.ts +++ b/grafast/grafast/src/steps/reverse.ts @@ -44,11 +44,10 @@ export class ReverseStep extends UnbatchedExecutableStep< executeV2({ count, values: [values0], - unaries: [unaries0], }: ExecutionDetails<[TData[]]>): GrafastResultsList { const results: any[] = []; for (let i = 0; i < count; i++) { - const arr = values0 === null ? unaries0 : values0[i]; + const arr = values0.at(i); results.push(arr == null ? arr : reverseArray(arr)); } return results; From 386e79474e2b265ef77269f421b96ead1af25164 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 28 Feb 2024 10:12:54 +0000 Subject: [PATCH 35/48] Lint --- grafast/dataplan-pg/src/steps/pgDeleteSingle.ts | 1 - grafast/dataplan-pg/src/steps/pgInsertSingle.ts | 1 - grafast/dataplan-pg/src/steps/pgUnionAll.ts | 1 - grafast/dataplan-pg/src/steps/pgUpdateSingle.ts | 7 +------ grafast/grafast/src/engine/executeBucket.ts | 2 +- grafast/grafast/src/steps/applyTransforms.ts | 7 +------ grafast/grafast/src/steps/graphqlResolver.ts | 1 - grafast/grafast/src/steps/listTransform.ts | 6 +----- 8 files changed, 4 insertions(+), 22 deletions(-) diff --git a/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts b/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts index 85f1f1dbab..211748dcaa 100644 --- a/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts +++ b/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts @@ -1,7 +1,6 @@ import type { ExecutionDetails, GrafastResultsList, - GrafastValuesList, PromiseOrDirect, } from "grafast"; import { ExecutableStep, exportAs, isDev, SafeError } from "grafast"; diff --git a/grafast/dataplan-pg/src/steps/pgInsertSingle.ts b/grafast/dataplan-pg/src/steps/pgInsertSingle.ts index 4767f9da6a..2fdd1e5a9e 100644 --- a/grafast/dataplan-pg/src/steps/pgInsertSingle.ts +++ b/grafast/dataplan-pg/src/steps/pgInsertSingle.ts @@ -1,7 +1,6 @@ import type { ExecutionDetails, GrafastResultsList, - GrafastValuesList, PromiseOrDirect, SetterCapableStep, SetterStep, diff --git a/grafast/dataplan-pg/src/steps/pgUnionAll.ts b/grafast/dataplan-pg/src/steps/pgUnionAll.ts index 917a4de0cd..10c2dfdd6c 100644 --- a/grafast/dataplan-pg/src/steps/pgUnionAll.ts +++ b/grafast/dataplan-pg/src/steps/pgUnionAll.ts @@ -6,7 +6,6 @@ import type { ConnectionStep, EdgeCapableStep, ExecutionDetails, - ExecutionExtra, GrafastResultsList, GrafastValuesList, InputStep, diff --git a/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts b/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts index 1a91688879..f2ffd07290 100644 --- a/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts +++ b/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts @@ -1,9 +1,4 @@ -import type { - ExecutionDetails, - GrafastResultsList, - GrafastValuesList, - SetterStep, -} from "grafast"; +import type { ExecutionDetails, GrafastResultsList, SetterStep } from "grafast"; import { ExecutableStep, exportAs, isDev, SafeError, setter } from "grafast"; import type { SQL, SQLRawValue } from "pg-sql2"; import sql from "pg-sql2"; diff --git a/grafast/grafast/src/engine/executeBucket.ts b/grafast/grafast/src/engine/executeBucket.ts index f74cbebed2..d6b4b705ce 100644 --- a/grafast/grafast/src/engine/executeBucket.ts +++ b/grafast/grafast/src/engine/executeBucket.ts @@ -687,7 +687,7 @@ export function executeBucket( }); } else if (streamOptions && isStreamableStep(step)) { // Backwards compatibility - const backfilledValues = values.map((v, i) => + const backfilledValues = values.map((v) => v.isBatch ? v.entries : arrayOfLength(count, v.value), ); return step.stream(count, backfilledValues, extra, streamOptions); diff --git a/grafast/grafast/src/steps/applyTransforms.ts b/grafast/grafast/src/steps/applyTransforms.ts index 24186d0e76..7529c278fb 100644 --- a/grafast/grafast/src/steps/applyTransforms.ts +++ b/grafast/grafast/src/steps/applyTransforms.ts @@ -6,12 +6,7 @@ import type { LayerPlanReasonSubroutine } from "../engine/LayerPlan.js"; import { LayerPlan } from "../engine/LayerPlan.js"; import { withGlobalLayerPlan } from "../engine/lib/withGlobalLayerPlan.js"; import type { GrafastError } from "../error.js"; -import type { - ExecutionDetails, - ExecutionExtra, - GrafastResultsList, - GrafastValuesList, -} from "../interfaces.js"; +import type { ExecutionDetails, GrafastResultsList } from "../interfaces.js"; import type { ListCapableStep } from "../step.js"; import { ExecutableStep, isListCapableStep } from "../step.js"; import { __ItemStep } from "./__item.js"; diff --git a/grafast/grafast/src/steps/graphqlResolver.ts b/grafast/grafast/src/steps/graphqlResolver.ts index d63c177a72..dfa6b65927 100644 --- a/grafast/grafast/src/steps/graphqlResolver.ts +++ b/grafast/grafast/src/steps/graphqlResolver.ts @@ -13,7 +13,6 @@ import type { ExecutionExtra, GrafastResultsList, GrafastResultStreamList, - GrafastValuesList, UnbatchedExecutionExtra, } from "../interfaces.js"; import { polymorphicWrap } from "../polymorphic.js"; diff --git a/grafast/grafast/src/steps/listTransform.ts b/grafast/grafast/src/steps/listTransform.ts index 5e39f96288..ca2ec47a11 100644 --- a/grafast/grafast/src/steps/listTransform.ts +++ b/grafast/grafast/src/steps/listTransform.ts @@ -7,11 +7,7 @@ import { LayerPlan } from "../engine/LayerPlan.js"; import { withGlobalLayerPlan } from "../engine/lib/withGlobalLayerPlan.js"; import type { GrafastError } from "../error.js"; import type { ConnectionCapableStep, ExecutionDetails } from "../index.js"; -import type { - ExecutionExtra, - GrafastResultsList, - GrafastValuesList, -} from "../interfaces.js"; +import type { GrafastResultsList } from "../interfaces.js"; import type { ListCapableStep } from "../step.js"; import { $$deepDepSkip, ExecutableStep, isListCapableStep } from "../step.js"; import { __ItemStep } from "./__item.js"; From f4bebc2138c84001ccfacb0a02b5524955e3c80c Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 28 Feb 2024 19:49:54 +0000 Subject: [PATCH 36/48] Update docs --- grafast/grafast/__tests__/unaryDeps-test.ts | 7 +- grafast/grafast/src/engine/executeBucket.ts | 10 +- grafast/grafast/src/interfaces.ts | 9 +- .../website/grafast/getting-started/index.mdx | 32 +-- grafast/website/grafast/index.mdx | 257 ++++++++++++++++-- grafast/website/grafast/step-classes.md | 214 ++++++++++----- 6 files changed, 399 insertions(+), 130 deletions(-) diff --git a/grafast/grafast/__tests__/unaryDeps-test.ts b/grafast/grafast/__tests__/unaryDeps-test.ts index 7b200f9870..1756f25a92 100644 --- a/grafast/grafast/__tests__/unaryDeps-test.ts +++ b/grafast/grafast/__tests__/unaryDeps-test.ts @@ -4,12 +4,7 @@ import type { ExecutionResult } from "graphql"; import { it } from "mocha"; import sqlite3 from "sqlite3"; -import type { - ExecutionDetails, - ExecutionExtra, - GrafastResultsList, - GrafastValuesList, -} from "../dist/index.js"; +import type { ExecutionDetails, GrafastResultsList } from "../dist/index.js"; import { access, context, diff --git a/grafast/grafast/src/engine/executeBucket.ts b/grafast/grafast/src/engine/executeBucket.ts index d6b4b705ce..56d9dd9ab3 100644 --- a/grafast/grafast/src/engine/executeBucket.ts +++ b/grafast/grafast/src/engine/executeBucket.ts @@ -1069,22 +1069,24 @@ export function newBucket( }; } +// TODO: memoize? function batchExecutionValue(entries: TData[]): ExecutionValue { return { - isBatch: true, - entries, at(i) { return entries[i]; }, + isBatch: true, + entries, }; } +// TODO: memoize? function unaryExecutionValue(value: TData): ExecutionValue { return { - isBatch: false, - value, at() { return value; }, + isBatch: false, + value, }; } diff --git a/grafast/grafast/src/interfaces.ts b/grafast/grafast/src/interfaces.ts index 2cbb41061c..7b16807a26 100644 --- a/grafast/grafast/src/interfaces.ts +++ b/grafast/grafast/src/interfaces.ts @@ -776,12 +776,17 @@ export interface UnbatchedExecutionExtra extends ExecutionExtraBase {} export type ExecutionValue = | { + at(i: number): TData; isBatch: true; entries: ReadonlyArray; value?: never; - at(i: number): TData; } - | { isBatch: false; value: TData; entries?: never; at(i: number): TData }; + | { + at(i: number): TData; + isBatch: false; + value: TData; + entries?: never; + }; export interface ExecutionDetails< TDeps extends readonly [...any[]] = readonly [...any[]], diff --git a/grafast/website/grafast/getting-started/index.mdx b/grafast/website/grafast/getting-started/index.mdx index d031cdd0f4..35cb4f9174 100644 --- a/grafast/website/grafast/getting-started/index.mdx +++ b/grafast/website/grafast/getting-started/index.mdx @@ -178,7 +178,7 @@ The building blocks of an operation plan are "steps." Steps are instances of "step classes," and makes available a modest range of [standard steps][] that you can use; but when these aren't enough you can write your own. Step classes extend the `ExecutableStep` class. The only required method to -define is `execute`, however most steps will also have a `constructor` in which +define is `executeV2`, however most steps will also have a `constructor` in which they accept their arguments (some of which may be dependencies) and may also have the various lifecycle methods. @@ -195,34 +195,16 @@ class AddStep extends ExecutableStep { this.addDependency($b); } - execute(count, [allA, allB]) { - const results = []; - for (let i = 0; i < count; i++) { - // `allA` and `allB` have the same length, which is `count`, and the - // entries at the same index in each list relate to each other. - const a = allA[i]; - const b = allB[i]; - results.push(a + b); - } - return results; + executeV2({ count, values: [aDep, bDep] }) { + return Array.from({ length: count }, (_, i) => { + const a = aDep.at(i); + const b = bDep.at(i); + return a + b; + }); } } ``` -:::tip - -The above example of `execute` is verbose to ease understanding, but could have -leveraged the knowledge that there's exactly two dependencies and that the two -lists have the same length in order to use a much more concise implementation: - -```ts - execute(count, [allA, allB]) { - return allA.map((a, i) => a + allB[i]); - } -``` - -::: - By convention, we always define a function that constructs an instance of our class: diff --git a/grafast/website/grafast/index.mdx b/grafast/website/grafast/index.mdx index 5269c12d4c..dba28a7288 100644 --- a/grafast/website/grafast/index.mdx +++ b/grafast/website/grafast/index.mdx @@ -1,6 +1,7 @@ --- sidebar_position: 1 title: "Grafast Introduction" +toc_max_heading_level: 4 --- import Mermaid from "@theme/Mermaid"; @@ -9,7 +10,7 @@ import mermaidPlan from "../examples/users-and-friends/plan-simplified.mermaid?r # introduction The GraphQL specification describes how a GraphQL operation should be executed, -talking in terms of layer-by-layer resolution of data using "resolvers." But +talking in terms of layer–by–layer resolution of data using "resolvers." But critical to note is this sentence from the beginning of the specification: > _Conformance requirements [...] can be fulfilled [...] in any way as long as @@ -19,8 +20,8 @@ critical to note is this sentence from the beginning of the specification: Resolvers are relatively straightforward to understand, but when implemented naively can very quickly result in serious performance issues. [DataLoader][] is one of the approaches suggested to solve the "N+1 problem," but this is only the -most egregious performance issue that a naive GraphQL schema may face - there -are others such as server-side over-fetching and under-fetching and related +most egregious performance issue that a naive GraphQL schema may face — there +are others such as server–side over–fetching and under–fetching and related issues that can really build up as your schemas and operations get more complex. ​ was designed from the ground up to eliminate these issues and more @@ -31,7 +32,7 @@ and unlocks the potential for significant optimizations not previously achievable without a herculean effort. Please note that is not tied to any particular storage or business -logic layer - any valid GraphQL schema could be implemented with , +logic layer — any valid GraphQL schema could be implemented with , and a schema can query any data source, service, or business logic that Node.js can query. @@ -44,7 +45,7 @@ execution algorithm in a language other than JavaScript, please get in touch! ::: -## Planning +## Plan resolvers _This is just an overview, for full documentation see [Plan Resolvers](./plan-resolvers)._ @@ -123,20 +124,38 @@ const planResolvers = { ``` As you can see, the shape of the logic is quite similar, but the -plan resolvers are synchronous since their job isn't to get the data to use, -but instead to outline the steps required to get the data. For example, since -the `User.friends` Gra*fast* plan resolver cannot explicitly loop through the -data (it hasn't been fetched yet!), it uses an [`each` -step](/grafast/step-library/standard-steps/each) to detail which steps to take -for each item made available later. +plan resolvers are synchronous. operates in two phases: planning +(synchronous) and execution (asynchronous); plan resolvers are called during +the planning phase. -:::tip +The job of a plan resolver is not to retrieve data, it's to detail the +**steps** necessary to retrieve it. Plan resolvers do not have access to any +runtime data, they must describe what to do for arbitrary future data. For +example, the `User.friends` Gra*fast* plan resolver cannot loop through the +runtime data with a `map` function as in the resolver example (since there is +not yet any data to loop over), instead it describes the plan to do so using an +[`each` step](/grafast/step-library/standard-steps/each), detailing what to do +with each item made available later. + + +:::tip The dollar convention By convention, when a variable represents a step, the variable will -be named starting with a `$`. +be named starting with a `$` (dollar symbol). ::: +## Steps + +Steps are the basic building blocks of a plan; they are instances +of a step class, constructed via the function calls in the plan resolver. Step +classes describe how to perform a specific action and help plan how to perform +the action more efficiently via the **lifecycle methods**. provides +optimized built–in steps for common needs; it's common that you can get started +using just these, but as you go about optimizing your schema further it's +expected that you will build your own step classes, in the same way that you'd +build DataLoaders in a resolver–based GraphQL API. + If we were to make a request to the above schema with the following query: @@ -158,6 +177,196 @@ of this operation plan is: +Each node in this diagram represents a **step** in the operation plan, and the +arrows show how the data flows between these steps. + +:::tip Plans can be reused for multiple requests + +When the same operation is seen again its existing plan can (generally) be +reused; this is why, to get the very best performance from , you +should use static GraphQL documents and pass variables at run–time. + +::: + +### Batched execution + +The main concern of most steps is execution. In all execution is +batched, so each of the nodes in the operation plan will execute at most once +during a GraphQL query or mutation — this is one of the major differences when +compared to traditional GraphQL execution. + +When it comes time to execute an operation plan, will automatically +populate the steps whose names begin with `__` (e.g. the context and variable +values) and then will begin the process of executing each step +once all of its dependencies are ready, continuing until all steps are +complete. + +At planning time a step can add a dependency on another step via `const depId = +this.addDependency($otherStep);`. This `depId` is the index in the **values +tuple** that the step can use at execution time to retrieve the associated +values. + +When a step executes, its `executeV2` method is passed the **execution +details** which includes: + +- `count` — the size of the batch to be executed +- `values` — the **values tuple**, the values for each of the dependencies the + step added + +:::note Why `executeV2`? + +`executeV2` is our second signature for step execution; the old `execute` +method is still supported but is less efficient. + +::: + +The `executeV2` method must return a list (or a promise to a list) of length +`count`, where each entry in this list relates to the corresponding entries in +`values` — this should be at least a little familiar to anyone who has written +a DataLoader before. + + + +When a plan starts executing it always starts with a batch size (`count`) of 1; +but many things may affect this batch size for later steps — for example when +processing the items in a list, the batch must grow to contain each item (via +the `__Item` step). handles all of these complexities for you +internally, so you don't generally need to think about them. + +#### Unary steps + +A "unary step" is a regular step which the system has determined will always +represent exactly one value. The system steps which represent request–level +data (e.g. context, variable and argument values) are always unary steps, and +​ will automatically determine which other steps are also unary +steps. + + + +Sometimes you'll want to ensure that one or more of the steps your step class +depends on will have exactly one value at runtime; to do so, you can use +`this.addUnaryDependency($step)` rather than `this.addDependency($step)`. +This +ensures that the given dependency will always be a unary step, and is primarily +useful when a parameter to a remote service request needs to be the same for +all entries in the batch; typically this will be the case for ordering, +pagination and access control. For example if you're retrieving the first N +pets from each of your friends you might want to add `limit N` to an SQL query +— by adding the N as a unary dependency you can guarantee that there will be +exactly one value of N for each execution, and can construct the SQL query +accordingly (see `limitSQL` in the example below). + +#### SQL example + +Here's a step class which retrieves records matching a given column (i.e. +`WHERE columnName = $columnValue`) from a given table in an SQL database. +Optionally, you may request to limit to the first `$first` results. + +```ts +export class RecordsByColumnStep extends ExecutableStep { + constructor(tableName, columnName, $columnValue) { + super(); + this.tableName = tableName; + this.columnName = columnName; + this.columnValueDepIdx = this.addDependency($columnValue); + } + + setFirst($first) { + this.firstDepId = this.addUnaryDependency($first); + } + + async executeV2({ count, values }) { + // Retrieve the values for the `$columnValue` dependency + const columnValueDep = values[this.columnValueDepIdx]; + + // We may or may not have added a `$first` limit: + const firstDep = + this.firstDepId !== undefined ? values[this.firstDepId] : undefined; + + // firstDep, if it exists, is definitely a unary dep (!firstDep.isBatch), so + // we can retrieve its value directly: + const first = firstDep ? parseInt(firstDep.value, 10) : null; + + // Create a `LIMIT` clause in our SQL if the user specified a `$first` limit: + const limitSQL = Number.isFinite(first) ? `limit ${first}` : ``; + + // Create placeholders for each entry in our batch in the SQL: + const placeholders = Array.from({ length: count }, () => "?"); + const placeholderValues = Array.from({ length: count }, (_, i) => + // The value from `$columnValue` for this index `i` in the batch + columnValueDep.at(i), + ); + + // Build the SQL query to execute: + const sql = `\ + select * + from ${this.tableName} + where ${this.columnName} in (${placeholders.join(", ")}) + ${limitSQL} + `; + + // Execute the SQL query once for all values in the batch: + const rows = await executeSQL(sql, placeholderValues); + + // Figure out which rows relate to which batched inputs: + return Array.from({ length: count }, (_, i) => + rows.filter((row) => row[this.columnName] === columnValueDep.at(i)), + ); + } +} + +function petsByOwnerId($ownerId) { + return new RecordsByColumnStep("pets", "owner_id", $ownerId); +} +``` + +Notice that there's only a single `await` call in this step's execute method, +and we already know the step is only executed once per request; compare +this single asynchronous action with the number of promises that would need +to be created were you to use `DataLoader` instead. + +:::info Not just databases! + +The `executeV2` method is just JavaScript; it can +talk to absolutely any data source that Node.js itself can talk to. Though the +example shows SQL you could replace the `executeSQL()` call with `fetch()` or +any other arbitrary JavaScript function to achieve your goals. + +::: + +:::note Simplified example + +The code above was written to be a simple example; though it works ([see full +solution using +it](https://github.com/graphile/crystal/blob/main/grafast/website/grafast/index.example.mjs)), +it's not nearly as good as it could be — for example it does not track the +columns accessed so that only these columns are retrieved, nor does it use +lifecycle methods to determine more optimal ways of executing. + +(Another thing: it passes the `tableName` and `columnName` values directly into +SQL — it would be safer to use an `escapeIdentifier()` call around these.) + + +::: + +### Step lifecycle + +The [**execution plan**](/grafast/operation-plan#execution-plan) diagram you +saw above is the final form of the plan, there were many intermediate states +that it will have gone through in order to reach this most optimal form, made +possible by 's lifecycle methods. + :::info If you want to explore this example more, please see the @@ -168,20 +377,10 @@ For more information about understanding plan diagrams please see ::: -When the same operation is seen again its existing plan can (generally) be -reused; this is why, to get the very best performance from , you -should use static GraphQL documents and pass variables at run-time. - -The [**execution plan**](/grafast/operation-plan#execution-plan) diagram you -see above is the final form of the plan, there were many intermediate states -that it will have gone through in order to reach this most optimal form, made -possible by 's plan lifecycle. - -## Plan lifecycle _This is just an overview, for full documentation see [lifecycle][lifecycle]._ -All plan lifecycle methods are optional, and due to the always-batched nature +All plan lifecycle methods are optional, and due to the always–batched nature of plans you can get good performance without using any of them (performance generally on a par with reliable usage of DataLoader). However, if you leverage lifecycle methods your performance can go from "good" to @@ -212,19 +411,19 @@ optimal code paths deeper in the plan tree). Purpose one is that optimize lets a step "talk" to its ancestors, typically to tell them about data that will be needed so that they may fetch it proactively. This should not change the observed behavior of the ancestor (e.g. you should -not use it to apply filters to an ancestor - this may contradict the GraphQL +not use it to apply filters to an ancestor — this may contradict the GraphQL specification!) but it can be used to ask the ancestor to fetch additional data. The second purpose is that optimize can be used to replace the step being -optimized with an alternative (presumably more-optimal) step. This may result +optimized with an alternative (presumably more–optimal) step. This may result in multiple steps being dropped from the plan graph due to "tree shaking." This might be used when the step has told an ancestor to fetch additional data and the step can then replace itself with a simple "access" step. It can also be -used to dispose of plan-only steps that have meaning at planning time but have -no execution-time behaviors. +used to dispose of plan–only steps that have meaning at planning time but have +no execution–time behaviors. -In the "friends" example above, this was used to change the DataLoader-style +In the "friends" example above, this was used to change the DataLoader–style `select * from ...` query to a more optimal `select id, full_name from ...` query. In more advanced plans (for example those made available through [@dataplan/pg][]), optimize can go much further, for example inlining its data diff --git a/grafast/website/grafast/step-classes.md b/grafast/website/grafast/step-classes.md index 286132bf12..195a0382d4 100644 --- a/grafast/website/grafast/step-classes.md +++ b/grafast/website/grafast/step-classes.md @@ -16,15 +16,22 @@ to use; but when these aren't enough you are encouraged to write your own (or pull down third party step classes from npm or similar). Step classes extend the `ExecutableStep` class, the only required method to -define is `execute`, but you may also implement the various lifecycle methods, +define is `executeV2`, but you may also implement the various lifecycle methods, or add methods of your own to make it easier for you to write [plan resolvers][]. +:::info + +Earlier versions of used an `execute` method; we're still backwards +compatible with that, but you should use `executeV2` for all future work. + +::: + ```ts /** XKCD-221 step class @ref https://xkcd.com/221/ */ class GetRandomNumberStep extends ExecutableStep { - execute(count) { + executeV2({ count }) { return new Array(count).fill(4); // chosen by fair dice roll. // guaranteed to be random. } @@ -35,7 +42,7 @@ function getRandomNumber() { } ``` -:::tip +:::tip Use prefixes on custom fields/methods. If you add any custom fields or methods to your step classes we recommend that you prefix them with your initials or organization name to avoid naming @@ -43,7 +50,7 @@ conflicts occurring. ::: -:::tip +:::warning Don't subclass steps. Don't subclass steps, this will make things very confusing for you. Always inherit directly from `ExecutableStep`. @@ -60,7 +67,7 @@ as part of `ExecutableStep`. When your step requires another step's value in order to execute (which is the case for the majority of steps!) it must add a dependency via the `this.addDependency($otherStep)` method. This method will return a number, -which is the index in the execute values tuple that represents this step. +which is the index in the `executeV2` values tuple that represents this step. It's common to do this in the constructor, but it can be done at other stages too, for example during the optimize phase a step's descendent might ask it to @@ -78,7 +85,7 @@ class AddStep extends ExecutableStep { } ``` -:::warning +:::warning Steps are ethemeral, never store a reference to a step. You must never store a reference to another step directly (or indirectly) in your step class. Steps come and go at quite a rate during planning - being @@ -95,6 +102,34 @@ should have been a dependency after all? ::: +### addUnaryDependency + +Sometimes you'll want to ensure that one or more of the steps your step class +depends on will have exactly one value at runtime; to do so, you can use +`this.addUnaryDependency($step)` rather than `this.addDependency($step)`. This +asserts that the given dependency is a **unary step** (a regular step which the +system has determined will always represent exactly one value) and is primarily +useful when a parameter to a remote service request needs to be the same for +all entries in the batch; typically this will be the case for ordering, +pagination and access control. + +:::warning Use with caution. + +`this.addUnaryDependency($step)` will raise an error during planning if the +given `$step` is not unary, so you should be very careful using it. If in +doubt, use `this.addDependency($step)` instead. + +The system steps which represent request–level data (e.g. context, variable and +argument values) are always unary steps, and ​ will +automatically determine which other steps are also unary steps. + +It's generally intended for `addUnaryDependency` to be used for arguments and +their derivatives; it can also be used with `context`-derived values, but there +is complexity when it comes to mutations since `context` is mutable (whereas +input values are not). + +::: + ### getDep Pass in the number of the dependency (`0` for the first dependency, `1` for the @@ -133,56 +168,75 @@ that would occur between the triangular brackets). ## Lifecycle methods -### execute +### executeV2 ```ts -execute( - count: number, - values: ReadonlyArray, - extra: ExecutionExtra, -): PromiseOrDirect +executeV2(details: ExecutionDetails): PromiseOrDirect ``` -Execute is the one method that your step class must define, and it has very -strict rules. +```ts +// These are simplified types +interface ExecutionDetails { + count: number; + values: [...ExecutionValue[]]; + extra: ExecutionExtra; +} -The first argument to the execute method, `count`, indicates how many values -will be fed into your execute method, and the length of the list that the -method must return. +type ExecutionValue = + | { at(i: number): TData; isBatch: true; entries: ReadonlyArray } + | { at(i: number): TData; isBatch: false; value: TData }; + +type GrafastResultsList = ReadonlyArray>; +``` -The second argument to the execute method, `values`, will be an n-tuple (a -tuple with `n` entries), where `n` is the number of dependencies the step has. -Each of the entries in the tuple will be a list of length `count`, and -contains the data that relates to the corresponding dependency. The order of -the entries in these lists is significant - the N'th entry in each list -corresponds with the N'th entry in each of the other lists. +`executeV2` is the one method that your step class must define, and it has very +strict rules. -The third argument is currently experimental, use it at your own risk (and see -the source for documentation). +It is passed one argument, the "execution details", which is an object containing: + +- `count` — the size of the batch being processed (and thus the length of the list that must be returned) +- `values` — the "values tuple", an n-tuple (a tuple with `n` entries), where + `n` is the number of dependencies the step has. Each of the entries in the + tuple will be an "execution value" containing the data that relates to the + corresponding dependency +- `extra` — currently experimental, use it at your own risk (and see the source + for documentation) + +An "execution value", `dep`, is an object containing the data for a given +dependency. It will either be a "batch" value (`dep.isBatch === true`) in which +case `dep.entries` will be an array containing `count` entries (the order of +which is significant), or it will be a "unary" value (`dep.isBatch === false`) +in which case `dep.value` will be the common value for this dependency across +all entries in the batch. Either way, `dep.at(i)` will return the value for +this dependency corresponding with the i'th entry in the batch (`dep.at(i)` is +equivalent to `dep.isBatch ? dep.entries[i] : dep.value`). Execute must return a list (or a promise to a list) of size `count`, where the -N'th entry in this list corresponds with the N'th entries in each of the -`values` tuple's lists. +i'th entry in this list corresponds to the `dep.at(i)` value for each `dep` in +the "values tuple". The result of `executeV2` may or may not be a promise, and +each entry in the resulting list may or may not be a promise. -:::danger +:::warning If your step has no dependencies If the step has no dependencies then `values` will be a 0-tuple (an empty tuple), so in situations where this is possible you _must_ use `count` to -determine how many results to return. +determine how many results to return; e.g.: + +```ts +return Array.from({ length: count }, () => 42); +``` ::: :::info -You might wonder why the `values` input is a tuple of lists, rather than a list -of tuples. The reason comes down to efficiency, by using a tuple of lists, -only needs to build one new array (the tuple), and into that array it can -insert the results from previous execute methods unmodified. Were it to provide -a list of tuples instead then it would need to build N+1 new arrays, where N -was the number of values being processed, which can easily be in the thousands. - -The result of execute may or may not be a promise, and each entry in the -resulting list may or may not be a promise. +You might wonder why the `values` input is a tuple of execution values, rather +than a list of tuples. The reason comes down to efficiency, by using a tuple of +execution values, only needs to build one new array (the tuple), +and into that array it can insert the results from previously executed steps +unmodified. Were it to provide a list of tuples instead then it would need to +build N+1 new arrays, where N was the number of values being processed, which +can easily be in the thousands. ::: @@ -191,51 +245,54 @@ resulting list may or may not be a promise. If you want one of your entries to throw an error, but the others shouldn't, then an easy way to achieve this is to set the corresponding entry in the results list to `Promise.reject(new Error(...))`. You can do this even if you -don't use promises for any of the other values. +don't use promises for any of the other values, and even if your `executeV2` +method is not marked as `async`. You **must not** do this if you have marked +your step class with `isSyncAndSafe = true`. ::: #### Example In the [getting started][] guide we built an `AddStep` step class that adds two -numbers together. It's execute method looked like this: +numbers together. It's `executeV2` method looked like this: ```ts - execute(count, [allA, allB]) { - const results = []; - for (let i = 0; i < count; i++) { - // `allA` and `allB` have the same length, which is `count`, and the - // entries at the same index in each list relate to each other. - const a = allA[i]; - const b = allB[i]; - results.push(a + b); - } - return results; + executeV2({ count, values: [aDep, bDep] }) { + return Array.from({ length: count }, (_, i) => { + const a = aDep.at(i); + const b = bDep.at(i); + return a + b; + }); } ``` Imagine at runtime needed to execute this operation for three -(`count = 3`) pairs of values: `[1, 2]`, `[3, 4]` and `[5, 6]`. Since batches everything the values for `$a` would be `allA = [1, 3, 5]` and the -values for `$b` would be `allB = [2, 4, 6]`. The execute method then returns -the same number of results in the same order: `[3, 7, 11]`. +(`count = 3`) pairs of values: `[1, 2]`, `[3, 4]` and `[5, 6]`. The values for +`$a` would be `aDep.values = [1, 3, 5]` and the values for `$b` would be +`bDep.values = [2, 4, 6]`. The execute method then returns the same number of +results in the same order: `[3, 7, 11]`. -### stream +### streamV2 _This method is optional._ ```ts -stream( - count: number, - values: ReadonlyArray, - extra: ExecutionExtra, +streamV2(details: StreamDetails): PromiseOrDirect +``` + +```ts +interface StreamDetails extends ExecutionDetails { streamOptions: { initialCount: number; - }, -): PromiseOrDirect + }; +} + +type GrafastResultStreamList = ReadonlyArray< + PromiseOrDirect> | null> +>; ``` -TODO: document stream. (It's like execute, except it returns a list of async iterators.) +TODO: document streamV2. (It's like executeV2, except it returns a list of async iterators.) ### deduplicate @@ -390,6 +447,35 @@ should use the `optimize` method to do so. ::: +### execute + +**Deprecated**! Use [`executeV2`](#executev2) instead. Existing `execute` +methods should continue to work. + +```ts +execute( + count: number, + values: ReadonlyArray, + extra: ExecutionExtra, +): PromiseOrDirect +``` + +### stream + +**Deprecated**! Use [`streamV2`](#streamv2) instead. Existing `stream` methods +should continue to work. + +```ts +stream( + count: number, + values: ReadonlyArray, + extra: ExecutionExtra, + streamOptions: { + initialCount: number; + }, +): PromiseOrDirect +``` + ## Other properties ### id @@ -449,7 +535,7 @@ This is set `true` after the step has been optimized. Set this true if your plan's optimize method can be called a second time. -:::warning +:::warning Your dependencies may change classes! In this situation it's likely that your dependencies (or their dependencies) will not be what you expect them to be (e.g. a `PgSelectSingleStep` might @@ -471,7 +557,7 @@ of the class. You can even set it to a shared value between multiple step classes (a "family" of step classes) should that make sense. By default no `metaKey` is set, and your class will therefore have no `meta` object. -:::tip +:::tip Inspiration The `loadMany` and `loadOne` standard steps make use of this key to optimize value caching, you may want to look at them for more inspiration. From e958af3ecf77b0c36cbb48061f004da324ce7486 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 28 Feb 2024 19:57:18 +0000 Subject: [PATCH 37/48] Remove comments --- grafast/website/grafast/index.mdx | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/grafast/website/grafast/index.mdx b/grafast/website/grafast/index.mdx index dba28a7288..b22dbbb394 100644 --- a/grafast/website/grafast/index.mdx +++ b/grafast/website/grafast/index.mdx @@ -137,7 +137,6 @@ not yet any data to loop over), instead it describes the plan to do so using an [`each` step](/grafast/step-library/standard-steps/each), detailing what to do with each item made available later. - :::tip The dollar convention By convention, when a variable represents a step, the variable will @@ -225,14 +224,6 @@ The `executeV2` method must return a list (or a promise to a list) of length `values` — this should be at least a little familiar to anyone who has written a DataLoader before. - - When a plan starts executing it always starts with a batch size (`count`) of 1; but many things may affect this batch size for later steps — for example when processing the items in a list, the batch must grow to contain each item (via @@ -247,13 +238,6 @@ data (e.g. context, variable and argument values) are always unary steps, and ​ will automatically determine which other steps are also unary steps. - - Sometimes you'll want to ensure that one or more of the steps your step class depends on will have exactly one value at runtime; to do so, you can use `this.addUnaryDependency($step)` rather than `this.addDependency($step)`. @@ -357,7 +341,6 @@ lifecycle methods to determine more optimal ways of executing. (Another thing: it passes the `tableName` and `columnName` values directly into SQL — it would be safer to use an `escapeIdentifier()` call around these.) - ::: ### Step lifecycle @@ -377,7 +360,6 @@ For more information about understanding plan diagrams please see ::: - _This is just an overview, for full documentation see [lifecycle][lifecycle]._ All plan lifecycle methods are optional, and due to the always–batched nature From 4fb4e418fd2516f2735e1a77fe3b83e6b5e877b2 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 29 Feb 2024 15:17:08 +0000 Subject: [PATCH 38/48] Introduce new indexMap function and use it for all executeV2 methods --- grafast/dataplan-json/src/steps/jsonParse.ts | 16 +++--- .../dataplan-pg/src/steps/pgDeleteSingle.ts | 29 +++++----- .../dataplan-pg/src/steps/pgInsertSingle.ts | 12 ++-- grafast/dataplan-pg/src/steps/pgSelect.ts | 31 +++++----- .../src/steps/pgSingleTablePolymorphic.ts | 14 ++--- grafast/dataplan-pg/src/steps/pgUnionAll.ts | 11 ++-- .../dataplan-pg/src/steps/pgUpdateSingle.ts | 52 ++++++++--------- .../src/steps/pgValidateParsedCursor.ts | 12 ++-- grafast/dataplan-pg/src/steps/withPgClient.ts | 10 +--- .../grafast/__tests__/errorHandling-test.ts | 29 ++++------ .../errorHandlingStreamTermination-test.ts | 39 +++++-------- grafast/grafast/__tests__/stream-test.ts | 29 ++++------ grafast/grafast/__tests__/unaryDeps-test.ts | 17 +++--- grafast/grafast/src/engine/executeBucket.ts | 47 +++++++++++++++- grafast/grafast/src/interfaces.ts | 5 ++ grafast/grafast/src/step.ts | 12 ++-- grafast/grafast/src/steps/applyTransforms.ts | 26 ++++----- grafast/grafast/src/steps/first.ts | 10 +--- grafast/grafast/src/steps/graphqlResolver.ts | 56 ++++++++----------- grafast/grafast/src/steps/list.ts | 12 ++-- grafast/grafast/src/steps/listTransform.ts | 21 +++---- grafast/grafast/src/steps/listen.ts | 10 ++-- grafast/grafast/src/steps/object.ts | 16 +++--- .../grafast/src/steps/polymorphicBranch.ts | 10 ++-- grafast/grafast/src/steps/remapKeys.ts | 8 +-- grafast/grafast/src/steps/reverse.ts | 10 ++-- 26 files changed, 251 insertions(+), 293 deletions(-) diff --git a/grafast/dataplan-json/src/steps/jsonParse.ts b/grafast/dataplan-json/src/steps/jsonParse.ts index a7c857eedf..4e9bf3db73 100644 --- a/grafast/dataplan-json/src/steps/jsonParse.ts +++ b/grafast/dataplan-json/src/steps/jsonParse.ts @@ -54,22 +54,21 @@ export class JSONParseStep< } executeV2({ - count, + indexMap, values: [stringDep], }: ExecutionDetails<[string]>): GrafastResultsList { - const result: Array> = []; // new Array(count); - for (let i = 0; i < count; i++) { + return indexMap>((i) => { const v = stringDep.at(i); if (typeof v === "string") { try { - result[i] = JSON.parse(v); + return JSON.parse(v); } catch (e) { - result[i] = Promise.reject(e); + return Promise.reject(e); } } else if (v == null) { - result[i] = null as any; + return null as any; } else { - result[i] = Promise.reject( + return Promise.reject( new Error( `JSONParseStep: expected string to parse, but received ${ Array.isArray(v) ? "array" : typeof v @@ -77,8 +76,7 @@ export class JSONParseStep< ), ); } - } - return result; + }); } } diff --git a/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts b/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts index 211748dcaa..89a663fe87 100644 --- a/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts +++ b/grafast/dataplan-pg/src/steps/pgDeleteSingle.ts @@ -246,7 +246,7 @@ export class PgDeleteSingleStep< * the plans stored in this.identifiers to get actual values we can use. */ async executeV2({ - count, + indexMap, values, }: ExecutionDetails): Promise> { if (!this.finalizeResults) { @@ -258,9 +258,8 @@ export class PgDeleteSingleStep< // We must execute each mutation on its own, but we can at least do so in // parallel. Note we return a list of promises, each may reject or resolve // without causing the others to reject. - const result: Array> = []; const contextDep = values[this.contextId]; - for (let i = 0; i < count; i++) { + return indexMap>(async (i) => { const context = contextDep.at(i); const sqlValues = queryValueDetailsBySymbol.size ? rawSqlValues.map((v) => { @@ -276,24 +275,22 @@ export class PgDeleteSingleStep< } }) : rawSqlValues; - const promise = this.resource.executeMutation({ + const { rows, rowCount } = await this.resource.executeMutation({ context, text, values: sqlValues, }); - result[i] = promise.then( - ({ rows, rowCount }) => - rows[0] ?? - (rowCount === 0 - ? Promise.reject( - new Error( - `No values were deleted in collection '${this.resource.name}' because no values you can delete were found matching these criteria.`, - ), - ) - : Object.create(null)), + return ( + rows[0] ?? + (rowCount === 0 + ? Promise.reject( + new Error( + `No values were deleted in collection '${this.resource.name}' because no values you can delete were found matching these criteria.`, + ), + ) + : Object.create(null)) ); - } - return result; + }); } public finalize(): void { diff --git a/grafast/dataplan-pg/src/steps/pgInsertSingle.ts b/grafast/dataplan-pg/src/steps/pgInsertSingle.ts index 2fdd1e5a9e..abff73d44b 100644 --- a/grafast/dataplan-pg/src/steps/pgInsertSingle.ts +++ b/grafast/dataplan-pg/src/steps/pgInsertSingle.ts @@ -282,7 +282,7 @@ export class PgInsertSingleStep< * the plans stored in this.identifiers to get actual values we can use. */ async executeV2({ - count, + indexMap, values, }: ExecutionDetails): Promise> { if (!this.finalizeResults) { @@ -294,8 +294,7 @@ export class PgInsertSingleStep< // We must execute each mutation on its own, but we can at least do so in // parallel. Note we return a list of promises, each may reject or resolve // without causing the others to reject. - const result: Array> = []; - for (let i = 0; i < count; i++) { + return indexMap>(async (i) => { const value = values.map((v) => v.at(i)); const sqlValues = queryValueDetailsBySymbol.size ? rawSqlValues.map((v) => { @@ -311,14 +310,13 @@ export class PgInsertSingleStep< } }) : rawSqlValues; - const promise = this.resource.executeMutation({ + const { rows } = await this.resource.executeMutation({ context: value[this.contextId], text, values: sqlValues, }); - result[i] = promise.then(({ rows }) => rows[0] ?? Object.create(null)); - } - return result; + return rows[0] ?? Object.create(null); + }); } public finalize(): void { diff --git a/grafast/dataplan-pg/src/steps/pgSelect.ts b/grafast/dataplan-pg/src/steps/pgSelect.ts index b0b14719ea..09bf0c1c84 100644 --- a/grafast/dataplan-pg/src/steps/pgSelect.ts +++ b/grafast/dataplan-pg/src/steps/pgSelect.ts @@ -1210,6 +1210,7 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} * the plans stored in this.identifiers to get actual values we can use. */ async executeV2({ + indexMap, count, values, extra: { eventEmitter }, @@ -1231,10 +1232,9 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} } = this.finalizeResults; const contextDep = values[this.contextId]; - const specs: Array> = []; - for (let i = 0; i < count; i++) { + const specs = indexMap>((i) => { const context = contextDep.at(i); - specs.push({ + return { // The context is how we'd handle different connections with different claims context, queryValues: @@ -1244,8 +1244,8 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} return val == null ? null : codec.toPg(val); }) : EMPTY_ARRAY, - }); - } + }; + }); const executionResult = await this.resource.executeWithCache(specs, { text, textForSingle, @@ -1292,7 +1292,7 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} * Like `execute`, but stream the results via async iterables. */ async streamV2({ - count, + indexMap, values, extra: { eventEmitter }, }: ExecutionDetails): Promise> { @@ -1317,11 +1317,11 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} } const contextDep = values[this.contextId]; - const specs: PgExecutorInput[] | null = text ? [] : null; + let specs: readonly PgExecutorInput[] | null = null; if (text) { - for (let i = 0; i < count; i++) { + specs = indexMap((i) => { const context = contextDep.at(i); - specs!.push({ + return { // The context is how we'd handle different connections with different claims context, queryValues: @@ -1331,8 +1331,8 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} return val == null ? null : codec.toPg(val); }) : EMPTY_ARRAY, - }); - } + }; + }); } const initialFetchResult = specs ? ( @@ -1345,11 +1345,10 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} ).values : null; - const streamSpecs: PgExecutorInput[] = []; - for (let i = 0; i < count; i++) { + const streamSpecs = indexMap>((i) => { const context = contextDep.at(i); - streamSpecs.push({ + return { // The context is how we'd handle different connections with different claims context, queryValues: @@ -1359,8 +1358,8 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} return val == null ? val : codec.toPg(val); }) : EMPTY_ARRAY, - }); - } + }; + }); const streams = ( await this.resource.executeStream(streamSpecs, { text: textForDeclare, diff --git a/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts b/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts index 9865e15742..719105f9ec 100644 --- a/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts +++ b/grafast/dataplan-pg/src/steps/pgSingleTablePolymorphic.ts @@ -57,21 +57,19 @@ export class PgSingleTablePolymorphicStep< } executeV2({ - count, + indexMap, values, }: ExecutionDetails): GrafastResultsList > | null> { - const result: Array< - PromiseOrDirect> | null> - > = []; const valuesDep = values[this.typeStepId]; - for (let i = 0; i < count; i++) { + return indexMap< + PromiseOrDirect> | null> + >((i) => { const v = valuesDep.at(i); - result[i] = v ? polymorphicWrap(v) : null; - } - return result; + return v ? polymorphicWrap(v) : null; + }); } } diff --git a/grafast/dataplan-pg/src/steps/pgUnionAll.ts b/grafast/dataplan-pg/src/steps/pgUnionAll.ts index 10c2dfdd6c..aae304ca9d 100644 --- a/grafast/dataplan-pg/src/steps/pgUnionAll.ts +++ b/grafast/dataplan-pg/src/steps/pgUnionAll.ts @@ -1934,7 +1934,7 @@ ${lateralText};`; // Be careful if we add streaming - ensure `shouldReverseOrder` is fine. async executeV2({ - count, + indexMap, values, extra: { eventEmitter }, }: ExecutionDetails): Promise> { @@ -1946,10 +1946,9 @@ ${lateralText};`; throw new Error("We have no context dependency?"); } - const specs: Array> = []; - for (let i = 0; i < count; i++) { + const specs = indexMap>((i) => { const context = contextDep.at(i); - specs.push({ + return { // The context is how we'd handle different connections with different claims context, queryValues: @@ -1965,8 +1964,8 @@ ${lateralText};`; }, ) : EMPTY_ARRAY, - }); - } + }; + }); const executionResult = await this.executor.executeWithCache(specs, { text, rawSqlValues, diff --git a/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts b/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts index f2ffd07290..2d87826b8c 100644 --- a/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts +++ b/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts @@ -314,35 +314,29 @@ export class PgUpdateSingleStep< // We must execute each mutation on its own, but we can at least do so in // parallel. Note we return a list of promises, each may reject or resolve // without causing the others to reject. - const promises: Promise[] = []; - for (let i = 0; i < count; i++) { - promises.push( - (async () => { - const context = contextDep.at(i); - const sqlValues = queryValueDetailsBySymbol.size - ? rawSqlValues.map((v) => { - if (typeof v === "symbol") { - const details = queryValueDetailsBySymbol.get(v); - if (!details) { - throw new Error(`Saw unexpected symbol '${inspect(v)}'`); - } - const val = values[details.depId].at(i); - return val == null ? null : details.processor(val); - } else { - return v; - } - }) - : rawSqlValues; - const { rows, rowCount } = await this.resource.executeMutation({ - context, - text, - values: sqlValues, - }); - return rows[0] ?? (rowCount === 0 ? null : Object.create(null)); - })(), - ); - } - return promises; + return Array.from({ length: count }, async (_, i) => { + const context = contextDep.at(i); + const sqlValues = queryValueDetailsBySymbol.size + ? rawSqlValues.map((v) => { + if (typeof v === "symbol") { + const details = queryValueDetailsBySymbol.get(v); + if (!details) { + throw new Error(`Saw unexpected symbol '${inspect(v)}'`); + } + const val = values[details.depId].at(i); + return val == null ? null : details.processor(val); + } else { + return v; + } + }) + : rawSqlValues; + const { rows, rowCount } = await this.resource.executeMutation({ + context, + text, + values: sqlValues, + }); + return rows[0] ?? (rowCount === 0 ? null : Object.create(null)); + }); } public finalize(): void { diff --git a/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts b/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts index 2be581ee6d..9245ec22f5 100644 --- a/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts +++ b/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts @@ -38,16 +38,15 @@ export class PgValidateParsedCursorStep extends ExecutableStep { } executeV2({ - count, + indexMap, values: [parsedCursorDep], }: ExecutionDetails<[string | null]>): GrafastResultsList { - const results: any[] = []; - for (let i = 0; i < count; i++) { + return indexMap((i) => { const decoded = parsedCursorDep.isBatch ? parsedCursorDep.entries[i] : parsedCursorDep.value; if (!decoded) { - results.push(undefined); + return undefined; } else { try { const [cursorDigest, ...cursorParts] = decoded; @@ -70,7 +69,7 @@ export class PgValidateParsedCursorStep extends ExecutableStep { `Invalid cursor length - ${cursorParts.length} !== ${this.orderCount}`, ); } - results.push(undefined); + return undefined; } catch (e) { if (isDev) { console.error("Invalid cursor:"); @@ -82,8 +81,7 @@ export class PgValidateParsedCursorStep extends ExecutableStep { ); } } - } - return results; + }); } } diff --git a/grafast/dataplan-pg/src/steps/withPgClient.ts b/grafast/dataplan-pg/src/steps/withPgClient.ts index 462c0ec766..e773f9cc32 100644 --- a/grafast/dataplan-pg/src/steps/withPgClient.ts +++ b/grafast/dataplan-pg/src/steps/withPgClient.ts @@ -60,16 +60,12 @@ export class WithPgClientStep< >): GrafastResultsList { const contextDep = values[this.contextId as 0]; const dataDep = values[this.dataId as 1]; - const promises: Promise[] = []; - for (let i = 0; i < count; i++) { + return Array.from({ length: count }, (_, i) => { const context = contextDep.at(i); const data = dataDep.at(i); const { withPgClient, pgSettings } = context; - promises.push( - withPgClient(pgSettings, (client) => this.callback(client, data)), - ); - } - return promises; + return withPgClient(pgSettings, (client) => this.callback(client, data)); + }); } } diff --git a/grafast/grafast/__tests__/errorHandling-test.ts b/grafast/grafast/__tests__/errorHandling-test.ts index 9ec782068a..1e59074f02 100644 --- a/grafast/grafast/__tests__/errorHandling-test.ts +++ b/grafast/grafast/__tests__/errorHandling-test.ts @@ -27,30 +27,21 @@ class SyncListCallbackStep< this.addDependency($dep); } executeV2({ - count, + indexMap, values: [values0], - }: ExecutionDetails<[TIn]>): Array> { - let result: PromiseOrDirect[] = []; - for (let i = 0; i < count; i++) { - const entry = values0.at(i); - result.push(this.callback(entry)); - } - return result; + }: ExecutionDetails<[TIn]>): ReadonlyArray> { + return indexMap((i) => this.callback(values0.at(i))); } - async streamV2({ count, values: [values0] }: ExecutionDetails<[TIn]>) { + async streamV2({ indexMap, values: [values0] }: ExecutionDetails<[TIn]>) { await sleep(0); const { callback } = this; - const results: any[] = []; - for (let i = 0; i < count; i++) { + return indexMap((i) => { const entry = values0.at(i); - results.push( - (async function* () { - const data = await callback(entry); - yield* data; - })(), - ); - } - return results; + return (async function* () { + const data = await callback(entry); + yield* data; + })(); + }); } } diff --git a/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts b/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts index 5d62917233..618800edb8 100644 --- a/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts +++ b/grafast/grafast/__tests__/errorHandlingStreamTermination-test.ts @@ -30,38 +30,29 @@ class SyncListCallbackStep< this.addDependency($dep); } executeV2({ - count, + indexMap, values: [values0], - }: ExecutionDetails<[TIn]>): Array> { - let result: PromiseOrDirect[] = []; - for (let i = 0; i < count; i++) { - const entry = values0.at(i); - result.push(this.callback(entry)); - } - return result; + }: ExecutionDetails<[TIn]>): ReadonlyArray> { + return indexMap((i) => this.callback(values0.at(i))); } - async streamV2({ count, values: [values0] }: StreamDetails<[TIn]>) { + async streamV2({ indexMap, values: [values0] }: StreamDetails<[TIn]>) { await sleep(0); const { callback, setStreaming } = this; - const results: any[] = []; - for (let i = 0; i < count; i++) { + return indexMap((i) => { const entry = values0.at(i); setStreaming(true); - results.push( - (async function* () { - try { - const data = await callback(entry); - for (const item of data) { - yield item; - } - } finally { - setStreaming(false); + return (async function* () { + try { + const data = await callback(entry); + for (const item of data) { + yield item; } - })(), - ); - } - return results; + } finally { + setStreaming(false); + } + })(); + }); } } diff --git a/grafast/grafast/__tests__/stream-test.ts b/grafast/grafast/__tests__/stream-test.ts index d244dbd68d..e54465cd5c 100644 --- a/grafast/grafast/__tests__/stream-test.ts +++ b/grafast/grafast/__tests__/stream-test.ts @@ -30,29 +30,20 @@ class SyncListCallbackStep< this.addDependency($dep); } executeV2({ - count, + indexMap, values: [values0], - }: ExecutionDetails<[TIn]>): Array> { - let result: PromiseOrDirect[] = []; - for (let i = 0; i < count; i++) { - const entry = values0.at(i); - result.push(this.callback(entry)); - } - return result; + }: ExecutionDetails<[TIn]>): ReadonlyArray> { + return indexMap((i) => this.callback(values0.at(i))); } - streamV2({ count, values: [values0] }: StreamDetails<[TIn]>) { + streamV2({ indexMap, values: [values0] }: StreamDetails<[TIn]>) { const { callback } = this; - let results: any[] = []; - for (let i = 0; i < count; i++) { + return indexMap((i) => { const entry = values0.at(i); - results.push( - (async function* () { - const data = await callback(entry); - yield* data; - })(), - ); - } - return results; + return (async function* () { + const data = await callback(entry); + yield* data; + })(); + }); } } diff --git a/grafast/grafast/__tests__/unaryDeps-test.ts b/grafast/grafast/__tests__/unaryDeps-test.ts index 1756f25a92..19dca52891 100644 --- a/grafast/grafast/__tests__/unaryDeps-test.ts +++ b/grafast/grafast/__tests__/unaryDeps-test.ts @@ -79,7 +79,7 @@ class GetRecordsStep> extends ExecutableStep { } async executeV2({ - count, + indexMap, values, }: ExecutionDetails): Promise> { const db = values[this.dbDepId].value as sqlite3.Database; @@ -127,28 +127,25 @@ ${orderBy ? `order by ${orderBy}` : ""} `; const sqlValues: any[] = []; if (identifierCols.length > 0) { - const json: any[] = []; - for (let i = 0; i < count; i++) { + const json = indexMap((i) => { const obj = Object.fromEntries( Object.entries(this.depIdByIdentifier).map(([col, depId]) => [ col, values[depId].at(i), ]), ); - json.push(obj); - } + return obj; + }); sqlValues.push(JSON.stringify(json)); } const dbResults = await query(db, sql, sqlValues); - const results: T[][] = []; const entries = Object.entries(this.depIdByIdentifier); - for (let i = 0; i < count; i++) { + return indexMap((i) => { // This could be more optimal by leveraging they're already in order - results[i] = dbResults.filter((r) => { + return dbResults.filter((r) => { return entries.every(([col, depId]) => r[col] === values[depId].at(i)); }); - } - return results; + }); } listItem($item: ExecutableStep) { return access($item); diff --git a/grafast/grafast/src/engine/executeBucket.ts b/grafast/grafast/src/engine/executeBucket.ts index 56d9dd9ab3..537c60262f 100644 --- a/grafast/grafast/src/engine/executeBucket.ts +++ b/grafast/grafast/src/engine/executeBucket.ts @@ -16,6 +16,8 @@ import type { ExecutionValue, GrafastResultsList, GrafastResultStreamList, + IndexForEach, + IndexMap, PromiseOrDirect, StreamMaybeMoreableArray, UnbatchedExecutionExtra, @@ -680,6 +682,8 @@ export function executeBucket( const streamOptions = step._stepOptions.stream; if (streamOptions && isStreamV2ableStep(step)) { return step.streamV2({ + indexMap: makeIndexMap(count), + indexForEach: makeIndexForEach(count), count, values, extra, @@ -692,7 +696,13 @@ export function executeBucket( ); return step.stream(count, backfilledValues, extra, streamOptions); } else { - return step.executeV2({ count, values, extra }); + return step.executeV2({ + indexMap: makeIndexMap(count), + indexForEach: makeIndexForEach(count), + count, + values, + extra, + }); } } @@ -1090,3 +1100,38 @@ function unaryExecutionValue(value: TData): ExecutionValue { value, }; } + +const indexMapCache = new Map(); +function makeIndexMap(count: number) { + const existing = indexMapCache.get(count); + if (existing !== undefined) { + return existing; + } + const result: IndexMap = (callback) => { + const results = []; + for (let i = 0; i < count; i++) { + results.push(callback(i)); + } + return results; + }; + if (count <= 100) { + indexMapCache.set(count, result); + } + return result; +} +const indexForEachCache = new Map(); +function makeIndexForEach(count: number) { + const existing = indexForEachCache.get(count); + if (existing !== undefined) { + return existing; + } + const result: IndexForEach = (callback) => { + for (let i = 0; i < count; i++) { + callback(i); + } + }; + if (count <= 100) { + indexForEachCache.set(count, result); + } + return result; +} diff --git a/grafast/grafast/src/interfaces.ts b/grafast/grafast/src/interfaces.ts index 7b16807a26..a5d4e6f303 100644 --- a/grafast/grafast/src/interfaces.ts +++ b/grafast/grafast/src/interfaces.ts @@ -788,10 +788,15 @@ export type ExecutionValue = entries?: never; }; +export type IndexMap = (callback: (i: number) => T) => ReadonlyArray; +export type IndexForEach = (callback: (i: number) => any) => void; + export interface ExecutionDetails< TDeps extends readonly [...any[]] = readonly [...any[]], > { count: number; + indexMap: IndexMap; + indexForEach: IndexForEach; values: { [DepIdx in keyof TDeps]: ExecutionValue; } & { diff --git a/grafast/grafast/src/step.ts b/grafast/grafast/src/step.ts index 3c25cc068f..fb77d87cc3 100644 --- a/grafast/grafast/src/step.ts +++ b/grafast/grafast/src/step.ts @@ -625,23 +625,21 @@ export abstract class UnbatchedExecutableStep< } executeV2({ - count, + indexMap, values, extra, }: ExecutionDetails): PromiseOrDirect> { console.warn( `${this} didn't call 'super.finalize()' in the finalize method.`, ); - const results = []; - for (let i = 0; i < count; i++) { + return indexMap((i) => { try { const tuple = values.map((list) => list.at(i)); - results[i] = this.unbatchedExecute(extra, ...tuple); + return this.unbatchedExecute(extra, ...tuple); } catch (e) { - results[i] = e instanceof Error ? (e as never) : Promise.reject(e); + return e instanceof Error ? (e as never) : Promise.reject(e); } - } - return results; + }); } abstract unbatchedExecute( diff --git a/grafast/grafast/src/steps/applyTransforms.ts b/grafast/grafast/src/steps/applyTransforms.ts index 7529c278fb..9d23be9cab 100644 --- a/grafast/grafast/src/steps/applyTransforms.ts +++ b/grafast/grafast/src/steps/applyTransforms.ts @@ -70,11 +70,11 @@ export class ApplyTransformsStep extends ExecutableStep { } async executeV2({ - count, + indexMap, values: [values0], extra, }: ExecutionDetails<[any[] | null | undefined | GrafastError]>): Promise< - GrafastResultsList + GrafastResultsList > { const bucket = extra._bucket; @@ -126,10 +126,8 @@ export class ApplyTransformsStep extends ExecutableStep { // We'll typically be creating more listItem bucket entries than we // have parent buckets, so we must "multiply up" the store entries. - for (let originalIndex = 0; originalIndex < count; originalIndex++) { - const list = values0.isBatch - ? values0.entries[originalIndex] - : values0.value; + indexMap((originalIndex) => { + const list = values0.at(originalIndex); if (Array.isArray(list)) { const newIndexes: number[] = []; map.set(originalIndex, newIndexes); @@ -152,7 +150,7 @@ export class ApplyTransformsStep extends ExecutableStep { } } } - } + }); if (size > 0) { const childBucket = newBucket( @@ -174,14 +172,12 @@ export class ApplyTransformsStep extends ExecutableStep { ? [null, unaryStore.get(rootStep.id)] : [store.get(rootStep!.id)!, null]; - const results: any[] = []; - for (let originalIndex = 0; originalIndex < count; originalIndex++) { + return indexMap((originalIndex) => { const list = values0.isBatch ? values0.entries[originalIndex] : values0.value; if (list == null) { - results.push(list); - continue; + return list; } const indexes = map.get(originalIndex); if (!Array.isArray(list) || !Array.isArray(indexes)) { @@ -189,8 +185,7 @@ export class ApplyTransformsStep extends ExecutableStep { console.warn( `Either list or values was not an array when processing ${this}`, ); - results.push(null); - continue; + return null; } const values = indexes.map((idx) => { const val = depResults === null ? unaryResult : depResults[idx]; @@ -206,9 +201,8 @@ export class ApplyTransformsStep extends ExecutableStep { "GrafastInternalError<43cb302e-673b-4881-8c4c-f2d00fe5a3d7>: The list and values length must match for a ApplyTransformsStep", ); } - results.push(values); - } - return results; + return values; + }); } } diff --git a/grafast/grafast/src/steps/first.ts b/grafast/grafast/src/steps/first.ts index e0f2e745f6..75a84307ca 100644 --- a/grafast/grafast/src/steps/first.ts +++ b/grafast/grafast/src/steps/first.ts @@ -21,16 +21,10 @@ export class FirstStep extends UnbatchedExecutableStep { } executeV2({ - count, + indexMap, values: [values0], }: ExecutionDetails<[TData[]]>): GrafastResultsList { - const result: Array = []; - for (let i = 0; i < count; i++) { - result[i] = values0.isBatch - ? values0.entries[i]?.[0] - : values0.value?.[0]; - } - return result; + return indexMap((i) => values0.at(i)?.[0]); } unbatchedExecute(_extra: UnbatchedExecutionExtra, list: any[]) { diff --git a/grafast/grafast/src/steps/graphqlResolver.ts b/grafast/grafast/src/steps/graphqlResolver.ts index dfa6b65927..fe6b281d40 100644 --- a/grafast/grafast/src/steps/graphqlResolver.ts +++ b/grafast/grafast/src/steps/graphqlResolver.ts @@ -185,24 +185,22 @@ export class GraphQLResolverStep extends UnbatchedExecutableStep { } async streamV2({ - count, + indexMap, values, extra, }: ExecutionDetails): Promise> { - const results = []; const depCount = this.dependencies.length; - for (let i = 0; i < count; i++) { + return indexMap((i) => { try { const tuple = []; for (let j = 0; j < depCount; j++) { tuple[j] = values[j].at(i); } - results[i] = (this.unbatchedStream as any)(extra, ...tuple); + return (this.unbatchedStream as any)(extra, ...tuple); } catch (e) { - results[i] = e instanceof Error ? (e as never) : Promise.reject(e); + return e instanceof Error ? (e as never) : Promise.reject(e); } - } - return results; + }); } } @@ -312,54 +310,48 @@ export class GraphQLItemHandler } executeV2({ - count, + indexMap, values: [values0], }: ExecutionDetails< [Awaited>] >): GrafastResultsList { if (this.abstractType !== undefined) { - const results: any[] = []; - for (let i = 0; i < count; i++) { + return indexMap((i) => { const data = values0.at(i); if (data == null) { - results.push(data); + return data; } else if (isPromiseLike(data.data)) { - results.push( - data.data.then((resolvedData: unknown) => - this.polymorphicWrapData( - resolvedData, - data.context, - data.resolveInfo, - ), + return data.data.then((resolvedData: unknown) => + this.polymorphicWrapData( + resolvedData, + data.context, + data.resolveInfo, ), ); } else { - results.push( - this.polymorphicWrapData(data.data, data.context, data.resolveInfo), + return this.polymorphicWrapData( + data.data, + data.context, + data.resolveInfo, ); } - } - return results; + }); } else if (this.nullableInnerType != null) { - const results: any[] = []; - for (let i = 0; i < count; i++) { + return indexMap((i) => { const d = values0.at(i); if (d == null) { - results.push(null); + return null; } else { const { data, context, resolveInfo } = d; if (isPromiseLike(data)) { - results.push( - data.then((data) => - this.wrapListData(data, context, resolveInfo), - ), + return data.then((data) => + this.wrapListData(data, context, resolveInfo), ); } else { - results.push(this.wrapListData(data, context, resolveInfo)); + return this.wrapListData(data, context, resolveInfo); } } - } - return results; + }); } else { throw new Error( `GrafastInternalError<6a3ed701-6b53-41e6-9a64-fbea57c76ae7>: has to be abstract or list`, diff --git a/grafast/grafast/src/steps/list.ts b/grafast/grafast/src/steps/list.ts index 83085b64b0..af49fe9bcd 100644 --- a/grafast/grafast/src/steps/list.ts +++ b/grafast/grafast/src/steps/list.ts @@ -31,13 +31,11 @@ export class ListStep< } executeV2( - { count, values }: ExecutionDetails, //UnwrapPlanTuple, - ): Array> { - const result: any[] = []; - for (let i = 0; i < count; i++) { - result[i] = values.map((value) => value.at(i)); - } - return result; + { indexMap, values }: ExecutionDetails, //UnwrapPlanTuple, + ) { + return indexMap( + (i) => values.map((value) => value.at(i)) as UnwrapPlanTuple, + ); } unbatchedExecute( diff --git a/grafast/grafast/src/steps/listTransform.ts b/grafast/grafast/src/steps/listTransform.ts index ca2ec47a11..3244060f86 100644 --- a/grafast/grafast/src/steps/listTransform.ts +++ b/grafast/grafast/src/steps/listTransform.ts @@ -193,7 +193,8 @@ export class __ListTransformStep< } async executeV2({ - count, + indexForEach, + indexMap, values, extra, }: ExecutionDetails<[any[] | null | undefined | GrafastError]>): Promise< @@ -251,7 +252,7 @@ export class __ListTransformStep< // We'll typically be creating more listItem bucket entries than we // have parent buckets, so we must "multiply up" the store entries. - for (let originalIndex = 0; originalIndex < count; originalIndex++) { + indexForEach((originalIndex) => { const list = listStepValue.isBatch ? listStepValue.entries[originalIndex] : listStepValue.value; @@ -277,7 +278,7 @@ export class __ListTransformStep< } } } - } + }); if (size > 0) { const childBucket = newBucket( @@ -299,15 +300,13 @@ export class __ListTransformStep< ? [null, unaryStore.get(rootStep!.id)] : [store.get(rootStep!.id)!, null]; - const results: any[] = []; - for (let originalIndex = 0; originalIndex < count; originalIndex++) { + return indexMap((originalIndex) => { const list = listStepValue.isBatch ? listStepValue.entries[originalIndex] : listStepValue.value; if (list == null) { - results.push(list); - continue; + return list; } const indexes = map.get(originalIndex); if (!Array.isArray(list) || !Array.isArray(indexes)) { @@ -315,8 +314,7 @@ export class __ListTransformStep< console.warn( `Either list or values was not an array when processing ${this}`, ); - results.push(null); - continue; + return null; } const values = indexes.map((idx) => depResults === null ? unaryResult : depResults[idx], @@ -337,9 +335,8 @@ export class __ListTransformStep< const finalResult = this.finalizeCallback ? this.finalizeCallback(reduceResult) : reduceResult; - results.push(finalResult); - } - return results; + return finalResult; + }); } } diff --git a/grafast/grafast/src/steps/listen.ts b/grafast/grafast/src/steps/listen.ts index 77bf641040..6d2cc64263 100644 --- a/grafast/grafast/src/steps/listen.ts +++ b/grafast/grafast/src/steps/listen.ts @@ -64,15 +64,14 @@ export class ListenStep< } streamV2({ - count, + indexMap, values, }: StreamDetails< readonly [GrafastSubscriber, TTopic] >): GrafastResultStreamList { const pubsubValue = values[this.pubsubDep as 0]; const topicValue = values[this.topicDep as 1]; - const result = []; - for (let i = 0; i < count; i++) { + return indexMap((i) => { const pubsub = pubsubValue.isBatch ? pubsubValue.entries[i] : pubsubValue.value; @@ -91,9 +90,8 @@ export class ListenStep< const topic = topicValue.isBatch ? topicValue.entries[i] : topicValue.value; - result[i] = pubsub.subscribe(topic); - } - return result; + return pubsub.subscribe(topic); + }); } } diff --git a/grafast/grafast/src/steps/object.ts b/grafast/grafast/src/steps/object.ts index a75a6b5548..15f6d44907 100644 --- a/grafast/grafast/src/steps/object.ts +++ b/grafast/grafast/src/steps/object.ts @@ -217,17 +217,15 @@ ${inner} } executeV2({ - count, + indexMap, values, extra, - }: ExecutionDetails[keyof TPlans]>>): Array< - DataFromPlans - > { - const result: Array> = []; - for (let i = 0; i < count; i++) { - result[i] = this.unbatchedExecute!(extra, ...values.map((v) => v.at(i))); - } - return result; + }: ExecutionDetails< + Array[keyof TPlans]> + >): ReadonlyArray> { + return indexMap((i) => + this.unbatchedExecute!(extra, ...values.map((v) => v.at(i))), + ); } unbatchedExecute(_extra: UnbatchedExecutionExtra, ..._values: any[]): any { diff --git a/grafast/grafast/src/steps/polymorphicBranch.ts b/grafast/grafast/src/steps/polymorphicBranch.ts index e25b248691..c49fe488b2 100644 --- a/grafast/grafast/src/steps/polymorphicBranch.ts +++ b/grafast/grafast/src/steps/polymorphicBranch.ts @@ -72,11 +72,10 @@ export class PolymorphicBranchStep } executeV2({ - count, + indexMap, values: [values0], }: ExecutionDetails): PromiseOrDirect> { - const results: any[] = []; - for (let i = 0; i < count; i++) { + return indexMap((i) => { const obj = values0.at(i); let match: string | null = null; if (obj != null) { @@ -87,9 +86,8 @@ export class PolymorphicBranchStep } } } - results[i] = match !== null ? polymorphicWrap(match, obj) : null; - } - return results; + return match !== null ? polymorphicWrap(match, obj) : null; + }); } } diff --git a/grafast/grafast/src/steps/remapKeys.ts b/grafast/grafast/src/steps/remapKeys.ts index 90e71db7d9..baed03d29e 100644 --- a/grafast/grafast/src/steps/remapKeys.ts +++ b/grafast/grafast/src/steps/remapKeys.ts @@ -100,14 +100,10 @@ export class RemapKeysStep extends UnbatchedExecutableStep { } executeV2({ - count, + indexMap, values: [values0], }: ExecutionDetails): GrafastResultsList { - const results: any[] = []; - for (let i = 0; i < count; i++) { - results.push(this.mapper(values0.at(i))); - } - return results; + return indexMap((i) => this.mapper(values0.at(i))); } unbatchedExecute(_extra: UnbatchedExecutionExtra, value: any): any { diff --git a/grafast/grafast/src/steps/reverse.ts b/grafast/grafast/src/steps/reverse.ts index c564536d0f..47dd8fb668 100644 --- a/grafast/grafast/src/steps/reverse.ts +++ b/grafast/grafast/src/steps/reverse.ts @@ -42,15 +42,13 @@ export class ReverseStep extends UnbatchedExecutableStep< } executeV2({ - count, + indexMap, values: [values0], }: ExecutionDetails<[TData[]]>): GrafastResultsList { - const results: any[] = []; - for (let i = 0; i < count; i++) { + return indexMap((i) => { const arr = values0.at(i); - results.push(arr == null ? arr : reverseArray(arr)); - } - return results; + return arr == null ? arr : reverseArray(arr); + }); } unbatchedExecute(_extra: UnbatchedExecutionExtra, arr: TData[]): TData[] { From 503c873bc481e2958bc0d1d2f2ae70e542036354 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Thu, 29 Feb 2024 15:40:17 +0000 Subject: [PATCH 39/48] Move docs to using indexMap --- .../dataplan-pg/src/steps/pgUpdateSingle.ts | 4 ++-- grafast/dataplan-pg/src/steps/withPgClient.ts | 4 ++-- .../website/grafast/getting-started/index.mdx | 4 ++-- grafast/website/grafast/index.mdx | 18 +++++++++--------- grafast/website/grafast/step-classes.md | 17 ++++++++++++----- 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts b/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts index 2d87826b8c..44778b1ce8 100644 --- a/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts +++ b/grafast/dataplan-pg/src/steps/pgUpdateSingle.ts @@ -301,7 +301,7 @@ export class PgUpdateSingleStep< * the plans stored in this.identifiers to get actual values we can use. */ async executeV2({ - count, + indexMap, values, }: ExecutionDetails): Promise> { if (!this.finalizeResults) { @@ -314,7 +314,7 @@ export class PgUpdateSingleStep< // We must execute each mutation on its own, but we can at least do so in // parallel. Note we return a list of promises, each may reject or resolve // without causing the others to reject. - return Array.from({ length: count }, async (_, i) => { + return indexMap(async (i) => { const context = contextDep.at(i); const sqlValues = queryValueDetailsBySymbol.size ? rawSqlValues.map((v) => { diff --git a/grafast/dataplan-pg/src/steps/withPgClient.ts b/grafast/dataplan-pg/src/steps/withPgClient.ts index e773f9cc32..7e15705e6a 100644 --- a/grafast/dataplan-pg/src/steps/withPgClient.ts +++ b/grafast/dataplan-pg/src/steps/withPgClient.ts @@ -53,14 +53,14 @@ export class WithPgClientStep< } executeV2({ - count, + indexMap, values, }: ExecutionDetails< [{ pgSettings: any; withPgClient: WithPgClient }, TData] >): GrafastResultsList { const contextDep = values[this.contextId as 0]; const dataDep = values[this.dataId as 1]; - return Array.from({ length: count }, (_, i) => { + return indexMap((i) => { const context = contextDep.at(i); const data = dataDep.at(i); const { withPgClient, pgSettings } = context; diff --git a/grafast/website/grafast/getting-started/index.mdx b/grafast/website/grafast/getting-started/index.mdx index 35cb4f9174..e31ee6ee56 100644 --- a/grafast/website/grafast/getting-started/index.mdx +++ b/grafast/website/grafast/getting-started/index.mdx @@ -195,8 +195,8 @@ class AddStep extends ExecutableStep { this.addDependency($b); } - executeV2({ count, values: [aDep, bDep] }) { - return Array.from({ length: count }, (_, i) => { + executeV2({ indexMap, values: [aDep, bDep] }) { + return indexMap((i) => { const a = aDep.at(i); const b = bDep.at(i); return a + b; diff --git a/grafast/website/grafast/index.mdx b/grafast/website/grafast/index.mdx index b22dbbb394..faec5c2ed2 100644 --- a/grafast/website/grafast/index.mdx +++ b/grafast/website/grafast/index.mdx @@ -211,6 +211,8 @@ details** which includes: - `count` — the size of the batch to be executed - `values` — the **values tuple**, the values for each of the dependencies the step added +- `indexMap(callback)` — method returning an array by calling `callback(i)` for + each index `i` in the batch (from `0` to `count-1`) :::note Why `executeV2`? @@ -270,7 +272,7 @@ export class RecordsByColumnStep extends ExecutableStep { this.firstDepId = this.addUnaryDependency($first); } - async executeV2({ count, values }) { + async executeV2({ indexMap, values }) { // Retrieve the values for the `$columnValue` dependency const columnValueDep = values[this.columnValueDepIdx]; @@ -286,11 +288,9 @@ export class RecordsByColumnStep extends ExecutableStep { const limitSQL = Number.isFinite(first) ? `limit ${first}` : ``; // Create placeholders for each entry in our batch in the SQL: - const placeholders = Array.from({ length: count }, () => "?"); - const placeholderValues = Array.from({ length: count }, (_, i) => - // The value from `$columnValue` for this index `i` in the batch - columnValueDep.at(i), - ); + const placeholders = indexMap(() => "?"); + // The value from `$columnValue` for each index `i` in the batch + const columnValues = indexMap((i) => columnValueDep.at(i)); // Build the SQL query to execute: const sql = `\ @@ -301,11 +301,11 @@ export class RecordsByColumnStep extends ExecutableStep { `; // Execute the SQL query once for all values in the batch: - const rows = await executeSQL(sql, placeholderValues); + const rows = await executeSQL(sql, columnValues); // Figure out which rows relate to which batched inputs: - return Array.from({ length: count }, (_, i) => - rows.filter((row) => row[this.columnName] === columnValueDep.at(i)), + return indexMap((i) => + rows.filter((row) => row[this.columnName] === columnValues[i]), ); } } diff --git a/grafast/website/grafast/step-classes.md b/grafast/website/grafast/step-classes.md index 195a0382d4..3567ba3ae0 100644 --- a/grafast/website/grafast/step-classes.md +++ b/grafast/website/grafast/step-classes.md @@ -179,6 +179,8 @@ executeV2(details: ExecutionDetails): PromiseOrDirect interface ExecutionDetails { count: number; values: [...ExecutionValue[]]; + indexMap(callback: (i: number) => T): ReadonlyArray; + indexForEach(callback: (i: number) => any): void; extra: ExecutionExtra; } @@ -199,6 +201,11 @@ It is passed one argument, the "execution details", which is an object containin `n` is the number of dependencies the step has. Each of the entries in the tuple will be an "execution value" containing the data that relates to the corresponding dependency +- `indexMap(callback)` - a helper function that builds an array of length + `count` by calling `callback` for each index in the batch (from `0` to + `count-1`); equivalent to `Array.from({ length: count }, (_, i) => callback(i))` +- `indexForEach(callback)` - a helper function that calls `callback` for each + index in the batch (from `0` to `count-1`) but does not return anything - `extra` — currently experimental, use it at your own risk (and see the source for documentation) @@ -257,8 +264,8 @@ In the [getting started][] guide we built an `AddStep` step class that adds two numbers together. It's `executeV2` method looked like this: ```ts - executeV2({ count, values: [aDep, bDep] }) { - return Array.from({ length: count }, (_, i) => { + executeV2({ indexMap, values: [aDep, bDep] }) { + return indexMap((i) => { const a = aDep.at(i); const b = bDep.at(i); return a + b; @@ -268,9 +275,9 @@ numbers together. It's `executeV2` method looked like this: Imagine at runtime needed to execute this operation for three (`count = 3`) pairs of values: `[1, 2]`, `[3, 4]` and `[5, 6]`. The values for -`$a` would be `aDep.values = [1, 3, 5]` and the values for `$b` would be -`bDep.values = [2, 4, 6]`. The execute method then returns the same number of -results in the same order: `[3, 7, 11]`. +`$a` accessible through `aDep.get(i)` would be `[1, 3, 5]` and the values for +`$b` accessible through `bDep` would be `[2, 4, 6]`. The execute method then +returns the same number of results in the same order: `[3, 7, 11]`. ### streamV2 From 8b797ed0d91140f1be0ebf8c8118d41f955a0a9c Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Fri, 1 Mar 2024 08:09:18 +0000 Subject: [PATCH 40/48] Minor edits --- grafast/grafast/src/steps/applyTransforms.ts | 4 +--- grafast/grafast/src/steps/first.ts | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/grafast/grafast/src/steps/applyTransforms.ts b/grafast/grafast/src/steps/applyTransforms.ts index 9d23be9cab..90b6f030be 100644 --- a/grafast/grafast/src/steps/applyTransforms.ts +++ b/grafast/grafast/src/steps/applyTransforms.ts @@ -173,9 +173,7 @@ export class ApplyTransformsStep extends ExecutableStep { : [store.get(rootStep!.id)!, null]; return indexMap((originalIndex) => { - const list = values0.isBatch - ? values0.entries[originalIndex] - : values0.value; + const list = values0.at(originalIndex); if (list == null) { return list; } diff --git a/grafast/grafast/src/steps/first.ts b/grafast/grafast/src/steps/first.ts index 75a84307ca..e9b13afe2e 100644 --- a/grafast/grafast/src/steps/first.ts +++ b/grafast/grafast/src/steps/first.ts @@ -23,7 +23,7 @@ export class FirstStep extends UnbatchedExecutableStep { executeV2({ indexMap, values: [values0], - }: ExecutionDetails<[TData[]]>): GrafastResultsList { + }: ExecutionDetails<[ReadonlyArray]>): GrafastResultsList { return indexMap((i) => values0.at(i)?.[0]); } From 4e3fccb02630ee65b5428ec44ed566bb7e49ac27 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Fri, 1 Mar 2024 08:09:31 +0000 Subject: [PATCH 41/48] Restore old behavior where data contained promises --- grafast/grafast/src/steps/graphqlResolver.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/grafast/grafast/src/steps/graphqlResolver.ts b/grafast/grafast/src/steps/graphqlResolver.ts index fe6b281d40..8572b81631 100644 --- a/grafast/grafast/src/steps/graphqlResolver.ts +++ b/grafast/grafast/src/steps/graphqlResolver.ts @@ -41,11 +41,7 @@ function dcr( if (data == null) { return data; } - if (Array.isArray(data) && data.some(isPromiseLike)) { - return Promise.all(data).then((data) => ({ data, context, resolveInfo })); - } else { - return { data, context, resolveInfo }; - } + return { data, context, resolveInfo }; } /** From 6ce79d5fad93896a4803e5c8c25e71da78ffaabf Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Fri, 1 Mar 2024 08:14:11 +0000 Subject: [PATCH 42/48] Simplify isBatch expressions down to .at() --- grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts | 4 +--- grafast/grafast/src/steps/listTransform.ts | 9 ++------- grafast/grafast/src/steps/listen.ts | 8 ++------ 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts b/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts index 9245ec22f5..1881037903 100644 --- a/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts +++ b/grafast/dataplan-pg/src/steps/pgValidateParsedCursor.ts @@ -42,9 +42,7 @@ export class PgValidateParsedCursorStep extends ExecutableStep { values: [parsedCursorDep], }: ExecutionDetails<[string | null]>): GrafastResultsList { return indexMap((i) => { - const decoded = parsedCursorDep.isBatch - ? parsedCursorDep.entries[i] - : parsedCursorDep.value; + const decoded = parsedCursorDep.at(i); if (!decoded) { return undefined; } else { diff --git a/grafast/grafast/src/steps/listTransform.ts b/grafast/grafast/src/steps/listTransform.ts index 3244060f86..6df9adf5db 100644 --- a/grafast/grafast/src/steps/listTransform.ts +++ b/grafast/grafast/src/steps/listTransform.ts @@ -253,9 +253,7 @@ export class __ListTransformStep< // We'll typically be creating more listItem bucket entries than we // have parent buckets, so we must "multiply up" the store entries. indexForEach((originalIndex) => { - const list = listStepValue.isBatch - ? listStepValue.entries[originalIndex] - : listStepValue.value; + const list = listStepValue.at(originalIndex); if (Array.isArray(list)) { const newIndexes: number[] = []; map.set(originalIndex, newIndexes); @@ -301,10 +299,7 @@ export class __ListTransformStep< : [store.get(rootStep!.id)!, null]; return indexMap((originalIndex) => { - const list = listStepValue.isBatch - ? listStepValue.entries[originalIndex] - : listStepValue.value; - + const list = listStepValue.at(originalIndex); if (list == null) { return list; } diff --git a/grafast/grafast/src/steps/listen.ts b/grafast/grafast/src/steps/listen.ts index 6d2cc64263..9d3a52ac85 100644 --- a/grafast/grafast/src/steps/listen.ts +++ b/grafast/grafast/src/steps/listen.ts @@ -72,9 +72,7 @@ export class ListenStep< const pubsubValue = values[this.pubsubDep as 0]; const topicValue = values[this.topicDep as 1]; return indexMap((i) => { - const pubsub = pubsubValue.isBatch - ? pubsubValue.entries[i] - : pubsubValue.value; + const pubsub = pubsubValue.at(i); if (!pubsub) { throw new SafeError( "Subscription not supported", @@ -87,9 +85,7 @@ export class ListenStep< : {}, ); } - const topic = topicValue.isBatch - ? topicValue.entries[i] - : topicValue.value; + const topic = topicValue.at(i); return pubsub.subscribe(topic); }); } From b8cfdcf4d655915f48d99d590babed3781576eb3 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Fri, 1 Mar 2024 08:22:40 +0000 Subject: [PATCH 43/48] Minor optimizations --- grafast/grafast/src/steps/listTransform.ts | 9 ++++++--- grafast/grafast/src/steps/remapKeys.ts | 4 +++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/grafast/grafast/src/steps/listTransform.ts b/grafast/grafast/src/steps/listTransform.ts index 6df9adf5db..843911a843 100644 --- a/grafast/grafast/src/steps/listTransform.ts +++ b/grafast/grafast/src/steps/listTransform.ts @@ -204,6 +204,9 @@ export class __ListTransformStep< const childLayerPlan = this.subroutineLayer; const { copyUnaryStepIds, copyBatchStepIds, rootStep } = childLayerPlan; + if (rootStep === null) { + throw new Error(`rootStep of ${childLayerPlan} must not be null.`); + } const store: Bucket["store"] = new Map(); const unaryStore = new Map(); @@ -294,9 +297,9 @@ export class __ListTransformStep< await executeBucket(childBucket, extra._requestContext); } - const [depResults, unaryResult] = rootStep?._isUnary - ? [null, unaryStore.get(rootStep!.id)] - : [store.get(rootStep!.id)!, null]; + const [depResults, unaryResult] = rootStep._isUnary + ? [null, unaryStore.get(rootStep.id)] + : [store.get(rootStep.id)!, null]; return indexMap((originalIndex) => { const list = listStepValue.at(originalIndex); diff --git a/grafast/grafast/src/steps/remapKeys.ts b/grafast/grafast/src/steps/remapKeys.ts index baed03d29e..6f3ed1cc7b 100644 --- a/grafast/grafast/src/steps/remapKeys.ts +++ b/grafast/grafast/src/steps/remapKeys.ts @@ -103,7 +103,9 @@ export class RemapKeysStep extends UnbatchedExecutableStep { indexMap, values: [values0], }: ExecutionDetails): GrafastResultsList { - return indexMap((i) => this.mapper(values0.at(i))); + return values0.isBatch + ? values0.entries.map(this.mapper) + : indexMap((i) => this.mapper(values0.value)); } unbatchedExecute(_extra: UnbatchedExecutionExtra, value: any): any { From 458bed2fe31fbda88627d684dfcd2a1b9c1e051a Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Fri, 1 Mar 2024 08:25:01 +0000 Subject: [PATCH 44/48] Rename command that confuses people --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1e95c53528..065211e40f 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "watch": "yarn build && tsc -b --watch", "clean": "( jest --clearCache || true ) && rm -Rf {utils,grafast,graphile-build,postgraphile}/*/{dist,bundle,tsconfig.tsbuildinfo,tsconfig.build.tsbuildinfo}", "changeset:version": "yarn changeset version && node scripts/postversion.mjs", - "docs:gen": "yarn typedoc .", + "typedoc:gen": "yarn typedoc .", "w": "yarn workspace", "postgraphile": "cd postgraphile/postgraphile && node dist/cli-run.js", "-----": "-----", From 5696496ad5613bf54eb31eae0008a35be00cc34a Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Fri, 1 Mar 2024 08:27:34 +0000 Subject: [PATCH 45/48] Add website commands for people --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index 065211e40f..6abe71329a 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,10 @@ "typedoc:gen": "yarn typedoc .", "w": "yarn workspace", "postgraphile": "cd postgraphile/postgraphile && node dist/cli-run.js", + "website:grafast": "cd grafast/website && yarn start", + "website:postgraphile": "cd postgraphile/website && yarn start", + "website:build": "cd graphile-build/website && yarn start", + "website:star": "cd utils/website && yarn start", "-----": "-----", "eslint": "eslint --ext .js,.jsx,.ts,.tsx", "prettier": "prettier --cache --ignore-path ./.eslintignore", From 3b392a6004d2806de2eb0bbe2d579a3464667f19 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Fri, 1 Mar 2024 08:36:01 +0000 Subject: [PATCH 46/48] Clarification and better advice --- grafast/website/grafast/step-classes.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/grafast/website/grafast/step-classes.md b/grafast/website/grafast/step-classes.md index 3567ba3ae0..205871913f 100644 --- a/grafast/website/grafast/step-classes.md +++ b/grafast/website/grafast/step-classes.md @@ -226,11 +226,12 @@ each entry in the resulting list may or may not be a promise. :::warning If your step has no dependencies If the step has no dependencies then `values` will be a 0-tuple (an empty -tuple), so in situations where this is possible you _must_ use `count` to -determine how many results to return; e.g.: +tuple), but that doesn't mean the batch is empty or has size one, `count` may +be any positive integer. It's therefore recommended that you use `indexMap` to +generate your results in the vast majority of cases: ```ts -return Array.from({ length: count }, () => 42); +return indexMap((i) => 42); ``` ::: @@ -275,9 +276,10 @@ numbers together. It's `executeV2` method looked like this: Imagine at runtime needed to execute this operation for three (`count = 3`) pairs of values: `[1, 2]`, `[3, 4]` and `[5, 6]`. The values for -`$a` accessible through `aDep.get(i)` would be `[1, 3, 5]` and the values for -`$b` accessible through `bDep` would be `[2, 4, 6]`. The execute method then -returns the same number of results in the same order: `[3, 7, 11]`. +`$a` accessible through `aDep.get(i)` would be `1`, `3` and `5`; and the values +for `$b` accessible through `bDep.get(i)` would be `2`, `4` and `6`. The +execute method then returns the same number of results in the same order: `[3, +7, 11]`. ### streamV2 From 71ac409d21eddbfa7bdadaa001274ff62b0d32d4 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Fri, 1 Mar 2024 08:38:09 +0000 Subject: [PATCH 47/48] This error code wasn't used in the end --- grafast/website/src/pages/errors/ud.mdx | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 grafast/website/src/pages/errors/ud.mdx diff --git a/grafast/website/src/pages/errors/ud.mdx b/grafast/website/src/pages/errors/ud.mdx deleted file mode 100644 index dc510acf12..0000000000 --- a/grafast/website/src/pages/errors/ud.mdx +++ /dev/null @@ -1,3 +0,0 @@ -# Unary dependencies - -TODO: detail this error code From 94f2a36dd1821a7e3569193b9e60fdc5299b4e61 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Fri, 1 Mar 2024 09:03:06 +0000 Subject: [PATCH 48/48] Lint/efficiency --- grafast/grafast/src/steps/remapKeys.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grafast/grafast/src/steps/remapKeys.ts b/grafast/grafast/src/steps/remapKeys.ts index 6f3ed1cc7b..5492c3977b 100644 --- a/grafast/grafast/src/steps/remapKeys.ts +++ b/grafast/grafast/src/steps/remapKeys.ts @@ -100,12 +100,12 @@ export class RemapKeysStep extends UnbatchedExecutableStep { } executeV2({ - indexMap, + count, values: [values0], }: ExecutionDetails): GrafastResultsList { return values0.isBatch ? values0.entries.map(this.mapper) - : indexMap((i) => this.mapper(values0.value)); + : new Array(count).fill(this.mapper(values0.value)); } unbatchedExecute(_extra: UnbatchedExecutionExtra, value: any): any {