From b2013e08dd77ec0465c32b94b807b3321246f40f Mon Sep 17 00:00:00 2001 From: Laura Bergoens Date: Wed, 5 Mar 2025 15:43:28 +0100 Subject: [PATCH] tech(api): save of knowledge-element-snapshot-repository does "upsert" now Co-authored-by: Yvonnick Frin Co-authored-by: Xavier Carron --- .../knowledge-element-snapshot-repository.js | 39 ++++++++-------- ...wledge-element-snapshot-repository_test.js | 45 +++++++++++++++---- 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/api/src/prescription/campaign/infrastructure/repositories/knowledge-element-snapshot-repository.js b/api/src/prescription/campaign/infrastructure/repositories/knowledge-element-snapshot-repository.js index 047a382a22c..661e8cff361 100644 --- a/api/src/prescription/campaign/infrastructure/repositories/knowledge-element-snapshot-repository.js +++ b/api/src/prescription/campaign/infrastructure/repositories/knowledge-element-snapshot-repository.js @@ -1,27 +1,32 @@ import { knex } from '../../../../../db/knex-database-connection.js'; import { DomainTransaction } from '../../../../shared/domain/DomainTransaction.js'; -import { AlreadyExistingEntityError } from '../../../../shared/domain/errors.js'; import { KnowledgeElement } from '../../../../shared/domain/models/KnowledgeElement.js'; -import * as knexUtils from '../../../../shared/infrastructure/utils/knex-utils.js'; import { CampaignParticipationKnowledgeElementSnapshots } from '../../../shared/domain/read-models/CampaignParticipationKnowledgeElementSnapshots.js'; -const save = async function ({ userId, snappedAt, snapshot, campaignParticipationId }) { - try { - const knexConn = DomainTransaction.getConnection(); +export async function save({ userId, snappedAt, snapshot, campaignParticipationId }) { + const knexConn = DomainTransaction.getConnection(); + const existingSnapshot = await knexConn + .select('id') + .from('knowledge-element-snapshots') + .where('campaignParticipationId', campaignParticipationId) + .first(); + if (existingSnapshot) { + return await knexConn('knowledge-element-snapshots') + .update({ + userId, + snappedAt, + snapshot, + }) + .where('campaignParticipationId', campaignParticipationId); + } else { return await knexConn('knowledge-element-snapshots').insert({ userId, snappedAt, snapshot, campaignParticipationId, }); - } catch (error) { - if (knexUtils.isUniqConstraintViolated(error)) { - throw new AlreadyExistingEntityError( - `A snapshot already exists for the user ${userId} at the datetime ${snappedAt}.`, - ); - } } -}; +} /** * @function @@ -30,7 +35,7 @@ const save = async function ({ userId, snappedAt, snapshot, campaignParticipatio * @param {number[]} campaignParticipationIds * @returns {Promise>} */ -const findCampaignParticipationKnowledgeElementSnapshots = async function (campaignParticipationIds) { +export async function findCampaignParticipationKnowledgeElementSnapshots(campaignParticipationIds) { const knowledgeElementsByCampaignParticipation = await findByCampaignParticipationIds(campaignParticipationIds); return campaignParticipationIds.map( (campaignParticipationId) => @@ -39,14 +44,14 @@ const findCampaignParticipationKnowledgeElementSnapshots = async function (campa campaignParticipationId: campaignParticipationId, }), ); -}; +} /** * * @param {number[]} campaignParticipationIds * @returns {Object.} */ -const findByCampaignParticipationIds = async function (campaignParticipationIds) { +export async function findByCampaignParticipationIds(campaignParticipationIds) { const results = await knex .select('campaignParticipationId', 'snapshot') .from('knowledge-element-snapshots') @@ -60,6 +65,4 @@ const findByCampaignParticipationIds = async function (campaignParticipationIds) }), ]), ); -}; - -export { findByCampaignParticipationIds, findCampaignParticipationKnowledgeElementSnapshots, save }; +} diff --git a/api/tests/prescription/campaign/integration/infrastructure/repositories/knowledge-element-snapshot-repository_test.js b/api/tests/prescription/campaign/integration/infrastructure/repositories/knowledge-element-snapshot-repository_test.js index b42b97bd362..f97326ef76c 100644 --- a/api/tests/prescription/campaign/integration/infrastructure/repositories/knowledge-element-snapshot-repository_test.js +++ b/api/tests/prescription/campaign/integration/infrastructure/repositories/knowledge-element-snapshot-repository_test.js @@ -1,12 +1,11 @@ import * as knowledgeElementSnapshotRepository from '../../../../../../src/prescription/campaign/infrastructure/repositories/knowledge-element-snapshot-repository.js'; import { KnowledgeElementCollection } from '../../../../../../src/prescription/shared/domain/models/KnowledgeElementCollection.js'; import { DomainTransaction } from '../../../../../../src/shared/domain/DomainTransaction.js'; -import { AlreadyExistingEntityError } from '../../../../../../src/shared/domain/errors.js'; -import { catchErr, databaseBuilder, domainBuilder, expect, knex } from '../../../../../test-helper.js'; +import { databaseBuilder, domainBuilder, expect, knex } from '../../../../../test-helper.js'; describe('Integration | Repository | KnowledgeElementSnapshotRepository', function () { describe('#save', function () { - it('should save knowledge elements snapshot for a userId and a date', async function () { + it('should create a new knowledge elements snapshot when no snapshot exist for given campaignParticipationId', async function () { // given const snappedAt = new Date('2019-04-01'); const userId = databaseBuilder.factory.buildUser().id; @@ -34,28 +33,56 @@ describe('Integration | Repository | KnowledgeElementSnapshotRepository', functi const actualUserSnapshot = await knex.select('*').from('knowledge-element-snapshots').first(); expect(actualUserSnapshot.userId).to.deep.equal(userId); expect(actualUserSnapshot.snappedAt).to.deep.equal(snappedAt); - expect(actualUserSnapshot.snapshot).to.deep.equal(JSON.parse(knowledgeElements.toSnapshot())); }); - it('should throw an error if knowledge elements snapshot already exist for userId and a date', async function () { + it('should update the existing knowledge elements snapshot when snapshot exists for given campaignParticipationId', async function () { // given const snappedAt = new Date('2019-04-01'); const userId = databaseBuilder.factory.buildUser().id; const campaignParticipationId = databaseBuilder.factory.buildCampaignParticipation().id; - databaseBuilder.factory.buildKnowledgeElementSnapshot({ userId, snappedAt, campaignParticipationId }); + const knowledgeElement1 = databaseBuilder.factory.buildKnowledgeElement({ + userId, + createdAt: new Date('2019-03-01'), + skillId: 'acquis1', + }); + const knowledgeElement2 = databaseBuilder.factory.buildKnowledgeElement({ + userId, + createdAt: new Date('2019-03-01'), + skillId: 'acquis2', + }); + const knowledgeElement3 = databaseBuilder.factory.buildKnowledgeElement({ + userId, + createdAt: new Date('2019-03-01'), + skillId: 'acquis3', + }); + const knowledgeElementsBefore = new KnowledgeElementCollection([knowledgeElement1, knowledgeElement2]); + databaseBuilder.factory.buildKnowledgeElementSnapshot({ + userId, + snappedAt: new Date('2019-01-01'), + campaignParticipationId, + snapshot: knowledgeElementsBefore.toSnapshot(), + }); await databaseBuilder.commit(); + const knowledgeElementsAfter = new KnowledgeElementCollection([ + knowledgeElement1, + knowledgeElement2, + knowledgeElement3, + ]); // when - const error = await catchErr(knowledgeElementSnapshotRepository.save)({ + await knowledgeElementSnapshotRepository.save({ userId, snappedAt, - snapshot: JSON.stringify([]), + snapshot: knowledgeElementsAfter.toSnapshot(), campaignParticipationId, }); // then - expect(error).to.be.instanceOf(AlreadyExistingEntityError); + const actualUserSnapshot = await knex.select('*').from('knowledge-element-snapshots').first(); + expect(actualUserSnapshot.userId).to.deep.equal(userId); + expect(actualUserSnapshot.snappedAt).to.deep.equal(snappedAt); + expect(actualUserSnapshot.snapshot).to.deep.equal(JSON.parse(knowledgeElementsAfter.toSnapshot())); }); context('when a transaction is given transaction', function () {