diff --git a/packages/backend/migration/1651224615271-foreign-key.js b/packages/backend/migration/1651224615271-foreign-key.js new file mode 100644 index 0000000000..44ba7fb6c4 --- /dev/null +++ b/packages/backend/migration/1651224615271-foreign-key.js @@ -0,0 +1,89 @@ +export class foreignKeyReports1651224615271 { + name = 'foreignKeyReports1651224615271' + + async up(queryRunner) { + await Promise.all([ + queryRunner.query(`ALTER INDEX "public"."IDX_seoignmeoprigmkpodgrjmkpormg" RENAME TO "IDX_c8cc87bd0f2f4487d17c651fbf"`), + queryRunner.query(`DROP INDEX "public"."IDX_note_on_channelId_and_id_desc"`), + + // remove unnecessary default null, see also down + queryRunner.query(`ALTER TABLE "user" ALTER COLUMN "followersUri" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "access_token" ALTER COLUMN "session" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "access_token" ALTER COLUMN "appId" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "access_token" ALTER COLUMN "name" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "access_token" ALTER COLUMN "description" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "access_token" ALTER COLUMN "iconUrl" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "softwareName" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "softwareVersion" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "name" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "description" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "maintainerName" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "maintainerEmail" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "iconUrl" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "faviconUrl" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "themeColor" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "clip" ALTER COLUMN "description" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "note" ALTER COLUMN "channelId" DROP DEFAULT`), + queryRunner.query(`ALTER TABLE "abuse_user_report" ALTER COLUMN "comment" DROP DEFAULT`), + + queryRunner.query(`CREATE INDEX "IDX_315c779174fe8247ab324f036e" ON "drive_file" ("isLink")`), + queryRunner.query(`CREATE INDEX "IDX_f22169eb10657bded6d875ac8f" ON "note" ("channelId")`), + queryRunner.query(`CREATE INDEX "IDX_a9021cc2e1feb5f72d3db6e9f5" ON "abuse_user_report" ("targetUserId")`), + + queryRunner.query(`DELETE FROM "abuse_user_report" WHERE "targetUserId" NOT IN (SELECT "id" FROM "user")`).then(() => { + queryRunner.query(`ALTER TABLE "abuse_user_report" ADD CONSTRAINT "FK_a9021cc2e1feb5f72d3db6e9f5f" FOREIGN KEY ("targetUserId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + }), + + queryRunner.query(`ALTER TABLE "poll" ADD CONSTRAINT "UQ_da851e06d0dfe2ef397d8b1bf1b" UNIQUE ("noteId")`), + queryRunner.query(`ALTER TABLE "user_keypair" ADD CONSTRAINT "UQ_f4853eb41ab722fe05f81cedeb6" UNIQUE ("userId")`), + queryRunner.query(`ALTER TABLE "user_profile" ADD CONSTRAINT "UQ_51cb79b5555effaf7d69ba1cff9" UNIQUE ("userId")`), + queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "UQ_10c146e4b39b443ede016f6736d" UNIQUE ("userId")`), + queryRunner.query(`ALTER TABLE "promo_note" ADD CONSTRAINT "UQ_e263909ca4fe5d57f8d4230dd5c" UNIQUE ("noteId")`), + + queryRunner.query(`ALTER TABLE "page" RENAME CONSTRAINT "FK_3126dd7c502c9e4d7597ef7ef10" TO "FK_a9ca79ad939bf06066b81c9d3aa"`), + + queryRunner.query(`ALTER TYPE "public"."user_profile_mutingnotificationtypes_enum" ADD VALUE 'pollEnded' AFTER 'pollVote'`), + ]); + } + + async down(queryRunner) { + await Promise.all([ + // There is no ALTER TYPE REMOVE VALUE query, so the reverse operation is a bit more complex + queryRunner.query(`UPDATE "user_profile" SET "mutingNotificationTypes" = array_remove("mutingNotificationTypes", 'pollEnded')`) + .then(() => + queryRunner.query(`CREATE TYPE "public"."user_profile_mutingnotificationtypes_enum_old" AS ENUM('follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app')`) + ).then(() => + queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "mutingNotificationTypes" DROP DEFAULT`) + ).then(() => + queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "mutingNotificationTypes" TYPE "public"."user_profile_mutingnotificationtypes_enum_old"[] USING "mutingNotificationTypes"::"text"::"public"."user_profile_mutingnotificationtypes_enum_old"[]`) + ).then(() => + queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "mutingNotificationTypes" SET DEFAULT '{}'`) + ).then(() => + queryRunner.query(`DROP TYPE "public"."user_profile_mutingnotificationtypes_enum"`) + ).then(() => + queryRunner.query(`ALTER TYPE "public"."user_profile_mutingnotificationtypes_enum_old" RENAME TO "user_profile_mutingnotificationtypes_enum"`) + ), + + queryRunner.query(`ALTER TABLE "page" RENAME CONSTRAINT "FK_a9ca79ad939bf06066b81c9d3aa" TO "FK_3126dd7c502c9e4d7597ef7ef10"`), + + queryRunner.query(`ALTER TABLE "promo_note" DROP CONSTRAINT "UQ_e263909ca4fe5d57f8d4230dd5c"`), + queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "UQ_10c146e4b39b443ede016f6736d"`), + queryRunner.query(`ALTER TABLE "user_profile" DROP CONSTRAINT "UQ_51cb79b5555effaf7d69ba1cff9"`), + queryRunner.query(`ALTER TABLE "user_keypair" DROP CONSTRAINT "UQ_f4853eb41ab722fe05f81cedeb6"`), + queryRunner.query(`ALTER TABLE "poll" DROP CONSTRAINT "UQ_da851e06d0dfe2ef397d8b1bf1b"`), + + queryRunner.query(`ALTER TABLE "abuse_user_report" ALTER COLUMN "comment" SET DEFAULT '{}'`), + queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "FK_a9021cc2e1feb5f72d3db6e9f5f"`), + + queryRunner.query(`DROP INDEX "public"."IDX_a9021cc2e1feb5f72d3db6e9f5"`), + queryRunner.query(`DROP INDEX "public"."IDX_f22169eb10657bded6d875ac8f"`), + queryRunner.query(`DROP INDEX "public"."IDX_315c779174fe8247ab324f036e"`), + + /* DEFAULT's are not set again because if the column can be NULL, then DEFAULT NULL is not necessary. + see also https://github.com/typeorm/typeorm/issues/7579#issuecomment-835423615 */ + + queryRunner.query(`CREATE INDEX "IDX_note_on_channelId_and_id_desc" ON "note" ("id", "channelId") `), + queryRunner.query(`ALTER INDEX "public"."IDX_c8cc87bd0f2f4487d17c651fbf" RENAME TO "IDX_seoignmeoprigmkpodgrjmkpormg"`), + ]); + } +} diff --git a/packages/backend/src/models/entities/access-token.ts b/packages/backend/src/models/entities/access-token.ts index 69cdc49cec..c6e2141a46 100644 --- a/packages/backend/src/models/entities/access-token.ts +++ b/packages/backend/src/models/entities/access-token.ts @@ -15,7 +15,6 @@ export class AccessToken { @Column('timestamp with time zone', { nullable: true, - default: null, }) public lastUsedAt: Date | null; @@ -29,7 +28,6 @@ export class AccessToken { @Column('varchar', { length: 128, nullable: true, - default: null, }) public session: string | null; @@ -52,7 +50,6 @@ export class AccessToken { @Column({ ...id(), nullable: true, - default: null, }) public appId: App['id'] | null; @@ -65,21 +62,18 @@ export class AccessToken { @Column('varchar', { length: 128, nullable: true, - default: null, }) public name: string | null; @Column('varchar', { length: 512, nullable: true, - default: null, }) public description: string | null; @Column('varchar', { length: 512, nullable: true, - default: null, }) public iconUrl: string | null; diff --git a/packages/backend/src/models/entities/auth-session.ts b/packages/backend/src/models/entities/auth-session.ts index b825856201..295d1b486c 100644 --- a/packages/backend/src/models/entities/auth-session.ts +++ b/packages/backend/src/models/entities/auth-session.ts @@ -23,7 +23,7 @@ export class AuthSession { ...id(), nullable: true, }) - public userId: User['id']; + public userId: User['id'] | null; @ManyToOne(type => User, { onDelete: 'CASCADE', diff --git a/packages/backend/src/models/entities/clip.ts b/packages/backend/src/models/entities/clip.ts index da6b3c7a7f..1386684c32 100644 --- a/packages/backend/src/models/entities/clip.ts +++ b/packages/backend/src/models/entities/clip.ts @@ -37,7 +37,7 @@ export class Clip { public isPublic: boolean; @Column('varchar', { - length: 2048, nullable: true, default: null, + length: 2048, nullable: true, comment: 'The description of the Clip.', }) public description: string | null; diff --git a/packages/backend/src/models/entities/drive-file.ts b/packages/backend/src/models/entities/drive-file.ts index 3d375f0e35..a636d1d519 100644 --- a/packages/backend/src/models/entities/drive-file.ts +++ b/packages/backend/src/models/entities/drive-file.ts @@ -79,7 +79,6 @@ export class DriveFile { }) public properties: { width?: number; height?: number; orientation?: number; avgColor?: string }; - @Index() @Column('boolean') public storedInternal: boolean; diff --git a/packages/backend/src/models/entities/emoji.ts b/packages/backend/src/models/entities/emoji.ts index b72ca72331..7332dd1857 100644 --- a/packages/backend/src/models/entities/emoji.ts +++ b/packages/backend/src/models/entities/emoji.ts @@ -36,6 +36,7 @@ export class Emoji { @Column('varchar', { length: 512, + default: '', }) public publicUrl: string; diff --git a/packages/backend/src/models/entities/instance.ts b/packages/backend/src/models/entities/instance.ts index bb24d6b30f..7ea9234384 100644 --- a/packages/backend/src/models/entities/instance.ts +++ b/packages/backend/src/models/entities/instance.ts @@ -107,53 +107,53 @@ export class Instance { public isSuspended: boolean; @Column('varchar', { - length: 64, nullable: true, default: null, + length: 64, nullable: true, comment: 'The software of the Instance.', }) public softwareName: string | null; @Column('varchar', { - length: 64, nullable: true, default: null, + length: 64, nullable: true, }) public softwareVersion: string | null; @Column('boolean', { - nullable: true, default: null, + nullable: true, }) public openRegistrations: boolean | null; @Column('varchar', { - length: 256, nullable: true, default: null, + length: 256, nullable: true, }) public name: string | null; @Column('varchar', { - length: 4096, nullable: true, default: null, + length: 4096, nullable: true, }) public description: string | null; @Column('varchar', { - length: 128, nullable: true, default: null, + length: 128, nullable: true, }) public maintainerName: string | null; @Column('varchar', { - length: 256, nullable: true, default: null, + length: 256, nullable: true, }) public maintainerEmail: string | null; @Column('varchar', { - length: 256, nullable: true, default: null, + length: 256, nullable: true, }) public iconUrl: string | null; @Column('varchar', { - length: 256, nullable: true, default: null, + length: 256, nullable: true, }) public faviconUrl: string | null; @Column('varchar', { - length: 64, nullable: true, default: null, + length: 64, nullable: true, }) public themeColor: string | null; diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts index 4d58b5f04f..80b5228bcd 100644 --- a/packages/backend/src/models/entities/meta.ts +++ b/packages/backend/src/models/entities/meta.ts @@ -78,7 +78,7 @@ export class Meta { public blockedHosts: string[]; @Column('varchar', { - length: 512, array: true, default: '{"/featured", "/channels", "/explore", "/pages", "/about-misskey"}', + length: 512, array: true, default: '{/featured,/channels,/explore,/pages,/about-misskey}', }) public pinnedPages: string[]; @@ -346,14 +346,12 @@ export class Meta { @Column('varchar', { length: 8192, - default: null, nullable: true, }) public defaultLightTheme: string | null; @Column('varchar', { length: 8192, - default: null, nullable: true, }) public defaultDarkTheme: string | null; diff --git a/packages/backend/src/models/entities/muting.ts b/packages/backend/src/models/entities/muting.ts index b3a7e7a671..8f9e69063a 100644 --- a/packages/backend/src/models/entities/muting.ts +++ b/packages/backend/src/models/entities/muting.ts @@ -17,7 +17,6 @@ export class Muting { @Index() @Column('timestamp with time zone', { nullable: true, - default: null, }) public expiresAt: Date | null; diff --git a/packages/backend/src/models/entities/note.ts b/packages/backend/src/models/entities/note.ts index da49d53b69..0ffeb85f69 100644 --- a/packages/backend/src/models/entities/note.ts +++ b/packages/backend/src/models/entities/note.ts @@ -53,8 +53,8 @@ export class Note { }) public threadId: string | null; - @Column('varchar', { - length: 8192, nullable: true, + @Column('text', { + nullable: true, }) public text: string | null; @@ -179,7 +179,7 @@ export class Note { @Index() @Column({ ...id(), - nullable: true, default: null, + nullable: true, comment: 'The ID of source channel.', }) public channelId: Channel['id'] | null; diff --git a/packages/backend/src/models/entities/user-profile.ts b/packages/backend/src/models/entities/user-profile.ts index f95cb144c5..1778742ea2 100644 --- a/packages/backend/src/models/entities/user-profile.ts +++ b/packages/backend/src/models/entities/user-profile.ts @@ -192,6 +192,7 @@ export class UserProfile { @Column('jsonb', { default: [], + comment: 'List of instances muted by the user.', }) public mutedInstances: string[]; diff --git a/packages/backend/src/models/entities/user.ts b/packages/backend/src/models/entities/user.ts index 29d9a0c2ca..df92fb8259 100644 --- a/packages/backend/src/models/entities/user.ts +++ b/packages/backend/src/models/entities/user.ts @@ -207,7 +207,7 @@ export class User { @Column('boolean', { default: false, - comment: 'Whether to show users replying to other users in the timeline', + comment: 'Whether to show users replying to other users in the timeline.', }) public showTimelineReplies: boolean;