Skip to content
This repository was archived by the owner on Jan 14, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 20 additions & 16 deletions app/lib/database/repositories/Repository.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/

const { throwWrapper, NotFoundEntityError } = require('../../utils');
const { QueryBuilder } = require('../utilities');

const nonTransactionalFunctions = new Set(['constructor', 'asT', '_asT'])

Expand Down Expand Up @@ -41,28 +42,32 @@ class Repository {
this.model = model;
}

async count() {
return this.model.count();
async count(queryBuilder = new QueryBuilder()) {
queryBuilder = queryBuilder instanceof QueryBuilder ? queryBuilder : new QueryBuilder(queryBuilder);
return this.model.count(queryBuilder.toImplementation());
}

/**
* Returns all entities.
*
* @param {Object} queryClauses the find query (see sequelize findAll options)
* @param {Object} queryBuilder the find query (see sequelize findAll options)
* @returns {Promise<array>} Promise object representing the full mock data
*/
async findAll(queryClauses = {}) {
return this.model.findAll(queryClauses);
async findAll(queryBuilder = new QueryBuilder()) {
queryBuilder = queryBuilder instanceof QueryBuilder ? queryBuilder : new QueryBuilder(queryBuilder);
return this.model.findAll(queryBuilder.toImplementation());
}

/**
* Returns one entity.
*
* @param {Object} queryClauses the find query (see sequelize findOne options)
* @param {Object} queryBuilder the find query (see sequelize findOne options)
* @returns {Promise<Object>} Promise object representing the full mock data
*/
async findOne(queryClauses = {}) {
return this.model.findOne(queryClauses);
async findOne(queryBuilder = {}) {
queryBuilder = queryBuilder instanceof QueryBuilder ? queryBuilder : new QueryBuilder(queryBuilder);
queryBuilder.add({limit: 1})
return this.model.findOne(queryBuilder.toImplementation());
}

/**
Expand All @@ -84,8 +89,8 @@ class Repository {
* @throws {NotFoundEntityError} if cannot find dbObject with given query clause
* @return {Promise<void>} promise that resolves when the patch has been applied
*/
async findOneAndUpdate(query, patch) {
const entity = await this.model.findOne(query) ??
async findOneAndUpdate(queryBuilder, patch) {
const entity = await this.model.findOne(queryBuilder) ??
throwWrapper(new NotFoundEntityError(`No entity of model ${this.model.name} for clause ${JSON.stringify(query)}`));
await entity.update(patch);
}
Expand All @@ -100,13 +105,12 @@ class Repository {

/**
* Create new object in db
* @param {Object} whereClause
* @param {Object} queryBuilder
*/
async removeOne(whereClause) {
return await this.model.destroy({
limit: 1,
where: whereClause
});
async removeOne(queryBuilder) {
queryBuilder = queryBuilder instanceof QueryBuilder ? queryBuilder : new QueryBuilder(queryBuilder);
queryBuilder.add({limit: 1})
return await this.model.destroy(queryBuilder.toImplementation());
}

_asT(customOptions) {
Expand Down
10 changes: 5 additions & 5 deletions app/lib/database/repositories/RunRepository.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
* or submit itself to any jurisdiction.
*/

const { QueryBuilder } = require("../utilities");
const Repository = require("./Repository");
const deepmerge = require('deepmerge');

/**
* Sequelize implementation of the Repository.
Expand All @@ -24,15 +24,15 @@ class RunRepository extends Repository {
* @param {Object} queryClauses the find query (see sequelize findAll options) or a find query builder
* @returns {Promise<Run[]>} Promise object representing the full mock data
*/
async findAllWithDetectors(queryClauses = {}) {
const baseClause = {
async findAllWithDetectors(queryClauses = new QueryBuilder()) {
const baseClause = new QueryBuilder({
include: [{
model: this.model.sequelize.models.DetectorSubsystem,
raw:true,
required: true,
}],
};
return this.model.findAll(deepmerge(baseClause, queryClauses));
});
return this.model.findAll(baseClause.add(queryClauses).toImplementation());
}
}

Expand Down
46 changes: 46 additions & 0 deletions app/lib/database/utilities/QueryBuilder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* @license
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
* All rights not expressly granted are reserved.
*
* This software is distributed under the terms of the GNU General Public
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
*
* In applying this license CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*/

const { deepmerge } = require('../../utils');
const { filterToSequelizeWhereClause } = require('../../server/utilities');

class QueryBuilder {
constructor(initClauses) {
this.cluasesAccumulator = {...initClauses};
}

addFromHttpRequestQuery({ filter, page, order }) {
this.cluasesAccumulator = deepmerge(this.cluasesAccumulator, {
where: filterToSequelizeWhereClause(filter),
...page,
order: order ? Object.entries(order) : null,
})
return this;
}

add(clause) {
if (clause instanceof QueryBuilder) {
this.cluasesAccumulator = deepmerge(this.cluasesAccumulator, clause.toImplementation())
} else {
this.cluasesAccumulator = deepmerge(this.cluasesAccumulator, clause);
}
return this;
}

toImplementation() {
return this.cluasesAccumulator;
}
}

module.exports = QueryBuilder;
4 changes: 3 additions & 1 deletion app/lib/database/utilities/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
* or submit itself to any jurisdiction.
*/

const PGQueryBuilder = require('./PGQueryBuilder');
const PGQueryBuilder = require('./PGQueryBuilder.js');
const QueryBuilder = require('./QueryBuilder.js');

module.exports = {
PGQueryBuilder,
QueryBuilder,
};
3 changes: 2 additions & 1 deletion app/lib/domain/dtos/stdRequest.dto.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ const stdDataRequestDTO = Joi.object({
page: Joi.object({
limit: Joi.number(),
offset: Joi.number(),
}) }), //TODO make more strict
}),
order: Joi.object({}).unknown(true) }), //TODO make more strict
params: emptyDTO,
body: emptyDTO,
});
Expand Down
30 changes: 12 additions & 18 deletions app/lib/services/dataPasses/DataPassService.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,16 @@ const {
},
} = require('../../database/DatabaseManager');
const { dataPassAdapter } = require('../../database/adapters');
const { filterToSequelizeWhereClause } = require('../../server/utilities');
const { QueryBuilder } = require('../../database/utilities');

