package db const schema = ` -- Enable foreign keys PRAGMA foreign_keys = ON; -- Performers table CREATE TABLE IF NOT EXISTS performers ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, aliases TEXT, -- Physical attributes gender TEXT, birthday TEXT, astrology TEXT, birthplace TEXT, ethnicity TEXT, nationality TEXT, country TEXT, eye_color TEXT, hair_color TEXT, height INTEGER, weight INTEGER, measurements TEXT, cup_size TEXT, tattoo_description TEXT, piercing_description TEXT, boob_job TEXT, circumcised INTEGER DEFAULT 0, pubic_hair_type TEXT DEFAULT 'natural', -- Career information career TEXT, career_start_year INTEGER, career_end_year INTEGER, date_of_death TEXT, active INTEGER DEFAULT 1, -- Media image_path TEXT, image_url TEXT, poster_url TEXT, bio TEXT, -- Source tracking source TEXT, source_id TEXT, source_numeric_id INTEGER, created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')), -- Prevent duplicates from same source UNIQUE(source, source_id) ); -- Studios table CREATE TABLE IF NOT EXISTS studios ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, parent_id INTEGER, image_path TEXT, image_url TEXT, description TEXT, source TEXT, source_id TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')), FOREIGN KEY (parent_id) REFERENCES studios(id) ON DELETE SET NULL ); -- Tag Categories table (hierarchical) CREATE TABLE IF NOT EXISTS tag_categories ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, parent_id INTEGER, description TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), FOREIGN KEY (parent_id) REFERENCES tag_categories(id) ON DELETE CASCADE ); -- Tags table (enhanced with categories) CREATE TABLE IF NOT EXISTS tags ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, category_id INTEGER NOT NULL, aliases TEXT, description TEXT, source TEXT, source_id TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')), UNIQUE(category_id, name), FOREIGN KEY (category_id) REFERENCES tag_categories(id) ON DELETE CASCADE ); -- Scenes table CREATE TABLE IF NOT EXISTS scenes ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, code TEXT, date TEXT, studio_id INTEGER, description TEXT, image_path TEXT, image_url TEXT, director TEXT, url TEXT, source TEXT, source_id TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')), FOREIGN KEY (studio_id) REFERENCES studios(id) ON DELETE SET NULL ); -- Movies table (full-length DVDs/releases) CREATE TABLE IF NOT EXISTS movies ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, date TEXT, studio_id INTEGER, description TEXT, director TEXT, duration INTEGER, image_path TEXT, image_url TEXT, back_image_url TEXT, url TEXT, source TEXT, source_id TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')), FOREIGN KEY (studio_id) REFERENCES studios(id) ON DELETE SET NULL ); -- Movie-Scene many-to-many junction table (scenes belong to movies) CREATE TABLE IF NOT EXISTS movie_scenes ( movie_id INTEGER NOT NULL, scene_id INTEGER NOT NULL, scene_number INTEGER, PRIMARY KEY (movie_id, scene_id), FOREIGN KEY (movie_id) REFERENCES movies(id) ON DELETE CASCADE, FOREIGN KEY (scene_id) REFERENCES scenes(id) ON DELETE CASCADE ); -- Movie-Performer many-to-many junction table CREATE TABLE IF NOT EXISTS movie_performers ( movie_id INTEGER NOT NULL, performer_id INTEGER NOT NULL, PRIMARY KEY (movie_id, performer_id), FOREIGN KEY (movie_id) REFERENCES movies(id) ON DELETE CASCADE, FOREIGN KEY (performer_id) REFERENCES performers(id) ON DELETE CASCADE ); -- Movie-Tag many-to-many junction table CREATE TABLE IF NOT EXISTS movie_tags ( movie_id INTEGER NOT NULL, tag_id INTEGER NOT NULL, PRIMARY KEY (movie_id, tag_id), FOREIGN KEY (movie_id) REFERENCES movies(id) ON DELETE CASCADE, FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE ); -- Scene-Performer many-to-many junction table CREATE TABLE IF NOT EXISTS scene_performers ( scene_id INTEGER NOT NULL, performer_id INTEGER NOT NULL, PRIMARY KEY (scene_id, performer_id), FOREIGN KEY (scene_id) REFERENCES scenes(id) ON DELETE CASCADE, FOREIGN KEY (performer_id) REFERENCES performers(id) ON DELETE CASCADE ); -- Scene-Tag many-to-many junction table (enhanced with ML support) CREATE TABLE IF NOT EXISTS scene_tags ( scene_id INTEGER NOT NULL, tag_id INTEGER NOT NULL, confidence REAL DEFAULT 1.0, source TEXT NOT NULL DEFAULT 'user', verified INTEGER DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')), PRIMARY KEY (scene_id, tag_id), FOREIGN KEY (scene_id) REFERENCES scenes(id) ON DELETE CASCADE, FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE ); -- Scene ML Analysis results table (for storing per-scene ML predictions) CREATE TABLE IF NOT EXISTS scene_ml_analysis ( id INTEGER PRIMARY KEY AUTOINCREMENT, scene_id INTEGER NOT NULL, model_version TEXT NOT NULL, prediction_type TEXT NOT NULL, -- 'clothing', 'position', 'body_type', 'hair', 'ethnicity', etc. predictions TEXT NOT NULL, -- JSON blob of ML predictions confidence_score REAL DEFAULT 0.0, created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')), FOREIGN KEY (scene_id) REFERENCES scenes(id) ON DELETE CASCADE ); -- Scene Images table (for ML training and PornPics integration) CREATE TABLE IF NOT EXISTS scene_images ( id INTEGER PRIMARY KEY AUTOINCREMENT, scene_id INTEGER NOT NULL, image_url TEXT NOT NULL, image_path TEXT, source TEXT, source_id TEXT, width INTEGER, height INTEGER, file_size INTEGER, created_at TEXT NOT NULL DEFAULT (datetime('now')), FOREIGN KEY (scene_id) REFERENCES scenes(id) ON DELETE CASCADE ); -- ML Predictions table (track model versions and predictions) CREATE TABLE IF NOT EXISTS ml_predictions ( id INTEGER PRIMARY KEY AUTOINCREMENT, scene_id INTEGER, image_id INTEGER, model_version TEXT NOT NULL, predictions TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT (datetime('now')), FOREIGN KEY (scene_id) REFERENCES scenes(id) ON DELETE CASCADE, FOREIGN KEY (image_id) REFERENCES scene_images(id) ON DELETE CASCADE ); -- Indexes for common queries (v0.1.0) CREATE INDEX IF NOT EXISTS idx_performers_name ON performers(name); CREATE INDEX IF NOT EXISTS idx_studios_name ON studios(name); CREATE INDEX IF NOT EXISTS idx_scenes_title ON scenes(title); CREATE INDEX IF NOT EXISTS idx_scenes_code ON scenes(code); CREATE INDEX IF NOT EXISTS idx_scenes_date ON scenes(date); CREATE INDEX IF NOT EXISTS idx_movies_title ON movies(title); CREATE INDEX IF NOT EXISTS idx_movies_date ON movies(date); CREATE INDEX IF NOT EXISTS idx_movie_scenes_movie ON movie_scenes(movie_id); CREATE INDEX IF NOT EXISTS idx_movie_scenes_scene ON movie_scenes(scene_id); -- Tag search indexes (v0.2.0 - ML ready) CREATE INDEX IF NOT EXISTS idx_tag_categories_name ON tag_categories(name); CREATE INDEX IF NOT EXISTS idx_tag_categories_parent ON tag_categories(parent_id); CREATE INDEX IF NOT EXISTS idx_tags_name ON tags(name); CREATE INDEX IF NOT EXISTS idx_tags_category ON tags(category_id); -- Scene tag filtering indexes (critical for complex queries) CREATE INDEX IF NOT EXISTS idx_scene_tags_tag ON scene_tags(tag_id); CREATE INDEX IF NOT EXISTS idx_scene_tags_scene ON scene_tags(scene_id); CREATE INDEX IF NOT EXISTS idx_scene_tags_confidence ON scene_tags(confidence); CREATE INDEX IF NOT EXISTS idx_scene_tags_verified ON scene_tags(verified); CREATE INDEX IF NOT EXISTS idx_scene_tags_source ON scene_tags(source); -- Image processing indexes CREATE INDEX IF NOT EXISTS idx_scene_images_scene ON scene_images(scene_id); CREATE INDEX IF NOT EXISTS idx_scene_images_source ON scene_images(source, source_id); -- ML prediction indexes CREATE INDEX IF NOT EXISTS idx_ml_predictions_scene ON ml_predictions(scene_id); CREATE INDEX IF NOT EXISTS idx_ml_predictions_image ON ml_predictions(image_id); CREATE INDEX IF NOT EXISTS idx_ml_predictions_model ON ml_predictions(model_version); -- Sync metadata table (track last sync times) CREATE TABLE IF NOT EXISTS sync_metadata ( id INTEGER PRIMARY KEY AUTOINCREMENT, entity_type TEXT NOT NULL UNIQUE, last_sync_at TEXT NOT NULL, records_updated INTEGER DEFAULT 0, records_failed INTEGER DEFAULT 0, status TEXT NOT NULL DEFAULT 'completed', error_message TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE INDEX IF NOT EXISTS idx_sync_metadata_entity ON sync_metadata(entity_type); CREATE INDEX IF NOT EXISTS idx_sync_metadata_last_sync ON sync_metadata(last_sync_at); `