SELECT operations
The most fundamental operation when querying a database is the read
operation, which involves requesting a particular set of data stored in one or more tables.
When any of the CRUD operations are processed, the data received as response from the database will be of a generic type referred to as Row
. Row
is unique for each client library, but each of them refer to a single "row" retrieved from the database.
Canyon
's job is to then parse this retrieved response into T
or Vec<T>
, where T
is your defined type. As long as the types are properly annotated, the users don't need to worry about parsing the data themselves.
Here is the type that was described in the previous chapter:
#![allow(unused)] fn main() { #[derive(CanyonCrud, CanyonMapper)] #[canyon_entity] pub struct League { #[primary_key] pub id: i32, pub ext_id: i64, pub slug: String, pub name: String, pub region: String, pub image_url: String } }
Let's review what SELECT operations are automatically available now. With focus on those that are well known in the CRUD
world.
find_all
One of the most commonly used queries when working with databases. In summary, it is the same as saying:
"Please, database, give me all the data that you have for this table, including all of the columns!"
In Canyon
, this method is available as an associated function for your defined type T
. The type::find_all()
method can be translated to a SQL query SELECT * FROM {table_name}
, which will return a collection of Row
instances.
The retrieved Row
collection will then be automatically mapped into a Vec<T>
, where T
is the same type of the object where type::find_all
was called.
#![allow(unused)] fn main() { #[derive(CanyonCrud, CanyonMapper)] #[canyon_entity] pub struct League { #[primary_key] pub id: i32, pub ext_id: i64, pub slug: String, pub name: String, pub region: String, pub image_url: String } }
We can retrieve all rows of the league
table with the following line:
#![allow(unused)] fn main() { let leagues: Result<Vec<League>, _> = League::find_all().await; }
Unchecked alternatives
There are two more operations associated with the find_all()
function that provide unchecked alternatives.
In Canyon
, every database operation returns a Result<T, E>
. However, during software development, debugging, or prototyping, it may be useful to access query results without additional complications. For this purpose, Canyon
provides:
T::find_all_unchecked()
T::find_all_unchecked_datasource()
Both functions return a Vec<T>
directly, bypassing the Result
type. However, if there is any error during the database connection, the program will panic. Therefore, these functions are only recommended for quickly profiling or experimentation.
Find by PK
Another common pattern for reading data is to find a record by its primary key (PK
).
Looking at the previous example League
again:
#![allow(unused)] fn main() { #[derive(CanyonCrud, CanyonMapper)] #[canyon_entity] pub struct League { #[primary_key] pub id: i32, pub ext_id: i64, pub slug: String, pub name: String, pub region: String, pub image_url: String } }
The primary key in this case is id
. Therefore, only one League
row exists for every unique id
value. The auto-incrementing
parameter isn't set. So it is enabled. Check previous chapter for more information.
To find a record by its primary key, the method type::find_by_id
can be used:
#![allow(unused)] fn main() { // Searching for a row that has id=1 let league: Result<Option<League>, _> = League::find_by_id(&1).await; }
Note the reference on the function argument. The find_by_id
associated function doesn't take ownership of the parameter.