Skip to content

Commit

Permalink
SISMBIOHUB-259: Survey Block (#1085)
Browse files Browse the repository at this point in the history
Survey Block UI/ API endpoints added
  • Loading branch information
al-rosenthal authored Sep 8, 2023
1 parent df258a0 commit 5d80722
Show file tree
Hide file tree
Showing 19 changed files with 1,102 additions and 6 deletions.
3 changes: 3 additions & 0 deletions api/src/models/survey-create.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Feature } from 'geojson';
import { PostSurveyBlock } from '../repositories/survey-block-repository';

export class PostSurveyObject {
survey_details: PostSurveyDetailsData;
Expand All @@ -11,6 +12,7 @@ export class PostSurveyObject {
agreements: PostAgreementsData;
participants: PostParticipationData[];
partnerships: PostPartnershipsData;
blocks: PostSurveyBlock[];

constructor(obj?: any) {
this.survey_details = (obj?.survey_details && new PostSurveyDetailsData(obj.survey_details)) || null;
Expand All @@ -26,6 +28,7 @@ export class PostSurveyObject {
this.participants =
(obj?.participants?.length && obj.participants.map((p: any) => new PostParticipationData(p))) || [];
this.partnerships = (obj?.partnerships && new PostPartnershipsData(obj.partnerships)) || null;
this.blocks = (obj?.blocks && obj.blocks.map((p: any) => p as PostSurveyBlock)) || [];
}
}

Expand Down
3 changes: 3 additions & 0 deletions api/src/models/survey-update.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Feature } from 'geojson';
import { PostSurveyBlock } from '../repositories/survey-block-repository';

export class PutSurveyObject {
survey_details: PutSurveyDetailsData;
Expand All @@ -10,6 +11,7 @@ export class PutSurveyObject {
location: PutSurveyLocationData;
participants: PutSurveyParticipantsData[];
partnerships: PutPartnershipsData;
blocks: PostSurveyBlock[];

constructor(obj?: any) {
this.survey_details = (obj?.survey_details && new PutSurveyDetailsData(obj.survey_details)) || null;
Expand All @@ -24,6 +26,7 @@ export class PutSurveyObject {
this.participants =
(obj?.participants?.length && obj.participants.map((p: any) => new PutSurveyParticipantsData(p))) || [];
this.partnerships = (obj?.partnerships && new PutPartnershipsData(obj.partnerships)) || null;
this.blocks = (obj?.blocks && obj.blocks.map((p: any) => p as PostSurveyBlock)) || [];
}
}

Expand Down
2 changes: 2 additions & 0 deletions api/src/models/survey-view.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Feature } from 'geojson';
import { SurveyMetadataPublish } from '../repositories/history-publish-repository';
import { IPermitModel } from '../repositories/permit-repository';
import { SurveyBlockRecord } from '../repositories/survey-block-repository';
import { SurveyUser } from '../repositories/survey-participation-repository';

export type SurveyObject = {
Expand All @@ -13,6 +14,7 @@ export type SurveyObject = {
location: GetSurveyLocationData;
participants: SurveyUser[];
partnerships: ISurveyPartnerships;
blocks: SurveyBlockRecord[];
};

export interface ISurveyPartnerships {
Expand Down
15 changes: 15 additions & 0 deletions api/src/paths/project/{projectId}/survey/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,21 @@ POST.apiDoc = {
}
}
}
},
blocks: {
type: 'array',
items: {
type: 'object',
required: ['name', 'description'],
properties: {
name: {
type: 'string'
},
description: {
type: 'string'
}
}
}
}
}
}
Expand Down
19 changes: 19 additions & 0 deletions api/src/paths/project/{projectId}/survey/{surveyId}/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,25 @@ PUT.apiDoc = {
}
}
}
},
blocks: {
type: 'array',
items: {
type: 'object',
required: ['name', 'description'],
properties: {
survey_block_id: {
type: 'number',
nullable: true
},
name: {
type: 'string'
},
description: {
type: 'string'
}
}
}
}
}
}
Expand Down
18 changes: 18 additions & 0 deletions api/src/paths/project/{projectId}/survey/{surveyId}/update/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,24 @@ GET.apiDoc = {
}
}
}
},
blocks: {
type: 'array',
items: {
type: 'object',
required: ['survey_block_id', 'name', 'description'],
properties: {
survey_block_id: {
type: 'number'
},
name: {
type: 'string'
},
description: {
type: 'string'
}
}
}
}
}
}
Expand Down
210 changes: 210 additions & 0 deletions api/src/repositories/survey-block-repository.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
import chai, { expect } from 'chai';
import { describe } from 'mocha';
import { QueryResult } from 'pg';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import { ApiExecuteSQLError } from '../errors/api-error';
import { getMockDBConnection } from '../__mocks__/db';
import { PostSurveyBlock, SurveyBlockRepository } from './survey-block-repository';

chai.use(sinonChai);

