use cot::db::migrations::{MigrationContext, MigrationDependency, Operation, migration_op}; #[derive(Debug, Copy, Clone)] pub struct Migration; impl cot::db::migrations::Migration for Migration { const APP_NAME: &'static str = "meguri"; const MIGRATION_NAME: &'static str = "m_0008_workspaces"; const DEPENDENCIES: &'static [MigrationDependency] = &[MigrationDependency::migration("meguri", "m_0007_language")]; const OPERATIONS: &'static [Operation] = &[Operation::custom(upgrade).build()]; } #[migration_op] async fn upgrade(context: MigrationContext<'_>) -> cot::db::Result<()> { context.db.raw(r#"DO $$ BEGIN IF EXISTS(SELECT 1 FROM meguri__tenants) OR EXISTS(SELECT 1 FROM meguri__teams) THEN RAISE EXCEPTION 'Workspace schema requires a fresh database. Existing tenant/team data was not changed.'; END IF; DROP TABLE meguri__provider_objects,meguri__sync_jobs,meguri__audit_events,meguri__team_history,meguri__team_members,meguri__tenant_members,meguri__teams,meguri__tenants; CREATE TABLE meguri__workspaces(id text PRIMARY KEY,document text NOT NULL CHECK(jsonb_typeof(document::jsonb)='object'),revision bigint NOT NULL,created_at timestamptz NOT NULL,demo_deleted_at timestamptz); CREATE TABLE meguri__workspace_members(id text PRIMARY KEY,workspace_id text NOT NULL REFERENCES meguri__workspaces(id),user_id text NOT NULL REFERENCES meguri__users(id),permissions text NOT NULL CHECK(jsonb_typeof(permissions::jsonb)='array'),is_owner boolean NOT NULL,UNIQUE(workspace_id,user_id)); CREATE TABLE meguri__workspace_history(id text PRIMARY KEY,workspace_id text NOT NULL REFERENCES meguri__workspaces(id),revision bigint NOT NULL,document text NOT NULL,effective_at timestamptz NOT NULL,actor_id text,UNIQUE(workspace_id,revision)); CREATE TABLE meguri__audit_events(id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,workspace_id text NOT NULL REFERENCES meguri__workspaces(id),actor_id text,action text NOT NULL,details text NOT NULL,created_at timestamptz NOT NULL); CREATE TABLE meguri__sync_jobs(workspace_id text PRIMARY KEY REFERENCES meguri__workspaces(id),requested_revision bigint NOT NULL,published_revision bigint,state text NOT NULL,attempts integer NOT NULL,next_attempt timestamptz NOT NULL,last_error text,last_success timestamptz,window_end timestamptz,lease_token text,lease_until timestamptz); CREATE TABLE meguri__provider_objects(id text PRIMARY KEY,workspace_id text NOT NULL REFERENCES meguri__workspaces(id),object_key text NOT NULL,remote_id text NOT NULL,content text NOT NULL,updated_at timestamptz NOT NULL,UNIQUE(workspace_id,object_key)); CREATE INDEX workspace_sync_due ON meguri__sync_jobs(next_attempt); CREATE INDEX workspace_audit ON meguri__audit_events(workspace_id,id DESC); CREATE INDEX workspace_history_time ON meguri__workspace_history(workspace_id,effective_at); CREATE UNIQUE INDEX workspace_jsm_destination ON meguri__workspaces((document::jsonb->'integration'->>'cloud_id'),(document::jsonb->'integration'->>'team_id')) WHERE document::jsonb->'integration'->>'provider'='jsm'; END $$;"#).await?; Ok(()) }