Skip to content

Commit

Permalink
Merge branch 'develop' into feature/DEVSU-2457-update-kbmatches-multi…
Browse files Browse the repository at this point in the history
…ple-variants-per-statement
  • Loading branch information
bnguyen-bcgsc authored Nov 5, 2024
2 parents e467e5e + c5e3691 commit 03c0a6e
Show file tree
Hide file tree
Showing 11 changed files with 501 additions and 1 deletion.
1 change: 1 addition & 0 deletions app/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module.exports = {
protein: 'proteinVariants',
msi: 'msi',
tmb: 'tmburMutationBurden',
sigv: 'signatureVariants',
},
NOTIFICATION_EVENT: {
USER_BOUND: 'userBound',
Expand Down
2 changes: 2 additions & 0 deletions app/models/clearCache.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ module.exports = async (instance, method) => {
return removeKeys(`/reports/${report.ident}/immune-cell-types`);
case 'msi':
return removeKeys(`/reports/${report.ident}/msi`);
case 'signatureVariants':
return removeKeys(`/reports/${report.ident}/signature-variants`);
case 'signatures':
return removeKeys(`/reports/${report.ident}/signatures`);
case 'smallMutations':
Expand Down
10 changes: 10 additions & 0 deletions app/models/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,16 @@ msi.belongsTo(analysisReports, {
as: 'report', foreignKey: 'reportId', targetKey: 'id', onDelete: 'CASCADE', constraints: true,
});

// Signature Variants
const signatureVariants = require('./reports/signatureVariants')(sequelize, Sq);

analysisReports.hasMany(signatureVariants, {
as: 'signatureVariants', foreignKey: 'reportId', targetKey: 'id', onDelete: 'CASCADE', constraints: true,
});
signatureVariants.belongsTo(analysisReports, {
as: 'report', foreignKey: 'reportId', targetKey: 'id', onDelete: 'CASCADE', constraints: true,
});

// Tmbur Mutation Burden
const tmburMutationBurden = require('./reports/tmburMutationBurden')(sequelize, Sq);

Expand Down
57 changes: 57 additions & 0 deletions app/models/reports/signatureVariants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const {DEFAULT_COLUMNS, DEFAULT_REPORT_OPTIONS} = require('../base');

module.exports = (sequelize, Sq) => {
const signatureVariants = sequelize.define('signatureVariants', {
...DEFAULT_COLUMNS,
reportId: {
name: 'reportId',
field: 'report_id',
type: Sq.INTEGER,
references: {
model: 'reports',
key: 'id',
},
},
signatureName: {
name: 'signatureName',
field: 'signature_name',
type: Sq.TEXT,
},
variantTypeName: {
name: 'variantTypeName',
field: 'variant_type_name',
type: Sq.TEXT,
},
displayName: {
name: 'displayName',
field: 'display_name',
type: Sq.TEXT,
},
}, {
...DEFAULT_REPORT_OPTIONS,
tableName: 'reports_signature_variants',
scopes: {
public: {
attributes: {
exclude: ['id', 'reportId', 'deletedAt', 'updatedBy'],
},
},
extended: {
attributes: {
exclude: ['id', 'reportId', 'deletedAt', 'updatedBy'],
},
},
},
});

// set instance methods
signatureVariants.prototype.view = function (scope) {
if (scope === 'public') {
const {id, reportId, deletedAt, updatedBy, ...publicView} = this.dataValues;
return publicView;
}
return this;
};

return signatureVariants;
};
2 changes: 2 additions & 0 deletions app/routes/report/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const comparators = require('./comparators');
const patientInformation = require('./patientInformation');
const images = require('./image');
const msi = require('./msi');
const signatureVariants = require('./signatureVariants');
const reportUser = require('./reportUser');
const variants = require('./variants');

Expand Down Expand Up @@ -59,6 +60,7 @@ router.use('/genes', gene);
router.use('/sample-info', sampleInfo);
router.use('/patient-information', patientInformation);
router.use('/msi', msi);
router.use('/signature-variants', signatureVariants);
router.use('/user', reportUser);
router.use('/variants', variants);
router.use('/protein-variants', proteinVariants);
Expand Down
132 changes: 132 additions & 0 deletions app/routes/report/signatureVariants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
const HTTP_STATUS = require('http-status-codes');
const express = require('express');

const router = express.Router({mergeParams: true});

const db = require('../../models');
const logger = require('../../log');
const cache = require('../../cache');

const schemaGenerator = require('../../schemas/schemaGenerator');
const validateAgainstSchema = require('../../libs/validateAgainstSchema');
const {REPORT_CREATE_BASE_URI, REPORT_UPDATE_BASE_URI} = require('../../constants');

// Generate schema's
const createSchema = schemaGenerator(db.models.signatureVariants, {
baseUri: REPORT_CREATE_BASE_URI,
});
const updateSchema = schemaGenerator(db.models.signatureVariants, {
baseUri: REPORT_UPDATE_BASE_URI, nothingRequired: true,
});

// Middleware for signatureVariants
router.param('sigv', async (req, res, next, ident) => {
let result;
try {
result = await db.models.signatureVariants.findOne({
where: {ident, reportId: req.report.id},
});
} catch (error) {
logger.error(`Unable to lookup signatureVariants data error: ${error}`);
return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({error: {message: 'Unable to lookup signatureVariants data'}});
}

if (!result) {
logger.error(`Unable to find signatureVariants data for ${req.report.ident}`);
return res.status(HTTP_STATUS.NOT_FOUND).json({error: {message: `Unable to find signatureVariants data for ${req.report.ident}`}});
}

// Add signatureVariants data to request
req.sigv = result;
return next();
});

// Handle requests for signatureVariants by ident
router.route('/:sigv([A-z0-9-]{36})')
.get((req, res) => {
return res.json(req.sigv.view('public'));
})
.put(async (req, res) => {
// Validate request against schema
try {
validateAgainstSchema(updateSchema, req.body, false);
} catch (error) {
const message = `Error while validating signatureVariants update request ${error}`;
logger.error(message);
return res.status(HTTP_STATUS.BAD_REQUEST).json({error: {message}});
}
// Update db entry
try {
await req.sigv.update(req.body, {userId: req.user.id});
return res.json(req.sigv.view('public'));
} catch (error) {
logger.error(`Unable to update signatureVariants data ${error}`);
return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({error: {message: 'Unable to update signatureVariants data'}});
}
})
.delete(async (req, res) => {
// Soft delete the entry
try {
await req.sigv.destroy();
return res.status(HTTP_STATUS.NO_CONTENT).send();
} catch (error) {
logger.error(`Unable to remove signatureVariants data ${error}`);
return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({error: {message: 'Unable to remove signatureVariants data'}});
}
});

// Handle requests for SIGV's
router.route('/')
.get(async (req, res) => {
const key = `/reports/${req.report.ident}/signature-variants`;

try {
const cacheResults = await cache.get(key);

if (cacheResults) {
res.type('json');
return res.send(cacheResults);
}
} catch (error) {
logger.error(`Error while checking cache for signatureVariants data ${error}`);
}

try {
const results = await db.models.signatureVariants.scope('public').findAll({
where: {reportId: req.report.id},
});

if (key) {
cache.set(key, JSON.stringify(results), 'EX', 14400);
}

return res.json(results);
} catch (error) {
logger.error(`Unable to lookup signatureVariants for report ${req.report.ident} error: ${error}`);
return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({error: {message: `Unable to lookup the signatureVariants for ${req.report.ident}`}});
}
})
.post(async (req, res) => {
// Validate request against schema
try {
await validateAgainstSchema(createSchema, req.body);
} catch (error) {
const message = `Error while validating signatureVariants create request ${error}`;
logger.error(message);
return res.status(HTTP_STATUS.BAD_REQUEST).json({error: {message}});
}

// Create new entry in db
try {
const result = await db.models.signatureVariants.create({
...req.body,
reportId: req.report.id,
});
return res.status(HTTP_STATUS.CREATED).json(result.view('public'));
} catch (error) {
logger.error(`Unable to create signatureVariants ${error}`);
return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({error: {message: 'Unable to create signatureVariants'}});
}
});

module.exports = router;
11 changes: 11 additions & 0 deletions app/schemas/report/reportUpload/variant.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ const generateVariantUploadSchemas = (isJsonSchema) => {
isSubSchema: true,
});

variantSchemas.signatureVariants = schemaGenerator(db.models.signatureVariants, {
isJsonSchema,
baseUri: UPLOAD_BASE_URI,
properties: {
key: {
type: 'string', description: 'Unique identifier for this variant within this section used to link it to kb-matches',
},
},
isSubSchema: true,
});

variantSchemas.tmburMutationBurden = schemaGenerator(db.models.tmburMutationBurden, {
isJsonSchema,
baseUri: UPLOAD_BASE_URI,
Expand Down
9 changes: 9 additions & 0 deletions migrations/20241022233039-DEVSU-2458-add-new-variant-type.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
up: async (queryInterface) => {
queryInterface.sequelize.query('ALTER TYPE enum_reports_kb_matches_variant_type ADD VALUE \'sigv\'');
},

down: async () => {
throw new Error('Not Implemented!');
},
};
41 changes: 41 additions & 0 deletions migrations/20241023001234-DEVSU-2458-add-new-table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const TABLE = 'reports_signature_variants';
const {DEFAULT_COLUMNS} = require('../app/models/base');

module.exports = {
up: (queryInterface, Sq) => {
// Create new notifications tables
return queryInterface.sequelize.transaction(async (transaction) => {
await queryInterface.createTable(TABLE, {
...DEFAULT_COLUMNS,
reportId: {
name: 'reportId',
field: 'report_id',
type: Sq.INTEGER,
references: {
model: 'reports',
key: 'id',
},
},
signatureName: {
name: 'signatureName',
field: 'signature_name',
type: Sq.TEXT,
},
variantTypeName: {
name: 'variantTypeName',
field: 'variant_type_name',
type: Sq.TEXT,
},
displayName: {
name: 'displayName',
field: 'display_name',
type: Sq.TEXT,
},
}, {transaction});
});
},

down: () => {
throw new Error('Not Implemented!');
},
};
Loading

0 comments on commit 03c0a6e

Please sign in to comment.