| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970 |
- import { before, after, test } 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 db = new PGlite();
- const gateway = {};
- vm.createContext(gateway);
- const source = readFileSync(new URL('../deploy-admin-functions.mjs', import.meta.url), 'utf8');
- vm.runInContext(source.match(/const operationsGatewayCode = String.raw`([\s\S]*?)\n`;/)[1], gateway);
- gateway.companyIdOf = () => 'co';
- gateway.companyPointer = () => ({ id: 'co' });
- gateway.Psql = {
- query: async (sql, args) => (await db.query(sql, args)).rows,
- oneOrNone: async (sql, args) => (await db.query(sql, args)).rows[0] || null,
- };
- // Parse is external; SQL evidence queries and persisted identity changes use the real database.
- gateway.Parse = {
- Query: class {
- async get(id) {
- const row = (await db.query('SELECT * FROM "_User" WHERE "objectId"=$1', [id])).rows[0];
- return {
- get: key => row[key], set: (key, value) => { row[key] = value; },
- save: async () => db.query('UPDATE "_User" SET "identityType"=$2 WHERE "objectId"=$1', [id, row.identityType]),
- };
- }
- },
- Object: class { set() {} async save() {} },
- };
- before(async () => {
- await db.exec(`
- CREATE TABLE "_User"("objectId" text,company text,"legacyUserId" int,"legacyGroupId" int,"legacyUserData" jsonb,"isAdmin" boolean,"isDeleted" boolean,"identityType" text);
- CREATE TABLE "CourseAppointment"(company text,pl text,fxpl text,szyh text);
- CREATE TABLE "LessonRecord"(company text,jsmz text,xymz text);
- CREATE TABLE "DailyStudyRecord"(company text,"userId" int);
- CREATE TABLE "CourseBinding"(company text,yhid text);
- CREATE TABLE "PracticeRecord"(company text,yhid text);
- CREATE TABLE "LegacySyncConflict"("objectId" text,company text,dataset text,"legacyKey" text,resolved boolean);
- INSERT INTO "_User" VALUES
- ('teacher','co',1535,3,'{}',false,false,'conflict'),
- ('student','co',2,1,'{}',false,false,'member'),
- ('ambiguous','co',3,1,'{}',false,false,'conflict'),
- ('dual-binding','co',4,3,'{}',false,false,'conflict'),
- ('dual-lesson','co',5,3,'{}',false,false,'conflict'),
- ('store','co',6,2,'{}',false,false,'store');
- INSERT INTO "CourseAppointment" VALUES ('co','1535','1535','99'),('co','3',null,'99'),('co','4',null,'99'),('co','6',null,'6'),('other','99',null,'1535');
- INSERT INTO "LessonRecord" VALUES ('co','5','5');
- INSERT INTO "CourseBinding" VALUES ('co','4');
- INSERT INTO "PracticeRecord" VALUES ('co','1535'),('co','2'),('co','3');
- `);
- await gateway.refreshIdentityProjection({}, {});
- });
- after(() => db.close());
- const identity = async id => (await db.query('SELECT "identityType" FROM "_User" WHERE "objectId"=$1', [id])).rows[0].identityType;
- test('正式老师自己的单词练习不再把老师误标为冲突,其他帐套学员证据不串入', async () => {
- assert.equal(await identity('teacher'), 'coach');
- await gateway.refreshIdentityProjection({}, {});
- assert.equal(await identity('teacher'), 'coach');
- });
- test('仅练习的普通学员仍是学员,分组未经确认的双重身份仍需核实', async () => {
- assert.equal(await identity('student'), 'member');
- assert.equal(await identity('ambiguous'), 'conflict');
- });
- test('老师同时有正式学员课程或课后记录时仍保留冲突,门店角色不改变', async () => {
- assert.equal(await identity('dual-binding'), 'conflict');
- assert.equal(await identity('dual-lesson'), 'conflict');
- assert.equal(await identity('store'), 'store');
- });
|