mirror of https://github.com/buster-so/buster.git
184 lines
4.9 KiB
Plaintext
184 lines
4.9 KiB
Plaintext
---
|
|
description: This is helpful for building libs for our web server to interact with.
|
|
globs: libs/**/*.rs
|
|
alwaysApply: false
|
|
---
|
|
|
|
# Library Construction Guide
|
|
|
|
## Directory Structure
|
|
```
|
|
libs/
|
|
├── my_lib/
|
|
│ ├── Cargo.toml # Library-specific manifest
|
|
│ ├── src/
|
|
│ │ ├── lib.rs # Library root
|
|
│ │ ├── types.rs # Data structures and types
|
|
│ │ ├── utils/ # Utility functions
|
|
│ │ └── errors.rs # Custom error types
|
|
│ └── tests/ # Integration tests
|
|
```
|
|
|
|
## Cargo.toml Template
|
|
```toml
|
|
[package]
|
|
name = "my_lib"
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
|
|
# Dependencies should be inherited from workspace
|
|
[dependencies]
|
|
# Use workspace dependencies
|
|
anyhow = { workspace = true }
|
|
chrono = { workspace = true }
|
|
serde = { workspace = true }
|
|
serde_json = { workspace = true }
|
|
tokio = { workspace = true }
|
|
tracing = { workspace = true }
|
|
uuid = { workspace = true }
|
|
diesel = { workspace = true }
|
|
diesel-async = { workspace = true }
|
|
# Add other workspace dependencies as needed
|
|
|
|
# Development dependencies
|
|
[dev-dependencies]
|
|
tokio-test = { workspace = true }
|
|
# Add other workspace dev dependencies as needed
|
|
|
|
# Feature flags
|
|
[features]
|
|
default = []
|
|
# Define library-specific features here
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### 1. Workspace Integration
|
|
- Use `{ workspace = true }` for common dependencies
|
|
- Never specify library-specific versions for dependencies that exist in the workspace
|
|
- All dependencies should be managed by the workspace
|
|
- Keep feature flags modular and specific to the library's needs
|
|
|
|
### 2. Library Structure
|
|
- Keep the library focused on a single responsibility
|
|
- Use clear module hierarchies
|
|
- Export public API through `lib.rs`
|
|
- Follow the workspace's common patterns
|
|
|
|
Example `lib.rs`:
|
|
```rust
|
|
//! My Library documentation
|
|
//!
|
|
//! This library provides...
|
|
|
|
// Re-export common workspace types if needed
|
|
pub use anyhow::{Result, Error};
|
|
|
|
pub mod models;
|
|
pub mod utils;
|
|
mod errors;
|
|
|
|
// Re-exports
|
|
pub use errors::Error;
|
|
pub use models::{ImportantType, AnotherType};
|
|
```
|
|
|
|
### 3. Error Handling
|
|
- Use the workspace's common error types where appropriate
|
|
- Define library-specific errors only when needed
|
|
- Implement conversions to/from workspace error types
|
|
|
|
Example `errors.rs`:
|
|
```rust
|
|
use thiserror::Error;
|
|
use anyhow::Error as WorkspaceError;
|
|
|
|
#[derive(Error, Debug)]
|
|
pub enum Error {
|
|
#[error("library specific error: {0}")]
|
|
LibrarySpecific(String),
|
|
|
|
#[error(transparent)]
|
|
Workspace(#[from] WorkspaceError),
|
|
}
|
|
```
|
|
|
|
### 4. Testing
|
|
- Follow workspace testing conventions
|
|
- Use shared test utilities from workspace when available
|
|
- Keep library-specific test helpers in the library
|
|
- Use workspace-defined test macros if available
|
|
|
|
#### Database Integration Tests
|
|
For tests that require database access, the preferred approach is to use automatic pool initialization:
|
|
|
|
```rust
|
|
// IMPORTANT: These dependencies are for TESTS ONLY
|
|
// Add to your Cargo.toml under [dev-dependencies]:
|
|
// lazy_static = { workspace = true }
|
|
// ctor = "0.4.1"
|
|
|
|
// In tests/mod.rs - this is compiled ONLY during tests, not in release builds
|
|
use database::pool::init_pools;
|
|
use lazy_static::lazy_static;
|
|
|
|
lazy_static! {
|
|
// Initialize test environment once across all tests
|
|
static ref TEST_ENV: () = {
|
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
|
if let Err(e) = rt.block_on(init_pools()) {
|
|
panic!("Failed to initialize test pools: {}", e);
|
|
}
|
|
println!("✅ Test environment initialized");
|
|
};
|
|
}
|
|
|
|
// This constructor only exists in test builds
|
|
#[ctor::ctor]
|
|
fn init_test_env() {
|
|
lazy_static::initialize(&TEST_ENV);
|
|
}
|
|
```
|
|
|
|
Then write normal tests without explicit initialization:
|
|
|
|
```rust
|
|
// In your test file
|
|
#[tokio::test]
|
|
async fn test_database_functionality() -> Result<()> {
|
|
// Pool is already initialized - just get it
|
|
let pool = database::pool::get_pg_pool();
|
|
|
|
// Your test code here
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
This pattern ensures:
|
|
- Database pools are initialized exactly once at test startup
|
|
- All tests can access the same pool without manual initialization
|
|
- Test code remains clean without initialization boilerplate
|
|
|
|
### 5. Documentation
|
|
- Follow workspace documentation style
|
|
- Link to related workspace documentation
|
|
- Document workspace integration points
|
|
- Include examples showing workspace type usage
|
|
|
|
### 6. Integration Points
|
|
- Define clear boundaries with other workspace crates
|
|
- Use workspace traits and interfaces
|
|
- Share common utilities through workspace-level crates
|
|
- Consider cross-crate testing
|
|
|
|
### 7. Development Workflow
|
|
- Run workspace-level tests when making changes
|
|
- Update workspace documentation if needed
|
|
- Follow workspace versioning strategy
|
|
- Use workspace-level CI/CD pipelines
|
|
|
|
### 8. Dependencies
|
|
- All dependencies should be inherited from the workspace
|
|
- Never add library-specific dependency versions
|
|
- Keep dependencies minimal and focused
|
|
- The workspace will manage all dependency versions |