|
@@ -0,0 +1,70 @@
|
|
|
|
|
+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');
|
|
|
|
|
+});
|