Skip to content

Commit

Permalink
Rework based on adding argument instead of inside initial plan resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
benjie committed Oct 13, 2023
1 parent f63badb commit bced78b
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 103 deletions.
18 changes: 18 additions & 0 deletions grafast/dataplan-pg/src/steps/pgUnionAll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ export class PgUnionAllStep<
private locker: PgLocker<this> = new PgLocker(this);

private memberDigests: MemberDigest<TTypeNames>[];
private _limitToTypes: string[] | undefined;

constructor(
cloneFrom: PgUnionAllStep<TAttributes, TTypeNames>,
Expand All @@ -534,6 +535,9 @@ export class PgUnionAllStep<
cloneFrom.mode === this.mode ? cloneFrom : null;
this.spec = cloneFrom.spec;
this.memberDigests = cloneDigests(cloneFrom.memberDigests);
this._limitToTypes = cloneFrom._limitToTypes
? [...cloneFrom._limitToTypes]
: undefined;

cloneFrom.dependencies.forEach((planId, idx) => {
const myIdx = this.addDependency(cloneFrom.getDep(idx), true);
Expand Down Expand Up @@ -1516,7 +1520,21 @@ and ${condition(i + 1)}`}
return this.orders;
}

/** @experimental */
limitToTypes(types: readonly string[]): void {
if (!this._limitToTypes) {
this._limitToTypes = [...types];
} else {
this._limitToTypes = this._limitToTypes.filter((t) => types.includes(t));
}
}

optimize() {
if (this._limitToTypes) {
this.memberDigests = this.memberDigests.filter((d) =>
this._limitToTypes!.includes(d.member.typeName),
);
}
if (this.memberDigests.length === 0) {
// We have no implementations, we'll never return anything
return constant([], false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,6 @@ export const PgInterfaceModeUnionAllRowsPlugin: GraphileConfig.Plugin = {
});
}
const interfaceCodecName = interfaceCodec.name;
const onlyArgName =
inflection.pgPolymorphismOnlyArgument(interfaceCodec);
const enumTypeName =
inflection.pgPolymorphismEnumType(interfaceCodec);
const enumType = getTypeByName(enumTypeName);
build.extend(
fields,
{
Expand All @@ -166,104 +161,36 @@ export const PgInterfaceModeUnionAllRowsPlugin: GraphileConfig.Plugin = {
},
{
type: fieldType,
args: {
...(enumType
? {
[onlyArgName]: {
type: new GraphQLList(
new GraphQLNonNull(enumType),
),
description:
"Filter results to only those of the given types",
deprecationReason: "EXPERIMENTAL",
},
}
: null),
},
plan: enumType
? EXPORTABLE(
(
plan: EXPORTABLE(
(
attributes,
connection,
interfaceCodecName,
members,
pgUnionAll,
resourceByTypeName,
useConnection,
) => {
return function plan() {
const $list = pgUnionAll({
attributes,
connection,
interfaceCodecName,
members,
pgUnionAll,
resourceByTypeName,
useConnection,
) => {
return function plan(
_: any,
fieldArgs: FieldArgs,
) {
const $typeNames =
fieldArgs.getRaw(onlyArgName);
const typeNames = $typeNames.eval();
const filteredResources = typeNames
? Object.fromEntries(
Object.entries(resourceByTypeName).filter(
([typeName, _]) =>
typeNames.includes(typeName),
),
)
: resourceByTypeName;
const filteredMembers = typeNames
? members.filter((m) =>
typeNames.includes(m.typeName),
)
: members;
const $list = pgUnionAll({
attributes,
resourceByTypeName: filteredResources,
members: filteredMembers,
name: interfaceCodecName,
});
return useConnection
? connection($list)
: $list;
};
},
[
attributes,
connection,
interfaceCodecName,
members,
pgUnionAll,
resourceByTypeName,
useConnection,
],
)
: EXPORTABLE(
(
attributes,
connection,
interfaceCodecName,
members,
pgUnionAll,
resourceByTypeName,
useConnection,
) => {
return function plan() {
const $list = pgUnionAll({
attributes,
resourceByTypeName,
members,
name: interfaceCodecName,
});
return useConnection
? connection($list)
: $list;
};
},
[
attributes,
connection,
interfaceCodecName,
members,
pgUnionAll,
resourceByTypeName,
useConnection,
],
),
name: interfaceCodecName,
});
return useConnection ? connection($list) : $list;
};
},
[
attributes,
connection,
interfaceCodecName,
members,
pgUnionAll,
resourceByTypeName,
useConnection,
],
),
},
),
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import { GraphileConfig } from "graphile-config";
import { GraphileConfig, PluginHook } from "graphile-config";
import { version } from "../version.js";
import { PgCodec, PgCodecPolymorphismRelationalTypeSpec } from "@dataplan/pg";
import { GraphQLEnumValueConfigMap } from "graphql";
import {
PgCodec,
PgCodecPolymorphismRelationalTypeSpec,
PgUnionAllStep,
} from "@dataplan/pg";
import {
GraphQLEnumValueConfigMap,
GraphQLFieldConfigArgumentMap,
} from "graphql";
import { EXPORTABLE } from "graphile-build";
import {
ConnectionStep,
FieldArgs,
GrafastFieldConfigArgumentMap,
} from "grafast";

declare global {
namespace GraphileBuild {
Expand Down Expand Up @@ -133,6 +146,97 @@ export const PgPolymorphismOnlyArgumentPlugin: GraphileConfig.Plugin = {
}
return values;
},

GraphQLObjectType_fields_field_args: makeFieldsHook(false),
GraphQLInterfaceType_fields_field_args: makeFieldsHook(true),
},
},
};
function makeFieldsHook(isInterface: boolean) {
return (
args:
| GrafastFieldConfigArgumentMap<any, any, any, any>
| GraphQLFieldConfigArgumentMap,

build: GraphileBuild.Build,
context:
| GraphileBuild.ContextObjectFieldsFieldArgs
| GraphileBuild.ContextInterfaceFieldsFieldArgs,
) => {
const {
getTypeByName,
graphql: { GraphQLList, GraphQLNonNull },
inflection,
} = build;
const {
scope: {
pgFieldResource,
pgFieldCodec,
isPgFieldConnection,
isPgFieldSimpleCollection,
},
} = context;
if (!(isPgFieldConnection || isPgFieldSimpleCollection)) {
return args;
}
const codec: PgCodec | undefined = pgFieldCodec ?? pgFieldResource?.codec;
if (!codec || !codec.polymorphism) {
return args;
}
const enumTypeName = inflection.pgPolymorphismEnumType(codec);
const enumType = getTypeByName(enumTypeName);
if (!enumType) {
return args;
}
const argName = inflection.pgPolymorphismOnlyArgument(codec);
if (codec.polymorphism.mode === "union") {
args = build.extend(
args,
{
[argName]: {
type: new GraphQLList(new GraphQLNonNull(enumType)),
description: "Filter results to only those of the given types",
deprecationReason: "EXPERIMENTAL",
...(isInterface
? null
: {
autoApplyAfterParentPlan: true,
applyPlan: isPgFieldConnection
? EXPORTABLE(
() =>
(
$parent: any,
$connection: ConnectionStep<
any,
any,
PgUnionAllStep,
any
>,
fieldArgs: FieldArgs,
) => {
const $union = $connection.getSubplan();
$union.limitToTypes(fieldArgs.getRaw().eval());
},
[],
)
: EXPORTABLE(
() =>
(
$parent: any,
$union: PgUnionAllStep,
fieldArgs: FieldArgs,
) => {
$union.limitToTypes(fieldArgs.getRaw().eval());
},
[],
),
}),
},
},
`Adding "only" argument to union interface polymorphic connection/list field ${context.Self.name}.${context.scope.fieldName}`,
);
}

return args;
};
}

0 comments on commit bced78b

Please sign in to comment.