generated from fahricansecer/boilerplate-be
This commit is contained in:
@@ -81,23 +81,40 @@ export class ContentService {
|
||||
status?: ContentStatus;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
sortBy?: string;
|
||||
sortOrder?: 'asc' | 'desc';
|
||||
},
|
||||
) {
|
||||
return this.prisma.content.findMany({
|
||||
where: {
|
||||
...(userId && { userId }),
|
||||
...(options?.platform && { type: options.platform as any }),
|
||||
...(options?.status && { status: options.status }),
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: options?.limit || 50,
|
||||
skip: options?.offset || 0,
|
||||
include: {
|
||||
masterContent: { select: { id: true, title: true, type: true } },
|
||||
variants: { select: { id: true, name: true, isWinner: true } },
|
||||
_count: { select: { variants: true } },
|
||||
},
|
||||
});
|
||||
// Build dynamic orderBy
|
||||
const sortField = options?.sortBy || 'createdAt';
|
||||
const sortDir = options?.sortOrder || 'desc';
|
||||
const validSortFields = ['createdAt', 'updatedAt', 'type', 'status', 'publishedAt'];
|
||||
const orderBy = validSortFields.includes(sortField)
|
||||
? { [sortField]: sortDir }
|
||||
: { createdAt: 'desc' as const };
|
||||
|
||||
const where = {
|
||||
...(userId && { userId }),
|
||||
...(options?.platform && { type: options.platform as any }),
|
||||
...(options?.status && { status: options.status }),
|
||||
};
|
||||
|
||||
const [items, total] = await Promise.all([
|
||||
this.prisma.content.findMany({
|
||||
where,
|
||||
orderBy,
|
||||
take: options?.limit || 100,
|
||||
skip: options?.offset || 0,
|
||||
include: {
|
||||
masterContent: { select: { id: true, title: true, type: true } },
|
||||
variants: { select: { id: true, name: true, isWinner: true } },
|
||||
_count: { select: { variants: true } },
|
||||
},
|
||||
}),
|
||||
this.prisma.content.count({ where }),
|
||||
]);
|
||||
|
||||
return { items, total };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,12 +156,42 @@ export class ContentService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete content
|
||||
* Delete all related records for given content IDs, then delete the content.
|
||||
* Uses a transaction to ensure atomicity.
|
||||
*/
|
||||
private async cascadeDeleteContents(ids: string[]) {
|
||||
return this.prisma.$transaction(async (tx) => {
|
||||
// Delete all dependent relations first
|
||||
await tx.citation.deleteMany({ where: { contentId: { in: ids } } });
|
||||
await tx.contentVariant.deleteMany({ where: { contentId: { in: ids } } });
|
||||
await tx.media.deleteMany({ where: { contentId: { in: ids } } });
|
||||
await tx.scheduledPost.deleteMany({ where: { contentId: { in: ids } } });
|
||||
await tx.contentApproval.deleteMany({ where: { contentId: { in: ids } } });
|
||||
await tx.contentAnalytics.deleteMany({ where: { contentId: { in: ids } } });
|
||||
await tx.contentSeo.deleteMany({ where: { contentId: { in: ids } } });
|
||||
await tx.contentPsychology.deleteMany({ where: { contentId: { in: ids } } });
|
||||
await tx.contentSource.deleteMany({ where: { contentId: { in: ids } } });
|
||||
|
||||
// Now delete the content itself
|
||||
const result = await tx.content.deleteMany({ where: { id: { in: ids } } });
|
||||
return result.count;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete content (with cascade)
|
||||
*/
|
||||
async delete(id: string) {
|
||||
return this.prisma.content.delete({
|
||||
where: { id },
|
||||
});
|
||||
const deleted = await this.cascadeDeleteContents([id]);
|
||||
return { deleted };
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk delete content items (with cascade)
|
||||
*/
|
||||
async bulkDelete(ids: string[]) {
|
||||
const deleted = await this.cascadeDeleteContents(ids);
|
||||
return { deleted };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user