File size: 8,901 Bytes
46db677
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/usr/bin/env python3
"""
Production database initialization script.
This ensures templates are populated properly and verifies database health.
SAFE for PostgreSQL/RDS - only creates tables on SQLite databases.
"""

import sys
import os
import logging
from datetime import datetime, UTC

# Add the project root to the Python path
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from src.db.init_db import init_db, session_factory, engine, is_postgres_db
from src.db.schemas.models import Base, AgentTemplate, UserTemplatePreference
from scripts.populate_agent_templates import populate_templates
from sqlalchemy import inspect, text
from src.utils.logger import Logger

logger = Logger("init_production_db", see_time=True, console_log=True)

def get_database_type():
    """Get the database type (sqlite or postgresql)."""
    try:
        if is_postgres_db():
            return "postgresql"
        else:
            return "sqlite"
    except Exception as e:
        logger.log_message(f"Error determining database type: {e}", logging.ERROR)
        return "unknown"

def check_table_exists(table_name: str) -> bool:
    """Check if a table exists in the database."""
    try:
        inspector = inspect(engine)
        tables = inspector.get_table_names()
        return table_name in tables
    except Exception as e:
        logger.log_message(f"Error checking table existence: {e}", logging.ERROR)
        return False

def verify_database_schema():
    """Verify that all required tables exist. Only create tables on SQLite."""
    db_type = get_database_type()
    logger.log_message(f"πŸ” Verifying database schema for {db_type.upper()} database...", logging.INFO)
    
    required_tables = [
        'users', 'chats', 'messages', 'model_usage', 'code_executions',
        'message_feedback', 'deep_analysis_reports', 'agent_templates',
        'user_template_preferences'
    ]
    
    missing_tables = []
    existing_tables = []
    
    for table in required_tables:
        if not check_table_exists(table):
            missing_tables.append(table)
            logger.log_message(f"❌ Missing table: {table}", logging.WARNING)
        else:
            existing_tables.append(table)
            logger.log_message(f"βœ… Table exists: {table}", logging.INFO)
    
    if missing_tables:
        if db_type == "sqlite":
            logger.log_message(f"πŸ”§ Creating missing tables on SQLite: {missing_tables}", logging.INFO)
            try:
                # Safe to create tables on SQLite
                Base.metadata.create_all(engine)
                logger.log_message("βœ… All tables created successfully on SQLite", logging.INFO)
            except Exception as e:
                logger.log_message(f"❌ Failed to create tables: {e}", logging.ERROR)
                raise
        else:
            # PostgreSQL/RDS - DO NOT create tables automatically
            logger.log_message(f"⚠️  WARNING: Missing tables detected in {db_type.upper()} database: {missing_tables}", logging.WARNING)
            logger.log_message("πŸ›‘οΈ  SAFETY: Not creating tables automatically on PostgreSQL/RDS", logging.INFO)
            logger.log_message("πŸ“‹ Please ensure these tables exist in your RDS database:", logging.INFO)
            for table in missing_tables:
                logger.log_message(f"   - {table}", logging.INFO)
            
            # Continue without failing - the app might still work with existing tables
            if 'agent_templates' in missing_tables or 'user_template_preferences' in missing_tables:
                logger.log_message("⚠️  Template functionality may not work without agent_templates and user_template_preferences tables", logging.WARNING)
    else:
        logger.log_message(f"βœ… All required tables exist in {db_type.upper()} database", logging.INFO)

