|
|
@@ -0,0 +1,33 @@
|
|
|
+import {test,after} from 'node:test';
|
|
|
+import assert from 'node:assert/strict';
|
|
|
+import {readFileSync} from 'node:fs';
|
|
|
+import vm from 'node:vm';
|
|
|
+import {PGlite} from '@electric-sql/pglite';
|
|
|
+const source=readFileSync(new URL('../deploy-admin-functions.mjs',import.meta.url),'utf8');
|
|
|
+const baseline=JSON.parse(readFileSync(new URL('../../perf/admin-data-2026-10-15/legacy-read-queries.json',import.meta.url),'utf8'));
|
|
|
+const db=new PGlite(),query=async(sql,args)=>(await db.query(sql,args)).rows;
|
|
|
+after(()=>db.close());
|
|
|
+const ctx=vm.createContext({Psql:{query},companyIdOf:()=> 'a'});
|
|
|
+vm.runInContext(source.match(/const operationsGatewayCode = String.raw`([\s\S]*?)\n`;/)[1],ctx);
|
|
|
+const sorted=rows=>rows.toSorted((a,b)=>JSON.stringify(a).localeCompare(JSON.stringify(b)));
|
|
|
+test('set-based course and appointment reads preserve tenant, cancellation, duplicates and missing metadata',async()=>{
|
|
|
+ await db.exec(`CREATE TABLE "CommonModel"(company text,"modelId" numeric,"itemId" numeric,status numeric);
|
|
|
+ CREATE TABLE "CourseAppointment"(company text,id numeric,szyh text,dszt text,dslx text,yysj text,bxrq text,kcid text);
|
|
|
+ CREATE TABLE "CourseBinding"(company text,kcid text);
|
|
|
+ CREATE TABLE "Node"(company text,"nodeId" numeric,"parentId" numeric,"nodeName" text);
|
|
|
+ INSERT INTO "Node" VALUES ('a',1,0,'小学'),('a',2,1,'课程甲'),('a',3,1,'课程乙'),('a',398,1,'写作'),('a',8,1,'未使用'),('b',2,0,'其他帐套课程');
|
|
|
+ INSERT INTO "CourseBinding" VALUES('a','2'),('a','2'),('a','bad'),('b','8');
|
|
|
+ INSERT INTO "CourseAppointment" VALUES('a',1,'s1','0','3','2099-01-02',null,'3'),('a',2,'s1','30','1','2026-10-01',null,'3'),('a',3,'s2','11','3',null,'2099-01-03','3'),('a',4,'s2','99','1',null,null,null),('a',5,null,null,null,null,null,null),('b',1,'s1','20','3',null,null,'2');
|
|
|
+ INSERT INTO "CommonModel" VALUES('a',54,1,99),('a',54,1,-2),('a',54,1,-2),('a',54,2,99),('a',59,3,-2),('b',54,3,-2),('b',54,1,99);`);
|
|
|
+ const courseSql=vm.runInNewContext(source.match(/courseSql=('[\s\S]*?'),\[categories/)[1]);
|
|
|
+ for(const co of ['a','b',null]){
|
|
|
+ assert.deepEqual(sorted(await ctx.memberAppointmentStats(co)),sorted(await query(baseline.appointments,[co])));
|
|
|
+ assert.deepEqual(await query(courseSql,[co]),await query(baseline.courses,[co]));
|
|
|
+ }
|
|
|
+ const members=await ctx.memberAppointmentStats('a');
|
|
|
+ assert.equal(members.find(r=>r.uid==='s1').appointment_count,2);
|
|
|
+ assert.equal(members.find(r=>r.uid==='s1').unfinished,0);
|
|
|
+ assert.equal(members.find(r=>r.uid==='s2').unfinished,1);
|
|
|
+ assert.equal(members.find(r=>r.uid==='s2').abnormal,1);
|
|
|
+ assert.deepEqual((await query(courseSql,['a'])).map(r=>r.id).sort(),['2','3','398']);
|
|
|
+});
|