Rustelo/docs/database_support_summary.md

259 lines
7.2 KiB
Markdown
Raw Normal View History

# Database Support Summary
This document summarizes the database support implementation in the Rust application, which supports both PostgreSQL and SQLite databases based on the connection URL.
## Current Implementation Status
### ✅ What Works
1. **URL-Based Database Detection**: The application automatically detects database type from the connection URL
2. **PostgreSQL Support**: Full support for PostgreSQL with native SQL syntax
3. **SQLite Configuration**: Configuration files support SQLite URLs
4. **Unified Codebase**: Single codebase handles both database types
5. **Automatic Table Creation**: Database tables are created automatically on startup
### 🔧 Current Limitations
1. **PostgreSQL-First Implementation**: The current code uses PostgreSQL-specific SQL syntax
2. **SQLite Compatibility**: While SQLx supports SQLite, the SQL queries use PostgreSQL syntax ($1, $2) instead of SQLite syntax (?1, ?2)
3. **Type Handling**: Uses PostgreSQL-specific types (UUID, TIMESTAMPTZ, JSONB)
## How It Works
### Database Connection
The application detects the database type from the `DATABASE_URL` environment variable:
```rust
// In server/src/main.rs
let db_type = if database_url.starts_with("postgres://")
|| database_url.starts_with("postgresql://") {
"PostgreSQL"
} else if database_url.starts_with("sqlite:") {
"SQLite"
} else {
"Unknown"
};
```
### Current Database Pool
The application currently uses `PgPool` throughout, which works with PostgreSQL URLs directly and can be configured to work with SQLite through SQLx's compatibility layer.
```rust
// Uses PgPool but can connect to SQLite URLs
PgPool::connect(database_url).await
```
## Configuration Examples
### PostgreSQL Configuration
```toml
[database]
url = "postgresql://username:password@localhost:5432/database_name"
max_connections = 10
min_connections = 1
```
### SQLite Configuration
```toml
[database]
url = "sqlite:database.db"
max_connections = 10
min_connections = 1
```
### Environment Variable Override
```bash
# PostgreSQL
export DATABASE_URL="postgresql://user:pass@localhost:5432/mydb"
# SQLite
export DATABASE_URL="sqlite:my_app.db"
```
## Practical Usage
### Quick Start with SQLite
```bash
export DATABASE_URL="sqlite:database.db"
cargo run --bin server
```
### Quick Start with PostgreSQL
```bash
# Start PostgreSQL with Docker
docker run -d --name postgres -e POSTGRES_PASSWORD=password -p 5432:5432 postgres:15
# Connect to it
export DATABASE_URL="postgresql://postgres:password@localhost:5432/postgres"
cargo run --bin server
```
### Switching Between Databases
```bash
# Start with SQLite
export DATABASE_URL="sqlite:test.db"
cargo run --bin server
# Stop server (Ctrl+C), switch to PostgreSQL
export DATABASE_URL="postgresql://localhost:5432/mydb"
cargo run --bin server
```
## Implementation Architecture
### Current Structure
```
├── server/src/main.rs # Database connection logic
├── server/src/auth/repository.rs # Authentication database operations
├── server/src/content/repository.rs # Content management database operations
└── server/src/auth/two_factor.rs # 2FA database operations
```
### Database Abstraction Pattern
The code currently uses a direct `PgPool` approach with PostgreSQL syntax, but is structured to allow for database-specific implementations in the future.
## Future Enhancement Options
### Option 1: Full Database Abstraction (Recommended)
Create a `DatabasePool` enum that handles both database types with appropriate SQL syntax:
```rust
pub enum DatabasePool {
Postgres(PgPool),
Sqlite(SqlitePool),
}
```
### Option 2: Conditional Compilation
Use feature flags to compile for specific databases:
```rust
#[cfg(feature = "postgres")]
use sqlx::PgPool as DbPool;
#[cfg(feature = "sqlite")]
use sqlx::SqlitePool as DbPool;
```
### Option 3: SQLx Any Driver
Use SQLx's `Any` driver for complete database agnosticism (with some type limitations).
## Database Schema Compatibility
### PostgreSQL Schema Features
- UUID primary keys with `gen_random_uuid()`
- TIMESTAMPTZ for timestamps
- JSONB for JSON data
- Advanced indexing
### SQLite Equivalent Features
- TEXT UUIDs with custom generation
- DATETIME for timestamps
- TEXT for JSON storage
- Standard indexing
## Performance Considerations
### PostgreSQL
- **Best for**: Production, multi-user, high concurrency
- **Features**: Full ACID, advanced indexing, network access
- **Connection Pool**: 10-50 connections typical
### SQLite
- **Best for**: Development, testing, single-user apps
- **Features**: File-based, zero configuration, embedded
- **Connection Pool**: 1 connection recommended
## Security Considerations
### PostgreSQL
- Network security (firewall, VPN)
- Authentication (strong passwords, SSL)
- Authorization (role-based access)
- Regular security updates
### SQLite
- File system permissions (600/640)
- Backup encryption
- Access control at application level
## Testing Strategy
### Unit Tests
```bash
# PostgreSQL tests
export DATABASE_URL="postgresql://localhost/test_db"
cargo test
# SQLite tests
export DATABASE_URL="sqlite::memory:"
cargo test
```
### Integration Tests
The application includes integration tests that can run against both database types by setting the appropriate `DATABASE_URL`.
## Migration Strategy
### From SQLite to PostgreSQL
1. Export data from SQLite
2. Set up PostgreSQL instance
3. Change `DATABASE_URL`
4. Import data to PostgreSQL
5. Restart application
### From PostgreSQL to SQLite
1. Export data from PostgreSQL
2. Change `DATABASE_URL` to SQLite
3. Restart application (tables created automatically)
4. Import data to SQLite
## Troubleshooting
### Common Issues
**"spawn_local called from outside of a task::LocalSet"**
- ✅ Fixed: The application uses proper LocalSet configuration
**Database connection failed**
- Check if database server is running
- Verify connection string format
- Check network access and credentials
**Table creation errors**
- Ensure database user has CREATE privileges
- Check for existing incompatible tables
- Review logs for specific SQL errors
### Debug Commands
```bash
# Test database connection
psql $DATABASE_URL -c "SELECT 1;" # PostgreSQL
sqlite3 database.db "SELECT 1;" # SQLite
# Check application logs
RUST_LOG=debug cargo run --bin server
```
## Best Practices
1. **Use environment variables** for database URLs in production
2. **Start with SQLite** for development and testing
3. **Use PostgreSQL** for production deployments
4. **Configure appropriate connection pools** for your workload
5. **Monitor database performance** and adjust settings
6. **Regular backups** for production databases
7. **Test migrations** on both database types if needed
## Conclusion
The current implementation provides a solid foundation for supporting both PostgreSQL and SQLite databases. While the code currently uses PostgreSQL syntax throughout, the architecture is designed to accommodate both databases through URL-based configuration.
For most use cases:
- **Development**: Use SQLite for simplicity
- **Production**: Use PostgreSQL for scalability and features
- **Testing**: Use in-memory SQLite for speed
The database choice can be changed at any time by simply updating the `DATABASE_URL`, making it easy to evolve your database strategy as your application grows.