Creating Tables

First, create a database config for the sea_orm::DatabaseConnection to use to connect and authenticate to the PostgreSQL server.

+ use async_std::sync::Arc;
+ use sea_orm::{Database, DbBackend};

#[async_std::main]
async fn main() -> anyhow::Result<()> {
    //Define the database backend
    + let db_postgres = DbBackend::Postgres;

    // Read the database environment from the `.env` file
    + let env_database_url = include_str!("../.env").trim();
    // Split the env url
    + let split_url: Vec<&str> = env_database_url.split("=").collect();
    // Get item with the format `database_backend://username:password@localhost/database`
    + let database_url = split_url[1];

    // Perform a database connection
    + let db = Database::connect(database_url).await?;
    + let db = Arc::new(db);

    Ok(())
}

The include_str!("../.env").trim(); reads the .env file and loads it's content at compile time. This content is the PostgreSQL database configuration which we later split using split("=") and discard the DATABASE_URL= part since it's only needed by sea-orm-cli and not Database::connect() which only accepts database_backend://username:password@localhost/database.

Calling the Database::connect() on the parsed URL creates a DatabaseConnection that will perform all CRUD operations. This connection is kept behind an async_std::sync::Arc for thread safety when we spawn async tasks.

Add the code to create the three tables, todos, fruits and suppliers.

FILE:src/main.rs

  use async_std::sync::Arc;
- use sea_orm::{Database, DbBackend};
+ use sea_orm::{
+     sea_query::{Alias, ColumnDef, ForeignKey, ForeignKeyAction, Table},
+     ConnectionTrait, Database, DbBackend,
+ };

#[async_std::main]
async fn main() -> anyhow::Result<()> {

// --- code snippet ---

// Create the fruits table
    let fruits_table = Table::create()
        .table(Alias::new("fruits"))
        .if_not_exists()
        .col(
            ColumnDef::new(Alias::new("fruit_id"))
                .integer()
                .auto_increment()
                .primary_key()
                .not_null(),
        )
        .col(
            ColumnDef::new(Alias::new("fruit_name"))
                .string()
                .unique_key()
                .not_null(),
        )
        .to_owned();

    // Executing the SQL query to create the `fruits_table` in PostgreSQL
    let create_table_op = db.execute(db_postgres.build(&fruits_table)).await;
    // Print the result in a user friendly way
    println!(
        "`CREATE TABLE fruits` {:?}",
        match create_table_op {
            Ok(_) => "Operation Successful".to_owned(),
            Err(e) => format!("Unsuccessful - Error {:?}", e),
        }
    );

    // Create the `todos` table
    let todos_table = Table::create()
        .table(Alias::new("todos"))
        .if_not_exists()
        .col(
            ColumnDef::new(Alias::new("todo_id"))
                .integer()
                .auto_increment()
                .primary_key()
                .not_null(),
        )
        .col(
            ColumnDef::new(Alias::new("username"))
                .string()
                .unique_key()
                .not_null(),
        )
        .col(ColumnDef::new(Alias::new("todo_list")).string())
        .to_owned();

    // Executing the SQL query to create the `todos` table in PostgreSQL
    let create_table_op = db.execute(db_postgres.build(&todos_table)).await;
    // Print the result in a user friendly way
    println!(
        "`CREATE TABLE todos` {:?}",
        match create_table_op {
            Ok(_) => "Operation Successful".to_owned(),
            Err(e) => format!("Unsuccessful - Error {:?}", e),
        }
    );
    
	Ok(())
}

The previous tutorial gave an introduction on creating tables. Table::create() is the method to do this. Then the db.execute() method performs the database operation for table creation.

Next, use sea-orm-cli to auto-generate the code for Entity, Model, Relation , etc...

$ sea-orm-cli generate entity -o src/todo_list_table -t todos #The todos table

$ sea-orm-cli generate entity -o src/fruits_list_table -t fruits #The fruits table

$ sea-orm-cli generate entity -o src/suppliers_list_table -t suppliers #The suppliers table

This generates new directories

SeaORM-TODO-App
	|-- Cargo.toml
	|-- .env
	|-- src
+ 	|-- suppliers_list_table
+ 		|-- mod.rs
+ 		|-- prelude.rs
+ 		|-- suppliers.rs
+ 	|-- fruits_list_table
+ 		|-- mod.rs
+ 		|-- prelude.rs
+ 		|-- fruits.rs
+ 	|-- todo_list_table
+ 		|-- mod.rs
+ 		|-- prelude.rs
+ 		|-- todos.rs

