begin;

  -- credential_store
  create table credential_store (
    public_id wt_public_id primary key,
    scope_id wt_scope_id not null
      constraint iam_scope_fkey
        references iam_scope (public_id)
        on delete cascade
        on update cascade,

    -- The order of columns is important for performance. See:
    -- https://dba.stackexchange.com/questions/58970/enforcing-constraints-two-tables-away/58972#58972
    -- https://dba.stackexchange.com/questions/27481/is-a-composite-index-also-good-for-queries-on-the-first-field
    constraint credential_store_scope_id_public_id_uq
      unique(scope_id, public_id)
  );
  comment on table credential_store is
    'credential_store is a base table for the credential store type. '
    'Each row is owned by a single scope and maps 1-to-1 to a row in one of the credential store subtype tables.';

  create trigger immutable_columns before update on credential_store
    for each row execute procedure immutable_columns('public_id', 'scope_id');

  -- insert_credential_store_subtype() is a before insert trigger
  -- function for subtypes of credential_store
  create function insert_credential_store_subtype()
    returns trigger
  as $$
  begin
    insert into credential_store
      (public_id, scope_id)
    values
      (new.public_id, new.scope_id);
    return new;
  end;
  $$ language plpgsql;

  -- delete_credential_store_subtype() is an after delete trigger
  -- function for subtypes of credential_store
  create function delete_credential_store_subtype()
    returns trigger
  as $$
  begin
    delete from credential_store
    where public_id = old.public_id;
    return null; -- result is ignored since this is an after trigger
  end;
  $$ language plpgsql;


  -- credential_library
  create table credential_library (
    public_id wt_public_id primary key,
    store_id wt_public_id not null
      constraint credential_store_fkey
        references credential_store (public_id)
        on delete cascade
        on update cascade,
    constraint credential_library_store_id_public_id_uq
      unique(store_id, public_id)
  );
  comment on table credential_library is
    'credential_library is a base table for the credential library type and a child table of credential_store. '
    'Each row maps 1-to-1 to a row in one of the credential library subtype tables.';

  create trigger immutable_columns before update on credential_library
    for each row execute procedure immutable_columns('public_id', 'store_id');

  -- insert_credential_library_subtype() is a before insert trigger
  -- function for subtypes of credential_library
  create function insert_credential_library_subtype()
    returns trigger
  as $$
  begin
    insert into credential_library
      (public_id, store_id)
    values
      (new.public_id, new.store_id);
    return new;
  end;
  $$ language plpgsql;

  -- delete_credential_library_subtype() is an after delete trigger
  -- function for subtypes of credential_library
  create function delete_credential_library_subtype()
    returns trigger
  as $$
  begin
    delete from credential_library
    where public_id = old.public_id;
    return null; -- result is ignored since this is an after trigger
  end;
  $$ language plpgsql;

  -- credential
  create table credential (
    public_id wt_public_id primary key
  );
  comment on table credential is
    'credential is a base table for the credential type. ';

  create trigger immutable_columns before update on credential
    for each row execute procedure immutable_columns('public_id');

  -- insert_credential_subtype() is a before insert trigger
  -- function for subtypes of credential
  create function insert_credential_subtype()
    returns trigger
  as $$
  begin
    insert into credential
      (public_id)
    values
      (new.public_id);
    return new;
  end;
  $$ language plpgsql;

  -- delete_credential_subtype() is an after delete trigger
  -- function for subtypes of credential
  create function delete_credential_subtype()
    returns trigger
  as $$
  begin
    delete from credential
    where public_id = old.public_id;
    return null; -- result is ignored since this is an after trigger
  end;
  $$ language plpgsql;

  -- credential_static
  create table credential_static (
    public_id wt_public_id primary key
      constraint credential_fkey
        references credential (public_id)
        on delete cascade
        on update cascade,
    store_id wt_public_id not null
      constraint credential_store_fkey
        references credential_store (public_id)
        on delete cascade
        on update cascade,
    constraint credential_static_store_id_public_id_uq
      unique(store_id, public_id)
  );
  comment on table credential_static is
    'credential_static is a base table for the credential static type. '
    'It is a credential subtype and a child table of credential_store. ';

  create trigger immutable_columns before update on credential_static
    for each row execute procedure immutable_columns('public_id', 'store_id');

  create trigger insert_credential_subtype before insert on credential_static
    for each row execute procedure insert_credential_subtype();

  create trigger delete_credential_subtype after delete on credential_static
    for each row execute procedure delete_credential_subtype();

  -- insert_credential_static_subtype() is a before insert trigger
  -- function for subtypes of credential_static
  create function insert_credential_static_subtype()
    returns trigger
  as $$
  begin
    insert into credential_static
      (public_id, store_id)
    values
      (new.public_id, new.store_id);
    return new;
  end;
  $$ language plpgsql;

  -- delete_credential_static_subtype() is an after delete trigger
  -- function for subtypes of credential_static
  create function delete_credential_static_subtype()
    returns trigger
  as $$
  begin
    delete from credential_static
    where public_id = old.public_id;
    return null; -- result is ignored since this is an after trigger
  end;
  $$ language plpgsql;

  -- credential_dynamic
  create table credential_dynamic (
    public_id wt_public_id primary key
      constraint credential_fkey
        references credential (public_id)
        on delete cascade
        on update cascade,
    library_id wt_public_id not null
      constraint credential_library_fkey
        references credential_library (public_id)
        on delete cascade
        on update cascade,
    constraint credential_dynamic_library_id_public_id_uq
      unique(library_id, public_id)
  );
  comment on table credential_dynamic is
    'credential_dynamic is a base table for the credential dynamic type. '
    'It is a credential subtype and a child table of credential_library. ';

  create trigger immutable_columns before update on credential_dynamic
    for each row execute procedure immutable_columns('public_id', 'library_id');

  create trigger insert_credential_subtype before insert on credential_dynamic
    for each row execute procedure insert_credential_subtype();

  create trigger delete_credential_subtype after delete on credential_dynamic
    for each row execute procedure delete_credential_subtype();

  -- insert_credential_dynamic_subtype() is a before insert trigger
  -- function for subtypes of credential_dynamic
  create function insert_credential_dynamic_subtype()
    returns trigger
  as $$
  begin
    insert into credential_dynamic
      (public_id, library_id)
    values
      (new.public_id, new.library_id);
    return new;
  end;
  $$ language plpgsql;

  -- delete_credential_dynamic_subtype() is an after delete trigger
  -- function for subtypes of credential_dynamic
  create function delete_credential_dynamic_subtype()
    returns trigger
  as $$
  begin
    delete from credential_dynamic
    where public_id = old.public_id;
    return null; -- result is ignored since this is an after trigger
  end;
  $$ language plpgsql;

  create table credential_purpose_enm (
    name text primary key
      constraint only_predefined_credential_purposes_allowed
      check (
        name in (
          'application',
          'ingress',
          'egress'
        )
      )
  );
  comment on table credential_purpose_enm is
    'credential_purpose_enm is an enumeration table for credential purposes. '
    'It contains rows for representing the application, egress, and ingress credential purposes.';

  insert into credential_purpose_enm (name)
  values
    ('application'),
    ('ingress'),
    ('egress');

commit;
