MichalLytek / typegraphql-prisma

Prisma generator to emit TypeGraphQL types and CRUD resolvers from your Prisma schema
https://prisma.typegraphql.com
MIT License
883 stars 114 forks source link

Errors about accessing inputs before initialization #2

Open MichalLytek opened 3 years ago

MichalLytek commented 3 years ago

Originally posted by @j718 in https://github.com/MichalLytek/typegraphql-prisma/issues/1#issuecomment-697454730

"type-graphql": "^1.0.0",
typegraphql-prisma": "^0.6.1",

I keep getting errors about accessing inputs before initialization and wanted to get your input. The error is as follows:

ReferenceError: Cannot access 'BankAccountWhereInput' before initialization
    at Module.BankAccountWhereInput (C:\Users\jacob\OneDrive\Documents\GitHub\tictactoe\.next\server\pages\api\graphql.js:11490:113)
    at Module../src/prisma/generated/type-graphql/resolvers/inputs/BankAccountListRelationFilter.ts (C:\Users\jacob\OneDrive\Documents\GitHub\tictactoe\.next\server\pages\api\graphql.js:10345:110)
    at __webpack_require__ (C:\Users\jacob\OneDrive\Documents\GitHub\tictactoe\.next\server\pages\api\graphql.js:23:31)     
    at Module../src/prisma/generated/type-graphql/resolvers/inputs/BankConnectionWhereInput.ts (C:\Users\jacob\OneDrive\Documents\GitHub\tictactoe\.next\server\pages\api\graphql.js:13159:95)
    at __webpack_require__ (C:\Users\jacob\OneDrive\Documents\GitHub\tictactoe\.next\server\pages\api\graphql.js:23:31)     
    at Module../src/prisma/generated/type-graphql/resolvers/inputs/BankAccountWhereInput.ts (C:\Users\jacob\OneDrive\Documents\GitHub\tictactoe\.next\server\pages\api\graphql.js:11499:90)
    at __webpack_require__ (C:\Users\jacob\OneDrive\Documents\GitHub\tictactoe\.next\server\pages\api\graphql.js:23:31)     
    at Module../src/prisma/generated/type-graphql/resolvers/crud/BankAccount/args/AggregateBankAccountArgs.ts (C:\Users\jacob\OneDrive\Documents\GitHub\tictactoe\.next\server\pages\api\graphql.js:3695:87)
    at __webpack_require__ (C:\Users\jacob\OneDrive\Documents\GitHub\tictactoe\.next\server\pages\api\graphql.js:23:31)     
    at Module../src/prisma/generated/type-graphql/resolvers/crud/BankAccount/BankAccountCrudResolver.ts (C:\Users\jacob\OneDrive\Documents\GitHub\tictactoe\.next\server\pages\api\graphql.js:3208:88)

I have the following schema.prisma file.

generator client {
  provider = "prisma-client-js"
}

