feat: implement database layer and rename auction -> listing

Major Changes:
- Set up SQLx database connection and migration system
- Create complete initial database schema with all tables
- Rename 'auction' to 'listing' throughout codebase for better terminology
- Update bot commands: /newauction -> /newlisting, /myauctions -> /mylistings
- Update all database tables: auctions -> listings, auction_medias -> listing_medias
- Update foreign key relationships and indexes
- Add automatic database migration on startup
- Update documentation and README
- Complete backlog tasks: task-001, task-002, task-010

The bot now has a solid database foundation ready for implementing core business logic.
All tests pass and code compiles successfully.
This commit is contained in:
Dylan Knutson
2025-08-27 19:24:15 +00:00
parent 30751181e4
commit 348fa416e8
13 changed files with 312 additions and 77 deletions

View File

@@ -6,18 +6,18 @@ A Telegram bot for managing various types of auctions, built in Rust using SQLit
## Core Features ## Core Features
### Auction Types ### Listing Types
1. **Standard Auctions**: Traditional time-based bidding with anti-sniping protection 1. **Standard Auctions**: Traditional time-based bidding with anti-sniping protection
2. **Multi-slot Auctions**: Multiple winners (e.g., 3 commission slots available) 2. **Multi-slot Auctions**: Multiple winners (e.g., 3 commission slots available)
3. **Fixed Price Sales**: Set price with limited quantity 3. **Fixed Price Sales**: Set price with limited quantity
4. **Blind Auctions**: Bidders submit amounts with descriptions; seller chooses winner (not necessarily highest bid) 4. **Blind Auctions**: Bidders submit amounts with descriptions; seller chooses winner (not necessarily highest bid)
### Key Functionality ### Key Functionality
- **Telegram Bot**: The bot is interacted with primarily through Telegram. Sellers can create auctions, and view bids on auctions. Buyers can bid on auctions and view their bids. - **Telegram Bot**: The bot is interacted with primarily through Telegram. Sellers can create listings, and view bids on listings. Buyers can bid on listings and view their bids.
- **Proxy/Automatic Bidding**: Users set maximum bid; system auto-bids up to that amount - **Proxy/Automatic Bidding**: Users set maximum bid; system auto-bids up to that amount
- **Anti-sniping Protection**: Configurable time extension if bid placed in last N minutes - **Anti-sniping Protection**: Configurable time extension if bid placed in last N minutes
- **Buy-now Option**: Instant purchase at fixed price - **Buy-now Option**: Instant purchase at fixed price
- **Media Support**: Multiple images/videos per auction on the telegram post. - **Media Support**: Multiple images/videos per listing on the telegram post.
- **Outbid Notifications**: Configurable user notifications - **Outbid Notifications**: Configurable user notifications
- **Non-payment Handling**: Track failed payments, allow selection of next highest bidder - **Non-payment Handling**: Track failed payments, allow selection of next highest bidder
- **Localization Support**: Multi-language structure (to be implemented) - **Localization Support**: Multi-language structure (to be implemented)
@@ -37,11 +37,11 @@ CREATE TABLE users (
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
); );
-- Main auction table (handles all auction types) -- Main listing table (handles all listing types)
CREATE TABLE auctions ( CREATE TABLE listings (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
seller_id INTEGER NOT NULL, seller_id INTEGER NOT NULL,
auction_type TEXT NOT NULL, -- 'standard', 'multi_slot', 'fixed_price', 'blind' listing_type TEXT NOT NULL, -- 'standard', 'multi_slot', 'fixed_price', 'blind'
title TEXT NOT NULL, title TEXT NOT NULL,
description TEXT, description TEXT,
@@ -66,7 +66,7 @@ CREATE TABLE auctions (
-- Proxy bid strategies (NOT actual bids, but bidding strategies) -- Proxy bid strategies (NOT actual bids, but bidding strategies)
CREATE TABLE proxy_bids ( CREATE TABLE proxy_bids (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
auction_id INTEGER NOT NULL, listing_id INTEGER NOT NULL,
buyer_id INTEGER NOT NULL, buyer_id INTEGER NOT NULL,
max_amount DECIMAL(10,2) NOT NULL, max_amount DECIMAL(10,2) NOT NULL,
is_active BOOLEAN DEFAULT TRUE, is_active BOOLEAN DEFAULT TRUE,
@@ -74,45 +74,45 @@ CREATE TABLE proxy_bids (
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (auction_id) REFERENCES auctions(id), FOREIGN KEY (listing_id) REFERENCES listings(id),
FOREIGN KEY (buyer_id) REFERENCES users(id), FOREIGN KEY (buyer_id) REFERENCES users(id),
UNIQUE(auction_id, buyer_id) -- One active proxy per user per auction UNIQUE(listing_id, buyer_id) -- One active proxy per user per listing
); );
-- Actual bids that happened (events) -- Actual bids that happened (events)
CREATE TABLE bids ( CREATE TABLE bids (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
auction_id INTEGER NOT NULL, listing_id INTEGER NOT NULL,
buyer_id INTEGER NOT NULL, buyer_id INTEGER NOT NULL,
bid_amount DECIMAL(10,2) NOT NULL, bid_amount DECIMAL(10,2) NOT NULL,
-- For blind auctions -- For blind listings
description TEXT, description TEXT,
-- Status -- Status
is_cancelled BOOLEAN DEFAULT FALSE, is_cancelled BOOLEAN DEFAULT FALSE,
slot_number INTEGER, -- For multi-slot auctions slot_number INTEGER, -- For multi-slot listings
-- NULL = manual bid, NOT NULL = generated from proxy -- NULL = manual bid, NOT NULL = generated from proxy
proxy_bid_id INTEGER, proxy_bid_id INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (auction_id) REFERENCES auctions(id), FOREIGN KEY (listing_id) REFERENCES listings(id),
FOREIGN KEY (buyer_id) REFERENCES users(id), FOREIGN KEY (buyer_id) REFERENCES users(id),
FOREIGN KEY (proxy_bid_id) REFERENCES proxy_bids(id) FOREIGN KEY (proxy_bid_id) REFERENCES proxy_bids(id)
); );
-- Media attachments -- Media attachments
CREATE TABLE auction_medias ( CREATE TABLE listing_medias (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
auction_id INTEGER NOT NULL, listing_id INTEGER NOT NULL,
telegram_file_id TEXT NOT NULL, telegram_file_id TEXT NOT NULL,
media_type TEXT NOT NULL, -- 'photo', 'video' media_type TEXT NOT NULL, -- 'photo', 'video'
position INTEGER DEFAULT 0, position INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (auction_id) REFERENCES auctions(id) FOREIGN KEY (listing_id) REFERENCES listings(id)
); );
-- User preferences -- User preferences
@@ -233,8 +233,8 @@ TZ=UTC
``` ```
start - Show welcome message start - Show welcome message
help - Show help message help - Show help message
newauction - Create a new auction newlisting - Create a new listing
myauctions - View your auctions as a seller mylistings - View your listings as a seller
mybids - View your active bids mybids - View your active bids
settings - Configure notifications settings - Configure notifications
``` ```
@@ -248,11 +248,11 @@ settings - Configure notifications
## Next Implementation Steps (Priority Order) ## Next Implementation Steps (Priority Order)
### 1. Complete Auction Creation Flow ### 1. Complete Listing Creation Flow
- Implement multi-step wizard state machine - Implement multi-step wizard state machine
- Handle media uploads (store Telegram file_ids) - Handle media uploads (store Telegram file_ids)
- Add validation for each field - Add validation for each field
- Create auction in database - Create listing in database
### 2. Implement Bidding System ### 2. Implement Bidding System
- Place manual bid function - Place manual bid function
@@ -265,10 +265,10 @@ settings - Configure notifications
- Auction expiry processing - Auction expiry processing
- Notification sending - Notification sending
### 4. Auction Browsing ### 4. Listing Browsing
- Paginated list with filters - Paginated list with filters
- Search functionality - Search functionality
- Detailed auction view with bid history - Detailed listing view with bid history
### 5. Admin Interface ### 5. Admin Interface
- Axum web server in same binary - Axum web server in same binary

View File

@@ -1,9 +1,11 @@
--- ---
id: task-001 id: task-001
title: Set up database connection and SQLx integration title: Set up database connection and SQLx integration
status: To Do status: Done
assignee: [] assignee:
- '@assistant'
created_date: '2025-08-27 18:31' created_date: '2025-08-27 18:31'
updated_date: '2025-08-27 19:14'
labels: [] labels: []
dependencies: [] dependencies: []
--- ---
@@ -14,8 +16,20 @@ Integrate SQLx with the existing configuration system to establish database conn
## Acceptance Criteria ## Acceptance Criteria
<!-- AC:BEGIN --> <!-- AC:BEGIN -->
- [ ] #1 Database connection pool is created using Config.database_url - [x] #1 Database connection pool is created using Config.database_url
- [ ] #2 Connection health check function is implemented - [x] #2 Connection health check function is implemented
- [ ] #3 Database connection is properly integrated with main.rs - [x] #3 Database connection is properly integrated with main.rs
- [ ] #4 Error handling for database connection failures is implemented - [x] #4 Error handling for database connection failures is implemented
<!-- AC:END --> <!-- AC:END -->
## Implementation Plan
1. Add database connection pool to Config struct
2. Create database connection initialization function
3. Integrate database pool with main.rs startup
4. Add connection health check functionality
5. Implement proper error handling for database failures
## Implementation Notes
Database connection integration completed successfully. The connection pool is created in Config::create_database_pool(), integrated with main.rs, and includes proper error handling. Connection failures are caught and reported with detailed error messages. Health check functionality is implemented. Ready for migration system implementation.

View File

@@ -1,9 +1,11 @@
--- ---
id: task-002 id: task-002
title: Create database migration system title: Create database migration system
status: To Do status: Done
assignee: [] assignee:
- '@assistant'
created_date: '2025-08-27 18:31' created_date: '2025-08-27 18:31'
updated_date: '2025-08-27 19:17'
labels: [] labels: []
dependencies: [] dependencies: []
--- ---
@@ -14,8 +16,20 @@ Set up SQLx migrations infrastructure to manage database schema versions. Create
## Acceptance Criteria ## Acceptance Criteria
<!-- AC:BEGIN --> <!-- AC:BEGIN -->
- [ ] #1 migrations/ directory is created with proper structure - [x] #1 migrations/ directory is created with proper structure
- [ ] #2 001_initial_schema.sql migration file contains complete schema - [x] #2 001_initial_schema.sql migration file contains complete schema
- [ ] #3 Migration runner is integrated with application startup - [x] #3 Migration runner is integrated with application startup
- [ ] #4 Database schema matches the design specified in README.md - [x] #4 Database schema matches the design specified in README.md
<!-- AC:END --> <!-- AC:END -->
## Implementation Plan
1. Create migrations/ directory structure
2. Create 001_initial_schema.sql with complete database schema
3. Add sqlx::migrate!() macro integration to Config::create_database_pool()
4. Test migration system with database creation
5. Add migration status logging and error handling
## Implementation Notes
Database migration system successfully implemented using SQLx migrate!() macro. Created complete initial schema migration (20240827001_initial_schema.sql) with all tables from the design: users, auctions, proxy_bids, bids, auction_medias, user_settings. Added performance indexes. Migration system is automatically embedded in binary and runs on startup. Tested successfully - database file created and migrations applied.

View File

@@ -1,23 +0,0 @@
---
id: task-005
title: Implement auction database operations
status: To Do
assignee: []
created_date: '2025-08-27 18:31'
labels: []
dependencies: []
---
## Description
Create database operations for auction management including creation, retrieval, updates, and media handling. Support all four auction types: standard, multi-slot, fixed-price, and blind auctions.
## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 Auction creation function supports all four auction types
- [ ] #2 Auction retrieval by ID and by seller functions are implemented
- [ ] #3 Auction update functions (status, end time, etc.) are implemented
- [ ] #4 Active auctions listing with pagination is implemented
- [ ] #5 Auction media attachment functions are implemented
- [ ] #6 Auction search and filtering functionality is implemented
<!-- AC:END -->

View File

@@ -0,0 +1,30 @@
---
id: task-005
title: Implement listing database operations
status: To Do
assignee: []
created_date: '2025-08-27 18:31'
updated_date: '2025-08-27 19:21'
labels: []
dependencies: []
---
## Description
Create database operations for listing management including creation, retrieval, updates, and media handling. Support all four listing types: standard, multi-slot, fixed-price, and blind listings.
## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 Auction creation function supports all four auction types
- [ ] #2 Auction retrieval by ID and by seller functions are implemented
- [ ] #3 Auction update functions (status, end time, etc.) are implemented
- [ ] #4 Active auctions listing with pagination is implemented
- [ ] #5 Auction media attachment functions are implemented
- [ ] #6 Auction search and filtering functionality is implemented
- [ ] #7 Listing creation function supports all four listing types
- [ ] #8 Listing retrieval by ID and by seller functions are implemented
- [ ] #9 Listing update functions (status, end time, etc.) are implemented
- [ ] #10 Active listings listing with pagination is implemented
- [ ] #11 Listing media attachment functions are implemented
- [ ] #12 Listing search and filtering functionality is implemented
<!-- AC:END -->

View File

@@ -4,6 +4,7 @@ title: Integrate database with bot commands
status: To Do status: To Do
assignee: [] assignee: []
created_date: '2025-08-27 18:31' created_date: '2025-08-27 18:31'
updated_date: '2025-08-27 19:21'
labels: [] labels: []
dependencies: [] dependencies: []
--- ---
@@ -20,4 +21,10 @@ Connect the database operations with the existing bot command handlers to enable
- [ ] #4 MyBids command shows user's actual bid history - [ ] #4 MyBids command shows user's actual bid history
- [ ] #5 Error handling for database operations in commands - [ ] #5 Error handling for database operations in commands
- [ ] #6 User context is properly passed to database operations - [ ] #6 User context is properly passed to database operations
- [ ] #7 Start command registers new users automatically
- [ ] #8 Settings command integrates with user_settings table
- [ ] #9 MyListings command displays user's actual listings
- [ ] #10 MyBids command shows user's actual bid history
- [ ] #11 Error handling for database operations in commands
- [ ] #12 User context is properly passed to database operations
<!-- AC:END --> <!-- AC:END -->

View File

@@ -0,0 +1,29 @@
---
id: task-010
title: Rename 'auction' to 'listing' throughout codebase
status: Done
assignee:
- '@assistant'
created_date: '2025-08-27 19:19'
updated_date: '2025-08-27 19:22'
labels: []
dependencies: []
---
## Description
Update database schema, code references, and documentation to use 'listing' as the generic term covering both auctions and fixed-price sales. This makes the terminology more accurate and user-friendly.
## Acceptance Criteria
<!-- AC:BEGIN -->
- [x] #1 Database schema updated: auctions -> listings table
- [x] #2 Related table updated: auction_medias -> listing_medias
- [x] #3 Foreign key references updated: auction_id -> listing_id
- [x] #4 Code comments and documentation updated
- [x] #5 Enum values updated: auction_type -> listing_type
- [x] #6 Backlog tasks and README updated with new terminology
<!-- AC:END -->
## Implementation Notes
Successfully renamed 'auction' to 'listing' throughout the codebase. Updated database schema (auctions -> listings, auction_medias -> listing_medias, auction_id -> listing_id), bot commands (newauction -> newlisting, myauctions -> mylistings), command handlers, README documentation, and backlog tasks. Migration system tested and working with new schema. All code compiles successfully.

View File

@@ -0,0 +1,112 @@
-- Initial database schema for Pawctioneer Bot
-- Supports all listing types: standard, multi_slot, fixed_price, blind
-- Core user tracking
CREATE TABLE users (
id INTEGER PRIMARY KEY,
telegram_id INTEGER UNIQUE NOT NULL,
username TEXT,
display_name TEXT,
is_banned BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Main listing table (handles all listing types)
CREATE TABLE listings (
id INTEGER PRIMARY KEY,
seller_id INTEGER NOT NULL,
listing_type TEXT NOT NULL, -- 'standard', 'multi_slot', 'fixed_price', 'blind'
title TEXT NOT NULL,
description TEXT,
-- Pricing
starting_bid DECIMAL(10,2),
buy_now_price DECIMAL(10,2),
min_increment DECIMAL(10,2) DEFAULT 1.00,
-- Multi-slot/fixed price
slots_available INTEGER DEFAULT 1,
-- Timing
starts_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
ends_at TIMESTAMP NOT NULL,
anti_snipe_minutes INTEGER DEFAULT 5,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (seller_id) REFERENCES users(id)
);
-- Proxy bid strategies (NOT actual bids, but bidding strategies)
CREATE TABLE proxy_bids (
id INTEGER PRIMARY KEY,
listing_id INTEGER NOT NULL,
buyer_id INTEGER NOT NULL,
max_amount DECIMAL(10,2) NOT NULL,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (listing_id) REFERENCES listings(id),
FOREIGN KEY (buyer_id) REFERENCES users(id),
UNIQUE(listing_id, buyer_id) -- One active proxy per user per listing
);
-- Actual bids that happened (events)
CREATE TABLE bids (
id INTEGER PRIMARY KEY,
listing_id INTEGER NOT NULL,
buyer_id INTEGER NOT NULL,
bid_amount DECIMAL(10,2) NOT NULL,
-- For blind listings
description TEXT,
-- Status
is_cancelled BOOLEAN DEFAULT FALSE,
slot_number INTEGER, -- For multi-slot listings
-- NULL = manual bid, NOT NULL = generated from proxy
proxy_bid_id INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (listing_id) REFERENCES listings(id),
FOREIGN KEY (buyer_id) REFERENCES users(id),
FOREIGN KEY (proxy_bid_id) REFERENCES proxy_bids(id)
);
-- Media attachments
CREATE TABLE listing_medias (
id INTEGER PRIMARY KEY,
listing_id INTEGER NOT NULL,
telegram_file_id TEXT NOT NULL,
media_type TEXT NOT NULL, -- 'photo', 'video'
position INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (listing_id) REFERENCES listings(id)
);
-- User preferences
CREATE TABLE user_settings (
user_id INTEGER PRIMARY KEY,
language_code TEXT DEFAULT 'en',
notify_outbid BOOLEAN DEFAULT TRUE,
notify_won BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
-- Create indexes for better performance
CREATE INDEX idx_listings_seller_id ON listings(seller_id);
CREATE INDEX idx_listings_type ON listings(listing_type);
CREATE INDEX idx_listings_ends_at ON listings(ends_at);
CREATE INDEX idx_bids_listing_id ON bids(listing_id);
CREATE INDEX idx_bids_buyer_id ON bids(buyer_id);
CREATE INDEX idx_bids_amount ON bids(bid_amount);
CREATE INDEX idx_proxy_bids_listing_buyer ON proxy_bids(listing_id, buyer_id);
CREATE INDEX idx_listing_medias_listing_id ON listing_medias(listing_id);

View File

@@ -1,14 +1,14 @@
pub mod help; pub mod help;
pub mod myauctions;
pub mod mybids; pub mod mybids;
pub mod newauction; pub mod mylistings;
pub mod newlisting;
pub mod settings; pub mod settings;
pub mod start; pub mod start;
// Re-export all command handlers for easy access // Re-export all command handlers for easy access
pub use help::handle_help; pub use help::handle_help;
pub use myauctions::handle_my_auctions;
pub use mybids::handle_my_bids; pub use mybids::handle_my_bids;
pub use newauction::handle_new_auction; pub use mylistings::handle_my_listings;
pub use newlisting::handle_new_listing;
pub use settings::handle_settings; pub use settings::handle_settings;
pub use start::handle_start; pub use start::handle_start;

View File

@@ -1,17 +1,17 @@
use log::info; use log::info;
use teloxide::{prelude::*, types::Message, Bot}; use teloxide::{prelude::*, types::Message, Bot};
pub async fn handle_my_auctions(bot: Bot, msg: Message) -> ResponseResult<()> { pub async fn handle_my_listings(bot: Bot, msg: Message) -> ResponseResult<()> {
let response = "📊 My Auctions (Coming Soon)\n\n\ let response = "📊 My Listings and Auctions (Coming Soon)\n\n\
Here you'll be able to view and manage:\n\ Here you'll be able to view and manage:\n\
Your active auctions\n\ Your active listings and auctions\n\
Auction performance\n\ Listing performance\n\
Bid history\n\ Bid history\n\
Winner selection (for blind auctions)\n\n\ Winner selection (for blind auctions)\n\n\
Feature in development! 🔧"; Feature in development! 🔧";
info!( info!(
"User {} ({}) checked their auctions", "User {} ({}) checked their listings",
msg.chat.username().unwrap_or("unknown"), msg.chat.username().unwrap_or("unknown"),
msg.chat.id msg.chat.id
); );

View File

@@ -1,8 +1,8 @@
use log::info; use log::info;
use teloxide::{prelude::*, types::Message, Bot}; use teloxide::{prelude::*, types::Message, Bot};
pub async fn handle_new_auction(bot: Bot, msg: Message) -> ResponseResult<()> { pub async fn handle_new_listing(bot: Bot, msg: Message) -> ResponseResult<()> {
let response = "🏗️ New Auction Creation (Coming Soon)\n\n\ let response = "🏗️ New Listing or Auction Creation (Coming Soon)\n\n\
This feature will allow you to create:\n\ This feature will allow you to create:\n\
Standard time-based auctions\n\ Standard time-based auctions\n\
Multi-slot auctions\n\ Multi-slot auctions\n\
@@ -11,7 +11,7 @@ pub async fn handle_new_auction(bot: Bot, msg: Message) -> ResponseResult<()> {
Stay tuned! 🎪"; Stay tuned! 🎪";
info!( info!(
"User {} ({}) attempted to create new auction", "User {} ({}) attempted to create new listing or auctionc",
msg.chat.username().unwrap_or("unknown"), msg.chat.username().unwrap_or("unknown"),
msg.chat.id msg.chat.id
); );

View File

@@ -1,5 +1,6 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use std::env; use sqlx::SqlitePool;
use std::{env, str::FromStr};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Config { pub struct Config {
@@ -13,6 +14,9 @@ pub struct Config {
pub web_port: u16, pub web_port: u16,
} }
/// Database connection pool type alias for convenience
pub type DatabasePool = sqlx::SqlitePool;
impl Config { impl Config {
/// Load and validate configuration from environment variables /// Load and validate configuration from environment variables
/// ///
@@ -81,4 +85,49 @@ impl Config {
Ok(()) Ok(())
} }
/// Create a database connection pool using the configured database URL
///
/// This establishes a connection pool to the SQLite database and runs any pending migrations.
pub async fn create_database_pool(&self) -> Result<DatabasePool> {
log::info!("Connecting to database: {}", self.database_url);
// Create connection pool with sensible defaults for SQLite
// For SQLite, we need to ensure the database file can be created
let pool = SqlitePool::connect_with(
sqlx::sqlite::SqliteConnectOptions::from_str(&self.database_url)?
.create_if_missing(true),
)
.await
.with_context(|| format!("Failed to connect to database: {}", self.database_url))?;
// Run database migrations
log::info!("Running database migrations...");
sqlx::migrate!("./migrations")
.run(&pool)
.await
.context("Failed to run database migrations")?;
log::info!("Database migrations completed successfully");
// Run health check
Self::health_check(&pool)
.await
.context("Database health check failed after connection")?;
log::info!("Database connection pool created successfully");
Ok(pool)
}
/// Perform a health check on the database connection
///
/// This verifies the database is accessible and responding to queries.
pub async fn health_check(pool: &DatabasePool) -> Result<()> {
sqlx::query("SELECT 1")
.execute(pool)
.await
.context("Database health check query failed")?;
log::debug!("Database health check passed");
Ok(())
}
} }

View File

@@ -15,10 +15,10 @@ pub enum Command {
Start, Start,
#[command(description = "Show help message")] #[command(description = "Show help message")]
Help, Help,
#[command(description = "Create a new auction")] #[command(description = "Create a new listing or auction")]
NewAuction, NewListing,
#[command(description = "View your auctions as a seller")] #[command(description = "View your listings and auctions")]
MyAuctions, MyListings,
#[command(description = "View your active bids")] #[command(description = "View your active bids")]
MyBids, MyBids,
#[command(description = "Configure notifications")] #[command(description = "Configure notifications")]
@@ -35,6 +35,9 @@ async fn main() -> Result<()> {
// Load and validate configuration from environment/.env file // Load and validate configuration from environment/.env file
let config = Config::from_env()?; let config = Config::from_env()?;
// Create database connection pool
let db_pool = config.create_database_pool().await?;
info!("Starting Pawctioneer Bot..."); info!("Starting Pawctioneer Bot...");
let bot = Bot::new(&config.telegram_token); let bot = Bot::new(&config.telegram_token);
@@ -47,13 +50,13 @@ async fn main() -> Result<()> {
.filter_command::<Command>() .filter_command::<Command>()
.branch(dptree::case![Command::Start].endpoint(handle_start)) .branch(dptree::case![Command::Start].endpoint(handle_start))
.branch(dptree::case![Command::Help].endpoint(handle_help)) .branch(dptree::case![Command::Help].endpoint(handle_help))
.branch(dptree::case![Command::NewAuction].endpoint(handle_new_auction)) .branch(dptree::case![Command::NewListing].endpoint(handle_new_listing))
.branch(dptree::case![Command::MyAuctions].endpoint(handle_my_auctions)) .branch(dptree::case![Command::MyListings].endpoint(handle_my_listings))
.branch(dptree::case![Command::MyBids].endpoint(handle_my_bids)) .branch(dptree::case![Command::MyBids].endpoint(handle_my_bids))
.branch(dptree::case![Command::Settings].endpoint(handle_settings)), .branch(dptree::case![Command::Settings].endpoint(handle_settings)),
), ),
) )
.dependencies(dptree::deps![]) .dependencies(dptree::deps![db_pool])
.enable_ctrlc_handler() .enable_ctrlc_handler()
.build() .build()
.dispatch() .dispatch()