/*
sql code defining schema for registry database.

The schema itself looks like this:
    users: table of users (e.g. "who created this entry originally")
        user_id (PK): unique id for each user in this database.
            in local database, user_id=0 is reserved for unspecified user, username="__self__".
            in online database, user_id=0 is not allowed and all usernames must be specified.
        username: uniquely identifies this user across all databases.
    sources: table of sources (e.g. "which database did this entry come from")
        source_id (PK): unique id for each source in this database.
            source_id=0 is reserved for "this database".
        name: source name. Duplicates across registries are allowed but discouraged.
            default sql name is "__here__"; python updates to "_unnamed_{start_of_uuid}".
        source_uuid: uniquely identifies this source's database.
            default sql value is a bunch of 0s; python updates to an actual random uuid.
        creator_user_id (FK): user_id of the user who first created this source's database.
    runs: table of runs (or observations or other data source)
        run_id (PK): unique id for each run in this database.
        user_id (FK): tells which user last registered this run (see users table above)
        source_id (FK): tells which source this run came from (see below)
        source_run_id: tells run_id of this entry in its original registry (NULL when source_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
        user_id (FK): user_id telling which user made this register() call.
        source_id (FK): source_id telling which source this register() call occurred on.
        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()

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 users (
    user_id INTEGER PRIMARY KEY,
    username TEXT NOT NULL UNIQUE
);
INSERT INTO users (user_id, username) VALUES (0, '__self__');

CREATE TABLE sources (
    source_id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    source_uuid CHAR(32) NOT NULL,
    creator_user_id INTEGER NOT NULL,
    FOREIGN KEY (creator_user_id) REFERENCES users(user_id) ON DELETE CASCADE
);
INSERT INTO sources (source_id, name, source_uuid, creator_user_id)
    VALUES (0, '__here__', '00000000000000000000000000000000', 0);

CREATE TABLE runs (
    run_id INTEGER PRIMARY KEY,
    user_id INTEGER NOT NULL,
    source_id INTEGER NOT NULL,
    source_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 (source_id) REFERENCES sources(source_id) ON DELETE CASCADE,
    CHECK ((source_id = 0) == (source_run_id IS NULL))  -- source_id=0 when source_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 DOUBLE PRECISION,  -- "REAL" in sqlite matches postgres "DOUBLE PRECISION"
    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 DOUBLE PRECISION,
    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,
    user_id INTEGER NOT NULL,
    source_id INTEGER NOT NULL,
    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 (user_id) REFERENCES users(user_id) ON DELETE CASCADE,
    FOREIGN KEY (source_id) REFERENCES sources(source_id) ON DELETE CASCADE
);


/* 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);
