/** * Import tasks, goals and areas into the private `tasks` schema (idempotent). * * bun scripts/tasks-import.ts data/tasks/daisy-import.json # insert what is missing * bun scripts/tasks-import.ts --dry-run data/tasks/daisy-import.json # validate only * bun scripts/tasks-import.ts --update data/tasks/daisy-import.json # also overwrite existing rows * * Dedupe: areas on slug, goals on title, tasks on area + title (case-insensitive). * Uses DB_URL (the app role on prod, personal_dev on dev). */ import { readFile } from 'node:fs/promises'; import { drizzle } from 'drizzle-orm/postgres-js'; import postgres from 'postgres'; import { importSeed, seedFile } from '../src/lib/server/tasks'; const args = process.argv.slice(2); const dryRun = args.includes('--dry-run'); const update = args.includes('--update'); const files = args.filter((a) => !a.startsWith('--')); if (files.length !== 1) { console.error('usage: bun scripts/tasks-import.ts [--dry-run] [--update] '); process.exit(2); } const parsed = seedFile.safeParse(JSON.parse(await readFile(files[0], 'utf8'))); if (!parsed.success) { for (const issue of parsed.error.issues.slice(0, 50)) console.error(`${issue.path.join('.')}: ${issue.message}`); process.exit(1); } const seed = parsed.data; console.log( `Valid: ${seed.areas.length} areas, ${seed.goals.length} goals, ${seed.tasks.length} tasks` ); if (dryRun) process.exit(0); if (!process.env.DB_URL) throw new Error('DB_URL is required'); const client = postgres(process.env.DB_URL, { max: 1, onnotice: () => {} }); try { const r = await importSeed(drizzle({ client }), seed, { update }); console.log( `areas: ${r.areas.inserted} inserted, ${r.areas.existing} existing; ` + `goals: ${r.goals.inserted} inserted, ${r.goals.existing} existing, ${r.goals.updated} updated; ` + `tasks: ${r.tasks.inserted} inserted, ${r.tasks.existing} existing, ${r.tasks.updated} updated` ); } finally { await client.end(); }