fix: fix channel deletes when channel is associated with fillers (#889)

This commit is contained in:
Christian Benincasa
2024-10-18 12:31:05 -04:00
committed by GitHub
parent 03f57e0ed5
commit 83126c8659
11 changed files with 74 additions and 18 deletions

1
.prettierignore Normal file
View File

@@ -0,0 +1 @@
server/src/migrations/**/*.ts

View File

@@ -4,6 +4,7 @@
"overrides": [ "overrides": [
{ {
"files": ["*.ts", "*.mts", "*.tsx"], "files": ["*.ts", "*.mts", "*.tsx"],
"excludeFiles": ["server/src/migrations/**/*.ts"],
"options": { "options": {
"parser": "typescript" "parser": "typescript"
} }

View File

@@ -30,6 +30,7 @@ import { Migration20240618005544 } from './src/migrations/Migration2024061800554
import { Migration20240719145409 } from './src/migrations/Migration20240719145409.js'; import { Migration20240719145409 } from './src/migrations/Migration20240719145409.js';
import { Migration20240805185042 } from './src/migrations/Migration20240805185042.js'; import { Migration20240805185042 } from './src/migrations/Migration20240805185042.js';
import { Migration20240917191535 } from './src/migrations/Migration20240917191535.js'; import { Migration20240917191535 } from './src/migrations/Migration20240917191535.js';
import { Migration20241014205231 } from './src/migrations/Migration20241014205231.js';
import { DATABASE_LOCATION_ENV_VAR } from './src/util/constants.js'; import { DATABASE_LOCATION_ENV_VAR } from './src/util/constants.js';
import { getDefaultDatabaseDirectory } from './src/util/defaults.js'; import { getDefaultDatabaseDirectory } from './src/util/defaults.js';
@@ -143,6 +144,10 @@ export default defineConfig({
name: 'add_channel_stream_mode', name: 'add_channel_stream_mode',
class: Migration20240917191535, class: Migration20240917191535,
}, },
{
name: 'cascade_channel_filler_show_deletes',
class: Migration20241014205231,
},
], ],
}, },
extensions: [Migrator], extensions: [Migrator],

View File

@@ -23,6 +23,7 @@
"make-exec:macos-arm64": "tsx scripts/makeScriptPackage.ts --target macos-arm64", "make-exec:macos-arm64": "tsx scripts/makeScriptPackage.ts --target macos-arm64",
"make-exec:windows": "tsx scripts/makeScriptPackage.ts --target windows-x64", "make-exec:windows": "tsx scripts/makeScriptPackage.ts --target windows-x64",
"generate-db-migration": "dotenv -e .env.development -- tsx --tsconfig ./tsconfig.build.json src/index.ts db generate-migration", "generate-db-migration": "dotenv -e .env.development -- tsx --tsconfig ./tsconfig.build.json src/index.ts db generate-migration",
"generate-db-migration2": "dotenv -e .env.development -- tsx --tsconfig ./tsconfig.build.json scripts/generateDbMigration.ts",
"generate-db-cache": "dotenv -e .env.development -- tsx scripts/generateDbCache.ts", "generate-db-cache": "dotenv -e .env.development -- tsx scripts/generateDbCache.ts",
"generate-db-types": "dotenv -e .env.development -- tsx scripts/genDbTypes.ts", "generate-db-types": "dotenv -e .env.development -- tsx scripts/genDbTypes.ts",
"mikro-orm": "mikro-orm-esm", "mikro-orm": "mikro-orm-esm",

View File

@@ -0,0 +1,27 @@
import path from 'path';
import tmp from 'tmp';
import dbConfig from '../mikro-orm.config.js';
import { initOrm } from '../src/dao/dataSource';
const tmpdir = tmp.dirSync({
unsafeCleanup: true,
});
const dbName = path.join(tmpdir.name, 'db.db');
console.log(`using temporary database at ${dbName}`);
const orm = await initOrm({
...dbConfig,
dbName,
});
const migrationResult = await orm.migrator.createMigration('./src/migrations');
console.log(`Succcesfully created migration ${migrationResult.fileName}`);
console.debug(migrationResult.diff);
await orm.close();
tmpdir.removeCallback();

View File

@@ -478,6 +478,7 @@ export class ChannelDB {
try { try {
await this.markLineupFileForDeletion(channelId); await this.markLineupFileForDeletion(channelId);
marked = true; marked = true;
const ref = em.getReference(Channel, channelId); const ref = em.getReference(Channel, channelId);
await em.remove(ref).flush(); await em.remove(ref).flush();
// Best effort remove references to this channel // Best effort remove references to this channel
@@ -505,6 +506,8 @@ export class ChannelDB {
channelId, channelId,
e, e,
); );
throw e;
} }
} }

View File

