UNPKG

graphile-build-pg

Version:

Build a GraphQL schema by reflection over a PostgreSQL schema. Easy to customize since it's built with plugins on graphile-build

171 lines (165 loc) 5.87 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _PgComputedColumnsPlugin = require("./PgComputedColumnsPlugin"); var _assert = _interopRequireDefault(require("assert")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function getCompatibleComputedColumns(build, table) { const { pgIntrospectionResultsByKind: introspectionResultsByKind, pgOmit: omit } = build; return introspectionResultsByKind.procedure.reduce((memo, proc) => { /* ALSO SEE PgOrderComputedColumnsPlugin */ // Must be marked @filterable if (!proc.tags.filterable) return memo; // Must not be omitted if (omit(proc, "execute")) return memo; // Must be a computed column const computedColumnDetails = (0, _PgComputedColumnsPlugin.getComputedColumnDetails)(build, table, proc); if (!computedColumnDetails) return memo; const { pseudoColumnName } = computedColumnDetails; // Must have only one required argument const nonOptionalArgumentsCount = proc.inputArgsCount - proc.argDefaultsNum; if (nonOptionalArgumentsCount > 1) { return memo; } // Must return a scalar if (proc.returnsSet) return memo; const returnType = introspectionResultsByKind.typeById[proc.returnTypeId]; if (returnType.isPgArray) return memo; const returnTypeTable = introspectionResultsByKind.classById[returnType.classId]; if (returnTypeTable) return memo; const isRecordLike = returnType.id === "2249"; if (isRecordLike) return memo; const isVoid = String(returnType.id) === "2278"; if (isVoid) return memo; // Looks good memo.push({ proc, pseudoColumnName, returnType }); return memo; }, []); } var PgConditionComputedColumnPlugin = function PgConditionComputedColumnPlugin(builder) { builder.hook("GraphQLInputObjectType:fields", (fields, build, context) => { const { extend, pgGetGqlInputTypeByTypeIdAndModifier, inflection, describePgEntity } = build; const { scope: { isPgCondition, pgIntrospection: table }, fieldWithHooks } = context; if (!isPgCondition || !table || table.kind !== "class") { return fields; } const compatibleComputedColumns = getCompatibleComputedColumns(build, table); return extend(fields, compatibleComputedColumns.reduce((memo, { proc, pseudoColumnName }) => { const fieldName = inflection.computedColumn(pseudoColumnName, proc, table); const Type = pgGetGqlInputTypeByTypeIdAndModifier(proc.returnTypeId, null); if (!Type) return memo; memo = build.extend(memo, { [fieldName]: fieldWithHooks(fieldName, { description: build.wrapDescription(`Checks for equality with the object’s \`${fieldName}\` field.`, "field"), type: Type }, { isPgConnectionConditionInputField: true, pgFieldIntrospection: proc }) }, `Adding computed column condition argument for ${describePgEntity(proc)}`); return memo; }, {})); }, ["PgConditionComputedColumn"]); builder.hook("GraphQLObjectType:fields:field:args", (args, build, context) => { const { pgSql: sql, gql2pg, getTypeByName, pgGetGqlTypeByTypeIdAndModifier, inflection, pgOmit: omit, graphql: { getNullableType } } = build; const { scope: { isPgFieldConnection, isPgFieldSimpleCollection, pgFieldIntrospection, pgFieldIntrospectionTable }, addArgDataGenerator } = context; const shouldAddCondition = isPgFieldConnection || isPgFieldSimpleCollection; if (!shouldAddCondition) return args; if (!args.condition) { return args; } const proc = pgFieldIntrospection.kind === "procedure" ? pgFieldIntrospection : null; const table = pgFieldIntrospection.kind === "class" ? pgFieldIntrospection : proc ? pgFieldIntrospectionTable : null; if (!table || table.kind !== "class" || !table.namespace || omit(table, "filter")) { return args; } const TableType = pgGetGqlTypeByTypeIdAndModifier(table.type.id, null); const TableConditionType = getTypeByName(inflection.conditionType(TableType.name)); if (!TableConditionType) { return args; } (0, _assert.default)(getNullableType(args.condition.type) === TableConditionType, "Condition is present, but doesn't match?"); const compatibleComputedColumns = getCompatibleComputedColumns(build, table).map(o => { const { proc, pseudoColumnName } = o; const fieldName = inflection.computedColumn(pseudoColumnName, proc, table); const sqlFnName = sql.identifier(proc.namespaceName, proc.name); return { ...o, fieldName, sqlFnName }; }); addArgDataGenerator(function connectionCondition({ condition }) { return { pgQuery: queryBuilder => { if (condition != null) { compatibleComputedColumns.forEach(({ fieldName, sqlFnName, returnType }) => { const val = condition[fieldName]; const sqlCall = sql.fragment`${sqlFnName}(${queryBuilder.getTableAlias()})`; if (val != null) { queryBuilder.where(sql.fragment`${sqlCall} = ${gql2pg(val, returnType, null)}`); } else if (val === null) { queryBuilder.where(sql.fragment`${sqlCall} IS NULL`); } }); } } }; }); return args; }, ["PgConditionComputedColumn"]); }; exports.default = PgConditionComputedColumnPlugin; //# sourceMappingURL=PgConditionComputedColumnPlugin.js.map