CREATE SCHEMA "planes"; --> statement-breakpoint CREATE TABLE "planes"."makers" ( "id" serial PRIMARY KEY, "slug" text NOT NULL, "name" text NOT NULL, "full_name" text, "country" text, "wikidata" text, "wikipedia" text, "type_count" integer DEFAULT 0 NOT NULL, "first_year" smallint, "last_year" smallint, "built_total" integer DEFAULT 0 NOT NULL, "sources" text[] DEFAULT '{}'::text[] NOT NULL, "logo" text, "logo_file" text, "logo_author" text, "logo_license" text, "photo" text, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL ); --> statement-breakpoint CREATE TABLE "planes"."photos" ( "id" serial PRIMARY KEY, "type_id" integer NOT NULL, "position" smallint NOT NULL, "kind" text NOT NULL, "file" text NOT NULL, "caption" text, "thumb" text NOT NULL, "width" integer NOT NULL, "height" integer NOT NULL, "author" text, "license" text, "license_url" text ); --> statement-breakpoint CREATE TABLE "planes"."types" ( "id" serial PRIMARY KEY, "dex" integer NOT NULL, "maker_id" integer NOT NULL, "family_id" integer, "slug" text NOT NULL, "name" text NOT NULL, "full_name" text NOT NULL, "search" text NOT NULL, "wikidata" text NOT NULL, "wikipedia" text, "kind" text, "description" text, "summary" text, "role" text, "roles" text[] DEFAULT '{}'::text[] NOT NULL, "role_label" text, "country" text, "first_flight" text, "first_flight_year" smallint, "introduced_year" smallint, "retired_year" smallint, "status" text, "in_service" boolean, "number_built" integer, "makers" text[] DEFAULT '{}'::text[] NOT NULL, "engine_type" text, "engine_count" smallint, "engines" text[] DEFAULT '{}'::text[] NOT NULL, "crew" smallint, "passengers" smallint, "length_m" real, "wingspan_m" real, "height_m" real, "rotor_m" real, "mtow_kg" integer, "max_speed_kmh" smallint, "cruise_kmh" smallint, "range_km" integer, "ceiling_m" integer, "wing" text, "gear" text, "icao" text[] DEFAULT '{}'::text[] NOT NULL, "recognize" text, "sources" text[] DEFAULT '{}'::text[] NOT NULL, "photo" text, "photo_count" smallint DEFAULT 0 NOT NULL, "photos_checked_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 UNIQUE INDEX "makers_slug_key" ON "planes"."makers" ("slug");--> statement-breakpoint CREATE UNIQUE INDEX "photos_type_position_key" ON "planes"."photos" ("type_id","position");--> statement-breakpoint CREATE UNIQUE INDEX "types_dex_key" ON "planes"."types" ("dex");--> statement-breakpoint CREATE UNIQUE INDEX "types_wikidata_key" ON "planes"."types" ("wikidata");--> statement-breakpoint CREATE UNIQUE INDEX "types_maker_slug_key" ON "planes"."types" ("maker_id","slug");--> statement-breakpoint CREATE INDEX "types_number_built_idx" ON "planes"."types" ("number_built");--> statement-breakpoint CREATE INDEX "types_first_flight_year_idx" ON "planes"."types" ("first_flight_year");--> statement-breakpoint CREATE INDEX "types_search_trgm_idx" ON "planes"."types" USING gin ("search" public.gin_trgm_ops);--> statement-breakpoint ALTER TABLE "planes"."photos" ADD CONSTRAINT "photos_type_id_types_id_fkey" FOREIGN KEY ("type_id") REFERENCES "planes"."types"("id") ON DELETE CASCADE;--> statement-breakpoint ALTER TABLE "planes"."types" ADD CONSTRAINT "types_maker_id_makers_id_fkey" FOREIGN KEY ("maker_id") REFERENCES "planes"."makers"("id") ON DELETE CASCADE;--> statement-breakpoint ALTER TABLE "planes"."types" ADD CONSTRAINT "types_family_id_types_id_fkey" FOREIGN KEY ("family_id") REFERENCES "planes"."types"("id") ON DELETE SET NULL;--> statement-breakpoint -- Hand-written: updated_at triggers, grants, GUI registration. Data comes from scripts/planes-import.ts and scripts/planes-photos.ts. DO $$ DECLARE t text; BEGIN FOREACH t IN ARRAY ARRAY['makers','types'] LOOP EXECUTE format('CREATE TRIGGER touch_updated_at BEFORE UPDATE ON planes.%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 planes TO personal_app; GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA planes TO personal_app; GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA planes TO personal_app; ALTER DEFAULT PRIVILEGES IN SCHEMA planes GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO personal_app; ALTER DEFAULT PRIVILEGES IN SCHEMA planes 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 planes TO personal_ro; GRANT SELECT ON ALL TABLES IN SCHEMA planes TO personal_ro; ALTER DEFAULT PRIVILEGES IN SCHEMA planes 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 ('planes','makers','planes-makers','Plane makers','core',false,false,1000), ('planes','types','planes-types','Plane types','core',false,false,1000), ('planes','photos','planes-photos','Plane photos','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 $$;