# AGENTS.md - br-fields
> Database field standardization library for Rust. Generates SQL DDL for SQLite, MySQL, and PostgreSQL.
## Quick Reference
```bash
# Build & Test
cargo build
cargo test # Run all tests
cargo test -- --nocapture # Show println! output
# Lint & Format
cargo clippy --all-targets --all-features -- -D warnings
cargo fmt --check
```
## Structure
```
br-fields/
├── Cargo.toml # Package manifest (edition 2021, v2.2.5)
├── src/
│ ├── lib.rs # Field trait, FieldMode enum, field() & verify()
│ ├── str.rs # Str, Pass, Key, Tel, Email, Code, BarCode, QrCode, Ident, Color
│ ├── int.rs # Int, Switch
│ ├── float.rs # Float
│ ├── text.rs # Text, Editor, Json, Array, Object, Url
│ ├── datetime.rs # Year, YearMonth, Datetime, Time, Date, Timestamp
│ ├── select.rs # Radio, Select
│ ├── dict.rs # Dict
│ ├── files.rs # Files
│ ├── location.rs # Location, Polygon
│ └── table.rs # Table, Tree
└── tests/test.rs # Integration tests
```
## Database SQL Generation
| `sqlite` | unquoted | Yes (when require=true) | None |
| `pgsql` | `"field"` | **NO** (never added) | `-- comment` |
| `mysql` | `` `field` `` | Yes (when require=true) | `comment '...'` |
**PostgreSQL special behavior:** `not null` is NEVER added for pgsql, even when `require=true`. This allows inserting records without specifying all fields.
## Code Patterns
### Adding New Field Type
1. Create struct with: `require`, `field`, `mode`, `title`, `def`, `show`, `describe`, `example`
2. Implement `new()` constructor
3. Implement `Field` trait (`sql()`, `hide()`, `describe()`, `field()`, `swagger()`, `example()`)
4. Add to `FieldMode` enum in `lib.rs`
5. Add match arms in `field()` and `verify()` functions
6. Add tests in `tests/test.rs`
### SQL Method Pattern
```rust
fn sql(&mut self, model: &str) -> String {
let not_null = if self.require { " not null" } else { "" };
match model {
"sqlite" => format!("{} TYPE{} default ...", self.field, not_null),
"pgsql" => {
// NO not_null for pgsql
let sql = format!(r#""{}" TYPE default ..."#, self.field);
format!("{} --metadata", sql)
}
_ => { // MySQL
let sql = format!("`{}` TYPE{} default ...", self.field, not_null);
format!("{} comment 'metadata'", sql)
}
}
}
```
### Test Pattern
```rust
// sqlite/mysql: exact string match
assert_eq!("expected sql", res);
// pgsql: use contains() for flexibility
assert!(res.contains(r#""field" TYPE"#));
assert!(!res.contains("not null")); // Verify no not null
assert!(res.contains("--metadata"));
```
## Conventions
- **Doc comments:** Chinese language (`/// 中文描述`)
- **Imports:** std → external crates → internal (`use crate::...`)
- **Naming:** PascalCase structs, snake_case functions/fields
- **Error handling:** `.unwrap()` for JSON ops (assumes valid data)
- **Regex:** Use `lazy_static!` for compiled patterns
## Dependencies
| `json` | JSON serialization |
| `chrono` | Date/time handling |
| `rand` | Random generation |
| `lazy_static` | Static initialization |
| `regex` | Pattern matching |
| `log` | Logging facade |