refactor(database): ♻️ Move Note <-> Media relations to a many-to-many model instead of one-to-many

This commit is contained in:
Jesse Wierzbinski 2025-01-23 20:36:09 +01:00
parent 9c30dacda7
commit 3216fc339a
No known key found for this signature in database
7 changed files with 2428 additions and 31 deletions

View file

@ -17,7 +17,7 @@ import type {
import { Instance, db } from "@versia/kit/db"; import { Instance, db } from "@versia/kit/db";
import { import {
EmojiToNote, EmojiToNote,
Medias, MediasToNotes,
NoteToMentions, NoteToMentions,
Notes, Notes,
Users, Users,
@ -630,21 +630,14 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
// Remove old attachments // Remove old attachments
await db await db
.update(Medias) .delete(MediasToNotes)
.set({ .where(eq(MediasToNotes.noteId, this.data.id));
noteId: null,
}) await db.insert(MediasToNotes).values(
.where(eq(Medias.noteId, this.data.id)); mediaAttachments.map((media) => ({
await db
.update(Medias)
.set({
noteId: this.data.id, noteId: this.data.id,
}) mediaId: media.id,
.where( })),
inArray(
Medias.id,
mediaAttachments.map((i) => i.id),
),
); );
} }

View file

@ -38,7 +38,11 @@ export const findManyNotes = async (
...query, ...query,
with: { with: {
...query?.with, ...query?.with,
attachments: true, attachments: {
with: {
media: true,
},
},
emojis: { emojis: {
with: { with: {
emoji: { emoji: {
@ -65,7 +69,11 @@ export const findManyNotes = async (
}, },
reblog: { reblog: {
with: { with: {
attachments: true, attachments: {
with: {
media: true,
},
},
emojis: { emojis: {
with: { with: {
emoji: { emoji: {
@ -176,6 +184,7 @@ export const findManyNotes = async (
...mention.user, ...mention.user,
endpoints: mention.user.endpoints, endpoints: mention.user.endpoints,
})), })),
attachments: post.attachments.map((attachment) => attachment.media),
emojis: (post.emojis ?? []).map((emoji) => emoji.emoji), emojis: (post.emojis ?? []).map((emoji) => emoji.emoji),
reblog: post.reblog && { reblog: post.reblog && {
...post.reblog, ...post.reblog,
@ -184,6 +193,9 @@ export const findManyNotes = async (
...mention.user, ...mention.user,
endpoints: mention.user.endpoints, endpoints: mention.user.endpoints,
})), })),
attachments: post.reblog.attachments.map(
(attachment) => attachment.media,
),
emojis: (post.reblog.emojis ?? []).map((emoji) => emoji.emoji), emojis: (post.reblog.emojis ?? []).map((emoji) => emoji.emoji),
reblogCount: Number(post.reblog.reblogCount), reblogCount: Number(post.reblog.reblogCount),
likeCount: Number(post.reblog.likeCount), likeCount: Number(post.reblog.likeCount),

View file

@ -1,21 +1,20 @@
import type { Config } from "drizzle-kit"; import type { Config } from "drizzle-kit";
import { config } from "~/packages/config-manager/index.ts";
export default { export default {
dialect: "postgresql", dialect: "postgresql",
out: "./drizzle/migrations", out: "./drizzle/migrations",
schema: "./drizzle/schema.ts", schema: "./drizzle/schema.ts",
dbCredentials: { dbCredentials: {
/* host: "localhost", host: "localhost",
port: 40000, port: 40000,
user: "lysand", user: "lysand",
password: "lysand", password: "lysand",
database: "lysand", */ database: "lysand",
host: config.database.host, /* host: config.database.host,
port: Number(config.database.port), port: Number(config.database.port),
user: config.database.username, user: config.database.username,
password: config.database.password, password: config.database.password,
database: config.database.database, database: config.database.database, */
}, },
// Print all statements // Print all statements
verbose: true, verbose: true,

View file

@ -0,0 +1,26 @@
CREATE TABLE "MediasToNote" (
"mediaId" uuid NOT NULL,
"noteId" uuid NOT NULL
);
--> statement-breakpoint
ALTER TABLE "Medias" DROP CONSTRAINT "Medias_noteId_Notes_id_fk";
--> statement-breakpoint
ALTER TABLE "Medias" ADD COLUMN "content" jsonb NOT NULL;--> statement-breakpoint
ALTER TABLE "Medias" ADD COLUMN "original_content" jsonb;--> statement-breakpoint
ALTER TABLE "Medias" ADD COLUMN "thumbnail" jsonb;--> statement-breakpoint
ALTER TABLE "MediasToNote" ADD CONSTRAINT "MediasToNote_mediaId_Medias_id_fk" FOREIGN KEY ("mediaId") REFERENCES "public"."Medias"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
ALTER TABLE "MediasToNote" ADD CONSTRAINT "MediasToNote_noteId_Notes_id_fk" FOREIGN KEY ("noteId") REFERENCES "public"."Notes"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
CREATE INDEX "MediasToNote_mediaId_index" ON "MediasToNote" USING btree ("mediaId");--> statement-breakpoint
CREATE INDEX "MediasToNote_noteId_index" ON "MediasToNote" USING btree ("noteId");--> statement-breakpoint
ALTER TABLE "Medias" DROP COLUMN "url";--> statement-breakpoint
ALTER TABLE "Medias" DROP COLUMN "remote_url";--> statement-breakpoint
ALTER TABLE "Medias" DROP COLUMN "thumbnail_url";--> statement-breakpoint
ALTER TABLE "Medias" DROP COLUMN "mime_type";--> statement-breakpoint
ALTER TABLE "Medias" DROP COLUMN "description";--> statement-breakpoint
ALTER TABLE "Medias" DROP COLUMN "sha256";--> statement-breakpoint
ALTER TABLE "Medias" DROP COLUMN "fps";--> statement-breakpoint
ALTER TABLE "Medias" DROP COLUMN "duration";--> statement-breakpoint
ALTER TABLE "Medias" DROP COLUMN "width";--> statement-breakpoint
ALTER TABLE "Medias" DROP COLUMN "height";--> statement-breakpoint
ALTER TABLE "Medias" DROP COLUMN "size";--> statement-breakpoint
ALTER TABLE "Medias" DROP COLUMN "noteId";

File diff suppressed because it is too large Load diff

View file

@ -295,6 +295,13 @@
"when": 1737644734501, "when": 1737644734501,
"tag": "0041_bright_doctor_spectrum", "tag": "0041_bright_doctor_spectrum",
"breakpoints": true "breakpoints": true
},
{
"idx": 42,
"version": "7",
"when": 1737660317024,
"tag": "0042_swift_the_phantom",
"breakpoints": true
} }
] ]
} }

View file

@ -309,10 +309,6 @@ export const Medias = pgTable("Medias", {
originalContent: jsonb("original_content").$type<ContentFormat>(), originalContent: jsonb("original_content").$type<ContentFormat>(),
thumbnail: jsonb("thumbnail").$type<ContentFormat>(), thumbnail: jsonb("thumbnail").$type<ContentFormat>(),
blurhash: text("blurhash"), blurhash: text("blurhash"),
noteId: uuid("noteId").references(() => Notes.id, {
onDelete: "cascade",
onUpdate: "cascade",
}),
}); });
export const Notifications = pgTable("Notifications", { export const Notifications = pgTable("Notifications", {
@ -791,10 +787,38 @@ export const UserToPinnedNotes = pgTable(
], ],
); );
export const AttachmentsRelations = relations(Medias, ({ one }) => ({ export const MediasRelations = relations(Medias, ({ many }) => ({
notes: one(Notes, { notes: many(Notes),
fields: [Medias.noteId], }));
export const MediasToNotes = pgTable(
"MediasToNote",
{
mediaId: uuid("mediaId")
.notNull()
.references(() => Medias.id, {
onDelete: "cascade",
onUpdate: "cascade",
}),
noteId: uuid("noteId")
.notNull()
.references(() => Notes.id, {
onDelete: "cascade",
onUpdate: "cascade",
}),
},
(table) => [index().on(table.mediaId), index().on(table.noteId)],
);
export const MediasToNotesRelations = relations(MediasToNotes, ({ one }) => ({
media: one(Medias, {
fields: [MediasToNotes.mediaId],
references: [Medias.id],
}),
note: one(Notes, {
fields: [MediasToNotes.noteId],
references: [Notes.id], references: [Notes.id],
relationName: "AttachmentToNote",
}), }),
})); }));
@ -886,7 +910,9 @@ export const NotesRelations = relations(Notes, ({ many, one }) => ({
references: [Users.id], references: [Users.id],
relationName: "NoteToAuthor", relationName: "NoteToAuthor",
}), }),
attachments: many(Medias), attachments: many(MediasToNotes, {
relationName: "AttachmentToNote",
}),
mentions: many(NoteToMentions), mentions: many(NoteToMentions),
reblog: one(Notes, { reblog: one(Notes, {
fields: [Notes.reblogId], fields: [Notes.reblogId],