begin transaction;

create domain NixPath as bytea
    check (length(value) = 20);
create domain SHA256Hash as bytea
    check (length(value) = 16);
create domain Ed25519Public as bytea
    check (length(value) = 32);
create domain SignatureBytes as bytea
    check (length(value) = 64);

create table PathName (
    hash NixPath not null primary key,
    -- Split off into a separate PathName table since a reference only requires
    -- a PathName exists but not necessarily a full NarInfo
    name text not null
);

-- Yoinked from https://git.lix.systems/lix-project/lix/src/e34833c0253340f47dc0add8609eb86cf9cba19b/src/libstore/binary-cache-store.cc#L151-L158
create type Compression as enum (
    'none',
    'bzip2',
    'zstd',
    'xz',
    'lzip',
    'lz4',
    'br'
);

-- There are no non sha256 CA hashes in the wild and we can honestly just tell anyone sending us one to go away
create type CAType as enum (
    'textsha256',
    'fixedrecsha256',
    'fixedflatsha256'
);

create table NarInfo (
    -- URL not needed (derivable from file_hash and compression)
    file_size bigint not null,
    nar_size bigint not null,

    hash NixPath primary key not null references PathName(hash),
    file_hash SHA256Hash not null,
    nar_hash SHA256Hash not null,
    ca_hash SHA256Hash,

    compression Compression not null,
    ca_type CAType
);

create table Reference (
    target NixPath not null references PathName(hash),
    by_narinfo NixPath not null references NarInfo(hash),
    primary key (target, by_narinfo)
);

create index reference_by_target on Reference using hash (target);
create index reference_by_referencer on Reference using hash (by_narinfo);

create table KeyName (
    id serial primary key,
    name text not null
);

comment on table KeyName is 'The Nix name for a key, which is often, but not strictly, related to the domain name';

-- FIXME: partitioning the system for security? e.g. can we make it so that the app *cannot* mess with public key validity periods?
create table BuilderPublicKey (
    id integer primary key references KeyName(id),
    public_key Ed25519Public not null,
    comment text,
    valid_from timestamptz,
    valid_until timestamptz
);

comment on table BuilderPublicKey is 'Public keys which iron-seal is willing to re-sign paths signed with';
comment on column BuilderPublicKey.valid_from is 'Signature time when the public key is first trusted for new signatures. If null, from a time in the indefinite past.';
comment on column BuilderPublicKey.valid_until is 'Signature time when the public key is last trusted for new signatures. If null, to a time in the indefinite future.';

create table OwnPublicKey (
    id integer primary key references KeyName(id),
    public_key Ed25519Public not null,
    comment text,
    valid_from timestamptz,
    valid_until timestamptz
);

comment on table OwnPublicKey is 'Public keys which iron-seal will sign paths with during their validity period';
comment on column OwnPublicKey.valid_from is 'Signature time when the public key will first be used for new signatures. If null, from a time in the indefinite past.';
comment on column OwnPublicKey.valid_until is 'Signature time when the public key will last be used for new signatures. If null, to a time in the indefinite future.';

create table Signature (
    path NixPath references NarInfo(hash),

    id serial primary key,
    signer integer not null references KeyName(id),
    sig_bytes SignatureBytes not null,
    signed_at timestamptz not null
);

comment on column Signature.signed_at is 'When the path was signed. For s3-sourced paths we have a reliable idea of it if we take the narinfo date as the signature date (and can assume there is no backdating by trusting s3)';

create unique index signature_path_only_signed_once on Signature (signer, path);

-- Definitely want to be able to look up signatures by store path
create index signature_by_path on Signature using hash (path);
-- Definitely want to be able to look up paths signed by a key
create index signature_by_signer on Signature (signer);

rollback;
