graphile / crystal

🔮 Graphile's Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!
https://graphile.org/
Other
12.62k stars 571 forks source link

Allow using @deprecated on tables #1561

Open bfelbo opened 2 years ago

bfelbo commented 2 years ago

Feature description

Currently it's possible to deprecate functions and columns using the @deprecated smart tag. It'd be great to support adding @deprecated to a table, which would mark e.g. the following as deprecated in the GraphQL schema:

Motivating example

Big projects will have tons of tables and developers often need to deprecate tables as business or technical requirements change. There's currently no easy way to deprecate a table. One alternative solution is to write a plugin, but it requires diving into PostGraphile internals.

Supporting development

I

benjie commented 2 years ago

Deprecating a Postgres table should be akin to deprecating a GraphQL type. Currently it's not possible to deprecate a GraphQL type, so I do not want to add something to PostGraphile to deprecate a Postgres table because the implementation would change later when (if) GraphQL adds support for deprecating a type.

That said, I'd be happy to see a plugin do this. Here's the skeleton of what a plugin to do this might look like:

module.exports = function DeprecateTablePlugin(
  builder
) {
  builder.hook("build", build => {
    const {
      pgIntrospectionResultsByKind,
    } = build;
    const deprecatedClassIds = pgIntrospectionResultsByKind.class
      .filter(
        table => table.tags.deprecated
      ).map(table => table.id);
    pgIntrospectionResultsByKind.attribute
      .forEach(entity => {
        if (deprecatedClassIds.includes(entity.classId)) {
          // TODO: copy deprecation reason? Create a new reason based on the classId?
          entity.tags.deprecated = "Deprecated";
        }
      });
    pgIntrospectionResultsByKind.constraint
      .forEach(entity => {
        if (deprecatedClassIds.includes(entity.classId)) {
          entity.tags.deprecated = "Deprecated";
        }
      });
    pgIntrospectionResultsByKind.proc
      .forEach(entity => {
        // TODO: look at the returnTypeId and argTypeIds (recursively) and see if the types match up with the types of the relevant deprecated classes; if so: entity.tags.deprecated = "Yep"
      });
    return build;
  });
};

It'll need a lot of work to get it finished, but hopefully it acts as a starting point.

benjie commented 1 year ago

Relevant GraphQL Spec PR: https://github.com/graphql/graphql-spec/pull/997