Nestjs Prisma extension

Hi everyone I'm trying to fill the code field with a custom nanoid() with only uppercase letters and numbers, but when I do the $extends with my logic, I have two problems: - I think my custom nanoid() isn't working - Typescript is complaining because I didn't fill the code on the .create This is my prisma service:
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
private readonly logger = new Logger(PrismaService.name);
#nanoid: (size?: number) => string = undefined;

constructor() {
super();
this.#nanoid = customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 4);
}

async onModuleInit() {
this.logger.log(`CODE: ${this.#nanoid()}`);

this.$extends({
model: {
customer: {
create: ({ args, query }) => {
args.data = {
...args.data,
code: this.#nanoid(),
};

query(args);
},
},
},
}).$extends(
createSoftDeleteExtension({
models: {
User: true,
Customer: true,
},
defaultConfig: {
field: 'deletedAt',
createValue: (deleted) => {
if (deleted) {
return new Date();
}
return null;
},
},
}),
);

await this.$connect();
}

async onModuleDestroy() {
await this.$disconnect();
}
}
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
private readonly logger = new Logger(PrismaService.name);
#nanoid: (size?: number) => string = undefined;

constructor() {
super();
this.#nanoid = customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 4);
}

async onModuleInit() {
this.logger.log(`CODE: ${this.#nanoid()}`);

this.$extends({
model: {
customer: {
create: ({ args, query }) => {
args.data = {
...args.data,
code: this.#nanoid(),
};

query(args);
},
},
},
}).$extends(
createSoftDeleteExtension({
models: {
User: true,
Customer: true,
},
defaultConfig: {
field: 'deletedAt',
createValue: (deleted) => {
if (deleted) {
return new Date();
}
return null;
},
},
}),
);

await this.$connect();
}

async onModuleDestroy() {
await this.$disconnect();
}
}
8 Replies
Daniel Sousa @TutoDS
Invalid `this.prismaService.customer.create()` invocation in /src/modules/customers/customers.service.ts:20:48 17 18 async createCustomer(customer: CreateCustomerDto): Promise<Customer> { 19 try {→ 20 return await this.prismaService.customer.create({ data: { ...., + code: String } })Argument `code` is missing.
Invalid `this.prismaService.customer.create()` invocation in /src/modules/customers/customers.service.ts:20:48 17 18 async createCustomer(customer: CreateCustomerDto): Promise<Customer> { 19 try {→ 20 return await this.prismaService.customer.create({ data: { ...., + code: String } })Argument `code` is missing.
I changed my $extends to this:
this.$extends({
model: {
customer: {
create: ({ args, query }) => {
if (typeof this.#nanoid === 'undefined') {
return query(args);
}

const customerCode = this.#nanoid();

return query({
...args,
data: {
...args.data,
code: customerCode,
},
});
},
},
},
});
this.$extends({
model: {
customer: {
create: ({ args, query }) => {
if (typeof this.#nanoid === 'undefined') {
return query(args);
}

const customerCode = this.#nanoid();

return query({
...args,
data: {
...args.data,
code: customerCode,
},
});
},
},
},
});
But not working...
RaphaelEtim
RaphaelEtimthis hour
Hi @Daniel Sousa @TutoDS Can you modify your code to look like
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { customAlphabet } from 'nanoid';

const extendedPrismaClient = new PrismaClient().$extends({
model: {
customer: {
create: ({ args, query }) => {
const nanoid = customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 4);
args.data = {
...args.data,
code: nanoid(),
};
return query(args);
},
},
},
});

@Injectable()
export class PrismaService
extends PrismaClient
implements OnModuleInit
{
constructor() {
super();
Object.assign(this, extendedPrismaClient);
}

async onModuleInit() {
await this.$connect();
}
}
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { customAlphabet } from 'nanoid';

const extendedPrismaClient = new PrismaClient().$extends({
model: {
customer: {
create: ({ args, query }) => {
const nanoid = customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 4);
args.data = {
...args.data,
code: nanoid(),
};
return query(args);
},
},
},
});

@Injectable()
export class PrismaService
extends PrismaClient
implements OnModuleInit
{
constructor() {
super();
Object.assign(this, extendedPrismaClient);
}

async onModuleInit() {
await this.$connect();
}
}
Daniel Sousa @TutoDS
Is throwing this
No description
Daniel Sousa @TutoDS
console.log(args) returning undefined
RaphaelEtim
RaphaelEtim19h ago
Can you modify your extension to use $allOperations instead of targeting a specific model operation:
const extendedPrismaClient = new PrismaClient().$extends({
query: {
$allOperations: async ({ model, operation, args, query }) => {
if (model === 'customer' && operation === 'create') {
const nanoid = customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 4);
if (args && typeof args === 'object') {
args.data = {
...args.data,
code: nanoid(),
};
}
}
return query(args);
},
},
});
const extendedPrismaClient = new PrismaClient().$extends({
query: {
$allOperations: async ({ model, operation, args, query }) => {
if (model === 'customer' && operation === 'create') {
const nanoid = customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 4);
if (args && typeof args === 'object') {
args.data = {
...args.data,
code: nanoid(),
};
}
}
return query(args);
},
},
});
Daniel Sousa @TutoDS
Didn't work... Is generating a random nanoid without following the alphabet and the length
const extendedPrismaClient = new PrismaClient().$extends({
query: {
customer: {
create: async ({ args, query }) => {
const nanoid = customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 4);
if (args && typeof args === 'object') {
args.data = {
...args.data,
code: nanoid(4),
};
}

return query(args);
},
},
},
});
const extendedPrismaClient = new PrismaClient().$extends({
query: {
customer: {
create: async ({ args, query }) => {
const nanoid = customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 4);
if (args && typeof args === 'object') {
args.data = {
...args.data,
code: nanoid(4),
};
}

return query(args);
},
},
},
});
but this way I think it's working @RaphaelEtim By the way, I have the createdBy, updatedBy and deleteBy fields. Is possible to create an $extends to fill this with the current logged user? I already try to do it, but inside the onModuleInit because I need to inject the request
RaphaelEtim
RaphaelEtim17h ago
it is possible to use Prisma Client Extensions to automatically fill the createdBy, updatedBy, and deletedBy fields with the current logged-in user. You will need an extension function that takes the user information as an argument. This way, you can create a new extended Prisma client instance for each request, with the current user's information.
Daniel Sousa @TutoDS
can you share an example please?

Did you find this page helpful?