legacy-enrollment-reconciliation.sql 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. -- Historical authorizations already have an identity and learning progress.
  2. -- Complete only an unambiguous, confirmed WORD classification; never recreate them.
  3. CREATE OR REPLACE FUNCTION xs_reconcile_legacy_word_enrollments(co text,uid text DEFAULT NULL,course text DEFAULT NULL)
  4. RETURNS integer LANGUAGE plpgsql AS $$
  5. DECLARE candidate record; changed integer=0; affected integer;
  6. BEGIN
  7. FOR candidate IN
  8. SELECT b."objectId" FROM "CourseBinding" b
  9. WHERE b.company=co AND (uid IS NULL OR b.yhid=uid) AND (course IS NULL OR b.kcid=course)
  10. AND COALESCE(b."enrollmentStatus",'pending')='pending'
  11. AND (b."categoryKey" IS NULL OR b."categoryKey"='word')
  12. AND (b."sourceKey" ~ '^legacy[:\-]' OR b."sourceKey" ~ '^\[\["(ID|GeneralID)",[0-9]+\]\]$')
  13. ORDER BY b."objectId"
  14. LOOP
  15. BEGIN
  16. UPDATE "CourseBinding" b SET "categoryKey"='word',"categoryName"='单词课',"enrollmentStatus"='active',"updatedAt"=now()
  17. WHERE b.company=co AND b."objectId"=candidate."objectId"
  18. AND COALESCE(b."enrollmentStatus",'pending')='pending'
  19. AND (b."categoryKey" IS NULL OR b."categoryKey"='word')
  20. AND (b."sourceKey" ~ '^legacy[:\-]' OR b."sourceKey" ~ '^\[\["(ID|GeneralID)",[0-9]+\]\]$')
  21. AND EXISTS(SELECT 1 FROM "CommonModel" c WHERE c.company=b.company AND c."modelId"=58 AND c."itemId"=b.id AND c.status=99
  22. AND (c."sourceKey" ~ '^legacy[:\-]' OR c."sourceKey" ~ '^\[\["(ID|GeneralID)",[0-9]+\]\]$'))
  23. AND EXISTS(SELECT 1 FROM "Node" n WHERE n.company=b.company AND n."nodeId"::text=b.kcid AND COALESCE(n.zstatus,99)=99)
  24. AND EXISTS(SELECT 1 FROM "_User" u WHERE u.company=b.company AND u."legacyUserId"::text=b.yhid
  25. AND u."identityType"='member' AND NOT COALESCE(u."isDisabled",false) AND NOT COALESCE(u."isDeleted",false))
  26. AND EXISTS(SELECT 1 FROM "CourseTeachingProfile" p WHERE p.company=b.company AND p."courseId"::text=b.kcid AND p.confirmed=true AND p."categoryKey"='word')
  27. AND NOT EXISTS(SELECT 1 FROM "CourseTeachingProfile" p WHERE p.company=b.company AND p."courseId"::text=b.kcid AND p.confirmed=true AND p."categoryKey" IS DISTINCT FROM 'word')
  28. AND NOT EXISTS(SELECT 1 FROM "CourseBinding" other WHERE other.company=b.company AND other.yhid=b.yhid AND other.kcid=b.kcid
  29. AND other."objectId"<>b."objectId" AND COALESCE(other."enrollmentStatus",'pending')<>'recycled'
  30. AND (other."categoryKey" IS NULL OR other."categoryKey"='word'));
  31. GET DIAGNOSTICS affected=ROW_COUNT;
  32. changed=changed+affected;
  33. EXCEPTION WHEN unique_violation THEN
  34. -- A concurrent explicit enrollment won the active-identity index. Keep its
  35. -- new-system authorization and this historical record/progress unchanged.
  36. NULL;
  37. END;
  38. END LOOP;
  39. RETURN changed;
  40. END $$;
  41. CREATE OR REPLACE FUNCTION xs_legacy_word_enrollment_changed() RETURNS trigger LANGUAGE plpgsql AS $$
  42. DECLARE b record;
  43. BEGIN
  44. IF TG_TABLE_NAME='CourseBinding' THEN
  45. IF COALESCE(NEW."enrollmentStatus",'pending')='pending' AND (NEW."categoryKey" IS NULL OR NEW."categoryKey"='word') THEN
  46. PERFORM xs_reconcile_legacy_word_enrollments(NEW.company,NEW.yhid,NEW.kcid);
  47. END IF;
  48. ELSIF TG_TABLE_NAME='CommonModel' THEN
  49. IF NEW."modelId"=58 AND NEW.status=99 THEN
  50. FOR b IN SELECT yhid,kcid FROM "CourseBinding" WHERE company=NEW.company AND id=NEW."itemId" LOOP
  51. PERFORM xs_reconcile_legacy_word_enrollments(NEW.company,b.yhid,b.kcid);
  52. END LOOP;
  53. END IF;
  54. ELSIF TG_TABLE_NAME='_User' THEN
  55. IF NEW."identityType"='member' AND NOT COALESCE(NEW."isDisabled",false) AND NOT COALESCE(NEW."isDeleted",false) THEN
  56. PERFORM xs_reconcile_legacy_word_enrollments(NEW.company,NEW."legacyUserId"::text,NULL);
  57. END IF;
  58. ELSIF TG_TABLE_NAME='CourseTeachingProfile' THEN
  59. IF NEW.confirmed=true AND NEW."categoryKey"='word' THEN
  60. PERFORM xs_reconcile_legacy_word_enrollments(NEW.company,NULL,NEW."courseId"::text);
  61. END IF;
  62. ELSIF TG_TABLE_NAME='Node' THEN
  63. IF COALESCE(NEW.zstatus,99)=99 THEN
  64. PERFORM xs_reconcile_legacy_word_enrollments(NEW.company,NULL,NEW."nodeId"::text);
  65. END IF;
  66. END IF;
  67. RETURN NEW;
  68. END $$;
  69. DROP TRIGGER IF EXISTS xs_legacy_word_binding_changed ON "CourseBinding";
  70. CREATE TRIGGER xs_legacy_word_binding_changed AFTER INSERT OR UPDATE OF company,yhid,kcid,"categoryKey","enrollmentStatus","sourceKey" ON "CourseBinding"
  71. FOR EACH ROW EXECUTE FUNCTION xs_legacy_word_enrollment_changed();
  72. DROP TRIGGER IF EXISTS xs_legacy_word_common_changed ON "CommonModel";
  73. CREATE TRIGGER xs_legacy_word_common_changed AFTER INSERT OR UPDATE OF company,"modelId","itemId",status,"sourceKey" ON "CommonModel"
  74. FOR EACH ROW EXECUTE FUNCTION xs_legacy_word_enrollment_changed();
  75. DROP TRIGGER IF EXISTS xs_legacy_word_member_changed ON "_User";
  76. CREATE TRIGGER xs_legacy_word_member_changed AFTER INSERT OR UPDATE OF company,"legacyUserId","identityType","isDisabled","isDeleted" ON "_User"
  77. FOR EACH ROW EXECUTE FUNCTION xs_legacy_word_enrollment_changed();
  78. DROP TRIGGER IF EXISTS xs_legacy_word_profile_changed ON "CourseTeachingProfile";
  79. CREATE TRIGGER xs_legacy_word_profile_changed AFTER INSERT OR UPDATE OF company,"courseId","categoryKey",confirmed ON "CourseTeachingProfile"
  80. FOR EACH ROW EXECUTE FUNCTION xs_legacy_word_enrollment_changed();
  81. DROP TRIGGER IF EXISTS xs_legacy_word_node_changed ON "Node";
  82. CREATE TRIGGER xs_legacy_word_node_changed AFTER INSERT OR UPDATE OF company,"nodeId",zstatus ON "Node"
  83. FOR EACH ROW EXECUTE FUNCTION xs_legacy_word_enrollment_changed();
  84. REVOKE ALL ON FUNCTION xs_reconcile_legacy_word_enrollments(text,text,text) FROM PUBLIC;
  85. REVOKE ALL ON FUNCTION xs_legacy_word_enrollment_changed() FROM PUBLIC;
  86. DO $$
  87. DECLARE tenant record;
  88. BEGIN
  89. FOR tenant IN SELECT DISTINCT company FROM "CourseBinding" LOOP
  90. PERFORM xs_reconcile_legacy_word_enrollments(tenant.company);
  91. END LOOP;
  92. END $$;