import type { Attachment } from "@/lib/chat/types";
import type { ValidatedAttachment } from "@/lib/chat/attachments";
import type { Queryable } from "@/lib/db/types";
type AttachmentRow = {
id: string;
original_name: string;
content_type: string;
byte_size: number;
gate_file_id: string | null;
object_key: string | null;
};
export type StoredAttachment = Attachment & {
gateFileId: string | null;
objectKey: string | null;
};
export type GateAttachmentMetadata = ValidatedAttachment & { gateFileId: string };
export async function createPendingAttachment(
database: Queryable,
userId: string,
attachment: GateAttachmentMetadata,
): Promise<StoredAttachment> {
const result = await database.query<AttachmentRow>(
`INSERT INTO chat_attachments (user_id, original_name, content_type, byte_size, gate_file_id, state, expires_at)
VALUES ($1::uuid, $2, $3, $4, $5, 'pending', now() + interval '24 hours')
RETURNING id, original_name, content_type, byte_size, gate_file_id, object_key`,
[userId, attachment.name, attachment.contentType, attachment.size, attachment.gateFileId],
);
return mapStoredAttachment(result.rows[0]);
}
export async function getOwnedAttachment(
database: Queryable,
userId: string,
id: string,
): Promise<StoredAttachment | null> {
const result = await database.query<AttachmentRow>(
`SELECT id, original_name, content_type, byte_size, gate_file_id, object_key
FROM chat_attachments WHERE id = $1 AND user_id = $2`,
[id, userId],
);
return result.rows[0] ? mapStoredAttachment(result.rows[0]) : null;
}
export async function attachPendingAttachments(
database: Queryable,
userId: string,
messageId: string,
ids: string[],
): Promise<StoredAttachment[]> {
if (ids.length !== new Set(ids).size) throw new Error("Duplicate attachment IDs");
const result = await database.query<AttachmentRow>(
`UPDATE chat_attachments
SET message_id = $3, state = 'attached', expires_at = 'infinity'
WHERE id = ANY($1::uuid[]) AND user_id = $2 AND state = 'pending' AND expires_at > now()
RETURNING id, original_name, content_type, byte_size, gate_file_id, object_key`,
[ids, userId, messageId],
);
if (result.rows.length !== ids.length) throw new Error("Attachment not found");
return result.rows.map(mapStoredAttachment);
}
function mapAttachment(row: AttachmentRow): Attachment {
return { id: row.id, name: row.original_name, contentType: row.content_type, size: Number(row.byte_size) };
}
function mapStoredAttachment(row: AttachmentRow): StoredAttachment {
return {
...mapAttachment(row),
gateFileId: row.gate_file_id,
objectKey: row.object_key,
};
}