forked from FoundKeyGang/FoundKey
refactor: properly migrate thread ids
Commit fc65190ef7
introduced thread ids but
did not add the thread id to previous notes. This is fixed by this commit.
The original notes in each thread should also have a thread id set which will
be the same as their ID.
These two migrations allow the threadId column be a NOT NULL column.
This commit is contained in:
parent
e27494cf3e
commit
457bd5ee3f
8 changed files with 46 additions and 21 deletions
30
packages/backend/migration/1659446758000-fix-thread-id.js
Normal file
30
packages/backend/migration/1659446758000-fix-thread-id.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
export class fixThreadId1659446758000 {
|
||||||
|
name = 'fixThreadId1659446758000'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await Promise.all([
|
||||||
|
queryRunner.query(`UPDATE "note" SET "threadId" = "id" WHERE "replyId" IS NULL`),
|
||||||
|
queryRunner.query(`WITH "threads" ("noteId", "thread") AS (
|
||||||
|
SELECT "id" as "noteId", "parent" as "thread" FROM (
|
||||||
|
WITH RECURSIVE "parents" ("id", "parent", "height") AS (
|
||||||
|
SELECT "id", "replyId", 0 FROM "note" WHERE "replyId" IS NOT NULL AND "threadId" IS NULL
|
||||||
|
UNION ALL
|
||||||
|
SELECT "parents"."id", "note"."replyId", "parents"."height" + 1
|
||||||
|
FROM "parents"
|
||||||
|
JOIN "note" ON "parents"."parent" = "note"."id"
|
||||||
|
WHERE "note"."replyId" IS NOT NULL
|
||||||
|
) SELECT *, MAX("height") OVER (PARTITION BY "id") AS "maxheight" FROM "parents"
|
||||||
|
) AS "x"
|
||||||
|
WHERE "height" = "maxheight"
|
||||||
|
) UPDATE "note" SET "threadId" = "threads"."thread" FROM "threads" WHERE "id" = "threads"."noteId"`),
|
||||||
|
]);
|
||||||
|
await queryRunner.query(`ALTER TABLE "note" ALTER COLUMN "threadId" SET NOT NULL`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "note" ALTER COLUMN "threaadId" DROP NOT NULL`);
|
||||||
|
// Cannot un-fix thread id's for ones that just were not migrated (2nd query above)
|
||||||
|
// but can remove the thread ids for the root notes of each thread.
|
||||||
|
await queryRunner.query(`UPDATE "note" SET "threadId" = NULL WHERE "replyId" IS NULL`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,7 +51,7 @@ export class Note {
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 256, nullable: true,
|
||||||
})
|
})
|
||||||
public threadId: string | null;
|
public threadId: string;
|
||||||
|
|
||||||
@Column('text', {
|
@Column('text', {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
|
|
|
@ -7,11 +7,7 @@ export function generateMutedNoteThreadQuery(q: SelectQueryBuilder<any>, me: { i
|
||||||
.select('threadMuted.threadId')
|
.select('threadMuted.threadId')
|
||||||
.where('threadMuted.userId = :userId', { userId: me.id });
|
.where('threadMuted.userId = :userId', { userId: me.id });
|
||||||
|
|
||||||
q.andWhere(`note.id NOT IN (${ mutedQuery.getQuery() })`);
|
q.andWhere(`note.threadId NOT IN (${ mutedQuery.getQuery() })`);
|
||||||
q.andWhere(new Brackets(qb => { qb
|
|
||||||
.where('note.threadId IS NULL')
|
|
||||||
.orWhere(`note.threadId NOT IN (${ mutedQuery.getQuery() })`);
|
|
||||||
}));
|
|
||||||
|
|
||||||
q.setParameters(mutedQuery.getParameters());
|
q.setParameters(mutedQuery.getParameters());
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
NoteThreadMutings.count({
|
NoteThreadMutings.count({
|
||||||
where: {
|
where: {
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
threadId: note.threadId || note.id,
|
threadId: note.threadId,
|
||||||
},
|
},
|
||||||
take: 1,
|
take: 1,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -41,9 +41,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
|
|
||||||
const mutedNotes = await Notes.find({
|
const mutedNotes = await Notes.find({
|
||||||
where: [{
|
where: [{
|
||||||
id: note.threadId || note.id,
|
threadId: note.threadId,
|
||||||
}, {
|
|
||||||
threadId: note.threadId || note.id,
|
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -52,7 +50,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
await NoteThreadMutings.insert({
|
await NoteThreadMutings.insert({
|
||||||
id: genId(),
|
id: genId(),
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
threadId: note.threadId || note.id,
|
threadId: note.threadId,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
mutingNotificationTypes: ps.mutingNotificationTypes,
|
mutingNotificationTypes: ps.mutingNotificationTypes,
|
||||||
});
|
});
|
||||||
|
|
|
@ -29,7 +29,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
await NoteThreadMutings.delete({
|
await NoteThreadMutings.delete({
|
||||||
threadId: note.threadId || note.id,
|
threadId: note.threadId,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -369,7 +369,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
|
||||||
if (data.reply.userHost === null) {
|
if (data.reply.userHost === null) {
|
||||||
const threadMuted = await NoteThreadMutings.findOneBy({
|
const threadMuted = await NoteThreadMutings.findOneBy({
|
||||||
userId: data.reply.userId,
|
userId: data.reply.userId,
|
||||||
threadId: data.reply.threadId || data.reply.id,
|
threadId: data.reply.threadId,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!threadMuted) {
|
if (!threadMuted) {
|
||||||
|
@ -500,15 +500,16 @@ function incRenoteCount(renote: Note): void {
|
||||||
|
|
||||||
async function insertNote(user: { id: User['id']; host: User['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]): Promise<Note> {
|
async function insertNote(user: { id: User['id']; host: User['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]): Promise<Note> {
|
||||||
const createdAt = data.createdAt ?? new Date();
|
const createdAt = data.createdAt ?? new Date();
|
||||||
|
const id = genId(createdAt);
|
||||||
|
|
||||||
const insert = new Note({
|
const insert = new Note({
|
||||||
id: genId(createdAt),
|
id,
|
||||||
createdAt,
|
createdAt,
|
||||||
fileIds: data.files?.map(file => file.id) ?? [],
|
fileIds: data.files ? data.files.map(file => file.id) : [],
|
||||||
replyId: data.reply?.id ?? null,
|
replyId: data.reply ? data.reply.id : null,
|
||||||
renoteId: data.renote?.id ?? null,
|
renoteId: data.renote ? data.renote.id : null,
|
||||||
channelId: data.channel?.id ?? null,
|
channelId: data.channel ? data.channel.id : null,
|
||||||
threadId: data.reply?.threadId ?? data.reply?.id ?? null,
|
threadId: data.reply?.threadId ?? id,
|
||||||
name: data.name,
|
name: data.name,
|
||||||
text: data.text,
|
text: data.text,
|
||||||
hasPoll: data.poll != null,
|
hasPoll: data.poll != null,
|
||||||
|
@ -616,7 +617,7 @@ async function createMentionedEvents(mentionedUsers: MinimumUser[], note: Note,
|
||||||
for (const u of mentionedUsers.filter(u => Users.isLocalUser(u))) {
|
for (const u of mentionedUsers.filter(u => Users.isLocalUser(u))) {
|
||||||
const threadMuted = await NoteThreadMutings.findOneBy({
|
const threadMuted = await NoteThreadMutings.findOneBy({
|
||||||
userId: u.id,
|
userId: u.id,
|
||||||
threadId: note.threadId || note.id,
|
threadId: note.threadId,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (threadMuted) {
|
if (threadMuted) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ export async function insertNoteUnread(userId: User['id'], note: Note, params: {
|
||||||
// スレッドミュート
|
// スレッドミュート
|
||||||
const threadMute = await NoteThreadMutings.findOneBy({
|
const threadMute = await NoteThreadMutings.findOneBy({
|
||||||
userId,
|
userId,
|
||||||
threadId: note.threadId || note.id,
|
threadId: note.threadId,
|
||||||
});
|
});
|
||||||
if (threadMute) return;
|
if (threadMute) return;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue