Created
December 31, 2022 19:01
-
-
Save ttfkam/1ac171945ec1b5fab36034afeb7a541a to your computer and use it in GitHub Desktop.
Enhance Postgraphile compatibility with PostgREST
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { Plugin, Build } from "graphile-build"; | |
import type { PgClass, PgProc } from "./PgIntrospectionPlugin"; | |
export const getComputedColumnDetails = ( | |
build: Build, | |
table: PgClass, | |
proc: PgProc | |
) => { | |
if (proc.isVolatile) return null; | |
if (proc.namespaceId !== table.namespaceId) return null; | |
if (proc.argTypeIds.length < 1) return null; | |
if (proc.argTypeIds[0] !== table.type.id) return null; | |
const argTypes = proc.argTypeIds.reduce((prev, typeId, idx) => { | |
if ( | |
proc.argModes.length === 0 || // all args are `in` | |
proc.argModes[idx] === "i" || // this arg is `in` | |
proc.argModes[idx] === "b" // this arg is `inout` | |
) { | |
prev.push(build.pgIntrospectionResultsByKind.typeById[typeId]); | |
} | |
return prev; | |
}, []); | |
if ( | |
argTypes | |
.slice(1) | |
.some(type => type.type === "c" && type.class && type.class.isSelectable) | |
) { | |
// Accepts two input tables? Skip. | |
return null; | |
} | |
const pseudoColumnName = proc.name.startsWith(`${table.name}_`) ? proc.name.slice(table.name.length + 1) : proc.name; | |
return { argTypes, pseudoColumnName }; | |
}; | |
export default (function PgComputedColumnsPlugin( | |
builder, | |
{ pgSimpleCollections, pgComputedColumnNames } | |
) { | |
builder.hook( | |
"GraphQLObjectType:fields", | |
(fields, build, context) => { | |
const { | |
scope: { | |
isPgRowType, | |
isPgCompoundType, | |
isInputType, | |
pgIntrospection: table, | |
}, | |
fieldWithHooks, | |
Self, | |
} = context; | |
if ( | |
isInputType || | |
!(isPgRowType || isPgCompoundType) || | |
!table || | |
table.kind !== "class" || | |
!table.namespace | |
) { | |
return fields; | |
} | |
const { | |
extend, | |
pgIntrospectionResultsByKind: introspectionResultsByKind, | |
inflection, | |
pgOmit: omit, | |
pgMakeProcField: makeProcField, | |
swallowError, | |
describePgEntity, | |
sqlCommentByAddingTags, | |
} = build; | |
const tableType = table.type; | |
if (!tableType) { | |
throw new Error("Could not determine the type for this table"); | |
} | |
return extend( | |
fields, | |
introspectionResultsByKind.procedure.reduce((memo, proc) => { | |
if (omit(proc, "execute")) return memo; | |
const isVerboseName = proc.name.startsWith(`${table.name}_`); | |
if ((isVerboseName && pgComputedColumnNames === 'simple') || | |
(!isVerboseName && pgComputedColumnNames === 'verbose')) { | |
return memo; | |
} | |
const computedColumnDetails = getComputedColumnDetails( | |
build, | |
table, | |
proc | |
); | |
if (!computedColumnDetails) return memo; | |
const { pseudoColumnName } = computedColumnDetails; | |
function makeField(forceList) { | |
const fieldName = forceList | |
? inflection.computedColumnList(pseudoColumnName, proc, table) | |
: inflection.computedColumn(pseudoColumnName, proc, table); | |
try { | |
memo = extend( | |
memo, | |
{ | |
[fieldName]: makeProcField(fieldName, proc, build, { | |
fieldWithHooks, | |
computed: true, | |
forceList, | |
}), | |
}, | |
`Adding computed column for ${describePgEntity( | |
proc | |
)}. You can rename this field with a 'Smart Comment':\n\n ${sqlCommentByAddingTags( | |
proc, | |
{ | |
fieldName: "newNameHere", | |
} | |
)}` | |
); | |
} catch (e) { | |
swallowError(e); | |
} | |
} | |
const simpleCollections = | |
proc.tags.simpleCollections || pgSimpleCollections; | |
const hasConnections = simpleCollections !== "only"; | |
const hasSimpleCollections = | |
simpleCollections === "only" || simpleCollections === "both"; | |
if (!proc.returnsSet || hasConnections) { | |
makeField(false); | |
} | |
if (proc.returnsSet && hasSimpleCollections) { | |
makeField(true); | |
} | |
return memo; | |
}, {}), | |
`Adding computed column to '${Self.name}'` | |
); | |
}, | |
["PgComputedColumns"] | |
); | |
}: Plugin); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment