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

NestJS usage #7

Closed
gagermaniac opened this issue Mar 2, 2023 · 15 comments
Closed

NestJS usage #7

gagermaniac opened this issue Mar 2, 2023 · 15 comments
Labels
question Further information is requested

Comments

@gagermaniac
Copy link

Sorry for making an issue here,
is there any way to use this extension on nestjs?

I've been using it like this

import pagination from 'prisma-extension-pagination';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$extends(pagination).$connect();
  }

  async enableShutdownHooks(app: INestApplication) {
    this.$on('beforeExit', async () => {
      await app.close();
    });
  }
}

but it doesn't seems work as it say
Property 'paginate' does not exist on type 'GetModel<InstancesDelegate<RejectOnNotFound | RejectPerOperation, DefaultArgs>, unknown>'

@deptyped deptyped added the question Further information is requested label Mar 2, 2023
@deptyped
Copy link
Owner

deptyped commented Mar 2, 2023

This is correct. Because $extends() returns a new Prisma Client instance with the extension applied, rather than modifying the original one.

const prisma = new PrismaClient()

// Declare an extended client that has pagination applied
const prismaA = prisma.$extends(pagination)

// prisma remains unchanged
// prismaA has pagination applied

You need to use a modified instance with the extension applied. Unfortunately, I don't have enough experience with NestJS to know how to do this.

@gagermaniac
Copy link
Author

Ah, i see
ended up using it like this

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect();
  }

  pg() {
    return this.$extends({
      model: {
        $allModels: {
          paginate,
        },
      },
    });
  }
}

and usage

findAll(id: string) {
    return this.prismaService.pg().instances.paginate().withPages({
      limit: 10,
    });
  }

Many Thanks, for this awesome lib

@jdavidferreira
Copy link

jdavidferreira commented Jul 31, 2023

Ah, i see ended up using it like this

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect();
  }

  pg() {
    return this.$extends({
      model: {
        $allModels: {
          paginate,
        },
      },
    });
  }
}

and usage

findAll(id: string) {
    return this.prismaService.pg().instances.paginate().withPages({
      limit: 10,
    });
  }

Many Thanks, for this awesome lib

@gagermaniac Wouldn't that extend the prisma client every time you call the PrismaService.pg() function? I got a workaround for when you want to install extension on certain models, I didn't like it much either though. It consists of extending the prisma client just once per model in the constructor of the model service class.

@Injectable()
export class EntityService {
  private redonly prismaExtended
  
  constructor(private readonly prisma: PrismaService) {
     this.prismaExtended = this.prisma.$extends({
      model: {
        product: {
          paginate,
        },
      },
    })
  }
  
  findAllPaginated() {
    return this.prismaExtended.entity
      .paginate()
      .withPages({
        limit: 10,
      })
  }
}

Probably this can be done too to install the extension to all models in the PrismaService installing the extension only once.

@jdavidferreira
Copy link

Ok. I think I got it. This installs the extension to all models.

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  public readonly pg

  constructor() {
    super()

    this.pg = this.$extends(pagination)
  }

  async onModuleInit() {
    await this.$connect()
  }
}

Usage:

findAll(id: string) {
    return this.prismaService.pg.instances.paginate().withPages({
      limit: 10,
    });
}

@hisabimbola
Copy link

@jdavidferreira did you get the typing to working. When I do this.prismaService.pg.instances I don't get any type interference

@btd1337
Copy link

btd1337 commented Nov 21, 2023

@jdavidferreira did you get the typing to working. When I do this.prismaService.pg.instances I don't get any type interference

It's necessary to type the variable pg in the PrismaService class, but I don't know what the type is

@jdavidferreira
Copy link

jdavidferreira commented Nov 21, 2023

@hisabimbola, @btd1337
Sorry, let me fix and improve the example:

import pagination from 'prisma-extension-pagination'

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  public readonly prismaExtended

  constructor() {
    super()

    // This will install the extension to all models. You can also install the extension on some models only, see: https://github.com/deptyped/prisma-extension-pagination#install-extension-on-some-models
    this.prismaExtended = this.$extends(pagination())
  }

  async onModuleInit() {
    await this.$connect()
  }
}

Usage:

@Injectable()
export class ProductsService {
  constructor(private readonly prisma: PrismaService) {}

  findAll() {
    return this.prisma.prismaExtended.product.paginate().withPages({
      limit: 10,
    })
  }
}

@btd1337
Copy link

btd1337 commented Nov 21, 2023

@jdavidferreira the issue is not this. The real problem is that if you write your code without typing the prismaExtended variable, all type recognition is lost. No changes made in the Prisma schema will be detected or flagged. You won't know if there were breakchanges when you alter your schema. Do you understand?

Therefore, it is necessary to type the prismaExtended variable correctly.

Reference: #19

@jdavidferreira
Copy link

jdavidferreira commented Nov 21, 2023

@hisabimbola Did you try my new implementation?

My previous example was wrong and the prismaExtended type (previously pg) was not being infered. I fixed the implementation. TypeScript is able to infer the type based on the assignment inside the constructor without typing it at declaration.

Evidence:
Animation

@btd1337
Copy link

btd1337 commented Nov 21, 2023

@hisabimbola Did you try my new implementation?

My previous example was wrong and the prismaExtended type (previously pg) was not being infered. I fixed the implementation. TypeScript is able to infer the type based on the assignment inside the constructor without typing it at declaration.

@jdavidferreira what TypeScript version is your project using? And could you please share your tsconfig?

This behavior is not occurring in my VSCode IDE.

@jdavidferreira
Copy link

That could be the issue. I'm using the TypeScript version 5.2.2.

tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "ES2020",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./",
    "incremental": true,
    "skipLibCheck": true,
    "strict": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true
  }
}

@btd1337
Copy link

btd1337 commented Nov 21, 2023

@jdavidferreira I found the problem:

The property "noImplicitAny": false in tsconfig file.

I removed this property, and autocomplete now works correctly, but the code break with errors:

Captura de Tela 2023-11-21 às 19 26 07

@jdavidferreira
Copy link

jdavidferreira commented Nov 21, 2023

I removed this property, and autocomplete now works correctly, but the code break with errors:

@btd1337 You have to type all those fields. 😬 It will be tedious but you will have more type safety throughout your project.

@JSantangelo-Octopus
Copy link

Hi @jdavidferreira ! Im following this setup :

@hisabimbola, @btd1337 Sorry, let me fix and improve the example:

import pagination from 'prisma-extension-pagination'

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  public readonly prismaExtended

  constructor() {
    super()

    // This will install the extension to all models. You can also install the extension on some models only, see: https://github.com/deptyped/prisma-extension-pagination#install-extension-on-some-models
    this.prismaExtended = this.$extends(pagination())
  }

  async onModuleInit() {
    await this.$connect()
  }
}

Usage:

@Injectable()
export class ProductsService {
  constructor(private readonly prisma: PrismaService) {}

  findAll() {
    return this.prisma.prismaExtended.product.paginate().withPages({
      limit: 10,
    })
  }
}

But the prismaExtended type is not being infered. This is my tsconfig.json (i remove the "noImplicitAny": false value)

{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "target": "ES2021",
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./",
    "incremental": true,
    "skipLibCheck": true,
    "strictNullChecks": false,
    "strictBindCallApply": false,
    "forceConsistentCasingInFileNames": false,
    "noFallthroughCasesInSwitch": false,
    "esModuleInterop": true
  }
}

Demo:

demo_prisma_2.webm

Is there another configuration to check?

@AlexRMU
Copy link

AlexRMU commented Apr 2, 2024

Look at this

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

No branches or pull requests

7 participants