0ac4beaaa8
- Add requireAuth() to admin-permissions.ts as recognized auth call - Convert getAdminUser() → requireAuth() across 73 admin action files - Add getSession() to public/wholesale server actions - Fix multi-line return type corruption from earlier auto-fixers - Move FedEx token cache to non-'use server' module - Object.freeze module-level constants: PRICE_KEYS, EMPTY_MOBILE_DASHBOARD, EMPTY_PAY_PERIOD, LOCALE_CART_SUBJECT, WELCOME_EMAILS - Update Stripe API version 2026-05-27 → 2026-06-24 - Fix wholesale employee portal: getEmployeeSessionAction + EmployeePortalClient - Fix 51 TypeScript errors (return type corruption, missing imports)
79 lines
2.5 KiB
TypeScript
79 lines
2.5 KiB
TypeScript
/**
|
|
* Cleanup script: remove duplicate stops from the Tuxedo Corn 2026 tour.
|
|
* Keeps the row with the latest created_at per (brand_id, date, city, state, location, time).
|
|
* Run: DATABASE_URL="postgresql://..." npx tsx scripts/cleanup-duplicate-stops.ts
|
|
*/
|
|
import { Pool } from "pg";
|
|
|
|
const pool = new Pool({
|
|
connectionString:
|
|
process.env.DATABASE_ADMIN_URL ??
|
|
process.env.DATABASE_URL ??
|
|
"postgres://postgres:postgres@localhost:5432/route_commerce",
|
|
});
|
|
|
|
async function main() {
|
|
const client = await pool.connect();
|
|
try {
|
|
await client.query("BEGIN");
|
|
|
|
// Find duplicate groups (same brand_id, date, city, state, location, time)
|
|
const dupes = await client.query(`
|
|
SELECT brand_id::text, date, city, state, location, time, count(*) as cnt, min(created_at::text) as oldest, max(created_at::text) as newest
|
|
FROM stops
|
|
WHERE deleted_at IS NULL
|
|
GROUP BY brand_id, date, city, state, location, time
|
|
HAVING count(*) > 1
|
|
ORDER BY date, city
|
|
`);
|
|
|
|
console.log(`Found ${dupes.rowCount} duplicate groups`);
|
|
if (dupes.rowCount === 0) {
|
|
await client.query("COMMIT");
|
|
console.log("No duplicates found.");
|
|
return;
|
|
}
|
|
|
|
let totalDeleted = 0;
|
|
for (const row of dupes.rows) {
|
|
// Keep the row with the latest created_at, delete the rest
|
|
const del = await client.query(`
|
|
DELETE FROM stops
|
|
WHERE brand_id = $1
|
|
AND date = $2
|
|
AND city = $3
|
|
AND state = $4
|
|
AND location = $5
|
|
AND time IS NOT DISTINCT FROM $6
|
|
AND deleted_at IS NULL
|
|
AND created_at < (
|
|
SELECT max(created_at) FROM stops s2
|
|
WHERE s2.brand_id = stops.brand_id
|
|
AND s2.date = stops.date
|
|
AND s2.city = stops.city
|
|
AND s2.state = stops.state
|
|
AND s2.location = stops.location
|
|
AND (s2.time IS NOT DISTINCT FROM stops.time)
|
|
AND s2.deleted_at IS NULL
|
|
)
|
|
`, [row.brand_id, row.date, row.city, row.state, row.location, row.time]);
|
|
totalDeleted += del.rowCount ?? 0;
|
|
console.log(` Deleted ${del.rowCount} duplicate(s) for ${row.city}, ${row.state} on ${row.date}`);
|
|
}
|
|
|
|
await client.query("COMMIT");
|
|
console.log(`\nDone. Total duplicates removed: ${totalDeleted}`);
|
|
} catch (e) {
|
|
await client.query("ROLLBACK");
|
|
throw e;
|
|
} finally {
|
|
client.release();
|
|
await pool.end();
|
|
}
|
|
}
|
|
|
|
main().catch((e) => {
|
|
console.error(e);
|
|
process.exit(1);
|
|
});
|