Kaynağa Gözat

added auto increment vid in Prisma videoMedia

Dave 1 ay önce
ebeveyn
işleme
1764dd0f21

+ 87 - 0
apps/box-mgnt-api/src/mgnt-backend/feature/video-media/video-media.service.ts

@@ -3,6 +3,7 @@ import {
   NotFoundException,
   BadRequestException,
   Inject,
+  Logger,
 } from '@nestjs/common';
 import type { MultipartFile } from '@fastify/multipart';
 import { MongoPrismaService } from '@box/db/prisma/mongo-prisma.service';
@@ -27,6 +28,9 @@ type MongoAggregateResult = {
 
 @Injectable()
 export class VideoMediaService {
+  private readonly logger = new Logger(VideoMediaService.name);
+  private isBackfillingVid = false;
+
   constructor(
     private readonly prisma: MongoPrismaService,
     private readonly cacheSyncService: CacheSyncService,
@@ -35,7 +39,89 @@ export class VideoMediaService {
     private readonly mediaStorageStrategy: StorageStrategy,
   ) {}
 
+  // helper to generate next vid
+  private async generateNextVid(): Promise<number> {
+    const last = await this.prisma.videoMedia.findFirst({
+      where: { vid: { isSet: true } },
+      orderBy: { vid: 'desc' },
+      select: { vid: true },
+    });
+
+    return (last?.vid ?? 0) + 1;
+  }
+
+  // backfill vid for videoMedia documents without one
+  private async backfillVids(): Promise<void> {
+    if (this.isBackfillingVid) {
+      this.logger.warn('backfillVids is already running, skipping.');
+      return;
+    }
+
+    this.isBackfillingVid = true;
+    this.logger.log('Starting backfill of vid...');
+    try {
+      const videosWithoutVid = await this.prisma.videoMedia.findMany({
+        where: {
+          OR: [{ vid: { isSet: false } }, { vid: null }],
+        },
+        orderBy: { createdAt: 'asc' },
+        select: { id: true },
+      });
+
+      if (videosWithoutVid.length === 0) {
+        this.logger.log('No videos need backfilling vid.');
+        return;
+      }
+
+      this.logger.log(
+        `Found ${videosWithoutVid.length} videos without vid. Starting backfill...`,
+      );
+
+      let nextVid = await this.generateNextVid();
+
+      for (const video of videosWithoutVid) {
+        let assigned = false;
+
+        while (!assigned) {
+          try {
+            await this.prisma.videoMedia.update({
+              where: { id: video.id },
+              data: { vid: nextVid },
+            });
+
+            this.logger.log(
+              `Backfilled vid ${nextVid} for videoMedia id ${video.id}`,
+            );
+
+            nextVid += 1;
+            assigned = true;
+          } catch (e: any) {
+            // Unique constraint violation → retry with a fresh number
+            if (e?.code === 'P2002') {
+              this.logger.warn(`Duplicate vid ${nextVid}, retrying...`);
+              nextVid = await this.generateNextVid();
+            } else {
+              throw e;
+            }
+          }
+        }
+      }
+
+      this.logger.log(
+        `Backfilled ${videosWithoutVid.length} vids successfully.`,
+      );
+    } finally {
+      this.isBackfillingVid = false;
+      this.logger.log('Finished backfillVids process.');
+    }
+  }
+
   async findAll(query: VideoMediaListQueryDto): Promise<any> {
+    // ensure vids are backfilled
+    await this.backfillVids().catch((err) =>
+      this.logger.error('Backfill vid failed', err?.stack ?? String(err)),
+    );
+
     const page = query.page ?? 1;
     const pageSize = query.size ?? 20;
     const skip = (page - 1) * pageSize;
@@ -93,6 +179,7 @@ export class VideoMediaService {
       pageSize,
       items: rows.map((row) => ({
         id: row.id,
+        vid: row.vid ?? null,
         title: row.title,
         filename: row.filename,
         videoTime: row.videoTime,

+ 1 - 0
prisma/mongo/schema/video-media.prisma

@@ -1,6 +1,7 @@
 model VideoMedia {
   /// Mongo ObjectId stored in `_id`
   id            String    @id @map("_id") @db.ObjectId
+  vid           Int?      @unique
 
   srcId         Int       @default(0)
   title         String    @default("")