Models and ORM
Relevant source files
The following files were used as context for generating this wiki page:
Models and the Object-Relational Mapping (ORM) system in Loco provide a structured way to interact with databases using Rust entities instead of raw SQL. Backed by SeaORM, this module allows developers to define rich business logic, relationships, and validations directly on data structures.
The system is designed for high developer productivity, utilizing code generators to produce boilerplate code for entities, migrations, and active models. It supports multiple database backends, including PostgreSQL, SQLite, and MySQL, while providing tools for schema management, data seeding, and automated entity generation.
Sources: README.md:28-32, docs-site/config.toml:79-84
Database Connection Management
Loco manages database connections through a configuration-driven approach, supporting both single and multiple database setups via the MultiDb structure. Connections are established using ConnectOptions, which allow for fine-tuning performance through settings such as connection pooling, timeouts, and logging.
The diagram shows the flow from configuration to the establishment of connection pools for different supported database backends.
Sources: src/db.rs:60-70, src/db.rs:114-140
Multi-Database Support
The MultiDb struct enables applications to interact with multiple databases simultaneously by storing a map of DatabaseConnection instances indexed by name.
| Feature | Description |
|---|---|
MultiDb::new | Creates multiple DB connections from a hashmap of configurations. |
MultiDb::get | Retrieves a specific connection by its identifier. |
verify_access | Checks if the current user has permission to access tables (specifically for Postgres). |
Sources: src/db.rs:65-88, src/db.rs:95-105
Entity Generation and Maintenance
Loco leverages sea-orm-cli to generate Rust entities from the database schema. This process is orchestrated through the CLI and include specific logic to clean up and extend generated code to adhere to Loco's architectural patterns.
Generation Workflow
When running cargo loco db entities, the framework executes a multi-step process:
- Validation: Checks if
sea-orm-cliis installed and the database is accessible. - Execution: Runs
sea-orm-cli generate entitywith flags for Serde support and table ignores. - Fixup: The
fix_entitiesfunction modifies the generated files insrc/models/_entitiesto moveActiveModelBehaviorlogic to an extension module.
The sequence shows how Loco wraps the standard SeaORM generation to provide a cleaner separation between generated code and user-defined logic.
Sources: src/db.rs:434-455, src/db.rs:475-495, src/cli.rs:563-565
Model Extensions
Loco promotes a pattern where generated code resides in _entities, while custom logic is implemented in the parent models directory. The framework automatically generates boilerplate for Model, ActiveModel, and Entity implementations, including automatic updated_at timestamp handling if the column is detected.
Sources: src/db.rs:530-580
Schema Management and Migrations
Schema evolution is handled through a migration system where developers define changes in Rust. The db module provides functions to apply (up), revert (down), and check the status of migrations.
Migration Operations
| Operation | Function | Description |
|---|---|---|
| Migrate | migrate::<M> | Applies all pending migrations. |
| Down | down::<M> | Reverts a specific number of migration steps. |
| Reset | reset::<M> | Drops all tables and reapplies migrations from scratch. |
| Converge | converge::<H, M> | High-level function to synchronize DB state based on config (auto-migrate or recreate). |
Sources: src/db.rs:189-215, src/db.rs:107-128
Schema Inspection
The system provides utilities to inspect the database at runtime:
extract_db_name: Parses connection URIs to identify the target database.get_tables: Retrieves a list of all non-system tables.has_id_column: Detects if a table contains a primary key namedid.is_auto_increment: Checks if theidcolumn uses a sequence or autoincrement feature.
Sources: src/db.rs:163-172, src/db.rs:300-340, src/db.rs:659-688
Data Seeding and Dumping
Loco supports YAML-based fixtures for both populating the database and exporting existing data.
Seeding Logic
The seed function deserializes YAML files into serde_json::Value vectors and performs batch inserts. A critical feature is the reset_autoincrement function, which ensures that after manual ID inserts during seeding, the database's internal counters are updated to prevent primary key collisions on subsequent writes.
Sources: src/db.rs:228-258, src/db.rs:388-420
Dumping Data and Schema
Applications can export their state for testing or backup:
- dump_tables: Iterates through tables and creates YAML snapshots. It includes specialized logic to handle boolean conversion for SQLite (converting 0/1 back to true/false).
- dump_schema: Exports the database structure (table names, columns, and types) into a JSON file.
Sources: src/db.rs:739-755, src/db.rs:850-865
Scaffolding and Code Generation
The loco-gen module provides the logic for the generate command, allowing rapid creation of models and migrations from the CLI.
Field Parsing
When a user runs cargo loco g model posts title:string, the framework maps the requested type to the appropriate database column type.
| Input Type | Internal Mapping |
|---|---|
string | StringNull |
string! | String |
string^ | StringUniq |
references | Creates a foreign key relationship (e.g., user_id). |
Sources: loco-gen/src/model.rs:36-60, loco-gen/src/model.rs:150-165
Conclusion
Models and ORM in Loco serve as the backbone for data persistence, combining the power of SeaORM with high-level automation. By automating entity generation, migration management, and providing robust seeding/dumping utilities, Loco enables developers to maintain a consistent data layer with minimal manual effort. This integrated approach ensures that the database schema and the Rust application code remain synchronized throughout the development lifecycle.
Sources: README.md:14-18, src/db.rs:1-5