Database access logic isolates functions that read and write persistent data from HTTP handlers. In a Rust web API, handlers translate requests and responses while a separate module owns SQL queries, database mapping, and database-facing errors. section 4.4 section 6.3.2
A practical access layer typically provides:
- A module such as src/iter5/dbaccess/tutor.rs containing tutor-specific functions. section 6.3.3
- Asynchronous functions receiving a PostgreSQL connection pool and returning domain models or EzyTutorError. section 6.3.3 section 8.1
- Queries for listing, retrieving, inserting, updating, and deleting records, with handlers invoking the corresponding database functions. section 6.3.2 section 6.3.3
- A stable function signature that lets the database implementation change without rewriting handlers. section 4.4
Tutor retrieval and insertion
A list function executes a SELECT with sqlx, fetches all rows, manually maps each row into Tutor, and returns NotFound when the result is empty. A detail function accepts tutor_id, maps the row, converts lookup errors with map_err, and propagates failures with ?. An insertion function executes INSERT ... RETURNING, fetches the new row, maps it to Tutor, and returns it to the handler. section 6.3.3
Manual row-to-struct mapping is useful when Rust models contain computed fields, additional fields, or nested data that does not match database columns directly. Automatic query_as! mapping remains an alternative when names align. section 6.3.3
Use the API structure diagram to trace the relationship among routes, handlers, and database access functions for tutor operations. section 6.3
