graphile / crystal

đź”® Graphile's Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!
https://graphile.org/
Other
12.6k stars 569 forks source link

Can't export schema -- "Error: We don't support exporting classes directly" #1921

Closed nckswt closed 8 months ago

nckswt commented 9 months ago

Summary

Trying to export a schema derived from a local PostgreSQL instance running with TimescaleDB. I'm planning on using a lambda handler and want to export the schema so we don't have to regenerate it on each API call.

Steps to reproduce

//graphile.config.ts
import { makePgService } from 'postgraphile/adaptors/pg';
import { PostGraphileAmberPreset } from 'postgraphile/presets/amber';

interface PgConnectConfig {
  user: string
  database: string
  password: string
  host: string
  port: string
}

const pgConfig: PgConnectConfig = {
  user: process.env.TSDB_USERNAME! || 'postgres',
  password: process.env.TSDB_PASSWORD! || 'password',
  database: process.env.TSDB_DATABASE! || 'local_test',
  host: process.env.TSDB_HOST! || '127.0.0.1',
  port: process.env.TSDB_PORT! || '5432',
};

const connectionString = `postgres://${pgConfig.user}:${pgConfig.password}@${pgConfig.host}:${pgConfig.port}/${pgConfig.database}`;

const preset: GraphileConfig.Preset = {
  extends: [PostGraphileAmberPreset],
  pgServices: [makePgService({ connectionString })],
};

export default preset;
// export.ts
import { makeSchema } from "postgraphile";
import { exportSchema } from "graphile-export";
import preset from "../src/graphile.config.js";
import path from 'path';

const __dirname = path.resolve();

const main = async () => {
  console.log(`Exporting a GraphQL schema from the database at ${preset?.pgServices?.[0].name}...`);

  const { schema, resolvedPreset } = await makeSchema(preset);
  const exportFileLocation = `${__dirname}/src/exported-schema.js`;

  await exportSchema(schema, exportFileLocation, {
    mode: "typeDefs",
  });

}

await main();

Expected results

I'd expect to see a exported-schema.js file that I could load into my handler.

Actual results

I get the following error:

Error: We don't support exporting classes directly, instead you should mark your class as importable via:
Object.defineProperty(SafeError, '$$export', { value: { moduleName: 'my-module', exportName: 'SafeError' } });
    at funcToAst (/home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1319:11)
    at func (/home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1231:12)
    at _convertToAST (/home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1006:12)
    at convertToIdentifierViaAST (/home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1136:7)
    at /home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1259:12
    at Array.map (<anonymous>)
    at factoryAst (/home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1245:37)
    at convertToIdentifierViaAST (/home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1135:7)
    at /home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1259:12
    at Array.map (<anonymous>)
    at factoryAst (/home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1245:37)
    at convertToIdentifierViaAST (/home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1135:7)
    at handleSubvalue (/home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:961:19)
    at /home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1027:24
    at Array.forEach (<anonymous>)
    at _convertToAST (/home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1025:27)
    at convertToIdentifierViaAST (/home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1136:7)
    at /home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1522:19
    at Array.map (<anonymous>)
    at /home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1519:16
    at Array.forEach (<anonymous>)
    at exportSchemaTypeDefs (/home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1462:15)
    at exportSchemaAsString (/home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1776:5)
    at exportSchema (/home/nick/code/cloud/tycho-service/packages/operations-metrics/node_modules/graphile-export/src/exportSchema.ts:1794:26)
    at main (file:///home/nick/code/cloud/tycho-service/packages/operations-metrics/tools/export.ts:20:9)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async file:///home/nick/code/cloud/tycho-service/packages/operations-metrics/tools/export.ts:27:1 {
  retry: false
}

Additional context

I'm using:

