Browse Source

refactor(db): rename post_media_refs to media_refs

Made-with: Cursor
main
npmrun 3 hours ago
parent
commit
03ceb6a2bd
  1. 6
      packages/drizzle-pkg/database/sqlite/schema/content.ts
  2. BIN
      packages/drizzle-pkg/db.sqlite
  3. 2
      packages/drizzle-pkg/lib/schema/content.ts
  4. 3
      packages/drizzle-pkg/migrations/0004_rename_post_media_refs_to_media_refs.sql
  5. 1135
      packages/drizzle-pkg/migrations/meta/0004_snapshot.json
  6. 7
      packages/drizzle-pkg/migrations/meta/_journal.json
  7. 26
      server/service/media/index.ts
  8. 12
      server/service/media/storage-audit.ts
  9. 8
      server/service/posts/index.ts

6
packages/drizzle-pkg/database/sqlite/schema/content.ts

@ -58,8 +58,8 @@ export const mediaAssets = sqliteTable(
],
);
export const postMediaRefs = sqliteTable(
"post_media_refs",
export const mediaRefs = sqliteTable(
"media_refs",
{
postId: integer("post_id")
.notNull()
@ -70,7 +70,7 @@ export const postMediaRefs = sqliteTable(
},
(table) => [
primaryKey({ columns: [table.postId, table.assetId] }),
index("post_media_refs_asset_id_idx").on(table.assetId),
index("media_refs_asset_id_idx").on(table.assetId),
],
);

BIN
packages/drizzle-pkg/db.sqlite

Binary file not shown.

2
packages/drizzle-pkg/lib/schema/content.ts

@ -1 +1 @@
export { mediaAssets, postComments, postMediaRefs, posts, timelineEvents } from "../../database/sqlite/schema/content";
export { mediaAssets, mediaRefs, postComments, posts, timelineEvents } from "../../database/sqlite/schema/content";

3
packages/drizzle-pkg/migrations/0004_rename_post_media_refs_to_media_refs.sql

@ -0,0 +1,3 @@
ALTER TABLE `post_media_refs` RENAME TO `media_refs`;--> statement-breakpoint
DROP INDEX `post_media_refs_asset_id_idx`;--> statement-breakpoint
CREATE INDEX `media_refs_asset_id_idx` ON `media_refs` (`asset_id`);

1135
packages/drizzle-pkg/migrations/meta/0004_snapshot.json

File diff suppressed because it is too large

7
packages/drizzle-pkg/migrations/meta/_journal.json

@ -29,6 +29,13 @@
"when": 1776516043018,
"tag": "0003_media-assets",
"breakpoints": true
},
{
"idx": 4,
"version": "6",
"when": 1776600000000,
"tag": "0004_rename_post_media_refs_to_media_refs",
"breakpoints": true
}
]
}

26
server/service/media/index.ts

