Skip to content
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
4 changes: 2 additions & 2 deletions src/AddConnectionFilterOperatorPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { GraphQLInputType } from "graphql";
import { $$filters } from "./interfaces";
import { makeApplyPlanFromOperatorSpec } from "./PgConnectionArgFilterOperatorsPlugin";
import { makeApplyFromOperatorSpec } from "./PgConnectionArgFilterOperatorsPlugin";

const { version } = require("../package.json");

Expand Down Expand Up @@ -103,7 +103,7 @@
{
description,
type,
applyPlan: makeApplyPlanFromOperatorSpec(
apply: makeApplyFromOperatorSpec(
build,
Self.name,
filterName,
Expand Down
45 changes: 26 additions & 19 deletions src/PgConnectionArgFilterAttributesPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import type { PgConditionStep, PgCodecWithAttributes } from "@dataplan/pg";
import type {
PgCodecWithAttributes,
PgConditionCapableParent,
} from "@dataplan/pg";
import type { GraphQLInputObjectType } from "graphql";
import { isEmpty } from "./utils";

const { version } = require("../package.json");

Expand All @@ -17,7 +22,7 @@
const {
inflection,
connectionFilterOperatorsDigest,
dataplanPg: { PgConditionStep },
dataplanPg: { PgCondition },
EXPORTABLE,
} = build;
const {
Expand Down Expand Up @@ -47,7 +52,9 @@
if (!digest) {
continue;
}
const OperatorsType = build.getTypeByName(digest.operatorsTypeName);
const OperatorsType = build.getTypeByName(
digest.operatorsTypeName
) as GraphQLInputObjectType;
if (!OperatorsType) {
continue;
}
Expand All @@ -66,22 +73,24 @@
() => ({
description: `Filter by the object’s \`${fieldName}\` field.`,
type: OperatorsType,
applyPlan: EXPORTABLE(
apply: EXPORTABLE(
(
PgConditionStep,
PgCondition,
colSpec,
connectionFilterAllowEmptyObjectInput,
connectionFilterAllowNullInput
connectionFilterAllowNullInput,
isEmpty
) =>
function ($where: PgConditionStep<any>, fieldArgs: any) {
const $raw = fieldArgs.getRaw();
if ($raw.evalIs(undefined)) {
function (
queryBuilder: PgConditionCapableParent,
value: unknown
) {
if (value === undefined) {
return;
}
if (
!connectionFilterAllowEmptyObjectInput &&
"evalIsEmpty" in $raw &&
$raw.evalIsEmpty()
isEmpty(value)
) {
throw Object.assign(
new Error(
Expand All @@ -92,10 +101,7 @@
}
);
}
if (
!connectionFilterAllowNullInput &&
$raw.evalIs(null)
) {
if (!connectionFilterAllowNullInput && value === null) {
throw Object.assign(
new Error(
"Null literals are forbidden in filter argument input."
Expand All @@ -105,15 +111,16 @@
}
);
}
const $col = new PgConditionStep($where);
$col.extensions.pgFilterAttribute = colSpec;
fieldArgs.apply($col);
const condition = new PgCondition(queryBuilder);
condition.extensions.pgFilterAttribute = colSpec;
return condition;
},
[
PgConditionStep,
PgCondition,
colSpec,
connectionFilterAllowEmptyObjectInput,
connectionFilterAllowNullInput,
isEmpty,
]
),
})
Expand Down
97 changes: 61 additions & 36 deletions src/PgConnectionArgFilterBackwardRelationsPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type {
PgConditionStep,
PgCondition,
PgCodecRelation,
PgCodecWithAttributes,
PgRegistry,
PgResource,
} from "@dataplan/pg";
import { makeAssertAllowed } from "./utils";
import type { GraphQLInputObjectType } from "graphql";

const { version } = require("../package.json");

Expand Down Expand Up @@ -319,7 +320,7 @@
inflection.filterType(foreignTableTypeName);
const ForeignTableFilterType = build.getTypeByName(
foreignTableFilterTypeName
);
) as GraphQLInputObjectType;
if (!ForeignTableFilterType) continue;

if (typeof foreignTable.from === "function") {
Expand All @@ -338,8 +339,14 @@
source.codec,
foreignTable
);
const FilterManyType =
build.getTypeByName(filterManyTypeName);
const FilterManyType = build.getTypeByName(
filterManyTypeName
) as GraphQLInputObjectType;
if (!FilterManyType) {
throw new Error(
`Failed to retrieve type '${filterManyTypeName}'`
);
}
// TODO: revisit using `_` prefixed inflector
const fieldName = inflection._manyRelation({
registry: source.registry,
Expand All @@ -360,7 +367,7 @@
() => ({
description: `Filter by the object’s \`${fieldName}\` relation.`,
type: FilterManyType,
applyPlan: EXPORTABLE(
apply: EXPORTABLE(
(
assertAllowed,
foreignTable,
Expand All @@ -369,10 +376,10 @@
remoteAttributes
) =>
function (
$where: PgConditionStep<any>,
fieldArgs
$where: PgCondition,
value: object | null
) {
assertAllowed(fieldArgs, "object");
assertAllowed(value, "object");
// $where.alias represents source; we need a condition that references the relational target
const $rel = $where.andPlan();
$rel.extensions.pgFilterRelation = {
Expand All @@ -381,7 +388,7 @@
localAttributes,
remoteAttributes,
};
fieldArgs.apply($rel);
return $rel;
},
[
assertAllowed,
Expand Down Expand Up @@ -417,7 +424,7 @@
// and in PgConnectionArgFilterForwardRelationsPlugin
// are very very similar. We should extract them to a
// helper function.
applyPlan: EXPORTABLE(
apply: EXPORTABLE(
(
assertAllowed,
foreignTable,
Expand All @@ -427,14 +434,15 @@
sql
) =>
function (
$where: PgConditionStep<any>,
fieldArgs
$where: PgCondition,
value: boolean | null
) {
assertAllowed(fieldArgs, "scalar");
assertAllowed(value, "scalar");
if (value == null) return;
const $subQuery = $where.existsPlan({
tableExpression: foreignTableExpression,
alias: foreignTable.name,
$equals: fieldArgs.get(),
equals: value as boolean,
});
localAttributes.forEach((localAttribute, i) => {
const remoteAttribute = remoteAttributes[i];
Expand Down Expand Up @@ -483,7 +491,7 @@
() => ({
description: `Filter by the object’s \`${fieldName}\` relation.`,
type: ForeignTableFilterType,
applyPlan: EXPORTABLE(
apply: EXPORTABLE(
(
assertAllowed,
foreignTable,
Expand All @@ -492,8 +500,11 @@
remoteAttributes,
sql
) =>
function ($where: PgConditionStep<any>, fieldArgs) {
assertAllowed(fieldArgs, "object");
function (
$where: PgCondition,
value: object | null
) {
assertAllowed(value, "object");
const $subQuery = $where.existsPlan({
tableExpression: foreignTableExpression,
alias: foreignTable.name,
Expand All @@ -508,7 +519,7 @@
)}`
);
});
fieldArgs.apply($subQuery);
return $subQuery;
},
[
assertAllowed,
Expand Down Expand Up @@ -541,7 +552,7 @@
() => ({
description: `A related \`${fieldName}\` exists.`,
type: GraphQLBoolean,
applyPlan: EXPORTABLE(
apply: EXPORTABLE(
(
assertAllowed,
foreignTable,
Expand All @@ -551,14 +562,15 @@
sql
) =>
function (
$where: PgConditionStep<any>,
fieldArgs
$where: PgCondition,
value: boolean | null
) {
assertAllowed(fieldArgs, "scalar");
assertAllowed(value, "scalar");
if (value == null) return;
const $subQuery = $where.existsPlan({
tableExpression: foreignTableExpression,
alias: foreignTable.name,
$equals: fieldArgs.get(),
equals: value,
});
localAttributes.forEach((localAttribute, i) => {
const remoteAttribute = remoteAttributes[i];
Expand Down Expand Up @@ -596,7 +608,14 @@
);
const foreignTableFilterTypeName =
inflection.filterType(foreignTableTypeName);
const FilterType = build.getTypeByName(foreignTableFilterTypeName);
const FilterType = build.getTypeByName(
foreignTableFilterTypeName
) as GraphQLInputObjectType;
if (!FilterType) {
throw new Error(
`Failed to load type ${foreignTableFilterTypeName}`
);
}

const manyFields = {
every: fieldWithHooks(
Expand All @@ -607,10 +626,14 @@
() => ({
description: `Every related \`${foreignTableTypeName}\` matches the filter criteria. All fields are combined with a logical ‘and.’`,
type: FilterType,
applyPlan: EXPORTABLE(
apply: EXPORTABLE(
(assertAllowed, sql) =>
function ($where: PgConditionStep<any>, fieldArgs) {
assertAllowed(fieldArgs, "object");
function (
$where: PgCondition<any>,
value: object | null
) {
assertAllowed(value, "object");
if (value == null) return;
if (!$where.extensions.pgFilterRelation) {
throw new Error(
`Invalid use of filter, 'pgFilterRelation' expected`
Expand All @@ -636,7 +659,7 @@
)}`
);
});
fieldArgs.apply($subQuery.notPlan().andPlan());
return $subQuery.notPlan().andPlan();
},
[assertAllowed, sql]
),
Expand All @@ -650,10 +673,11 @@
() => ({
description: `Some related \`${foreignTableTypeName}\` matches the filter criteria. All fields are combined with a logical ‘and.’`,
type: FilterType,
applyPlan: EXPORTABLE(
apply: EXPORTABLE(
(assertAllowed, sql) =>
function ($where: PgConditionStep<any>, fieldArgs) {
assertAllowed(fieldArgs, "object");
function ($where: PgCondition, value: object | null) {
assertAllowed(value, "object");
if (value == null) return;
if (!$where.extensions.pgFilterRelation) {
throw new Error(
`Invalid use of filter, 'pgFilterRelation' expected`
Expand All @@ -679,7 +703,7 @@
)}`
);
});
fieldArgs.apply($subQuery);
return $subQuery;
},
[assertAllowed, sql]
),
Expand All @@ -693,10 +717,11 @@
() => ({
description: `No related \`${foreignTableTypeName}\` matches the filter criteria. All fields are combined with a logical ‘and.’`,
type: FilterType,
applyPlan: EXPORTABLE(
apply: EXPORTABLE(
(assertAllowed, sql) =>
function ($where: PgConditionStep<any>, fieldArgs) {
assertAllowed(fieldArgs, "object");
function ($where: PgCondition, value: object | null) {
assertAllowed(value, "object");
if (value == null) return;
if (!$where.extensions.pgFilterRelation) {
throw new Error(
`Invalid use of filter, 'pgFilterRelation' expected`
Expand All @@ -722,7 +747,7 @@
)}`
);
});
fieldArgs.apply($subQuery);
return $subQuery;
},
[assertAllowed, sql]
),
Expand Down
5 changes: 4 additions & 1 deletion src/PgConnectionArgFilterCompositeTypeAttributesPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { PgCodecAttributes, PgCodecWithAttributes } from "@dataplan/pg";
import type { GraphQLInputObjectType } from "graphql";

const { version } = require("../package.json");

Expand Down Expand Up @@ -72,7 +73,9 @@ export const PgConnectionArgFilterCompositeTypeAttributesPlugin: GraphileConfig.
}

const filterTypeName = inflection.filterType(nodeTypeName);
const CompositeFilterType = build.getTypeByName(filterTypeName);
const CompositeFilterType = build.getTypeByName(
filterTypeName
) as GraphQLInputObjectType;
if (!CompositeFilterType) {
continue;
}
Expand Down
Loading
Loading