Add database initialization and schema
This commit is contained in:
156
server/db/init.js
Normal file
156
server/db/init.js
Normal file
@@ -0,0 +1,156 @@
|
||||
const Database = require('better-sqlite3');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
function initDatabase(dbPath) {
|
||||
// Ensure data directory exists
|
||||
const dir = path.dirname(dbPath);
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
|
||||
const db = new Database(dbPath);
|
||||
|
||||
// Enable foreign keys
|
||||
db.pragma('foreign_keys = ON');
|
||||
|
||||
console.log('Initializing database schema...');
|
||||
|
||||
// Dogs table - Core registry
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS dogs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
registration_number TEXT UNIQUE,
|
||||
breed TEXT NOT NULL,
|
||||
sex TEXT NOT NULL CHECK(sex IN ('male', 'female')),
|
||||
birth_date DATE,
|
||||
color TEXT,
|
||||
microchip TEXT UNIQUE,
|
||||
photo_urls TEXT, -- JSON array of photo URLs
|
||||
notes TEXT,
|
||||
is_active INTEGER DEFAULT 1,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`);
|
||||
|
||||
// Parents table - Relationship mapping
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS parents (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
dog_id INTEGER NOT NULL,
|
||||
parent_id INTEGER NOT NULL,
|
||||
parent_type TEXT NOT NULL CHECK(parent_type IN ('sire', 'dam')),
|
||||
FOREIGN KEY (dog_id) REFERENCES dogs(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (parent_id) REFERENCES dogs(id) ON DELETE CASCADE,
|
||||
UNIQUE(dog_id, parent_id, parent_type)
|
||||
)
|
||||
`);
|
||||
|
||||
// Litters table - Breeding records
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS litters (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
sire_id INTEGER NOT NULL,
|
||||
dam_id INTEGER NOT NULL,
|
||||
breeding_date DATE NOT NULL,
|
||||
whelping_date DATE,
|
||||
puppy_count INTEGER DEFAULT 0,
|
||||
notes TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (sire_id) REFERENCES dogs(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (dam_id) REFERENCES dogs(id) ON DELETE CASCADE
|
||||
)
|
||||
`);
|
||||
|
||||
// Health records table
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS health_records (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
dog_id INTEGER NOT NULL,
|
||||
record_type TEXT NOT NULL CHECK(record_type IN ('test', 'vaccination', 'exam', 'treatment', 'certification')),
|
||||
test_name TEXT,
|
||||
test_date DATE NOT NULL,
|
||||
result TEXT,
|
||||
document_url TEXT,
|
||||
notes TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (dog_id) REFERENCES dogs(id) ON DELETE CASCADE
|
||||
)
|
||||
`);
|
||||
|
||||
// Heat cycles table
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS heat_cycles (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
dog_id INTEGER NOT NULL,
|
||||
start_date DATE NOT NULL,
|
||||
end_date DATE,
|
||||
progesterone_peak_date DATE,
|
||||
breeding_date DATE,
|
||||
breeding_successful INTEGER DEFAULT 0,
|
||||
notes TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (dog_id) REFERENCES dogs(id) ON DELETE CASCADE
|
||||
)
|
||||
`);
|
||||
|
||||
// Traits table - Genetic trait tracking
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS traits (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
dog_id INTEGER NOT NULL,
|
||||
trait_category TEXT NOT NULL,
|
||||
trait_name TEXT NOT NULL,
|
||||
trait_value TEXT NOT NULL,
|
||||
inherited_from INTEGER,
|
||||
notes TEXT,
|
||||
FOREIGN KEY (dog_id) REFERENCES dogs(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (inherited_from) REFERENCES dogs(id) ON DELETE SET NULL
|
||||
)
|
||||
`);
|
||||
|
||||
// Create indexes for performance
|
||||
db.exec(`
|
||||
CREATE INDEX IF NOT EXISTS idx_dogs_name ON dogs(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_dogs_registration ON dogs(registration_number);
|
||||
CREATE INDEX IF NOT EXISTS idx_parents_dog ON parents(dog_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_parents_parent ON parents(parent_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_litters_sire ON litters(sire_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_litters_dam ON litters(dam_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_health_dog ON health_records(dog_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_heat_dog ON heat_cycles(dog_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_traits_dog ON traits(dog_id);
|
||||
`);
|
||||
|
||||
// Create trigger for updated_at
|
||||
db.exec(`
|
||||
CREATE TRIGGER IF NOT EXISTS update_dogs_timestamp
|
||||
AFTER UPDATE ON dogs
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE dogs SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
|
||||
END;
|
||||
`);
|
||||
|
||||
console.log('Database schema initialized successfully!');
|
||||
|
||||
db.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
function getDatabase() {
|
||||
const dbPath = process.env.DB_PATH || path.join(__dirname, '../../data/breedr.db');
|
||||
const db = new Database(dbPath);
|
||||
db.pragma('foreign_keys = ON');
|
||||
return db;
|
||||
}
|
||||
|
||||
module.exports = { initDatabase, getDatabase };
|
||||
|
||||
// Run initialization if called directly
|
||||
if (require.main === module) {
|
||||
const dbPath = process.env.DB_PATH || path.join(__dirname, '../../data/breedr.db');
|
||||
initDatabase(dbPath);
|
||||
}
|
||||
Reference in New Issue
Block a user