diff --git a/.changeset/some-beers-drop.md b/.changeset/some-beers-drop.md new file mode 100644 index 0000000000..34406e2eef --- /dev/null +++ b/.changeset/some-beers-drop.md @@ -0,0 +1,6 @@ +--- +"@dataplan/pg": patch +--- + +Fixes an issue where `loadOneWithPgClient`/`loadManyWithPgClient` might result +in `Step>` types. Steps will never represent promises. diff --git a/grafast/dataplan-pg/src/steps/withPgClient.ts b/grafast/dataplan-pg/src/steps/withPgClient.ts index a421c8ee68..ba59f30a90 100644 --- a/grafast/dataplan-pg/src/steps/withPgClient.ts +++ b/grafast/dataplan-pg/src/steps/withPgClient.ts @@ -1,6 +1,7 @@ import type { ExecutionDetails, GrafastResultsList, + LoadManyAwaitedData, LoadManyInfo, LoadManyLoader, LoadManyStep, @@ -156,7 +157,13 @@ export function loadOneWithPgClient< TParams, TShared >, -): LoadOneStep, TItem, TData, TParams, TShared> { +): LoadOneStep< + UnwrapMultistep, + Awaited, + Awaited, + TParams, + TShared +> { const newLoader = transformLoadOneLoader(executor, loader); return loadOne(lookup, newLoader); } @@ -172,7 +179,7 @@ export type LoadOneWithPgClientCallback< pgClient: PgClient, lookups: ReadonlyArray, info: LoadOneInfo, - ): PromiseOrDirect>; + ): PromiseOrDirect>>; displayName?: string; }; @@ -328,7 +335,7 @@ export type LoadManyWithPgClientCallback< pgClient: PgClient, lookups: ReadonlyArray, info: LoadManyInfo, - ): PromiseOrDirect>; + ): PromiseOrDirect>>; displayName?: string; }; @@ -368,7 +375,13 @@ export function loadManyWithPgClient< TParams, TShared >, -): LoadManyStep, TItem, TData, TParams, TShared> { +): LoadManyStep< + UnwrapMultistep, + Awaited, + LoadManyAwaitedData, + TParams, + TShared +> { const newLoader = transformLoadManyLoader(executor, loader); return loadMany(lookup, newLoader); } diff --git a/grafast/grafast/src/index.ts b/grafast/grafast/src/index.ts index e8f5c0ea0c..cb782ac579 100644 --- a/grafast/grafast/src/index.ts +++ b/grafast/grafast/src/index.ts @@ -166,6 +166,7 @@ import type { ListTransformItemPlanCallback, ListTransformOptions, ListTransformReduce, + LoadManyAwaitedData, LoadManyCallback, LoadManyInfo, LoadManyLoader, @@ -375,6 +376,7 @@ export type { ListTransformItemPlanCallback, ListTransformOptions, ListTransformReduce, + LoadManyAwaitedData, LoadManyCallback, LoadManyInfo, LoadManyLoader, diff --git a/grafast/grafast/src/steps/index.ts b/grafast/grafast/src/steps/index.ts index d5d8ca3ca2..198a7c496d 100644 --- a/grafast/grafast/src/steps/index.ts +++ b/grafast/grafast/src/steps/index.ts @@ -79,6 +79,7 @@ export { condition, ConditionStep } from "./condition.ts"; export { graphqlResolver, GraphQLResolverStep } from "./graphqlResolver.ts"; export { LoadedRecordStep } from "./loadedRecord.ts"; export type { + LoadManyAwaitedData, LoadManyCallback, LoadManyInfo, LoadManyLoader, diff --git a/grafast/grafast/src/steps/loadMany.ts b/grafast/grafast/src/steps/loadMany.ts index 446a573661..6e4044ef0b 100644 --- a/grafast/grafast/src/steps/loadMany.ts +++ b/grafast/grafast/src/steps/loadMany.ts @@ -103,6 +103,13 @@ interface LoadManyBaseParams { limit?: Maybe; } +export type LoadManyAwaitedData = + TData extends ReadonlyArray + ? ReadonlyArray> + : TData extends AsyncIterable + ? AsyncIterable> + : TData; + export class LoadManyStep< const TLookup extends Multistep, TItem, @@ -419,12 +426,24 @@ export function loadMany< >( lookup: TLookup, loader: - | LoadManyCallback, TItem, TData, TParams, TShared> - | LoadManyLoader, TItem, TData, TParams, TShared>, + | LoadManyCallback< + UnwrapMultistep, + Awaited, + LoadManyAwaitedData, + TParams, + TShared + > + | LoadManyLoader< + UnwrapMultistep, + Awaited, + LoadManyAwaitedData, + TParams, + TShared + >, ): LoadManyStep< UnwrapMultistep, - TItem, - TData, + Awaited, + LoadManyAwaitedData, TParams, UnwrapMultistep > { @@ -438,8 +457,8 @@ export function loadMany< typeof loader === "function" ? ({ load: loader } as LoadManyLoader< UnwrapMultistep, - TItem, - TData, + Awaited, + LoadManyAwaitedData, TParams, TShared >) diff --git a/grafast/grafast/src/steps/loadOne.ts b/grafast/grafast/src/steps/loadOne.ts index 717b6cdd5b..8fdf4341a0 100644 --- a/grafast/grafast/src/steps/loadOne.ts +++ b/grafast/grafast/src/steps/loadOne.ts @@ -309,13 +309,25 @@ export function loadOne< loader: | LoadOneCallback< UnwrapMultistep, - TItem, - TData, + Awaited, + Awaited, TParams, never // If you want context, you must use the loader object > - | LoadOneLoader, TItem, TData, TParams, TShared>, -): LoadOneStep, TItem, TData, TParams, TShared> { + | LoadOneLoader< + UnwrapMultistep, + Awaited, + Awaited, + TParams, + TShared + >, +): LoadOneStep< + UnwrapMultistep, + Awaited, + Awaited, + TParams, + TShared +> { if (arguments.length > 2) { throw new Error( "The signature of loadOne has changed, additional arguments should now be passed via a 'loader' object: `loadOne(lookup, loader)` where `loader` is either a `load` function or object containing it `{ load, shared?, ioEquivalence?, paginationSupport? }`", @@ -326,8 +338,8 @@ export function loadOne< typeof loader === "function" ? ({ load: loader } as LoadOneLoader< UnwrapMultistep, - TItem, - TData, + Awaited, + Awaited, TParams, TShared >) diff --git a/postgraphile/postgraphile/__tests__/queries/plugins/Issue2212.ts b/postgraphile/postgraphile/__tests__/queries/plugins/Issue2212.ts index e4789142ad..3c82fe27fe 100644 --- a/postgraphile/postgraphile/__tests__/queries/plugins/Issue2212.ts +++ b/postgraphile/postgraphile/__tests__/queries/plugins/Issue2212.ts @@ -1,6 +1,7 @@ import "graphile-config"; import type { PgSelectSingleStep } from "@dataplan/pg"; +import type { LoadOneStep } from "grafast"; import { EXPORTABLE, extendSchema } from "graphile-utils"; const plugin = extendSchema((build) => { @@ -28,7 +29,6 @@ const plugin = extendSchema((build) => { loadManyWithPgClient, normalizePhone, orders, - sql, ) => ($user: PgSelectSingleStep) => { const $id = $user.get("id"); @@ -70,7 +70,8 @@ const plugin = extendSchema((build) => { ); const $orders = orders.find(); $orders.where( - sql`${$orders}.phone_e164 = any(${$orders.placeholder($phoneNumbers, listOfCodec(TYPES.text))})`, + (sql) => + sql`${$orders}.phone_e164 = any(${$orders.placeholder($phoneNumbers, listOfCodec(TYPES.text))})`, ); return connection($orders); }, @@ -82,14 +83,13 @@ const plugin = extendSchema((build) => { loadManyWithPgClient, normalizePhone, orders, - sql, ], ), lifetimeOrderTotal: EXPORTABLE( (executor, loadOneWithPgClient, normalizePhone) => ($user: PgSelectSingleStep) => { const $id = $user.get("id"); - return loadOneWithPgClient( + const $loaded = loadOneWithPgClient( executor, $id, async (pgClient, userIds) => { @@ -131,7 +131,7 @@ const plugin = extendSchema((build) => { }); // Finally - match the inputs to the outputs - return userIds.map((userId) => { + return userIds.map(async (userId) => { const phoneNumbers = phoneNumbersByUserId[userId] ?? new Set(); let total = 0; @@ -147,6 +147,16 @@ const plugin = extendSchema((build) => { }); }, ); + // The type of `$loaded` should NOT involve `Promise<...>` + const $assertion: LoadOneStep< + any, + // TODO: we should be able to assert this is a `number` too... but that is going to need a type overhaul + any, + number, + any, + any + > = $loaded; + return $assertion; }, [executor, loadOneWithPgClient, normalizePhone], ),