Skip to content

Commit 03b3245

Browse files
committed
fix: Ensure local database is created during app creation, not just app execution
- Modified initializeDatabaseForFramework to actually create databases during app creation for Flask, FastAPI, and Node.js frameworks - Updated ensureBackendDirectory to verify database initialization for existing backends - Databases are now persistent across app restarts and created when apps are first created - Added proper error handling and logging for database initialization
1 parent 031056d commit 03b3245

File tree

2 files changed

+123
-12
lines changed

2 files changed

+123
-12
lines changed

src/ipc/handlers/app_handlers.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import { createLoggedHandler } from "./safe_handle";
4343
import { getLanguageModelProviders } from "../shared/language_model_helpers";
4444
import { startProxy } from "../utils/start_proxy_server";
4545
import { Worker } from "worker_threads";
46-
import { createFromTemplate, setupBackendFramework, getStartCommandForFramework } from "./createFromTemplate";
46+
import { createFromTemplate, setupBackendFramework, getStartCommandForFramework, runCommandInDirectory } from "./createFromTemplate";
4747
import { gitCommit } from "../utils/git_utils";
4848
import { safeSend } from "../utils/safe_sender";
4949
import { normalizePath } from "../../../shared/normalizePath";
@@ -232,7 +232,7 @@ async function ensureBackendDirectory(backendPath: string): Promise<void> {
232232
logger.info(`Created backend directory: ${backendPath}`);
233233
}
234234

235-
// Check if backend directory is empty or missing key files
235+
// Check if backend directory has the necessary files but ensure database exists
236236
const backendFiles = fs.readdirSync(backendPath);
237237
if (backendFiles.length === 0) {
238238
// Create a basic Python Flask backend structure with database support
@@ -320,6 +320,45 @@ python app.py
320320
logger.error(`Failed to create backend structure in ${backendPath}:`, error);
321321
throw error;
322322
}
323+
} else {
324+
// Backend directory exists, but ensure database is initialized for existing backends
325+
// This handles the case where backend was created during app creation but database needs to be ensured
326+
const hasAppPy = backendFiles.includes('app.py');
327+
const hasRequirements = backendFiles.includes('requirements.txt');
328+
329+
if (hasAppPy && hasRequirements) {
330+
// Check if this is a Python backend that needs database initialization
331+
const framework = await detectPythonFramework(backendPath);
332+
if (framework === 'flask') {
333+
// Ensure Flask database is initialized
334+
try {
335+
const initScript = `
336+
import os
337+
os.chdir('${backendPath.replace(/\\/g, '\\\\')}')
338+
339+
from models import db
340+
from app import app
341+
342+
# Create database tables within app context
343+
with app.app_context():
344+
db.create_all()
345+
print("Flask database tables verified/created successfully")
346+
`;
347+
await fsPromises.writeFile(path.join(backendPath, 'init_db.py'), initScript);
348+
349+
// Run the initialization script
350+
await runCommandInDirectory(backendPath, "python init_db.py");
351+
352+
// Clean up the temporary script
353+
await fsPromises.unlink(path.join(backendPath, 'init_db.py')).catch(() => {});
354+
355+
logger.info(`Ensured Flask database is initialized in ${backendPath}`);
356+
} catch (error) {
357+
logger.warn(`Failed to ensure Flask database initialization:`, error);
358+
// Don't throw - database might already exist
359+
}
360+
}
361+
}
323362
}
324363
}
325364