Modify the src/suppliers_list_table/prelude.rs and import the types using friendly names.

- pub use super::suppliers::Entity as Suppliers;

+ pub use super::suppliers::{
+     ActiveModel as SuppliersActiveModel, Column as SuppliersColumn, Entity as Suppliers,
+     Model as SuppliersModel, PrimaryKey as SuppliersPrimaryKey, Relation as SuppliersRelation,
+ };

Do the same to the src/fruits_table/prelude.rs

- pub use super::fruits::Entity as Fruits;

+ pub use super::fruits::{
+     ActiveModel as FruitsActiveModel, Column as FruitsColumn, Entity as Fruits,
+     Model as FruitsModel, PrimaryKey as FruitsPrimaryKey, Relation as FruitsRelation,
+ };

Do the same ot the src/todos_table/prelude.rs

//! SeaORM Entity. Generated by sea-orm-codegen 0.5.0
- pub use super::todos::Entity as Todos;

+ pub use super::todos::{
+     ActiveModel as TodosActiveModel, Column as TodosColumn, Entity as Todos, Model as TodosModel,
+     PrimaryKey as TodosPrimaryKey, Relation as TodosRelation,
+ };

Modify the Model and Relation part of Suppliers Entity to import Fruits entity properly

//! SeaORM Entity. Generated by sea-orm-codegen 0.6.0

use sea_orm::entity::prelude::*;

#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "suppliers")]
pub struct Model {
    #[sea_orm(primary_key)]
    pub suppliers_id: i32,
    #[sea_orm(unique)]
    pub suppliers_name: String,
    pub fruit_id: i32,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
    #[sea_orm(
-		belongs_to = "super::fruits::Entity",
+		belongs_to = "crate::Fruits",
        from = "Column::FruitId",
-		to = "super::fruits::Column::FruitId",
+		to = "crate::FruitsColumn::FruitId",
        on_update = "Cascade",
        on_delete = "Cascade"
    )]
    Fruits,
}

- impl Related<super::fruits::Entity> for Entity {
+ impl Related<crate::Fruits> for Entity {
    fn to() -> RelationDef {
        Relation::Fruits.def()
    }
}

impl ActiveModelBehavior for ActiveModel {}

Import these modules into src/main.rs

// --- code snippet ---
+ mod fruits_list_table;
+ mod suppliers_list_table;
+ mod todo_list_table;

+ pub use fruits_list_table::prelude::*;
+ pub use suppliers_list_table::prelude::*;
+ pub use todo_list_table::prelude::*;

#[async_std::main]
async fn main() -> anyhow::Result<()> {
    // --- code snippet ---
    
    Ok(())
 }

Next, populate the fruits and suppliers tables with data.

Create a new file src/insert_values.rs and add the following code:

use crate::{Fruits, FruitsActiveModel, Suppliers, SuppliersActiveModel};
use sea_orm::{DatabaseConnection, EntityTrait, Set};

// Insert suppliers in the `suppliers` table
pub async fn insert_fruits(db: &DatabaseConnection) -> anyhow::Result<()> {

    let apple = FruitsActiveModel {
        fruit_name: Set("Apple".to_owned()),
        ..Default::default()
    };

    let orange = FruitsActiveModel {
        fruit_name: Set("Orange".to_owned()),
        ..Default::default()
    };

    let mango = FruitsActiveModel {
        fruit_name: Set("Mango".to_owned()),
        ..Default::default()
    };

    let pineapple = FruitsActiveModel {
        fruit_name: Set("Pineapple".to_owned()),
        ..Default::default()
    };

    let fruit_insert_operation = Fruits::insert_many(vec![apple, orange, mango, pineapple])
        .exec(db)
        .await;

    println!("INSERTED FRUITS: {:?}", fruit_insert_operation?);

    Ok(())
}

Here, ActiveModel is used to prepare the data for insertion into the database using Entity::insert() .

Import this module to the src/main.rs file and call these functions to perform insert operations

// --- code snippet ---
+ mod insert_values;
+ pub use insert_values::*;

#[async_std::main]
async fn main() -> anyhow::Result<()> {
    // --- code snippet ---
    
+	 insert_fruits(&db).await?;
+    insert_suppliers(&db).await?;
    
     Ok(())
}