postgraphile-plugin-connection-filter
Version:
Filtering on PostGraphile connections
150 lines • 8.24 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PgConnectionArgFilterForwardRelationsPlugin = void 0;
const utils_1 = require("./utils");
const EXPORTABLE_1 = require("./EXPORTABLE");
const version_1 = require("./version");
const pgConnectionFilterApplySingleRelation = (0, EXPORTABLE_1.EXPORTABLE)(() => (assertAllowed, foreignTable, foreignTableExpression, localAttributes, remoteAttributes, sql, $where, value) => {
assertAllowed(value, "object");
if (value == null)
return;
const $subQuery = $where.existsPlan({
tableExpression: foreignTableExpression,
alias: foreignTable.name,
});
localAttributes.forEach((localAttribute, i) => {
const remoteAttribute = remoteAttributes[i];
$subQuery.where(sql `${$where.alias}.${sql.identifier(localAttribute)} = ${$subQuery.alias}.${sql.identifier(remoteAttribute)}`);
});
$subQuery.ignoreUnlessAmended();
return $subQuery;
}, [], "pgConnectionFilterApplySingleRelation");
const pgConnectionFilterApplyForwardRelationExists = (0, EXPORTABLE_1.EXPORTABLE)(() => (assertAllowed, foreignTable, foreignTableExpression, localAttributes, remoteAttributes, sql, $where, value) => {
assertAllowed(value, "scalar");
if (value == null)
return;
const $subQuery = $where.existsPlan({
tableExpression: foreignTableExpression,
alias: foreignTable.name,
equals: value,
});
localAttributes.forEach((localAttribute, i) => {
const remoteAttribute = remoteAttributes[i];
$subQuery.where(sql `${$where.alias}.${sql.identifier(localAttribute)} = ${$subQuery.alias}.${sql.identifier(remoteAttribute)}`);
});
}, [], "pgConnectionFilterApplyForwardRelationExists");
exports.PgConnectionArgFilterForwardRelationsPlugin = {
name: "PgConnectionArgFilterForwardRelationsPlugin",
version: version_1.version,
inflection: {
add: {
filterForwardRelationExistsFieldName(_preset, relationFieldName) {
return `${relationFieldName}Exists`;
},
filterSingleRelationFieldName(_preset, fieldName) {
return fieldName;
},
},
},
schema: {
behaviorRegistry: {
add: {
filterBy: {
description: "Can we filter by the results of this relation?",
entities: ["pgCodecRelation"],
},
},
},
entityBehavior: {
pgCodecRelation: "filterBy",
},
hooks: {
GraphQLInputObjectType_fields(fields, build, context) {
const { extend, inflection, graphql: { GraphQLBoolean }, sql, options: { pgIgnoreReferentialIntegrity }, EXPORTABLE, } = build;
const { fieldWithHooks, scope: { pgCodec, isPgConnectionFilter }, } = context;
const assertAllowed = (0, utils_1.makeAssertAllowed)(build);
const source = pgCodec &&
Object.values(build.input.pgRegistry.pgResources).find((s) => s.codec === pgCodec && !s.parameters);
if (!isPgConnectionFilter ||
!pgCodec ||
!pgCodec.attributes ||
!source) {
return fields;
}
const forwardRelations = Object.entries(source.getRelations()).filter(([_relationName, relation]) => {
return !relation.isReferencee;
});
for (const [relationName, relation] of forwardRelations) {
const foreignTable = relation.remoteResource; // Deliberate shadowing
// Used to use 'read' behavior too
if (!build.behavior.pgCodecRelationMatches(relation, "filterBy")) {
continue;
}
const fieldName = inflection.singleRelation({
registry: source.registry,
codec: source.codec,
relationName,
});
const filterFieldName = inflection.filterSingleRelationFieldName(fieldName);
const foreignTableTypeName = inflection.tableType(foreignTable.codec);
const foreignTableFilterTypeName = inflection.filterType(foreignTableTypeName);
const ForeignTableFilterType = build.getTypeByName(foreignTableFilterTypeName);
if (!ForeignTableFilterType)
continue;
if (typeof foreignTable.from === "function") {
continue;
}
const foreignTableExpression = foreignTable.from;
const localAttributes = relation.localAttributes;
const remoteAttributes = relation.remoteAttributes;
fields = extend(fields, {
[filterFieldName]: fieldWithHooks({
fieldName: filterFieldName,
isPgConnectionFilterField: true,
}, () => ({
description: `Filter by the object’s \`${fieldName}\` relation.`,
type: ForeignTableFilterType,
apply: EXPORTABLE((assertAllowed, foreignTable, foreignTableExpression, localAttributes, pgConnectionFilterApplySingleRelation, remoteAttributes, sql) => function ($where, value) {
return pgConnectionFilterApplySingleRelation(assertAllowed, foreignTable, foreignTableExpression, localAttributes, remoteAttributes, sql, $where, value);
}, [
assertAllowed,
foreignTable,
foreignTableExpression,
localAttributes,
pgConnectionFilterApplySingleRelation,
remoteAttributes,
sql,
]),
})),
}, `Adding connection filter forward relation field from ${source.name} to ${foreignTable.name}`);
const keyIsNullable = relation.localAttributes.some((col) => !source.codec.attributes[col].notNull);
if (keyIsNullable || pgIgnoreReferentialIntegrity) {
const existsFieldName = inflection.filterForwardRelationExistsFieldName(fieldName);
fields = extend(fields, {
[existsFieldName]: fieldWithHooks({
fieldName: existsFieldName,
isPgConnectionFilterField: true,
}, () => ({
description: `A related \`${fieldName}\` exists.`,
type: GraphQLBoolean,
apply: EXPORTABLE((assertAllowed, foreignTable, foreignTableExpression, localAttributes, pgConnectionFilterApplyForwardRelationExists, remoteAttributes, sql) => function ($where, value) {
return pgConnectionFilterApplyForwardRelationExists(assertAllowed, foreignTable, foreignTableExpression, localAttributes, remoteAttributes, sql, $where, value);
}, [
assertAllowed,
foreignTable,
foreignTableExpression,
localAttributes,
pgConnectionFilterApplyForwardRelationExists,
remoteAttributes,
sql,
]),
})),
}, `Adding connection filter forward relation exists field from ${source.name} to ${foreignTable.name}`);
}
}
return fields;
},
},
},
};
//# sourceMappingURL=PgConnectionArgFilterForwardRelationsPlugin.js.map