describe('SurveyBlockRepository', () => {
afterEach(() => {
sinon.restore();
});

describe('getSurveyBlocksForSurveyId', () => {
it('should succeed with valid data', async () => {
const mockResponse = ({
rows: [
{
survey_block_id: 1,
survey_id: 1,
name: '',
description: '',
create_date: '',
create_user: 1,
update_date: '',
update_user: 1,
revision_count: 1
}
],
rowCount: 1
} as any) as Promise<QueryResult<any>>;
const dbConnection = getMockDBConnection({
sql: () => mockResponse
});

const repo = new SurveyBlockRepository(dbConnection);
const response = await repo.getSurveyBlocksForSurveyId(1);

response.forEach((item) => {
expect(item.survey_id).to.be.eql(1);
});
});

it('should succeed with empty data', async () => {
const mockResponse = ({
rows: [],
rowCount: 0
} as any) as Promise<QueryResult<any>>;
const dbConnection = getMockDBConnection({
sql: () => mockResponse
});

const repo = new SurveyBlockRepository(dbConnection);
const response = await repo.getSurveyBlocksForSurveyId(1);
expect(response).to.be.empty;
});
});

describe('updateSurveyBlock', () => {
it('should succeed with valid data', async () => {
const mockResponse = ({
rows: [
{
survey_block_id: 1,
survey_id: 1,
name: 'Updated name',
description: '',
create_date: '',
create_user: 1,
update_date: '',
update_user: 1,
revision_count: 1
}
],
rowCount: 1
} as any) as Promise<QueryResult<any>>;
const dbConnection = getMockDBConnection({
sql: () => mockResponse
});

const repo = new SurveyBlockRepository(dbConnection);
const block: PostSurveyBlock = { survey_block_id: 1, survey_id: 1, name: 'Updated name', description: 'block' };
const response = await repo.updateSurveyBlock(block);
expect(response.survey_block_id).to.be.eql(1);
expect(response.name).to.be.eql('Updated name');
});

it('should failed with erroneous data', async () => {
const mockResponse = ({
rows: [],
rowCount: 0
} as any) as Promise<QueryResult<any>>;
const dbConnection = getMockDBConnection({
sql: () => mockResponse
});

const repo = new SurveyBlockRepository(dbConnection);
const block: PostSurveyBlock = { survey_block_id: null, survey_id: 1, name: 'new', description: 'block' };
try {
await repo.updateSurveyBlock(block);
expect.fail();
} catch (error) {
expect(((error as any) as ApiExecuteSQLError).message).to.be.eq('Failed to update survey block');
}
});
});

describe('insertSurveyBlock', () => {
it('should succeed with valid data', async () => {
const mockResponse = ({
rows: [
{
survey_block_id: 1,
survey_id: 1,
name: 'new',
description: 'block',
create_date: '',
create_user: 1,
update_date: '',
update_user: 1,
revision_count: 1
}
],
rowCount: 1
} as any) as Promise<QueryResult<any>>;
const dbConnection = getMockDBConnection({
sql: () => mockResponse
});
const repo = new SurveyBlockRepository(dbConnection);

const block: PostSurveyBlock = { survey_block_id: null, survey_id: 1, name: 'new', description: 'block' };
const response = await repo.insertSurveyBlock(block);

expect(response.name).to.be.eql('new');
expect(response.description).to.be.eql('block');
});

it('should fail with erroneous data', async () => {
const mockResponse = ({
rows: [],
rowCount: 0
} as any) as Promise<QueryResult<any>>;
const dbConnection = getMockDBConnection({
sql: () => mockResponse
});
const repo = new SurveyBlockRepository(dbConnection);
try {
const block = ({
survey_block_id: null,
survey_id: 1,
name: null,
description: null
} as any) as PostSurveyBlock;
await repo.insertSurveyBlock(block);
expect.fail();
} catch (error) {
expect(((error as any) as ApiExecuteSQLError).message).to.be.eq('Failed to insert survey block');
}
});
});

describe('deleteSurveyBlockRecord', () => {
it('should succeed with valid data', async () => {
const mockResponse = ({
rows: [
{
survey_block_id: 1,
survey_id: 1,
name: 'Deleted record',
description: '',
create_date: '',
create_user: 1,
update_date: '',
update_user: 1,
revision_count: 1
}
],
rowCount: 1
} as any) as Promise<QueryResult<any>>;
const dbConnection = getMockDBConnection({
sql: () => mockResponse
});

const repo = new SurveyBlockRepository(dbConnection);
const response = await repo.deleteSurveyBlockRecord(1);
expect(response.survey_block_id).to.be.eql(1);
});

it('should failed with erroneous data', async () => {
const mockResponse = ({
rows: [],
rowCount: 0
} as any) as Promise<QueryResult<any>>;
const dbConnection = getMockDBConnection({
sql: () => mockResponse
});

const repo = new SurveyBlockRepository(dbConnection);
try {
await repo.deleteSurveyBlockRecord(1);
expect.fail();
} catch (error) {
expect(((error as any) as ApiExecuteSQLError).message).to.be.eq('Failed to delete survey block record');
}
});
});
});
Loading

0 comments on commit 5d80722

Please sign in to comment.