diff --git a/README.md b/README.md index aaef28f..709b775 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Transform natural language into powerful database queries through an intuitive web interface that: - **Understands Context**: Interprets user intent from conversational prompts -- **Supports Multiple Databases**: Works with SQLAlchemy and Snowflake databases +- **Supports Multiple Databases**: Works with SQLAlchemy, Snowflake, and SQLite databases (backend implementation required) - **Provides Real-time Results**: Shows query results instantly in formatted tables - **Handles Errors Gracefully**: Offers helpful error messages and suggestions @@ -141,6 +141,57 @@ This repository is participating in **Hacktoberfest 2025**! We welcome contribut 4. **Open your browser** Navigate to [http://localhost:3000](http://localhost:3000) +### SQLite Local Development Setup + +For local development with SQLite, follow these additional steps: + +1. **Set up environment variables** for SQLite: + + ```bash + # Create .env.local file + DATABASE_TYPE=sqlite + DATABASE_URL=sqlite:///local_dev.db + ``` + +2. **Initialize the SQLite database** (requires Python and SQLAlchemy): + + ```bash + # Install Python dependencies (if not already installed) + pip install sqlalchemy + + # Initialize database + python scripts/init_sqlite.py + + # Optional: Add sample data + python scripts/seed_data.py + ``` + +3. **Configure your MCP server** to use SQLite backend + + **⚠️ Important**: The MCP-DB Connector server must be updated to support SQLite queries. The frontend now accepts SQLite as a target, but the backend server needs corresponding SQLite support. + +4. **Start both servers**: + + ```bash + # Terminal 1: Start MCP server (with SQLite support) + # Your MCP server command here + + # Terminal 2: Start Next.js development server + npm run dev + ``` + +**SQLite Benefits for Development:** +- No external database server required +- File-based storage (`local_dev.db`) +- Easy to reset and recreate +- Perfect for testing and development + +**SQLite Limitations:** +- Single-writer concurrency (not suitable for high-traffic production) +- No built-in user authentication or permissions +- Limited data types compared to PostgreSQL/MySQL +- File-based (backup and replication require manual processes) + ### Usage #### Database Console @@ -152,8 +203,9 @@ Navigate to `/db-console` to access the database query interface: - Example: "Find the top 10 products by sales" 2. **Select Database Target**: Choose between: - - **SQLAlchemy**: For SQLAlchemy-based applications - - **Snowflake**: For Snowflake data warehouse + - **SQLAlchemy**: For SQLAlchemy-based applications + - **Snowflake**: For Snowflake data warehouse + - **SQLite**: For local development with SQLite database 3. **Execute Query**: Click "Execute Query" to run your prompt @@ -188,7 +240,7 @@ Execute a database query using natural language. ```json { "prompt": "string", - "target": "sqlalchemy" | "snowflake" + "target": "sqlalchemy" | "snowflake" | "sqlite" } ``` diff --git a/app/api/db/[query]/route.ts b/app/api/db/[query]/route.ts index c46fea2..7379acb 100644 --- a/app/api/db/[query]/route.ts +++ b/app/api/db/[query]/route.ts @@ -30,10 +30,10 @@ export async function POST( } // Validate target value - if (!['sqlalchemy', 'snowflake'].includes(body.target)) { + if (!['sqlalchemy', 'snowflake', 'sqlite'].includes(body.target)) { const errorResponse: DatabaseErrorResponse = { success: false, - error: 'Invalid target: must be either "sqlalchemy" or "snowflake"' + error: 'Invalid target: must be either "sqlalchemy", "snowflake", or "sqlite"' }; return NextResponse.json(errorResponse, { status: 400 }); } diff --git a/app/components/DbConsole.tsx b/app/components/DbConsole.tsx index 55522c9..6ce66f0 100644 --- a/app/components/DbConsole.tsx +++ b/app/components/DbConsole.tsx @@ -8,7 +8,7 @@ import { DatabaseTarget, DatabaseQueryResponse } from '@/app/types/database'; * A reusable component for database query interface * Features: * - Natural language prompt input - * - Database target selection (SQLAlchemy or Snowflake) + * - Database target selection (SQLAlchemy, Snowflake, or SQLite) * - Query submission with loading states * - Results display in a styled table * - Error handling and user feedback @@ -198,6 +198,7 @@ export default function DbConsole() { > + diff --git a/app/types/database.ts b/app/types/database.ts index ad2db63..b05b9b6 100644 --- a/app/types/database.ts +++ b/app/types/database.ts @@ -1,5 +1,5 @@ // Database target types -export type DatabaseTarget = 'sqlalchemy' | 'snowflake'; +export type DatabaseTarget = 'sqlalchemy' | 'snowflake' | 'sqlite'; // API request types export interface DatabaseQueryRequest { diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 2a9b3e1..938dd4b 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -158,13 +158,61 @@ Create a `.env.local` file with the following variables: # MCP Server Configuration MCP_SERVER_URL=http://localhost:8000 -# Database Configuration (if needed) -DATABASE_URL=your_database_url +# Database Configuration +# For SQLite local development (recommended) +DATABASE_TYPE=sqlite +DATABASE_URL=sqlite:///local_dev.db + +# For production databases (uncomment as needed) +# DATABASE_TYPE=sqlalchemy +# DATABASE_URL=postgresql://user:password@localhost:5432/dbname # Development Configuration NODE_ENV=development ``` +## SQLite Development Setup + +For local development with SQLite, additional setup is required: + +### Prerequisites + +- **Python** 3.8+ (for database scripts) +- **SQLAlchemy** (install with `pip install sqlalchemy`) +- **MCP-DB Connector server** with SQLite support + +### Database Initialization + +1. **Initialize SQLite database**: + + ```bash + python scripts/init_sqlite.py + ``` + +2. **Optional: Add sample data**: + + ```bash + python scripts/seed_data.py + ``` + +3. **Configure MCP server** to connect to SQLite database + + **⚠️ Backend Requirement**: The MCP-DB Connector server must be updated separately to handle SQLite queries. The frontend changes allow selecting SQLite as a target, but the backend server needs corresponding implementation. + +### SQLite Benefits + +- **No external dependencies**: File-based database +- **Easy reset**: Delete `local_dev.db` to start fresh +- **Fast setup**: No server installation required +- **Development focused**: Perfect for testing and prototyping + +### Database Scripts + +- `scripts/init_sqlite.py`: Creates database schema +- `scripts/seed_data.py`: Populates with sample data + +Both scripts are idempotent and can be run multiple times safely. + ## Debugging ### Common Issues diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index 1803a5b..b2ffce9 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -6,8 +6,23 @@ Copy this file to `.env.local` and update the values for your environment. # MCP Server Configuration MCP_SERVER_URL=http://localhost:8000 -# Database Configuration (if needed) -DATABASE_URL=your_database_url +# Database Configuration +# For SQLite local development (recommended for development) +DATABASE_TYPE=sqlite +DATABASE_URL=sqlite:///local_dev.db + +# For production databases (uncomment and configure as needed) +# DATABASE_TYPE=sqlalchemy +# DATABASE_URL=postgresql://user:password@localhost:5432/dbname + +# For Snowflake (uncomment and configure as needed) +# DATABASE_TYPE=snowflake +# SNOWFLAKE_ACCOUNT=your_account +# SNOWFLAKE_USER=your_user +# SNOWFLAKE_PASSWORD=your_password +# SNOWFLAKE_DATABASE=your_database +# SNOWFLAKE_SCHEMA=your_schema +# SNOWFLAKE_WAREHOUSE=your_warehouse # Application Configuration NODE_ENV=development diff --git a/scripts/init_sqlite.py b/scripts/init_sqlite.py new file mode 100644 index 0000000..2f8ecfa --- /dev/null +++ b/scripts/init_sqlite.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +""" +SQLite Database Initialization Script + +This script initializes a SQLite database for local development. +It creates the database file and sets up the basic schema structure. + +Usage: + python scripts/init_sqlite.py + +Requirements: + - SQLAlchemy + - Your SQLAlchemy models/base configuration + +Environment Variables: + - DATABASE_URL: SQLite connection string (default: sqlite:///local_dev.db) +""" + +import os +import sys +from sqlalchemy import create_engine, MetaData, text +from sqlalchemy.orm import sessionmaker +from sqlalchemy.ext.declarative import declarative_base + +# Import your SQLAlchemy models here +# from your_models import Base, YourModel1, YourModel2 + +# Database configuration +DATABASE_URL = os.getenv('DATABASE_URL', 'sqlite:///local_dev.db') + +def init_database(): + """Initialize the SQLite database with schema.""" + try: + print(f"Initializing SQLite database at: {DATABASE_URL}") + + # Create engine + engine = create_engine(DATABASE_URL, echo=True) + + # Create all tables defined in your models + # Replace this with your actual Base.metadata.create_all() call + # Base.metadata.create_all(engine) + + print("✅ Database initialized successfully!") + print(f"📁 Database file location: {DATABASE_URL.replace('sqlite:///', '')}") + + # Optional: Create a test connection + with engine.connect() as conn: + result = conn.execute(text("SELECT sqlite_version()")) + version = result.fetchone()[0] + print(f"📊 SQLite version: {version}") + + except Exception as e: + print(f"❌ Error initializing database: {e}") + sys.exit(1) + +def create_sample_data(): + """Optional: Create sample data for development.""" + try: + engine = create_engine(DATABASE_URL) + SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + db = SessionLocal() + + # Add your sample data creation logic here + # Example: + # sample_user = User(name="John Doe", email="john@example.com") + # db.add(sample_user) + # db.commit() + + print("✅ Sample data created successfully!") + + db.close() + + except Exception as e: + print(f"❌ Error creating sample data: {e}") + sys.exit(1) + +if __name__ == "__main__": + if len(sys.argv) > 1 and sys.argv[1] == "--with-sample-data": + init_database() + create_sample_data() + else: + init_database() + print("\n💡 Tip: Run with --with-sample-data to also create sample data") + print(" python scripts/init_sqlite.py --with-sample-data") \ No newline at end of file diff --git a/scripts/seed_data.py b/scripts/seed_data.py new file mode 100644 index 0000000..6f0814e --- /dev/null +++ b/scripts/seed_data.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 +""" +SQLite Sample Data Seeding Script + +This script populates the SQLite database with realistic sample data +for development and testing purposes. + +Usage: + python scripts/seed_data.py + +Requirements: + - SQLAlchemy + - Your SQLAlchemy models + - Initialized database (run init_sqlite.py first) + +Environment Variables: + - DATABASE_URL: SQLite connection string (default: sqlite:///local_dev.db) +""" + +import os +import sys +import random +from datetime import datetime, timedelta +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker + +# Import your SQLAlchemy models here +# from your_models import User, Product, Order, Base + +# Database configuration +DATABASE_URL = os.getenv('DATABASE_URL', 'sqlite:///local_dev.db') + +def create_sample_users(db): + """Create sample user data.""" + print("Creating sample users...") + + # Sample user data + users_data = [ + {"name": "Alice Johnson", "email": "alice@example.com", "role": "admin"}, + {"name": "Bob Smith", "email": "bob@example.com", "role": "user"}, + {"name": "Carol Williams", "email": "carol@example.com", "role": "user"}, + {"name": "David Brown", "email": "david@example.com", "role": "moderator"}, + {"name": "Emma Davis", "email": "emma@example.com", "role": "user"}, + {"name": "Frank Miller", "email": "frank@example.com", "role": "user"}, + {"name": "Grace Wilson", "email": "grace@example.com", "role": "user"}, + {"name": "Henry Taylor", "email": "henry@example.com", "role": "user"}, + {"name": "Ivy Anderson", "email": "ivy@example.com", "role": "user"}, + {"name": "Jack Thomas", "email": "jack@example.com", "role": "user"}, + ] + + # Uncomment and modify based on your User model + # for user_data in users_data: + # user = User(**user_data) + # user.created_at = datetime.utcnow() - timedelta(days=random.randint(0, 365)) + # db.add(user) + + # db.commit() + print("✅ Sample users created") + +def create_sample_products(db): + """Create sample product data.""" + print("Creating sample products...") + + # Sample product data + products_data = [ + {"name": "Laptop Pro", "price": 1299.99, "category": "Electronics"}, + {"name": "Wireless Mouse", "price": 29.99, "category": "Electronics"}, + {"name": "Coffee Maker", "price": 89.99, "category": "Appliances"}, + {"name": "Running Shoes", "price": 149.99, "category": "Sports"}, + {"name": "Book: Python Guide", "price": 39.99, "category": "Books"}, + {"name": "Desk Chair", "price": 299.99, "category": "Furniture"}, + {"name": "Headphones", "price": 199.99, "category": "Electronics"}, + {"name": "Water Bottle", "price": 24.99, "category": "Sports"}, + {"name": "Notebook", "price": 9.99, "category": "Stationery"}, + {"name": "Smartphone Case", "price": 19.99, "category": "Electronics"}, + ] + + # Uncomment and modify based on your Product model + # for product_data in products_data: + # product = Product(**product_data) + # db.add(product) + + # db.commit() + print("✅ Sample products created") + +def create_sample_orders(db): + """Create sample order data.""" + print("Creating sample orders...") + + # Sample order data - requires users and products to exist first + # Uncomment and modify based on your Order model + # for i in range(50): + # order = Order( + # user_id=random.randint(1, 10), + # product_id=random.randint(1, 10), + # quantity=random.randint(1, 5), + # order_date=datetime.utcnow() - timedelta(days=random.randint(0, 90)) + # ) + # db.add(order) + + # db.commit() + print("✅ Sample orders created") + +def seed_database(): + """Main function to seed the database with sample data.""" + try: + print(f"Seeding database: {DATABASE_URL}") + + # Create engine and session + engine = create_engine(DATABASE_URL) + SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + db = SessionLocal() + + # Create sample data + create_sample_users(db) + create_sample_products(db) + create_sample_orders(db) + + db.close() + print("✅ Database seeding completed successfully!") + + except Exception as e: + print(f"❌ Error seeding database: {e}") + sys.exit(1) + +def clear_existing_data(db): + """Optional: Clear existing data before seeding.""" + try: + print("Clearing existing data...") + + # Uncomment and modify based on your models + # db.query(Order).delete() + # db.query(Product).delete() + # db.query(User).delete() + # db.commit() + + print("✅ Existing data cleared") + + except Exception as e: + print(f"⚠️ Warning: Could not clear existing data: {e}") + +if __name__ == "__main__": + if len(sys.argv) > 1 and sys.argv[1] == "--clear": + engine = create_engine(DATABASE_URL) + SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + db = SessionLocal() + clear_existing_data(db) + db.close() + print("💡 Run without --clear to seed data") + else: + seed_database() + print("\n💡 Tip: Run with --clear to clear existing data first") + print(" python scripts/seed_data.py --clear") \ No newline at end of file