//package.json
{
  "name": "@tailosinc/tycho-operations-metrics-service",
  "private": true,
  "version": "1.0.0",
  "license": "Apache-2.0",
  "type": "module",
  "homepage": "https://github.com/tailosinc/tycho-service/tree/main/packages/operations-metrics",
  "repository": {
    "type": "git",
    "url": "git@github.com:tailosinc/tycho-service.git"
  },
  "scripts": {
    "test:sls": "sls package --verbose",
    "dp": "sls deploy --verbose --force",
    "update-schema": "ts-node -P tsconfig.node.json tools/export.ts",
    "start": "ts-node -P tsconfig.node.json tools/server.ts"
  },
  "dependencies": {
    "@tailosinc/borg-event-client-kinesis": "^1.29.3",
    "@tailosinc/borg-event-common": "^1.37.0",
    "@tailosinc/borg-event-stream-kinesis": "^2.12.3",
    "@tailosinc/borg-utils": "1.33.0",
    "lodash": "4.17.21",
    "postgraphile": "^5.0.0-beta.18"
  },
  "devDependencies": {
    "@tailosinc/borg-handoff-serverless-plugin": "^1.28.15",
    "@types/debug": "^4.1.7",
    "@types/highland": "^2.12.14",
    "serverless": "3.38.0",
    "serverless-deployment-bucket": "1.6.0",
    "serverless-prune-plugin": "2.0.2",
    "serverless-offline": "8.8.1",
    "serverless-webpack": "5.7.1",
    "graphile-export": "0.0.2-beta.4"
  },
  "jest": {
    "setupFiles": [
      "jest-date-mock"
    ]
  }
}
//tsconfig.node.json
{
  "compilerOptions": {
      "target": "ESNext",
      "module": "NodeNext",
      "moduleResolution": "NodeNext",
      "strict": true,
      "skipLibCheck": true,
      "esModuleInterop": true,
      "rootDir": "./src",
      "forceConsistentCasingInFileNames": true,
      "noImplicitAny": false
    },
    "ts-node": {
      "esm": true,
      "compilerOptions": {
        "target": "ESNext",
        "module": "NodeNext",
        "moduleResolution": "NodeNext",
        "strict": true,
        "skipLibCheck": true,
        "esModuleInterop": true,
        "rootDir": "./src",
        "forceConsistentCasingInFileNames": true,
        "noImplicitAny": false
      },
    },
    "include": ["./src/**/*.ts"]
}

Note that we're an NPM house using monorepos via npm workspaces, so it's not easy for me to swap over to yarn, and that wouldn't be a long-term solution for us.

Possible Solution

I tried adding

Object.defineProperty(SafeError, '$$export', { value: { moduleName: 'my-module', exportName: 'SafeError' } });

but SafeError doesn't exist in my codebase -- looks like it's a Grafast thing?

I was able to console.log the result of makeSchema but it doesn't get me much.

benjie commented 9 months ago

SafeError and isSafeError need to be in this list:

https://github.com/graphile/crystal/blob/main/grafast/grafast/src/index.ts#L431

nckswt commented 9 months ago

Thanks! Is that something I can do at application level, did you want me to PR it, or will you have time to handle it and I'll keep an eye out for a version bump?

benjie commented 9 months ago

PR welcome, otherwise it’s on the list and will be addressed at some point. Weird that our tests haven’t caught it though.

benjie commented 9 months ago

(You could probably also address it via patch-package)

benjie commented 9 months ago

Failed attempt at reproduction here: https://github.com/benjie/crystal1921

nckswt commented 9 months ago

thanks @benjie! I'll test it out and report back once I see a package bump

benjie commented 8 months ago

I'm going to close this because I think it's fixed; hopefully doing a release in the next few hours, failing that it'll be early next week. Please reopen if the next release doesn't fix the issue.

nckswt commented 8 months ago

@benjie It fixed the issue for me, but I'm now getting the following error when I try to use the exported schema:

{
    "errorType": "ReferenceError",
    "errorMessage": "Cannot access 'nodeIdHandlerByTypeName' before initialization",
    "stack": [
        "ReferenceError: Cannot access 'nodeIdHandlerByTypeName' before initialization",
        "    at /var/task/src/graphql/index.js:8705:12",
        "    at Object.<anonymous> (/var/task/src/graphql/index.js:10160:12)",
        "    at Module._compile (node:internal/modules/cjs/loader:1356:14)",
        "    at Module._extensions..js (node:internal/modules/cjs/loader:1414:10)",
        "    at Module.load (node:internal/modules/cjs/loader:1197:32)",
        "    at Module._load (node:internal/modules/cjs/loader:1013:12)",
        "    at Module.require (node:internal/modules/cjs/loader:1225:19)",
        "    at require (node:internal/modules/helpers:177:18)",
        "    at _tryRequireFile (file:///var/runtime/index.mjs:1002:37)",
        "    at _tryRequire (file:///var/runtime/index.mjs:1052:25)"
    ]
}

Looks to be tied to this issue: https://github.com/graphile/crystal/issues/1787

I'll keep this issue closed, but looks like #1787 will have to be reopened?