hansololai/postgraphile-polymorphic-relation-plugin

View on GitHub
src/define_polymorphic_constraint_plugin.ts

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
import { SchemaBuilder, Options } from 'postgraphile';
import { GraphileBuild, PgPolymorphicConstraint } from './postgraphile_types';
import { isPolymorphicColumn, columnToPolyConstraint } from './utils';
import { PgClass } from 'graphile-build-pg';

/**
 * @description This plugin add an array named 'pgPolymorphicClassAndTargetModels' in build,
 * If it already exist, it will append to it. It adds custom defined polymorphic constraints.
 * A polymorphic association via @smartComments on a xxx_type column should have 2 fields in tag
 * a isPolymorphic:true, (maybe can be deprecated), a polymorphicTo:[ModelNames].
 * @example create comment syntax
 * comment on column notes.noteable
 *  is E'@isPolymorphic\n@polymorphicTo Location\n@polymorphicTo Workflow'
 * @param builder The SchemaBuilder
 * @param options The option passed in. This Option is the same object allows access of custom
 * parameters they pass in when the call 'createPostGraphileSchema'
 * @author Han Lai
 */
export const definePolymorphicCustom = (builder: SchemaBuilder, options: Options) => {
  // First add an inflector for polymorphic backrelation type name
  builder.hook('inflection', inflection => ({
    ...inflection,
    filterManyPolyType(table: PgClass, foreignTable: PgClass) {
      return `${this.filterManyType(table, foreignTable)}Poly`;
    },
    backwardRelationByPolymorphic(
      table: PgClass,
      polyConstraint: PgPolymorphicConstraint,
      isUnique: boolean,
    ) {
      const { backwardAssociationName } = polyConstraint;
      const name = backwardAssociationName || table.name;
      const fieldName = isUnique ? this.singularize(name) : this.pluralize(name);
      // return this.camelCase(`${fieldName}-as-${polymorphicName}`);
      return this.camelCase(fieldName);
    },
    backwardRelationByPolymorphicExist(
      table: PgClass,
      polyConstraint: PgPolymorphicConstraint,
      isUnique: boolean,
    ) {
      return `${this.backwardRelationByPolymorphic(table, polyConstraint, isUnique)}Exist`;
    },
  }));
  builder.hook('build', (build) => {
    const {
      pgIntrospectionResultsByKind: { attribute },
    } = build as GraphileBuild;

    const { pgSchemas = [] } = options as any;
    const pgPolymorphicClassAndTargetModels = attribute
      .filter((a) => {
        // the column must from a table of the same scheme
        return pgSchemas.includes(a.class.namespaceName)
          && isPolymorphicColumn(a);
      }).map(a => columnToPolyConstraint(build as GraphileBuild, a));

    return build.extend(build, {
      pgPolymorphicClassAndTargetModels,
    });
  });
};