feat(db): add is_external flag to dogs table with safe ALTER TABLE migration

This commit is contained in:
2026-03-10 15:23:35 -05:00
parent 01a5db10c0
commit 0c84b83e75

View File

@@ -13,33 +13,35 @@ function initDatabase() {
db.pragma('foreign_keys = ON'); db.pragma('foreign_keys = ON');
db.pragma('journal_mode = WAL'); db.pragma('journal_mode = WAL');
// ── Dogs ──────────────────────────────────────────────────────────── // ── Dogs ────────────────────────────────────────────────────────────────
db.exec(` db.exec(`
CREATE TABLE IF NOT EXISTS dogs ( CREATE TABLE IF NOT EXISTS dogs (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL, name TEXT NOT NULL,
registration_number TEXT, registration_number TEXT,
breed TEXT NOT NULL, breed TEXT NOT NULL,
sex TEXT NOT NULL CHECK(sex IN ('male', 'female')), sex TEXT NOT NULL CHECK(sex IN ('male', 'female')),
birth_date TEXT, birth_date TEXT,
color TEXT, color TEXT,
microchip TEXT, microchip TEXT,
litter_id INTEGER, litter_id INTEGER,
is_active INTEGER DEFAULT 1, is_active INTEGER DEFAULT 1,
is_champion INTEGER DEFAULT 0, is_champion INTEGER DEFAULT 0,
chic_number TEXT, is_external INTEGER DEFAULT 0,
age_at_death TEXT, chic_number TEXT,
cause_of_death TEXT, age_at_death TEXT,
photo_urls TEXT DEFAULT '[]', cause_of_death TEXT,
notes TEXT, photo_urls TEXT DEFAULT '[]',
created_at TEXT DEFAULT (datetime('now')), notes TEXT,
updated_at TEXT DEFAULT (datetime('now')) created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now'))
) )
`); `);
// migrate: add columns if missing (safe on existing DBs) // migrate: add columns if missing (safe on existing DBs)
const dogMigrations = [ const dogMigrations = [
['is_champion', 'INTEGER DEFAULT 0'], ['is_champion', 'INTEGER DEFAULT 0'],
['is_external', 'INTEGER DEFAULT 0'],
['chic_number', 'TEXT'], ['chic_number', 'TEXT'],
['age_at_death', 'TEXT'], ['age_at_death', 'TEXT'],
['cause_of_death', 'TEXT'], ['cause_of_death', 'TEXT'],
@@ -48,7 +50,7 @@ function initDatabase() {
try { db.exec(`ALTER TABLE dogs ADD COLUMN ${col} ${def}`); } catch (_) { /* already exists */ } try { db.exec(`ALTER TABLE dogs ADD COLUMN ${col} ${def}`); } catch (_) { /* already exists */ }
} }
// ── Parents ───────────────────────────────────────────────────────── // ── Parents ──────────────────────────────────────────────────────────────
db.exec(` db.exec(`
CREATE TABLE IF NOT EXISTS parents ( CREATE TABLE IF NOT EXISTS parents (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -60,7 +62,7 @@ function initDatabase() {
) )
`); `);
// ── Breeding Records ───────────────────────────────────────────────── // ── Breeding Records ─────────────────────────────────────────────────────
db.exec(` db.exec(`
CREATE TABLE IF NOT EXISTS breeding_records ( CREATE TABLE IF NOT EXISTS breeding_records (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -77,34 +79,28 @@ function initDatabase() {
) )
`); `);
// ── Litters ────────────────────────────────────────────────────────── // ── Litters ──────────────────────────────────────────────────────────────
db.exec(` db.exec(`
CREATE TABLE IF NOT EXISTS litters ( CREATE TABLE IF NOT EXISTS litters (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
breeding_id INTEGER, breeding_id INTEGER,
sire_id INTEGER NOT NULL, sire_id INTEGER NOT NULL,
dam_id INTEGER NOT NULL, dam_id INTEGER NOT NULL,
whelp_date TEXT, whelp_date TEXT,
total_count INTEGER DEFAULT 0, total_count INTEGER DEFAULT 0,
male_count INTEGER DEFAULT 0, male_count INTEGER DEFAULT 0,
female_count INTEGER DEFAULT 0, female_count INTEGER DEFAULT 0,
stillborn_count INTEGER DEFAULT 0, stillborn_count INTEGER DEFAULT 0,
notes TEXT, notes TEXT,
created_at TEXT DEFAULT (datetime('now')), created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')),
FOREIGN KEY (breeding_id) REFERENCES breeding_records(id), FOREIGN KEY (breeding_id) REFERENCES breeding_records(id),
FOREIGN KEY (sire_id) REFERENCES dogs(id), FOREIGN KEY (sire_id) REFERENCES dogs(id),
FOREIGN KEY (dam_id) REFERENCES dogs(id) FOREIGN KEY (dam_id) REFERENCES dogs(id)
) )
`); `);
// ── Health Records (OFA-extended) ──────────────────────────────────── // ── Health Records (OFA-extended) ─────────────────────────────────────────
// test_type values: hip_ofa | hip_pennhip | elbow_ofa | heart_ofa |
// heart_echo | eye_caer | thyroid_ofa | dna_panel | vaccination |
// other
// ofa_result values: excellent | good | fair | borderline | mild |
// moderate | severe | normal | abnormal | pass | fail | carrier |
// clear | affected | n/a
db.exec(` db.exec(`
CREATE TABLE IF NOT EXISTS health_records ( CREATE TABLE IF NOT EXISTS health_records (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -130,7 +126,7 @@ function initDatabase() {
// migrate: add OFA-specific columns if missing (covers existing DBs) // migrate: add OFA-specific columns if missing (covers existing DBs)
const healthMigrations = [ const healthMigrations = [
['test_type', 'TEXT'], ['test_type', 'TEXT'],
['ofa_result', 'TEXT'], ['ofa_result', 'TEXT'],
['ofa_number', 'TEXT'], ['ofa_number', 'TEXT'],
['performed_by', 'TEXT'], ['performed_by', 'TEXT'],
@@ -144,10 +140,7 @@ function initDatabase() {
try { db.exec(`ALTER TABLE health_records ADD COLUMN ${col} ${def}`); } catch (_) { /* already exists */ } try { db.exec(`ALTER TABLE health_records ADD COLUMN ${col} ${def}`); } catch (_) { /* already exists */ }
} }
// ── Genetic Tests (DNA Panel) ───────────────────────────────────────── // ── Genetic Tests (DNA Panel) ──────────────────────────────────────────────
// result values: clear | carrier | affected | not_tested
// marker examples: PRA1, PRA2, prcd-PRA, GR-PRA1, GR-PRA2, ICH1,
// ICH2, NCL, DM, MD
db.exec(` db.exec(`
CREATE TABLE IF NOT EXISTS genetic_tests ( CREATE TABLE IF NOT EXISTS genetic_tests (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -164,23 +157,23 @@ function initDatabase() {
) )
`); `);
// ── Cancer History ─────────────────────────────────────────────────── // ── Cancer History ────────────────────────────────────────────────────────
db.exec(` db.exec(`
CREATE TABLE IF NOT EXISTS cancer_history ( CREATE TABLE IF NOT EXISTS cancer_history (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
dog_id INTEGER NOT NULL, dog_id INTEGER NOT NULL,
cancer_type TEXT, cancer_type TEXT,
age_at_diagnosis TEXT, age_at_diagnosis TEXT,
age_at_death TEXT, age_at_death TEXT,
cause_of_death TEXT, cause_of_death TEXT,
notes TEXT, notes TEXT,
created_at TEXT DEFAULT (datetime('now')), created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')),
FOREIGN KEY (dog_id) REFERENCES dogs(id) FOREIGN KEY (dog_id) REFERENCES dogs(id)
) )
`); `);
// ── Settings ───────────────────────────────────────────────────────── // ── Settings ──────────────────────────────────────────────────────────────
db.exec(` db.exec(`
CREATE TABLE IF NOT EXISTS settings ( CREATE TABLE IF NOT EXISTS settings (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,