generator typegraphql {
  provider = "node ../node_modules/typegraphql-prisma/generator.js"
  output   = "../prisma/generated/type-graphql"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Account {
  id                 Int       @default(autoincrement()) @id
  compoundId         String    @unique @map(name: "compound_id")
  userId             Int       @map(name: "user_id")
  providerType       String    @map(name: "provider_type")
  providerId         String    @map(name: "provider_id")
  providerAccountId  String    @map(name: "provider_account_id")
  refreshToken       String?   @map(name: "refresh_token")
  accessToken        String?   @map(name: "access_token")
  accessTokenExpires DateTime? @map(name: "access_token_expires")
  createdAt          DateTime  @default(now()) @map(name: "created_at")
  updatedAt          DateTime  @default(now()) @map(name: "updated_at")

  @@index([providerAccountId], name: "providerAccountId")
  @@index([providerId], name: "providerId")
  @@index([userId], name: "userId")

  @@map(name: "accounts")
}

model BankAccount {
  account_id        String         @id
  bankConnectionId  Int            @map(name: "bank_connection_id")
  balancesAvailable Float            @map(name: "balances_available")
  balancesCurrent   Float            @map(name: "balances_current")
  isoCurrencyCode   String         @map(name: "iso_currency_code")
  name              String
  officialName      String         @map(name: "official_name")
  subtype           String
  type              String
  bankConnection    BankConnection @relation(fields: [bankConnectionId], references: [id])

  @@map(name: "bank_account")

}

model BankConnection {
  id          Int           @default(autoincrement()) @id
  user        User          @relation(fields: [userId], references: [id])
  userId      Int           @map(name: "user_id")
  itemId      String        @map(name: "item_id")
  accessToken String        @map(name: "access_token")
  bankAccounts BankAccount[]

  @@map(name: "bank_connection")

}
model Session {
  id           Int      @default(autoincrement()) @id
  userId       Int      @map(name: "user_id")
  expires      DateTime
  sessionToken String   @unique @map(name: "session_token")
  accessToken  String   @unique @map(name: "access_token")
  createdAt    DateTime @default(now()) @map(name: "created_at")
  updatedAt    DateTime @default(now()) @map(name: "updated_at")
  user         User     @relation(fields: [userId], references: [id])

  @@map(name: "sessions")
}

model User {
  id              Int              @default(autoincrement()) @id
  name            String?
  email           String?          @unique
  emailVerified   DateTime?        @map(name: "email_verified")
  image           String?
  createdAt       DateTime         @default(now()) @map(name: "created_at")
  updatedAt       DateTime         @default(now()) @map(name: "updated_at")
  bankConnections BankConnection[]
  sessions        Session[]

  @@map(name: "users")
}

model VerificationRequest {
  id         Int      @default(autoincrement()) @id
  identifier String
  token      String   @unique
  expires    DateTime
  createdAt  DateTime @default(now()) @map(name: "created_at")
  updatedAt  DateTime @default(now()) @map(name: "updated_at")

  @@map(name: "verification_requests")
}

Here is my build schema command

    const schema = await buildSchema({
      // resolvers: [CreateLinkTokenResolver, UserCrudResolver, GameCrudResolver, UserRelationsResolver, GameRelationsResolver],
      resolvers: [LinkTokenResolver, UserRelationsResolver ],
      authChecker: customAuthChecker,
      validate: false,
    })
MichalLytek commented 3 years ago

Are you using CommonJS as your module type in your tsconfig?

Originally posted by @wSedlacek in https://github.com/MichalLytek/typegraphql-prisma/issues/1#issuecomment-697496611

MichalLytek commented 3 years ago

Yes, I am. Here is my tsconfig

{
  "compilerOptions": {
    "target": "es2018",
    "lib": [
      "dom",
      "dom.iterable",
      "es2018",
      "esnext.asynciterable"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "baseUrl": "./",
    "paths": {
      "~types/*": [
        "./@types/*"
      ],
      "~graphql/*": [
        "./pages/api/graphql/*"
      ],
      "~views/*": [
        "./src/views/*"
      ],
      "~viewsUi/*": [
        "./src/views/ui/*"
      ],
      "~viewsComp/*": [
        "./src/views/components/*"
      ],
      "~viewsLay/*": [
        "./src/views/layouts/*"
      ],
      "~styles/*": [
        "./src/styles/*"
      ],
      "~server/*": [
        "./server/*"
      ],
      "~lib/*": [
        "./src/lib/*"
      ],
      "~assets/*": [
        "./assets/*"
      ],
      "~static/*": [
        "./public/static/*"
      ],
      "~generated/*": [
        "./src/prisma/generated/*"
      ],
      "~context/*": [
        "./src/context/*"
      ],
      "~services/*": [
        "./src/services/*"
      ]
    },

  },
  "exclude": [
    "node_modules"
  ],
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ]
}

Here is my babel config

{
  "presets": ["next/babel", "@babel/preset-typescript"],
  "plugins": [
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    "@babel/plugin-transform-runtime",
    "babel-plugin-transform-typescript-metadata",
    ["@babel/plugin-proposal-class-properties", { "loose": true }],

    [
      "styled-components",
      {
        "ssr": true,
        "displayName": true,
        "preprocess": false
      }
    ]
  ]
}

Originally posted by @j718 in https://github.com/MichalLytek/typegraphql-prisma/issues/1#issuecomment-697562870

redbaron76 commented 3 years ago

I confirm this bug in a simple Book (author) -> User relation inside a Next.js (v10.0.1) boilerplate integration test.

tsconfig.json

{
  "compilerOptions": {
    "target": "es2018",
    "lib": ["dom", "dom.iterable", "es2018", "esnext.asynciterable"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "baseUrl": "."
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

schema.prisma

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

generator typegraphql {
  provider = "typegraphql-prisma"
  output   = "../src/generated/typegraphql-prisma"
}

enum Role {
  USER
  PLAYER
  SHOP
  ADMIN
}

model User {
  id        Int     @id @default(autoincrement())
  email     String  @unique
  firstName String
  lastName  String
  password  String
  role      Role    @default(USER)
  count     Int     @default(0)
  books     Book[]
  profile   Profile
}

model Profile {
  id     Int    @id @default(autoincrement())
  bio    String
  user   User   @relation(fields: [userId], references: [id])
  userId Int
}

model Book {
  id         Int        @id @default(autoincrement())
  title      String
  author     User       @relation(fields: [userId], references: [id])
  userId     Int
  categories Category[]
}

model Category {
  id    Int    @id @default(autoincrement())
  books Book[]
}

schema builder

import { resolvers } from "src/generated/typegraphql-prisma";
import { buildSchema } from "type-graphql";
import path from "path";

export const doBuildSchema = async () => {
  return await buildSchema({
    resolvers,
    emitSchemaFile: path.join(process.cwd(), "../generated/schema.gql"),
    validate: false,
  });
};
ReferenceError: Cannot access 'BookWhereInput' before initialization
    at Module.eval [as BookWhereInput] (webpack-internal:///./src/generated/typegraphql-prisma/resolvers/inputs/BookWhereInput.ts:2:106)
    at eval (webpack-internal:///./src/generated/typegraphql-prisma/resolvers/inputs/BookListRelationFilter.ts:24:103)
    at Module../src/generated/typegraphql-prisma/resolvers/inputs/BookListRelationFilter.ts (/Users/fabio/Documents/LAVORI/PROGETTI/next10-api-graphql-prisma/.next/server/pages/api/graphql.js:1448:1)
    at __webpack_require__ (/Users/fabio/Documents/LAVORI/PROGETTI/next10-api-graphql-prisma/.next/server/pages/api/graphql.js:23:31)
    at eval (webpack-internal:///./src/generated/typegraphql-prisma/resolvers/inputs/CategoryWhereInput.ts:5:88)
    at Module../src/generated/typegraphql-prisma/resolvers/inputs/CategoryWhereInput.ts (/Users/fabio/Documents/LAVORI/PROGETTI/next10-api-graphql-prisma/.next/server/pages/api/graphql.js:1808:1)
    at __webpack_require__ (/Users/fabio/Documents/LAVORI/PROGETTI/next10-api-graphql-prisma/.next/server/pages/api/graphql.js:23:31)
    at eval (webpack-internal:///./src/generated/typegraphql-prisma/resolvers/inputs/CategoryListRelationFilter.ts:5:84)
    at Module../src/generated/typegraphql-prisma/resolvers/inputs/CategoryListRelationFilter.ts (/Users/fabio/Documents/LAVORI/PROGETTI/next10-api-graphql-prisma/.next/server/pages/api/graphql.js:1688:1)
    at __webpack_require__ (/Users/fabio/Documents/LAVORI/PROGETTI/next10-api-graphql-prisma/.next/server/pages/api/graphql.js:23:31)
waweru-kamau commented 3 years ago

@MichalLytek Did you find a solution for this?

MichalLytek commented 3 years ago

@KamauIan I don't think there's a solution for that. NodeJS doesn't like single output file when you have circular references as it then cannot access before initialization. CommonJS modules can handle the references correctly. The issue is with TypeScript reflection which is directly referencing the classes in the emited code, not in a () => function like TypeGraphQL.

waweru-kamau commented 3 years ago

So I decided to transpile the es6 to es5 with babel after compiling typescript. Not sure if this is a good practice but seems to work now.

danim47c commented 3 years ago

I've been a full day trying to solve this problem and finally, I had to use "babel-plugin-transform-es2015-modules-commonjs" babel plugin.

cbaucom commented 3 years ago

I've been a full day trying to solve this problem and finally, I had to use "babel-plugin-transform-es2015-modules-commonjs" babel plugin.

When I try adding this to my project, I then get a 500 error for my graphql endpoint instead of the original error this thread is about. Any ideas how to then fix the 500 error for /api/graphql? GH repo here

faustinozanetto commented 3 years ago

I´ve encountered the same issue while trying to use apollo-server-micro on my nextjs project, typegraphql-prisma and prisma2 and still have not found a solution. If anyone knows a possible solution, please let me know. Thanks

SheaBelsky commented 2 years ago

@faustinozanetto I got this to work by installing the @babel/plugin-transform-modules-commonjs Babel plugin.

I plan on uploading a minimal viable GitHub repo which includes everything (NextJS, TypeGraphQL, Prisma) over the next few days once I fully finish migrating my project over. So if you (or others) are still having problems, stay tuned to this space and I will hopefully have something soon :)

jctaoo commented 2 years ago

@faustinozanetto I got this to work by installing the @babel/plugin-transform-modules-commonjs Babel plugin.

I plan on uploading a minimal viable GitHub repo which includes everything (NextJS, TypeGraphQL, Prisma) over the next few days once I fully finish migrating my project over. So if you (or others) are still having problems, stay tuned to this space and I will hopefully have something soon :)

But @babel/plugin-transform-modules-commonjs will break the refresh behavior of next js. After apply this babel plugin, the whole page will be reloaded when I even update some simple plain text elements.

SheaBelsky commented 2 years ago

@jctaoo Hmm I hadn't noticed that before, but now I can see that problem happening. That's strange, not sure what could be causing that.

SheaBelsky commented 2 years ago

@jctaoo

Here's my minimally viable repo: https://github.com/SheaBelsky/nextjs-prisma-typegraphql

So far I'm not running into the issue where changing one component causes Next to completely reload everything. I'm not sure what triggers that, but would love to explore what's causing that!

jctaoo commented 2 years ago

@SheaBelsky

Next refresh behavior base on analyzing static import/export statements. But @babel/plugin-transform-modules-commonjs transform these statements to something like:

// original
export default 42;

// transformed
Object.defineProperty(exports, "__esModule", {
  value: true,
});
jctaoo commented 2 years ago

If we can use @babel/plugin-transform-modules-commonjs on only files generated by typegraphql-prisma, it will be good.

jacobjove commented 2 years ago

@babel/plugin-transform-modules-commonjs prevents using ECMAScript-only features like top-level awaits... Is there any potential solution that does not require transforming to CommonJS?

giacomorebonato commented 2 years ago

Does async import help for this?

const { resolvers } = await import('../generated/type-graphql')
kryptonian41 commented 2 years ago

@MichalLytek Any updates on this issue, because I am facing the same problem, even after using commonjs as the module system for typescript compilation in a next.js project.

devnaumov commented 1 year ago

Any news?

gBusato commented 1 year ago

Still currently having this issue on nextjs and prisma

abd30590 commented 1 year ago

can you share the BankAccountWhereInput.ts file I've run into this issue before. but i'm using only typeGraphql, not prisma in my project I had to change the tsconfig module from commonJs to esnext, and problems began to come!!. anyway, you need to double check that you don't have a circular dependency.

I solved it by using (import type) syntax you can check the import type here https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html

here is an example:

import type { Users as UsersType } from "../../../common/Entitites/Users.js";//use this for attributes/variable types

import { Users } from "../../../common/Entitites/Users";//use this as value

export class Passenger extends Audit {

@OneToOne(() => Users//<---used as value
 , (user) => user.passenger)
psgrId: number;

@Field(() => Int)
user: UsersType ;//<---type

}

or you can skip import type and use typeof like below:

import { Users } from "../../../common/Entitites/Users"; export class Passenger extends Audit { @OneToOne(() => Users//<---used as value , (user) => user.passenger) psgrId: number;

@Field(() => Int)
user: typeof Users ;//<---type

}

vanduc1102 commented 10 months ago

I have to omit a field when the problem occurs

model Product {

....

   /// @TypeGraphQL.omit(output: true, input: true)
    cartItems          CartItem[]
}
gabrielbryk commented 4 months ago

Has anyone found a useable workaround for this?

vanics commented 4 months ago

Same boat. Same problem

gabrielbryk commented 4 months ago

@vanics The best solution I have so far is selectively ignoring the problem fields in the prisma schema and creating custom resolvers for the specific queries/mutations I need.

eduardolundgren commented 1 month ago

@MichalLytek

@KamauIan I don't think there's a solution for that. NodeJS doesn't like single output file when you have circular references as it then cannot access before initialization. CommonJS modules can handle the references correctly. The issue is with TypeScript reflection which is directly referencing the classes in the emited code, not in a () => function like TypeGraphQL.

@MichalLytek Is there something that can be done at the library level, or do you have any ideas to address the limitations with TypeScript reflection? While selectively ignoring cyclic fields has been a useful workaround for compatibility with Next.js, this approach sometimes requires ignoring important fields, which can limit the functionality of GraphQL. Any insights or solutions to improve this would be greatly appreciated!