/*
sql code defining schema for registry database.

The schema itself looks roughly like this:
    runs: table of runs (or observations or other data source)
        run_id (PK): unique id for each run in this database.
        origin_id (FK): tells which origin this run came from (see below)
        origin_run_id: tells run_id of this entry in its original registry (NULL when origin_id=0)
        pc_uuid: unique uuid for this run. Saved to _pc_uuid.txt in the run directory.
        registered_at_first: datetime when this run was first registered
        registered_at: datetime when this run's data was last updated
        calculator_type: name of PlasmaCalculator class which called .register()
        ... more metadata about the run, e.g. datetime_run
    params: table of values of all input parameters across all runs
        param_id (PK): unique id for each param entry
        run_id (FK): run_id associated with this entry
        name: name of this param
        value: value of this param (if numerical), must be a single scalar
        value_text: value of this param (if string or anything more complicated like a list)
    metrics: table of values of all metrics across all runs
        metric_id (PK): unique id for each metric entry
        run_id (FK): run_id associated with this entry
        name: name of this metric
        value: value of this metric (numerical)
        is_pc_quantity: bool telling whether this metric was computed directly as a quantity or not
    register_history: table tracking calls to register() which caused any changes to database.
        history_id (PK): unique id for each history entry
        run_id (FK): run_id associated with this entry
        entered_at: datetime when this call to register() occurred
        pc_version: PlasmaCalcs.__version__ when .register() was called
        updated_metadata: list of metadata updated (i.e. value changed) by this call to register()
        updated_metrics: list of metrics updated (i.e. value changed) by this call to register()
    origins: table of origins (e.g. "which database did this entry come from")
        origin_id (PK): unique id for each origin in this database.
            origin_id = 0 is reserved for self, with name as canonical name for this database;
            name set to '__self__' by sql defaults, or set to "_unnamed_<short_uuid>" by python defaults,
            replacing <short_uuid> with unique identifier string, e.g. 'e0b4460e'.
        name: unique name for this origin

Note: codes running this should probably start with BEGIN; and end with COMMIT;
    but those aren't included here in case migrations or other lines are added later.
    E.g. if a seprate registry_postgre_schema.sql is needed for PostgreSQL later,
    then one might do BEGIN; <this file> <other file> COMMIT; instead.

SQLite reminder:
    for each connection, to enable FK constraints like ON DELETE CASCADE, make sure to do:
        PRAGMA foreign_keys = ON;
*/

CREATE TABLE origins (
    origin_id INTEGER PRIMARY KEY,
    name TEXT NOT NULL
);
CREATE UNIQUE INDEX ux_origins_name ON origins(name);
-- named index ^^ to allow schema update files to delete index easily,
-- e.g. when adding multiple users, will instead want unique origins(user_id, name).
INSERT INTO origins (origin_id, name) VALUES (0, '__self__');

CREATE TABLE runs (
    run_id INTEGER PRIMARY KEY,
    origin_id INTEGER NOT NULL,
    origin_run_id INTEGER,
    pc_uuid CHAR(32) NOT NULL UNIQUE,
    calculator_type TEXT NOT NULL,
    registered_at_first TIMESTAMP NOT NULL,
    registered_at TIMESTAMP NOT NULL,
    FOREIGN KEY (origin_id) REFERENCES origins(origin_id) ON DELETE CASCADE,
    CHECK ((origin_id = 0) == (origin_run_id IS NULL))  -- origin_id=0 when origin_run_id is NULL
);

CREATE TABLE params (
    param_id INTEGER PRIMARY KEY,  -- not really used here, but included for future-proofing.
    run_id INTEGER NOT NULL,
    name TEXT NOT NULL,
    value REAL,
    value_text TEXT,
    FOREIGN KEY (run_id) REFERENCES runs(run_id) ON DELETE CASCADE,
    CHECK ((value IS NULL) <> (value_text IS NULL)),  -- provide value or value_text, and not both.
    UNIQUE (run_id, name)  -- each (run_id, name) pair should only appear once.
);

CREATE TABLE metrics (
    metric_id INTEGER PRIMARY KEY,  -- not really used here, but included for future-proofing.
    run_id INTEGER NOT NULL,
    name TEXT NOT NULL,
    value REAL,
    is_pc_quantity BOOLEAN NOT NULL, -- whether this metric is a direct result of calculator(name)
    FOREIGN KEY (run_id) REFERENCES runs(run_id) ON DELETE CASCADE
    -- not forcing UNIQUE (run_id, name); e.g., might allow same-name if varying component=x,y,z.
);

CREATE TABLE register_history (
    history_id INTEGER PRIMARY KEY,  -- not really used here, but included for future-proofing.
    run_id INTEGER NOT NULL,
    origin_id INTEGER NOT NULL,  -- which origin caused this change; should be 0 for self-originated changes.
    entered_at TIMESTAMP NOT NULL,
    pc_version TEXT NOT NULL,
    updated_metadata TEXT,
    updated_metrics TEXT,
    FOREIGN KEY (run_id) REFERENCES runs(run_id) ON DELETE CASCADE,
    FOREIGN KEY (origin_id) REFERENCES origins(origin_id) -- CASCADE already handled by runs(run_id) FK.
);


/* indexes, for efficiency on common queries */
CREATE INDEX idx_params_run_id ON params(run_id);
CREATE INDEX idx_metrics_run_id ON metrics(run_id);
CREATE INDEX idx_register_history_run_id ON register_history(run_id);
