feat(v2.2): 完成高频读取热路径
This commit is contained in:
@@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user