在nestjs + prisma中,prisma的创建时间createdAt和更新时间updatedAt存储的是UTC时间,响应时需要返回时间戳,还有就是对分页进行封装。

下面代码参考:knotekbr 的代码,适用于prisma 5.x版本

分页处理


// src/modules/prisma/extensions/get-page.extension.ts

import { Prisma } from '@prisma/client';

import type { PrismaClient } from '@prisma/client';
import AppConfig from 'src/config';

type GetPageRes<T> = {
  records: T;
  total: number;
  page: number;
  size: number;
};

/**
 * 查询并返回列表+总数
 * @param prisma - PrismaClient实例
 * @returns 返回一个包含getPage方法的对象
 */
export function createGetPageExtension<TModel = any, TArgs = any>(
  prisma: PrismaClient,
) {
  return {
    name: 'getPage',
    model: {
      $allModels: {
        async getPage(
          this: TModel,
          args?: Prisma.Exact<TArgs, Prisma.Args<TModel, 'findMany'>>,
          limit?: { page?: number; size?: number },
        ): Promise<GetPageRes<Prisma.Result<TModel, TArgs, 'findMany'>>> {
          const context = Prisma.getExtensionContext(this);

          const { page = 1, size = AppConfig.defaultPageSize } = limit ?? {};

          const [records, total] = await prisma.$transaction([
            (context as any).findMany({
              orderBy: { id: 'desc' },
              skip: (page - 1) * size,
              take: parseInt(size as unknown as string),
              ...((args ?? {}) as any),
            }),
            (context as any).count({ where: (args as any)?.where }),
          ]);

          return {
            records,
            total,
            page: page * 1,
            size: size * 1,
          };
        },
      },
    },
  };
}

export type GetPage<TModel, TArgs> = ReturnType<
  typeof createGetPageExtension<TModel, TArgs>
>['model']['$allModels']['getPage'];


响应时间处理


// src/modules/prisma/extensions/result-timestamp.extension.ts
/**
 * 响应创建时间、更新时间转为时间戳
 */
export function createResultTimestampExtension() {
  return {
    name: 'resultTimestamp',
    result: {
      $allModels: {
        createdAt: {
          compute(data: any) {
            return new Date(data.createdAt).getTime();
          },
        },
        updatedAt: {
          compute(data: any) {
            return new Date(data.updatedAt).getTime();
          },
        },
      },
    },
  };
}

export type ResultTimestamp = ReturnType<
  typeof createResultTimestampExtension
>['result']['$allModels']['createdAt'];


引入各个模块扩展


// src/modules/prisma/extended-client.ts

import { PrismaClient } from '@prisma/client';

import {
  createGetPageExtension,
  type GetPage,
} from './extensions/get-page.extension';
import { createResultTimestampExtension } from './extensions/result-timestamp.extension';

type ModelsWithExtensions = {
  [Model in keyof PrismaClient]: PrismaClient[Model] extends {
    findMany: (args: infer TArgs) => Promise<any>;
  }
    ? {
        getPage: GetPage<PrismaClient[Model], TArgs>;
      } & PrismaClient[Model]
    : PrismaClient[Model];
};

class UntypedExtendedClient extends PrismaClient {
  constructor(options?: ConstructorParameters<typeof PrismaClient>[0]) {
    super(options);
    // 注入分页、result处理扩展
    return this.$extends(createGetPageExtension(this)).$extends(
      createResultTimestampExtension(),
    ) as this;
  }
}

const ExtendedPrismaClient = UntypedExtendedClient as unknown as new (
  options?: ConstructorParameters<typeof PrismaClient>[0],
) => PrismaClient & ModelsWithExtensions;

export { ExtendedPrismaClient };


注入扩展


// src/modules/prisma/prisma.service.ts
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { ExtendedPrismaClient } from './extended-client';

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

  async onModuleDestroy() {
    await this.$disconnect();
  }
}