refactor(database): 🚚 Rename "Attachment" to "Media"

This commit is contained in:
Jesse Wierzbinski 2025-01-23 16:08:42 +01:00
parent bbd56b600d
commit 2f61cd8f0a
No known key found for this signature in database
21 changed files with 2429 additions and 101 deletions

View file

@ -2,7 +2,7 @@ import { proxyUrl } from "@/response";
import type { Attachment as ApiAttachment } from "@versia/client/types";
import type { ContentFormat } from "@versia/federation/types";
import { db } from "@versia/kit/db";
import { Attachments } from "@versia/kit/tables";
import { Medias } from "@versia/kit/tables";
import {
type InferInsertModel,
type InferSelectModel,
@ -20,9 +20,9 @@ import { MediaManager } from "../media/media-manager.ts";
import { MediaJobType, mediaQueue } from "../queues/media.ts";
import { BaseInterface } from "./base.ts";
type AttachmentType = InferSelectModel<typeof Attachments>;
type MediaType = InferSelectModel<typeof Medias>;
export class Attachment extends BaseInterface<typeof Attachments> {
export class Media extends BaseInterface<typeof Medias> {
public static schema: z.ZodType<ApiAttachment> = z.object({
id: z.string().uuid(),
type: z.enum(["unknown", "image", "gifv", "video", "audio"]),
@ -51,10 +51,10 @@ export class Attachment extends BaseInterface<typeof Attachments> {
blurhash: z.string().nullable(),
});
public static $type: AttachmentType;
public static $type: MediaType;
public async reload(): Promise<void> {
const reloaded = await Attachment.fromId(this.data.id);
const reloaded = await Media.fromId(this.data.id);
if (!reloaded) {
throw new Error("Failed to reload attachment");
@ -63,23 +63,23 @@ export class Attachment extends BaseInterface<typeof Attachments> {
this.data = reloaded.data;
}
public static async fromId(id: string | null): Promise<Attachment | null> {
public static async fromId(id: string | null): Promise<Media | null> {
if (!id) {
return null;
}
return await Attachment.fromSql(eq(Attachments.id, id));
return await Media.fromSql(eq(Medias.id, id));
}
public static async fromIds(ids: string[]): Promise<Attachment[]> {
return await Attachment.manyFromSql(inArray(Attachments.id, ids));
public static async fromIds(ids: string[]): Promise<Media[]> {
return await Media.manyFromSql(inArray(Medias.id, ids));
}
public static async fromSql(
sql: SQL<unknown> | undefined,
orderBy: SQL<unknown> | undefined = desc(Attachments.id),
): Promise<Attachment | null> {
const found = await db.query.Attachments.findFirst({
orderBy: SQL<unknown> | undefined = desc(Medias.id),
): Promise<Media | null> {
const found = await db.query.Medias.findFirst({
where: sql,
orderBy,
});
@ -87,17 +87,17 @@ export class Attachment extends BaseInterface<typeof Attachments> {
if (!found) {
return null;
}
return new Attachment(found);
return new Media(found);
}
public static async manyFromSql(
sql: SQL<unknown> | undefined,
orderBy: SQL<unknown> | undefined = desc(Attachments.id),
orderBy: SQL<unknown> | undefined = desc(Medias.id),
limit?: number,
offset?: number,
extra?: Parameters<typeof db.query.Attachments.findMany>[0],
): Promise<Attachment[]> {
const found = await db.query.Attachments.findMany({
extra?: Parameters<typeof db.query.Medias.findMany>[0],
): Promise<Media[]> {
const found = await db.query.Medias.findMany({
where: sql,
orderBy,
limit,
@ -105,18 +105,16 @@ export class Attachment extends BaseInterface<typeof Attachments> {
with: extra?.with,
});
return found.map((s) => new Attachment(s));
return found.map((s) => new Media(s));
}
public async update(
newAttachment: Partial<AttachmentType>,
): Promise<AttachmentType> {
public async update(newAttachment: Partial<MediaType>): Promise<MediaType> {
await db
.update(Attachments)
.update(Medias)
.set(newAttachment)
.where(eq(Attachments.id, this.id));
.where(eq(Medias.id, this.id));
const updated = await Attachment.fromId(this.data.id);
const updated = await Media.fromId(this.data.id);
if (!updated) {
throw new Error("Failed to update attachment");
@ -126,26 +124,24 @@ export class Attachment extends BaseInterface<typeof Attachments> {
return updated.data;
}
public save(): Promise<AttachmentType> {
public save(): Promise<MediaType> {
return this.update(this.data);
}
public async delete(ids?: string[]): Promise<void> {
if (Array.isArray(ids)) {
await db.delete(Attachments).where(inArray(Attachments.id, ids));
await db.delete(Medias).where(inArray(Medias.id, ids));
} else {
await db.delete(Attachments).where(eq(Attachments.id, this.id));
await db.delete(Medias).where(eq(Medias.id, this.id));
}
}
public static async insert(
data: InferInsertModel<typeof Attachments>,
): Promise<Attachment> {
const inserted = (
await db.insert(Attachments).values(data).returning()
)[0];
data: InferInsertModel<typeof Medias>,
): Promise<Media> {
const inserted = (await db.insert(Medias).values(data).returning())[0];
const attachment = await Attachment.fromId(inserted.id);
const attachment = await Media.fromId(inserted.id);
if (!attachment) {
throw new Error("Failed to insert attachment");
@ -160,7 +156,7 @@ export class Attachment extends BaseInterface<typeof Attachments> {
description?: string;
thumbnail?: File;
},
): Promise<Attachment> {
): Promise<Media> {
if (file.size > config.validation.max_media_size) {
throw new ApiError(
413,
@ -191,17 +187,17 @@ export class Attachment extends BaseInterface<typeof Attachments> {
const { path } = await mediaManager.addFile(file);
const url = Attachment.getUrl(path);
const url = Media.getUrl(path);
let thumbnailUrl = "";
if (options?.thumbnail) {
const { path } = await mediaManager.addFile(options.thumbnail);
thumbnailUrl = Attachment.getUrl(path);
thumbnailUrl = Media.getUrl(path);
}
const newAttachment = await Attachment.insert({
const newAttachment = await Media.insert({
url,
thumbnailUrl: thumbnailUrl || undefined,
sha256: sha256.update(await file.arrayBuffer()).digest("hex"),
@ -319,11 +315,11 @@ export class Attachment extends BaseInterface<typeof Attachments> {
public static fromVersia(
attachmentToConvert: ContentFormat,
): Promise<Attachment> {
): Promise<Media> {
const key = Object.keys(attachmentToConvert)[0];
const value = attachmentToConvert[key];
return Attachment.insert({
return Media.insert({
mimeType: key,
url: value.content,
description: value.description || undefined,

View file

@ -16,8 +16,8 @@ import type {
} from "@versia/federation/types";
import { Instance, db } from "@versia/kit/db";
import {
Attachments,
EmojiToNote,
Medias,
NoteToMentions,
Notes,
Users,
@ -44,7 +44,7 @@ import {
import { config } from "~/packages/config-manager";
import { DeliveryJobType, deliveryQueue } from "../queues/delivery.ts";
import { Application } from "./application.ts";
import { Attachment } from "./attachment.ts";
import { Media } from "./attachment.ts";
import { BaseInterface } from "./base.ts";
import { Emoji } from "./emoji.ts";
import { User } from "./user.ts";
@ -56,7 +56,7 @@ type NoteTypeWithRelations = NoteType & {
mentions: (InferSelectModel<typeof Users> & {
instance: typeof Instance.$type | null;
})[];
attachments: (typeof Attachment.$type)[];
attachments: (typeof Media.$type)[];
reblog: NoteTypeWithoutRecursiveRelations | null;
emojis: (typeof Emoji.$type)[];
reply: NoteType | null;
@ -102,7 +102,7 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
sensitive: z.boolean(),
spoiler_text: z.string(),
visibility: z.enum(["public", "unlisted", "private", "direct"]),
media_attachments: z.array(Attachment.schema),
media_attachments: z.array(Media.schema),
mentions: z.array(
z.object({
id: z.string().uuid(),
@ -442,7 +442,7 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
uri?: string;
mentions?: User[];
/** List of IDs of database Attachment objects */
mediaAttachments?: Attachment[];
mediaAttachments?: Media[];
replyId?: string;
quoteId?: string;
application?: Application;
@ -515,7 +515,7 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
emojis?: Emoji[];
uri?: string;
mentions?: User[];
mediaAttachments?: Attachment[];
mediaAttachments?: Media[];
replyId?: string;
quoteId?: string;
application?: Application;
@ -623,28 +623,26 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
* Deletes all existing attachments associated with this note, then replaces them with the provided attachments.
* @param mediaAttachments - The IDs of the attachments to associate with this note
*/
public async updateAttachments(
mediaAttachments: Attachment[],
): Promise<void> {
public async updateAttachments(mediaAttachments: Media[]): Promise<void> {
if (mediaAttachments.length === 0) {
return;
}
// Remove old attachments
await db
.update(Attachments)
.update(Medias)
.set({
noteId: null,
})
.where(eq(Attachments.noteId, this.data.id));
.where(eq(Medias.noteId, this.data.id));
await db
.update(Attachments)
.update(Medias)
.set({
noteId: this.data.id,
})
.where(
inArray(
Attachments.id,
Medias.id,
mediaAttachments.map((i) => i.id),
),
);
@ -740,16 +738,16 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
}
}
const attachments: Attachment[] = [];
const attachments: Media[] = [];
for (const attachment of note.attachments ?? []) {
const resolvedAttachment = await Attachment.fromVersia(
attachment,
).catch((e) => {
logger.error`${e}`;
sentry?.captureException(e);
return null;
});
const resolvedAttachment = await Media.fromVersia(attachment).catch(
(e) => {
logger.error`${e}`;
sentry?.captureException(e);
return null;
},
);
if (resolvedAttachment) {
attachments.push(resolvedAttachment);
@ -908,7 +906,7 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
favourited: data.liked,
favourites_count: data.likeCount,
media_attachments: (data.attachments ?? []).map(
(a) => new Attachment(a).toApi() as ApiAttachment,
(a) => new Media(a).toApi() as ApiAttachment,
),
mentions: data.mentions.map((mention) => ({
id: mention.id,
@ -1014,7 +1012,7 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
},
},
attachments: (status.attachments ?? []).map((attachment) =>
new Attachment(attachment).toVersia(),
new Media(attachment).toVersia(),
),
is_sensitive: status.sensitive,
mentions: status.mentions.map((mention) =>