Canyon Entity

Welcome to the section dedicated to one of the most iconic features of Canyon - The Entities.

Definition of Canyon Entity

Throughout the previous chapters, we have already introduced the concept of entity and demonstrated its usage in various contexts. In Canyon, however, an entity holds an even more powerful meaning than what was presented before.

Put simply, a Canyon Entity is a user-defined type, which is represented as a struct, and is annotated with a special procedural macro:


#![allow(unused)]
fn main() {
use canyon_sql::macros::canyon_entity;

#[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
}
}

This macro unlocks a set of new features for the type. These features include:

  • Inform Canyon that it should handle everything in the program that relates to this type on the database;
  • Track the type along with all the necessary metadata on a special register;
  • Allow the user to configure an alternative table name and specify the schema in which the entity being pointed to resides;

These features provide a wealth of functionalities that will be explored further in upcoming chapters.

The table_name and the schema attribute parameters

The canyon_entity macro can optionally receive two parameters: table_name and schema.

Example:


#![allow(unused)]
fn main() {
#[canyon_entity(table_name = "other_league", schema = "tic")]
}

The naming convention for Rust types is CamelCase. On the other hand, the naming convention for databases tables and schemas is often snake_case. These attributes allow us to fulfill both standards.

Typically, Canyon adheres to the convention of converting the name of a user-defined struct to a snake-case identifier for the purpose of generating database operations. This approach eliminates the need for modifying anything other than the defaults. Enabling users to conform to established ORM conventions in conjunction with the most common method of defining a table across various database engines.

However, it is not always necessary to follow this convention. In some cases, tables may already exist in the database, requiring different mapping. There may also be situations where the user prefer to use a different type name that cannot be converted to snake_case as described above. To accomodate these scenarios, the user has the ability to specify the name of the database entity accordingly.

Additionally, Canyon assumes assumes that the entities will be placed in the default schema, such as public in PostgreSQL or dbo in MSSQL. If there is need to use an alternative schema, the user may configure this on a per-entity basis using the schema parameter.

The #[primary_key] field attribute

Let's discuss one of the fundamental concepts in relational databases: the primary_key. Each table in a database typically has its own primary key, and the primary purpose of designating one is to identify each unique record in a particular table.

In Canyon, this is a significant concept. Almost every entity must be annotated with a primary_key to unlock the full potential of the CRUD operations generated by the CanyonCrud derive macro. It also manages other things, such as:

  • Identifying each unique record in a table;
  • Facilitating data serialization;
  • Auto-incrementing the primary_key of new inserted rows;

The primary_key attribute has one optional parameter: autoincremental. This is enabled by default. And means that each new row will have the key of the last row incremented by 1.

Sometimes, the user may not wish an incremental primary key (usually on rare cases where a unique String is used as primary key). Although this is not common, it is sometimes used. In that case, the user may disable autoincremental by including:


#![allow(unused)]
fn main() {
#[primary_key(autoincremental = false)]
}

Note: autoincremental is enabled by default. Not specifying it means it is true.