Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Give gather access to more helpers #2250

Merged
merged 20 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/purple-cats-fetch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"pg-sql2": patch
---

Export version number.
6 changes: 6 additions & 0 deletions .changeset/thin-rocks-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"graphile-config": patch
---

Add support for 'preset.lib' which can be used to store global module references
to help avoid the dual package hazard.
8 changes: 8 additions & 0 deletions .changeset/tidy-poets-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"graphile-build-pg": patch
"graphile-build": patch
---

Integrate preset.lib into build and gather context so plugins can use modules
without needing to install dependencies (and thus avoiding the dual package
hazard).
10 changes: 7 additions & 3 deletions graphile-build/graphile-build-pg/src/plugins/PgBasicsPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import type {
PgResource,
PgResourceUnique,
} from "@dataplan/pg";
import * as dataplanPg from "@dataplan/pg";
import type { GraphQLType } from "grafast/graphql";
import { EXPORTABLE, gatherConfig } from "graphile-build";
import { gatherConfig } from "graphile-build";
import type { SQL } from "pg-sql2";
import sql from "pg-sql2";
import type sql from "pg-sql2";

import { getBehavior } from "../behavior.js";
import type { PgCodecMetaLookup } from "../inputUtils.js";
Expand Down Expand Up @@ -168,6 +167,10 @@ export const PgBasicsPlugin: GraphileConfig.Plugin = {
namespace: "pgBasics",
helpers: {
identifier(info, ...parts) {
const {
sql,
graphileBuild: { EXPORTABLE },
} = info.lib;
switch (info.options.pgIdentifiers) {
case "unqualified": {
// strip the schema
Expand Down Expand Up @@ -380,6 +383,7 @@ export const PgBasicsPlugin: GraphileConfig.Plugin = {
build(build) {
const {
graphql: { GraphQLList, GraphQLNonNull },
lib: { dataplanPg, sql },
} = build;
const pgCodecMetaLookup = getCodecMetaLookupFromInput(build.input);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import type {
PgClass,
PgConstraint,
} from "pg-introspection";
import { sql } from "pg-sql2";

import { version } from "../version.js";

Expand Down Expand Up @@ -168,6 +167,7 @@ export const PgEnumTablesPlugin: GraphileConfig.Plugin = {
return false;
},
async getIntrospectionData(info, serviceName, pgClass, attributes) {
const { sql } = info.lib;
// Load data from the table/view.
const query = sql.compile(
sql.fragment`select ${sql.join(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import type {
PgConstraint,
} from "pg-introspection";
import { parseSmartComment } from "pg-introspection";
import { escapeSqlIdentifier } from "pg-sql2";

import { version } from "../version.js";

Expand Down Expand Up @@ -276,6 +275,8 @@ async function processFk(
pgClass: PgClass,
rawSpec: string | true | (string | true)[],
) {
const { escapeSqlIdentifier } = info.lib.sql;

const identity = () =>
`${pgClass.getNamespace()!.nspname}.${pgClass.relname}`;
const { serviceName, introspection } = event;
Expand Down
16 changes: 10 additions & 6 deletions graphile-build/graphile-build-pg/src/plugins/PgLtreePlugin.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import type { PgCodec } from "@dataplan/pg";
import { listOfCodec } from "@dataplan/pg";
import { EXPORTABLE } from "graphile-build";
import sql from "pg-sql2";
import { gatherConfig } from "graphile-build";

import { version } from "../version.js";

interface State {
ltreeCodec: PgCodec<string, any, any, any, undefined, any, any>;
ltreeArrayCodec: PgCodec;
}
interface Cache {}

declare global {
namespace GraphileConfig {
Expand All @@ -22,8 +21,13 @@ export const PgLtreePlugin: GraphileConfig.Plugin = {
name: "PgLtreePlugin",
version,

gather: {
initialState(): State {
gather: gatherConfig({
initialState(cache: Cache, { lib }): State {
const {
dataplanPg: { listOfCodec },
graphileBuild: { EXPORTABLE },
sql,
} = lib;
const ltreeCodec: PgCodec<string, any, any, any, undefined, any, any> =
EXPORTABLE(
(sql) => ({
Expand Down Expand Up @@ -68,7 +72,7 @@ export const PgLtreePlugin: GraphileConfig.Plugin = {
}
},
},
},
}),
schema: {
hooks: {
init(_, build) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
} from "@dataplan/pg";
import { EXPORTABLE, gatherConfig } from "graphile-build";
import type { PgProc, PgProcArgument } from "pg-introspection";
import sql from "pg-sql2";

import { exportNameHint } from "../utils.js";
import { version } from "../version.js";
Expand Down Expand Up @@ -140,6 +139,7 @@ export const PgProceduresPlugin: GraphileConfig.Plugin = {
namespace: "pgProcedures",
helpers: {
async getResourceOptions(info, serviceName, pgProc) {
const { sql } = info.lib;
let resourceOptionsByPgProc =
info.state.resourceOptionsByPgProcByService.get(serviceName);
if (!resourceOptionsByPgProc) {
Expand Down
29 changes: 28 additions & 1 deletion graphile-build/graphile-build-pg/src/preset.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import "graphile-config";

import * as dataplanPg from "@dataplan/pg";
import { PgContextPlugin } from "@dataplan/pg";
import sql, { version as pgSql2Version } from "pg-sql2";

import { PgRBACPlugin } from "./index.js";
import { PgAllRowsPlugin } from "./plugins/PgAllRowsPlugin.js";
import { PgAttributeDeprecationPlugin } from "./plugins/PgAttributeDeprecationPlugin.js";
import { PgAttributesPlugin } from "./plugins/PgAttributesPlugin.js";
Expand Down Expand Up @@ -32,6 +33,7 @@ import { PgOrderCustomFieldsPlugin } from "./plugins/PgOrderCustomFieldsPlugin.j
import { PgPolymorphismOnlyArgumentPlugin } from "./plugins/PgPolymorphismOnlyArgumentPlugin.js";
import { PgPolymorphismPlugin } from "./plugins/PgPolymorphismPlugin.js";
import { PgProceduresPlugin } from "./plugins/PgProceduresPlugin.js";
import { PgRBACPlugin } from "./plugins/PgRBACPlugin.js";
import { PgRefsPlugin } from "./plugins/PgRefsPlugin.js";
import { PgRegistryPlugin } from "./plugins/PgRegistryPlugin.js";
import { PgRelationsPlugin } from "./plugins/PgRelationsPlugin.js";
Expand All @@ -40,9 +42,34 @@ import { PgRowByUniquePlugin } from "./plugins/PgRowByUniquePlugin.js";
import { PgTableNodePlugin } from "./plugins/PgTableNodePlugin.js";
import { PgTablesPlugin } from "./plugins/PgTablesPlugin.js";
import { PgTypesPlugin } from "./plugins/PgTypesPlugin.js";
import { version } from "./version.js";

declare global {
namespace GraphileConfig {
interface Lib {
/** The `@dataplan/pg` module */
dataplanPg: typeof dataplanPg;
/** The `pg-sql2` module's `sql` export */
sql: typeof sql;
}
}
}

export const GraphileBuildPgLibPreset: GraphileConfig.Preset = {
lib: {
versions: {
"graphile-build-pg": version,
"@dataplan/pg": dataplanPg.version,
"pg-sql2": pgSql2Version,
},
dataplanPg,
sql,
},
};

// TODO: version this.
export const defaultPreset: GraphileConfig.Preset = {
extends: [GraphileBuildPgLibPreset],
plugins: [
PgBasicsPlugin,
PgLtreePlugin,
Expand Down
2 changes: 1 addition & 1 deletion graphile-build/graphile-build/src/SchemaBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class SchemaBuilder<
newWithHooks: NewWithHooksFunction;

constructor(
private resolvedPreset: GraphileConfig.ResolvedPreset,
public readonly resolvedPreset: GraphileConfig.ResolvedPreset,
private inflection: GraphileBuild.Inflection,
) {
super();
Expand Down
6 changes: 6 additions & 0 deletions graphile-build/graphile-build/src/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,12 @@ declare global {
* calling any hooks.
*/
interface BuildBase {
/**
* Various libraries and utilities to save from having to import them in
* plugins (and thereby avoid having module conflict errors).
*/
lib: GraphileConfig.Lib;

/**
* The options that graphile-build was called with.
*/
Expand Down
52 changes: 35 additions & 17 deletions graphile-build/graphile-build/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,12 @@ import type {
} from "grafast/graphql";
import type { PluginHook } from "graphile-config";

import type { GatherPluginContext } from "./interfaces.js";
import type {
GatherPluginContext,
GatherPluginContextBase,
} from "./interfaces.js";
import type { NewWithHooksFunction } from "./newWithHooks/index.js";
import { GraphileBuildLibPreset } from "./preset.js";
import { EXPORTABLE } from "./utils.js";

// export globals for TypeDoc
Expand Down Expand Up @@ -176,6 +180,21 @@ const gatherBase = (
const helpers: { [key: string]: any } = Object.create(null); // GatherHelpers

const hooks = new AsyncHooks<GraphileConfig.GatherHooks>();
const contextBase: GatherPluginContextBase = Object.freeze({
// Global libraries/helpers
lib: resolvedPreset.lib,

// DEPRECATED: use `lib` instead:
grafast,
EXPORTABLE,

// Established by the start of the gather phase
resolvedPreset,
options,
inflection,
process: hooks.process.bind(hooks),
helpers: helpers as GraphileConfig.GatherHelpers,
});

const pluginContext = new Map<
GraphileConfig.Plugin,
Expand All @@ -196,25 +215,18 @@ const gatherBase = (
);
}
const cache = (globalState[specNamespace] =
spec.initialCache?.() ?? Object.create(null));
spec.initialCache?.(contextBase) ?? Object.create(null));
if (typeof cache.then === "function") {
// ENHANCE: can we just make `initialCache` allow promises?
throw new Error(
`\`initialCache\` may not return a promise directly; instead set one of the keys on the object it returns to a promise and await that in \`initialState\` (which is allowed to be async)`,
);
}
const state = EMPTY_OBJECT;
const context: GatherPluginContext<any, any> = {
helpers: helpers as GraphileConfig.GatherHelpers,
options,
state,
const context: GatherPluginContext<any, any> = Object.seal({
...contextBase,
cache,
process: hooks.process.bind(hooks),
inflection,
resolvedPreset,
grafast,
EXPORTABLE,
};
state: EMPTY_OBJECT /* This will be overwritten before it's used */,
});
pluginContext.set(plugin, context);
helpers[specNamespace] = Object.create(null);
if (spec.helpers != null) {
Expand Down Expand Up @@ -261,7 +273,7 @@ const gatherBase = (
const context = pluginContext.get(plugin)!;
const val =
typeof spec.initialState === "function"
? await spec.initialState(context.cache)
? await spec.initialState(context.cache, context)
: Object.create(null);
context.state = gatherState[specNamespace] = val;
}
Expand Down Expand Up @@ -460,12 +472,15 @@ async function writeFileIfDiffers(
* Builds a GraphQL schema according to the given preset and input data.
*/
export const buildSchema = (
preset: GraphileConfig.Preset,
rawPreset: GraphileConfig.Preset,
input: GraphileBuild.BuildInput,
shared: {
inflection?: GraphileBuild.Inflection;
} = {},
): GraphQLSchema => {
const preset = {
extends: [GraphileBuildLibPreset, rawPreset],
};
const builder = getBuilder(preset, shared.inflection);
const schema = builder.buildSchema(input);
const {
Expand Down Expand Up @@ -803,13 +818,16 @@ declare global {
* is an optimisation for watch mode), this returns the value to initialise
* this cache to.
*/
initialCache?: () => TCache;
initialCache?: (context: GatherPluginContextBase) => TCache;

/**
* The initial value to use for this plugin when a new gather run
* executes.
*/
initialState?: (cache: TCache) => PromiseOrDirect<TState>;
initialState?: (
cache: TCache,
context: GatherPluginContextBase,
) => PromiseOrDirect<TState>;

/**
* The plugin must register helpers to allow other plugins to access its
Expand Down
Loading