2 unstable releases

new 0.2.0 Feb 18, 2025
0.1.0 Feb 17, 2025

#8 in #connection-manager

47 downloads per month

MIT/Apache

38KB
82 lines

mobc-surrealdb

License: MIT    License: Apache 2.0    crates.io

mobc-surrealdb is an asynchronous connection pool manager for Surrealdb, that is built on top of the mobc library. Its design emphasizes high performance and flexibility while providing support for multiple connection protocols.

Features

  • Asynchronous Connection Pooling:
    Leverages mobc to manage a pool of connections, reducing the overhead of establishing new connections.

  • Automatic Connection Recycling:
    Validates and reuses connections, ensuring optimal performance even under high load.

  • Customizable Pool Settings:
    Configure parameters such as maximum open connections, idle connections, and connection lifetime to suit your application's needs.

  • Protocol Flexibility:
    Supports multiple connection protocols (HTTP, HTTPS, WS, WSS). By default, the connection protocol is set to WebSocket (ws) for high performance, but you can override it using a custom constructor.

Installation

Add mobc-surrealdb to your project's Cargo.toml:

[dependencies]
mobc-surrealdb = "0.2.0"

Alternatively, you can add it directly using the cargo add command:

cargo add mobc-surrealdb

Dependencies

This crate depends on the following libraries:

  • mobc: A generic connection pool for asynchronous Rust.

  • surrealdb: The official SurrealDB client for Rust.

Examples

Here’s a quick example of how to use mobc-surrealdb in your project:

// Import necessary crates and modules
use mobc::Pool; // The mobc connection pool
use mobc_surrealdb::SurrealDBConnectionManager; // The connection manager
use serde::{Deserialize, Serialize}; // For serializing/deserializing our data types
use std::time::Duration; // For configuring pool settings
use surrealdb::sql::Thing; // SurrealDB's type for record IDs
use tokio; // Tokio runtime for asynchronous execution

// Define a struct to represent a person, with fields for ID, name, and age.
// The ID is optional because it will be assigned by the database upon insertion.
#[derive(Debug, Serialize, Deserialize)]
struct Person {
    id: Option<Thing>, // Optional record ID (assigned by the database)
    name: String,      // Person's name
    age: i64,          // Person's age (64-bit integer)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize the connection manager without specifying a protocol.
    // By default, it will use WebSocket (ws) as the connection protocol.
    let manager = SurrealDBConnectionManager::new(
        "127.0.0.1:8000", // SurrealDB server address
        "root",           // SurrealDB Default Username
        "root",           // SurrealDB Default Password
    );

    // Build the connection pool with custom settings:
    // - Maximum of 20 open connections.
    // - Maximum of 5 idle connections.
    // - Each connection lives for up to 300 seconds.
    // You can keep connections open indefinitely by using ".max_lifetime(None)".
    let pool = Pool::builder()
        .max_open(20)
        .max_idle(5)
        .max_lifetime(Some(Duration::from_secs(300))) 
        .build(manager);

    // Get a connection from the pool asynchronously.
    let conn = pool.get().await?;

    // Set the operational context by specifying the namespace and database.
    // SurrealDB requires a namespace and database context to execute queries.
    conn.use_ns("accounts").use_db("users").await?;

    // Create a new person instance.
    // The ID is None because it will be auto-assigned by the database upon insertion.
    let person = Person {
        id: None,
        name: "Alice".to_string(),
        age: 30,
    };

    // Insert the person into the "user" table.
    let _created: Option<Person> = conn.create("user").content(person).await?;

    // Retrieve all records from the "user" table with a SQL query.
    let mut response = conn.query("SELECT * FROM user").await?;
    let persons: Vec<Person> = response.take(0)?;

    // Iterate over each person and print their details.
    for person in persons {
        println!("******************");
        // Check if the person has an assigned ID.
        if let Some(ref thing) = person.id {
            // If the ID is a string variant, print it.
            if let surrealdb::sql::Id::String(ref id_str) = thing.id {
                println!("id: {}", id_str);
            } else {
                println!("id: Non-string ID");
            }
        } else {
            println!("id: None");
        }
        println!("name: {}", person.name);
        println!("age: {}", person.age);
        println!("******************");
    }

