Postgraphile comes with many good defaults out of the box, but occassionally it’s necessary to replace a default type.
Update 6th Jan: Benjie suggested in discord that it’s better to use the API to query the type OID like this:
const timestampOid = build.pgIntrospectionResultsByKind.type.find(
(type: any) => {
return type.namespaceName === 'pg_catalog' && type.name === 'timestamp';
}).id;
(Old) To replace a type we first need the type’s oid
. In a psql shell do e.g. this:
tom=# select typname, oid from pg_type where typname = 'timestamp';
typname | oid
-----------+------
timestamp | 1114
(1 row)
We will need the oid 1114
later.
In our toy example below (make sure you check timezones work as expected if using it!) we replace
the timestamp
type: Instead of the default ISO 8601 string we return a GraphQL Object with
a new field, human
, that renders e.g. as “2 days ago”.
The actual replacing happens by hooking into the build
phase of the schema builder.
The code below should be faily self-explanatory. The most interesting thing IMO is, that
we can implement the resolver directly in the type.
import { SchemaBuilder } from "postgraphile";
import moment from "moment";
module.exports = (
builder: SchemaBuilder
) => {
builder.hook("build", (build: Build) => {
// Use introspection API to retrieve type OID
const timestampOid = build.pgIntrospectionResultsByKind.type.find(
(type: any) => {
return type.namespaceName === 'pg_catalog' && type.name === 'timestamp';
}).id;
build.pgRegisterGqlTypeByTypeId(
timestampOid,
() => new build.graphql.GraphQLObjectType({
name: 'Datetime',
fields: {
human: {
type: build.graphql.GraphQLNonNull(build.graphql.GraphQLString),
resolve: (parent, a, b) => {
return moment(parent).fromNow();
}
},
},
})
);
return build;
});
}
(Code inspired by this issue)