Logo

Green Barrel

ORM-like API MongoDB for Rust

To simulate fields of type ForeignKey and ManyToMany, a simplified alternative (Types of selective fields with dynamic addition of elements) is used. Support for Actix-GreenPanel is temporarily unavailable.

crates.io crates.io crates.io crates.io

Attention

MongoDB version 4.4

MongoDB Rust Driver version 1.2.5 is used.

Support for Actix-GreenPanel is temporarily unavailable.

Requirements

Model parameters

( all parameters are optional )

| Parameter: | Default: | Description: | | :------------------ | :----------- | :--------------------------------------------------------------------------------------------------- | | dbclientname | empty string | Used to connect to a MongoDB cluster. | | dbquerydocslimit | 1000 | limiting query results. | | isadddocs | true | Create documents in the database. false - Alternatively, use it to validate data from web forms. | | isupdocs | true | Update documents in the database. | | isdeldocs | true | Delete documents from the database. | | ignorefields | empty string | Fields that are not included in the database (separated by commas). | | isuseaddvalid | false | Allows additional validation - impl AdditionalValidation for ModelName. | | isuse_hooks | false | Allows hooks methods - impl Hooks for ModelName. |

Field types

See documentation -fields.

Methods for Developers

Main

Caching

Control

Hooks

QCommons

QPaladins

Install mongodb (if not installed)

```shell

Ubuntu, Mint:

$ sudo apt install mongodb

OR

Ubuntu 20.04, Mint 20.x:

$ sudo apt update $ sudo apt install dirmngr gnupg apt-transport-https ca-certificates $ wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add - $ sudo add-apt-repository 'deb [arch=amd64] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse' $ sudo apt update $ sudo apt install mongodb-org $ sudo systemctl enable --now mongod

For check

$ mongod --version $ mongo --eval 'db.runCommand({ connectionStatus: 1 })' $ reboot #

Configuration file:

$ sudo nano /etc/mongod.conf #

Systemd:

$ sudo systemctl status mongod $ sudo systemctl start mongod $ sudo systemctl stop mongod $ sudo systemctl restart mongod $ sudo systemctl enable mongod $ sudo systemctl disable mongod #

Uninstall:

$ sudo systemctl stop mongod $ sudo systemctl disable mongod $ sudo apt --purge remove mongodb* # OR (for mongodb-org) - $ sudo apt --purge remove mongodb-org** $ sudo rm -r /var/log/mongodb $ sudo rm -r /var/lib/mongodb $ sudo rm -f /etc/mongod.conf $ sudo apt-add-repository --remove 'deb [arch=amd64] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse' # for mongodb-org $ sudo apt update ```

Example Usage:

Cargo.toml

```toml [dependencies] green-barrel = "1.0.8-beta" metamorphose = "1.0.2-beta" regex = "1.6.0" serde_json = "1.0.85"

[dependencies.mongodb] default-features = false features = ["sync"] version = "1.2.5"

[dependencies.serde] features = ["derive"] version = "1.0.145" ```

src/settings.rs

```rust // General settings for the project. // Project name. // Hint: PROJECTNAM it is recommended not to change. // Valid characters: _ a-z A-Z 0-9 // Max size: 21 // First character: a-z A-Z pub const PROJECTNAME: &str = "store";

// Unique project key. // Hint: UNIQUEPROJECTKEY it is recommended not to change. // Valid characters: a-z A-Z 0-9 // Size: 8-16 // Example: "7rzgacfqQB3B7q7T" // To generate a key: https://randompasswordgen.com/ pub const UNIQUEPROJECTKEY: &str = "A3iBcq9K19287PN3";

// Settings for user accounts. pub mod users { // Valid characters: _ a-z A-Z 0-9 // Max size: 31 // First character: a-z A-Z pub const SERVICENAME: &str = "accounts"; // Valid characters: _ a-z A-Z 0-9 // Max size: 21 // First character: a-z A-Z pub const DATABASENAME: &str = "accounts"; pub const DBCLIENTNAME: &str = "default"; pub const DBQUERYDOCS_LIMIT: u32 = 1000; } ```

src/migration.rs

