135 lines
5.1 KiB
SQL
135 lines
5.1 KiB
SQL
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 $$;
|