-- Migration Script: Fix Database Field Name Inconsistencies -- Created: 2025-06-18 -- Purpose: Standardize field names and remove duplicate columns -- ===================================================== -- STEP 1: Create backup of affected data -- ===================================================== -- Create backup table for sessions data CREATE TABLE IF NOT EXISTS sessions_backup_20250618 AS SELECT * FROM sessions; -- ===================================================== -- STEP 2: Create compatibility views (temporary) -- ===================================================== -- Drop existing view if exists DROP VIEW IF EXISTS sessions_compat; -- Create compatibility view for smooth transition CREATE VIEW sessions_compat AS SELECT id, license_id, license_key, session_id, username, computer_name, hardware_id, hardware_id as device_id, -- Compatibility alias ip_address, user_agent, app_version, started_at, started_at as login_time, -- Compatibility alias last_heartbeat, last_heartbeat as last_activity, -- Compatibility alias ended_at, ended_at as logout_time, -- Compatibility alias is_active, is_active as active -- Compatibility alias FROM sessions; -- ===================================================== -- STEP 3: Update data in duplicate columns -- ===================================================== -- Sync data from primary columns to alias columns (safety measure) UPDATE sessions SET login_time = COALESCE(login_time, started_at), last_activity = COALESCE(last_activity, last_heartbeat), logout_time = COALESCE(logout_time, ended_at), active = COALESCE(active, is_active) WHERE login_time IS NULL OR last_activity IS NULL OR logout_time IS NULL OR active IS NULL; -- Sync data from alias columns to primary columns (if primary is null) UPDATE sessions SET started_at = COALESCE(started_at, login_time), last_heartbeat = COALESCE(last_heartbeat, last_activity), ended_at = COALESCE(ended_at, logout_time), is_active = COALESCE(is_active, active) WHERE started_at IS NULL OR last_heartbeat IS NULL OR ended_at IS NULL OR is_active IS NULL; -- ===================================================== -- STEP 4: Create function to check code dependencies -- ===================================================== CREATE OR REPLACE FUNCTION check_field_usage() RETURNS TABLE ( query_count INTEGER, field_name TEXT, usage_type TEXT ) AS $$ BEGIN -- Check for references to old field names RETURN QUERY SELECT COUNT(*)::INTEGER, 'device_id'::TEXT, 'Should use hardware_id'::TEXT FROM pg_stat_statements WHERE query ILIKE '%device_id%' UNION ALL SELECT COUNT(*)::INTEGER, 'active'::TEXT, 'Should use is_active'::TEXT FROM pg_stat_statements WHERE query ILIKE '%active%' AND query NOT ILIKE '%is_active%' UNION ALL SELECT COUNT(*)::INTEGER, 'login_time'::TEXT, 'Should use started_at'::TEXT FROM pg_stat_statements WHERE query ILIKE '%login_time%'; END; $$ LANGUAGE plpgsql; -- ===================================================== -- STEP 5: Migration queries for code updates -- ===================================================== -- These queries help identify code that needs updating: -- Find sessions queries using old field names COMMENT ON VIEW sessions_compat IS 'Compatibility view for sessions table during field name migration. Old fields mapped: - device_id → hardware_id - active → is_active - login_time → started_at - last_activity → last_heartbeat - logout_time → ended_at'; -- ===================================================== -- STEP 6: Final cleanup (run after code is updated) -- ===================================================== -- DO NOT RUN THIS UNTIL ALL CODE IS UPDATED! /* -- Remove duplicate columns ALTER TABLE sessions DROP COLUMN IF EXISTS active, DROP COLUMN IF EXISTS login_time, DROP COLUMN IF EXISTS last_activity, DROP COLUMN IF EXISTS logout_time; -- Drop compatibility view DROP VIEW IF EXISTS sessions_compat; -- Drop helper function DROP FUNCTION IF EXISTS check_field_usage(); */ -- ===================================================== -- VERIFICATION QUERIES -- ===================================================== -- Check for null values in primary columns SELECT COUNT(*) FILTER (WHERE started_at IS NULL) as null_started_at, COUNT(*) FILTER (WHERE last_heartbeat IS NULL) as null_last_heartbeat, COUNT(*) FILTER (WHERE ended_at IS NULL AND is_active = FALSE) as null_ended_at, COUNT(*) FILTER (WHERE is_active IS NULL) as null_is_active, COUNT(*) as total_sessions FROM sessions; -- Check data consistency between duplicate columns SELECT COUNT(*) FILTER (WHERE started_at != login_time) as started_login_diff, COUNT(*) FILTER (WHERE last_heartbeat != last_activity) as heartbeat_activity_diff, COUNT(*) FILTER (WHERE ended_at != logout_time) as ended_logout_diff, COUNT(*) FILTER (WHERE is_active != active) as active_diff, COUNT(*) as total_sessions FROM sessions WHERE login_time IS NOT NULL OR last_activity IS NOT NULL OR logout_time IS NOT NULL OR active IS NOT NULL;