From 901cb5ca873e9b4e352b93b8f76c55e1a6e69080 Mon Sep 17 00:00:00 2001 From: Macgregor Aubertin-Young Date: Fri, 5 Jul 2024 15:34:27 -0700 Subject: [PATCH 1/2] fix bug when upserting observations --- .../observation-repository/observation-repository.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/src/repositories/observation-repository/observation-repository.ts b/api/src/repositories/observation-repository/observation-repository.ts index 85360f1354..86753256ee 100644 --- a/api/src/repositories/observation-repository/observation-repository.ts +++ b/api/src/repositories/observation-repository/observation-repository.ts @@ -304,7 +304,9 @@ export class ObservationRepository extends BaseRepository { observations .map((observation) => { return `(${[ - 'survey_observation_id' in observation ? observation.survey_observation_id : 'DEFAULT', + 'survey_observation_id' in observation && observation.survey_observation_id + ? observation.survey_observation_id + : 'DEFAULT', surveyId, observation.survey_sample_site_id ?? 'NULL', observation.survey_sample_method_id ?? 'NULL', @@ -321,6 +323,8 @@ export class ObservationRepository extends BaseRepository { .join(', ') ); + console.log(sqlStatement); + sqlStatement.append(` ON CONFLICT (survey_observation_id) From 7a2e3825ee966863ffa902528acef8eea753a21e Mon Sep 17 00:00:00 2001 From: Nick Phura Date: Mon, 8 Jul 2024 09:43:14 -0700 Subject: [PATCH 2/2] Delete unused function. Misc cleanup. --- .../{surveyId}/observations/index.test.ts | 4 +- .../survey/{surveyId}/observations/index.ts | 13 ++- .../observation-repository.ts | 2 - api/src/services/observation-service.test.ts | 91 +------------------ api/src/services/observation-service.ts | 25 ----- 5 files changed, 11 insertions(+), 124 deletions(-) diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/observations/index.test.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/observations/index.test.ts index d9fa1c43bf..744c7706a4 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/observations/index.test.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/observations/index.test.ts @@ -75,7 +75,7 @@ describe('insertUpdateManualSurveyObservations', () => { surveyObservations }; - const requestHandler = observationRecords.insertUpdateManualSurveyObservations(); + const requestHandler = observationRecords.putObservations(); await requestHandler(mockReq, mockRes, mockNext); @@ -126,7 +126,7 @@ describe('insertUpdateManualSurveyObservations', () => { }; try { - const requestHandler = observationRecords.insertUpdateManualSurveyObservations(); + const requestHandler = observationRecords.putObservations(); await requestHandler(mockReq, mockRes, mockNext); expect.fail(); diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/observations/index.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/observations/index.ts index d670b31308..49aa7688bd 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/observations/index.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/observations/index.ts @@ -52,7 +52,7 @@ export const PUT: Operation = [ ] }; }), - insertUpdateManualSurveyObservations() + putObservations() ]; GET.apiDoc = { @@ -168,7 +168,8 @@ PUT.apiDoc = { type: 'integer', minimum: 1, nullable: true, - description: 'The survey observation ID. If provided observation, the record will be updated.' + description: + 'The survey observation ID. If provided, the matching existing observation record will be updated. If not provided, a new observation record will be inserted.' }, itis_tsn: { type: 'integer' @@ -229,9 +230,11 @@ PUT.apiDoc = { ], properties: { observation_subcount_id: { - type: 'number', + type: 'integer', + minimum: 1, nullable: true, - description: 'The observation subcount ID. If provided, the subcount record will be updated.' + description: + 'The observation subcount ID. If provided, the mataching existing subcount record will be updated. If not provided, a new subcount record will be inserted.' }, subcount: { type: 'number', @@ -407,7 +410,7 @@ export function getSurveyObservations(): RequestHandler { * @export * @return {*} {RequestHandler} */ -export function insertUpdateManualSurveyObservations(): RequestHandler { +export function putObservations(): RequestHandler { return async (req, res) => { const surveyId = Number(req.params.surveyId); diff --git a/api/src/repositories/observation-repository/observation-repository.ts b/api/src/repositories/observation-repository/observation-repository.ts index 86753256ee..f9ad81ce6a 100644 --- a/api/src/repositories/observation-repository/observation-repository.ts +++ b/api/src/repositories/observation-repository/observation-repository.ts @@ -323,8 +323,6 @@ export class ObservationRepository extends BaseRepository { .join(', ') ); - console.log(sqlStatement); - sqlStatement.append(` ON CONFLICT (survey_observation_id) diff --git a/api/src/services/observation-service.test.ts b/api/src/services/observation-service.test.ts index 8c4e9726b5..157c613664 100644 --- a/api/src/services/observation-service.test.ts +++ b/api/src/services/observation-service.test.ts @@ -2,11 +2,8 @@ import chai, { expect } from 'chai'; import sinon from 'sinon'; import sinonChai from 'sinon-chai'; import { - InsertObservation, - ObservationRecord, ObservationRecordWithSamplingAndSubcountData, - ObservationRepository, - UpdateObservation + ObservationRepository } from '../repositories/observation-repository/observation-repository'; import * as file_utils from '../utils/file-utils'; import { getMockDBConnection } from '../__mocks__/db'; @@ -28,92 +25,6 @@ describe('ObservationService', () => { expect(observationService).to.be.instanceof(ObservationService); }); - describe('insertUpdateDeleteSurveyObservations', () => { - it('deletes, creates, and updates observation records', async () => { - const mockDBConnection = getMockDBConnection(); - - const deleteObservationsNotInArrayStub = sinon - .stub(ObservationRepository.prototype, 'deleteObservationsNotInArray') - .resolves(); - - const mockInsertUpdateResponse: ObservationRecord[] = [ - { - survey_observation_id: 11, - survey_id: 1, - latitude: 3, - longitude: 4, - count: 5, - itis_tsn: 6, - itis_scientific_name: 'itis_scientific_name', - observation_date: '2023-01-01', - observation_time: '12:00:00', - create_date: '2023-04-04', - create_user: 1, - update_date: null, - update_user: null, - revision_count: 0, - survey_sample_site_id: 1, - survey_sample_method_id: 1, - survey_sample_period_id: 1 - }, - { - survey_observation_id: 6, - survey_id: 1, - latitude: 8, - longitude: 9, - count: 10, - itis_tsn: 6, - itis_scientific_name: 'itis_scientific_name', - observation_date: '2023-02-02', - observation_time: '13:00:00', - create_date: '2023-03-03', - create_user: 1, - update_date: '2023-04-04', - update_user: 2, - revision_count: 1, - survey_sample_site_id: 1, - survey_sample_method_id: 1, - survey_sample_period_id: 1 - } - ]; - const insertUpdateSurveyObservationsStub = sinon - .stub(ObservationRepository.prototype, 'insertUpdateSurveyObservations') - .resolves(mockInsertUpdateResponse); - - const surveyId = 1; - const observations: (InsertObservation | UpdateObservation)[] = [ - { - survey_id: 1, - latitude: 3, - longitude: 4, - count: 5, - itis_tsn: 6, - itis_scientific_name: 'itis_scientific_name', - observation_date: '2023-01-01', - observation_time: '12:00:00' - } as InsertObservation, - { - survey_observation_id: 6, - latitude: 8, - longitude: 9, - count: 10, - itis_tsn: 6, - itis_scientific_name: 'itis_scientific_name', - observation_date: '2023-02-02', - observation_time: '13:00:00' - } as UpdateObservation - ]; - - const observationService = new ObservationService(mockDBConnection); - - const response = await observationService.insertUpdateDeleteSurveyObservations(surveyId, observations); - - expect(deleteObservationsNotInArrayStub).to.have.been.calledOnceWith(surveyId, [6]); - expect(insertUpdateSurveyObservationsStub).to.have.been.calledOnceWith(surveyId, observations); - expect(response).to.eql(mockInsertUpdateResponse); - }); - }); - describe('getSurveyObservationsWithSupplementaryAndSamplingDataAndAttributeData', () => { it('Gets observations by survey id', async () => { const mockDBConnection = getMockDBConnection(); diff --git a/api/src/services/observation-service.ts b/api/src/services/observation-service.ts index 798ebb7082..720da3e757 100644 --- a/api/src/services/observation-service.ts +++ b/api/src/services/observation-service.ts @@ -140,31 +140,6 @@ export class ObservationService extends DBService { return this.observationRepository.findObservations(isUserAdmin, systemUserId, filterFields, pagination); } - /** - * Performs an upsert for all observation records belonging to the given survey, while removing - * any records associated for the survey that aren't included in the given records, then - * returns the updated rows - * - * @param {number} surveyId - * @param {((Observation | ObservationRecord)[])} observations - * @return {*} {Promise} - * @memberof ObservationService - */ - async insertUpdateDeleteSurveyObservations( - surveyId: number, - observations: (InsertObservation | UpdateObservation)[] - ): Promise { - const retainedObservationIds = observations - .filter((observation): observation is UpdateObservation => { - return 'survey_observation_id' in observation && Boolean(observation.survey_observation_id); - }) - .map((observation) => observation.survey_observation_id); - - await this.observationRepository.deleteObservationsNotInArray(surveyId, retainedObservationIds); - - return this.observationRepository.insertUpdateSurveyObservations(surveyId, observations); - } - /** * Upserts the given observation records and their associated measurements. *