cars: car pokedex tracker (brands, models, US variants from RDW + fueleconomy.gov), import script, search/filter UI, model pages
Some checks failed
Deploy production / deploy (push) Has been cancelled
Some checks failed
Deploy production / deploy (push) Has been cancelled
This commit is contained in:
134
drizzle/20261024153902_cars/migration.sql
Normal file
134
drizzle/20261024153902_cars/migration.sql
Normal file
@@ -0,0 +1,134 @@
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA public;
|
||||
--> statement-breakpoint
|
||||
CREATE SCHEMA "cars";
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "cars"."brands" (
|
||||
"id" serial PRIMARY KEY,
|
||||
"slug" text NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"country" text,
|
||||
"model_count" integer DEFAULT 0 NOT NULL,
|
||||
"nl_count" integer DEFAULT 0 NOT NULL,
|
||||
"first_year" smallint,
|
||||
"last_year" smallint,
|
||||
"sources" text[] DEFAULT '{}'::text[] NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "cars"."models" (
|
||||
"id" serial PRIMARY KEY,
|
||||
"dex" integer NOT NULL,
|
||||
"brand_id" integer NOT NULL,
|
||||
"slug" text NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"search" text NOT NULL,
|
||||
"first_year" smallint,
|
||||
"last_year" smallint,
|
||||
"bodies" text[] DEFAULT '{}'::text[] NOT NULL,
|
||||
"size_classes" text[] DEFAULT '{}'::text[] NOT NULL,
|
||||
"fuels" text[] DEFAULT '{}'::text[] NOT NULL,
|
||||
"drives" text[] DEFAULT '{}'::text[] NOT NULL,
|
||||
"transmissions" text[] DEFAULT '{}'::text[] NOT NULL,
|
||||
"engine_l_min" real,
|
||||
"engine_l_max" real,
|
||||
"cylinders_min" smallint,
|
||||
"cylinders_max" smallint,
|
||||
"turbo" boolean,
|
||||
"power_kw_min" real,
|
||||
"power_kw_max" real,
|
||||
"l100_min" real,
|
||||
"l100_max" real,
|
||||
"co2_min" smallint,
|
||||
"co2_max" smallint,
|
||||
"mpg_min" real,
|
||||
"mpg_max" real,
|
||||
"range_km_max" smallint,
|
||||
"seats" smallint,
|
||||
"doors" smallint,
|
||||
"mass_kg" smallint,
|
||||
"nl_count" integer DEFAULT 0 NOT NULL,
|
||||
"nl_rank" integer,
|
||||
"nl_first_year" smallint,
|
||||
"nl_last_year" smallint,
|
||||
"nl_price" integer,
|
||||
"nl_price_latest" integer,
|
||||
"nl_price_latest_year" smallint,
|
||||
"nl_years" jsonb DEFAULT '[]' NOT NULL,
|
||||
"nl_names" jsonb DEFAULT '[]' NOT NULL,
|
||||
"us_years" smallint[] DEFAULT '{}'::smallint[] NOT NULL,
|
||||
"variant_count" integer DEFAULT 0 NOT NULL,
|
||||
"sources" text[] DEFAULT '{}'::text[] NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "cars"."variants" (
|
||||
"id" serial PRIMARY KEY,
|
||||
"model_id" integer NOT NULL,
|
||||
"source" text DEFAULT 'fueleconomy.gov' NOT NULL,
|
||||
"source_id" integer,
|
||||
"year" smallint NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"engine_l" real,
|
||||
"cylinders" smallint,
|
||||
"transmission" text,
|
||||
"drive" text,
|
||||
"fuel" text,
|
||||
"size_class" text,
|
||||
"mpg_city" real,
|
||||
"mpg_hwy" real,
|
||||
"mpg_comb" real,
|
||||
"co2_gpm" smallint,
|
||||
"range_mi" smallint,
|
||||
"ev_motor" text,
|
||||
"turbo" boolean DEFAULT false NOT NULL,
|
||||
"supercharged" boolean DEFAULT false NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "brands_slug_key" ON "cars"."brands" ("slug");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "models_dex_key" ON "cars"."models" ("dex");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "models_brand_slug_key" ON "cars"."models" ("brand_id","slug");--> statement-breakpoint
|
||||
CREATE INDEX "models_nl_count_idx" ON "cars"."models" ("nl_count");--> statement-breakpoint
|
||||
CREATE INDEX "models_search_trgm_idx" ON "cars"."models" USING gin ("search" public.gin_trgm_ops);--> statement-breakpoint
|
||||
CREATE INDEX "variants_model_year_idx" ON "cars"."variants" ("model_id","year");--> statement-breakpoint
|
||||
ALTER TABLE "cars"."models" ADD CONSTRAINT "models_brand_id_brands_id_fkey" FOREIGN KEY ("brand_id") REFERENCES "cars"."brands"("id") ON DELETE CASCADE;--> statement-breakpoint
|
||||
ALTER TABLE "cars"."variants" ADD CONSTRAINT "variants_model_id_models_id_fkey" FOREIGN KEY ("model_id") REFERENCES "cars"."models"("id") ON DELETE CASCADE;
|
||||
--> statement-breakpoint
|
||||
-- Hand-written: updated_at triggers, grants, GUI registration. Data comes from scripts/cars-import.ts.
|
||||
DO $$
|
||||
DECLARE t text;
|
||||
BEGIN
|
||||
FOREACH t IN ARRAY ARRAY['brands','models'] LOOP
|
||||
EXECUTE format('CREATE TRIGGER touch_updated_at BEFORE UPDATE ON cars.%I FOR EACH ROW EXECUTE FUNCTION meta.touch_updated_at()', t);
|
||||
END LOOP;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'personal_app') THEN
|
||||
GRANT USAGE ON SCHEMA cars TO personal_app;
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA cars TO personal_app;
|
||||
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA cars TO personal_app;
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA cars GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO personal_app;
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA cars GRANT USAGE, SELECT ON SEQUENCES TO personal_app;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'personal_ro') THEN
|
||||
GRANT USAGE ON SCHEMA cars TO personal_ro;
|
||||
GRANT SELECT ON ALL TABLES IN SCHEMA cars TO personal_ro;
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA cars GRANT SELECT ON TABLES TO personal_ro;
|
||||
END IF;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$
|
||||
BEGIN
|
||||
IF to_regclass('meta.tables') IS NOT NULL THEN
|
||||
INSERT INTO meta.tables (schema_name, table_name, slug, display_name, kind, editable, has_done, sort_order)
|
||||
VALUES ('cars','brands','cars-brands','Car brands','core',false,false,1000),
|
||||
('cars','models','cars-models','Car models','core',false,false,1000)
|
||||
ON CONFLICT DO NOTHING;
|
||||
IF has_function_privilege('meta.sync(integer)', 'EXECUTE') THEN
|
||||
PERFORM meta.sync();
|
||||
END IF;
|
||||
END IF;
|
||||
END $$;
|
||||
18350
drizzle/20261024153902_cars/snapshot.json
Normal file
18350
drizzle/20261024153902_cars/snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user