Skip to content

Commit

Permalink
Merge branch 'master' into heartbeat
Browse files Browse the repository at this point in the history
  • Loading branch information
kafkasl authored Apr 21, 2022
2 parents 5881065 + c002b90 commit 74d7d43
Show file tree
Hide file tree
Showing 18 changed files with 1,192 additions and 195 deletions.
352 changes: 173 additions & 179 deletions package-lock.json

Large diffs are not rendered by default.

22 changes: 20 additions & 2 deletions src/api.v2/controllers/experimentController.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ const createExperiment = async (req, res) => {
const patchExperiment = async (req, res) => {
const { params: { experimentId }, body } = req;

logger.log(`Updating experiment ${experimentId}`);
logger.log(`Patching experiment ${experimentId}`);

const snakeCasedKeysToPatch = _.mapKeys(body, (_value, key) => _.snakeCase(key));

await new Experiment().updateById(experimentId, snakeCasedKeysToPatch);

logger.log(`Finished updating experiment ${experimentId}`);
logger.log(`Finished patching experiment ${experimentId}`);

res.json(OK());
};
Expand All @@ -86,6 +86,22 @@ const updateSamplePosition = async (req, res) => {
res.json(OK());
};

const getProcessingConfig = async (req, res) => {
const { params: { experimentId } } = req;
logger.log('Getting processing config for experiment ', experimentId);

const result = await new Experiment().getProcessingConfig(experimentId);
res.json(result);
};

const updateProcessingConfig = async (req, res) => {
const { params: { experimentId }, body } = req;
logger.log('Updating processing config for experiment ', experimentId);

await new Experiment().updateProcessingConfig(experimentId, body);
res.json(OK());
};

const getBackendStatus = async (req, res) => {
const { experimentId } = req.params;

Expand Down Expand Up @@ -114,7 +130,9 @@ module.exports = {
getAllExperiments,
getExperiment,
createExperiment,
updateProcessingConfig,
patchExperiment,
updateSamplePosition,
getProcessingConfig,
getBackendStatus,
};
19 changes: 19 additions & 0 deletions src/api.v2/controllers/sampleController.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const _ = require('lodash');

const Sample = require('../model/Sample');
const Experiment = require('../model/Experiment');
const MetadataTrack = require('../model/MetadataTrack');
Expand Down Expand Up @@ -36,9 +38,25 @@ const createSample = async (req, res) => {
res.json(OK());
};

const patchSample = async (req, res) => {
const { params: { experimentId, sampleId }, body } = req;

logger.log(`Patching sample ${sampleId} in experiment ${experimentId}`);

const snakeCasedKeysToPatch = _.mapKeys(body, (_value, key) => _.snakeCase(key));

await new Sample().updateById(sampleId, snakeCasedKeysToPatch);

logger.log(`Finished patching sample ${sampleId} in experiment ${experimentId}`);

res.json(OK());
};

const deleteSample = async (req, res) => {
const { params: { experimentId, sampleId } } = req;

logger.log(`Deleting sample ${sampleId} from experiment ${experimentId}`);

await sqlClient.get().transaction(async (trx) => {
await new Sample(trx).destroy(sampleId);
await new Experiment(trx).deleteSample(experimentId, sampleId);
Expand All @@ -51,5 +69,6 @@ const deleteSample = async (req, res) => {

module.exports = {
createSample,
patchSample,
deleteSample,
};
19 changes: 19 additions & 0 deletions src/api.v2/model/Experiment.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,25 @@ class Experiment extends BasicModel {
}
}

async getProcessingConfig(experimentId) {
const result = await this.findOne({ id: experimentId });
if (_.isEmpty(result)) {
throw new NotFoundError('Experiment not found');
}

return result.processingConfig;
}

async updateProcessingConfig(experimentId, body) {
const { name: stepName, body: change } = body[0];
const updateString = JSON.stringify({ [stepName]: change });

await this.sql(tableNames.EXPERIMENT)
.update({
processing_config: this.sql.raw(`processing_config || '${updateString}'::jsonb`),
}).where('id', experimentId);
}

async addSample(experimentId, sampleId) {
await this.sql(tableNames.EXPERIMENT)
.update({
Expand Down
2 changes: 2 additions & 0 deletions src/api.v2/model/__mocks__/Experiment.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const stub = {
getAllExperiments: jest.fn(),
getExperimentData: jest.fn(),
updateSamplePosition: jest.fn(),
updateProcessingConfig: jest.fn(),
getProcessingConfig: jest.fn(),
addSample: jest.fn(),
deleteSample: jest.fn(),
...BasicModel,
Expand Down
12 changes: 10 additions & 2 deletions src/api.v2/routes/experiment.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const {
createExperiment, getExperiment, patchExperiment, getAllExperiments,
updateSamplePosition, getBackendStatus,
createExperiment, getExperiment, patchExperiment, updateSamplePosition,
getAllExperiments, getProcessingConfig, updateProcessingConfig, getBackendStatus,
} = require('../controllers/experimentController');

const { expressAuthenticationOnlyMiddleware, expressAuthorizationMiddleware } = require('../middlewares/authMiddlewares');
Expand All @@ -26,6 +26,14 @@ module.exports = {
expressAuthorizationMiddleware,
(req, res, next) => updateSamplePosition(req, res).catch(next),
],
'experiment#getProcessingConfig': [
expressAuthorizationMiddleware,
(req, res, next) => getProcessingConfig(req, res).catch(next),
],
'experiment#updateProcessingConfig': [
expressAuthorizationMiddleware,
(req, res, next) => updateProcessingConfig(req, res).catch(next),
],
'experiment#getBackendStatus': [
expressAuthorizationMiddleware,
(req, res, next) => getBackendStatus(req, res).catch(next),
Expand Down
5 changes: 5 additions & 0 deletions src/api.v2/routes/sample.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const {
createSample,
patchSample,
deleteSample,
} = require('../controllers/sampleController');

Expand All @@ -10,6 +11,10 @@ module.exports = {
expressAuthorizationMiddleware,
(req, res, next) => createSample(req, res).catch(next),
],
'sample#patchSample': [
expressAuthorizationMiddleware,
(req, res, next) => patchSample(req, res).catch(next),
],
'sample#deleteSample': [
expressAuthorizationMiddleware,
(req, res, next) => deleteSample(req, res).catch(next),
Expand Down
120 changes: 117 additions & 3 deletions src/specs/api.v2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,71 @@ paths:
- env
- clusterEnv
description: Returns a status on the health of the API.
'/experiments/{experimentId}/processingConfig':
get:
summary: Get processing configuration for an experiment
description: Get processing configuration for an experiment
operationId: getProcessingConfig
x-eov-operation-id: experiment#getProcessingConfig
x-eov-operation-handler: routes/experiment
responses:
'200':
description: get processing configuration for an experiment
content:
application/json:
schema:
$ref: '#/components/schemas/ProcessingConfig'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPError'
'401':
description: The request lacks authentication credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPError'
'404':
description: Not found error.
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPError'

put:
summary: Update processing configuration for an experiment
description: Update processing configuration for an experiment
operationId: updateProcessingConfig
x-eov-operation-id: experiment#updateProcessingConfig
x-eov-operation-handler: routes/experiment
responses:
'200':
description: Processing configuration for an experiment
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPSuccess'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPError'
'401':
description: The request lacks authentication credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPError'
'404':
description: Not found error.
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPError'

'/experiments':
get:
summary: Get all experiments
Expand Down Expand Up @@ -168,7 +233,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/ExperimentPatch'
$ref: '#/components/schemas/PatchExperiment'
responses:
'200':
description: Create experiment
Expand Down Expand Up @@ -283,6 +348,52 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/HTTPError'
patch:
summary: Patch sample
operationId: patchSample
x-eov-operation-id: sample#patchSample
x-eov-operation-handler: routes/sample
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
additionalProperties: false
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPSuccess'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPError'
'401':
description: The request lacks authentication credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPError'
'403':
description: Forbidden request for this user.
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPError'
'404':
description: Not found error.
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPError'

delete:
summary: Delete sample
operationId: deleteSample
Expand Down Expand Up @@ -371,14 +482,17 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/HTTPError'

components:
schemas:
CreateExperiment:
$ref: './models/experiment-bodies/CreateExperiment.v2.yaml'
ExperimentInfo:
$ref: './models/experiment-bodies/ExperimentInfo.v2.yaml'
ExperimentPatch:
$ref: './models/experiment-bodies/ExperimentPatch.v2.yaml'
PatchExperiment:
$ref: './models/experiment-bodies/PatchExperiment.v2.yaml'
ProcessingConfig:
$ref: './models/experiment-bodies/ProcessingConfig.v2.yaml'
GetAllExperiments:
$ref: './models/experiment-bodies/GetAllExperiments.v2.yaml'
CreateSample:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
title: Experiment Patch
title: Patch Experiment
description: The properties of an experiment that can be patched
type: object
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ required:
- numGenesVsNumUmis
- doubletScores
- dataIntegration
- configureEmbedding
- configureEmbedding
32 changes: 32 additions & 0 deletions tests/api.v2/controllers/experimentController.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,38 @@ describe('experimentController', () => {
expect(experimentInstance.updateSamplePosition).not.toHaveBeenCalled();
});

it('getProcessingConfig works', async () => {
const mockReq = {
params: {
experimentId: mockExperiment.id,
},
};
experimentInstance.getProcessingConfig.mockImplementationOnce(() => Promise.resolve());

await experimentController.getProcessingConfig(mockReq, mockRes);
expect(experimentInstance.getProcessingConfig).toHaveBeenCalledWith(mockExperiment.id);
});

it('updateProcessingConfig works', async () => {
const mockReq = {
params: {
experimentId: mockExperiment.id,
},
body: [{
name: 'classifier',
body: {
someChangedField: 'a value',
},
}],
};
experimentInstance.updateProcessingConfig.mockImplementationOnce(() => Promise.resolve());

await experimentController.updateProcessingConfig(mockReq, mockRes);
expect(experimentInstance.updateProcessingConfig).toHaveBeenCalledWith(
mockExperiment.id, mockReq.body,
);
});

it('getBackendStatus works correctly', async () => {
getPipelineStatus
.mockImplementationOnce(() => Promise.resolve('gem2sStatus'))
Expand Down
18 changes: 18 additions & 0 deletions tests/api.v2/controllers/sampleController.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,22 @@ describe('sampleController', () => {

expect(mockRes.json).not.toHaveBeenCalled();
});

it('patchSample works correctly', async () => {
const mockSampleNewName = 'theNewName';
const mockReq = {
params: { experimentId: mockExperimentId, sampleId: mockSampleId },
body: { name: mockSampleNewName },
};

sampleInstance.updateById.mockImplementationOnce(() => Promise.resolve());

await sampleController.patchSample(mockReq, mockRes);

expect(sampleInstance.updateById).toHaveBeenCalledWith(
mockSampleId, { name: mockSampleNewName },
);

expect(mockRes.json).toHaveBeenCalledWith(OK());
});
});
Loading

0 comments on commit 74d7d43

Please sign in to comment.