From bb5a9c3845fe2de0ed76e2c584314b634529c551 Mon Sep 17 00:00:00 2001 From: Isaac Hill <71404865+isaachilly@users.noreply.github.com> Date: Thu, 5 Mar 2026 14:51:18 +0100 Subject: [PATCH 01/13] [O2B-1545] Add GAQ summary models, adapters and migration --- lib/database/adapters/GaqSummaryAdapter.js | 56 +++++++++++++ .../adapters/GaqSummaryInvalidationAdapter.js | 46 +++++++++++ lib/database/adapters/index.js | 6 ++ ...0260223120000-create-gaq-summary-tables.js | 82 +++++++++++++++++++ lib/database/models/gaqSummary.js | 52 ++++++++++++ lib/database/models/gaqSummaryInvalidation.js | 37 +++++++++ lib/database/models/index.js | 4 + 7 files changed, 283 insertions(+) create mode 100644 lib/database/adapters/GaqSummaryAdapter.js create mode 100644 lib/database/adapters/GaqSummaryInvalidationAdapter.js create mode 100644 lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js create mode 100644 lib/database/models/gaqSummary.js create mode 100644 lib/database/models/gaqSummaryInvalidation.js diff --git a/lib/database/adapters/GaqSummaryAdapter.js b/lib/database/adapters/GaqSummaryAdapter.js new file mode 100644 index 0000000000..f069b0bfa7 --- /dev/null +++ b/lib/database/adapters/GaqSummaryAdapter.js @@ -0,0 +1,56 @@ +/** + * @license + * Copyright CERN and copyright holders of ALICE O2. This software is + * distributed under the terms of the GNU General Public License v3 (GPL + * Version 3), copied verbatim in the file "COPYING". + * + * See http://alice-o2.web.cern.ch/license for full licensing information. + * + * 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. + */ + +/** + * GaqSummaryAdapter + */ +class GaqSummaryAdapter { + /** + * Constructor + */ + constructor() { + this.toEntity = this.toEntity.bind(this); + } + + /** + * Converts the given database object to an entity object. + * + * @param {SequelizeGaqSummary} databaseObject Object to convert. + * @returns {GaqSummary} Converted entity object. + */ + toEntity(databaseObject) { + const { + dataPassId, + runNumber, + badEffectiveRunCoverage, + explicitlyNotBadEffectiveRunCoverage, + mcReproducible, + missingVerificationsCount, + undefinedQualityPeriodsCount, + computedAt, + } = databaseObject; + + return { + dataPassId, + runNumber, + badEffectiveRunCoverage, + explicitlyNotBadEffectiveRunCoverage, + mcReproducible, + missingVerificationsCount, + undefinedQualityPeriodsCount, + computedAt, + }; + } +} + +module.exports = { GaqSummaryAdapter }; diff --git a/lib/database/adapters/GaqSummaryInvalidationAdapter.js b/lib/database/adapters/GaqSummaryInvalidationAdapter.js new file mode 100644 index 0000000000..63d3ebce73 --- /dev/null +++ b/lib/database/adapters/GaqSummaryInvalidationAdapter.js @@ -0,0 +1,46 @@ +/** + * @license + * Copyright CERN and copyright holders of ALICE O2. This software is + * distributed under the terms of the GNU General Public License v3 (GPL + * Version 3), copied verbatim in the file "COPYING". + * + * See http://alice-o2.web.cern.ch/license for full licensing information. + * + * 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. + */ + +/** + * GaqSummaryInvalidationAdapter + */ +class GaqSummaryInvalidationAdapter { + /** + * Constructor + */ + constructor() { + this.toEntity = this.toEntity.bind(this); + } + + /** + * Converts the given database object to an entity object. + * + * @param {SequelizeGaqSummaryInvalidation} databaseObject Object to convert. + * @returns {GaqSummaryInvalidation} Converted entity object. + */ + toEntity(databaseObject) { + const { + dataPassId, + runNumber, + invalidatedAt, + } = databaseObject; + + return { + dataPassId, + runNumber, + invalidatedAt, + }; + } +} + +module.exports = { GaqSummaryInvalidationAdapter }; diff --git a/lib/database/adapters/index.js b/lib/database/adapters/index.js index 5ff6404b3d..97d22b927f 100644 --- a/lib/database/adapters/index.js +++ b/lib/database/adapters/index.js @@ -27,6 +27,8 @@ const EorReasonAdapter = require('./EorReasonAdapter'); const FlpRoleAdapter = require('./FlpRoleAdapter'); const { HostAdapter } = require('./HostAdapter.js'); const { GaqDetectorAdapter } = require('./GaqDetectorAdapter.js'); +const { GaqSummaryAdapter } = require('./GaqSummaryAdapter.js'); +const { GaqSummaryInvalidationAdapter } = require('./GaqSummaryInvalidationAdapter.js'); const { LhcFillAdapter } = require('./LhcFillAdapter.js'); const { LhcFillStatisticsAdapter } = require('./LhcFillStatisticsAdapter.js'); const LhcPeriodAdapter = require('./LhcPeriodAdapter'); @@ -63,6 +65,8 @@ const environmentHistoryItemAdapter = new EnvironmentHistoryItemAdapter(); const eorReasonAdapter = new EorReasonAdapter(); const flpRoleAdapter = new FlpRoleAdapter(); const gaqDetectorAdapter = new GaqDetectorAdapter(); +const gaqSummaryAdapter = new GaqSummaryAdapter(); +const gaqSummaryInvalidationAdapter = new GaqSummaryInvalidationAdapter(); const hostAdapter = new HostAdapter(); const lhcFillAdapter = new LhcFillAdapter(); const lhcFillStatisticsAdapter = new LhcFillStatisticsAdapter(); @@ -159,6 +163,8 @@ module.exports = { eorReasonAdapter, flpRoleAdapter, gaqDetectorAdapter, + gaqSummaryAdapter, + gaqSummaryInvalidationAdapter, hostAdapter, lhcFillAdapter, lhcFillStatisticsAdapter, diff --git a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js new file mode 100644 index 0000000000..9ead5d5f32 --- /dev/null +++ b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js @@ -0,0 +1,82 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + up: async (queryInterface, Sequelize) => queryInterface.sequelize.transaction(async (transaction) => { + await queryInterface.createTable('gaq_summaries', { + data_pass_id: { + type: Sequelize.INTEGER, + primaryKey: true, + allowNull: false, + references: { + model: 'data_passes', + key: 'id', + }, + }, + run_number: { + type: Sequelize.INTEGER, + primaryKey: true, + allowNull: false, + references: { + model: 'runs', + key: 'run_number', + }, + }, + bad_effective_run_coverage: { + type: Sequelize.FLOAT, + allowNull: false, + }, + explicitly_not_bad_effective_run_coverage: { + type: Sequelize.FLOAT, + allowNull: false, + }, + mc_reproducible: { + type: Sequelize.BOOLEAN, + allowNull: false, + }, + missing_verifications_count: { + type: Sequelize.INTEGER, + allowNull: false, + }, + undefined_quality_periods_count: { + type: Sequelize.INTEGER, + allowNull: false, + }, + computed_at: { + type: Sequelize.DATE(3), + allowNull: false, + }, + }, { transaction }); + + await queryInterface.createTable('gaq_summary_invalidations', { + data_pass_id: { + type: Sequelize.INTEGER, + primaryKey: true, + allowNull: false, + references: { + model: 'data_passes', + key: 'id', + }, + }, + run_number: { + type: Sequelize.INTEGER, + primaryKey: true, + allowNull: false, + references: { + model: 'runs', + key: 'run_number', + }, + }, + invalidated_at: { + type: Sequelize.DATE(3), + allowNull: false, + defaultValue: Sequelize.literal('CURRENT_TIMESTAMP(3)'), + }, + }, { transaction }); + }), + + down: async (queryInterface) => queryInterface.sequelize.transaction(async (transaction) => { + await queryInterface.dropTable('gaq_summary_invalidations', { transaction }); + await queryInterface.dropTable('gaq_summaries', { transaction }); + }), +}; diff --git a/lib/database/models/gaqSummary.js b/lib/database/models/gaqSummary.js new file mode 100644 index 0000000000..80e21f0145 --- /dev/null +++ b/lib/database/models/gaqSummary.js @@ -0,0 +1,52 @@ +/** + * @license + * Copyright CERN and copyright holders of ALICE O2. This software is + * distributed under the terms of the GNU General Public License v3 (GPL + * Version 3), copied verbatim in the file "COPYING". + * + * See http://alice-o2.web.cern.ch/license for full licensing information. + * + * 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. + */ + +module.exports = (sequelize) => { + const Sequelize = require('sequelize'); + + const GaqSummary = sequelize.define('GaqSummary', { + dataPassId: { + type: Sequelize.INTEGER, + }, + runNumber: { + type: Sequelize.INTEGER, + }, + badEffectiveRunCoverage: { + type: Sequelize.FLOAT, + }, + explicitlyNotBadEffectiveRunCoverage: { + type: Sequelize.FLOAT, + }, + mcReproducible: { + type: Sequelize.BOOLEAN, + }, + missingVerificationsCount: { + type: Sequelize.INTEGER, + }, + undefinedQualityPeriodsCount: { + type: Sequelize.INTEGER, + }, + computedAt: { + type: Sequelize.DATE(3), + }, + }, { tableName: 'gaq_summaries' }); + + GaqSummary.removeAttribute('id'); + + GaqSummary.associate = (models) => { + GaqSummary.belongsTo(models.Run, { foreignKey: 'runNumber', as: 'run' }); + GaqSummary.belongsTo(models.DataPass, { foreignKey: 'dataPassId', as: 'dataPass' }); + }; + + return GaqSummary; +}; diff --git a/lib/database/models/gaqSummaryInvalidation.js b/lib/database/models/gaqSummaryInvalidation.js new file mode 100644 index 0000000000..f99b5d0895 --- /dev/null +++ b/lib/database/models/gaqSummaryInvalidation.js @@ -0,0 +1,37 @@ +/** + * @license + * Copyright CERN and copyright holders of ALICE O2. This software is + * distributed under the terms of the GNU General Public License v3 (GPL + * Version 3), copied verbatim in the file "COPYING". + * + * See http://alice-o2.web.cern.ch/license for full licensing information. + * + * 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. + */ + +module.exports = (sequelize) => { + const Sequelize = require('sequelize'); + + const GaqSummaryInvalidation = sequelize.define('GaqSummaryInvalidation', { + dataPassId: { + type: Sequelize.INTEGER, + }, + runNumber: { + type: Sequelize.INTEGER, + }, + invalidatedAt: { + type: Sequelize.DATE(3), + }, + }, { tableName: 'gaq_summary_invalidations' }); + + GaqSummaryInvalidation.removeAttribute('id'); + + GaqSummaryInvalidation.associate = (models) => { + GaqSummaryInvalidation.belongsTo(models.Run, { foreignKey: 'runNumber', as: 'run' }); + GaqSummaryInvalidation.belongsTo(models.DataPass, { foreignKey: 'dataPassId', as: 'dataPass' }); + }; + + return GaqSummaryInvalidation; +}; diff --git a/lib/database/models/index.js b/lib/database/models/index.js index 87d793fac3..36736ce905 100644 --- a/lib/database/models/index.js +++ b/lib/database/models/index.js @@ -27,6 +27,8 @@ const EorReason = require('./eorreason'); const EpnRoleSession = require('./epnrolesession'); const FlpRole = require('./flprole'); const GaqDetector = require('./gaqDetector.js'); +const GaqSummary = require('./gaqSummary.js'); +const GaqSummaryInvalidation = require('./gaqSummaryInvalidation.js'); const Host = require('./host.js'); const LhcFill = require('./lhcFill'); const LhcFillStatistics = require('./lhcFillStatistics.js'); @@ -66,6 +68,8 @@ module.exports = (sequelize) => { EpnRoleSessionkey: EpnRoleSession(sequelize), FlpRole: FlpRole(sequelize), GaqDetector: GaqDetector(sequelize), + GaqSummary: GaqSummary(sequelize), + GaqSummaryInvalidation: GaqSummaryInvalidation(sequelize), Host: Host(sequelize), LhcFill: LhcFill(sequelize), LhcFillStatistics: LhcFillStatistics(sequelize), From 4fade0f12b6ac96baa67f298431e7025cafd7cca Mon Sep 17 00:00:00 2001 From: Isaac Hill <71404865+isaachilly@users.noreply.github.com> Date: Mon, 16 Mar 2026 16:08:20 +0100 Subject: [PATCH 02/13] [O2B-1545] Add GAQ summary repositories and timestamps Add GaqSummaryRepository and GaqSummaryInvalidationRepository and export them from the repositories index. Update migration to replace the previous invalidated_at field with created_at and add updated_at to mirror default Sequelize tables. --- .../adapters/GaqSummaryInvalidationAdapter.js | 6 ++-- ...0260223120000-create-gaq-summary-tables.js | 7 +++- lib/database/models/gaqSummaryInvalidation.js | 3 -- .../GaqSummaryInvalidationRepository.js | 33 +++++++++++++++++++ .../repositories/GaqSummaryRepository.js | 33 +++++++++++++++++++ lib/database/repositories/index.js | 4 +++ 6 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 lib/database/repositories/GaqSummaryInvalidationRepository.js create mode 100644 lib/database/repositories/GaqSummaryRepository.js diff --git a/lib/database/adapters/GaqSummaryInvalidationAdapter.js b/lib/database/adapters/GaqSummaryInvalidationAdapter.js index 63d3ebce73..dbd76df3a8 100644 --- a/lib/database/adapters/GaqSummaryInvalidationAdapter.js +++ b/lib/database/adapters/GaqSummaryInvalidationAdapter.js @@ -32,13 +32,15 @@ class GaqSummaryInvalidationAdapter { const { dataPassId, runNumber, - invalidatedAt, + createdAt, + updatedAt, } = databaseObject; return { dataPassId, runNumber, - invalidatedAt, + createdAt, + updatedAt, }; } } diff --git a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js index 9ead5d5f32..7f08357a89 100644 --- a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js +++ b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js @@ -67,11 +67,16 @@ module.exports = { key: 'run_number', }, }, - invalidated_at: { + created_at: { type: Sequelize.DATE(3), allowNull: false, defaultValue: Sequelize.literal('CURRENT_TIMESTAMP(3)'), }, + updated_at: { + type: Sequelize.DATE(3), + allowNull: false, + defaultValue: Sequelize.literal('CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)'), + }, }, { transaction }); }), diff --git a/lib/database/models/gaqSummaryInvalidation.js b/lib/database/models/gaqSummaryInvalidation.js index f99b5d0895..3c0944b9bc 100644 --- a/lib/database/models/gaqSummaryInvalidation.js +++ b/lib/database/models/gaqSummaryInvalidation.js @@ -21,9 +21,6 @@ module.exports = (sequelize) => { runNumber: { type: Sequelize.INTEGER, }, - invalidatedAt: { - type: Sequelize.DATE(3), - }, }, { tableName: 'gaq_summary_invalidations' }); GaqSummaryInvalidation.removeAttribute('id'); diff --git a/lib/database/repositories/GaqSummaryInvalidationRepository.js b/lib/database/repositories/GaqSummaryInvalidationRepository.js new file mode 100644 index 0000000000..c6608f9e83 --- /dev/null +++ b/lib/database/repositories/GaqSummaryInvalidationRepository.js @@ -0,0 +1,33 @@ +/** + * @license + * Copyright CERN and copyright holders of ALICE O2. This software is + * distributed under the terms of the GNU General Public License v3 (GPL + * Version 3), copied verbatim in the file "COPYING". + * + * See http://alice-o2.web.cern.ch/license for full licensing information. + * + * 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 { + models: { + GaqSummaryInvalidation, + }, +} = require('..'); +const Repository = require('./Repository'); + +/** + * GaqSummaryInvalidation repository + */ +class GaqSummaryInvalidationRepository extends Repository { + /** + * Creates a new `GaqSummaryInvalidationRepository` instance. + */ + constructor() { + super(GaqSummaryInvalidation); + } +} + +module.exports = new GaqSummaryInvalidationRepository(); diff --git a/lib/database/repositories/GaqSummaryRepository.js b/lib/database/repositories/GaqSummaryRepository.js new file mode 100644 index 0000000000..98986de513 --- /dev/null +++ b/lib/database/repositories/GaqSummaryRepository.js @@ -0,0 +1,33 @@ +/** + * @license + * Copyright CERN and copyright holders of ALICE O2. This software is + * distributed under the terms of the GNU General Public License v3 (GPL + * Version 3), copied verbatim in the file "COPYING". + * + * See http://alice-o2.web.cern.ch/license for full licensing information. + * + * 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 { + models: { + GaqSummary, + }, +} = require('..'); +const Repository = require('./Repository'); + +/** + * GaqSummary repository + */ +class GaqSummaryRepository extends Repository { + /** + * Creates a new `GaqSummaryRepository` instance. + */ + constructor() { + super(GaqSummary); + } +} + +module.exports = new GaqSummaryRepository(); diff --git a/lib/database/repositories/index.js b/lib/database/repositories/index.js index 0c79279752..417ccd5375 100644 --- a/lib/database/repositories/index.js +++ b/lib/database/repositories/index.js @@ -27,6 +27,8 @@ const EnvironmentRepository = require('./EnvironmentRepository'); const EorReasonRepository = require('./EorReasonRepository'); const FlpRoleRepository = require('./FlpRoleRepository'); const GaqDetectorRepository = require('./GaqDetectorRepository.js'); +const GaqSummaryInvalidationRepository = require('./GaqSummaryInvalidationRepository.js'); +const GaqSummaryRepository = require('./GaqSummaryRepository.js'); const HostRepository = require('./HostRepository.js'); const LhcFillRepository = require('./LhcFillRepository'); const LhcFillStatisticsRepository = require('./LhcFillStatisticsRepository.js'); @@ -70,6 +72,8 @@ module.exports = { EorReasonRepository, FlpRoleRepository, GaqDetectorRepository, + GaqSummaryInvalidationRepository, + GaqSummaryRepository, HostRepository, LhcFillRepository, LhcFillStatisticsRepository, From 15afdaac85826129a0b127db26be1a3d355c5fdf Mon Sep 17 00:00:00 2001 From: Isaac Hill <71404865+isaachilly@users.noreply.github.com> Date: Tue, 17 Mar 2026 10:15:14 +0100 Subject: [PATCH 03/13] [O2B-1545] Use default Sequelize createdAt/updatedAt instead of computedAt --- lib/database/adapters/GaqSummaryAdapter.js | 6 ++++-- .../v1/20260223120000-create-gaq-summary-tables.js | 8 +++++++- lib/database/models/gaqSummary.js | 3 --- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/database/adapters/GaqSummaryAdapter.js b/lib/database/adapters/GaqSummaryAdapter.js index f069b0bfa7..88d7394126 100644 --- a/lib/database/adapters/GaqSummaryAdapter.js +++ b/lib/database/adapters/GaqSummaryAdapter.js @@ -37,7 +37,8 @@ class GaqSummaryAdapter { mcReproducible, missingVerificationsCount, undefinedQualityPeriodsCount, - computedAt, + createdAt, + updatedAt, } = databaseObject; return { @@ -48,7 +49,8 @@ class GaqSummaryAdapter { mcReproducible, missingVerificationsCount, undefinedQualityPeriodsCount, - computedAt, + createdAt, + updatedAt, }; } } diff --git a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js index 7f08357a89..1e404d3645 100644 --- a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js +++ b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js @@ -42,9 +42,15 @@ module.exports = { type: Sequelize.INTEGER, allowNull: false, }, - computed_at: { + created_at: { type: Sequelize.DATE(3), allowNull: false, + defaultValue: Sequelize.literal('CURRENT_TIMESTAMP(3)'), + }, + updated_at: { + type: Sequelize.DATE(3), + allowNull: false, + defaultValue: Sequelize.literal('CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)'), }, }, { transaction }); diff --git a/lib/database/models/gaqSummary.js b/lib/database/models/gaqSummary.js index 80e21f0145..55b33b3521 100644 --- a/lib/database/models/gaqSummary.js +++ b/lib/database/models/gaqSummary.js @@ -36,9 +36,6 @@ module.exports = (sequelize) => { undefinedQualityPeriodsCount: { type: Sequelize.INTEGER, }, - computedAt: { - type: Sequelize.DATE(3), - }, }, { tableName: 'gaq_summaries' }); GaqSummary.removeAttribute('id'); From 363f09bed1b972877e491ca6f5c7a224617b8392 Mon Sep 17 00:00:00 2001 From: Isaac Hill <71404865+isaachilly@users.noreply.github.com> Date: Tue, 17 Mar 2026 17:03:35 +0100 Subject: [PATCH 04/13] [O2B-1545] Use mcReproducibleCoverage float instead of boolean Rename and change mcReproducible to be the coverage float not the boolean. --- lib/database/adapters/GaqSummaryAdapter.js | 4 ++-- .../migrations/v1/20260223120000-create-gaq-summary-tables.js | 4 ++-- lib/database/models/gaqSummary.js | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/database/adapters/GaqSummaryAdapter.js b/lib/database/adapters/GaqSummaryAdapter.js index 88d7394126..fd9ba4aa0e 100644 --- a/lib/database/adapters/GaqSummaryAdapter.js +++ b/lib/database/adapters/GaqSummaryAdapter.js @@ -34,7 +34,7 @@ class GaqSummaryAdapter { runNumber, badEffectiveRunCoverage, explicitlyNotBadEffectiveRunCoverage, - mcReproducible, + mcReproducibleCoverage, missingVerificationsCount, undefinedQualityPeriodsCount, createdAt, @@ -46,7 +46,7 @@ class GaqSummaryAdapter { runNumber, badEffectiveRunCoverage, explicitlyNotBadEffectiveRunCoverage, - mcReproducible, + mcReproducibleCoverage, missingVerificationsCount, undefinedQualityPeriodsCount, createdAt, diff --git a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js index 1e404d3645..8122607a37 100644 --- a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js +++ b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js @@ -30,8 +30,8 @@ module.exports = { type: Sequelize.FLOAT, allowNull: false, }, - mc_reproducible: { - type: Sequelize.BOOLEAN, + mc_reproducible_coverage: { + type: Sequelize.FLOAT, allowNull: false, }, missing_verifications_count: { diff --git a/lib/database/models/gaqSummary.js b/lib/database/models/gaqSummary.js index 55b33b3521..de91be13f2 100644 --- a/lib/database/models/gaqSummary.js +++ b/lib/database/models/gaqSummary.js @@ -30,6 +30,9 @@ module.exports = (sequelize) => { mcReproducible: { type: Sequelize.BOOLEAN, }, + mcReproducibleCoverage: { + type: Sequelize.FLOAT, + }, missingVerificationsCount: { type: Sequelize.INTEGER, }, From 002f3012a18f31ebaff85827935529156ce2909f Mon Sep 17 00:00:00 2001 From: Isaac Hill <71404865+isaachilly@users.noreply.github.com> Date: Tue, 17 Mar 2026 17:49:41 +0100 Subject: [PATCH 05/13] [O2B-1545] Remove mcReproducible field Forgot to remove. --- lib/database/models/gaqSummary.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/database/models/gaqSummary.js b/lib/database/models/gaqSummary.js index de91be13f2..f3338e5557 100644 --- a/lib/database/models/gaqSummary.js +++ b/lib/database/models/gaqSummary.js @@ -27,9 +27,6 @@ module.exports = (sequelize) => { explicitlyNotBadEffectiveRunCoverage: { type: Sequelize.FLOAT, }, - mcReproducible: { - type: Sequelize.BOOLEAN, - }, mcReproducibleCoverage: { type: Sequelize.FLOAT, }, From 16d3563ef0813e8c10de405ef7d9cda50eed8b3c Mon Sep 17 00:00:00 2001 From: Isaac Hill <71404865+isaachilly@users.noreply.github.com> Date: Wed, 18 Mar 2026 16:34:34 +0100 Subject: [PATCH 06/13] [O2B-1545] Rename GAQ summary coverage fields --- lib/database/adapters/GaqSummaryAdapter.js | 8 ++++---- .../v1/20260223120000-create-gaq-summary-tables.js | 4 ++-- lib/database/models/gaqSummary.js | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/database/adapters/GaqSummaryAdapter.js b/lib/database/adapters/GaqSummaryAdapter.js index fd9ba4aa0e..77ff939d69 100644 --- a/lib/database/adapters/GaqSummaryAdapter.js +++ b/lib/database/adapters/GaqSummaryAdapter.js @@ -32,8 +32,8 @@ class GaqSummaryAdapter { const { dataPassId, runNumber, - badEffectiveRunCoverage, - explicitlyNotBadEffectiveRunCoverage, + badRunCoverage, + explicitlyNotBadRunCoverage, mcReproducibleCoverage, missingVerificationsCount, undefinedQualityPeriodsCount, @@ -44,8 +44,8 @@ class GaqSummaryAdapter { return { dataPassId, runNumber, - badEffectiveRunCoverage, - explicitlyNotBadEffectiveRunCoverage, + badRunCoverage, + explicitlyNotBadRunCoverage, mcReproducibleCoverage, missingVerificationsCount, undefinedQualityPeriodsCount, diff --git a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js index 8122607a37..b734f32e32 100644 --- a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js +++ b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js @@ -22,11 +22,11 @@ module.exports = { key: 'run_number', }, }, - bad_effective_run_coverage: { + bad_run_coverage: { type: Sequelize.FLOAT, allowNull: false, }, - explicitly_not_bad_effective_run_coverage: { + explicitly_not_bad_run_coverage: { type: Sequelize.FLOAT, allowNull: false, }, diff --git a/lib/database/models/gaqSummary.js b/lib/database/models/gaqSummary.js index f3338e5557..480a9a4943 100644 --- a/lib/database/models/gaqSummary.js +++ b/lib/database/models/gaqSummary.js @@ -21,10 +21,10 @@ module.exports = (sequelize) => { runNumber: { type: Sequelize.INTEGER, }, - badEffectiveRunCoverage: { + badRunCoverage: { type: Sequelize.FLOAT, }, - explicitlyNotBadEffectiveRunCoverage: { + explicitlyNotBadRunCoverage: { type: Sequelize.FLOAT, }, mcReproducibleCoverage: { From c2ccbd476f83ce5ffb60097db8d1f373c61812b5 Mon Sep 17 00:00:00 2001 From: Isaac Hill <71404865+isaachilly@users.noreply.github.com> Date: Fri, 17 Apr 2026 15:52:40 +0200 Subject: [PATCH 07/13] Add calculationFailed to GAQ summaries Add a calculation_failed boolean column to gaq_summaries. This allows us to know whether a summary has been attempted to be calculated but unsuccessful due to limited data etc. --- lib/database/adapters/GaqSummaryAdapter.js | 2 ++ .../v1/20260223120000-create-gaq-summary-tables.js | 5 +++++ lib/database/models/gaqSummary.js | 3 +++ 3 files changed, 10 insertions(+) diff --git a/lib/database/adapters/GaqSummaryAdapter.js b/lib/database/adapters/GaqSummaryAdapter.js index 77ff939d69..21cd7b7004 100644 --- a/lib/database/adapters/GaqSummaryAdapter.js +++ b/lib/database/adapters/GaqSummaryAdapter.js @@ -37,6 +37,7 @@ class GaqSummaryAdapter { mcReproducibleCoverage, missingVerificationsCount, undefinedQualityPeriodsCount, + calculationFailed, createdAt, updatedAt, } = databaseObject; @@ -49,6 +50,7 @@ class GaqSummaryAdapter { mcReproducibleCoverage, missingVerificationsCount, undefinedQualityPeriodsCount, + calculationFailed, createdAt, updatedAt, }; diff --git a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js index b734f32e32..3a787b02e7 100644 --- a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js +++ b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js @@ -42,6 +42,11 @@ module.exports = { type: Sequelize.INTEGER, allowNull: false, }, + calculation_failed: { + type: Sequelize.BOOLEAN, + allowNull: false, + defaultValue: false, + }, created_at: { type: Sequelize.DATE(3), allowNull: false, diff --git a/lib/database/models/gaqSummary.js b/lib/database/models/gaqSummary.js index 480a9a4943..aab9a04dfd 100644 --- a/lib/database/models/gaqSummary.js +++ b/lib/database/models/gaqSummary.js @@ -36,6 +36,9 @@ module.exports = (sequelize) => { undefinedQualityPeriodsCount: { type: Sequelize.INTEGER, }, + calculationFailed: { + type: Sequelize.BOOLEAN, + }, }, { tableName: 'gaq_summaries' }); GaqSummary.removeAttribute('id'); From 35112e5e34b7c8f75240e086dd1cd100abc395da Mon Sep 17 00:00:00 2001 From: Isaac Hill <71404865+isaachilly@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:15:47 +0200 Subject: [PATCH 08/13] [O2B-1545] Make GAQ summary columns nullable Remove not-null constraints from several GAQ summary columns in the migration to allow NULL when values are unavailable. --- .../v1/20260223120000-create-gaq-summary-tables.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js index 3a787b02e7..4540a01c4a 100644 --- a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js +++ b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js @@ -24,23 +24,18 @@ module.exports = { }, bad_run_coverage: { type: Sequelize.FLOAT, - allowNull: false, }, explicitly_not_bad_run_coverage: { type: Sequelize.FLOAT, - allowNull: false, }, mc_reproducible_coverage: { type: Sequelize.FLOAT, - allowNull: false, }, missing_verifications_count: { type: Sequelize.INTEGER, - allowNull: false, }, undefined_quality_periods_count: { type: Sequelize.INTEGER, - allowNull: false, }, calculation_failed: { type: Sequelize.BOOLEAN, From 5059082f89dae13ed149d910b413e0757e87c0b3 Mon Sep 17 00:00:00 2001 From: Isaac Hill <71404865+isaachilly@users.noreply.github.com> Date: Mon, 4 May 2026 14:20:48 +0200 Subject: [PATCH 09/13] [O2B-1545] Add invalidatedAt to gaq_summaries, remove invalidation table Store invalidation timestamp directly on gaq_summaries instead of a separate gaq_summary_invalidations table. --- lib/database/adapters/GaqSummaryAdapter.js | 2 ++ ...0260223120000-create-gaq-summary-tables.js | 33 ++----------------- lib/database/models/gaqSummary.js | 3 ++ 3 files changed, 8 insertions(+), 30 deletions(-) diff --git a/lib/database/adapters/GaqSummaryAdapter.js b/lib/database/adapters/GaqSummaryAdapter.js index 21cd7b7004..262fceb5be 100644 --- a/lib/database/adapters/GaqSummaryAdapter.js +++ b/lib/database/adapters/GaqSummaryAdapter.js @@ -38,6 +38,7 @@ class GaqSummaryAdapter { missingVerificationsCount, undefinedQualityPeriodsCount, calculationFailed, + invalidatedAt, createdAt, updatedAt, } = databaseObject; @@ -51,6 +52,7 @@ class GaqSummaryAdapter { missingVerificationsCount, undefinedQualityPeriodsCount, calculationFailed, + invalidatedAt, createdAt, updatedAt, }; diff --git a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js index 4540a01c4a..05b2693702 100644 --- a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js +++ b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js @@ -42,36 +42,10 @@ module.exports = { allowNull: false, defaultValue: false, }, - created_at: { + invalidated_at: { type: Sequelize.DATE(3), - allowNull: false, - defaultValue: Sequelize.literal('CURRENT_TIMESTAMP(3)'), - }, - updated_at: { - type: Sequelize.DATE(3), - allowNull: false, - defaultValue: Sequelize.literal('CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)'), - }, - }, { transaction }); - - await queryInterface.createTable('gaq_summary_invalidations', { - data_pass_id: { - type: Sequelize.INTEGER, - primaryKey: true, - allowNull: false, - references: { - model: 'data_passes', - key: 'id', - }, - }, - run_number: { - type: Sequelize.INTEGER, - primaryKey: true, - allowNull: false, - references: { - model: 'runs', - key: 'run_number', - }, + allowNull: true, + defaultValue: null, }, created_at: { type: Sequelize.DATE(3), @@ -87,7 +61,6 @@ module.exports = { }), down: async (queryInterface) => queryInterface.sequelize.transaction(async (transaction) => { - await queryInterface.dropTable('gaq_summary_invalidations', { transaction }); await queryInterface.dropTable('gaq_summaries', { transaction }); }), }; diff --git a/lib/database/models/gaqSummary.js b/lib/database/models/gaqSummary.js index aab9a04dfd..97099f256d 100644 --- a/lib/database/models/gaqSummary.js +++ b/lib/database/models/gaqSummary.js @@ -39,6 +39,9 @@ module.exports = (sequelize) => { calculationFailed: { type: Sequelize.BOOLEAN, }, + invalidatedAt: { + type: Sequelize.DATE(3), + }, }, { tableName: 'gaq_summaries' }); GaqSummary.removeAttribute('id'); From 9893667ba7ccb7629c8c66d1b77cec5fb11c580d Mon Sep 17 00:00:00 2001 From: Isaac Hill <71404865+isaachilly@users.noreply.github.com> Date: Mon, 4 May 2026 14:23:39 +0200 Subject: [PATCH 10/13] [O2B-1545] Rename calculationFailed to notComputable --- lib/database/adapters/GaqSummaryAdapter.js | 4 ++-- .../migrations/v1/20260223120000-create-gaq-summary-tables.js | 2 +- lib/database/models/gaqSummary.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/database/adapters/GaqSummaryAdapter.js b/lib/database/adapters/GaqSummaryAdapter.js index 262fceb5be..53b6baf61a 100644 --- a/lib/database/adapters/GaqSummaryAdapter.js +++ b/lib/database/adapters/GaqSummaryAdapter.js @@ -37,7 +37,7 @@ class GaqSummaryAdapter { mcReproducibleCoverage, missingVerificationsCount, undefinedQualityPeriodsCount, - calculationFailed, + notComputable, invalidatedAt, createdAt, updatedAt, @@ -51,7 +51,7 @@ class GaqSummaryAdapter { mcReproducibleCoverage, missingVerificationsCount, undefinedQualityPeriodsCount, - calculationFailed, + notComputable, invalidatedAt, createdAt, updatedAt, diff --git a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js index 05b2693702..9366d050ce 100644 --- a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js +++ b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js @@ -37,7 +37,7 @@ module.exports = { undefined_quality_periods_count: { type: Sequelize.INTEGER, }, - calculation_failed: { + not_computable: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: false, diff --git a/lib/database/models/gaqSummary.js b/lib/database/models/gaqSummary.js index 97099f256d..efa76e04fd 100644 --- a/lib/database/models/gaqSummary.js +++ b/lib/database/models/gaqSummary.js @@ -36,7 +36,7 @@ module.exports = (sequelize) => { undefinedQualityPeriodsCount: { type: Sequelize.INTEGER, }, - calculationFailed: { + notComputable: { type: Sequelize.BOOLEAN, }, invalidatedAt: { From 47449a7da2403962c4e7417076d06807f38ad453 Mon Sep 17 00:00:00 2001 From: Isaac Hill <71404865+isaachilly@users.noreply.github.com> Date: Mon, 4 May 2026 14:31:43 +0200 Subject: [PATCH 11/13] [O2B-1545] Remove unused GaqSummaryInvalidation files and imports --- .../adapters/GaqSummaryInvalidationAdapter.js | 48 ------------------- lib/database/adapters/index.js | 3 -- lib/database/models/gaqSummaryInvalidation.js | 34 ------------- lib/database/models/index.js | 2 - .../GaqSummaryInvalidationRepository.js | 33 ------------- lib/database/repositories/index.js | 2 - 6 files changed, 122 deletions(-) delete mode 100644 lib/database/adapters/GaqSummaryInvalidationAdapter.js delete mode 100644 lib/database/models/gaqSummaryInvalidation.js delete mode 100644 lib/database/repositories/GaqSummaryInvalidationRepository.js diff --git a/lib/database/adapters/GaqSummaryInvalidationAdapter.js b/lib/database/adapters/GaqSummaryInvalidationAdapter.js deleted file mode 100644 index dbd76df3a8..0000000000 --- a/lib/database/adapters/GaqSummaryInvalidationAdapter.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @license - * Copyright CERN and copyright holders of ALICE O2. This software is - * distributed under the terms of the GNU General Public License v3 (GPL - * Version 3), copied verbatim in the file "COPYING". - * - * See http://alice-o2.web.cern.ch/license for full licensing information. - * - * 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. - */ - -/** - * GaqSummaryInvalidationAdapter - */ -class GaqSummaryInvalidationAdapter { - /** - * Constructor - */ - constructor() { - this.toEntity = this.toEntity.bind(this); - } - - /** - * Converts the given database object to an entity object. - * - * @param {SequelizeGaqSummaryInvalidation} databaseObject Object to convert. - * @returns {GaqSummaryInvalidation} Converted entity object. - */ - toEntity(databaseObject) { - const { - dataPassId, - runNumber, - createdAt, - updatedAt, - } = databaseObject; - - return { - dataPassId, - runNumber, - createdAt, - updatedAt, - }; - } -} - -module.exports = { GaqSummaryInvalidationAdapter }; diff --git a/lib/database/adapters/index.js b/lib/database/adapters/index.js index 97d22b927f..9c858e1bc2 100644 --- a/lib/database/adapters/index.js +++ b/lib/database/adapters/index.js @@ -28,7 +28,6 @@ const FlpRoleAdapter = require('./FlpRoleAdapter'); const { HostAdapter } = require('./HostAdapter.js'); const { GaqDetectorAdapter } = require('./GaqDetectorAdapter.js'); const { GaqSummaryAdapter } = require('./GaqSummaryAdapter.js'); -const { GaqSummaryInvalidationAdapter } = require('./GaqSummaryInvalidationAdapter.js'); const { LhcFillAdapter } = require('./LhcFillAdapter.js'); const { LhcFillStatisticsAdapter } = require('./LhcFillStatisticsAdapter.js'); const LhcPeriodAdapter = require('./LhcPeriodAdapter'); @@ -66,7 +65,6 @@ const eorReasonAdapter = new EorReasonAdapter(); const flpRoleAdapter = new FlpRoleAdapter(); const gaqDetectorAdapter = new GaqDetectorAdapter(); const gaqSummaryAdapter = new GaqSummaryAdapter(); -const gaqSummaryInvalidationAdapter = new GaqSummaryInvalidationAdapter(); const hostAdapter = new HostAdapter(); const lhcFillAdapter = new LhcFillAdapter(); const lhcFillStatisticsAdapter = new LhcFillStatisticsAdapter(); @@ -164,7 +162,6 @@ module.exports = { flpRoleAdapter, gaqDetectorAdapter, gaqSummaryAdapter, - gaqSummaryInvalidationAdapter, hostAdapter, lhcFillAdapter, lhcFillStatisticsAdapter, diff --git a/lib/database/models/gaqSummaryInvalidation.js b/lib/database/models/gaqSummaryInvalidation.js deleted file mode 100644 index 3c0944b9bc..0000000000 --- a/lib/database/models/gaqSummaryInvalidation.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @license - * Copyright CERN and copyright holders of ALICE O2. This software is - * distributed under the terms of the GNU General Public License v3 (GPL - * Version 3), copied verbatim in the file "COPYING". - * - * See http://alice-o2.web.cern.ch/license for full licensing information. - * - * 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. - */ - -module.exports = (sequelize) => { - const Sequelize = require('sequelize'); - - const GaqSummaryInvalidation = sequelize.define('GaqSummaryInvalidation', { - dataPassId: { - type: Sequelize.INTEGER, - }, - runNumber: { - type: Sequelize.INTEGER, - }, - }, { tableName: 'gaq_summary_invalidations' }); - - GaqSummaryInvalidation.removeAttribute('id'); - - GaqSummaryInvalidation.associate = (models) => { - GaqSummaryInvalidation.belongsTo(models.Run, { foreignKey: 'runNumber', as: 'run' }); - GaqSummaryInvalidation.belongsTo(models.DataPass, { foreignKey: 'dataPassId', as: 'dataPass' }); - }; - - return GaqSummaryInvalidation; -}; diff --git a/lib/database/models/index.js b/lib/database/models/index.js index 36736ce905..2549209c5b 100644 --- a/lib/database/models/index.js +++ b/lib/database/models/index.js @@ -28,7 +28,6 @@ const EpnRoleSession = require('./epnrolesession'); const FlpRole = require('./flprole'); const GaqDetector = require('./gaqDetector.js'); const GaqSummary = require('./gaqSummary.js'); -const GaqSummaryInvalidation = require('./gaqSummaryInvalidation.js'); const Host = require('./host.js'); const LhcFill = require('./lhcFill'); const LhcFillStatistics = require('./lhcFillStatistics.js'); @@ -69,7 +68,6 @@ module.exports = (sequelize) => { FlpRole: FlpRole(sequelize), GaqDetector: GaqDetector(sequelize), GaqSummary: GaqSummary(sequelize), - GaqSummaryInvalidation: GaqSummaryInvalidation(sequelize), Host: Host(sequelize), LhcFill: LhcFill(sequelize), LhcFillStatistics: LhcFillStatistics(sequelize), diff --git a/lib/database/repositories/GaqSummaryInvalidationRepository.js b/lib/database/repositories/GaqSummaryInvalidationRepository.js deleted file mode 100644 index c6608f9e83..0000000000 --- a/lib/database/repositories/GaqSummaryInvalidationRepository.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @license - * Copyright CERN and copyright holders of ALICE O2. This software is - * distributed under the terms of the GNU General Public License v3 (GPL - * Version 3), copied verbatim in the file "COPYING". - * - * See http://alice-o2.web.cern.ch/license for full licensing information. - * - * 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 { - models: { - GaqSummaryInvalidation, - }, -} = require('..'); -const Repository = require('./Repository'); - -/** - * GaqSummaryInvalidation repository - */ -class GaqSummaryInvalidationRepository extends Repository { - /** - * Creates a new `GaqSummaryInvalidationRepository` instance. - */ - constructor() { - super(GaqSummaryInvalidation); - } -} - -module.exports = new GaqSummaryInvalidationRepository(); diff --git a/lib/database/repositories/index.js b/lib/database/repositories/index.js index 417ccd5375..4be7600145 100644 --- a/lib/database/repositories/index.js +++ b/lib/database/repositories/index.js @@ -27,7 +27,6 @@ const EnvironmentRepository = require('./EnvironmentRepository'); const EorReasonRepository = require('./EorReasonRepository'); const FlpRoleRepository = require('./FlpRoleRepository'); const GaqDetectorRepository = require('./GaqDetectorRepository.js'); -const GaqSummaryInvalidationRepository = require('./GaqSummaryInvalidationRepository.js'); const GaqSummaryRepository = require('./GaqSummaryRepository.js'); const HostRepository = require('./HostRepository.js'); const LhcFillRepository = require('./LhcFillRepository'); @@ -72,7 +71,6 @@ module.exports = { EorReasonRepository, FlpRoleRepository, GaqDetectorRepository, - GaqSummaryInvalidationRepository, GaqSummaryRepository, HostRepository, LhcFillRepository, From 772a96c179e35f1f705a6a04e6f41a518c627856 Mon Sep 17 00:00:00 2001 From: Isaac Hill <71404865+isaachilly@users.noreply.github.com> Date: Tue, 5 May 2026 10:23:03 +0200 Subject: [PATCH 12/13] [O2B-1545] Add index on gaq_summaries.invalidated_at Create an index on invalidated_at column of gaq_summaries table to improve query performance, as it is commonly used to fetch the invalidated summary queue. --- .../v1/20260223120000-create-gaq-summary-tables.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js index 9366d050ce..639db07c5c 100644 --- a/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js +++ b/lib/database/migrations/v1/20260223120000-create-gaq-summary-tables.js @@ -58,6 +58,11 @@ module.exports = { defaultValue: Sequelize.literal('CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)'), }, }, { transaction }); + + await queryInterface.addIndex('gaq_summaries', { + name: 'gaq_summaries_invalidated_at_idx', + fields: ['invalidated_at'], + }, { transaction }); }), down: async (queryInterface) => queryInterface.sequelize.transaction(async (transaction) => { From f5f686c906213b99e563f1ceb81882c53bb2d345 Mon Sep 17 00:00:00 2001 From: Isaac Hill <71404865+isaachilly@users.noreply.github.com> Date: Thu, 18 Jun 2026 12:15:32 +0200 Subject: [PATCH 13/13] [O2B-1545] Add a composite primary key on GAQSummary table Sequelize model omitted the primaryKey that migration file defines. --- lib/database/models/gaqSummary.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/database/models/gaqSummary.js b/lib/database/models/gaqSummary.js index efa76e04fd..3a12f62f33 100644 --- a/lib/database/models/gaqSummary.js +++ b/lib/database/models/gaqSummary.js @@ -17,9 +17,11 @@ module.exports = (sequelize) => { const GaqSummary = sequelize.define('GaqSummary', { dataPassId: { type: Sequelize.INTEGER, + primaryKey: true, }, runNumber: { type: Sequelize.INTEGER, + primaryKey: true, }, badRunCoverage: { type: Sequelize.FLOAT,