@ -1,7 +1,7 @@
import fs from "node:fs";
import path from "node:path";
import { dbGlobal } from "drizzle-pkg/lib/db";
import { mediaAssets, postMediaRefs } from "drizzle-pkg/lib/schema/content";
import { mediaAssets, mediaRefs } from "drizzle-pkg/lib/schema/content";
import { and, count, desc, eq, inArray, isNotNull, isNull, lte, not, notExists, or, sql } from "drizzle-orm";
import {
MEDIA_ORPHAN_GRACE_HOURS_AFTER_DEREF,
@ -104,7 +104,7 @@ export function computeOrphanGraceExpiresAt(row: {
function orphanCondition() {
return notExists(
dbGlobal.select({ x: sql`1` }).from(postMediaRefs).where(eq(postMediaRefs.assetId, mediaAssets.id)),
dbGlobal.select({ x: sql`1` }).from(mediaRefs).where(eq(mediaRefs.assetId, mediaAssets.id)),
);
}
@ -147,8 +147,8 @@ export async function reconcileAssetTimestampsAfterRefChange(assetIds: number[])
for (const id of unique) {
const [{ c }] = await dbGlobal
.select({ c: count() })
.from(postMediaRefs)
.where(eq(postMediaRefs.assetId, id));
.from(mediaRefs)
.where(eq(mediaRefs.assetId, id));
if (c > 0) {
const [row] = await dbGlobal.select().from(mediaAssets).where(eq(mediaAssets.id, id)).limit(1);
@ -189,12 +189,12 @@ export async function syncPostMediaRefs(
coverUrl: string | null,
): Promise<void> {
const beforeRows = await dbGlobal
.select({ assetId: postMediaRefs.assetId })
.from(postMediaRefs)
.where(eq(postMediaRefs.postId, postId));
.select({ assetId: mediaRefs.assetId })
.from(mediaRefs)
.where(eq(mediaRefs.postId, postId));
const beforeIds = beforeRows.map((r) => r.assetId);
await dbGlobal.delete(postMediaRefs).where(eq(postMediaRefs.postId, postId));
await dbGlobal.delete(mediaRefs).where(eq(mediaRefs.postId, postId));
const urls = mergePostMediaUrls(bodyMarkdown, coverUrl);
const keys = [...new Set(urls.map((u) => publicAssetUrlToStorageKey(u)).filter((k): k is string => k != null))];
@ -208,7 +208,7 @@ export async function syncPostMediaRefs(
afterIds = assetRows.map((r) => r.id);
if (afterIds.length > 0) {
await dbGlobal
.insert(postMediaRefs)
.insert(mediaRefs)
.values(afterIds.map((assetId) => ({ postId, assetId })))
.onConflictDoNothing();
}
@ -285,8 +285,8 @@ export async function listOrphanCandidatesForUser(
async function assertAssetDeletableOrThrow(row: typeof mediaAssets.$inferSelect): Promise<void> {
const [{ c }] = await dbGlobal
.select({ c: count() })
.from(postMediaRefs)
.where(eq(postMediaRefs.assetId, row.id));
.from(mediaRefs)
.where(eq(mediaRefs.assetId, row.id));
if (c > 0) {
throw createError({ statusCode: 400, statusMessage: "资源仍被文章引用,无法删除" });
}
@ -328,8 +328,8 @@ export async function purgeAllDeletableOrphansGlobally(limit: number): Promise<n
for (const row of candidates) {
const [{ c }] = await dbGlobal
.select({ c: count() })
.from(postMediaRefs)
.where(eq(postMediaRefs.assetId, row.id));
.from(mediaRefs)
.where(eq(mediaRefs.assetId, row.id));
if (c > 0) {
continue;
}

12
server/service/media/storage-audit.ts

@ -1,7 +1,7 @@
import fs from "node:fs";
import path from "node:path";
import { dbGlobal } from "drizzle-pkg/lib/db";
import { mediaAssets, postMediaRefs } from "drizzle-pkg/lib/schema/content";
import { mediaAssets, mediaRefs } from "drizzle-pkg/lib/schema/content";
import { count, eq } from "drizzle-orm";
import { RELATIVE_ASSETS_DIR } from "#server/constants/media";
@ -57,11 +57,11 @@ export async function auditMediaStorageVsDb(): Promise<StorageAuditResult> {
const refAgg = await dbGlobal
.select({
assetId: postMediaRefs.assetId,
assetId: mediaRefs.assetId,
c: count(),
})
.from(postMediaRefs)
.groupBy(postMediaRefs.assetId);
.from(mediaRefs)
.groupBy(mediaRefs.assetId);
const refMap = new Map<number, number>();
for (const r of refAgg) {
@ -167,8 +167,8 @@ export async function removeUnreferencedDbRowsForMissingFiles(): Promise<{
}
const [{ n }] = await dbGlobal
.select({ n: count() })
.from(postMediaRefs)
.where(eq(postMediaRefs.assetId, c.id));
.from(mediaRefs)
.where(eq(mediaRefs.assetId, c.id));
if (n > 0) {
continue;
}

8
server/service/posts/index.ts

@ -1,5 +1,5 @@
import { dbGlobal } from "drizzle-pkg/lib/db";
import { postMediaRefs, posts } from "drizzle-pkg/lib/schema/content";
import { mediaRefs, posts } from "drizzle-pkg/lib/schema/content";
import { reconcileAssetTimestampsAfterRefChange, syncPostMediaRefs } from "#server/service/media";
import { users } from "drizzle-pkg/lib/schema/auth";
import { and, count, desc, eq } from "drizzle-orm";
@ -121,9 +121,9 @@ export async function deletePost(userId: number, id: number) {
return false;
}
const refRows = await dbGlobal
.select({ assetId: postMediaRefs.assetId })
.from(postMediaRefs)
.where(eq(postMediaRefs.postId, id));
.select({ assetId: mediaRefs.assetId })
.from(mediaRefs)
.where(eq(mediaRefs.postId, id));
const touched = refRows.map((r) => r.assetId);
await dbGlobal.delete(posts).where(and(eq(posts.id, id), eq(posts.userId, userId)));
await reconcileAssetTimestampsAfterRefChange(touched);

Loading…
Cancel
Save