From a61741ad48770f378767a53a3b0a40ce34880bc1 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 7 Feb 2024 09:50:03 +0000 Subject: [PATCH] Fix double-encoding of queryValues --- grafast/dataplan-pg/src/steps/pgSelect.ts | 3 +- .../queries/v4/connections.boolean.json5 | 40 ++++ .../queries/v4/connections.boolean.mermaid | 180 ++++++++++++++++++ .../queries/v4/connections.boolean.sql | 37 ++++ .../v4/connections.boolean.test.graphql | 37 ++++ 5 files changed, 295 insertions(+), 2 deletions(-) create mode 100644 postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.json5 create mode 100644 postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.mermaid create mode 100644 postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.sql create mode 100644 postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.test.graphql diff --git a/grafast/dataplan-pg/src/steps/pgSelect.ts b/grafast/dataplan-pg/src/steps/pgSelect.ts index ec25a9995b..c0215a3014 100644 --- a/grafast/dataplan-pg/src/steps/pgSelect.ts +++ b/grafast/dataplan-pg/src/steps/pgSelect.ts @@ -67,7 +67,6 @@ import { pgPageInfo } from "./pgPageInfo.js"; import type { PgSelectSinglePlanOptions } from "./pgSelectSingle.js"; import { PgSelectSingleStep } from "./pgSelectSingle.js"; import { pgValidateParsedCursor } from "./pgValidateParsedCursor.js"; -import { toPg } from "./toPg.js"; export type PgSelectParsedCursorStep = LambdaStep; @@ -1099,7 +1098,7 @@ export class PgSelectStep< getFragmentAndCodecFromOrder(this.alias, order, this.resource.codec); const { nulls, direction } = order; const sqlValue = this.placeholder( - toPg(access($parsedCursorPlan, [i + 1]), orderCodec), + access($parsedCursorPlan, [i + 1]), orderCodec, ); diff --git a/postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.json5 b/postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.json5 new file mode 100644 index 0000000000..3779fcb006 --- /dev/null +++ b/postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.json5 @@ -0,0 +1,40 @@ +{ + page1: { + pageInfo: { + startCursor: "WyIzNjY0MzE3ZDgwIixmYWxzZSwyLDFd", + endCursor: "WyIzNjY0MzE3ZDgwIixmYWxzZSwyLDFd", + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 6, + edges: [ + { + cursor: "WyIzNjY0MzE3ZDgwIixmYWxzZSwyLDFd", + node: { + extra: false, + personId1: 2, + personId2: 1, + }, + }, + ], + }, + page2: { + pageInfo: { + startCursor: "WyIzNjY0MzE3ZDgwIixmYWxzZSw0LDRd", + endCursor: "WyIzNjY0MzE3ZDgwIixmYWxzZSw0LDRd", + hasNextPage: true, + hasPreviousPage: false, + }, + totalCount: 6, + edges: [ + { + cursor: "WyIzNjY0MzE3ZDgwIixmYWxzZSw0LDRd", + node: { + extra: false, + personId1: 4, + personId2: 4, + }, + }, + ], + }, +} diff --git a/postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.mermaid b/postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.mermaid new file mode 100644 index 0000000000..61c2873110 --- /dev/null +++ b/postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.mermaid @@ -0,0 +1,180 @@ +%%{init: {'themeVariables': { 'fontSize': '12px'}}}%% +graph TD + classDef path fill:#eee,stroke:#000,color:#000 + classDef plan fill:#fff,stroke-width:1px,color:#000 + classDef itemplan fill:#fff,stroke-width:2px,color:#000 + classDef unbatchedplan fill:#dff,stroke-width:1px,color:#000 + classDef sideeffectplan fill:#fcc,stroke-width:2px,color:#000 + classDef bucket fill:#f6f6f6,color:#000,stroke-width:2px,text-align:left + + + %% plan dependencies + Connection71{{"Connection[71∈0]
ᐸ67ᐳ"}}:::plan + Constant124{{"Constant[124∈0]
ᐸ1ᐳ"}}:::plan + Lambda72{{"Lambda[72∈0]
ᐸparseCursorᐳ"}}:::plan + PgValidateParsedCursor78["PgValidateParsedCursor[78∈0]"]:::plan + Constant124 & Lambda72 & PgValidateParsedCursor78 & PgValidateParsedCursor78 & PgValidateParsedCursor78 & PgValidateParsedCursor78 --> Connection71 + Object20{{"Object[20∈0]
ᐸ{pgSettings,withPgClient}ᐳ"}}:::plan + Access18{{"Access[18∈0]
ᐸ3.pgSettingsᐳ"}}:::plan + Access19{{"Access[19∈0]
ᐸ3.withPgClientᐳ"}}:::plan + Access18 & Access19 --> Object20 + __Value3["__Value[3∈0]
ᐸcontextᐳ"]:::plan + __Value3 --> Access18 + __Value3 --> Access19 + Connection21{{"Connection[21∈0]
ᐸ17ᐳ"}}:::plan + Constant124 --> Connection21 + Constant126{{"Constant[126∈0]
ᐸ'WyIzNjY0MzE3ZDgwIixmYWxzZSwyLDFd'ᐳ"}}:::plan + Constant126 --> Lambda72 + Lambda72 --> PgValidateParsedCursor78 + __Value0["__Value[0∈0]"]:::plan + __Value5["__Value[5∈0]
ᐸrootValueᐳ"]:::plan + Constant41{{"Constant[41∈0]
ᐸfalseᐳ"}}:::plan + List30{{"List[30∈1]
ᐸ27,28,29ᐳ"}}:::plan + PgClassExpression27{{"PgClassExpression[27∈1]
ᐸ__compound...__.”extra”ᐳ"}}:::plan + PgClassExpression28{{"PgClassExpression[28∈1]
ᐸ__compound...rson_id_1”ᐳ"}}:::plan + PgClassExpression29{{"PgClassExpression[29∈1]
ᐸ__compound...rson_id_2”ᐳ"}}:::plan + PgClassExpression27 & PgClassExpression28 & PgClassExpression29 --> List30 + List38{{"List[38∈1]
ᐸ35,36,37ᐳ"}}:::plan + PgClassExpression35{{"PgClassExpression[35∈1]
ᐸ__compound...__.”extra”ᐳ"}}:::plan + PgClassExpression36{{"PgClassExpression[36∈1]
ᐸ__compound...rson_id_1”ᐳ"}}:::plan + PgClassExpression37{{"PgClassExpression[37∈1]
ᐸ__compound...rson_id_2”ᐳ"}}:::plan + PgClassExpression35 & PgClassExpression36 & PgClassExpression37 --> List38 + PgSelect23[["PgSelect[23∈1]
ᐸcompound_key+1ᐳ"]]:::plan + Object20 & Connection21 --> PgSelect23 + PgSelect42[["PgSelect[42∈1]
ᐸcompound_key(aggregate)ᐳ"]]:::plan + Object20 & Connection21 --> PgSelect42 + PgPageInfo22{{"PgPageInfo[22∈1]"}}:::plan + Connection21 --> PgPageInfo22 + First24{{"First[24∈1]"}}:::plan + PgSelect23 --> First24 + PgSelectSingle25{{"PgSelectSingle[25∈1]
ᐸcompound_keyᐳ"}}:::plan + First24 --> PgSelectSingle25 + PgCursor26{{"PgCursor[26∈1]"}}:::plan + List30 --> PgCursor26 + PgSelectSingle25 --> PgClassExpression27 + PgSelectSingle25 --> PgClassExpression28 + PgSelectSingle25 --> PgClassExpression29 + Last32{{"Last[32∈1]"}}:::plan + PgSelect23 --> Last32 + PgSelectSingle33{{"PgSelectSingle[33∈1]
ᐸcompound_keyᐳ"}}:::plan + Last32 --> PgSelectSingle33 + PgCursor34{{"PgCursor[34∈1]"}}:::plan + List38 --> PgCursor34 + PgSelectSingle33 --> PgClassExpression35 + PgSelectSingle33 --> PgClassExpression36 + PgSelectSingle33 --> PgClassExpression37 + Access40{{"Access[40∈1]
ᐸ23.hasMoreᐳ"}}:::plan + PgSelect23 --> Access40 + First43{{"First[43∈1]"}}:::plan + PgSelect42 --> First43 + PgSelectSingle44{{"PgSelectSingle[44∈1]
ᐸcompound_keyᐳ"}}:::plan + First43 --> PgSelectSingle44 + PgClassExpression45{{"PgClassExpression[45∈1]
ᐸcount(*)ᐳ"}}:::plan + PgSelectSingle44 --> PgClassExpression45 + __Item47[/"__Item[47∈2]
ᐸ23ᐳ"\]:::itemplan + PgSelect23 ==> __Item47 + PgSelectSingle48{{"PgSelectSingle[48∈2]
ᐸcompound_keyᐳ"}}:::plan + __Item47 --> PgSelectSingle48 + List53{{"List[53∈3]
ᐸ50,51,52ᐳ"}}:::plan + PgClassExpression50{{"PgClassExpression[50∈3]
ᐸ__compound...__.”extra”ᐳ"}}:::plan + PgClassExpression51{{"PgClassExpression[51∈3]
ᐸ__compound...rson_id_1”ᐳ"}}:::plan + PgClassExpression52{{"PgClassExpression[52∈3]
ᐸ__compound...rson_id_2”ᐳ"}}:::plan + PgClassExpression50 & PgClassExpression51 & PgClassExpression52 --> List53 + PgCursor49{{"PgCursor[49∈3]"}}:::plan + List53 --> PgCursor49 + PgSelectSingle48 --> PgClassExpression50 + PgSelectSingle48 --> PgClassExpression51 + PgSelectSingle48 --> PgClassExpression52 + PgSelect74[["PgSelect[74∈4]
ᐸcompound_key+1ᐳ"]]:::plan + Access79{{"Access[79∈4]
ᐸ72.1ᐳ"}}:::plan + Access80{{"Access[80∈4]
ᐸ72.2ᐳ"}}:::plan + Access81{{"Access[81∈4]
ᐸ72.3ᐳ"}}:::plan + Object20 & Connection71 & Lambda72 & Access79 & Access80 & Access81 --> PgSelect74 + List85{{"List[85∈4]
ᐸ82,83,84ᐳ"}}:::plan + PgClassExpression82{{"PgClassExpression[82∈4]
ᐸ__compound...__.”extra”ᐳ"}}:::plan + PgClassExpression83{{"PgClassExpression[83∈4]
ᐸ__compound...rson_id_1”ᐳ"}}:::plan + PgClassExpression84{{"PgClassExpression[84∈4]
ᐸ__compound...rson_id_2”ᐳ"}}:::plan + PgClassExpression82 & PgClassExpression83 & PgClassExpression84 --> List85 + List97{{"List[97∈4]
ᐸ94,95,96ᐳ"}}:::plan + PgClassExpression94{{"PgClassExpression[94∈4]
ᐸ__compound...__.”extra”ᐳ"}}:::plan + PgClassExpression95{{"PgClassExpression[95∈4]
ᐸ__compound...rson_id_1”ᐳ"}}:::plan + PgClassExpression96{{"PgClassExpression[96∈4]
ᐸ__compound...rson_id_2”ᐳ"}}:::plan + PgClassExpression94 & PgClassExpression95 & PgClassExpression96 --> List97 + PgSelect105[["PgSelect[105∈4]
ᐸcompound_key(aggregate)ᐳ"]]:::plan + Object20 & Connection71 --> PgSelect105 + PgPageInfo73{{"PgPageInfo[73∈4]"}}:::plan + Connection71 --> PgPageInfo73 + First75{{"First[75∈4]"}}:::plan + PgSelect74 --> First75 + PgSelectSingle76{{"PgSelectSingle[76∈4]
ᐸcompound_keyᐳ"}}:::plan + First75 --> PgSelectSingle76 + PgCursor77{{"PgCursor[77∈4]"}}:::plan + List85 --> PgCursor77 + Lambda72 --> Access79 + Lambda72 --> Access80 + Lambda72 --> Access81 + PgSelectSingle76 --> PgClassExpression82 + PgSelectSingle76 --> PgClassExpression83 + PgSelectSingle76 --> PgClassExpression84 + Last87{{"Last[87∈4]"}}:::plan + PgSelect74 --> Last87 + PgSelectSingle88{{"PgSelectSingle[88∈4]
ᐸcompound_keyᐳ"}}:::plan + Last87 --> PgSelectSingle88 + PgCursor89{{"PgCursor[89∈4]"}}:::plan + List97 --> PgCursor89 + PgSelectSingle88 --> PgClassExpression94 + PgSelectSingle88 --> PgClassExpression95 + PgSelectSingle88 --> PgClassExpression96 + Access99{{"Access[99∈4]
ᐸ74.hasMoreᐳ"}}:::plan + PgSelect74 --> Access99 + First106{{"First[106∈4]"}}:::plan + PgSelect105 --> First106 + PgSelectSingle107{{"PgSelectSingle[107∈4]
ᐸcompound_keyᐳ"}}:::plan + First106 --> PgSelectSingle107 + PgClassExpression108{{"PgClassExpression[108∈4]
ᐸcount(*)ᐳ"}}:::plan + PgSelectSingle107 --> PgClassExpression108 + __Item114[/"__Item[114∈5]
ᐸ74ᐳ"\]:::itemplan + PgSelect74 ==> __Item114 + PgSelectSingle115{{"PgSelectSingle[115∈5]
ᐸcompound_keyᐳ"}}:::plan + __Item114 --> PgSelectSingle115 + List120{{"List[120∈6]
ᐸ117,118,119ᐳ"}}:::plan + PgClassExpression117{{"PgClassExpression[117∈6]
ᐸ__compound...__.”extra”ᐳ"}}:::plan + PgClassExpression118{{"PgClassExpression[118∈6]
ᐸ__compound...rson_id_1”ᐳ"}}:::plan + PgClassExpression119{{"PgClassExpression[119∈6]
ᐸ__compound...rson_id_2”ᐳ"}}:::plan + PgClassExpression117 & PgClassExpression118 & PgClassExpression119 --> List120 + PgCursor116{{"PgCursor[116∈6]"}}:::plan + List120 --> PgCursor116 + PgSelectSingle115 --> PgClassExpression117 + PgSelectSingle115 --> PgClassExpression118 + PgSelectSingle115 --> PgClassExpression119 + + %% define steps + + subgraph "Buckets for queries/v4/connections.boolean" + Bucket0("Bucket 0 (root)
1:
ᐳ: 18, 19, 41, 124, 126, 20, 21, 72
2: PgValidateParsedCursor[78]
ᐳ: Connection[71]"):::bucket + classDef bucket0 stroke:#696969 + class Bucket0,__Value0,__Value3,__Value5,Access18,Access19,Object20,Connection21,Constant41,Connection71,Lambda72,PgValidateParsedCursor78,Constant124,Constant126 bucket0 + Bucket1("Bucket 1 (nullableBoundary)
Deps: 21, 20, 41

ROOT Connectionᐸ17ᐳ[21]"):::bucket + classDef bucket1 stroke:#00bfff + class Bucket1,PgPageInfo22,PgSelect23,First24,PgSelectSingle25,PgCursor26,PgClassExpression27,PgClassExpression28,PgClassExpression29,List30,Last32,PgSelectSingle33,PgCursor34,PgClassExpression35,PgClassExpression36,PgClassExpression37,List38,Access40,PgSelect42,First43,PgSelectSingle44,PgClassExpression45 bucket1 + Bucket2("Bucket 2 (listItem)
ROOT __Item{2}ᐸ23ᐳ[47]"):::bucket + classDef bucket2 stroke:#7f007f + class Bucket2,__Item47,PgSelectSingle48 bucket2 + Bucket3("Bucket 3 (nullableBoundary)
Deps: 48

ROOT PgSelectSingle{2}ᐸcompound_keyᐳ[48]"):::bucket + classDef bucket3 stroke:#ffa500 + class Bucket3,PgCursor49,PgClassExpression50,PgClassExpression51,PgClassExpression52,List53 bucket3 + Bucket4("Bucket 4 (nullableBoundary)
Deps: 71, 20, 72, 41

ROOT Connectionᐸ67ᐳ[71]
1: PgSelect[105]
ᐳ: 73, 79, 80, 81, 106, 107, 108
2: PgSelect[74]
ᐳ: 75, 76, 82, 83, 84, 85, 87, 88, 94, 95, 96, 97, 99, 77, 89"):::bucket + classDef bucket4 stroke:#0000ff + class Bucket4,PgPageInfo73,PgSelect74,First75,PgSelectSingle76,PgCursor77,Access79,Access80,Access81,PgClassExpression82,PgClassExpression83,PgClassExpression84,List85,Last87,PgSelectSingle88,PgCursor89,PgClassExpression94,PgClassExpression95,PgClassExpression96,List97,Access99,PgSelect105,First106,PgSelectSingle107,PgClassExpression108 bucket4 + Bucket5("Bucket 5 (listItem)
ROOT __Item{5}ᐸ74ᐳ[114]"):::bucket + classDef bucket5 stroke:#7fff00 + class Bucket5,__Item114,PgSelectSingle115 bucket5 + Bucket6("Bucket 6 (nullableBoundary)
Deps: 115

ROOT PgSelectSingle{5}ᐸcompound_keyᐳ[115]"):::bucket + classDef bucket6 stroke:#ff1493 + class Bucket6,PgCursor116,PgClassExpression117,PgClassExpression118,PgClassExpression119,List120 bucket6 + Bucket0 --> Bucket1 & Bucket4 + Bucket1 --> Bucket2 + Bucket2 --> Bucket3 + Bucket4 --> Bucket5 + Bucket5 --> Bucket6 + end diff --git a/postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.sql b/postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.sql new file mode 100644 index 0000000000..3a3001ded4 --- /dev/null +++ b/postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.sql @@ -0,0 +1,37 @@ +select + __compound_key__."extra"::text as "0", + __compound_key__."person_id_1"::text as "1", + __compound_key__."person_id_2"::text as "2" +from "c"."compound_key" as __compound_key__ +order by __compound_key__."extra" asc, __compound_key__."person_id_1" asc, __compound_key__."person_id_2" asc +limit 2; + +select + (count(*))::text as "0" +from "c"."compound_key" as __compound_key__; + +select __compound_key_result__.* +from (select 0 as idx, $1::"bool" as "id0", $2::"int4" as "id1", $3::"int4" as "id2") as __compound_key_identifiers__, +lateral ( + select + __compound_key__."extra"::text as "0", + __compound_key__."person_id_1"::text as "1", + __compound_key__."person_id_2"::text as "2", + __compound_key_identifiers__.idx as "3" + from "c"."compound_key" as __compound_key__ + where ( + (((__compound_key__."extra" > __compound_key_identifiers__."id0") or (__compound_key__."extra" is not null and __compound_key_identifiers__."id0" is null))) + or ( + __compound_key__."extra" is not distinct from __compound_key_identifiers__."id0" + and + ((__compound_key__."person_id_1" > __compound_key_identifiers__."id1") + or ( + __compound_key__."person_id_1" = __compound_key_identifiers__."id1" + and + (__compound_key__."person_id_2" > __compound_key_identifiers__."id2") + )) + ) + ) + order by __compound_key__."extra" asc, __compound_key__."person_id_1" asc, __compound_key__."person_id_2" asc + limit 2 +) as __compound_key_result__; \ No newline at end of file diff --git a/postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.test.graphql b/postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.test.graphql new file mode 100644 index 0000000000..eed7a50f18 --- /dev/null +++ b/postgraphile/postgraphile/__tests__/queries/v4/connections.boolean.test.graphql @@ -0,0 +1,37 @@ +## expect(errors).toBeFalsy(); +## expect(data.page1.pageInfo.endCursor).toEqual("WyIzNjY0MzE3ZDgwIixmYWxzZSwyLDFd") +#> schema: ["a", "b", "c"] +#> subscriptions: true +query { + page1: allCompoundKeys( + orderBy: [EXTRA_ASC, PERSON_ID_1_ASC, PERSON_ID_2_ASC] + first: 1 + ) { + ...compoundKeysConnection + } + page2: allCompoundKeys( + orderBy: [EXTRA_ASC, PERSON_ID_1_ASC, PERSON_ID_2_ASC] + first: 1 + after: "WyIzNjY0MzE3ZDgwIixmYWxzZSwyLDFd" + ) { + ...compoundKeysConnection + } +} + +fragment compoundKeysConnection on CompoundKeysConnection { + pageInfo { + startCursor + endCursor + hasNextPage + hasPreviousPage + } + totalCount + edges { + cursor + node { + extra + personId1 + personId2 + } + } +}