Commit the first migration, and apply schema the same way everywhere
`drizzle/` was gitignored, so every environment re-derived the schema from src/db/schema and nothing recorded what a given release expected. That is survivable while nothing is deployed and a problem the moment something is. The generated migration is now committed: four tables, three enums, five foreign keys, and the per-farm unique index on gateway_printer_id. It needed one hand-added line to be usable on its own. drizzle-kit does not emit extension statements, but frame_embeddings.embedding is vector(512) with an ivfflat index, so as generated the migration only applied to a database somebody had already run `CREATE EXTENSION vector` on - which was true locally precisely because dev-env.sh does that, and would not have been true on a fresh deploy. `CREATE EXTENSION IF NOT EXISTS vector` now leads the file, and it survives regeneration: drizzle only appends new migrations, and the diffing snapshot lives in meta/0000_snapshot.json rather than in the SQL. Verified by dropping the database, recreating it with no extensions at all (`pg_extension` count 0), and running db:migrate: the extension and all four tables were created, `db:generate` then reported no pending changes, and the e2e script still passed against both live printers on the result. `dev-env.sh schema` now runs `migrate` instead of `push`, so a local database and a deployed one get the schema by the same route - testing `push` locally while production runs `migrate` tests two different things. `push` is still available as its own command for iterating on a table that is still moving, with a comment about what it does not record.
This commit is contained in:
@@ -4,6 +4,5 @@ bun.lockb
|
|||||||
bun.lock
|
bun.lock
|
||||||
.env
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
drizzle/
|
|
||||||
*.log
|
*.log
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ with pgvector for frame embeddings), Valkey Streams, and Cloudflare R2 storage.
|
|||||||
```sh
|
```sh
|
||||||
bun install
|
bun install
|
||||||
scripts/dev-env.sh up # Valkey + Postgres/pgvector, and print the URLs
|
scripts/dev-env.sh up # Valkey + Postgres/pgvector, and print the URLs
|
||||||
scripts/dev-env.sh schema # or: bun run db:migrate
|
scripts/dev-env.sh schema # apply drizzle/ - same as bun run db:migrate
|
||||||
cp .env.example .env # fill in the URLs it printed, plus R2_*, SUPABASE_JWT_SECRET
|
cp .env.example .env # fill in the URLs it printed, plus R2_*, SUPABASE_JWT_SECRET
|
||||||
bun run dev
|
bun run dev
|
||||||
```
|
```
|
||||||
@@ -20,6 +20,16 @@ dockerd needs `CAP_NET_ADMIN` for its bridge and user namespaces to unpack an
|
|||||||
image, and neither can be granted from inside. `scripts/dev-env.sh status`
|
image, and neither can be granted from inside. `scripts/dev-env.sh status`
|
||||||
says which backend is in use.
|
says which backend is in use.
|
||||||
|
|
||||||
|
Schema changes go through migrations: edit `src/db/schema/`, run
|
||||||
|
`bun run db:generate`, and commit the file it writes to `drizzle/` along with
|
||||||
|
the schema change. `scripts/dev-env.sh push` reshapes a local database straight
|
||||||
|
from the schema with no migration file, which is faster while a table is still
|
||||||
|
moving but records nothing and will drop a column to make things match - so
|
||||||
|
generate before committing. `drizzle/0000_*.sql` creates the `vector` extension
|
||||||
|
itself; that line is hand-added, since drizzle-kit does not emit extension
|
||||||
|
statements and the migration would otherwise only apply to a database somebody
|
||||||
|
had already prepared.
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -61,8 +71,9 @@ Valkey and Postgres+pgvector for local development.
|
|||||||
(`"p1p"`) onto rows here; telemetry for an unclaimed id is logged and skipped,
|
(`"p1p"`) onto rows here; telemetry for an unclaimed id is logged and skipped,
|
||||||
never inserted.
|
never inserted.
|
||||||
|
|
||||||
`frame_embeddings.embedding` requires the `vector` extension:
|
`frame_embeddings.embedding` requires the `vector` extension. The first
|
||||||
`CREATE EXTENSION IF NOT EXISTS vector;` (`scripts/dev-env.sh up` does this).
|
migration creates it, and `scripts/dev-env.sh up` also does so for the `push`
|
||||||
|
path, which does not run migrations.
|
||||||
|
|
||||||
## Dependency pins
|
## Dependency pins
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
-- Hand-added to the generated migration: drizzle-kit does not emit extension
|
||||||
|
-- statements, but frame_embeddings.embedding is vector(512) and its index is
|
||||||
|
-- ivfflat, so this migration cannot apply to a database without pgvector. A
|
||||||
|
-- committed migration has to stand on its own - relying on whoever set the
|
||||||
|
-- database up having run this first is how a deploy fails.
|
||||||
|
--
|
||||||
|
-- Safe to keep across regeneration: drizzle only ever appends new files, and
|
||||||
|
-- the diffing snapshot lives in meta/0000_snapshot.json, not here.
|
||||||
|
CREATE EXTENSION IF NOT EXISTS vector;
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
CREATE TYPE "public"."printer_status" AS ENUM('offline', 'idle', 'printing', 'paused', 'error', 'maintenance');
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
CREATE TYPE "public"."printer_vendor" AS ENUM('bambu', 'prusa', 'klipper');
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
CREATE TYPE "public"."print_job_status" AS ENUM('queued', 'uploading', 'printing', 'paused', 'completed', 'failed', 'cancelled');
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE IF NOT EXISTS "farms" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"owner_id" uuid NOT NULL,
|
||||||
|
"edge_proxy_token" text NOT NULL,
|
||||||
|
"location" text,
|
||||||
|
"settings" jsonb DEFAULT '{}'::jsonb,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE IF NOT EXISTS "printers" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"farm_id" uuid NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"vendor" "printer_vendor" NOT NULL,
|
||||||
|
"status" "printer_status" DEFAULT 'offline' NOT NULL,
|
||||||
|
"lan_address" text,
|
||||||
|
"serial_number" text,
|
||||||
|
"access_code" text,
|
||||||
|
"gateway_printer_id" text,
|
||||||
|
"nozzle_temp_c" real,
|
||||||
|
"nozzle_target_temp_c" real,
|
||||||
|
"bed_temp_c" real,
|
||||||
|
"bed_target_temp_c" real,
|
||||||
|
"progress_percent" integer,
|
||||||
|
"current_layer" integer,
|
||||||
|
"total_layers" integer,
|
||||||
|
"remaining_minutes" integer,
|
||||||
|
"current_job_name" text,
|
||||||
|
"active_alerts" integer,
|
||||||
|
"vendor_state" text,
|
||||||
|
"vendor_error_code" integer,
|
||||||
|
"metadata" jsonb DEFAULT '{}'::jsonb,
|
||||||
|
"last_seen_at" timestamp with time zone,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE IF NOT EXISTS "print_jobs" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"farm_id" uuid NOT NULL,
|
||||||
|
"printer_id" uuid,
|
||||||
|
"file_name" text NOT NULL,
|
||||||
|
"r2_object_key" text NOT NULL,
|
||||||
|
"status" "print_job_status" DEFAULT 'queued' NOT NULL,
|
||||||
|
"progress_pct" real DEFAULT 0 NOT NULL,
|
||||||
|
"estimated_time_s" real,
|
||||||
|
"elapsed_time_s" real,
|
||||||
|
"submitted_by" uuid NOT NULL,
|
||||||
|
"metadata" jsonb DEFAULT '{}'::jsonb,
|
||||||
|
"started_at" timestamp with time zone,
|
||||||
|
"completed_at" timestamp with time zone,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE IF NOT EXISTS "frame_embeddings" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"print_job_id" uuid NOT NULL,
|
||||||
|
"printer_id" uuid NOT NULL,
|
||||||
|
"r2_object_key" text NOT NULL,
|
||||||
|
"embedding" vector(512) NOT NULL,
|
||||||
|
"captured_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "printers" ADD CONSTRAINT "printers_farm_id_farms_id_fk" FOREIGN KEY ("farm_id") REFERENCES "public"."farms"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "print_jobs" ADD CONSTRAINT "print_jobs_farm_id_farms_id_fk" FOREIGN KEY ("farm_id") REFERENCES "public"."farms"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "print_jobs" ADD CONSTRAINT "print_jobs_printer_id_printers_id_fk" FOREIGN KEY ("printer_id") REFERENCES "public"."printers"("id") ON DELETE set null ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "frame_embeddings" ADD CONSTRAINT "frame_embeddings_print_job_id_print_jobs_id_fk" FOREIGN KEY ("print_job_id") REFERENCES "public"."print_jobs"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "frame_embeddings" ADD CONSTRAINT "frame_embeddings_printer_id_printers_id_fk" FOREIGN KEY ("printer_id") REFERENCES "public"."printers"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS "printers_farm_gateway_printer_id_idx" ON "printers" USING btree ("farm_id","gateway_printer_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX IF NOT EXISTS "frame_embeddings_embedding_ivfflat_idx" ON "frame_embeddings" USING ivfflat ("embedding" vector_cosine_ops) WITH (lists=100);
|
||||||
@@ -0,0 +1,544 @@
|
|||||||
|
{
|
||||||
|
"id": "f60fed84-9b69-403f-a789-9e29cee970f1",
|
||||||
|
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"tables": {
|
||||||
|
"public.farms": {
|
||||||
|
"name": "farms",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"owner_id": {
|
||||||
|
"name": "owner_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"edge_proxy_token": {
|
||||||
|
"name": "edge_proxy_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"name": "location",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"name": "settings",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "'{}'::jsonb"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"public.printers": {
|
||||||
|
"name": "printers",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"farm_id": {
|
||||||
|
"name": "farm_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"vendor": {
|
||||||
|
"name": "vendor",
|
||||||
|
"type": "printer_vendor",
|
||||||
|
"typeSchema": "public",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "printer_status",
|
||||||
|
"typeSchema": "public",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'offline'"
|
||||||
|
},
|
||||||
|
"lan_address": {
|
||||||
|
"name": "lan_address",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"serial_number": {
|
||||||
|
"name": "serial_number",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"access_code": {
|
||||||
|
"name": "access_code",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"gateway_printer_id": {
|
||||||
|
"name": "gateway_printer_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"nozzle_temp_c": {
|
||||||
|
"name": "nozzle_temp_c",
|
||||||
|
"type": "real",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"nozzle_target_temp_c": {
|
||||||
|
"name": "nozzle_target_temp_c",
|
||||||
|
"type": "real",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"bed_temp_c": {
|
||||||
|
"name": "bed_temp_c",
|
||||||
|
"type": "real",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"bed_target_temp_c": {
|
||||||
|
"name": "bed_target_temp_c",
|
||||||
|
"type": "real",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"progress_percent": {
|
||||||
|
"name": "progress_percent",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"current_layer": {
|
||||||
|
"name": "current_layer",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"total_layers": {
|
||||||
|
"name": "total_layers",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"remaining_minutes": {
|
||||||
|
"name": "remaining_minutes",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"current_job_name": {
|
||||||
|
"name": "current_job_name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"active_alerts": {
|
||||||
|
"name": "active_alerts",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"vendor_state": {
|
||||||
|
"name": "vendor_state",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"vendor_error_code": {
|
||||||
|
"name": "vendor_error_code",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"name": "metadata",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "'{}'::jsonb"
|
||||||
|
},
|
||||||
|
"last_seen_at": {
|
||||||
|
"name": "last_seen_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"printers_farm_gateway_printer_id_idx": {
|
||||||
|
"name": "printers_farm_gateway_printer_id_idx",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "farm_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression": "gateway_printer_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"printers_farm_id_farms_id_fk": {
|
||||||
|
"name": "printers_farm_id_farms_id_fk",
|
||||||
|
"tableFrom": "printers",
|
||||||
|
"tableTo": "farms",
|
||||||
|
"columnsFrom": [
|
||||||
|
"farm_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"public.print_jobs": {
|
||||||
|
"name": "print_jobs",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"farm_id": {
|
||||||
|
"name": "farm_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"printer_id": {
|
||||||
|
"name": "printer_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"file_name": {
|
||||||
|
"name": "file_name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"r2_object_key": {
|
||||||
|
"name": "r2_object_key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "print_job_status",
|
||||||
|
"typeSchema": "public",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'queued'"
|
||||||
|
},
|
||||||
|
"progress_pct": {
|
||||||
|
"name": "progress_pct",
|
||||||
|
"type": "real",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"estimated_time_s": {
|
||||||
|
"name": "estimated_time_s",
|
||||||
|
"type": "real",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"elapsed_time_s": {
|
||||||
|
"name": "elapsed_time_s",
|
||||||
|
"type": "real",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"submitted_by": {
|
||||||
|
"name": "submitted_by",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"name": "metadata",
|
||||||
|
"type": "jsonb",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "'{}'::jsonb"
|
||||||
|
},
|
||||||
|
"started_at": {
|
||||||
|
"name": "started_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"completed_at": {
|
||||||
|
"name": "completed_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"print_jobs_farm_id_farms_id_fk": {
|
||||||
|
"name": "print_jobs_farm_id_farms_id_fk",
|
||||||
|
"tableFrom": "print_jobs",
|
||||||
|
"tableTo": "farms",
|
||||||
|
"columnsFrom": [
|
||||||
|
"farm_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"print_jobs_printer_id_printers_id_fk": {
|
||||||
|
"name": "print_jobs_printer_id_printers_id_fk",
|
||||||
|
"tableFrom": "print_jobs",
|
||||||
|
"tableTo": "printers",
|
||||||
|
"columnsFrom": [
|
||||||
|
"printer_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "set null",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"public.frame_embeddings": {
|
||||||
|
"name": "frame_embeddings",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"print_job_id": {
|
||||||
|
"name": "print_job_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"printer_id": {
|
||||||
|
"name": "printer_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"r2_object_key": {
|
||||||
|
"name": "r2_object_key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"embedding": {
|
||||||
|
"name": "embedding",
|
||||||
|
"type": "vector(512)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"captured_at": {
|
||||||
|
"name": "captured_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"frame_embeddings_embedding_ivfflat_idx": {
|
||||||
|
"name": "frame_embeddings_embedding_ivfflat_idx",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "embedding",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last",
|
||||||
|
"opclass": "vector_cosine_ops"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "ivfflat",
|
||||||
|
"with": {
|
||||||
|
"lists": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"frame_embeddings_print_job_id_print_jobs_id_fk": {
|
||||||
|
"name": "frame_embeddings_print_job_id_print_jobs_id_fk",
|
||||||
|
"tableFrom": "frame_embeddings",
|
||||||
|
"tableTo": "print_jobs",
|
||||||
|
"columnsFrom": [
|
||||||
|
"print_job_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"frame_embeddings_printer_id_printers_id_fk": {
|
||||||
|
"name": "frame_embeddings_printer_id_printers_id_fk",
|
||||||
|
"tableFrom": "frame_embeddings",
|
||||||
|
"tableTo": "printers",
|
||||||
|
"columnsFrom": [
|
||||||
|
"printer_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {
|
||||||
|
"public.printer_status": {
|
||||||
|
"name": "printer_status",
|
||||||
|
"schema": "public",
|
||||||
|
"values": [
|
||||||
|
"offline",
|
||||||
|
"idle",
|
||||||
|
"printing",
|
||||||
|
"paused",
|
||||||
|
"error",
|
||||||
|
"maintenance"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"public.printer_vendor": {
|
||||||
|
"name": "printer_vendor",
|
||||||
|
"schema": "public",
|
||||||
|
"values": [
|
||||||
|
"bambu",
|
||||||
|
"prusa",
|
||||||
|
"klipper"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"public.print_job_status": {
|
||||||
|
"name": "print_job_status",
|
||||||
|
"schema": "public",
|
||||||
|
"values": [
|
||||||
|
"queued",
|
||||||
|
"uploading",
|
||||||
|
"printing",
|
||||||
|
"paused",
|
||||||
|
"completed",
|
||||||
|
"failed",
|
||||||
|
"cancelled"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemas": {},
|
||||||
|
"sequences": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"idx": 0,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1791029521420,
|
||||||
|
"tag": "0000_watery_firedrake",
|
||||||
|
"breakpoints": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
+18
-7
@@ -24,7 +24,8 @@
|
|||||||
# scripts/dev-env.sh reset stop them AND delete all data
|
# scripts/dev-env.sh reset stop them AND delete all data
|
||||||
# scripts/dev-env.sh status what is running, and which backend
|
# scripts/dev-env.sh status what is running, and which backend
|
||||||
# scripts/dev-env.sh psql open a shell on the database
|
# scripts/dev-env.sh psql open a shell on the database
|
||||||
# scripts/dev-env.sh schema apply the Drizzle schema (drizzle-kit push)
|
# scripts/dev-env.sh schema apply the committed migrations (drizzle-kit migrate)
|
||||||
|
# scripts/dev-env.sh push reshape the db from src/db/schema, no migration
|
||||||
# scripts/dev-env.sh env print the DATABASE_URL/VALKEY_URL to use
|
# scripts/dev-env.sh env print the DATABASE_URL/VALKEY_URL to use
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -204,12 +205,21 @@ cmd_status() { case "$(backend)" in docker) echo "backend: docker"; sudo docker
|
|||||||
cmd_psql() { PGPASSWORD=continuum psql -h localhost -p "$PG_PORT" -U continuum -d continuum "$@"; }
|
cmd_psql() { PGPASSWORD=continuum psql -h localhost -p "$PG_PORT" -U continuum -d continuum "$@"; }
|
||||||
cmd_env() { echo "DATABASE_URL=$DEV_DATABASE_URL"; echo "VALKEY_URL=$DEV_VALKEY_URL"; }
|
cmd_env() { echo "DATABASE_URL=$DEV_DATABASE_URL"; echo "VALKEY_URL=$DEV_VALKEY_URL"; }
|
||||||
|
|
||||||
|
# Applies the committed migrations in drizzle/, the same way a deploy would.
|
||||||
|
# This is the default because it is the path that has to work in production -
|
||||||
|
# testing `push` locally and `migrate` in production tests two different things.
|
||||||
cmd_schema() {
|
cmd_schema() {
|
||||||
# `push` rather than generate+migrate: no migrations are committed and the
|
echo "==> applying committed migrations to $DEV_DATABASE_URL"
|
||||||
# schema is still moving. Switch once it settles - push diffs the live
|
DATABASE_URL="$DEV_DATABASE_URL" bunx drizzle-kit migrate
|
||||||
# database against the schema and will happily drop a column, which is fine
|
}
|
||||||
# locally and nowhere else.
|
|
||||||
echo "==> applying the Drizzle schema to $DEV_DATABASE_URL"
|
# Diffs the live database against src/db/schema and reshapes it in place, with
|
||||||
|
# no migration file. Faster while iterating on the schema, and destructive: it
|
||||||
|
# will drop a column to make the database match. Local only - and whatever it
|
||||||
|
# does is not recorded anywhere, so run `bun run db:generate` before committing
|
||||||
|
# a schema change made this way.
|
||||||
|
cmd_push() {
|
||||||
|
echo "==> pushing src/db/schema straight onto $DEV_DATABASE_URL"
|
||||||
DATABASE_URL="$DEV_DATABASE_URL" bunx drizzle-kit push --force
|
DATABASE_URL="$DEV_DATABASE_URL" bunx drizzle-kit push --force
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,6 +230,7 @@ case "${1:-}" in
|
|||||||
status) cmd_status ;;
|
status) cmd_status ;;
|
||||||
psql) shift; cmd_psql "$@" ;;
|
psql) shift; cmd_psql "$@" ;;
|
||||||
schema) cmd_schema ;;
|
schema) cmd_schema ;;
|
||||||
|
push) cmd_push ;;
|
||||||
env) cmd_env ;;
|
env) cmd_env ;;
|
||||||
*) sed -n '2,30p' "${BASH_SOURCE[0]}" | sed 's/^# \?//'; exit 1 ;;
|
*) awk 'NR>1 && /^#/ { sub(/^# ?/, ""); print; next } NR>1 { exit }' "${BASH_SOURCE[0]}"; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
Reference in New Issue
Block a user