Skip to content

Commit

Permalink
Preserve string-based approach for selecting adaptor
Browse files Browse the repository at this point in the history
WIP
  • Loading branch information
hannesj committed Apr 24, 2024
1 parent 2cba7b9 commit c394ea4
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 55 deletions.
8 changes: 4 additions & 4 deletions grafast/dataplan-pg/src/adaptors/pg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ export function createWithPgClient(
}

// This is here as a TypeScript assertion, to ensure we conform to PgAdaptor
const _testValidAdaptor: PgAdaptor<PgAdaptorSettings>["createWithPgClient"] =
const _testValidAdaptor: PgAdaptor<"@dataplan/pg/adaptors/pg">["createWithPgClient"] =
createWithPgClient;

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
Expand Down Expand Up @@ -718,8 +718,8 @@ declare global {
}

export function makePgService(
options: MakePgServiceOptions<PgAdaptorSettings> & { pool?: pg.Pool },
): GraphileConfig.PgServiceConfiguration<PgAdaptorSettings> {
options: MakePgServiceOptions & { pool?: pg.Pool },
): GraphileConfig.PgServiceConfiguration {
const {
name = "main",
connectionString,
Expand Down Expand Up @@ -760,7 +760,7 @@ export function makePgService(
pgSubscriber = new PgSubscriber(pool);
releasers.push(() => pgSubscriber!.release?.());
}
const service: GraphileConfig.PgServiceConfiguration<PgAdaptorSettings> = {
const service: GraphileConfig.PgServiceConfiguration = {
name,
schemas: Array.isArray(schemas) ? schemas : [schemas ?? "public"],
withPgClientKey: withPgClientKey as any,
Expand Down
3 changes: 2 additions & 1 deletion grafast/dataplan-pg/src/examples/exampleSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import { inspect } from "util";

import type {
GetPgResourceRelations,
PgClient,
PgCodecAttribute,
PgCodecAttributeVia,
PgConditionStep,
Expand Down Expand Up @@ -4853,7 +4854,7 @@ export function makeExampleSchema(

const MultipleActionsPayload = newObjectTypeBuilder<
OurGraphQLContext,
WithPgClientStep
WithPgClientStep<PgClient>
>(WithPgClientStep)({
name: "MultipleActionsPayload",
fields: {
Expand Down
2 changes: 1 addition & 1 deletion grafast/dataplan-pg/src/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export interface PgClientResult<TData> {
*/
export interface PgClient {
query<TData>(opts: PgClientQuery): Promise<PgClientResult<TData>>;
withTransaction<T>(callback: (client: PgClient) => Promise<T>): Promise<T>;
withTransaction<T>(callback: (client: this) => Promise<T>): Promise<T>;
}

export interface WithPgClient<TPgClient extends PgClient = PgClient> {
Expand Down
26 changes: 21 additions & 5 deletions grafast/dataplan-pg/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { GrafastSubscriber } from "grafast";
import { exportAsMany } from "grafast";

import type { NodePostgresPgClient, PgAdaptorSettings } from "./adaptors/pg.js";
import {
domainOfCodec,
enumCodec,
Expand Down Expand Up @@ -426,15 +427,21 @@ export { version } from "./version.js";

declare global {
namespace GraphileConfig {
interface PgServiceConfiguration<TAdaptorSettings> {
interface PgServiceConfiguration<
TAdaptor extends
keyof GraphileConfig.PgAdaptors = keyof GraphileConfig.PgAdaptors,
> {
name: string;
schemas?: string[];

adaptor: PgAdaptor<TAdaptorSettings>;
adaptorSettings?: TAdaptorSettings;
adaptor: GraphileConfig.PgAdaptors[TAdaptor]["adaptor"];
adaptorSettings?: GraphileConfig.PgAdaptors[TAdaptor]["adaptorSettings"];

/** The key on 'context' where the withPgClient function will be sourced */
withPgClientKey: KeysOfType<Grafast.Context & object, WithPgClient>;
withPgClientKey: KeysOfType<
Grafast.Context & object,
WithPgClient<GraphileConfig.PgAdaptors[TAdaptor]["client"]>
>;

/** Return settings to set in the session */
pgSettings?: (
Expand Down Expand Up @@ -467,7 +474,16 @@ declare global {
}

interface Preset {
pgServices?: ReadonlyArray<PgServiceConfiguration<unknown>>;
pgServices?: ReadonlyArray<PgServiceConfiguration>;
}

interface PgAdaptors {
"@dataplan/pg/adaptors/pg": {
adaptor: PgAdaptor;
adaptorSettings: PgAdaptorSettings;
client: NodePostgresPgClient;
};
/* Add your own via declaration merging */
}
}
namespace DataplanPg {
Expand Down
4 changes: 2 additions & 2 deletions grafast/dataplan-pg/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -415,10 +415,10 @@ export type KeysOfType<TObject, TValueType> = {
[key in keyof TObject]: TObject[key] extends TValueType ? key : never;
}[keyof TObject];

export interface MakePgServiceOptions<TAdaptorSettings>
export interface MakePgServiceOptions
extends Partial<
Pick<
GraphileConfig.PgServiceConfiguration<TAdaptorSettings>,
GraphileConfig.PgServiceConfiguration,
| "name"
| "pgSettings"
| "pgSettingsForIntrospection"
Expand Down
37 changes: 22 additions & 15 deletions grafast/dataplan-pg/src/pgServices.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import type * as pg from "pg";

import type { PgClient, WithPgClient } from "./executor.ts";
import type { PgClient, WithPgClient } from "./executor";
import type { MakePgServiceOptions } from "./interfaces";

type PromiseOrDirect<T> = T | PromiseLike<T>;

/** @experimental */
export interface PgAdaptor<TAdaptorSettings> {
export interface PgAdaptor<
TAdaptor extends
keyof GraphileConfig.PgAdaptors = keyof GraphileConfig.PgAdaptors,
> {
createWithPgClient: (
adaptorSettings: TAdaptorSettings | undefined,
adaptorSettings:
| GraphileConfig.PgAdaptors[TAdaptor]["adaptorSettings"]
| undefined,
variant?: "SUPERUSER" | null,
) => PromiseOrDirect<WithPgClient>;
) => PromiseOrDirect<
WithPgClient<GraphileConfig.PgAdaptors[TAdaptor]["client"]>
>;
makePgService: (
options: MakePgServiceOptions<TAdaptorSettings> & { pool?: pg.Pool },
) => GraphileConfig.PgServiceConfiguration<TAdaptorSettings>;
options: MakePgServiceOptions & { pool?: pg.Pool },
) => GraphileConfig.PgServiceConfiguration;
}

/**
Expand All @@ -28,22 +35,22 @@ export function isPromiseLike<T>(
const isTest = process.env.NODE_ENV === "test";

interface PgClientBySourceCacheValue {
withPgClient: WithPgClient;
withPgClient: WithPgClient<any>;
retainers: number;
}

const withPgClientDetailsByConfigCache = new Map<
GraphileConfig.PgServiceConfiguration<any>,
GraphileConfig.PgServiceConfiguration,
PromiseOrDirect<PgClientBySourceCacheValue>
>();

/**
* Get or build the 'withPgClient' callback function for a given database
* config, caching it to make future lookups faster.
*/
export function getWithPgClientFromPgService<TAdaptorOptions>(
config: GraphileConfig.PgServiceConfiguration<TAdaptorOptions>,
): PromiseOrDirect<WithPgClient> {
export function getWithPgClientFromPgService<TPgClient extends PgClient>(
config: GraphileConfig.PgServiceConfiguration,
): PromiseOrDirect<WithPgClient<TPgClient>> {
const existing = withPgClientDetailsByConfigCache.get(config);
if (existing) {
if (isPromiseLike(existing)) {
Expand Down Expand Up @@ -103,8 +110,8 @@ export function getWithPgClientFromPgService<TAdaptorOptions>(
}
}

export async function withPgClientFromPgService<T, TAdaptorSettings>(
config: GraphileConfig.PgServiceConfiguration<TAdaptorSettings>,
export async function withPgClientFromPgService<T>(
config: GraphileConfig.PgServiceConfiguration,
pgSettings: { [key: string]: string } | null,
callback: (client: PgClient) => T | Promise<T>,
): Promise<T> {
Expand All @@ -120,8 +127,8 @@ export async function withPgClientFromPgService<T, TAdaptorSettings>(
}

// We don't cache superuser withPgClients
export async function withSuperuserPgClientFromPgService<T, TAdaptorSettings>(
config: GraphileConfig.PgServiceConfiguration<TAdaptorSettings>,
export async function withSuperuserPgClientFromPgService<T>(
config: GraphileConfig.PgServiceConfiguration,
pgSettings: { [key: string]: string } | null,
callback: (client: PgClient) => T | Promise<T>,
): Promise<T> {
Expand Down
28 changes: 17 additions & 11 deletions grafast/dataplan-pg/src/steps/withPgClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ import { constant, ExecutableStep } from "grafast";

import type { PgClient, PgExecutor, WithPgClient } from "../executor";

export type WithPgClientStepCallback<TData, TResult> = (
client: PgClient,
data: TData,
) => Promise<TResult>;
export type WithPgClientStepCallback<
TPgClient extends PgClient,
TData,
TResult,
> = (client: TPgClient, data: TData) => Promise<TResult>;

/**
* Runs the given `callback` against the given `executor` using any plan data
* from `$data` (which can be `constant(null)` if you don't need it). Typically
* useful for running custom transactions.
*/
export class WithPgClientStep<
TPgClient extends PgClient,
TData = any,
TResult = any,
> extends ExecutableStep<TResult> {
Expand Down Expand Up @@ -44,7 +46,7 @@ export class WithPgClientStep<
constructor(
executor: PgExecutor,
$data: ExecutableStep<TData>,
private callback: WithPgClientStepCallback<TData, TResult>,
private callback: WithPgClientStepCallback<TPgClient, TData, TResult>,
) {
super();
this.executor = executor;
Expand All @@ -56,7 +58,7 @@ export class WithPgClientStep<
indexMap,
values,
}: ExecutionDetails<
[{ pgSettings: any; withPgClient: WithPgClient }, TData]
[{ pgSettings: any; withPgClient: WithPgClient<TPgClient> }, TData]
>): GrafastResultsList<TResult> {
const contextDep = values[this.contextId as 0];
const dataDep = values[this.dataId as 1];
Expand All @@ -69,12 +71,12 @@ export class WithPgClientStep<
}
}

export function withPgClient<TData, TResult>(
export function withPgClient<TPgClient extends PgClient, TData, TResult>(
executor: PgExecutor,
$data:
| ExecutableStep<TData>
| (TData extends null | undefined ? null | undefined : never),
callback: WithPgClientStepCallback<TData, TResult>,
callback: WithPgClientStepCallback<TPgClient, TData, TResult>,
) {
return new WithPgClientStep(
executor,
Expand All @@ -83,17 +85,21 @@ export function withPgClient<TData, TResult>(
);
}

export function withPgClientTransaction<TData, TResult>(
export function withPgClientTransaction<
TPgClient extends PgClient,
TData,
TResult,
>(
executor: PgExecutor,
$data:
| ExecutableStep<TData>
| (TData extends null | undefined ? null | undefined : never),
callback: WithPgClientStepCallback<TData, TResult>,
callback: WithPgClientStepCallback<TPgClient, TData, TResult>,
) {
return withPgClient(
executor,
$data ?? constant($data as TData),
(client, data) =>
(client: TPgClient, data) =>
client.withTransaction((txClient) => callback(txClient, data)),
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ declare global {
getIntrospection(): PromiseOrDirect<IntrospectionResults>;
getService(serviceName: string): Promise<{
introspection: Introspection;
pgService: GraphileConfig.PgServiceConfiguration<unknown>;
pgService: GraphileConfig.PgServiceConfiguration;
}>;
getExecutorForService(serviceName: string): PgExecutor;

Expand Down Expand Up @@ -229,7 +229,7 @@ declare global {
}

type IntrospectionResults = Array<{
pgService: GraphileConfig.PgServiceConfiguration<unknown>;
pgService: GraphileConfig.PgServiceConfiguration;
introspection: Introspection;
}>;

Expand Down Expand Up @@ -705,9 +705,7 @@ export const PgIntrospectionPlugin: GraphileConfig.Plugin = {
};

function introspectPgServices(
pgServices:
| ReadonlyArray<GraphileConfig.PgServiceConfiguration<unknown>>
| undefined,
pgServices: ReadonlyArray<GraphileConfig.PgServiceConfiguration> | undefined,
): Promise<IntrospectionResults> {
if (!pgServices) {
return Promise.resolve([]);
Expand Down
11 changes: 6 additions & 5 deletions postgraphile/postgraphile/__tests__/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import type {
PgClientResult,
WithPgClient,
} from "@dataplan/pg";
import { createWithPgClient, PgSubscriber } from "@dataplan/pg/adaptors/pg";
import { PgSubscriber } from "@dataplan/pg/adaptors/pg";
import * as PGAdaptor from "@dataplan/pg/adaptors/pg";
import { promises as fsp } from "fs";
import {
$$bypassGraphQL,
Expand Down Expand Up @@ -238,7 +239,7 @@ export async function runTestQuery(
plugins: [StreamDeferPlugin],
pgServices: [
{
adaptor: { createWithPgClient },
adaptor: PGAdaptor,
name: "main",
withPgClientKey: "withPgClient",
pgSettingsKey: "pgSettings",
Expand All @@ -256,15 +257,15 @@ export async function runTestQuery(
search_path,
})
: search_path
? {
? () => ({
search_path,
}
})
: undefined,
schemas: schemas,
adaptorSettings: {
connectionString,
},
} as GraphileConfig.PgServiceConfiguration,
} satisfies GraphileConfig.PgServiceConfiguration<"@dataplan/pg/adaptors/pg">,
],
schema: {
pgForbidSetofFunctionsToReturnNull:
Expand Down
6 changes: 3 additions & 3 deletions postgraphile/postgraphile/__tests__/schema/v4/core.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createWithPgClient } from "@dataplan/pg/adaptors/pg";
import * as PGAdaptor from "@dataplan/pg/adaptors/pg";
import { writeFile } from "fs/promises";
import type { PromiseOrDirect } from "grafast";
import type { GraphQLSchema } from "grafast/graphql";
Expand Down Expand Up @@ -47,7 +47,7 @@ export const test =
plugins: [StripOidsPlugin],
pgServices: [
{
adaptor: { createWithPgClient },
adaptor: PGAdaptor,
name: "main",
withPgClientKey: "withPgClient",
pgSettingsKey: "pgSettings",
Expand All @@ -68,7 +68,7 @@ export const test =
adaptorSettings: {
poolClient: client,
},
} as GraphileConfig.PgServiceConfiguration,
} satisfies GraphileConfig.PgServiceConfiguration<"@dataplan/pg/adaptors/pg">,
],
schema: {
...graphileBuildOptions,
Expand Down
6 changes: 3 additions & 3 deletions postgraphile/postgraphile/__tests__/schema/v5/core.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createWithPgClient } from "@dataplan/pg/adaptors/pg";
import * as PGAdaptor from "@dataplan/pg/adaptors/pg";
import { writeFile } from "fs/promises";
import type { PromiseOrDirect } from "grafast";
import type { GraphQLSchema } from "grafast/graphql";
Expand Down Expand Up @@ -43,7 +43,7 @@ export const test =
plugins: [StripOidsPlugin],
pgServices: [
{
adaptor: { createWithPgClient },
adaptor: PGAdaptor,
name: "main",
withPgClientKey: "withPgClient",
pgSettingsKey: "pgSettings",
Expand All @@ -53,7 +53,7 @@ export const test =
adaptorSettings: {
poolClient: client,
},
} as GraphileConfig.PgServiceConfiguration,
} satisfies GraphileConfig.PgServiceConfiguration<"@dataplan/pg/adaptors/pg">,
],
schema: {
...graphileBuildOptions,
Expand Down

0 comments on commit c394ea4

Please sign in to comment.