@@ -1,5 +1,4 @@
import { import {
Cascade,
Collection, Collection,
Entity, Entity,
Enum, Enum,
@@ -191,7 +190,7 @@ export class Channel extends BaseEntity {
entity: () => FillerShow, entity: () => FillerShow,
pivotEntity: () => ChannelFillerShow, pivotEntity: () => ChannelFillerShow,
mappedBy: (filler) => filler.channels, mappedBy: (filler) => filler.channels,
cascade: [Cascade.PERSIST, Cascade.REMOVE], deleteRule: 'cascade',
}) })
fillers = new Collection<FillerShow>(this); fillers = new Collection<FillerShow>(this);
@@ -204,7 +203,10 @@ export class Channel extends BaseEntity {
@Property({ nullable: true }) @Property({ nullable: true })
fillerRepeatCooldown?: number; // Seconds fillerRepeatCooldown?: number; // Seconds
@ManyToMany(() => CustomShow) @ManyToMany({
entity: () => CustomShow,
deleteRule: 'cascade',
})
customShows = new Collection<CustomShow>(this); customShows = new Collection<CustomShow>(this);
// Watermark // Watermark
@@ -219,7 +221,10 @@ export class Channel extends BaseEntity {
}) })
transcoding?: IType<ChannelTranscodingSettings, string>; transcoding?: IType<ChannelTranscodingSettings, string>;
@ManyToMany(() => Program) @ManyToMany({
entity: () => Program,
deleteRule: 'cascade',
})
fallback = new Collection<Program>(this); fallback = new Collection<Program>(this);
@Enum({ items: () => ChannelStreamModes, default: 'hls' }) @Enum({ items: () => ChannelStreamModes, default: 'hls' })

View File

@@ -8,7 +8,11 @@ export class ChannelFillerShow {
@ManyToOne({ primary: true, entity: () => FillerShow }) @ManyToOne({ primary: true, entity: () => FillerShow })
fillerShow!: Ref<FillerShow>; fillerShow!: Ref<FillerShow>;
@ManyToOne({ primary: true, entity: () => Channel }) @ManyToOne({
primary: true,
entity: () => Channel,
deleteRule: 'cascade',
})
channel!: Ref<Channel>; channel!: Ref<Channel>;
@Property() @Property()

View File

@@ -237,7 +237,8 @@
"default": "'hls'", "default": "'hls'",
"enumItems": [ "enumItems": [
"hls", "hls",
"hls_slower" "hls_slower",
"mpegts"
], ],
"mappedType": "enum" "mappedType": "enum"
} }
@@ -578,6 +579,7 @@
"uuid" "uuid"
], ],
"referencedTableName": "channel", "referencedTableName": "channel",
"deleteRule": "cascade",
"updateRule": "cascade" "updateRule": "cascade"
} }
}, },

View File

@@ -0,0 +1,18 @@
import { Migration } from '@mikro-orm/migrations';
export class Migration20241014205231 extends Migration {
async up(): Promise<void> {
this.addSql('pragma foreign_keys = off;');
this.addSql('PRAGMA defer_foreign_keys = ON;');
this.addSql('create table `channel_filler_show__temp_alter` (`filler_show_uuid` text not null, `channel_uuid` text not null, `weight` integer not null, `cooldown` integer not null, constraint `channel_filler_show_filler_show_uuid_foreign` foreign key(`filler_show_uuid`) references `filler_show`(`uuid`) on update cascade, constraint `channel_filler_show_channel_uuid_foreign` foreign key(`channel_uuid`) references `channel`(`uuid`) on delete cascade on update cascade, primary key (`filler_show_uuid`, `channel_uuid`));');
this.addSql('insert into `channel_filler_show__temp_alter` select * from `channel_filler_show`;');
this.addSql('drop table `channel_filler_show`;');
this.addSql('alter table `channel_filler_show__temp_alter` rename to `channel_filler_show`;');
this.addSql('create index `channel_filler_show_filler_show_uuid_index` on `channel_filler_show` (`filler_show_uuid`);');
this.addSql('create index `channel_filler_show_channel_uuid_index` on `channel_filler_show` (`channel_uuid`);');
this.addSql('pragma foreign_keys = on;');
this.addSql('PRAGMA defer_foreign_keys = OFF;');
}
}

View File

@@ -144,16 +144,6 @@ export class TVGuideService {
this.currentUpdateTime = now; this.currentUpdateTime = now;
this.currentEndTime = now + guideDuration.asMilliseconds(); this.currentEndTime = now + guideDuration.asMilliseconds();
this.eventService.push({
type: 'xmltv',
message: `Started building tv-guide at = ${dayjs(now).format()}`,
module: 'xmltv',
detail: {
time: now,
},
level: 'info',
});
this.currentChannels = values( this.currentChannels = values(
mapValues( mapValues(
await this.channelDb.loadAllLineups(), await this.channelDb.loadAllLineups(),
@@ -799,11 +789,10 @@ export class TVGuideService {
} }
private async refreshXML() { private async refreshXML() {
// const xmltvSettings = (await getSettings()).xmlTvSettings();
await this.xmltv.write(values(this.cachedGuide)); await this.xmltv.write(values(this.cachedGuide));
this.eventService.push({ this.eventService.push({
type: 'xmltv', type: 'xmltv',
message: `XMLTV updated at server time = ${new Date().toISOString()}`, message: `XMLTV updated at server time = ${dayjs().format()}`,
module: 'xmltv', module: 'xmltv',
detail: { detail: {
time: new Date().getTime(), time: new Date().getTime(),