mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-01-11 19:56:44 +00:00
feat: Implement comprehensive migration from TelemetryService to Service, including data transfer and constraint updates
This commit is contained in:
parent
81051064dd
commit
a9b5ea4702
3 changed files with 126 additions and 122 deletions
|
|
@ -1,23 +1,117 @@
|
|||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
// Schema + Data migration: Move TelemetryService to Service table
|
||||
export class MigrationName1767979448478 implements MigrationInterface {
|
||||
name = 'MigrationName1767979448478'
|
||||
public name = 'MigrationName1767979448478'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryException" DROP CONSTRAINT "FK_6470c69cb5f53c5899c0483df5f"`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryUsageBilling" DROP CONSTRAINT "FK_91333210492e5d2f334231468a7"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_6470c69cb5f53c5899c0483df5"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_91333210492e5d2f334231468a"`);
|
||||
// Step 1: Drop old FK constraints (pointing to TelemetryService)
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryException" DROP CONSTRAINT IF EXISTS "FK_6470c69cb5f53c5899c0483df5f"`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryUsageBilling" DROP CONSTRAINT IF EXISTS "FK_91333210492e5d2f334231468a7"`);
|
||||
|
||||
// Step 2: Drop old indexes
|
||||
await queryRunner.query(`DROP INDEX IF EXISTS "public"."IDX_6470c69cb5f53c5899c0483df5"`);
|
||||
await queryRunner.query(`DROP INDEX IF EXISTS "public"."IDX_91333210492e5d2f334231468a"`);
|
||||
|
||||
// Step 3: Add retainTelemetryDataForDays column to Service (needed before data migration)
|
||||
await queryRunner.query(`ALTER TABLE "Service" ADD COLUMN IF NOT EXISTS "retainTelemetryDataForDays" integer DEFAULT '15'`);
|
||||
|
||||
// Step 4: Migrate TelemetryService data to Service table (BEFORE renaming columns and adding FK)
|
||||
// Preserve the same _id so existing references remain valid
|
||||
const telemetryServiceTableExists = await queryRunner.query(`
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'TelemetryService'
|
||||
)
|
||||
`);
|
||||
|
||||
if (telemetryServiceTableExists[0]?.exists) {
|
||||
await queryRunner.query(`
|
||||
INSERT INTO "Service" (
|
||||
"_id",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
"deletedAt",
|
||||
"version",
|
||||
"projectId",
|
||||
"name",
|
||||
"slug",
|
||||
"description",
|
||||
"createdByUserId",
|
||||
"deletedByUserId",
|
||||
"serviceColor",
|
||||
"retainTelemetryDataForDays"
|
||||
)
|
||||
SELECT
|
||||
"_id",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
"deletedAt",
|
||||
"version",
|
||||
"projectId",
|
||||
"name",
|
||||
"slug",
|
||||
"description",
|
||||
"createdByUserId",
|
||||
"deletedByUserId",
|
||||
"serviceColor",
|
||||
"retainTelemetryDataForDays"
|
||||
FROM "TelemetryService"
|
||||
ON CONFLICT ("_id") DO NOTHING
|
||||
`);
|
||||
}
|
||||
|
||||
// Step 5: Migrate TelemetryServiceLabel to ServiceLabel
|
||||
const telemetryServiceLabelExists = await queryRunner.query(`
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'TelemetryServiceLabel'
|
||||
)
|
||||
`);
|
||||
|
||||
if (telemetryServiceLabelExists[0]?.exists) {
|
||||
await queryRunner.query(`
|
||||
INSERT INTO "ServiceLabel" ("serviceId", "labelId")
|
||||
SELECT "telemetryServiceId", "labelId"
|
||||
FROM "TelemetryServiceLabel"
|
||||
ON CONFLICT DO NOTHING
|
||||
`);
|
||||
}
|
||||
|
||||
// Step 6: Rename columns (telemetryServiceId -> serviceId)
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryException" RENAME COLUMN "telemetryServiceId" TO "serviceId"`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryUsageBilling" RENAME COLUMN "telemetryServiceId" TO "serviceId"`);
|
||||
await queryRunner.query(`CREATE TABLE "MetricTypeService" ("metricTypeId" uuid NOT NULL, "serviceId" uuid NOT NULL, CONSTRAINT "PK_21b7a84eea5b71922ac5ccc92e9" PRIMARY KEY ("metricTypeId", "serviceId"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_e6b6e365ad502b487cb63d2891" ON "MetricTypeService" ("metricTypeId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_c67839207ff53f33eb22648b56" ON "MetricTypeService" ("serviceId") `);
|
||||
await queryRunner.query(`ALTER TABLE "Service" ADD "retainTelemetryDataForDays" integer DEFAULT '15'`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_08a0cfa9f184257b1e57da4cf5" ON "TelemetryException" ("serviceId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_b9f49cd8318a35757fc843ee90" ON "TelemetryUsageBilling" ("serviceId") `);
|
||||
|
||||
// Step 7: Create MetricTypeService table
|
||||
await queryRunner.query(`CREATE TABLE IF NOT EXISTS "MetricTypeService" ("metricTypeId" uuid NOT NULL, "serviceId" uuid NOT NULL, CONSTRAINT "PK_21b7a84eea5b71922ac5ccc92e9" PRIMARY KEY ("metricTypeId", "serviceId"))`);
|
||||
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_e6b6e365ad502b487cb63d2891" ON "MetricTypeService" ("metricTypeId") `);
|
||||
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_c67839207ff53f33eb22648b56" ON "MetricTypeService" ("serviceId") `);
|
||||
|
||||
// Step 8: Migrate MetricTypeTelemetryService to MetricTypeService
|
||||
const metricTypeTelemetryServiceExists = await queryRunner.query(`
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'MetricTypeTelemetryService'
|
||||
)
|
||||
`);
|
||||
|
||||
if (metricTypeTelemetryServiceExists[0]?.exists) {
|
||||
await queryRunner.query(`
|
||||
INSERT INTO "MetricTypeService" ("metricTypeId", "serviceId")
|
||||
SELECT "metricTypeId", "telemetryServiceId"
|
||||
FROM "MetricTypeTelemetryService"
|
||||
ON CONFLICT DO NOTHING
|
||||
`);
|
||||
}
|
||||
|
||||
// Step 10: Create new indexes
|
||||
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_08a0cfa9f184257b1e57da4cf5" ON "TelemetryException" ("serviceId") `);
|
||||
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_b9f49cd8318a35757fc843ee90" ON "TelemetryUsageBilling" ("serviceId") `);
|
||||
|
||||
// Step 11: Add new FK constraints (NOW safe because Service table has the migrated data)
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryException" ADD CONSTRAINT "FK_08a0cfa9f184257b1e57da4cf50" FOREIGN KEY ("serviceId") REFERENCES "Service"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryUsageBilling" ADD CONSTRAINT "FK_b9f49cd8318a35757fc843ee900" FOREIGN KEY ("serviceId") REFERENCES "Service"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "MetricTypeService" ADD CONSTRAINT "FK_e6b6e365ad502b487cb63d28913" FOREIGN KEY ("metricTypeId") REFERENCES "MetricType"("_id") ON DELETE CASCADE ON UPDATE CASCADE`);
|
||||
|
|
@ -25,24 +119,38 @@ export class MigrationName1767979448478 implements MigrationInterface {
|
|||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
// Drop new FK constraints
|
||||
await queryRunner.query(`ALTER TABLE "MetricTypeService" DROP CONSTRAINT "FK_c67839207ff53f33eb22648b567"`);
|
||||
await queryRunner.query(`ALTER TABLE "MetricTypeService" DROP CONSTRAINT "FK_e6b6e365ad502b487cb63d28913"`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryUsageBilling" DROP CONSTRAINT "FK_b9f49cd8318a35757fc843ee900"`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryException" DROP CONSTRAINT "FK_08a0cfa9f184257b1e57da4cf50"`);
|
||||
|
||||
// Drop new indexes
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_b9f49cd8318a35757fc843ee90"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_08a0cfa9f184257b1e57da4cf5"`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`);
|
||||
await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`);
|
||||
|
||||
// Drop retainTelemetryDataForDays column
|
||||
await queryRunner.query(`ALTER TABLE "Service" DROP COLUMN "retainTelemetryDataForDays"`);
|
||||
|
||||
// Drop MetricTypeService table and indexes
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_c67839207ff53f33eb22648b56"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_e6b6e365ad502b487cb63d2891"`);
|
||||
await queryRunner.query(`DROP TABLE "MetricTypeService"`);
|
||||
|
||||
// Rename columns back
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryUsageBilling" RENAME COLUMN "serviceId" TO "telemetryServiceId"`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryException" RENAME COLUMN "serviceId" TO "telemetryServiceId"`);
|
||||
|
||||
// Recreate old indexes
|
||||
await queryRunner.query(`CREATE INDEX "IDX_91333210492e5d2f334231468a" ON "TelemetryUsageBilling" ("telemetryServiceId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_6470c69cb5f53c5899c0483df5" ON "TelemetryException" ("telemetryServiceId") `);
|
||||
|
||||
// Restore old FK constraints (pointing back to TelemetryService)
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryUsageBilling" ADD CONSTRAINT "FK_91333210492e5d2f334231468a7" FOREIGN KEY ("telemetryServiceId") REFERENCES "TelemetryService"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "TelemetryException" ADD CONSTRAINT "FK_6470c69cb5f53c5899c0483df5f" FOREIGN KEY ("telemetryServiceId") REFERENCES "TelemetryService"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
|
||||
// Note: We don't delete the migrated data from Service table in down migration
|
||||
// as it could be dangerous if new Service records were created
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,106 +0,0 @@
|
|||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
// Data migration: Move data from TelemetryService to Service table
|
||||
export class MigrationName1767979448479 implements MigrationInterface {
|
||||
public name = 'MigrationName1767979448479'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
// Check if TelemetryService table exists before migrating data
|
||||
const telemetryServiceTableExists = await queryRunner.query(`
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'TelemetryService'
|
||||
)
|
||||
`);
|
||||
|
||||
if (!telemetryServiceTableExists[0]?.exists) {
|
||||
// TelemetryService table doesn't exist, nothing to migrate
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 1: Copy TelemetryService data to Service table
|
||||
// Insert TelemetryService records into Service, preserving the same _id
|
||||
// This ensures existing FK references in TelemetryException, TelemetryUsageBilling remain valid
|
||||
await queryRunner.query(`
|
||||
INSERT INTO "Service" (
|
||||
"_id",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
"deletedAt",
|
||||
"version",
|
||||
"projectId",
|
||||
"name",
|
||||
"slug",
|
||||
"description",
|
||||
"createdByUserId",
|
||||
"deletedByUserId",
|
||||
"serviceColor",
|
||||
"retainTelemetryDataForDays"
|
||||
)
|
||||
SELECT
|
||||
"_id",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
"deletedAt",
|
||||
"version",
|
||||
"projectId",
|
||||
"name",
|
||||
"slug",
|
||||
"description",
|
||||
"createdByUserId",
|
||||
"deletedByUserId",
|
||||
"serviceColor",
|
||||
"retainTelemetryDataForDays"
|
||||
FROM "TelemetryService"
|
||||
ON CONFLICT ("_id") DO NOTHING
|
||||
`);
|
||||
|
||||
// Step 2: Copy TelemetryServiceLabel data to ServiceLabel
|
||||
// Check if TelemetryServiceLabel table exists
|
||||
const telemetryServiceLabelExists = await queryRunner.query(`
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'TelemetryServiceLabel'
|
||||
)
|
||||
`);
|
||||
|
||||
if (telemetryServiceLabelExists[0]?.exists) {
|
||||
await queryRunner.query(`
|
||||
INSERT INTO "ServiceLabel" ("serviceId", "labelId")
|
||||
SELECT "telemetryServiceId", "labelId"
|
||||
FROM "TelemetryServiceLabel"
|
||||
ON CONFLICT DO NOTHING
|
||||
`);
|
||||
}
|
||||
|
||||
// Step 3: Copy MetricTypeTelemetryService data to MetricTypeService
|
||||
// Check if MetricTypeTelemetryService table exists
|
||||
const metricTypeTelemetryServiceExists = await queryRunner.query(`
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'MetricTypeTelemetryService'
|
||||
)
|
||||
`);
|
||||
|
||||
if (metricTypeTelemetryServiceExists[0]?.exists) {
|
||||
await queryRunner.query(`
|
||||
INSERT INTO "MetricTypeService" ("metricTypeId", "serviceId")
|
||||
SELECT "metricTypeId", "telemetryServiceId"
|
||||
FROM "MetricTypeTelemetryService"
|
||||
ON CONFLICT DO NOTHING
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
public async down(_queryRunner: QueryRunner): Promise<void> {
|
||||
// Data migration rollback is not straightforward
|
||||
// The original TelemetryService data is still intact in the TelemetryService table
|
||||
// We would need to delete the copied records from Service table
|
||||
// but this could be dangerous as new Service records may have been created
|
||||
// For safety, we don't delete any data in the down migration
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -215,6 +215,7 @@ import { AddGitHubAppInstallationIdToProject1766958924188 } from "./176695892418
|
|||
import { MigrationName1767009661768 } from "./1767009661768-MigrationName";
|
||||
import { RenameServiceCatalogToService1767966850199 } from "./1767966850199-RenameServiceCatalogToService";
|
||||
import { MigrationName1767979055522 } from "./1767979055522-MigrationName";
|
||||
import { MigrationName1767979448478 } from "./1767979448478-MigrationName";
|
||||
|
||||
export default [
|
||||
InitialMigration,
|
||||
|
|
@ -433,5 +434,6 @@ export default [
|
|||
AddGitHubAppInstallationIdToProject1766958924188,
|
||||
MigrationName1767009661768,
|
||||
RenameServiceCatalogToService1767966850199,
|
||||
MigrationName1767979055522
|
||||
MigrationName1767979055522,
|
||||
MigrationName1767979448478
|
||||
];
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue