fix: optimize test infrastructure and fix missing brand migration
- Share PGlite instance per test file (TRUNCATE RESTART IDENTITY instead of creating new instance per test) — tests run in ~9s vs minutes - Add missing 'brand' column to items table migration - Fix corrupt 0002 snapshot (merge conflict artifacts) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ CREATE TABLE "global_item_tags" (
|
|||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
ALTER TABLE "items" ADD COLUMN "global_item_id" integer;--> statement-breakpoint
|
ALTER TABLE "items" ADD COLUMN "global_item_id" integer;--> statement-breakpoint
|
||||||
ALTER TABLE "items" ADD COLUMN "purchase_price_cents" integer;--> statement-breakpoint
|
ALTER TABLE "items" ADD COLUMN "purchase_price_cents" integer;--> statement-breakpoint
|
||||||
|
ALTER TABLE "items" ADD COLUMN "brand" text;--> statement-breakpoint
|
||||||
ALTER TABLE "thread_candidates" ADD COLUMN "global_item_id" integer;--> statement-breakpoint
|
ALTER TABLE "thread_candidates" ADD COLUMN "global_item_id" integer;--> statement-breakpoint
|
||||||
UPDATE "items" SET "global_item_id" = (
|
UPDATE "items" SET "global_item_id" = (
|
||||||
SELECT "global_item_id" FROM "item_global_links"
|
SELECT "global_item_id" FROM "item_global_links"
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
{
|
{
|
||||||
<<<<<<< HEAD
|
|
||||||
"id": "1c8fbda2-e486-4f57-a6d5-1a2e7042e413",
|
|
||||||
=======
|
|
||||||
"id": "4b01f839-a5ff-416c-826c-1e37e76d0a78",
|
"id": "4b01f839-a5ff-416c-826c-1e37e76d0a78",
|
||||||
>>>>>>> worktree-agent-adbc35a5
|
|
||||||
"prevId": "8fb47390-ff75-41f7-aa35-fad97b1a097e",
|
"prevId": "8fb47390-ff75-41f7-aa35-fad97b1a097e",
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"dialect": "postgresql",
|
"dialect": "postgresql",
|
||||||
@@ -140,69 +136,6 @@
|
|||||||
"checkConstraints": {},
|
"checkConstraints": {},
|
||||||
"isRLSEnabled": false
|
"isRLSEnabled": false
|
||||||
},
|
},
|
||||||
<<<<<<< HEAD
|
|
||||||
"public.global_item_tags": {
|
|
||||||
"name": "global_item_tags",
|
|
||||||
"schema": "",
|
|
||||||
"columns": {
|
|
||||||
"global_item_id": {
|
|
||||||
"name": "global_item_id",
|
|
||||||
"type": "integer",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"tag_id": {
|
|
||||||
"name": "tag_id",
|
|
||||||
"type": "integer",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"global_item_tags_global_item_id_global_items_id_fk": {
|
|
||||||
"name": "global_item_tags_global_item_id_global_items_id_fk",
|
|
||||||
"tableFrom": "global_item_tags",
|
|
||||||
"tableTo": "global_items",
|
|
||||||
"columnsFrom": [
|
|
||||||
"global_item_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"global_item_tags_tag_id_tags_id_fk": {
|
|
||||||
"name": "global_item_tags_tag_id_tags_id_fk",
|
|
||||||
"tableFrom": "global_item_tags",
|
|
||||||
"tableTo": "tags",
|
|
||||||
"columnsFrom": [
|
|
||||||
"tag_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {
|
|
||||||
"global_item_tags_global_item_id_tag_id_pk": {
|
|
||||||
"name": "global_item_tags_global_item_id_tag_id_pk",
|
|
||||||
"columns": [
|
|
||||||
"global_item_id",
|
|
||||||
"tag_id"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"uniqueConstraints": {},
|
|
||||||
"policies": {},
|
|
||||||
"checkConstraints": {},
|
|
||||||
"isRLSEnabled": false
|
|
||||||
},
|
|
||||||
=======
|
|
||||||
>>>>>>> worktree-agent-adbc35a5
|
|
||||||
"public.global_items": {
|
"public.global_items": {
|
||||||
"name": "global_items",
|
"name": "global_items",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
@@ -271,75 +204,6 @@
|
|||||||
"checkConstraints": {},
|
"checkConstraints": {},
|
||||||
"isRLSEnabled": false
|
"isRLSEnabled": false
|
||||||
},
|
},
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
"public.item_global_links": {
|
|
||||||
"name": "item_global_links",
|
|
||||||
"schema": "",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "serial",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"item_id": {
|
|
||||||
"name": "item_id",
|
|
||||||
"type": "integer",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"global_item_id": {
|
|
||||||
"name": "global_item_id",
|
|
||||||
"type": "integer",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"item_global_links_item_id_items_id_fk": {
|
|
||||||
"name": "item_global_links_item_id_items_id_fk",
|
|
||||||
"tableFrom": "item_global_links",
|
|
||||||
"tableTo": "items",
|
|
||||||
"columnsFrom": [
|
|
||||||
"item_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"item_global_links_global_item_id_global_items_id_fk": {
|
|
||||||
"name": "item_global_links_global_item_id_global_items_id_fk",
|
|
||||||
"tableFrom": "item_global_links",
|
|
||||||
"tableTo": "global_items",
|
|
||||||
"columnsFrom": [
|
|
||||||
"global_item_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {
|
|
||||||
"item_global_links_item_id_unique": {
|
|
||||||
"name": "item_global_links_item_id_unique",
|
|
||||||
"nullsNotDistinct": false,
|
|
||||||
"columns": [
|
|
||||||
"item_id"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"policies": {},
|
|
||||||
"checkConstraints": {},
|
|
||||||
"isRLSEnabled": false
|
|
||||||
},
|
|
||||||
>>>>>>> worktree-agent-adbc35a5
|
|
||||||
"public.items": {
|
"public.items": {
|
||||||
"name": "items",
|
"name": "items",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
@@ -411,21 +275,6 @@
|
|||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": 1
|
"default": 1
|
||||||
},
|
},
|
||||||
<<<<<<< HEAD
|
|
||||||
"global_item_id": {
|
|
||||||
"name": "global_item_id",
|
|
||||||
"type": "integer",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"purchase_price_cents": {
|
|
||||||
"name": "purchase_price_cents",
|
|
||||||
"type": "integer",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
=======
|
|
||||||
>>>>>>> worktree-agent-adbc35a5
|
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp",
|
||||||
@@ -439,6 +288,24 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"global_item_id": {
|
||||||
|
"name": "global_item_id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"purchase_price_cents": {
|
||||||
|
"name": "purchase_price_cents",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"brand": {
|
||||||
|
"name": "brand",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {},
|
"indexes": {},
|
||||||
@@ -468,22 +335,6 @@
|
|||||||
],
|
],
|
||||||
"onDelete": "no action",
|
"onDelete": "no action",
|
||||||
"onUpdate": "no action"
|
"onUpdate": "no action"
|
||||||
<<<<<<< HEAD
|
|
||||||
},
|
|
||||||
"items_global_item_id_global_items_id_fk": {
|
|
||||||
"name": "items_global_item_id_global_items_id_fk",
|
|
||||||
"tableFrom": "items",
|
|
||||||
"tableTo": "global_items",
|
|
||||||
"columnsFrom": [
|
|
||||||
"global_item_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "no action",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
=======
|
|
||||||
>>>>>>> worktree-agent-adbc35a5
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"compositePrimaryKeys": {},
|
"compositePrimaryKeys": {},
|
||||||
@@ -1020,15 +871,6 @@
|
|||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": 0
|
"default": 0
|
||||||
},
|
},
|
||||||
<<<<<<< HEAD
|
|
||||||
"global_item_id": {
|
|
||||||
"name": "global_item_id",
|
|
||||||
"type": "integer",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
=======
|
|
||||||
>>>>>>> worktree-agent-adbc35a5
|
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp",
|
||||||
@@ -1042,6 +884,12 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true,
|
"notNull": true,
|
||||||
"default": "now()"
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"global_item_id": {
|
||||||
|
"name": "global_item_id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {},
|
"indexes": {},
|
||||||
@@ -1071,22 +919,6 @@
|
|||||||
],
|
],
|
||||||
"onDelete": "no action",
|
"onDelete": "no action",
|
||||||
"onUpdate": "no action"
|
"onUpdate": "no action"
|
||||||
<<<<<<< HEAD
|
|
||||||
},
|
|
||||||
"thread_candidates_global_item_id_global_items_id_fk": {
|
|
||||||
"name": "thread_candidates_global_item_id_global_items_id_fk",
|
|
||||||
"tableFrom": "thread_candidates",
|
|
||||||
"tableTo": "global_items",
|
|
||||||
"columnsFrom": [
|
|
||||||
"global_item_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "no action",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
=======
|
|
||||||
>>>>>>> worktree-agent-adbc35a5
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"compositePrimaryKeys": {},
|
"compositePrimaryKeys": {},
|
||||||
|
|||||||
@@ -1,16 +1,51 @@
|
|||||||
import { PGlite } from "@electric-sql/pglite";
|
import { PGlite } from "@electric-sql/pglite";
|
||||||
|
import { sql } from "drizzle-orm";
|
||||||
import { drizzle } from "drizzle-orm/pglite";
|
import { drizzle } from "drizzle-orm/pglite";
|
||||||
import { migrate } from "drizzle-orm/pglite/migrator";
|
import { migrate } from "drizzle-orm/pglite/migrator";
|
||||||
import * as schema from "../../src/db/schema.ts";
|
import * as schema from "../../src/db/schema.ts";
|
||||||
|
|
||||||
type Db = ReturnType<typeof drizzle<typeof schema>>;
|
type Db = ReturnType<typeof drizzle<typeof schema>>;
|
||||||
|
|
||||||
export async function createTestDb() {
|
// Cache: one PGlite instance per test file (per worker)
|
||||||
const client = new PGlite();
|
let cachedClient: PGlite | null = null;
|
||||||
const db = drizzle(client, { schema });
|
let cachedDb: Db | null = null;
|
||||||
|
|
||||||
// Apply all migrations to create tables
|
async function getOrCreateDb(): Promise<Db> {
|
||||||
await migrate(db, { migrationsFolder: "./drizzle-pg" });
|
if (cachedDb) return cachedDb;
|
||||||
|
cachedClient = new PGlite();
|
||||||
|
cachedDb = drizzle(cachedClient, { schema });
|
||||||
|
await migrate(cachedDb, { migrationsFolder: "./drizzle-pg" });
|
||||||
|
return cachedDb;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truncation order respects foreign keys (children first)
|
||||||
|
const TRUNCATE_TABLES = [
|
||||||
|
"setup_items",
|
||||||
|
"setups",
|
||||||
|
"thread_candidates",
|
||||||
|
"threads",
|
||||||
|
"items",
|
||||||
|
"global_item_tags",
|
||||||
|
"global_items",
|
||||||
|
"tags",
|
||||||
|
"oauth_tokens",
|
||||||
|
"oauth_codes",
|
||||||
|
"oauth_clients",
|
||||||
|
"api_keys",
|
||||||
|
"settings",
|
||||||
|
"categories",
|
||||||
|
"users",
|
||||||
|
];
|
||||||
|
|
||||||
|
export async function createTestDb() {
|
||||||
|
const db = await getOrCreateDb();
|
||||||
|
|
||||||
|
// Truncate all tables and reset sequences (fast reset, no PGlite restart)
|
||||||
|
for (const t of TRUNCATE_TABLES) {
|
||||||
|
await db.execute(
|
||||||
|
sql.raw(`TRUNCATE TABLE "${t}" RESTART IDENTITY CASCADE`),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Seed a test user
|
// Seed a test user
|
||||||
const [user] = await db
|
const [user] = await db
|
||||||
|
|||||||
Reference in New Issue
Block a user