Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Error: No prisma client" in version 2.1.0 #265

Open
subvertallchris opened this issue Jan 23, 2024 · 2 comments
Open

"Error: No prisma client" in version 2.1.0 #265

subvertallchris opened this issue Jan 23, 2024 · 2 comments

Comments

@subvertallchris
Copy link

subvertallchris commented Jan 23, 2024

Describe the bug
After upgrading from 2.0.2 to 2.1.0, a function that I use to seed my database fails with the error Error: No prisma client. I confirmed that initialize is called prior to this. Even moving the initialize call immediately before UserFactory.create() does not resolve it.

To Reproduce
Steps to reproduce the behavior:

  1. Upgrade to 2.1.0
  2. Run the Prisma migrate command to rebuild the client
  3. Run tests

Expected behavior

It should create database records without crashing :-)

Your Schema

Sorry, I can't provide this.

Environment (please complete the following information):

  • Database kind - Postgres
  • Node.js version - 20.10.0
  • @prisma/client version - 5.8.1
  • TypeScript version - 5.2.2

Additional context

There might be some important things to know.

  1. I perform some database operations at the beginning of each run of my tests. I am using Vite and have a globalSetup file, globalDbSetup.ts. That file is this:
import { dbConnectionHelper } from './testDbHelper';

let dbBootstrapped = false;

export default async function setup({ provide }: { provide: (key: string, value: unknown) => void }) {
  if (dbBootstrapped) {
    throw new Error('We already setup the database once!');
  }
  dbBootstrapped = true;

  dbConnectionHelper.setup();
  // This is going to cleanup the database by truncating it. It ensures we always start with a clean slate.
  await dbConnectionHelper.cleanup();
  const userId = await dbConnectionHelper.bootstrap();
  if (!userId) {
    throw new Error('ERROR: no user was created!');
  }
  provide('userId', userId);
}

The dbConnectionHelper is a singleton object that is responsible for the connection. It looks like this:

import { getPrismaClient } from '@/lib/getPrismaClient';

import { initialize } from './__generated__/fabbrica';
import { UserFactory } from './factories/UserFactory';

class DbConnectionHelper {
  connection?: ReturnType<typeof getPrismaClient>;
  userId?: string;

  constructor() {
    if (!process.env.VITEST) {
      throw new Error('ERROR: This class is not for use outside of testing!');
    }
  }

  getUserId() {
    if (!this.userId) {
      throw new Error('ERROR: no user id has been set!');
    }

    return this.userId;
  }

  setup() {
    this.connection = getPrismaClient();
    initialize({ prisma: this.connection });
  }

  async bootstrap() {
    if (this.userId) {
      return this.userId;
    }

    const user = await this.seedDatabase();
    this.userId = user.id;
    return this.userId;
  }

  async cleanup() {
    if (!this.connection) {
      throw new Error('ERROR: no connection has been established!');
    }

    if (!process.env.VITEST) {
      throw new Error('ERROR: This method is not for use outside of testing!');
    }

    console.log('TRUNCATING DATABASE TABLES');
    const tableNames = await this.getTableNames();

    try {
      for await (const tableName of tableNames) {
        await this.connection.$queryRawUnsafe(`TRUNCATE TABLE "${tableName}" CASCADE`);
      }
    } catch (e) {
      console.log('CLEANUP FAILED:');
      console.log(e);
    }
  }

  async getTableNames() {
    if (!this.connection) {
      throw new Error('ERROR: no connection has been established!');
    }

    if (!process.env.VITEST) {
      throw new Error('ERROR: This method is not for use outside of testing!');
    }

    const tables = await this.connection.$queryRaw`SELECT table_name
    FROM information_schema.tables
    WHERE table_schema = 'public'
    `;

    return (tables as { table_name: string }[])
      .map((table) => table.table_name)
      .filter((name) => name !== '_prisma_migrations' && !name.startsWith('pg_'));
  }

  async seedDatabase() {
    if (!this.connection) {
      throw new Error('ERROR: no connection has been established!');
    }

    if (!process.env.VITEST) {
      throw new Error('ERROR: This method is not for use outside of testing!');
    }

    const user = await UserFactory.create();
    // Some more setup logic happens here. We create some related objects that are expected to exist.
    return user;
  }
}

export const dbConnectionHelper = new DbConnectionHelper();

The failure occurs within seedDatabase as soon as we call UserFactory.create().

  1. I use an extende Prisma client. Calling getPrismaClient() returns this.
  2. I am using https://github.com/aiji42/vitest-environment-vprisma (@aiji42) which does some tricky things with the Prisma client. I wonder if this is related? From my debugging, it's not using the vPrisma client.
  3. The Prisma connection is active because the earlier queries to get table names return correctly. This is limited to the factories' connection.

Finally, sorry for not responding about the WIP traits! I'll review those now.

@subvertallchris
Copy link
Author

Hey, just circling back here, I'm still getting this with 2.1.1. I'd love to get it resolved so I can stay current. If there are any tips for troubleshooting, I'm happy to do the legwork. @aiji42 pinging you since this pertains to your work as well.

@rayehizoba
Copy link

I experienced this issue. The solution was as follows:

import { PrismaClient } from '@prisma/client';
import {initialize} from '.prisma/factory';

const prisma = new PrismaClient();
initialize({ prisma }); // <-- This line is important

// the rest of your code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants