crystal icon indicating copy to clipboard operation
crystal copied to clipboard

Allow using @deprecated on tables

Open bfelbo opened this issue 3 years ago • 2 comments

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:

  • any allFoos query
  • any foreign key references to this table from other tables/functions

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

  • [ ] am interested in building this feature myself
  • [x] am interested in collaborating on building this feature
  • [x] am willing to help testing this feature before it's released
  • [ ] am willing to write a test-driven test suite for this feature (before it exists)
  • [x] am a Graphile sponsor ❤️
  • [ ] have an active support or consultancy contract with Graphile

bfelbo avatar Nov 30 '21 12:11 bfelbo

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 avatar Dec 02 '21 13:12 benjie

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

benjie avatar Oct 05 '23 08:10 benjie