```rust use crate::{models, settings}; use greenbarrel::{Caching, Monitor, MONGODBCLIENT_STORE}; use std::error::Error;

// Migration pub fn runmigration() -> Result<(), Box> { // Caching MongoDB clients. { let mut clientstore = MONGODBCLIENTSTORE.write()?; clientstore.insert( "default".tostring(), mongodb::sync::Client::withuristr("mongodb://localhost:27017")?, ); } // Monitor initialization. let monitor = Monitor { projectname: settings::PROJECTNAME, uniqueprojectkey: settings::UNIQUEPROJECTKEY, // Register models. metadata_list: vec![models::User::meta()?], }; // Run migration monitor.migrat()?;

Ok(())

} ```

src/models.rs

```rust use green_barrel::*; use metamorphose::Model; use regex::RegexBuilder; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, error::Error};

use crate::settings::{ users::{DATABASENAME, DBCLIENTNAME, DBQUERYDOCSLIMIT, SERVICENAME}, PROJECTNAME, UNIQUEPROJECTKEY, };

[Model(

is_use_add_valid = true,
is_use_hooks = true,
ignore_fields = "confirm_password" // Example: "field_name, field_name_2"

)]

[derive(Serialize, Deserialize, Default, Debug)]

pub struct User { pub username: InputText, pub slug: AutoSlug, pub firstname: InputText, pub lastname: InputText, pub email: InputEmail, pub phone: InputPhone, pub password: InputPassword, pub confirmpassword: InputPassword, pub isstaff: CheckBox, pub is_active: CheckBox, }

impl Control for User { fn customdefault() -> Self { Self { username: InputText { label: "Username".into(), placeholder: "Enter your username".into(), maxlength: 150, required: true, unique: true, hint: "Valid characters: a-z A-Z 0-9 _ @ + .
Max size: 150".into(), ..Default::default() }, slug: AutoSlug { label: "Slug".into(), unique: true, readonly: true, hint: "To create a human readable url".into(), slug
sources: vec!["hash".into(), "username".into()], ..Default::default() }, firstname: InputText { label: "First name".into(), placeholder: "Enter your First name".into(), maxlength: 150, ..Default::default() }, lastname: InputText { label: "Last name".into(), placeholder: "Enter your Last name".into(), maxlength: 150, ..Default::default() }, email: InputEmail { label: "E-mail".into(), placeholder: "Please enter your email".into(), required: true, unique: true, maxlength: 320, hint: "Your actual E-mail".into(), ..Default::default() }, phone: InputPhone { label: "Phone number".into(), placeholder: "Please enter your phone number".into(), unique: true, maxlength: 30, hint: "Your actual phone number".into(), ..Default::default() }, password: InputPassword { label: "Password".into(), placeholder: "Enter your password".into(), required: true, minlength: 8, hint: "Valid characters: a-z A-Z 0-9 @ # $ % ^ & + = * ! ~ ) (
Min size: 8" .into(), ..Default::default() }, confirmpassword: InputPassword { label: "Confirm password".into(), placeholder: "Repeat your password".into(), required: true, minlength: 8, ..Default::default() }, isstaff: CheckBox { label: "is staff?".into(), checked: Some(true), hint: "User can access the admin site?".into(), ..Default::default() }, is_active: CheckBox { label: "is active?".into(), checked: Some(true), hint: "Is this an active account?".into(), ..Default::default() }, ..Default::default() } } }

impl AdditionalValidation for User { fn addvalidation<'a>(&self) -> Result, Box> { // Hint: errormap.insert("fieldname", "Error message.") let mut errormap = HashMap::<&'a str, &'a str>::new();

    // Get clean data
    let hash = self.hash.value.clone().unwrap_or_default();
    let password = self.password.value.clone().unwrap_or_default();
    let confirm_password = self.confirm_password.value.clone().unwrap_or_default();
    let username = self.username.value.clone().unwrap_or_default();

    // Fields validation
    if hash.is_empty() && password != confirm_password {
        error_map.insert("confirm_password", "Password confirmation does not match.");
    }
    if !RegexBuilder::new(r"^[a-z\d_@+.]+$")
        .case_insensitive(true)
        .build()
        .unwrap()
        .is_match(username.as_str())
    {
        error_map.insert(
            "username",
            "Invalid characters present.<br>\
             Valid characters: a-z A-Z 0-9 _ @ + .",
        );
    }

    Ok(error_map)
}

}

impl Hooks for User { fn precreate(&self) { println!("!!!Pre Create!!!"); } // fn postcreate(&self) { println!("!!!Post Create!!!"); } // fn preupdate(&self) { println!("!!!Pre Update!!!"); } // fn postupdate(&self) { println!("!!!Post Update!!!"); } // fn predelete(&self) { println!("!!!Pre Delet!!!"); } // fn postdelete(&self) { println!("!!!Post Delet!!!"); } } ```

