From 500754d7a5bcb0b8dc4e9dafe61ad0ee5fb04b7f Mon Sep 17 00:00:00 2001 From: "Pierre TOP (TOPI)" Date: Wed, 15 Dec 2021 21:32:22 +0100 Subject: [PATCH 1/4] Add script for alter table bigint --- ...answers-id-type-to-bigint-with-downtime.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 api/scripts/bigint/change-answers-id-type-to-bigint-with-downtime.js diff --git a/api/scripts/bigint/change-answers-id-type-to-bigint-with-downtime.js b/api/scripts/bigint/change-answers-id-type-to-bigint-with-downtime.js new file mode 100644 index 00000000000..8714e786b0a --- /dev/null +++ b/api/scripts/bigint/change-answers-id-type-to-bigint-with-downtime.js @@ -0,0 +1,34 @@ +require('dotenv').config(); +const { knex } = require('../../db/knex-database-connection'); +const logger = require('../../lib/infrastructure/logger'); + +const changeAnswerIdTypeToBigint = async () => { + logger.info('Altering knowledge-elements.answerId type to BIGINT - In progress'); + await knex.raw(`ALTER TABLE "knowledge-elements" ALTER COLUMN "answerId" TYPE BIGINT`); + logger.info('Altering knowledge-elements.answerId type to BIGINT - Done'); + + logger.info('Altering answers.id type to BIGINT - In progress'); + await knex.raw(`ALTER TABLE "answers" ALTER COLUMN "id" TYPE BIGINT`); + logger.info('Altering answers.id type to BIGINT - Done'); + + logger.info('Altering answers_id_seq type to BIGINT - In progress'); + await knex.raw(`ALTER SEQUENCE "answers_id_seq" AS BIGINT`); + logger.info('Altering answers_id_seq type to BIGINT - Done'); +}; + +const preventOneOffContainerTimeout = () => { + setInterval(() => { + logger.info('alive'); + }, 1000); +}; + +(async () => { + try { + preventOneOffContainerTimeout(); + await changeAnswerIdTypeToBigint(); + process.exit(0); + } catch (error) { + logger.fatal(error); + process.exit(1); + } +})(); From 8998b81d58cf960ce86385a5a40efeeeacba9b03 Mon Sep 17 00:00:00 2001 From: yahya Date: Mon, 11 Jul 2022 12:04:29 +0200 Subject: [PATCH 2/4] Migrate answer fk to bigint --- .../bigint/change-answers-id-type-to-bigint-with-downtime.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/scripts/bigint/change-answers-id-type-to-bigint-with-downtime.js b/api/scripts/bigint/change-answers-id-type-to-bigint-with-downtime.js index 8714e786b0a..2b06b0bd60f 100644 --- a/api/scripts/bigint/change-answers-id-type-to-bigint-with-downtime.js +++ b/api/scripts/bigint/change-answers-id-type-to-bigint-with-downtime.js @@ -7,6 +7,10 @@ const changeAnswerIdTypeToBigint = async () => { await knex.raw(`ALTER TABLE "knowledge-elements" ALTER COLUMN "answerId" TYPE BIGINT`); logger.info('Altering knowledge-elements.answerId type to BIGINT - Done'); + logger.info('Altering flash-assessment-results.answerId type to BIGINT - In progress'); + await knex.raw(`ALTER TABLE "flash-assessment-results" ALTER COLUMN "answerId" TYPE BIGINT`); + logger.info('Altering flash-assessment-results.answerId type to BIGINT - Done'); + logger.info('Altering answers.id type to BIGINT - In progress'); await knex.raw(`ALTER TABLE "answers" ALTER COLUMN "id" TYPE BIGINT`); logger.info('Altering answers.id type to BIGINT - Done'); From f2cdad5818243f2ce18ef6efdf5a8a4b7d29df47 Mon Sep 17 00:00:00 2001 From: yahya Date: Mon, 11 Jul 2022 13:16:26 +0200 Subject: [PATCH 3/4] Wrap alter table with knex transaction --- ...answers-id-type-to-bigint-with-downtime.js | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/api/scripts/bigint/change-answers-id-type-to-bigint-with-downtime.js b/api/scripts/bigint/change-answers-id-type-to-bigint-with-downtime.js index 2b06b0bd60f..976ecdcfc33 100644 --- a/api/scripts/bigint/change-answers-id-type-to-bigint-with-downtime.js +++ b/api/scripts/bigint/change-answers-id-type-to-bigint-with-downtime.js @@ -3,21 +3,23 @@ const { knex } = require('../../db/knex-database-connection'); const logger = require('../../lib/infrastructure/logger'); const changeAnswerIdTypeToBigint = async () => { - logger.info('Altering knowledge-elements.answerId type to BIGINT - In progress'); - await knex.raw(`ALTER TABLE "knowledge-elements" ALTER COLUMN "answerId" TYPE BIGINT`); - logger.info('Altering knowledge-elements.answerId type to BIGINT - Done'); + await knex.transaction(async (trx) => { + logger.info('Altering knowledge-elements.answerId type to BIGINT - In progress'); + await knex.raw(`ALTER TABLE "knowledge-elements" ALTER COLUMN "answerId" TYPE BIGINT`).transacting(trx); + logger.info('Altering knowledge-elements.answerId type to BIGINT - Done'); - logger.info('Altering flash-assessment-results.answerId type to BIGINT - In progress'); - await knex.raw(`ALTER TABLE "flash-assessment-results" ALTER COLUMN "answerId" TYPE BIGINT`); - logger.info('Altering flash-assessment-results.answerId type to BIGINT - Done'); + logger.info('Altering flash-assessment-results.answerId type to BIGINT - In progress'); + await knex.raw(`ALTER TABLE "flash-assessment-results" ALTER COLUMN "answerId" TYPE BIGINT`).transacting(trx); + logger.info('Altering flash-assessment-results.answerId type to BIGINT - Done'); - logger.info('Altering answers.id type to BIGINT - In progress'); - await knex.raw(`ALTER TABLE "answers" ALTER COLUMN "id" TYPE BIGINT`); - logger.info('Altering answers.id type to BIGINT - Done'); + logger.info('Altering answers.id type to BIGINT - In progress'); + await knex.raw(`ALTER TABLE "answers" ALTER COLUMN "id" TYPE BIGINT`).transacting(trx); + logger.info('Altering answers.id type to BIGINT - Done'); - logger.info('Altering answers_id_seq type to BIGINT - In progress'); - await knex.raw(`ALTER SEQUENCE "answers_id_seq" AS BIGINT`); - logger.info('Altering answers_id_seq type to BIGINT - Done'); + logger.info('Altering answers_id_seq type to BIGINT - In progress'); + await knex.raw(`ALTER SEQUENCE "answers_id_seq" AS BIGINT`).transacting(trx); + logger.info('Altering answers_id_seq type to BIGINT - Done'); + }); }; const preventOneOffContainerTimeout = () => { @@ -36,3 +38,5 @@ const preventOneOffContainerTimeout = () => { process.exit(1); } })(); + +module.exports = { changeAnswerIdTypeToBigint }; From 089088effb41bd0407afc19967b49d78eff0f726 Mon Sep 17 00:00:00 2001 From: yahya Date: Mon, 11 Jul 2022 18:37:28 +0200 Subject: [PATCH 4/4] Add acceptance test for migration --- ...rs-id-type-to-bigint-with-downtime_test.js | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 api/tests/acceptance/scripts/bigint/change-answers-id-type-to-bigint-with-downtime_test.js diff --git a/api/tests/acceptance/scripts/bigint/change-answers-id-type-to-bigint-with-downtime_test.js b/api/tests/acceptance/scripts/bigint/change-answers-id-type-to-bigint-with-downtime_test.js new file mode 100644 index 00000000000..65e5227edf0 --- /dev/null +++ b/api/tests/acceptance/scripts/bigint/change-answers-id-type-to-bigint-with-downtime_test.js @@ -0,0 +1,64 @@ +const { + changeAnswerIdTypeToBigint, +} = require('../../../../scripts/bigint/change-answers-id-type-to-bigint-with-downtime'); +const { expect, knex } = require('../../../test-helper'); +const DatabaseBuilder = require('../../../../db/database-builder/database-builder'); +const databaseBuilder = new DatabaseBuilder({ knex }); + +describe('#changeAnswerIdTypeToBigint', function () { + let answerIdInsertedBeforeSwitch; + + it('should insert answer with an id bigger than the maximum integer type value', async function () { + // when + await changeAnswerIdTypeToBigint(); + const maxValueBigIntType = '9223372036854775807'; + const { id: assessmentId } = databaseBuilder.factory.buildAssessment(); + const { id: answerId } = databaseBuilder.factory.buildAnswer({ id: maxValueBigIntType, assessmentId }); + databaseBuilder.factory.buildKnowledgeElement({ assessmentId, answerId }); + await databaseBuilder.commit(); + + // then + expect(answerId).to.be.equal(maxValueBigIntType); + }); + + it('should change type of answer sequence from integer to bigint', async function () { + // when + await changeAnswerIdTypeToBigint(); + + // then + const { rows: sequenceDataType } = await knex.raw( + `SELECT data_type FROM information_schema.sequences WHERE sequence_name = 'answers_id_seq'` + ); + expect(sequenceDataType[0]['data_type']).to.equal('bigint'); + }); + + it('should sequence are correctly reassigned', async function () { + // given + await changeAnswerIdTypeToBigint(); + + // when + const [{ id: answerIdInsertedAfterSwitch }] = await knex('answers') + .insert({ + value: 'Some value for answer', + result: 'Some result for answer', + challengeId: 'rec123ABC', + createdAt: new Date('2020-01-01'), + updatedAt: new Date('2020-01-02'), + resultDetails: 'Some result details for answer.', + timeSpent: 30, + }) + .returning('id'); + + // then + expect(answerIdInsertedAfterSwitch).to.equal(answerIdInsertedBeforeSwitch + 1); + }); + + afterEach(async function () { + await knex.transaction(async (trx) => { + await knex.raw(`ALTER TABLE "knowledge-elements" ALTER COLUMN "answerId" TYPE INTEGER`).transacting(trx); + await knex.raw(`ALTER TABLE "flash-assessment-results" ALTER COLUMN "answerId" TYPE INTEGER`).transacting(trx); + await knex.raw(`ALTER TABLE "answers" ALTER COLUMN "id" TYPE INTEGER`).transacting(trx); + await knex.raw(`ALTER SEQUENCE "answers_id_seq" AS INTEGER`).transacting(trx); + }); + }); +});