Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Ecological Units to Survey Focal Species #1343

Merged
merged 11 commits into from
Sep 6, 2024
4 changes: 2 additions & 2 deletions api/src/models/survey-create.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SurveyStratum } from '../repositories/site-selection-strategy-repository';
import { PostSurveyBlock } from '../repositories/survey-block-repository';
import { ITaxonomy } from '../services/platform-service';
import { ITaxonomyWithEcologicalUnits } from '../services/platform-service';
import { PostSurveyLocationData } from './survey-update';

export class PostSurveyObject {
Expand Down Expand Up @@ -89,7 +89,7 @@ export class PostSurveyDetailsData {
}

export class PostSpeciesData {
focal_species: ITaxonomy[];
focal_species: ITaxonomyWithEcologicalUnits[];

constructor(obj?: any) {
this.focal_species = (obj?.focal_species?.length && obj.focal_species) || [];
Expand Down
4 changes: 2 additions & 2 deletions api/src/models/survey-update.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Feature } from 'geojson';
import { SurveyStratum, SurveyStratumRecord } from '../repositories/site-selection-strategy-repository';
import { PostSurveyBlock } from '../repositories/survey-block-repository';
import { ITaxonomy } from '../services/platform-service';
import { ITaxonomyWithEcologicalUnits } from '../services/platform-service';

export class PutSurveyObject {
survey_details: PutSurveyDetailsData;
Expand Down Expand Up @@ -99,7 +99,7 @@ export class PutSurveyDetailsData {
}

export class PutSurveySpeciesData {
focal_species: ITaxonomy[];
focal_species: ITaxonomyWithEcologicalUnits[];

constructor(obj?: any) {
this.focal_species = (obj?.focal_species?.length && obj?.focal_species) || [];
Expand Down
4 changes: 2 additions & 2 deletions api/src/models/survey-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { SurveyBlockRecord } from '../repositories/survey-block-repository';
import { SurveyLocationRecord } from '../repositories/survey-location-repository';
import { SurveyUser } from '../repositories/survey-participation-repository';
import { SystemUser } from '../repositories/user-repository';
import { ITaxonomy } from '../services/platform-service';
import { ITaxonomyWithEcologicalUnits } from '../services/platform-service';

export interface ISurveyAdvancedFilters {
keyword?: string;
Expand Down Expand Up @@ -101,7 +101,7 @@ export class GetSurveyFundingSourceData {
}

export class GetFocalSpeciesData {
focal_species: ITaxonomy[];
focal_species: ITaxonomyWithEcologicalUnits[];

constructor(obj?: any[]) {
this.focal_species = [];
Expand Down
64 changes: 30 additions & 34 deletions api/src/openapi/schemas/critter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
import { OpenAPIV3 } from 'openapi-types';

export const collectionUnitsSchema: OpenAPIV3.SchemaObject = {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
required: ['collection_category_id', 'collection_unit_id'],
properties: {
critter_collection_unit_id: {
type: 'string',
format: 'uuid'
},
collection_category_id: {
type: 'string',
format: 'uuid'
},
collection_unit_id: {
type: 'string',
format: 'uuid'
},
unit_name: {
type: 'string'
},
category_name: {
type: 'string'
}
}
}
};

export const critterSchema: OpenAPIV3.SchemaObject = {
type: 'object',
additionalProperties: false,
Expand Down Expand Up @@ -54,40 +83,7 @@ export const critterSchema: OpenAPIV3.SchemaObject = {
}
}
},
collection_units: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
required: [
'critter_collection_unit_id',
'collection_category_id',
'collection_unit_id',
'unit_name',
'category_name'
],
properties: {
critter_collection_unit_id: {
type: 'string',
format: 'uuid'
},
collection_category_id: {
type: 'string',
format: 'uuid'
},
collection_unit_id: {
type: 'string',
format: 'uuid'
},
unit_name: {
type: 'string'
},
category_name: {
type: 'string'
}
}
}
}
collection_units: collectionUnitsSchema
}
};

Expand Down
29 changes: 27 additions & 2 deletions api/src/openapi/schemas/survey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,30 @@ export const surveyDetailsSchema: OpenAPIV3.SchemaObject = {
}
};

/**
* Schema for creating, updating and retrieving ecological units for focal species in a SIMS survey.
* Prefixed with critterbase_* to match database field names in SIMS.
*
*/
export const SurveyEcologicalUnitsSchema: OpenAPIV3.SchemaObject = {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
required: ['critterbase_collection_category_id', 'critterbase_collection_unit_id'],
properties: {
critterbase_collection_category_id: {
type: 'string',
format: 'uuid'
},
critterbase_collection_unit_id: {
type: 'string',
format: 'uuid'
}
}
}
};

