Fix leaveEvent persistence: use SPARQL DELETE instead of ORM ngSet.delete()

ngSet.delete() updates the local reactive set but does not persist to the
broker. Use ng.sparql_update() with SPARQL DELETE WHERE to remove RDF triples
directly — the broker sends back a GraphOrmUpdate that reactively removes the
item from the ORM set. The two methods must not be combined as they conflict
in the CRDT.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sylvain Duchesne
2026-03-17 12:28:02 +01:00
parent ea8fbcf8b7
commit 6b95695d34
3 changed files with 127 additions and 6 deletions
+26 -6
View File
@@ -24,6 +24,8 @@ import {
import type { FpEvent, FpUserProfile, FpParticipation } from '../shapes/orm/festipodShapes.typings';
import { bootstrapWallet, type BootstrapResult } from '../utils/ngBootstrap';
import { ensureGraphNuri } from '../utils/ngGraph';
import { sessionPromise } from '../utils/ngSession';
import { ng } from '@ng-org/web';
// ============================================================================
// Context interface
@@ -334,12 +336,30 @@ function useNgData(): FestipodDataContextValue {
console.log('[FestipodData] leaveEvent (NG):', eventId, 'user:', uid);
const ngPart = [...participationsShape.ngSet].find(p => p.event === eventId && p.user === uid);
if (ngPart) {
console.log('[FestipodData] Deleting participation:', ngPart["@id"]);
participationsShape.ngSet.delete(ngPart);
const ngEvent = findNg(eventsShape.ngSet as any as Set<FpEvent>, e => e["@id"] === eventId);
if (ngEvent) {
ngEvent.participantCount = Math.max(0, ngEvent.participantCount - 1);
}
const partId = ngPart["@id"];
const partGraph = ngPart["@graph"];
console.log('[FestipodData] Deleting participation:', partId, '@graph:', partGraph);
// Use ONLY sparql_update to delete — the broker will send back a GraphOrmUpdate
// that removes the item from the ORM set reactively. Avoid calling ngSet.delete()
// simultaneously as the two operations can conflict in the CRDT.
(async () => {
try {
const session = await sessionPromise;
await ng.sparql_update(
session.session_id,
`DELETE WHERE { GRAPH <${partGraph}> { <${partId}> ?p ?o } }`,
partGraph,
);
console.log('[FestipodData] SPARQL DELETE succeeded for participation:', partId);
// Update participantCount after confirmed deletion
const ngEvent = findNg(eventsShape.ngSet as any as Set<FpEvent>, e => e["@id"] === eventId);
if (ngEvent) {
ngEvent.participantCount = Math.max(0, ngEvent.participantCount - 1);
}
} catch (err) {
console.error('[FestipodData] SPARQL DELETE failed:', err);
}
})();
}
}, [participationsShape.ngSet, eventsShape.ngSet, currentUserId]);