Skip to content

Commit

Permalink
Better comments
Browse files Browse the repository at this point in the history
  • Loading branch information
ktuite committed Apr 18, 2024
1 parent 0ce31ce commit 94841b6
Showing 1 changed file with 55 additions and 27 deletions.
82 changes: 55 additions & 27 deletions lib/model/query/audits.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,57 @@ const getBySubmissionId = (submissionId, options) => ({ all }) => _getBySubmissi
return new Audit({ ...audit, details: { ...audit.details, entity } }, { actor: audit.aux.actor });
}));

// Get every audit for an entity. Some audits do not directly reference the
// entity or def, but instead reference a shared source, e.g. `entity.bulk.create` events.
// Fetching these events is done by looking at every Def of an Entity and the
// Source of that Def, then getting audits that reference either the Entity Def
// itself or the Source.
//
// This query also joins in other things linked from the Source, including:
// - The source's triggering event (e.g. an entity update event) and event actor
// - a submission creation event (and actor) IF a submission was part of the source.
// (This submission creation event is not necessarily the same as the triggering event
// but it can be.)
//
// This second part to get a submission creation event is to get basic information
// (mainly instanceId) about the source submission, even if it has been deleted.
//
// There is a separate query below to assemble full submission details for non-deleted
// submissions, but it was far too slow to have be part of this query.
const _getByEntityId = (fields, options, entityId) => sql`
SELECT ${fields} FROM entity_defs
LEFT JOIN entity_def_sources on entity_def_sources.id = entity_defs."sourceId"
INNER JOIN audits ON ((audits.details->>'entityDefId')::INTEGER = entity_defs.id OR (audits.details->>'sourceId')::INTEGER = entity_def_sources.id)
LEFT JOIN actors ON actors.id=audits."actorId"
LEFT JOIN audits triggering_event ON entity_def_sources."auditId" = triggering_event.id
LEFT JOIN actors triggering_event_actor ON triggering_event_actor.id = triggering_event."actorId"
-- if triggering event has a submissionId defined, look up creation event for that submission
-- it has info about the submission and creator we want to show even if the submission is deleted
LEFT JOIN audits submission_create_event ON (triggering_event.details->'submissionId')::INTEGER = (submission_create_event.details->'submissionId')::INTEGER AND submission_create_event.action = 'submission.create'
LEFT JOIN actors submission_create_event_actor ON submission_create_event_actor.id = submission_create_event."actorId"
WHERE entity_defs."entityId" = ${entityId}
ORDER BY audits."loggedAt" DESC, audits.id DESC
${page(options)}`;

// Get the full and current Submission linked to each Entity Def of a given Entity.
// If an Entity is created or updated by a Submission, that Entity Def is linked
// (via Entity Def Source) to the specific Submission Def that modified it.
// This query gets all relevant info about each Submission Def linked to each Def
// in an Entity.
//
// It can handle a variety of situations including:
// - The Def did not come from a Submission
// - The Submission has been purged, possibly by purging the whole Form
// - The Form has been soft-deleted so the Submission should not be returned
// - The Submission has been soft-deleted (though this is not possible to do)
//
// It will return the CURRENT version of the Dubmission rather than the version
// used to create the Entity Def (used to display updated Submission instanceName).
const _getEntityDefsWithSubs = (fields, entityId) => sql`
SELECT ${fields} FROM entity_defs
LEFT JOIN entity_def_sources on entity_def_sources.id = entity_defs."sourceId"
Expand All @@ -154,34 +204,10 @@ SELECT ${fields} FROM entity_defs
LEFT JOIN actors submission_actor ON submission_actor.id = submissions."submitterId"
LEFT JOIN actors current_submission_actor on current_submission_actor.id=current_submission_def."submitterId"
-- if some other kind of target object defined, add subquery here
-- ...
WHERE entity_defs."entityId" = ${entityId}
ORDER BY entity_defs.id DESC;
`;

const _getByEntityId = (fields, options, entityId) => sql`
SELECT ${fields} FROM entity_defs
LEFT JOIN entity_def_sources on entity_def_sources.id = entity_defs."sourceId"
INNER JOIN audits ON ((audits.details->>'entityDefId')::INTEGER = entity_defs.id OR (audits.details->>'sourceId')::INTEGER = entity_def_sources.id)
LEFT JOIN actors ON actors.id=audits."actorId"
LEFT JOIN audits triggering_event ON entity_def_sources."auditId" = triggering_event.id
LEFT JOIN actors triggering_event_actor ON triggering_event_actor.id = triggering_event."actorId"
-- if triggering event has a submissionId defined, look up creation event for that submission
-- it has info about the submission and creator we want to show even if the submission is deleted
LEFT JOIN audits submission_create_event ON (triggering_event.details->'submissionId')::INTEGER = (submission_create_event.details->'submissionId')::INTEGER AND submission_create_event.action = 'submission.create'
LEFT JOIN actors submission_create_event_actor ON submission_create_event_actor.id = submission_create_event."actorId"
-- if some other kind of target object defined, add subquery here
-- ...
WHERE entity_defs."entityId" = ${entityId}
ORDER BY audits."loggedAt" DESC, audits.id DESC
${page(options)}`;

const getByEntityId = (entityId, options) => ({ all }) => {

const _unjoiner = unjoiner(
Expand All @@ -202,8 +228,10 @@ const getByEntityId = (entityId, options) => ({ all }) => {
all(_getByEntityId(_unjoiner.fields, options, entityId)).then(map(_unjoiner)),
all(_getEntityDefsWithSubs(_defUnjoiner.fields, entityId)).then(map(_defUnjoiner))
])
.then(([audits, defs]) => {
const entityDefDict = Object.fromEntries(defs.map(def => [def.id, def]));
.then(([audits, defsWithSubs]) => {
// Build a map of Entity Def Ids to objects that contain full Submission information
// linked to that Def (if Submission exists and if Def is even linked to a Submission).
const entityDefDict = Object.fromEntries(defsWithSubs.map(def => [def.id, def]));

return audits.map(audit => {
const entitySourceDetails = audit.aux.source.forApi();
Expand All @@ -222,7 +250,7 @@ const getByEntityId = (entityId, options) => ({ all }) => {
}))
.orElse(undefined);

// Looking up in a different dict for the full submission details if they exist
// Look up the full Submission information and attempt to merge it in if it exists.
const subOption = entityDefDict[audit.aux.def.id];
const fullSubmission = subOption.aux.submission
.map(s => s.withAux('submitter', subOption.aux.submissionActor.orNull()))
Expand Down

0 comments on commit 94841b6

Please sign in to comment.