src/ipc/handlers/createFromTemplate.ts

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2438,29 +2438,101 @@ async function initializeDatabaseForFramework(backendPath: string, framework: st
24382438
break;
24392439

24402440
case "fastapi":
2441-
// For FastAPI, the database tables are created automatically when the app starts
2442-
// due to the models.Base.metadata.create_all(bind=engine) call in main.py
2443-
logger.info(`FastAPI database will be initialized when server starts`);
2441+
// For FastAPI, run a Python script to create database tables
2442+
try {
2443+
logger.info(`Creating FastAPI database tables in ${backendPath}`);
2444+
// Create a temporary script to initialize the database
2445+
const initScript = `
2446+
import os
2447+
os.chdir('${backendPath.replace(/\\/g, '\\\\')}')
2448+
2449+
from database import Base, engine
2450+
from models import Item
2451+
2452+
# Create all tables
2453+
Base.metadata.create_all(bind=engine)
2454+
print("FastAPI database tables created successfully")
2455+
`;
2456+
await fs.writeFile(path.join(backendPath, 'init_db.py'), initScript);
2457+
2458+
// Run the initialization script
2459+
await runCommandInDirectory(backendPath, "python init_db.py");
2460+
2461+
// Clean up the temporary script
2462+
await fs.unlink(path.join(backendPath, 'init_db.py')).catch(() => {});
2463+
2464+
logger.info(`FastAPI database initialized successfully`);
2465+
} catch (error) {
2466+
logger.warn(`Failed to initialize FastAPI database:`, error);
2467+
throw error;
2468+
}
24442469
break;
24452470

24462471
case "flask":
2447-
// For Flask, the database tables are created automatically when the app starts
2448-
// due to the db.create_all() call in app.py
2449-
logger.info(`Flask database will be initialized when server starts`);
2472+
// For Flask, run a Python script to create database tables
2473+
try {
2474+
logger.info(`Creating Flask database tables in ${backendPath}`);
2475+
// Create a temporary script to initialize the database
2476+
const initScript = `
2477+
import os
2478+
os.chdir('${backendPath.replace(/\\/g, '\\\\')}')
2479+
2480+
from models import db
2481+
from app import app
2482+
2483+
# Create database tables within app context
2484+
with app.app_context():
2485+
db.create_all()
2486+
print("Flask database tables created successfully")
2487+
`;
2488+
await fs.writeFile(path.join(backendPath, 'init_db.py'), initScript);
2489+
2490+
// Run the initialization script
2491+
await runCommandInDirectory(backendPath, "python init_db.py");
2492+
2493+
// Clean up the temporary script
2494+
await fs.unlink(path.join(backendPath, 'init_db.py')).catch(() => {});
2495+
2496+
logger.info(`Flask database initialized successfully`);
2497+
} catch (error) {
2498+
logger.warn(`Failed to initialize Flask database:`, error);
2499+
throw error;
2500+
}
24502501
break;
24512502

24522503
case "nodejs":
2453-
// For Node.js, the database tables are created automatically when the server starts
2454-
// due to the CREATE TABLE IF NOT EXISTS statement in db.js
2455-
logger.info(`Node.js SQLite database will be initialized when server starts`);
2504+
// For Node.js, run a Node.js script to create database tables
2505+
try {
2506+
logger.info(`Creating Node.js SQLite database tables in ${backendPath}`);
2507+
// Create a temporary script to initialize the database
2508+
const initScript = `
2509+
const path = require('path');
2510+
const { db } = require('./db');
2511+
2512+
// The db.js file already creates tables on import, so we just need to verify
2513+
console.log('Node.js SQLite database tables created successfully');
2514+
`;
2515+
await fs.writeFile(path.join(backendPath, 'init_db.js'), initScript);
2516+
2517+
// Run the initialization script
2518+
await runCommandInDirectory(backendPath, "node init_db.js");
2519+
2520+
// Clean up the temporary script
2521+
await fs.unlink(path.join(backendPath, 'init_db.js')).catch(() => {});
2522+
2523+
logger.info(`Node.js SQLite database initialized successfully`);
2524+
} catch (error) {
2525+
logger.warn(`Failed to initialize Node.js database:`, error);
2526+
throw error;
2527+
}
24562528
break;
24572529

24582530
default:
24592531
logger.warn(`Unknown framework for database initialization: ${framework}`);
24602532
}
24612533
}
24622534

2463-
async function runCommandInDirectory(directory: string, command: string): Promise<void> {
2535+
export async function runCommandInDirectory(directory: string, command: string): Promise<void> {
24642536
return new Promise<void>((resolve, reject) => {
24652537
const { spawn } = require('child_process');
24662538
const process = spawn(command, [], {

0 commit comments

Comments
 (0)