Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recipe: translate range types to/from Postgres' format instead of the object version #341

Open
dmfay opened this issue Oct 26, 2022 · 0 comments

Comments

@dmfay
Copy link

dmfay commented Oct 26, 2022

Sometimes the old way is more convenient :)

import { GraphQLScalarType } from "graphql"
import type { SchemaBuilder, Build } from "graphile-build"
import type { PgType } from "graphile-build-pg"

/**
 * This plugin switches the expression of range types back to Postgres' native
 * `[lower,upper)` formats instead of Postgraphile's more verbose nested-object
 * `{start: {value, inclusive}, end: {...}` version.
 */
export default function TranslateRangesPlugin(builder: SchemaBuilder) {
    builder.hook("build", (build: Build) => {
        const {
            pgIntrospectionResultsByKind,
            pgRegisterGqlInputTypeByTypeId,
            pgRegisterGqlTypeByTypeId,
            pg2GqlMapper,
            pgSql: sql,
        } = build

        // find our target type oid. If you want to change the behavior for a
        // built-in range type, you can use one of the following default oids:
        //
        // 3904 int4range
        // 3906 numrange
        // 3908 tsrange
        // 3910 tstzrange
        // 3912 daterange
        // 3926 int8range
        const myRange = pgIntrospectionResultsByKind.type.find(
            (t: PgType) => t.namespaceName === "my_schema" && t.name === "my_range"
        )

        if (!myRange) {
            return build // something went horribly wrong, abort
        }

        // declare a new kind of scalar
        const MyRangeType = new GraphQLScalarType({
            name: "MyRange",
            description: "An int8range dedicated to a more specific purpose",
            serialize: (a: string) => a,
            parseValue: (a: string) => a,
        })

        // register input and output types for the oid
        pgRegisterGqlInputTypeByTypeId(myRange.id, () => MyRangeType)
        pgRegisterGqlTypeByTypeId(myRange.id, () => MyRangeType)

        // define mappings to and from
        pg2GqlMapper[myRange.id] = {
            // SQL -> GQL
            map: (output: string) => output,
            // GQL -> SQL; substitute your target range type for `int8range` as necessary
            unmap: (input: string) => sql.fragment`${sql.value(input)}::int8range`,
        }

        return build // pass the build object back for the next stage
    })
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant