feat(v2.2): 完成高频读取热路径

This commit is contained in:
Script Generator
2026-07-03 11:53:25 +08:00
parent 5a90923031
commit 70460c3273
28 changed files with 3042 additions and 121 deletions

View File

@@ -15,6 +15,20 @@ describe('AppDataV22MigrationService', () => {
},
],
},
{
key: 'members',
value: {
members: [
{
id: 'member-pm',
name: 'Product manager',
username: 'pm',
email: '',
createdAt: '2026-01-01T00:00:00.000Z',
},
],
},
},
{
key: 'requirements',
value: {
@@ -26,6 +40,7 @@ describe('AppDataV22MigrationService', () => {
projectId: 'project-1',
versionId: 'version-1',
title: 'Customer import',
creator: 'member-pm',
createdAt: '2026-01-01T00:00:00.000Z',
},
],
@@ -64,10 +79,98 @@ describe('AppDataV22MigrationService', () => {
products: 1,
projects: 1,
versions: 1,
users: 1,
requirements: 1,
devTasks: 1,
}),
);
expect(preview.skipped).toEqual([]);
});
it('imports mapped rows in foreign-key-safe order with duplicate protection', async () => {
const calls: string[] = [];
const delegate = (name: string) => ({
createMany: jest.fn().mockImplementation(async () => {
calls.push(name);
return { count: 1 };
}),
});
const tx = {
user: delegate('user'),
product: delegate('product'),
project: delegate('project'),
version: delegate('version'),
taskCategory: delegate('taskCategory'),
requirement: delegate('requirement'),
versionPlan: delegate('versionPlan'),
devTask: delegate('devTask'),
testCase: delegate('testCase'),
bug: delegate('bug'),
workActivity: delegate('workActivity'),
taskWorklog: delegate('taskWorklog'),
overtimeRecord: delegate('overtimeRecord'),
xiaobaoRiskSnapshot: delegate('xiaobaoRiskSnapshot'),
xiaobaoRiskInsight: delegate('xiaobaoRiskInsight'),
xiaobaoRiskSummary: delegate('xiaobaoRiskSummary'),
};
const prisma = {
$transaction: jest.fn().mockImplementation(async (callback: (client: typeof tx) => Promise<unknown>) => callback(tx)),
appData: { findMany: jest.fn() },
};
const service = new AppDataV22MigrationService(prisma as any);
const mapped = service.mapSnapshot({
'products-overview': [
{
id: 'product-1',
name: 'FTB',
projects: [{ id: 'project-1', name: 'CRM', description: '', createdAt: '2026-01-01T00:00:00.000Z' }],
versions: [{ id: 'version-1', name: 'CRM V1.0', createdAt: '2026-01-01T00:00:00.000Z' }],
},
],
members: {
members: [{ id: 'member-pm', name: 'Product manager', username: 'pm', email: '', createdAt: '2026-01-01' }],
},
'task-categories': [
{
id: 'cat-fe',
code: 'frontend_development',
name: 'Frontend development',
group: 'development',
isSystem: true,
},
],
requirements: {
requirements: [
{
id: 'req-1',
code: 'REQ-001',
productId: 'product-1',
projectId: 'project-1',
versionId: 'version-1',
title: 'Customer import',
creator: 'member-pm',
createdAt: '2026-01-01T00:00:00.000Z',
},
],
},
});
const result = await service.importMappedRows(mapped);
expect(result.readyToImport).toBe(true);
expect(result.inserted).toEqual(expect.objectContaining({ users: 1, products: 1, requirements: 1 }));
expect(calls.slice(0, 6)).toEqual(['user', 'product', 'project', 'version', 'taskCategory', 'requirement']);
expect(tx.user.createMany).toHaveBeenCalledWith({
data: [expect.objectContaining({
id: 'member-pm',
email: 'pm@local.ftb',
createdAt: '2026-01-01T00:00:00.000Z',
})],
skipDuplicates: true,
});
expect(tx.requirement.createMany).toHaveBeenCalledWith({
data: [expect.objectContaining({ creatorId: 'member-pm' })],
skipDuplicates: true,
});
});
});