src/main.rs

```rust mod migration; mod models; mod settings;

use green_barrel::*; use std::error::Error;

fn main() -> Result<(), Box> { // Run migration. migration::run_migration()?;

// Create model instance.
// ---------------------------------------------------------------------------------------------
let mut user = models::User::new()?;
user.username.set("user_1");
user.email.set("user_1_@noreply.net");
user.password.set("12345678");
user.confirm_password.value = Some("12345678".to_string()); // Example without the set() method
user.is_staff.set(true);
user.is_active.set(true);

// Check Model.
// ---------------------------------------------------------------------------------------------
println!("\n\nCheck Modell:\n");
let output_data = user.check(None)?;
if output_data.is_valid() {
    println!("Hash: {:?}", user.hash.get());
    println!("Hash: {}", output_data.hash());

    println!("Created at: {:?}", user.created_at.get());
    println!("Updated at: {:?}", user.updated_at.get());
    println!("Created at: {:?}", output_data.created_at());
    println!("Updated at: {:?}", output_data.updated_at());

    println!("Object Id: {:?}", user.hash.obj_id()?);
    println!("Object Id: {:?}", output_data.obj_id()?);
} else {
    // Printing errors to the console ( for development ).
    output_data.print_err();
}

//println!("Json:\n{}", output_data.json()?);
//println!("Json for admin:\n{}", output_data.json_for_admin()?);

// Create document in database.
// ---------------------------------------------------------------------------------------------
println!("\n\nCreate document in database:\n");
let output_data = user.save(None, None)?;
if output_data.is_valid() {
    println!("Hash: {}", user.hash.get().unwrap());
    println!("Hash: {}", output_data.hash());

    println!("Created at: {}", user.created_at.get().unwrap());
    println!("Updated at: {}", user.updated_at.get().unwrap());
    println!("Created at: {}", output_data.created_at().unwrap());
    println!("Updated at: {}", output_data.updated_at().unwrap());

    println!("Object Id: {:?}", user.hash.obj_id()?.unwrap());
    println!("Object Id: {:?}", output_data.obj_id()?.unwrap());

    // If there are AutoSlug fields, do an update.
    user = output_data.update()?;
    println!("Slug: {}", user.slug.get().unwrap())

    //println!("Json:\n{}", output_data.json()?);
    //println!("Json for admin:\n{}", output_data.json_for_admin()?);
} else {
    // Printing errors to the console ( for development ).
    output_data.print_err();
}

// Update document in database.
// ---------------------------------------------------------------------------------------------
println!("\n\nUpdate document in database:\n");
if output_data.is_valid() {
    user.username.set("user_1_update");
    let output_data = user.save(None, None)?;
    println!("Hash: {}", user.hash.get().unwrap());
    println!("Hash: {}", output_data.hash());

    println!("Created at: {}", user.created_at.get().unwrap());
    println!("Updated at: {}", user.updated_at.get().unwrap());
    println!("Created at: {}", output_data.created_at().unwrap());
    println!("Updated at: {}", output_data.updated_at().unwrap());

    println!("Object Id: {:?}", user.hash.obj_id()?.unwrap());
    println!("Object Id: {:?}", output_data.obj_id()?.unwrap());

    // If there are AutoSlug fields, do an update.
    user = output_data.update()?;
    println!("Slug: {}", user.slug.get().unwrap())

    //println!("Json:\n{}", output_data.json()?);
    //println!("Json for admin:\n{}", output_data.json_for_admin()?);
} else {
    // Printing errors to the console ( for development ).
    output_data.print_err();
}

// Delete document in database.
// ---------------------------------------------------------------------------------------------
println!("\n\nDelete document in database:\n");
let output_data = user.delete(None)?;
if !output_data.is_valid() {
    // Printing errors to the console ( for development ).
    output_data.print_err();
}

Ok(())

} ```

Changelog

License

This project is licensed under the MIT and Apache Version 2.0