Embedding in Rust
SurrealDB is designed to be run in many different ways, and environments. Due to the separation of the storage and API layers, SurrealDB can be run in embedded mode, from within a number of different language environments. In Rust, SurrealDB can be run as an in-memory database, it can persist data using a file-based storage engine, or on a distributed cluster.
To contribute to this documentation, edit this file on GitHub.
To contribute to the SDK code, submit an Issue or Pull Request here.
Install the SDK
First, create a new project using cargo new
and add the SurrealDB crate to your dependencies:
cargo add surrealdb
You will then need to enable the appropriate features (for a full list see https://crates.io/crates/surrealdb):
# For an in memory database
cargo add surrealdb --features kv-mem
# For a RocksDB file
cargo add surrealdb --features kv-rocksdb
# For a SpeeDB file
cargo add surrealdb --features kv-speedb
# For FoundationDB cluster (FoundationDB must be installed and the appropriate version selected)
cargo add surrealdb --features kv-fdb-7_1
# For a TiKV cluster (TiKV and other dependancies must be installed)
cargo add surrealdb --features kv-tikv
You will need to add the following additional dependencies:
cargo add serde --features derive
cargo add tokio --features macros,rt-multi-thread
Connect to SurrealDB
Open src/main.rs
and replace everything in there with the following code to try out some basic
operations using the SurrealDB SDK with an embedded database. Look at
integrations to connect to a database.
use serde::{Deserialize, Serialize};
use surrealdb::engine::local::Mem;
use surrealdb::sql::Thing;
use surrealdb::Surreal;
#[derive(Debug, Serialize)]
struct Name<'a> {
first: &'a str,
last: &'a str,
}
#[derive(Debug, Serialize)]
struct Person<'a> {
title: &'a str,
name: Name<'a>,
marketing: bool,
}
#[derive(Debug, Serialize)]
struct Responsibility {
marketing: bool,
}
#[derive(Debug, Deserialize)]
struct Record {
#[allow(dead_code)]
id: Thing,
}
#[tokio::main]
async fn main() -> surrealdb::Result<()> {
// Create database connection
let db = Surreal::new::<Mem>(()).await?;
// Select a specific namespace / database
db.use_ns("test").use_db("test").await?;
// Create a new person with a random id
let created: Vec<Record> = db
.create("person")
.content(Person {
title: "Founder & CEO",
name: Name {
first: "Tobie",
last: "Morgan Hitchcock",
},
marketing: true,
})
.await?;
dbg!(created);
// Update a person record with a specific id
let updated: Option<Record> = db
.update(("person", "jaime"))
.merge(Responsibility { marketing: true })
.await?;
dbg!(updated);
// Select all people records
let people: Vec<Record> = db.select("person").await?;
dbg!(people);
// Perform a custom advanced query
let groups = db
.query("SELECT marketing, count() FROM type::table($table) GROUP BY marketing")
.bind(("table", "person"))
.await?;
dbg!(groups);
Ok(())
}
Run your program from the command line with:
cargo run
SDK methods
The Rust SDK comes with a number of built-in functions.
Function | Description |
---|---|
Surreal::init()
|
Initialises a static database engine |
db.connect(endpoint)
|
Connects to a specific database endpoint, saving the connection on the static client |
Surreal::new::<T>(endpoint)
|
Connects to a local or remote database endpoint |
db.use_ns(namespace).use_db(database)
|
Switch to a specific namespace and database |
db.set(key, val)
|
Assigns a value as a parameter for this connection |
db.query(sql)
|
Runs a set of SurrealQL statements against the database |
db.select(resource)
|
Selects all records in a table, or a specific record |
db.create(resource).content(data)
|
Creates a record in the database |
db.update(resource).content(data)
|
Updates all records in a table, or a specific record |
db.update(resource).merge(data)
|
Modifies all records in a table, or a specific record |
db.update(resource).patch(data)
|
Applies JSON Patch changes to all records in a table, or a specific record |
db.delete(resource)
|
Deletes all records, or a specific record |
Surreal::init()
The DB
static singleton ensures that a single database instance is available across very large
or complicated applications. With the singleton, only one connection to the database is instantiated, and
the database connection does not have to be shared across components or controllers.
static DB: Lazy<Surreal<Db>> = Lazy::new(Surreal::init);
#[tokio::main]
async fn main() -> surrealdb::Result<()> {
// Connect to the database
DB.connect::<File>("/path/to/database.db").await?;
// Select a namespace + database
DB.use_ns("test").use_db("test").await?;
// Create or update a specific record
let tobie: Option<Record> = DB
.update(("person", "tobie"))
.content(Person { name: "Tobie" })
.await?;
Ok(())
}
db.connect(endpoint)
Connects to a local or remote database endpoint.
Arguments | Description |
---|---|
endpoint
|
The database endpoint to connect to. |
// Create an in memory database
DB.connect::<Mem>(()).await?;
// Connect to a RocksDB file
DB.connect::<RocksDb>("/path/to/database.db").await?;
// Connect to a SpeeDB file (note: RocksDB and SpeeDB can't be used together)
DB.connect::<SpeeDb>("/path/to/database.db").await?;
// Connect to a FoundationDB file (note: make sure you have FoundationDB installed)
DB.connect::<FDb>("/path/to/fdb.cluster").await?;
// Connect to a TiKv cluster
DB.connect::<TiKv>("127.0.0.1:2379").await?;
// Connect to an IndxDB database
DB.connect::<IndxDb>("MyDatabase").await?;
Surreal::new::<T>(endpoint)
Connects to a local or remote database endpoint.
Arguments | Description |
---|---|
endpoint
|
The database endpoint to connect to. |
// In memory database
let db = Surreal::new::<Mem>(()).await?;
// RocksDB backed database
let db = Surreal::new::<RocksDb>("/path/to/database").await?;
db.use_ns(ns).use_db(db)
Switch to a specific namespace and database.
Arguments | Description |
---|---|
ns
|
Switches to a specific namespace. |
db
|
Switches to a specific database. |
db.use_ns("test").use_db("test").await?;
db.set(key, val)
Assigns a value as a parameter for this connection.
Arguments | Description |
---|---|
key
|
Specifies the name of the variable. |
val
|
Assigns the value to the variable name. |
// Assign the variable on the connection
db.set("name", Name {
first: "Tobie",
last: "Morgan Hitchcock",
}).await?;
// Use the variable in a subsequent query
db.query("CREATE person SET name = $name").await?.check()?;
// Use the variable in a subsequent query
db.query("SELECT * FROM person WHERE name.first = $name.first").await?.check()?;
db.query(sql).bind(vars)
Runs a set of SurrealQL statements against the database.
Arguments | Description |
---|---|
sql
|
Specifies the SurrealQL statements. |
vars
|
Assigns variables which can be used in the query. |
// Assign the variable on the connection
let mut result = db
.query("CREATE person; SELECT * FROM type::table($table);")
.bind(("table", "person"))
.await?;
// Get the first result from the first query statement
let created: Option<Person> = result.take(0)?;
// Get all of the results from the second query statement
let people: Vec<Person> = result.take(1)?;
db.select(resource)
Selects all records in a table, or a specific record, from the database.
Arguments | Description |
---|---|
resource
|
The table name or a record ID to select. |
// Select all records from a table
let people: Vec<Person> = db.select("person").await?;
// Select a specific record from a table
let person: Option<Person> = db.select(("person", "h5wxrf2ewk8xjxosxtyc")).await?;
This function will run the following query in the database:
SELECT * FROM $resource;
db.create(resource).content(data)
Creates a record in the database.
Arguments | Description |
---|---|
resource
|
The table name or the specific record ID to create. |
data
|
The document / record data to insert. |
// Create a record with a random ID
let people: Vec<Person> = db.create("person").await?;
// Create a record with a specific ID
let record: Option<Record> = db
.create(("person", "tobie"))
.content(Person {
name: "Tobie",
settings: {
active: true,
marketing: true,
},
}).await?;
This function will run the following query in the database:
CREATE $resource CONTENT $data;
db.update(resource).content(data)
Updates all records in a table, or a specific record, in the database.
This function replaces the current document / record data with the specified data.
Arguments | Description |
---|---|
resource
|
The table name or the specific record ID to update. |
data
|
The document / record data to insert. |
// Update all records in a table
let people: Vec<Person> = db.update("person").await?;
// Update a record with a specific ID
let person: Option<Person> = db
.update(("person", "tobie"))
.content(Person {
name: "Tobie",
settings: {
active: true,
marketing: true,
},
}).await?;
This function will run the following query in the database:
UPDATE $resource CONTENT $data;
db.update(resource).merge(data)
Modifies all records in a table, or a specific record, in the database.
This function merges the current document / record data with the specified data.
Arguments | Description |
---|---|
resource
|
The table name or the specific record ID to change |
data
|
The document / record data to insert. |
// Update all records in a table
let people: Vec<Person> = db.update("person")
.merge(Document {
updated_at: Datetime::default(),
})
.await?;
// Update a record with a specific ID
let person: Option<Person> = db.update(("person", "tobie"))
.merge(Document {
updated_at: Datetime::default(),
settings: Settings {
active: true,
},
})
.await?;
This function will run the following query in the database:
UPDATE $resource MERGE $data;
db.update(resource).patch(data)
Applies JSON Patch changes to all records, or a specific record, in the database.
This function patches the current document / record data with the specified JSON Patch data.
Arguments | Description |
---|---|
resource
|
The table name or the specific record ID to modify. |
data
|
The JSON Patch data with which to modify the records. |
// Update all records in a table
let people: Vec<Person> = db.update("person")
.patch(PatchOp::replace("/created_at", Datetime::default()))
.await?;
// Update a record with a specific ID
let person: Option<Person> = db.update(("person", "tobie"))
.patch(PatchOp::replace("/settings/active", false))
.patch(PatchOp::add("/tags", &["developer", "engineer"]))
.patch(PatchOp::remove("/temp"))
.await?;
This function will run the following query in the database:
UPDATE $resource PATCH $data;
db.delete(resource)
Deletes all records in a table, or a specific record, from the database.
Arguments | Description |
---|---|
resource
|
The table name or a record ID to select. |
// Delete all records from a table
let people: Vec<Person> = db.delete("person").await?;
// Delete a specific record from a table
let person: Option<Person> = db.delete(("person", "h5wxrf2ewk8xjxosxtyc")).await?;
This function will run the following query in the database:
DELETE FROM $resource RETURN BEFORE;