def verify_template_data():
    """Verify that agent templates are populated. Safe for all database types."""
    logger.log_message("πŸ“‹ Verifying template data...", logging.INFO)
    
    session = session_factory()
    try:
        # Check if agent_templates table exists before querying
        if not check_table_exists('agent_templates'):
            logger.log_message("⚠️  agent_templates table does not exist, skipping template verification", logging.WARNING)
            return
        
        template_count = session.query(AgentTemplate).filter(AgentTemplate.is_active == True).count()
        logger.log_message(f"πŸ“Š Found {template_count} active templates", logging.INFO)
        
        if template_count == 0:
            logger.log_message("πŸ”§ No templates found, populating...", logging.INFO)
            try:
                populate_templates()
                
                # Verify population worked
                new_count = session.query(AgentTemplate).filter(AgentTemplate.is_active == True).count()
                logger.log_message(f"βœ… Templates populated. Total active templates: {new_count}", logging.INFO)
            except Exception as e:
                logger.log_message(f"❌ Template population failed: {e}", logging.ERROR)
                logger.log_message("⚠️  App will continue but template functionality may not work", logging.WARNING)
        else:
            logger.log_message("βœ… Templates already populated", logging.INFO)
            
    except Exception as e:
        logger.log_message(f"❌ Error verifying templates: {e}", logging.ERROR)
        logger.log_message("⚠️  Template verification failed, but app will continue", logging.WARNING)
    finally:
        session.close()

def test_template_api_functionality():
    """Test that template-related database operations work. Safe for all database types."""
    logger.log_message("πŸ§ͺ Testing template API functionality...", logging.INFO)
    
    session = session_factory()
    try:
        # Check if agent_templates table exists before testing
        if not check_table_exists('agent_templates'):
            logger.log_message("⚠️  agent_templates table does not exist, skipping API test", logging.WARNING)
            return
        
        # Test basic template query
        templates = session.query(AgentTemplate).filter(AgentTemplate.is_active == True).limit(5).all()
        logger.log_message(f"βœ… Successfully queried {len(templates)} templates", logging.INFO)
        
        if templates:
            sample_template = templates[0]
            logger.log_message(f"πŸ“„ Sample template: {sample_template.template_name} - {sample_template.display_name}", logging.INFO)
        else:
            logger.log_message("πŸ“­ No templates found in database", logging.INFO)
        
    except Exception as e:
        logger.log_message(f"❌ Template API test failed: {e}", logging.ERROR)
        logger.log_message("⚠️  Template API may not work properly", logging.WARNING)
    finally:
        session.close()

def run_safe_initialization():
    """Run safe database initialization that respects production databases."""
    db_type = get_database_type()
    logger.log_message(f"πŸš€ Starting SAFE database initialization for {db_type.upper()}...", logging.INFO)
    
    if db_type == "postgresql":
        logger.log_message("πŸ›‘οΈ  PostgreSQL/RDS detected - running in SAFE mode", logging.INFO)
        logger.log_message("πŸ“‹ Will only verify schema and populate templates", logging.INFO)
    elif db_type == "sqlite":
        logger.log_message("πŸ’½ SQLite detected - full initialization mode", logging.INFO)
    
    try:
        # Step 1: Initialize database (safe for all types)
        logger.log_message("Step 1: Basic database initialization", logging.INFO)
        if db_type == "sqlite":
            init_db()  # Only run full init on SQLite
        else:
            logger.log_message("Skipping init_db() for PostgreSQL (safety)", logging.INFO)
        
        # Step 2: Verify schema (safe - only creates tables on SQLite)
        logger.log_message("Step 2: Schema verification", logging.INFO)
        verify_database_schema()
        
        # Step 3: Verify template data (safe for all types)
        logger.log_message("Step 3: Template data verification", logging.INFO)
        verify_template_data()
        
        # Step 4: Test functionality (safe for all types)
        logger.log_message("Step 4: Functionality testing", logging.INFO)
        test_template_api_functionality()
        
        logger.log_message(f"πŸŽ‰ Safe database initialization completed for {db_type.upper()}!", logging.INFO)
        
    except Exception as e:
        logger.log_message(f"πŸ’₯ Database initialization failed: {e}", logging.ERROR)
        logger.log_message("⚠️  App may still start but some features might not work", logging.WARNING)
        # Don't raise - let the app try to start anyway

if __name__ == "__main__":
    run_safe_initialization()