mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-14 16:46:22 +08:00
0a422aa158
#### PR Dependency Tree * **PR #15165** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added automated backend maintenance for missing blob metadata backfill, document-to-blob reference rebuilding, and unreferenced blob cleanup planning/execution. * Introduced scheduled batch processing (workspace-paged) and paginated object-storage listing. * **Bug Fixes** * Improved reliability of object-storage reads by treating expected “not found” results as non-errors. * Strengthened blob/expired cleanup flows with runtime-driven batching and reduced coupling to metadata synchronization. * **Tests** * Expanded unit and e2e coverage for partial blob metadata and updated runtime/job cleanup test assertions. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
113 lines
2.2 KiB
TypeScript
113 lines
2.2 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { Prisma } from '@prisma/client';
|
|
|
|
import { BaseModel } from './base';
|
|
|
|
export type CreateBlobInput = Prisma.BlobUncheckedCreateInput;
|
|
|
|
/**
|
|
* Blob Model
|
|
*/
|
|
@Injectable()
|
|
export class BlobModel extends BaseModel {
|
|
async upsert(blob: CreateBlobInput) {
|
|
return await this.db.blob.upsert({
|
|
where: {
|
|
workspaceId_key: {
|
|
workspaceId: blob.workspaceId,
|
|
key: blob.key,
|
|
},
|
|
},
|
|
update: {
|
|
mime: blob.mime,
|
|
size: blob.size,
|
|
status: blob.status,
|
|
uploadId: blob.uploadId,
|
|
},
|
|
create: {
|
|
workspaceId: blob.workspaceId,
|
|
key: blob.key,
|
|
mime: blob.mime,
|
|
size: blob.size,
|
|
status: blob.status,
|
|
uploadId: blob.uploadId,
|
|
},
|
|
});
|
|
}
|
|
|
|
async delete(workspaceId: string, key: string, permanently = false) {
|
|
if (permanently) {
|
|
await this.db.blob.deleteMany({
|
|
where: {
|
|
workspaceId,
|
|
key,
|
|
},
|
|
});
|
|
this.logger.log(`deleted blob ${workspaceId}/${key} permanently`);
|
|
return;
|
|
}
|
|
|
|
await this.db.blob.update({
|
|
where: {
|
|
workspaceId_key: {
|
|
workspaceId,
|
|
key,
|
|
},
|
|
},
|
|
data: {
|
|
deletedAt: new Date(),
|
|
},
|
|
});
|
|
}
|
|
|
|
async get(workspaceId: string, key: string) {
|
|
return await this.db.blob.findUnique({
|
|
where: {
|
|
workspaceId_key: {
|
|
workspaceId,
|
|
key,
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
async list(
|
|
workspaceId: string,
|
|
options?: { where: Prisma.BlobWhereInput; select?: Prisma.BlobSelect }
|
|
) {
|
|
return await this.db.blob.findMany({
|
|
where: {
|
|
...options?.where,
|
|
workspaceId,
|
|
deletedAt: null,
|
|
status: 'completed',
|
|
},
|
|
select: options?.select,
|
|
});
|
|
}
|
|
|
|
async hasAny(workspaceId: string) {
|
|
const count = await this.db.blob.count({
|
|
where: {
|
|
workspaceId,
|
|
deletedAt: null,
|
|
},
|
|
});
|
|
return count > 0;
|
|
}
|
|
|
|
async totalSize(workspaceId: string) {
|
|
const sum = await this.db.blob.aggregate({
|
|
where: {
|
|
workspaceId,
|
|
deletedAt: null,
|
|
},
|
|
_sum: {
|
|
size: true,
|
|
},
|
|
});
|
|
|
|
return sum._sum.size ?? 0;
|
|
}
|
|
}
|