zero4rs 2.0.0

zero4rs is a powerful, pragmatic, and extremely fast web framework for Rust
Documentation
use lazy_static::lazy_static;

// https://handlebarsjs.com/
#[rustfmt::skip]
lazy_static! {
    pub static ref IQL_TEMPLATE: &'static str = r#"
use lazy_static::lazy_static;

use anyhow::Context as _;
use serde::{Deserialize, Serialize};
use sqlx::{MySql, Pool, QueryBuilder, Row};
use sqlx::mysql::MySqlRow;

lazy_static! {
    #[rustfmt::skip]
    pub static ref SELECT_STATMENT: &'static str = "select {{#each fields}}{{this.db_field_name}}{{#if (not @last) }}, {{/if}}{{/each}} from {{ table_name }}";
}

// use crate::core::error2::Error;
use crate::core::error2::Result;

#[rustfmt::skip]
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct {{ struct_name }} {
    {{#each fields}}
        {{# if this.nullable }}
    #[serde(skip_serializing_if = "Option::is_none")]
        {{else if (eq this.rust_type "String") }}
    #[serde(skip_serializing_if = "String::is_empty")]
        {{/if}}
    pub {{this.name}}: {{# if this.nullable }}Option<{{this.rust_type}}>{{else}}{{this.rust_type}}{{/if}},
    {{/each}}
}

#[rustfmt::skip]
#[allow(dead_code)]
impl {{ struct_name }} {
    pub fn new() -> Self {
        Self {
            ..Default::default()
        }
    }

    pub async fn select_by_primary_key(pool: &Pool<MySql>, {{ pk_rs_name }}: {{{ pk_rs_type }}}) -> Result<Option<MySqlRow>> {
        #[rustfmt::skip]
        let statment: &str = *SELECT_STATMENT;

        let mut query_builder: sqlx::QueryBuilder<sqlx::MySql> = sqlx::QueryBuilder::new(statment);

        query_builder.push(" where {{ pk_db_name }} = ");
        query_builder.push_bind({{ pk_rs_name }});

        let row = query_builder
                .build()
                .fetch_optional(pool)
                .await
                .context("select_by_primary_key: Failed to perform a query to retrieve a otpcode.")?;

        Ok(row)
    }

    pub async fn insert(pool: &Pool<MySql>, record: &{{ struct_name }}) -> Result<u64> {
        let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(
            "INSERT INTO {{ table_name }} ({{#each fields}}{{this.db_field_name}}{{#if (not @last) }}, {{/if}}{{/each}}) ",
        );

        query_builder.push_values([record].iter(), |mut b, record| {
        {{#each fields}}
            b.push_bind(record.{{this.name}}.to_owned());
        {{/each}}
        });

        let mut transaction = pool.begin().await.map_err(|e| {
            log::error!("insert-failed: error={:?}", e);
            anyhow::anyhow!(e)
        })?;

        let last_insert_id = query_builder
            .build()
            // .execute(pool)
            .execute(&mut *transaction)
            .await
            .map_err(|e| anyhow::anyhow!(e))?
            .last_insert_id();

        // if commit or rollback have not been called before the Transaction object goes out of scope (i.e. Drop is invoked),
        // a rollback command is queued to be executed as soon as an opportunity arises.
        transaction.commit().await.map_err(|e| {
            log::error!("insert-failed: error={:?}", e);
            anyhow::anyhow!(e)
        })?;

        Ok(last_insert_id)
    }

    pub async fn insert_bulk(pool: &Pool<MySql>, data: Vec<{{ struct_name }}>) -> Result<u64> {
        let mut insert_result_int = 0;

        for chunk in data.chunks(5000) {
            let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(
                "INSERT INTO {{ table_name }} ({{#each fields}}{{this.db_field_name}}{{#if (not @last) }}, {{/if}}{{/each}}) ",
            );

            query_builder.push_values(chunk.iter().take(5000 / {{field_count}}), |mut b, record| {
                {{#each fields}}
                b.push_bind(record.{{this.name}}.to_owned());
                {{/each}}
            });

            insert_result_int += query_builder
                .build()
                .execute(pool)
                .await
                .map_err(|e| anyhow::anyhow!(e))?
                .rows_affected();
        }

        Ok(insert_result_int)
    }

    pub async fn update_by_primary_key(
        pool: &Pool<MySql>,
        {{ pk_rs_name }}: {{{ pk_rs_type }}},
        data: &{{ struct_name }},
    ) -> Result<bool> {
        let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new("update {{ table_name }} ");
        {{#each fields}}

        query_builder.push("{{#if @first }}set {{else if (not @first)}}, {{/if}}{{this.db_field_name}} = ");

            {{#if this.nullable}}
        if let Some(_{{this.name}}) = &data.{{this.name}} {
            {{#if (eq this.rust_type "String")}}
            if _{{this.name}}.trim() != "" {
                query_builder.push_bind(_{{this.name}}.trim());
            } else {
                query_builder.push_bind(None::<{{this.rust_type}}>);
            }
            {{else}}
            query_builder.push_bind(_{{this.name}});
            {{/if}}
        } else {
            query_builder.push_bind(None::<{{this.rust_type}}>);
        }
            {{else}}
        if data.{{this.name}}{{#if (eq this.rust_type "String")}}.trim(){{/if}} != "" {
            {{#if (eq this.rust_type "String")}}
            query_builder.push_bind(data.{{this.name}}.trim());
            {{else}}
            query_builder.push_bind(data.{{this.name}});
            {{/if}}
        } else {
            query_builder.push_bind(None::<{{this.rust_type}}>);
        }
            {{/if}}
        {{/each}}

        query_builder.push(" where {{ pk_db_name }} = ");
        query_builder.push_bind({{ pk_rs_name }});

        let update_result_int = query_builder
            .build()
            .execute(pool)
            .await
            .map_err(|e| anyhow::anyhow!(e))?
            .rows_affected();

        Ok(update_result_int > 0)
    }

    pub async fn update_by_primary_key_selective(
            pool: &Pool<MySql>,
            {{ pk_rs_name }}: {{{ pk_rs_type }}},
            data: &{{ struct_name }},
        ) -> Result<bool> {
        let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new("update {{ table_name }}");
        {{#each fields}}

        query_builder.push("{{#if @first }}set {{else if (not @first)}}, {{/if}}{{this.db_field_name}} = ");

            {{#if this.nullable}}
        if let Some(_{{this.name}}) = &data.{{this.name}} {
            {{#if (eq this.rust_type "String")}}
            if _{{this.name}}.trim() != "" {
                query_builder.push_bind(_{{this.name}}.trim());
            } else {
                query_builder.push_bind(None::<{{this.rust_type}}>);
            }
            {{else}}
            query_builder.push_bind(_{{this.name}});
            {{/if}}
        } else {
            query_builder.push_bind(None::<{{this.rust_type}}>);
        }
            {{else}}
        if data.{{this.name}}{{#if (eq this.rust_type "String")}}.trim(){{/if}} != "" {
            {{#if (eq this.rust_type "String")}}
            query_builder.push_bind(data.{{this.name}}.trim());
            {{else}}
            query_builder.push_bind(data.{{this.name}});
            {{/if}}
        } else {
            query_builder.push_bind(None::<{{this.rust_type}}>);
        }
            {{/if}}
        {{/each}}

        query_builder.push(" where {{ pk_db_name }} = ");
        query_builder.push_bind({{ pk_rs_name }});

        let update_result_int = query_builder
            .build()
            .execute(pool)
            .await
            .map_err(|e| anyhow::anyhow!(e))?
            .rows_affected();

        Ok(update_result_int > 0)
    }

    pub fn from_row(row: sqlx::mysql::MySqlRow) -> Result<{{ struct_name }}> {
        Ok({{ struct_name }} {
        {{#each fields}}
            {{this.name}}: row.get({{@index}}),
        {{/each}}
        })
    }
}
"#;
}