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.

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

Attention

MongoDB version 4.4

MongoDB Rust Driver version 1.2.5 is used.

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

AdditionalValidation

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.36-beta" metamorphose = "1.0.6-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: 20 // 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: 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: 30 // First character: a-z A-Z pub const SERVICENAME: &str = "accounts"; // Valid characters: _ a-z A-Z 0-9 // Max size: 20 // 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.get().unwrap_or_default();
    let password = self.password.get().unwrap_or_default();
    let confirm_password = self.confirm_password.get().unwrap_or_default();
    let username = self.username.get().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() {
    // Update instance.
    user = output_data.update()?;

    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());

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

    println!("Slug: {}", user.slug.get().unwrap())
} 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() {
    // Update instance.
    user = output_data.update()?;

    user.username.set("new_user_1");
    let output_data = user.save(None, None)?;

    if output_data.is_valid() {
        // Update instance.
        user = output_data.update()?;

        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());

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

        println!("Slug: {}", user.slug.get().unwrap())
    } else {
        // Printing errors to the console ( for development ).
        output_data.print_err();
    }
} 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