    Ok(())
}


If you would like to explicitly define a connection protocol, you can make use of the new_with_protocol constructor instead of the default new constructor. This approach allows you to specify the connection protocol, offering greater flexibility in how you connect to SurrealDB. Below is an example demonstrating how to utilize this function effectively for your use case:

    // Import both connection manager and protocol enum
    use mobc_surrealdb::{ConnectionProtocol , SurrealDBConnectionManager};

    // Initialize the connection manager using a custom protocol.
    // Here, we choose HTTP as the connection protocol by using the `new_with_protocol` constructor.
    let manager = SurrealDBConnectionManager::new_with_protocol(
        ConnectionProtocol::Http,  // Specify HTTP protocol
        "127.0.0.1:8000",          // SurrealDB server address (host:port)
        "root",                    // Username for authentication
        "root",                    // Password for authentication
    );
Enum Protocol
ConnectionProtocol::Http http://
ConnectionProtocol::Https https://
ConnectionProtocol::Ws ws://
ConnectionProtocol::Wss wss://

In some applications, you may need to interact with SurrealDB using different connection protocols simultaneously for performance, scalability, or specific use cases. Here's an example of how you can easily manage multiple protocols by creating separate connection managers and pools for each:


    // Import both connection manager and protocol enum
    use mobc_surrealdb::{ConnectionProtocol , SurrealDBConnectionManager};

    // WS Connection Manager
    let ws_manager = SurrealDBConnectionManager::new_with_protocol(
        ConnectionProtocol::Ws, // Specify WS protocol
        "127.0.0.1:8000",       // SurrealDB server address (for WS)
        "root",                 // SurrealDB username
        "root",                 // SurrealDB password
    );

    // HTTP Connection Manager
    let http_manager = SurrealDBConnectionManager::new_with_protocol(
        ConnectionProtocol::Http, // Specify HTTP protocol
        "127.0.0.1:8000",         // SurrealDB server address (for HTTP)
        "root",                   // SurrealDB username
        "root",                   // SurrealDB password
    );

    // WebSocket (WS) Connection Pool
    let ws_pool = Pool::builder()
        .max_open(10)
        .max_idle(2)
        .max_lifetime(Some(Duration::from_secs(300)))
        .build(ws_manager);

    // HTTP Connection Pool
    let http_pool = Pool::builder()
        .max_open(10)
        .max_idle(2)
        .max_lifetime(Some(Duration::from_secs(300)))
        .build(http_manager);

Note

If you're using the example above, make sure to include the necessary dependencies in your project. You can add them easily using the following command:

cargo add serde
cargo add surrealdb
cargo add mobc
cargo add mobc-surrealdb

here is the code that you need to create the required connection pool. Feel free to configure it as needed. This code only creates the connection pool without interacting with the database, i.e., 'storing and retrieving' data.

// Import necessary crates and modules
use mobc::Pool; // The mobc connection pool
use mobc_surrealdb::SurrealDBConnectionManager;  // The connection manager
use std::time::Duration; // For configuring pool settings
use tokio; // Tokio runtime for asynchronous execution

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize the connection manager without specifying a protocol.
    // By default, it will use WebSocket (ws) as the connection protocol.
    let manager = SurrealDBConnectionManager::new(
        "127.0.0.1:8000", // SurrealDB server address
        "root",           // SurrealDB Default Username
        "root",           // SurrealDB Default Password
    );

    // Build the connection pool with custom settings:
    // - Maximum of 20 open connections.
    // - Maximum of 5 idle connections.
    // - Each connection lives for up to 300 seconds.
    // You can keep connections open indefinitely by using ".max_lifetime(None)".
    let pool = Pool::builder()
        .max_open(20)
        .max_idle(5)
        .max_lifetime(Some(Duration::from_secs(300)))
        .build(manager);
    Ok(())
}

Dependencies

~79MB
~1.5M SLoC