import endent from 'endent'; import * as fs from 'fs'; import { JSONPgSmartTags } from 'graphile-utils'; import * as JSON5 from 'json5'; import * as path from 'path'; import { BaseSmartTags, PgColumn, PgFkColumn, PgTable, TableSmartTags, } from '../abstractions'; /** * Builds smart tags for FK constraints. * @param columns - Array of FK columns. */ export function buildFkConstraintSmartTags(columns: PgFkColumn[]): { [name: string]: BaseSmartTags; } { return columns.reduce((acc, col) => { if (col.fkName) { acc[col.fkName] = { tags: { foreignFieldName: `${col.table.displayName ?? col.table.name}`, }, }; } return acc; }, {} as { [name: string]: BaseSmartTags }); } /** * Builds class (table) level smart tags. * @param tables - Array of tables. */ export function buildClassSmartTags(tables: PgTable[]): { [name: string]: TableSmartTags; } { const tags: { [name: string]: TableSmartTags } = {}; tables.forEach((t) => { tags[t.name] = t.buildSmartTags(); }); return tags; } /** * Builds smart tags for virtual FK columns. * @param virtualFks - Array of virtual FK columns. */ export function buildVirtualFkSmartTags(virtualFks: PgFkColumn[]): string[] { return virtualFks.map((vfk) => { return `(${vfk.name}) references ${vfk.targetPk.table.name}|@omit many`; }); } /** * Builds attribute (column) level smart tags. * @param columns - Array of PgColumns. */ export function buildAttributeSmartTags(columns: PgColumn[]): { [name: string]: BaseSmartTags; } { return columns.reduce((acc, col) => { acc[col.name] = col.buildSmartTags(); return acc; }, {} as { [name: string]: BaseSmartTags }); } // TODO: Replace with camelCase from graphile-build. export function snakeCaseToCamelCase(input: string): string { return input .split('_') .reduce( (res, word, i) => i === 0 ? word.toLowerCase() : `${res}${word.charAt(0).toUpperCase()}${word .substr(1) .toLowerCase()}`, '', ); } /** * Generates a smart tags plugin file. * @param tags - Smart tags configuration. * @param outPath - Output path where the plugin will be written. */ export function generateSmartTagsPlugin( tags: JSONPgSmartTags, outPath: string, ): void { const dirPath = path.dirname(outPath); if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath, { recursive: true }); } console.log(`Writing smart tags plugn to to ${outPath}.`); const pluginSrc = endent` import { makeJSONPgSmartTagsPlugin } from 'graphile-utils'; /** * Smart tags to adjust and enhance the generated GraphQL API. */ export const SmartTagsPlugin = makeJSONPgSmartTagsPlugin(${endent.pretty( // Use JSON5 to generate keys without quotes to make the generated code already compatible with prettier. JSON5.stringify(tags, null, 2), )}); `; fs.writeFileSync(outPath, pluginSrc); }