120 lines · 4.1 KB
Raw Download
1
<?php
2
3
function config(): array
4
{
5
    static $cfg = null;
6
    return $cfg ??= require __DIR__ . '/config.php';
7
}
8
9
// Snapshot the database into data/backups/ before any write (add, edit,
10
// delete, bulk edit, usage deduction), so a botched change can be undone by
11
// copying a backup over filaments.sqlite. The newest 10 snapshots are kept.
12
function backup_db(): void
13
{
14
    $src = config()['db_path'];
15
    if (!is_file($src)) {
16
        return;
17
    }
18
    $dir = dirname($src) . '/backups';
19
    if (!is_dir($dir)) {
20
        mkdir($dir, 0775, true);
21
    }
22
    // Microseconds keep two writes within the same second from colliding.
23
    copy($src, $dir . '/filaments-' . (new DateTime())->format('Ymd-His-u') . '.sqlite');
24
    $old = glob($dir . '/filaments-*.sqlite');
25
    sort($old); // timestamped names sort chronologically
26
    foreach (array_slice($old, 0, max(0, count($old) - 10)) as $f) {
27
        unlink($f);
28
    }
29
}
30
31
function db(): PDO
32
{
33
    static $pdo = null;
34
    if ($pdo === null) {
35
        $path = config()['db_path'];
36
        $dir = dirname($path);
37
        if (!is_dir($dir)) {
38
            mkdir($dir, 0775, true);
39
        }
40
        $pdo = new PDO('sqlite:' . $path, null, null, [
41
            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
42
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
43
        ]);
44
        $pdo->exec('PRAGMA foreign_keys = ON');
45
        $pdo->exec(<<<SQL
46
CREATE TABLE IF NOT EXISTS filaments (
47
    id             INTEGER PRIMARY KEY AUTOINCREMENT,
48
    type           TEXT NOT NULL,
49
    color_hex      TEXT,
50
    color_hex2     TEXT,
51
    color_name     TEXT,
52
    brand          TEXT,
53
    total_weight_g REAL,
54
    spool_weight_g REAL,
55
    original_g     REAL DEFAULT 1000,
56
    remaining_g    REAL,
57
    abrasive       INTEGER NOT NULL DEFAULT 0,
58
    highflow       INTEGER NOT NULL DEFAULT 0,
59
    silk           INTEGER NOT NULL DEFAULT 0,
60
    matte          INTEGER NOT NULL DEFAULT 0,
61
    rainbow        INTEGER NOT NULL DEFAULT 0,
62
    transparent    INTEGER NOT NULL DEFAULT 0,
63
    twotone        INTEGER NOT NULL DEFAULT 0,
64
    sparkle        INTEGER NOT NULL DEFAULT 0,
65
    small_spool    INTEGER NOT NULL DEFAULT 0,
66
    cost           REAL,
67
    last_used_at   TEXT,
68
    notes          TEXT,
69
    created_at     TEXT DEFAULT (datetime('now')),
70
    updated_at     TEXT
71
);
72
CREATE TABLE IF NOT EXISTS usage_log (
73
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
74
    filament_id INTEGER NOT NULL REFERENCES filaments(id) ON DELETE CASCADE,
75
    grams       REAL NOT NULL,
76
    source_file TEXT,
77
    created_at  TEXT DEFAULT (datetime('now'))
78
);
79
CREATE TABLE IF NOT EXISTS settings (
80
    key   TEXT PRIMARY KEY,
81
    value TEXT
82
);
83
CREATE TABLE IF NOT EXISTS auth_tokens (
84
    id           INTEGER PRIMARY KEY AUTOINCREMENT,
85
    selector     TEXT NOT NULL UNIQUE,
86
    validator    TEXT NOT NULL,
87
    created_at   TEXT DEFAULT (datetime('now')),
88
    last_used_at TEXT
89
);
90
CREATE TABLE IF NOT EXISTS passkeys (
91
    id            INTEGER PRIMARY KEY AUTOINCREMENT,
92
    credential_id TEXT NOT NULL UNIQUE,
93
    public_key    TEXT NOT NULL,
94
    sign_count    INTEGER NOT NULL DEFAULT 0,
95
    rp_id         TEXT NOT NULL,
96
    label         TEXT,
97
    created_at    TEXT DEFAULT (datetime('now')),
98
    last_used_at  TEXT
99
);
100
SQL);
101
        // Databases created before these columns existed need them added.
102
        $cols = $pdo->query('PRAGMA table_info(filaments)')->fetchAll(PDO::FETCH_COLUMN, 1);
103
        if (!in_array('color_name', $cols, true)) {
104
            $pdo->exec('ALTER TABLE filaments ADD COLUMN color_name TEXT');
105
        }
106
        if (!in_array('color_hex2', $cols, true)) {
107
            $pdo->exec('ALTER TABLE filaments ADD COLUMN color_hex2 TEXT');
108
        }
109
        if (!in_array('original_g', $cols, true)) {
110
            $pdo->exec('ALTER TABLE filaments ADD COLUMN original_g REAL DEFAULT 1000');
111
        }
112
        foreach (['silk', 'matte', 'rainbow', 'transparent', 'twotone', 'sparkle', 'small_spool'] as $col) {
113
            if (!in_array($col, $cols, true)) {
114
                $pdo->exec("ALTER TABLE filaments ADD COLUMN $col INTEGER NOT NULL DEFAULT 0");
115
            }
116
        }
117
    }
118
    return $pdo;
119
}
120