export const surveyFundingSourceSchema: OpenAPIV3.SchemaObject = {
title: 'survey funding source response object',
type: 'object',
Expand Down Expand Up @@ -112,7 +136,7 @@ export const focalSpeciesSchema: OpenAPIV3.SchemaObject = {
title: 'focal species response object',
type: 'object',
additionalProperties: false,
required: ['tsn', 'commonNames', 'scientificName'],
required: ['tsn', 'commonNames', 'scientificName', 'ecological_units'],
properties: {
tsn: {
description: 'Taxonomy tsn',
Expand All @@ -137,7 +161,8 @@ export const focalSpeciesSchema: OpenAPIV3.SchemaObject = {
kingdom: {
description: 'Taxonomy kingdom name',
type: 'string'
}
},
ecological_units: SurveyEcologicalUnitsSchema
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ describe('getSurveyObservedSpecies', () => {
const mockTsns = [1, 2, 3];
const mockSpecies = mockTsns.map((tsn) => ({ itis_tsn: tsn }));
const mockItisResponse = [
{ tsn: '1', commonNames: ['common name 1'], scientificName: 'scientific name 1' },
{ tsn: '2', commonNames: ['common name 2'], scientificName: 'scientific name 2' },
{ tsn: '3', commonNames: ['common name 3'], scientificName: 'scientific name 3' }
{ tsn: 1, commonNames: ['common name 1'], scientificName: 'scientific name 1' },
{ tsn: 2, commonNames: ['common name 2'], scientificName: 'scientific name 2' },
{ tsn: 3, commonNames: ['common name 3'], scientificName: 'scientific name 3' }
];
const mockFormattedItisResponse = mockItisResponse.map((species) => ({ ...species, tsn: Number(species.tsn) }));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export function getSurveyObservedSpecies(): RequestHandler {

const species = await platformService.getTaxonomyByTsns(observedSpecies.flatMap((species) => species.itis_tsn));

const formattedResponse = species.map((taxon) => ({ ...taxon, tsn: Number(taxon.tsn) }));
const formattedResponse = species.map((taxon) => ({ ...taxon, tsn: taxon.tsn }));

return res.status(200).json(formattedResponse);
} catch (error) {
Expand Down
39 changes: 32 additions & 7 deletions api/src/repositories/survey-repository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ import { PostProprietorData, PostSurveyObject } from '../models/survey-create';
import { PutSurveyObject } from '../models/survey-update';
import { GetAttachmentsData, GetSurveyProprietorData, GetSurveyPurposeAndMethodologyData } from '../models/survey-view';
import { getMockDBConnection } from '../__mocks__/db';
import { SurveyRecord, SurveyRepository, SurveyTypeRecord } from './survey-repository';
import {
SurveyRecord,
SurveyRepository,
SurveyTaxonomyWithEcologicalUnits,
SurveyTypeRecord
} from './survey-repository';

chai.use(sinonChai);

Expand Down Expand Up @@ -140,26 +145,46 @@ describe('SurveyRepository', () => {

describe('getSpeciesData', () => {
it('should return result', async () => {
const mockResponse = { rows: [{ id: 1 }], rowCount: 1 } as any as Promise<QueryResult<any>>;
const mockRows: SurveyTaxonomyWithEcologicalUnits[] = [
{
itis_tsn: 123456,
ecological_units: [
{
critterbase_collection_category_id: '123-456-789',
critterbase_collection_unit_id: '987-654-321'
}
]
},
{
itis_tsn: 654321,
ecological_units: []
}
];
const mockResponse = { rows: mockRows, rowCount: 1 } as any as Promise<QueryResult<any>>;
const dbConnection = getMockDBConnection({ sql: () => mockResponse });

const repository = new SurveyRepository(dbConnection);

const response = await repository.getSpeciesData(1);
const surveyId = 1;

expect(response).to.eql([{ id: 1 }]);
const response = await repository.getSpeciesData(surveyId);

expect(response).to.eql(mockRows);
});

it('should return empty rows', async () => {
const mockResponse = { rows: [], rowCount: 1 } as any as Promise<QueryResult<any>>;
const mockRows: SurveyTaxonomyWithEcologicalUnits[] = [];
const mockResponse = { rows: mockRows, rowCount: 1 } as any as Promise<QueryResult<any>>;
const dbConnection = getMockDBConnection({ sql: () => mockResponse });

const repository = new SurveyRepository(dbConnection);

const response = await repository.getSpeciesData(1);
const surveyId = 1;

const response = await repository.getSpeciesData(surveyId);

expect(response).to.not.be.null;
expect(response).to.eql([]);
expect(response).to.eql(mockRows);
});
});

Expand Down
Loading