-- TestDataDB PostgreSQL Schema -- Migrated from SQLite schema.sql -- PostgreSQL 18 on AD2 (192.168.0.6) -- Main test records table CREATE TABLE IF NOT EXISTS test_records ( id BIGSERIAL PRIMARY KEY, log_type TEXT NOT NULL, model_number TEXT NOT NULL, serial_number TEXT NOT NULL, test_date TEXT NOT NULL, test_station TEXT, overall_result TEXT, raw_data TEXT, source_file TEXT, import_date TIMESTAMPTZ DEFAULT NOW(), datasheet_exported_at TIMESTAMPTZ DEFAULT NULL, forweb_exported_at TIMESTAMPTZ DEFAULT NULL, work_order TEXT DEFAULT NULL, search_vector tsvector, UNIQUE(log_type, model_number, serial_number, test_date, test_station) ); -- Indexes for fast searching CREATE INDEX IF NOT EXISTS idx_serial ON test_records(serial_number); CREATE INDEX IF NOT EXISTS idx_model ON test_records(model_number); CREATE INDEX IF NOT EXISTS idx_date ON test_records(test_date); CREATE INDEX IF NOT EXISTS idx_model_serial ON test_records(model_number, serial_number); CREATE INDEX IF NOT EXISTS idx_result ON test_records(overall_result); CREATE INDEX IF NOT EXISTS idx_log_type ON test_records(log_type); CREATE INDEX IF NOT EXISTS idx_test_wo ON test_records(work_order); -- Partial index for unexported PASS records (speeds up export queries) CREATE INDEX IF NOT EXISTS idx_unexported_pass ON test_records(overall_result, forweb_exported_at) WHERE overall_result = 'PASS' AND forweb_exported_at IS NULL; -- GIN index for full-text search (replaces SQLite FTS5 virtual table) CREATE INDEX IF NOT EXISTS idx_search_vector ON test_records USING GIN(search_vector); -- Trigger function to maintain search_vector on INSERT/UPDATE CREATE OR REPLACE FUNCTION update_search_vector() RETURNS trigger AS $$ BEGIN NEW.search_vector := to_tsvector('english', COALESCE(NEW.serial_number, '') || ' ' || COALESCE(NEW.model_number, '') || ' ' || COALESCE(NEW.raw_data, '') ); RETURN NEW; END; $$ LANGUAGE plpgsql; -- Drop trigger if exists, then create DROP TRIGGER IF EXISTS trg_search_vector ON test_records; CREATE TRIGGER trg_search_vector BEFORE INSERT OR UPDATE ON test_records FOR EACH ROW EXECUTE FUNCTION update_search_vector(); -- Work orders table CREATE TABLE IF NOT EXISTS work_orders ( id BIGSERIAL PRIMARY KEY, wo_number TEXT NOT NULL, wo_date TEXT, program TEXT, version TEXT, lib_version TEXT, test_station TEXT, source_file TEXT, import_date TIMESTAMPTZ DEFAULT NOW(), UNIQUE(wo_number, test_station) ); CREATE INDEX IF NOT EXISTS idx_wo_number ON work_orders(wo_number); CREATE INDEX IF NOT EXISTS idx_wo_station ON work_orders(test_station); -- Work order lines table CREATE TABLE IF NOT EXISTS work_order_lines ( id BIGSERIAL PRIMARY KEY, wo_number TEXT NOT NULL, serial_number TEXT NOT NULL, status TEXT, model_number TEXT, ds_filename TEXT, test_date TEXT, test_time TEXT, test_station TEXT, UNIQUE(wo_number, serial_number, test_date, test_time) ); CREATE INDEX IF NOT EXISTS idx_wol_wo ON work_order_lines(wo_number); CREATE INDEX IF NOT EXISTS idx_wol_serial ON work_order_lines(serial_number); CREATE INDEX IF NOT EXISTS idx_wol_model ON work_order_lines(model_number); -- Grant permissions to app role GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO testdatadb_app; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO testdatadb_app;