Skip to content

Commit

Permalink
working on force-processing updates as creates
Browse files Browse the repository at this point in the history
  • Loading branch information
ktuite committed Jul 24, 2024
1 parent 52c3f93 commit 748054d
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 10 deletions.
28 changes: 18 additions & 10 deletions lib/model/query/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,14 @@ const _getHeldSubmissionsAsEvents = () => ({ all }) => all(sql`
// Used by _updateVerison below to figure out the intended base version in Central
// based on the branchId, trunkVersion, and baseVersion in the submission
const _computeBaseVersion = async (maybeOne, run, eventId, dataset, clientEntity, submissionDef, forceOutOfOrderProcessing = false) => {
if (forceOutOfOrderProcessing) {
// we are forcefully applying an update of this submission
// and the correct base version does not exist in the database.
// we will be using trunk version instead
// but also removing the held submission from the backlog
await _checkAndDeleteHeldSubmission(maybeOne, clientEntity.def.branchId, clientEntity.def.baseVersion);
}

if (!clientEntity.def.trunkVersion || clientEntity.def.baseVersion === clientEntity.def.trunkVersion) {
// trunk and client baseVersion are the same, indicating the start of a batch
return clientEntity.def.baseVersion;
Expand All @@ -232,11 +240,6 @@ const _computeBaseVersion = async (maybeOne, run, eventId, dataset, clientEntity

if (!previousInBranch.isDefined()) {
if (forceOutOfOrderProcessing) {
// we are forcefully applying an update of this submission
// and the correct base version does not exist in the database.
// we will be using trunk version instead
// but also removing the held submission from the backlog
await _checkAndDeleteHeldSubmission(maybeOne, clientEntity.def.branchId, clientEntity.def.baseVersion);
return clientEntity.def.trunkVersion;
} else {
// not ready to process this submission. eventually hold it for later.
Expand All @@ -249,13 +252,17 @@ const _computeBaseVersion = async (maybeOne, run, eventId, dataset, clientEntity
}
};

const _createEntity = (dataset, entityData, submissionId, submissionDef, submissionDefId, event, parentEvent) => async ({ Audits, Entities }) => {
const _createEntity = (dataset, entityData, submissionId, submissionDef, submissionDefId, event, parentEvent, forceOutOfOrderProcessing = false) => async ({ Audits, Entities }) => {
// If dataset requires approval on submission to create an entity and this event is not
// an approval event, then don't create an entity
if ((dataset.approvalRequired && event.details.reviewState !== 'approved') ||
(!dataset.approvalRequired && event.action === 'submission.update')) // don't process submission if approval is not required and submission metadata is updated
return null;

if (forceOutOfOrderProcessing && entityData.system.label == null) {
// eslint-disable-next-line no-param-reassign
entityData.system.label = 'auto generated';
}
const partial = await Entity.fromParseEntityData(entityData, { create: true });

const sourceDetails = { submission: { instanceId: submissionDef.instanceId }, parentEventId: parentEvent ? parentEvent.id : undefined };
Expand Down Expand Up @@ -286,7 +293,7 @@ const _updateEntity = (dataset, entityData, submissionId, submissionDef, submiss
// If the entity doesn't exist, check branchId - maybe this is an update for an entity created offline
let serverEntity = await Entities.getById(dataset.id, clientEntity.uuid, QueryOptions.forUpdate);
if (!serverEntity.isDefined()) {
if (clientEntity.def.branchId == null) {
if (clientEntity.def.branchId == null || forceOutOfOrderProcessing) {
throw Problem.user.entityNotFound({ entityUuid: clientEntity.uuid, datasetName: dataset.name });
} else {
await _holdSubmission(run, event.id, submissionDef.submissionId, submissionDef.id, clientEntity.def.branchId, clientEntity.def.baseVersion);
Expand Down Expand Up @@ -314,7 +321,7 @@ const _updateEntity = (dataset, entityData, submissionId, submissionDef, submiss
if (baseVersion == null)
return null;

if (baseVersion !== serverEntity.aux.currentVersion.version) {
if (baseVersion !== serverEntity.aux.currentVersion.version && !forceOutOfOrderProcessing) {

const condition = { datasetId: dataset.id, uuid: clientEntity.uuid, version: baseVersion };
// eslint-disable-next-line no-use-before-define
Expand Down Expand Up @@ -437,8 +444,9 @@ const _processSubmissionEvent = (event, parentEvent) => async ({ Audits, Dataset
try {
maybeEntity = await Entities._updateEntity(dataset, entityData, submissionId, submissionDef, submissionDefId, event, forceOutOfOrderProcessing);
} catch (err) {
if ((err.problemCode === 404.8) && (entityData.system.create === '1' || entityData.system.create === 'true')) {
maybeEntity = await Entities._createEntity(dataset, entityData, submissionId, submissionDef, submissionDefId, event, parentEvent);
const attemptCreate = (entityData.system.create === '1' || entityData.system.create === 'true') || forceOutOfOrderProcessing;
if ((err.problemCode === 404.8) && attemptCreate) {
maybeEntity = await Entities._createEntity(dataset, entityData, submissionId, submissionDef, submissionDefId, event, parentEvent, forceOutOfOrderProcessing);
} else {
throw (err);
}
Expand Down
94 changes: 94 additions & 0 deletions test/integration/api/offline-entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -888,5 +888,99 @@ describe('Offline Entities', () => {
backlogCount = await container.oneFirst(sql`select count(*) from entity_submission_backlog`);
backlogCount.should.equal(0);
}));

it('should apply an entity update as a create', testOfflineEntities(async (service, container) => {
const asAlice = await service.login('alice');
const branchId = uuid();
const newUuid = uuid();

// Base version is 1 but it doesnt exist
// trunk version doesnt make sense to exist here either
await asAlice.post('/v1/projects/1/forms/offlineEntity/submissions')
.send(testData.instances.offlineEntity.one
.replace('id="12345678-1234-4123-8234-123456789abc"', `id="${newUuid}"`)
.replace('branchId=""', `branchId="${branchId}"`)
.replace('trunkVersion="1"', 'trunkVersion=""')
)
.set('Content-Type', 'application/xml')
.expect(200);

await exhaust(container);

let backlogCount = await container.oneFirst(sql`select count(*) from entity_submission_backlog`);
backlogCount.should.equal(1);

await container.Entities.processHeldSubmissions();

await asAlice.get(`/v1/projects/1/datasets/people/entities/${newUuid}`)
.expect(200)
.then(({ body }) => {
body.currentVersion.version.should.equal(1);
body.currentVersion.data.should.eql({ status: 'arrived' });
body.currentVersion.label.should.eql('auto generated');
body.currentVersion.branchId.should.equal(branchId);


// This is the first version of the entity so there should be no base or trunk versions
should.not.exist(body.currentVersion.trunkVersion);
should.not.exist(body.currentVersion.baseVersion);
should.not.exist(body.currentVersion.branchBaseVersion);
});

backlogCount = await container.oneFirst(sql`select count(*) from entity_submission_backlog`);
backlogCount.should.equal(0);
}));

it('should apply an entity update as a create followed by another update', testOfflineEntities(async (service, container) => {
const asAlice = await service.login('alice');
const branchId = uuid();
const newUuid = uuid();

// Base version is 1 but it doesnt exist
// trunk version doesnt make sense to exist here either
await asAlice.post('/v1/projects/1/forms/offlineEntity/submissions')
.send(testData.instances.offlineEntity.one
.replace('id="12345678-1234-4123-8234-123456789abc"', `id="${newUuid}"`)
.replace('branchId=""', `branchId="${branchId}"`)
.replace('trunkVersion="1"', 'trunkVersion=""')
)
.set('Content-Type', 'application/xml')
.expect(200);

// base version is 2 now
await asAlice.post('/v1/projects/1/forms/offlineEntity/submissions')
.send(testData.instances.offlineEntity.one
.replace('one', 'one-update')
.replace('id="12345678-1234-4123-8234-123456789abc"', `id="${newUuid}"`)
.replace('branchId=""', `branchId="${branchId}"`)
.replace('baseVersion="1"', 'baseVersion="2"')
.replace('trunkVersion="1"', 'trunkVersion=""')
.replace('<status>arrived</status>', '<name>Dana</name><status>checked in</status>')
)
.set('Content-Type', 'application/xml')
.expect(200);

await exhaust(container);

let backlogCount = await container.oneFirst(sql`select count(*) from entity_submission_backlog`);
backlogCount.should.equal(2);

await container.Entities.processHeldSubmissions();

await asAlice.get(`/v1/projects/1/datasets/people/entities/${newUuid}`)
.expect(200)
.then(({ body }) => {
body.currentVersion.version.should.equal(2);
body.currentVersion.data.should.eql({ status: 'checked in', first_name: 'Dana' });
body.currentVersion.label.should.eql('auto generated');
body.currentVersion.branchId.should.equal(branchId);
body.currentVersion.baseVersion.should.equal(2); // TODO: fix, this doesnt really make sense
body.currentVersion.branchBaseVersion.should.equal(2);
should.not.exist(body.currentVersion.trunkVersion);
});

backlogCount = await container.oneFirst(sql`select count(*) from entity_submission_backlog`);
backlogCount.should.equal(0);
}));
});
});

0 comments on commit 748054d

Please sign in to comment.