class DataPassService {
/**
* Return all data passes,
* @param {Object} query - Filtering query definiton from http request
* @returns {Promise<DataPass[]>} Promise object represents the result of this use case.
*/
async getAll({ filter, page }) {
const periods = await DataPassRepository.findAll({
where: filterToSequelizeWhereClause(filter),
...page,
});
async getAll(query) {
const periods = await DataPassRepository.findAll(new QueryBuilder().addFromHttpRequestQuery(query));
return periods.map((dataPass) => dataPassAdapter.toEntity(dataPass));
}

Expand All @@ -44,14 +41,14 @@ class DataPassService {
* @param {Object} query - Filtering query definiton from http request,... #TODO
* @returns {Promise<DataPass[]>} Promise object represents the result of this use case.
*/
async getDataPassesPerPeriod(periodId, { filter, page }) {
const runs = await DataPassRepository.findAll({
async getDataPassesPerPeriod(periodId, query) {
const baseClause = {
where: {
period_id: periodId,
...filterToSequelizeWhereClause(filter),
},
...page,
});
};

const runs = await DataPassRepository.findAll(new QueryBuilder(baseClause).addFromHttpRequestQuery(query));
return runs.map((dataPass) => dataPassAdapter.toEntity(dataPass));
}

Expand All @@ -61,8 +58,8 @@ class DataPassService {
* @param {Object} query - Filtering query definiton from http request,... #TODO
* @returns {Promise<DataPass[]>} Promise object represents the result of this use case.
*/
async getAnchoredToSimulationPass(simulationPassId, { filter, page }) {
const runs = await DataPassRepository.findAll({
async getAnchoredToSimulationPass(simulationPassId, query) {
const baseClause = {
include: [
{
model: SimulationPass,
Expand All @@ -75,12 +72,9 @@ class DataPassService {
},
},
],
};

where: {
...filterToSequelizeWhereClause(filter),
},
...page,
});
const runs = await DataPassRepository.findAll(new QueryBuilder(baseClause).addFromHttpRequestQuery(query));
return runs.map((dataPass) => dataPassAdapter.toEntity(dataPass));
}
}
Expand Down
11 changes: 5 additions & 6 deletions app/lib/services/periods/PeriodService.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,16 @@ const {
},
} = require('../../database/DatabaseManager');
const { periodAdapter } = require('../../database/adapters');
const { filterToSequelizeWhereClause } = require('../../server/utilities');
const { QueryBuilder } = require('../../database/utilities');

class PeriodService {
/**
* Return all periods
* @param {Object} query - Filtering query definiton from http request,... #TODO
* @returns {Promise<Period[]>} Promise object represents the result of this use case.
*/
async getAll({ filter, page }) {
const periods = await PeriodRepository.findAll({
async getAll(query) {
const baseClause = {
include: [
{
model: BeamType,
Expand All @@ -59,10 +59,9 @@ class PeriodService {
],
],
group: ['Period.id', 'BeamType.id'],
where: filterToSequelizeWhereClause(filter),
subQuery: false,
...page,
});
};
const periods = await PeriodRepository.findAll(new QueryBuilder(baseClause).addFromHttpRequestQuery(query));
return periods.map((period) => periodAdapter.toEntity(period));
}
}
Expand Down
14 changes: 7 additions & 7 deletions app/lib/services/qualityControl/QualityControlService.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,16 @@ const {
},
} = require('../../database/DatabaseManager');
const { qualityControlFlagAdapter } = require('../../database/adapters');
const { filterToSequelizeWhereClause } = require('../../server/utilities');
const { QueryBuilder } = require('../../database/utilities');

class QualityControlService {
/**
* Return All time based qualities / flags in db including their verification
* @param {Object} query - Filtering query definiton from http request,... #TODO
* @returns {Promise<Quality[]>} Promise object represents the result of this use case.
*/
async getAllTimeBasedFlags({ filter, page }) {
const qualityFlags = await QualityControlFlagRepository.findAll({
async getAllTimeBasedFlags(query) {
const baseClause = {
include: [
{
model: DetectorSubsystem,
Expand All @@ -50,9 +50,9 @@ class QualityControlService {
required: false,
},
],
where: filterToSequelizeWhereClause(filter),
...page,
});
};

const qualityFlags = await QualityControlFlagRepository.findAll(new QueryBuilder(baseClause).addFromHttpRequestQuery(query));
return qualityFlags.map((qualityFlags) => qualityControlFlagAdapter.toEntity(qualityFlags));
}

Expand All @@ -71,7 +71,7 @@ class QualityControlService {
* @returns {Promise} Promise object represents the result of this use case.
*/
async deleteTimeBasedQualityControlFlag(id) {
return await QualityControlFlagRepository.T.removeOne({ id });
return await QualityControlFlagRepository.T.removeOne({ where: { id } });
}

/**
Expand Down
Loading