src/databases/officer_db/src/<feature>/{schema.ts,queries.ts}, replacing the
parallel schema/ and queries/ trees. 24 feature directories, 46 files moved with
git mv so history follows.
The parallel trees had drifted, which is what the restructure is really fixing:
four features were named differently on each side — app-store/sidecar-installs,
email/email-accounts, server/server-config
operations had a schema and NO query file: its task_logs is reached directly
from src/servers/api/task-logger.ts, bypassing this package's own boundary
integrations had queries and NO schema, because it spans two features'
tables — server_integrations and user_integrations
Both lopsided cases survive as directories holding one file, which states the
problem instead of hiding it across two trees.
Nothing outside the package changed how it imports. `officerdb`, `officerdb/types`
and `officerdb/db` resolve exactly as before; index.ts absorbed the path changes.
Added `"./*": "./src/*"` so the new layout is reachable — `officerdb/soulseek/schema`
— which one script needed, because soulseek is a plugin and therefore commented
out of the aggregator.
schema/index.ts became src/schema.ts, keeping the core/plugin split from earlier
tonight. drizzle.config.ts and the package's "./schema" export follow it.
Verified rather than assumed: all 52 files in the package parse, every relative
import resolves against the new layout (checked by walking each specifier to a
real file, since parsing does not check paths), and everything in the tree
importing officerdb still parses. Not typechecked — empty node_modules, frozen
installs.
One rewrite bug worth recording: the rule mapping a query module's sibling import
also matched the './schema' this pass had just written, turning it into
'../schema/queries' in 22 files. Caught by the resolver check, not by parsing —
both spellings parse fine.
Also corrects every path reference the move invalidated: src/databases/CLAUDE.md's
layout diagram, the root CLAUDE.md data section, three docs, and seven sidecar
comments naming queries/<x>.ts.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
53 lines
2.1 KiB
TypeScript
53 lines
2.1 KiB
TypeScript
// Re-derive the stored tree shape for every cached share snapshot, from the folder rows already in
|
|
// Postgres — no peer contact, so it works with everyone offline and is deterministic.
|
|
//
|
|
// Written for the backfill when the tree columns were added, but kept because it's the answer to any
|
|
// future change in tree shape: it runs the SAME buildTree + finishSoulseekBrowse the sidecar's ingest
|
|
// runs, so there's no second implementation to drift.
|
|
//
|
|
// bun scripts/rebuild-soulseek-tree.ts
|
|
|
|
import type { BrowsedFile } from 'officerdb';
|
|
import { eq, asc } from 'drizzle-orm';
|
|
import { db, finishSoulseekBrowse } from 'officerdb';
|
|
// soulseek is a plugin, so its tables are commented out of officerdb's schema aggregator —
|
|
// import them from the feature directly.
|
|
import { soulseekBrowseSnapshots, soulseekBrowseDirs } from 'officerdb/soulseek/schema';
|
|
import { buildTree } from '../src/servers/sidecar/slskd/browse';
|
|
|
|
const snapshots = await db
|
|
.select({
|
|
id: soulseekBrowseSnapshots.id,
|
|
userId: soulseekBrowseSnapshots.userId,
|
|
username: soulseekBrowseSnapshots.username,
|
|
status: soulseekBrowseSnapshots.status,
|
|
})
|
|
.from(soulseekBrowseSnapshots)
|
|
.orderBy(asc(soulseekBrowseSnapshots.id));
|
|
|
|
console.log(`${snapshots.length} snapshot(s) to rebuild`);
|
|
|
|
for (const snap of snapshots) {
|
|
const started = Date.now();
|
|
const rows = await db
|
|
.select({ name: soulseekBrowseDirs.name, files: soulseekBrowseDirs.files })
|
|
.from(soulseekBrowseDirs)
|
|
.where(eq(soulseekBrowseDirs.snapshotId, snap.id));
|
|
|
|
if (!rows.length) {
|
|
console.log(` #${snap.id} ${snap.username}: no folder rows, skipped`);
|
|
continue;
|
|
}
|
|
|
|
const tree = buildTree(rows.map((r) => ({ name: r.name, files: r.files as BrowsedFile[] })));
|
|
await finishSoulseekBrowse(snap.id, tree);
|
|
const roots = tree.filter((t) => t.parentPath === null);
|
|
console.log(
|
|
` #${snap.id} ${snap.username}: ${rows.length} -> ${tree.length} rows ` +
|
|
`(+${tree.length - rows.length} synthesized), ${roots.length} root(s), ` +
|
|
`${roots.reduce((n, r) => n + r.subtreeFileCount, 0)} files, ${Date.now() - started}ms`,
|
|
);
|
|
}
|
|
|
|
process.exit(0);
|