53 lines
1.6 KiB
TypeScript
53 lines
1.6 KiB
TypeScript
|
|
/**
|
|||
|
|
* Dev-only smoke check for the berth recommender. Resolves the first
|
|||
|
|
* port-nimara interest (with desired dims set) and prints the top-N
|
|||
|
|
* recommendations.
|
|||
|
|
*
|
|||
|
|
* pnpm tsx scripts/dev-recommender-smoke.ts
|
|||
|
|
*/
|
|||
|
|
import 'dotenv/config';
|
|||
|
|
import { eq, isNotNull, and } from 'drizzle-orm';
|
|||
|
|
|
|||
|
|
import { db } from '@/lib/db';
|
|||
|
|
import { ports } from '@/lib/db/schema/ports';
|
|||
|
|
import { interests } from '@/lib/db/schema/interests';
|
|||
|
|
import { recommendBerths } from '@/lib/services/berth-recommender.service';
|
|||
|
|
|
|||
|
|
async function main() {
|
|||
|
|
const [port] = await db
|
|||
|
|
.select({ id: ports.id })
|
|||
|
|
.from(ports)
|
|||
|
|
.where(eq(ports.slug, 'port-nimara'))
|
|||
|
|
.limit(1);
|
|||
|
|
if (!port) throw new Error('port-nimara not found');
|
|||
|
|
|
|||
|
|
const [interest] = await db
|
|||
|
|
.select({ id: interests.id })
|
|||
|
|
.from(interests)
|
|||
|
|
.where(and(eq(interests.portId, port.id), isNotNull(interests.desiredLengthFt)))
|
|||
|
|
.limit(1);
|
|||
|
|
if (!interest) throw new Error('No interest with desired dims set');
|
|||
|
|
|
|||
|
|
console.log(`> Recommending berths for interest ${interest.id} on port ${port.id}…`);
|
|||
|
|
const recs = await recommendBerths({
|
|||
|
|
interestId: interest.id,
|
|||
|
|
portId: port.id,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
console.log(`> ${recs.length} recommendations:`);
|
|||
|
|
for (const r of recs) {
|
|||
|
|
console.log(
|
|||
|
|
` ${r.mooringNumber.padEnd(5)} tier=${r.tier} fit=${r.fitScore} ` +
|
|||
|
|
`${r.lengthFt}×${r.widthFt}×${r.draftFt} ft buf=${r.sizeBufferPct}% ` +
|
|||
|
|
`${r.reasons.dimensional}; ${r.reasons.pipeline}`,
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
main()
|
|||
|
|
.then(() => process.exit(0))
|
|||
|
|
.catch((err) => {
|
|||
|
|
console.error(err);
|
|||
|
|
process.exit(1);
|
|||
|
|
});
|