Expand description

This library provides several traits in order to make database access a lot easier. In addition when using naphtha, it is possible to change the database that is used for specific models in your application without the requirement of changing any code.

It implements the most common operations on a database like insert, update and remove for you, while also providing the ability to send custom queries to the database. In addition to that, when using the barrel-XXX features, you can write your SQL migrations and use them in your application during runtime. See the examples below.

Features overview

  • Most common function implementations insert, update, remove for your models.
  • Custom transactions provided by the custom function
  • DatabaseUpdateHandler enables you to change the models values before and after the update transaction to the database.
  • Change database on specific model in your application without the need to change your code.
  • Possibility to query a model from the database by using one of its member.
  • Integrated [barrel] for writing your SQL migrations and the possibility to apply them during runtime.
  • Thread safe handling of the database connection.

Supported databases

  • SQlite3 (using diesel under the hood).
  • MySQL (using diesel under the hood).
  • PostgreSQL (using diesel under the hood).

Examples

In this chapter, minimal usages are shown. Please have a look at the examples in the repository for more and detailed use.

Connecting to a database

use naphtha::{DatabaseConnection, DatabaseConnect};
// This is the only line required to be changed to switch database types.
type DbBackend = diesel::SqliteConnection;
let db: DatabaseConnection<DbBackend> = DatabaseConnection::connect(":memory:").unwrap();
// do some database work

Defining a model and use database connection

To create a model and its database integration, the following code is required.

Note that this is an excerpt, see the examples folder in the repository for a full working example.

#[model(table_name = "persons")]
pub struct Person {
    id: i32,
    pub description: Option<String>,
    pub updated_at: NaiveDateTime,
}

pub mod schema {
    table! {
        persons (id) {
            id -> Int4,
            description -> Nullable<Varchar>,
            updated_at -> Timestamp,
        }
    }
}

impl DatabaseModel for Person {
    type PrimaryKey = i32;
    fn primary_key(&self) -> Self::PrimaryKey {
        self.id
    }

    fn set_primary_key(&mut self, value: &Self::PrimaryKey) {
        self.id = *value;
    }

    fn default_primary_key() -> Self::PrimaryKey {
        0
    }

    fn table_name() -> &'static str {
        "persons"
    }
}

// Define your custom changes to the model before and after the transactions.
impl<T> naphtha::DatabaseUpdateHandler<T> for Person {}
impl<T> naphtha::DatabaseRemoveHandler<T> for Person {}
impl<T> naphtha::DatabaseInsertHandler<T> for Person {}

// This implements your database migration functions.
impl DatabaseSqlMigration for Person {
    fn migration_up(migration: &mut Migration) {
        use naphtha::DatabaseModel;
        migration.create_table_if_not_exists(Self::table_name(), |t| {
            t.add_column("id", types::primary());
            t.add_column("description", types::text().nullable(true));
            t.add_column("updated_at", types::custom("timestamp"));
        });
    }

    fn migration_down(migration: &mut Migration) {
        use naphtha::DatabaseModel;
        migration.drop_table_if_exists(Self::table_name());
    }
}

fn main() {
    use naphtha::{DatabaseConnection, DatabaseConnect};
    let db = DatabaseConnection::connect(":memory:").unwrap();
    // p is to be mutable because the insert function updates the id member
    // to the one given by the database.
    let mut p = Person {
        id: Person::default_primary_key(),
        description: Some("The new person is registered".into()),
    };
    p.insert(&db);
    // id member is set to the correct number given by the database.

    // do a custom query to the database
    db.custom::<diesel::result::QueryResult::<Person>, _>(|c: &DbBackend| {
        use schema::{persons, persons::dsl::*};
        persons.filter(id.eq(1)).first(c)
    });

    p.remove(&db);
    // p not available anymore in the database
}

Re-exports

pub extern crate log;
pub use diesel;

Structs

Thin wrapper around a Connection.

Traits

Contains functions database connection handling.

Methods that are called before and after the transaction executed when the insert method is called. Can be used to do custom changes to the database or the model instance. Useful for extending the basic CRUD model.

Defines the relation of the model to the database.

Defines functions to modify the stored model instance on the database.

Methods that are called before and after the transaction executed when the remove method is called. Can be used to do custom changes to the database or the model instance. Useful for extending the basic CRUD model.

Methods that are called before and after the transaction executed when the update method is called. Can be used to do custom changes to the database or the model instance. Useful for extending the basic CRUD model.

Attribute Macros

Defines your struct as a model and implements the required traits for interacting with the database. Currently only named struct member are supported.