diff --git a/app/migrations/0035_drop_admin_tables.sql b/app/migrations/0035_drop_admin_tables.sql new file mode 100644 index 00000000..7a3ad94a --- /dev/null +++ b/app/migrations/0035_drop_admin_tables.sql @@ -0,0 +1,2 @@ +DROP TABLE "administrators" CASCADE;--> statement-breakpoint +DROP TABLE "profile_users" CASCADE; \ No newline at end of file diff --git a/app/migrations/meta/0035_snapshot.json b/app/migrations/meta/0035_snapshot.json new file mode 100644 index 00000000..bfe3e0c9 --- /dev/null +++ b/app/migrations/meta/0035_snapshot.json @@ -0,0 +1,2684 @@ +{ + "id": "688e95e3-ba48-4822-9f86-af204699a2ec", + "prevId": "e8358ff9-265a-4bd3-9b1d-573985d69fcc", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.event_sponsors": { + "name": "event_sponsors", + "schema": "", + "columns": { + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "sponsor_id": { + "name": "sponsor_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "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 + } + }, + "indexes": {}, + "foreignKeys": { + "event_sponsors_event_id_events_id_fk": { + "name": "event_sponsors_event_id_events_id_fk", + "tableFrom": "event_sponsors", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "event_sponsors_sponsor_id_sponsors_id_fk": { + "name": "event_sponsors_sponsor_id_sponsors_id_fk", + "tableFrom": "event_sponsors", + "tableTo": "sponsors", + "columnsFrom": ["sponsor_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "event_sponsors_event_id_sponsor_id_pk": { + "name": "event_sponsors_event_id_sponsor_id_pk", + "columns": ["event_id", "sponsor_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.event_images": { + "name": "event_images", + "schema": "", + "columns": { + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "image_id": { + "name": "image_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "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 + } + }, + "indexes": {}, + "foreignKeys": { + "event_images_event_id_events_id_fk": { + "name": "event_images_event_id_events_id_fk", + "tableFrom": "event_images", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "event_images_image_id_images_id_fk": { + "name": "event_images_image_id_images_id_fk", + "tableFrom": "event_images", + "tableTo": "images", + "columnsFrom": ["image_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "event_images_event_id_image_id_pk": { + "name": "event_images_event_id_image_id_pk", + "columns": ["event_id", "image_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.event_notes": { + "name": "event_notes", + "schema": "", + "columns": { + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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 + } + }, + "indexes": {}, + "foreignKeys": { + "event_notes_event_id_events_id_fk": { + "name": "event_notes_event_id_events_id_fk", + "tableFrom": "event_notes", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "event_notes_event_id_position_pk": { + "name": "event_notes_event_id_position_pk", + "columns": ["event_id", "position"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "event_notes_position_check": { + "name": "event_notes_position_check", + "value": "\"position\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.event_people": { + "name": "event_people", + "schema": "", + "columns": { + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "profile_id": { + "name": "profile_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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 + } + }, + "indexes": {}, + "foreignKeys": { + "event_people_event_id_events_id_fk": { + "name": "event_people_event_id_events_id_fk", + "tableFrom": "event_people", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "event_people_profile_id_profiles_id_fk": { + "name": "event_people_profile_id_profiles_id_fk", + "tableFrom": "event_people", + "tableTo": "profiles", + "columnsFrom": ["profile_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "event_people_event_id_profile_id_role_pk": { + "name": "event_people_event_id_profile_id_role_pk", + "columns": ["event_id", "profile_id", "role"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "event_people_role_check": { + "name": "event_people_role_check", + "value": "\"role\" IN ('organizer', 'co-host', 'mc')" + }, + "event_people_position_check": { + "name": "event_people_position_check", + "value": "\"position\" >= 0" + }, + "event_people_source_check": { + "name": "event_people_source_check", + "value": "\"source\" IN ('luma', 'site')" + } + }, + "isRLSEnabled": false + }, + "public.event_posts": { + "name": "event_posts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "platform": { + "name": "platform", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "author_name": { + "name": "author_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "author_handle": { + "name": "author_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "author_url": { + "name": "author_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "author_avatar_source_url": { + "name": "author_avatar_source_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "author_avatar": { + "name": "author_avatar", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "posted_at": { + "name": "posted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "text": { + "name": "text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "image_source_url": { + "name": "image_source_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'approved'" + }, + "added_at": { + "name": "added_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 + } + }, + "indexes": { + "event_posts_event_id_idx": { + "name": "event_posts_event_id_idx", + "columns": [ + { + "expression": "event_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "event_posts_event_id_events_id_fk": { + "name": "event_posts_event_id_events_id_fk", + "tableFrom": "event_posts", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "event_posts_author_avatar_images_id_fk": { + "name": "event_posts_author_avatar_images_id_fk", + "tableFrom": "event_posts", + "tableTo": "images", + "columnsFrom": ["author_avatar"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "event_posts_image_images_id_fk": { + "name": "event_posts_image_images_id_fk", + "tableFrom": "event_posts", + "tableTo": "images", + "columnsFrom": ["image"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "event_posts_url_unique": { + "name": "event_posts_url_unique", + "nullsNotDistinct": false, + "columns": ["url"] + } + }, + "policies": {}, + "checkConstraints": { + "event_posts_platform_check": { + "name": "event_posts_platform_check", + "value": "\"platform\" IN ('x', 'bluesky', 'linkedin', 'other')" + }, + "event_posts_status_check": { + "name": "event_posts_status_check", + "value": "\"status\" IN ('approved', 'hidden', 'pending')" + } + }, + "isRLSEnabled": false + }, + "public.event_review_sessions": { + "name": "event_review_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'discord'" + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "root_message_id": { + "name": "root_message_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_seen_message_id": { + "name": "last_seen_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "approval_message_id": { + "name": "approval_message_id", + "type": "text", + "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 + } + }, + "indexes": {}, + "foreignKeys": { + "event_review_sessions_event_id_events_id_fk": { + "name": "event_review_sessions_event_id_events_id_fk", + "tableFrom": "event_review_sessions", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "event_review_sessions_event_id_unique": { + "name": "event_review_sessions_event_id_unique", + "nullsNotDistinct": false, + "columns": ["event_id"] + }, + "event_review_sessions_thread_id_unique": { + "name": "event_review_sessions_thread_id_unique", + "nullsNotDistinct": false, + "columns": ["thread_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.event_schedule_items": { + "name": "event_schedule_items", + "schema": "", + "columns": { + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "time": { + "name": "time", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "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 + } + }, + "indexes": {}, + "foreignKeys": { + "event_schedule_items_event_id_events_id_fk": { + "name": "event_schedule_items_event_id_events_id_fk", + "tableFrom": "event_schedule_items", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "event_schedule_items_event_id_position_pk": { + "name": "event_schedule_items_event_id_position_pk", + "columns": ["event_id", "position"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "event_schedule_items_position_check": { + "name": "event_schedule_items_position_check", + "value": "\"position\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.event_slugs": { + "name": "event_slugs", + "schema": "", + "columns": { + "slug": { + "name": "slug", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "event_slugs_event_id_events_id_fk": { + "name": "event_slugs_event_id_events_id_fk", + "tableFrom": "event_slugs", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "event_slugs_event_id_slug_unique": { + "name": "event_slugs_event_id_slug_unique", + "nullsNotDistinct": false, + "columns": ["event_id", "slug"] + } + }, + "policies": {}, + "checkConstraints": { + "event_slugs_slug_check": { + "name": "event_slugs_slug_check", + "value": "\"slug\" ~ '^(shared/)?[a-z0-9]+(-[a-z0-9]+)*$'" + } + }, + "isRLSEnabled": false + }, + "public.event_talks": { + "name": "event_talks", + "schema": "", + "columns": { + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "talk_id": { + "name": "talk_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "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 + }, + "position": { + "name": "position", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "starts_at": { + "name": "starts_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "event_talks_event_id_events_id_fk": { + "name": "event_talks_event_id_events_id_fk", + "tableFrom": "event_talks", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "event_talks_talk_id_talks_id_fk": { + "name": "event_talks_talk_id_talks_id_fk", + "tableFrom": "event_talks", + "tableTo": "talks", + "columnsFrom": ["talk_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "event_talks_event_id_talk_id_pk": { + "name": "event_talks_event_id_talk_id_pk", + "columns": ["event_id", "talk_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "event_talks_position_check": { + "name": "event_talks_position_check", + "value": "\"position\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "start_date": { + "name": "start_date", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "end_date": { + "name": "end_date", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tagline": { + "name": "tagline", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "attendee_limit": { + "name": "attendee_limit", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "street_address": { + "name": "street_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "short_location": { + "name": "short_location", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "full_address": { + "name": "full_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "venue_by_organizer": { + "name": "venue_by_organizer", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "luma_event_id": { + "name": "luma_event_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_hackathon": { + "name": "is_hackathon", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_draft": { + "name": "is_draft", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "highlight_on_landing_page": { + "name": "highlight_on_landing_page", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "preview_image": { + "name": "preview_image", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "recording_url": { + "name": "recording_url", + "type": "text", + "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 + }, + "topic": { + "name": "topic", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "luma_guest_count": { + "name": "luma_guest_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "luma_checked_in_count": { + "name": "luma_checked_in_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "program": { + "name": "program", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'talks'" + }, + "curation": { + "name": "curation", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'ours'" + }, + "organized_by": { + "name": "organized_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "luma_description": { + "name": "luma_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "luma_summary": { + "name": "luma_summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "short_slug": { + "name": "short_slug", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "events_preview_image_images_id_fk": { + "name": "events_preview_image_images_id_fk", + "tableFrom": "events", + "tableTo": "images", + "columnsFrom": ["preview_image"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "events_organized_by_sponsors_id_fk": { + "name": "events_organized_by_sponsors_id_fk", + "tableFrom": "events", + "tableTo": "sponsors", + "columnsFrom": ["organized_by"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "events_id_short_slug_event_slugs_fk": { + "name": "events_id_short_slug_event_slugs_fk", + "tableFrom": "events", + "tableTo": "event_slugs", + "columnsFrom": ["id", "short_slug"], + "columnsTo": ["event_id", "slug"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "events_slug_unique": { + "name": "events_slug_unique", + "nullsNotDistinct": false, + "columns": ["slug"] + }, + "events_luma_event_id_unique": { + "name": "events_luma_event_id_unique", + "nullsNotDistinct": false, + "columns": ["luma_event_id"] + }, + "events_short_slug_unique": { + "name": "events_short_slug_unique", + "nullsNotDistinct": false, + "columns": ["short_slug"] + } + }, + "policies": {}, + "checkConstraints": { + "events_luma_guest_count_check": { + "name": "events_luma_guest_count_check", + "value": "\"luma_guest_count\" >= 0" + }, + "events_program_check": { + "name": "events_program_check", + "value": "\"program\" IN ('talks', 'open-floor', 'social', 'hackathon')" + }, + "events_program_hackathon_check": { + "name": "events_program_hackathon_check", + "value": "(\"program\" = 'hackathon') = \"is_hackathon\"" + }, + "events_curation_check": { + "name": "events_curation_check", + "value": "\"curation\" IN ('ours', 'shared')" + }, + "events_curation_organizer_check": { + "name": "events_curation_organizer_check", + "value": "(\"curation\" = 'shared') = (\"organized_by\" IS NOT NULL)" + }, + "events_luma_checked_in_count_check": { + "name": "events_luma_checked_in_count_check", + "value": "\"luma_checked_in_count\" >= 0" + }, + "events_topic_check": { + "name": "events_topic_check", + "value": "char_length(\"topic\") <= 24\n AND \"topic\" IS NFC NORMALIZED\n AND \"topic\" = lower(\"topic\" COLLATE \"pg_c_utf8\")\n AND strpos(\"topic\", 'all things') = 0\n AND \"topic\" COLLATE \"pg_c_utf8\" ~ '^[[:alpha:][:digit:]](?:[[:alpha:][:digit:].&+#'']|(?<=[^ ]) (?=[^ ])|(?<=[[:alpha:][:digit:]])-(?=[[:alpha:][:digit:]]))*$'" + } + }, + "isRLSEnabled": false + }, + "public.external_talks": { + "name": "external_talks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "profile_id": { + "name": "profile_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_name": { + "name": "event_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "given_on": { + "name": "given_on", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "video_url": { + "name": "video_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_url": { + "name": "source_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "read_on": { + "name": "read_on", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "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 + } + }, + "indexes": { + "external_talks_profile_id_idx": { + "name": "external_talks_profile_id_idx", + "columns": [ + { + "expression": "profile_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "external_talks_profile_id_profiles_id_fk": { + "name": "external_talks_profile_id_profiles_id_fk", + "tableFrom": "external_talks", + "tableTo": "profiles", + "columnsFrom": ["profile_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "external_talks_profile_id_title_given_on_unique": { + "name": "external_talks_profile_id_title_given_on_unique", + "nullsNotDistinct": false, + "columns": ["profile_id", "title", "given_on"] + } + }, + "policies": {}, + "checkConstraints": { + "external_talks_kind_check": { + "name": "external_talks_kind_check", + "value": "\"kind\" IN ('conference', 'meetup', 'podcast', 'video', 'workshop')" + }, + "external_talks_url_check": { + "name": "external_talks_url_check", + "value": "\"url\" ~ '^https://'" + }, + "external_talks_video_url_check": { + "name": "external_talks_video_url_check", + "value": "\"video_url\" ~ '^https://'" + }, + "external_talks_source_url_check": { + "name": "external_talks_source_url_check", + "value": "\"source_url\" ~ '^https://'" + } + }, + "isRLSEnabled": false + }, + "public.sponsors": { + "name": "sponsors", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "about": { + "name": "about", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "square_logo_dark": { + "name": "square_logo_dark", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "square_logo_light": { + "name": "square_logo_light", + "type": "uuid", + "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 + }, + "website_url": { + "name": "website_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "twitter_handle": { + "name": "twitter_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bluesky_handle": { + "name": "bluesky_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "linkedin_handle": { + "name": "linkedin_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "luma_user_id": { + "name": "luma_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "sponsors_square_logo_dark_images_id_fk": { + "name": "sponsors_square_logo_dark_images_id_fk", + "tableFrom": "sponsors", + "tableTo": "images", + "columnsFrom": ["square_logo_dark"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "sponsors_square_logo_light_images_id_fk": { + "name": "sponsors_square_logo_light_images_id_fk", + "tableFrom": "sponsors", + "tableTo": "images", + "columnsFrom": ["square_logo_light"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "sponsors_name_unique": { + "name": "sponsors_name_unique", + "nullsNotDistinct": false, + "columns": ["name"] + }, + "sponsors_luma_user_id_unique": { + "name": "sponsors_luma_user_id_unique", + "nullsNotDistinct": false, + "columns": ["luma_user_id"] + } + }, + "policies": {}, + "checkConstraints": { + "sponsors_website_url_check": { + "name": "sponsors_website_url_check", + "value": "\"website_url\" ~ '^https://[A-Za-z0-9.-]+(/[^[:space:]]*)?$'" + }, + "sponsors_twitter_handle_check": { + "name": "sponsors_twitter_handle_check", + "value": "\"twitter_handle\" ~ '^[A-Za-z0-9_]{1,15}$'" + }, + "sponsors_bluesky_handle_check": { + "name": "sponsors_bluesky_handle_check", + "value": "\"bluesky_handle\" ~ '^([a-z0-9]([a-z0-9-]*[a-z0-9])?[.])+[a-z]{2,}$'" + }, + "sponsors_linkedin_handle_check": { + "name": "sponsors_linkedin_handle_check", + "value": "\"linkedin_handle\" ~ '^[A-Za-z0-9][A-Za-z0-9_-]{0,99}$'" + }, + "sponsors_luma_user_id_check": { + "name": "sponsors_luma_user_id_check", + "value": "\"luma_user_id\" ~ '^usr-[A-Za-z0-9]+$'" + } + }, + "isRLSEnabled": false + }, + "public.images": { + "name": "images", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "placeholder": { + "name": "placeholder", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "alt": { + "name": "alt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "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 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "planning.availability": { + "name": "availability", + "schema": "planning", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "wanted_speaker_id": { + "name": "wanted_speaker_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'available'" + }, + "starts_on": { + "name": "starts_on", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "ends_on": { + "name": "ends_on", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "availability_wanted_speaker_id_idx": { + "name": "availability_wanted_speaker_id_idx", + "columns": [ + { + "expression": "wanted_speaker_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "availability_wanted_speaker_id_wanted_speakers_id_fk": { + "name": "availability_wanted_speaker_id_wanted_speakers_id_fk", + "tableFrom": "availability", + "tableTo": "wanted_speakers", + "schemaTo": "planning", + "columnsFrom": ["wanted_speaker_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "availability_kind_check": { + "name": "availability_kind_check", + "value": "\"kind\" IN ('available', 'unavailable')" + }, + "availability_order_check": { + "name": "availability_order_check", + "value": "\"starts_on\" <= \"ends_on\"" + }, + "availability_said_check": { + "name": "availability_said_check", + "value": "num_nonnulls(\"starts_on\", \"ends_on\", \"note\") > 0" + } + }, + "isRLSEnabled": false + }, + "planning.contacts": { + "name": "contacts", + "schema": "planning", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sponsor_id": { + "name": "sponsor_id", + "type": "uuid", + "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": { + "contacts_sponsor_id_sponsors_id_fk": { + "name": "contacts_sponsor_id_sponsors_id_fk", + "tableFrom": "contacts", + "tableTo": "sponsors", + "columnsFrom": ["sponsor_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "contacts_name_check": { + "name": "contacts_name_check", + "value": "btrim(\"name\") <> ''" + }, + "contacts_email_check": { + "name": "contacts_email_check", + "value": "\"email\" ~ '^[^@[:space:]]+@[^@[:space:]]+[.][^@[:space:]]+$'" + }, + "contacts_url_check": { + "name": "contacts_url_check", + "value": "\"url\" ~ '^https://[^[:space:]]+$'" + } + }, + "isRLSEnabled": false + }, + "planning.host_prospects": { + "name": "host_prospects", + "schema": "planning", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "sponsor_id": { + "name": "sponsor_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "company_name": { + "name": "company_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contact_id": { + "name": "contact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'prospect'" + }, + "note": { + "name": "note", + "type": "text", + "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": { + "host_prospects_company_name_unique": { + "name": "host_prospects_company_name_unique", + "columns": [ + { + "expression": "lower(\"company_name\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "host_prospects_sponsor_id_sponsors_id_fk": { + "name": "host_prospects_sponsor_id_sponsors_id_fk", + "tableFrom": "host_prospects", + "tableTo": "sponsors", + "columnsFrom": ["sponsor_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "host_prospects_contact_id_contacts_id_fk": { + "name": "host_prospects_contact_id_contacts_id_fk", + "tableFrom": "host_prospects", + "tableTo": "contacts", + "schemaTo": "planning", + "columnsFrom": ["contact_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "host_prospects_sponsor_id_unique": { + "name": "host_prospects_sponsor_id_unique", + "nullsNotDistinct": false, + "columns": ["sponsor_id"] + } + }, + "policies": {}, + "checkConstraints": { + "host_prospects_company_check": { + "name": "host_prospects_company_check", + "value": "num_nonnulls(\"sponsor_id\", \"company_name\") = 1" + }, + "host_prospects_company_name_check": { + "name": "host_prospects_company_name_check", + "value": "btrim(\"company_name\") <> ''" + }, + "host_prospects_status_check": { + "name": "host_prospects_status_check", + "value": "\"status\" IN ('prospect', 'asked', 'confirmed', 'declined')" + } + }, + "isRLSEnabled": false + }, + "planning.ideas": { + "name": "ideas", + "schema": "planning", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pitch": { + "name": "pitch", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "program": { + "name": "program", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "topic": { + "name": "topic", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'idea'" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "inspired_by_event_id": { + "name": "inspired_by_event_id", + "type": "uuid", + "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": { + "ideas_event_id_events_id_fk": { + "name": "ideas_event_id_events_id_fk", + "tableFrom": "ideas", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "ideas_inspired_by_event_id_events_id_fk": { + "name": "ideas_inspired_by_event_id_events_id_fk", + "tableFrom": "ideas", + "tableTo": "events", + "columnsFrom": ["inspired_by_event_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "ideas_event_id_unique": { + "name": "ideas_event_id_unique", + "nullsNotDistinct": false, + "columns": ["event_id"] + } + }, + "policies": {}, + "checkConstraints": { + "ideas_title_check": { + "name": "ideas_title_check", + "value": "btrim(\"title\") <> ''" + }, + "ideas_pitch_check": { + "name": "ideas_pitch_check", + "value": "btrim(\"pitch\") <> ''" + }, + "ideas_program_check": { + "name": "ideas_program_check", + "value": "\"program\" IN ('talks', 'open-floor', 'social', 'hackathon')" + }, + "ideas_topic_check": { + "name": "ideas_topic_check", + "value": "char_length(\"topic\") <= 24\n AND \"topic\" IS NFC NORMALIZED\n AND \"topic\" = lower(\"topic\" COLLATE \"pg_c_utf8\")\n AND strpos(\"topic\", 'all things') = 0\n AND \"topic\" COLLATE \"pg_c_utf8\" ~ '^[[:alpha:][:digit:]](?:[[:alpha:][:digit:].&+#'']|(?<=[^ ]) (?=[^ ])|(?<=[[:alpha:][:digit:]])-(?=[[:alpha:][:digit:]]))*$'" + }, + "ideas_status_check": { + "name": "ideas_status_check", + "value": "\"status\" IN ('idea', 'drafting', 'scheduled', 'dropped')" + }, + "ideas_scheduled_event_check": { + "name": "ideas_scheduled_event_check", + "value": "\"status\" <> 'scheduled' OR \"event_id\" IS NOT NULL" + } + }, + "isRLSEnabled": false + }, + "planning.notes": { + "name": "notes", + "schema": "planning", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "profile_id": { + "name": "profile_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "sponsor_id": { + "name": "sponsor_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "contact_id": { + "name": "contact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "author": { + "name": "author", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "notes_profile_id_idx": { + "name": "notes_profile_id_idx", + "columns": [ + { + "expression": "profile_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "notes_sponsor_id_idx": { + "name": "notes_sponsor_id_idx", + "columns": [ + { + "expression": "sponsor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "notes_contact_id_idx": { + "name": "notes_contact_id_idx", + "columns": [ + { + "expression": "contact_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "notes_profile_id_profiles_id_fk": { + "name": "notes_profile_id_profiles_id_fk", + "tableFrom": "notes", + "tableTo": "profiles", + "columnsFrom": ["profile_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "notes_sponsor_id_sponsors_id_fk": { + "name": "notes_sponsor_id_sponsors_id_fk", + "tableFrom": "notes", + "tableTo": "sponsors", + "columnsFrom": ["sponsor_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "notes_contact_id_contacts_id_fk": { + "name": "notes_contact_id_contacts_id_fk", + "tableFrom": "notes", + "tableTo": "contacts", + "schemaTo": "planning", + "columnsFrom": ["contact_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "notes_subject_check": { + "name": "notes_subject_check", + "value": "num_nonnulls(\"profile_id\", \"sponsor_id\", \"contact_id\") = 1" + }, + "notes_body_check": { + "name": "notes_body_check", + "value": "btrim(\"body\") <> ''" + }, + "notes_author_check": { + "name": "notes_author_check", + "value": "btrim(\"author\") <> ''" + } + }, + "isRLSEnabled": false + }, + "planning.sent_posts": { + "name": "sent_posts", + "schema": "planning", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "moment": { + "name": "moment", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'sending'" + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "claimed_at": { + "name": "claimed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "sent_at": { + "name": "sent_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "sent_posts_event_id_events_id_fk": { + "name": "sent_posts_event_id_events_id_fk", + "tableFrom": "sent_posts", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "sent_posts_channel_event_id_moment_unique": { + "name": "sent_posts_channel_event_id_moment_unique", + "nullsNotDistinct": false, + "columns": ["channel", "event_id", "moment"] + } + }, + "policies": {}, + "checkConstraints": { + "sent_posts_channel_check": { + "name": "sent_posts_channel_check", + "value": "\"channel\" IN ('discord', 'x')" + }, + "sent_posts_moment_check": { + "name": "sent_posts_moment_check", + "value": "\"moment\" IN ('announce', 'dayOf', 'recap')" + }, + "sent_posts_token_check": { + "name": "sent_posts_token_check", + "value": "\"token\" ~ '^[0-9a-f]{16}$'" + }, + "sent_posts_status_check": { + "name": "sent_posts_status_check", + "value": "\"status\" IN ('sending', 'unanswered', 'sent')" + }, + "sent_posts_sent_check": { + "name": "sent_posts_sent_check", + "value": "(\"status\" = 'sent') = (\"message_id\" IS NOT NULL AND \"url\" IS NOT NULL AND \"sent_at\" IS NOT NULL)" + }, + "sent_posts_url_check": { + "name": "sent_posts_url_check", + "value": "\"url\" ~ '^https://[^[:space:]]+$'" + } + }, + "isRLSEnabled": false + }, + "planning.wanted_speaker_topics": { + "name": "wanted_speaker_topics", + "schema": "planning", + "columns": { + "wanted_speaker_id": { + "name": "wanted_speaker_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "topic": { + "name": "topic", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "wanted_speaker_topics_topic_idx": { + "name": "wanted_speaker_topics_topic_idx", + "columns": [ + { + "expression": "topic", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "wanted_speaker_topics_wanted_speaker_id_wanted_speakers_id_fk": { + "name": "wanted_speaker_topics_wanted_speaker_id_wanted_speakers_id_fk", + "tableFrom": "wanted_speaker_topics", + "tableTo": "wanted_speakers", + "schemaTo": "planning", + "columnsFrom": ["wanted_speaker_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "wanted_speaker_topics_wanted_speaker_id_topic_pk": { + "name": "wanted_speaker_topics_wanted_speaker_id_topic_pk", + "columns": ["wanted_speaker_id", "topic"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "wanted_speaker_topics_topic_check": { + "name": "wanted_speaker_topics_topic_check", + "value": "char_length(\"topic\") <= 24\n AND \"topic\" IS NFC NORMALIZED\n AND \"topic\" = lower(\"topic\" COLLATE \"pg_c_utf8\")\n AND strpos(\"topic\", 'all things') = 0\n AND \"topic\" COLLATE \"pg_c_utf8\" ~ '^[[:alpha:][:digit:]](?:[[:alpha:][:digit:].&+#'']|(?<=[^ ]) (?=[^ ])|(?<=[[:alpha:][:digit:]])-(?=[[:alpha:][:digit:]]))*$'" + } + }, + "isRLSEnabled": false + }, + "planning.wanted_speakers": { + "name": "wanted_speakers", + "schema": "planning", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "profile_id": { + "name": "profile_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "contact_id": { + "name": "contact_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'wanted'" + }, + "note": { + "name": "note", + "type": "text", + "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": { + "wanted_speakers_profile_id_profiles_id_fk": { + "name": "wanted_speakers_profile_id_profiles_id_fk", + "tableFrom": "wanted_speakers", + "tableTo": "profiles", + "columnsFrom": ["profile_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "wanted_speakers_contact_id_contacts_id_fk": { + "name": "wanted_speakers_contact_id_contacts_id_fk", + "tableFrom": "wanted_speakers", + "tableTo": "contacts", + "schemaTo": "planning", + "columnsFrom": ["contact_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "wanted_speakers_profile_id_unique": { + "name": "wanted_speakers_profile_id_unique", + "nullsNotDistinct": false, + "columns": ["profile_id"] + }, + "wanted_speakers_contact_id_unique": { + "name": "wanted_speakers_contact_id_unique", + "nullsNotDistinct": false, + "columns": ["contact_id"] + } + }, + "policies": {}, + "checkConstraints": { + "wanted_speakers_person_check": { + "name": "wanted_speakers_person_check", + "value": "num_nonnulls(\"profile_id\", \"contact_id\") = 1" + }, + "wanted_speakers_status_check": { + "name": "wanted_speakers_status_check", + "value": "\"status\" IN ('wanted', 'asked', 'confirmed', 'declined')" + } + }, + "isRLSEnabled": false + }, + "public.profile_slugs": { + "name": "profile_slugs", + "schema": "", + "columns": { + "slug": { + "name": "slug", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "profile_id": { + "name": "profile_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "profile_slugs_profile_id_idx": { + "name": "profile_slugs_profile_id_idx", + "columns": [ + { + "expression": "profile_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "profile_slugs_profile_id_profiles_id_fk": { + "name": "profile_slugs_profile_id_profiles_id_fk", + "tableFrom": "profile_slugs", + "tableTo": "profiles", + "columnsFrom": ["profile_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "profile_slugs_slug_check": { + "name": "profile_slugs_slug_check", + "value": "\"slug\" ~ '^[a-z0-9]+(-[a-z0-9]+)*$'" + } + }, + "isRLSEnabled": false + }, + "public.profiles": { + "name": "profiles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "twitter_handle": { + "name": "twitter_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bluesky_handle": { + "name": "bluesky_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "linkedin_handle": { + "name": "linkedin_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "photo_source_url": { + "name": "photo_source_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bio": { + "name": "bio", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "profile_type": { + "name": "profile_type", + "type": "profile_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "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 + }, + "luma_user_id": { + "name": "luma_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "x_followers": { + "name": "x_followers", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "x_followers_at": { + "name": "x_followers_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "x_followers_tried_at": { + "name": "x_followers_tried_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "x_user_id": { + "name": "x_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "x_handle_lost": { + "name": "x_handle_lost", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "x_handle_lost_at": { + "name": "x_handle_lost_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "profiles_image_images_id_fk": { + "name": "profiles_image_images_id_fk", + "tableFrom": "profiles", + "tableTo": "images", + "columnsFrom": ["image"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "profiles_luma_user_id_unique": { + "name": "profiles_luma_user_id_unique", + "nullsNotDistinct": false, + "columns": ["luma_user_id"] + }, + "profiles_slug_unique": { + "name": "profiles_slug_unique", + "nullsNotDistinct": false, + "columns": ["slug"] + }, + "profiles_x_user_id_unique": { + "name": "profiles_x_user_id_unique", + "nullsNotDistinct": false, + "columns": ["x_user_id"] + } + }, + "policies": {}, + "checkConstraints": { + "profiles_luma_user_id_check": { + "name": "profiles_luma_user_id_check", + "value": "\"luma_user_id\" ~ '^usr-[A-Za-z0-9]+$'" + }, + "profiles_x_followers_check": { + "name": "profiles_x_followers_check", + "value": "\"x_followers\" >= 0" + }, + "profiles_x_followers_at_check": { + "name": "profiles_x_followers_at_check", + "value": "(\"x_followers\" IS NULL) = (\"x_followers_at\" IS NULL)" + }, + "profiles_slug_check": { + "name": "profiles_slug_check", + "value": "\"slug\" ~ '^[a-z0-9]+(-[a-z0-9]+)*$'" + }, + "profiles_x_user_id_check": { + "name": "profiles_x_user_id_check", + "value": "\"x_user_id\" ~ '^[0-9]{1,20}$'" + }, + "profiles_x_handle_lost_check": { + "name": "profiles_x_handle_lost_check", + "value": "(\"x_handle_lost\" IS NULL) = (\"x_handle_lost_at\" IS NULL)" + } + }, + "isRLSEnabled": false + }, + "public.redirects": { + "name": "redirects", + "schema": "", + "columns": { + "slug": { + "name": "slug", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "destination_url": { + "name": "destination_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "comment": { + "name": "comment", + "type": "text", + "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 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.talk_speakers": { + "name": "talk_speakers", + "schema": "", + "columns": { + "talk_id": { + "name": "talk_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "speaker_id": { + "name": "speaker_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "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 + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'speaker'" + } + }, + "indexes": {}, + "foreignKeys": { + "talk_speakers_talk_id_talks_id_fk": { + "name": "talk_speakers_talk_id_talks_id_fk", + "tableFrom": "talk_speakers", + "tableTo": "talks", + "columnsFrom": ["talk_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "talk_speakers_speaker_id_profiles_id_fk": { + "name": "talk_speakers_speaker_id_profiles_id_fk", + "tableFrom": "talk_speakers", + "tableTo": "profiles", + "columnsFrom": ["speaker_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "talk_speakers_talk_id_speaker_id_pk": { + "name": "talk_speakers_talk_id_speaker_id_pk", + "columns": ["talk_id", "speaker_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "talk_speakers_role_check": { + "name": "talk_speakers_role_check", + "value": "\"role\" IN ('speaker', 'moderator')" + } + }, + "isRLSEnabled": false + }, + "public.talks": { + "name": "talks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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 + }, + "format": { + "name": "format", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'talk'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "talks_format_check": { + "name": "talks_format_check", + "value": "\"format\" IN ('talk', 'panel', 'fireside')" + } + }, + "isRLSEnabled": false + } + }, + "enums": { + "public.profile_type": { + "name": "profile_type", + "schema": "public", + "values": ["organizer", "member"] + } + }, + "schemas": { + "planning": "planning" + }, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/app/migrations/meta/_journal.json b/app/migrations/meta/_journal.json index 4f899ed0..96e7d631 100644 --- a/app/migrations/meta/_journal.json +++ b/app/migrations/meta/_journal.json @@ -246,6 +246,13 @@ "when": 1791353526953, "tag": "0034_x_sent_posts", "breakpoints": true + }, + { + "idx": 35, + "version": "7", + "when": 1791397442585, + "tag": "0035_drop_admin_tables", + "breakpoints": true } ] } diff --git a/app/src/lib/schema.ts b/app/src/lib/schema.ts index e03021c2..9a53e1fb 100644 --- a/app/src/lib/schema.ts +++ b/app/src/lib/schema.ts @@ -17,9 +17,6 @@ import { uniqueIndex, } from "drizzle-orm/pg-core"; import { sql } from "drizzle-orm"; -import { usersSync as usersSyncTable } from "drizzle-orm/neon"; - -export { usersSyncTable }; const createdAt = timestamp("created_at", { withTimezone: true }) .notNull() @@ -631,37 +628,6 @@ export type InsertEventReviewSession = export type SelectEventReviewSession = typeof eventReviewSessionsTable.$inferSelect; -export const administratorsTable = pgTable("administrators", { - id: uuid("id").primaryKey().defaultRandom(), - userId: text("user_id") - .notNull() - .references(() => usersSyncTable.id), - createdAt, - updatedAt, -}); - -export type InsertAdministrator = typeof administratorsTable.$inferInsert; -export type SelectAdministrator = typeof administratorsTable.$inferSelect; - -export const profileUsersTable = pgTable( - "profile_users", - { - profileId: uuid("profile_id") - .notNull() - .references(() => profilesTable.id) - .unique(), // One profile can only be associated with one user - userId: text("user_id") - .notNull() - .references(() => usersSyncTable.id), - createdAt, - updatedAt, - }, - (table) => [primaryKey({ columns: [table.profileId, table.userId] })], -); - -export type InsertProfileUser = typeof profileUsersTable.$inferInsert; -export type SelectProfileUser = typeof profileUsersTable.$inferSelect; - /** * Planning: ideas for evenings, speakers we'd like on stage and when they're * free, companies we'd like to host, and notes on the people and companies diff --git a/app/tests/short-links.test.ts b/app/tests/short-links.test.ts index dafe0785..1cd5e6e1 100644 --- a/app/tests/short-links.test.ts +++ b/app/tests/short-links.test.ts @@ -16,7 +16,6 @@ import * as schema from "../src/lib/schema"; const client = new PGlite(); const db = drizzle(client); beforeAll(async () => { - await client.exec("CREATE SCHEMA IF NOT EXISTS neon_auth"); for (const statement of await generateMigration( generateDrizzleJson({}), generateDrizzleJson(schema), diff --git a/app/tests/support/schema.ts b/app/tests/support/schema.ts index 1fd23ac2..fb47c2ad 100644 --- a/app/tests/support/schema.ts +++ b/app/tests/support/schema.ts @@ -10,7 +10,6 @@ import * as schema from "../../src/lib/schema"; * without what production runs. */ export async function createSchema(client: PGlite): Promise { - await client.exec("CREATE SCHEMA IF NOT EXISTS neon_auth"); for (const statement of await generateMigration( generateDrizzleJson({}), generateDrizzleJson(schema), diff --git a/core/README.md b/core/README.md index ca398a6b..926862bc 100644 --- a/core/README.md +++ b/core/README.md @@ -1008,6 +1008,14 @@ those files do not record. The test lists each difference with its reason. migration adds, and the tests hold the migrations to it both in PGlite and on Postgres 17 (`tests/postgres.test.ts`, in CI). +`neon_auth` is Neon Auth's schema, not ours. The baseline still makes a +stand-in `neon_auth.users_sync` where Neon Auth isn't on (tests, local +Postgres), because production had it in 2026-10. Since +`0023_drop_admin_tables`, nothing of the site's references it, and the +snapshot (`src/schema-snapshot.ts`) compares only `public` and `planning`. +So Neon Auth on or off changes nothing the migrations or tests check; a +test drops the schema to show it. + ### Running them ```sh diff --git a/core/migrations/0023_drop_admin_tables.ts b/core/migrations/0023_drop_admin_tables.ts new file mode 100644 index 00000000..e528270f --- /dev/null +++ b/core/migrations/0023_drop_admin_tables.ts @@ -0,0 +1,26 @@ +import { statements } from "./statements.ts"; + +/** + * The old app's admin and members' sign-in are gone (app/ no longer has + * them), so the two tables that tied Neon Auth's users to the site go too: + * `administrators`, who could use the admin, and `profile_users`, which + * profile a signed-in user could edit. They were the only references from + * the site's schemas to `neon_auth.users_sync`, so Neon Auth can be turned + * off without breaking anything here. `neon_auth` itself is Neon's, and is + * left alone. + * + * No CASCADE: if anything else came to depend on either table, this fails + * rather than dropping it silently. + * + * Ships with the app's drizzle migration 0035_drop_admin_tables, which drops + * the same two tables (with CASCADE, as drizzle writes a drop). The app's + * drizzle schema stops declaring `neon_auth.users_sync` too; drizzle-kit + * wrote a drop of it into 0035, taken out by hand, since `neon_auth` is + * Neon's. + */ +export const dropAdminTables: ReadonlyArray = [ + `DROP TABLE "public"."profile_users"`, + `DROP TABLE "public"."administrators"`, +]; + +export default statements(dropAdminTables); diff --git a/core/migrations/index.ts b/core/migrations/index.ts index 3bc6ef3f..d1e9532f 100644 --- a/core/migrations/index.ts +++ b/core/migrations/index.ts @@ -21,6 +21,7 @@ import xUserIdsMigration from "./0019_x_user_ids.ts"; import venueByOrganizerMigration from "./0020_venue_by_organizer.ts"; import sentPostsMigration from "./0021_sent_posts.ts"; import xSentPostsMigration from "./0022_x_sent_posts.ts"; +import dropAdminTablesMigration from "./0023_drop_admin_tables.ts"; import type { Migration } from "./statements.ts"; /** @@ -52,6 +53,7 @@ export const migrations: Readonly> = { "0020_venue_by_organizer": venueByOrganizerMigration, "0021_sent_posts": sentPostsMigration, "0022_x_sent_posts": xSentPostsMigration, + "0023_drop_admin_tables": dropAdminTablesMigration, }; /** The migrations, in id order, for the migrator. */ diff --git a/core/src/schema-snapshot.ts b/core/src/schema-snapshot.ts index 2d7cfc9c..f869b961 100644 --- a/core/src/schema-snapshot.ts +++ b/core/src/schema-snapshot.ts @@ -6,15 +6,18 @@ import type { SqlError } from "effect/sql/SqlError"; * A database's schema as sorted lines of text, read from the catalog, so two * databases can be compared exactly and their differences read as a diff. * - * It covers the schemas the app's tables live in: `public`; `neon_auth`, - * whose `users_sync` table Neon Auth owns and the app references; and - * `planning`, the organizers' private planning (migrations/0012_planning.ts). Each line is - * one object: a relation (with its row security and options), a column (its - * position among the table's live columns, type, nullability, default, - * identity, generation and collation), a constraint (primary, unique, check - * and foreign keys with their actions, as Postgres prints them), an index (its - * full definition, and whether it is valid), an enum (labels in order), a domain or other type, a - * sequence, a view, a trigger, a row security policy, a routine or a comment. + * It covers the schemas the app's tables live in: `public`, and `planning`, + * the organizers' private planning (migrations/0012_planning.ts). Not + * `neon_auth`: since migrations/0023_drop_admin_tables.ts nothing of the + * site's references it, and it is Neon's to keep or drop, so whether Neon + * Auth is on never changes the snapshot. Each line is one object: a + * relation (with its row security and options), a column (its position + * among the table's live columns, type, nullability, default, identity, + * generation and collation), a constraint (primary, unique, check and + * foreign keys with their actions, as Postgres prints them), an index (its + * full definition, and whether it is valid), an enum (labels in order), a + * domain or other type, a sequence, a view, a trigger, a row security + * policy, a routine or a comment. * * Owners and grants are left out: they belong to the environment (Neon's * roles), not to the schema the migrations create. So are the NOT NULL @@ -23,11 +26,7 @@ import type { SqlError } from "effect/sql/SqlError"; */ /** The schemas compared. */ -export const schemas: ReadonlyArray = [ - "public", - "neon_auth", - "planning", -]; +export const schemas: ReadonlyArray = ["public", "planning"]; /** * Objects the platform keeps in those schemas that no migration creates, each diff --git a/core/tests/fixtures/production-schema.txt b/core/tests/fixtures/production-schema.txt index 83e73b83..f6d33386 100644 --- a/core/tests/fixtures/production-schema.txt +++ b/core/tests/fixtures/production-schema.txt @@ -1,10 +1,3 @@ -column neon_auth.users_sync #001 raw_json jsonb not null -column neon_auth.users_sync #002 id text not null generated always as ((raw_json ->> 'id'::text)) stored -column neon_auth.users_sync #003 name text generated always as ((raw_json ->> 'display_name'::text)) stored -column neon_auth.users_sync #004 email text generated always as ((raw_json ->> 'primary_email'::text)) stored -column neon_auth.users_sync #005 created_at timestamp with time zone generated always as (to_timestamp((trunc((((raw_json ->> 'signed_up_at_millis'::text))::bigint)::double precision) / (1000)::double precision))) stored -column neon_auth.users_sync #006 updated_at timestamp with time zone -column neon_auth.users_sync #007 deleted_at timestamp with time zone column planning.availability #001 id uuid not null default gen_random_uuid() column planning.availability #002 wanted_speaker_id uuid not null column planning.availability #003 kind text not null default 'available'::text @@ -64,10 +57,6 @@ column planning.wanted_speakers #004 status text not null default 'wanted'::text column planning.wanted_speakers #005 note text column planning.wanted_speakers #006 created_at timestamp with time zone not null default now() column planning.wanted_speakers #007 updated_at timestamp with time zone not null default now() -column public.administrators #001 id uuid not null default gen_random_uuid() -column public.administrators #002 user_id text not null -column public.administrators #003 created_at timestamp with time zone not null default now() -column public.administrators #004 updated_at timestamp with time zone not null column public.event_images #001 event_id uuid not null column public.event_images #002 image_id uuid not null column public.event_images #003 created_at timestamp with time zone not null default now() @@ -184,10 +173,6 @@ column public.images #008 height integer not null column public.profile_slugs #001 slug text not null column public.profile_slugs #002 profile_id uuid not null column public.profile_slugs #003 created_at timestamp with time zone not null default now() -column public.profile_users #001 profile_id uuid not null -column public.profile_users #002 user_id text not null -column public.profile_users #003 created_at timestamp with time zone not null default now() -column public.profile_users #004 updated_at timestamp with time zone not null column public.profiles #001 id uuid not null default gen_random_uuid() column public.profiles #002 name text not null column public.profiles #003 title text not null @@ -236,7 +221,6 @@ column public.talks #003 description text not null column public.talks #004 created_at timestamp with time zone not null default now() column public.talks #005 updated_at timestamp with time zone not null column public.talks #006 format text not null default 'talk'::text -constraint neon_auth.users_sync users_sync_pkey PRIMARY KEY (id) constraint planning.availability availability_kind_check CHECK ((kind = ANY (ARRAY['available'::text, 'unavailable'::text]))) constraint planning.availability availability_order_check CHECK ((starts_on <= ends_on)) constraint planning.availability availability_pkey PRIMARY KEY (id) @@ -290,8 +274,6 @@ constraint planning.wanted_speakers wanted_speakers_pkey PRIMARY KEY (id) constraint planning.wanted_speakers wanted_speakers_profile_id_profiles_id_fk FOREIGN KEY (profile_id) REFERENCES profiles(id) constraint planning.wanted_speakers wanted_speakers_profile_id_unique UNIQUE (profile_id) constraint planning.wanted_speakers wanted_speakers_status_check CHECK ((status = ANY (ARRAY['wanted'::text, 'asked'::text, 'confirmed'::text, 'declined'::text]))) -constraint public.administrators administrators_pkey PRIMARY KEY (id) -constraint public.administrators administrators_user_id_users_sync_id_fk FOREIGN KEY (user_id) REFERENCES neon_auth.users_sync(id) constraint public.event_images event_images_event_id_events_id_fk FOREIGN KEY (event_id) REFERENCES events(id) constraint public.event_images event_images_event_id_image_id_pk PRIMARY KEY (event_id, image_id) constraint public.event_images event_images_image_id_images_id_fk FOREIGN KEY (image_id) REFERENCES images(id) @@ -354,10 +336,6 @@ constraint public.images images_pkey PRIMARY KEY (id) constraint public.profile_slugs profile_slugs_pkey PRIMARY KEY (slug) constraint public.profile_slugs profile_slugs_profile_id_profiles_id_fk FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE constraint public.profile_slugs profile_slugs_slug_check CHECK ((slug ~ '^[a-z0-9]+(-[a-z0-9]+)*$'::text)) -constraint public.profile_users profile_users_profile_id_profiles_id_fk FOREIGN KEY (profile_id) REFERENCES profiles(id) -constraint public.profile_users profile_users_profile_id_unique UNIQUE (profile_id) -constraint public.profile_users profile_users_profile_id_user_id_pk PRIMARY KEY (profile_id, user_id) -constraint public.profile_users profile_users_user_id_users_sync_id_fk FOREIGN KEY (user_id) REFERENCES neon_auth.users_sync(id) constraint public.profiles profiles_image_images_id_fk FOREIGN KEY (image) REFERENCES images(id) ON DELETE SET NULL constraint public.profiles profiles_luma_user_id_check CHECK ((luma_user_id ~ '^usr-[A-Za-z0-9]+$'::text)) constraint public.profiles profiles_luma_user_id_unique UNIQUE (luma_user_id) @@ -387,8 +365,6 @@ constraint public.talk_speakers talk_speakers_talk_id_talks_id_fk FOREIGN KEY (t constraint public.talks talks_format_check CHECK ((format = ANY (ARRAY['talk'::text, 'panel'::text, 'fireside'::text]))) constraint public.talks talks_pkey PRIMARY KEY (id) enum public.profile_type ('organizer', 'member') -index neon_auth.users_sync CREATE INDEX users_sync_deleted_at_idx ON neon_auth.users_sync USING btree (deleted_at) -index neon_auth.users_sync CREATE UNIQUE INDEX users_sync_pkey ON neon_auth.users_sync USING btree (id) index planning.availability CREATE INDEX availability_wanted_speaker_id_idx ON planning.availability USING btree (wanted_speaker_id) index planning.availability CREATE UNIQUE INDEX availability_pkey ON planning.availability USING btree (id) index planning.contacts CREATE UNIQUE INDEX contacts_pkey ON planning.contacts USING btree (id) @@ -408,7 +384,6 @@ index planning.wanted_speaker_topics CREATE UNIQUE INDEX wanted_speaker_topics_w index planning.wanted_speakers CREATE UNIQUE INDEX wanted_speakers_contact_id_unique ON planning.wanted_speakers USING btree (contact_id) index planning.wanted_speakers CREATE UNIQUE INDEX wanted_speakers_pkey ON planning.wanted_speakers USING btree (id) index planning.wanted_speakers CREATE UNIQUE INDEX wanted_speakers_profile_id_unique ON planning.wanted_speakers USING btree (profile_id) -index public.administrators CREATE UNIQUE INDEX administrators_pkey ON public.administrators USING btree (id) index public.event_images CREATE UNIQUE INDEX event_images_event_id_image_id_pk ON public.event_images USING btree (event_id, image_id) index public.event_notes CREATE UNIQUE INDEX event_notes_event_id_position_pk ON public.event_notes USING btree (event_id, "position") index public.event_people CREATE UNIQUE INDEX event_people_event_id_profile_id_role_pk ON public.event_people USING btree (event_id, profile_id, role) @@ -433,8 +408,6 @@ index public.external_talks CREATE UNIQUE INDEX external_talks_profile_id_title_ index public.images CREATE UNIQUE INDEX images_pkey ON public.images USING btree (id) index public.profile_slugs CREATE INDEX profile_slugs_profile_id_idx ON public.profile_slugs USING btree (profile_id) index public.profile_slugs CREATE UNIQUE INDEX profile_slugs_pkey ON public.profile_slugs USING btree (slug) -index public.profile_users CREATE UNIQUE INDEX profile_users_profile_id_unique ON public.profile_users USING btree (profile_id) -index public.profile_users CREATE UNIQUE INDEX profile_users_profile_id_user_id_pk ON public.profile_users USING btree (profile_id, user_id) index public.profiles CREATE UNIQUE INDEX profiles_luma_user_id_unique ON public.profiles USING btree (luma_user_id) index public.profiles CREATE UNIQUE INDEX profiles_pkey ON public.profiles USING btree (id) index public.profiles CREATE UNIQUE INDEX profiles_slug_unique ON public.profiles USING btree (slug) @@ -445,7 +418,6 @@ index public.sponsors CREATE UNIQUE INDEX sponsors_name_unique ON public.sponsor index public.sponsors CREATE UNIQUE INDEX sponsors_pkey ON public.sponsors USING btree (id) index public.talk_speakers CREATE UNIQUE INDEX talk_speakers_talk_id_speaker_id_pk ON public.talk_speakers USING btree (talk_id, speaker_id) index public.talks CREATE UNIQUE INDEX talks_pkey ON public.talks USING btree (id) -relation neon_auth.users_sync kind=r persistence=p rls=f force_rls=f replica_identity=d options= relation planning.availability kind=r persistence=p rls=f force_rls=f replica_identity=d options= relation planning.contacts kind=r persistence=p rls=f force_rls=f replica_identity=d options= relation planning.host_prospects kind=r persistence=p rls=f force_rls=f replica_identity=d options= @@ -454,7 +426,6 @@ relation planning.notes kind=r persistence=p rls=f force_rls=f replica_identity= relation planning.sent_posts kind=r persistence=p rls=f force_rls=f replica_identity=d options= relation planning.wanted_speaker_topics kind=r persistence=p rls=f force_rls=f replica_identity=d options= relation planning.wanted_speakers kind=r persistence=p rls=f force_rls=f replica_identity=d options= -relation public.administrators kind=r persistence=p rls=f force_rls=f replica_identity=d options= relation public.event_images kind=r persistence=p rls=f force_rls=f replica_identity=d options= relation public.event_notes kind=r persistence=p rls=f force_rls=f replica_identity=d options= relation public.event_people kind=r persistence=p rls=f force_rls=f replica_identity=d options= @@ -468,7 +439,6 @@ relation public.events kind=r persistence=p rls=f force_rls=f replica_identity=f relation public.external_talks kind=r persistence=p rls=f force_rls=f replica_identity=d options= relation public.images kind=r persistence=p rls=f force_rls=f replica_identity=f options= relation public.profile_slugs kind=r persistence=p rls=f force_rls=f replica_identity=d options= -relation public.profile_users kind=r persistence=p rls=f force_rls=f replica_identity=d options= relation public.profiles kind=r persistence=p rls=f force_rls=f replica_identity=d options= relation public.redirects kind=r persistence=p rls=f force_rls=f replica_identity=d options= relation public.sponsors kind=r persistence=p rls=f force_rls=f replica_identity=d options= diff --git a/core/tests/migrations.test.ts b/core/tests/migrations.test.ts index 77253d30..2541c7f4 100644 --- a/core/tests/migrations.test.ts +++ b/core/tests/migrations.test.ts @@ -168,18 +168,33 @@ describe("core/migrations", () => { test("an invalid index shows in the snapshot", async () => { const db = keep(await migratedDatabase()); await db.exec( - `UPDATE pg_catalog.pg_index SET indisvalid = false WHERE indexrelid = 'neon_auth.users_sync_deleted_at_idx'::regclass`, + `UPDATE pg_catalog.pg_index SET indisvalid = false WHERE indexrelid = 'public.event_posts_event_id_idx'::regclass`, ); expect(SchemaSnapshot.diff(fromMigrations, await snapshotOf(db))).toEqual({ missing: [ - "index neon_auth.users_sync CREATE INDEX users_sync_deleted_at_idx ON neon_auth.users_sync USING btree (deleted_at)", + "index public.event_posts CREATE INDEX event_posts_event_id_idx ON public.event_posts USING btree (event_id)", ], unexpected: [ - "index neon_auth.users_sync CREATE INDEX users_sync_deleted_at_idx ON neon_auth.users_sync USING btree (deleted_at) invalid", + "index public.event_posts CREATE INDEX event_posts_event_id_idx ON public.event_posts USING btree (event_id) invalid", ], }); }); + test("nothing of the site's references Neon Auth, so turning it off changes nothing checked", async () => { + const db = keep(await migratedDatabase()); + const references = await db.query<{ name: string }>( + `SELECT c.conname AS name FROM pg_catalog.pg_constraint c + WHERE c.confrelid IN ( + SELECT r.oid FROM pg_catalog.pg_class r + JOIN pg_catalog.pg_namespace n ON n.oid = r.relnamespace + WHERE n.nspname = 'neon_auth')`, + ); + expect(references.rows).toEqual([]); + // As turning Neon Auth off would leave it: no neon_auth at all. + await db.exec(`DROP SCHEMA "neon_auth" CASCADE`); + expect(await snapshotOf(db)).toEqual(fromMigrations); + }); + test("a platform object does not change the snapshot", async () => { const db = keep(await migratedDatabase()); await db.exec(