pub struct Surreal<C: Connection> { /* private fields */ }
Expand description
A database client instance for embedded or remote databases
Implementations§
Source§impl Surreal<Any>
impl Surreal<Any>
Sourcepub fn connect(&self, address: impl IntoEndpoint) -> Connect<Any, ()>
pub fn connect(&self, address: impl IntoEndpoint) -> Connect<Any, ()>
Connects to a specific database endpoint, saving the connection on the static client
§Examples
use std::sync::LazyLock;
use surrealdb::Surreal;
use surrealdb::engine::any::Any;
static DB: LazyLock<Surreal<Any>> = LazyLock::new(Surreal::init);
DB.connect("ws://localhost:8000").await?;
Source§impl Surreal<Client>
impl Surreal<Client>
Sourcepub fn connect<P>(
&self,
address: impl IntoEndpoint<P, Client = Client>,
) -> Connect<Client, ()>
Available on crate feature protocol-http
only.
pub fn connect<P>( &self, address: impl IntoEndpoint<P, Client = Client>, ) -> Connect<Client, ()>
protocol-http
only.Connects to a specific database endpoint, saving the connection on the static client
§Examples
use std::sync::LazyLock;
use surrealdb::Surreal;
use surrealdb::engine::remote::http::Client;
use surrealdb::engine::remote::http::Http;
static DB: LazyLock<Surreal<Client>> = LazyLock::new(Surreal::init);
DB.connect::<Http>("localhost:8000").await?;
Source§impl Surreal<Client>
impl Surreal<Client>
Sourcepub fn connect<P>(
&self,
address: impl IntoEndpoint<P, Client = Client>,
) -> Connect<Client, ()>
Available on crate feature protocol-ws
only.
pub fn connect<P>( &self, address: impl IntoEndpoint<P, Client = Client>, ) -> Connect<Client, ()>
protocol-ws
only.Connects to a specific database endpoint, saving the connection on the static client
§Examples
use std::sync::LazyLock;
use surrealdb::Surreal;
use surrealdb::engine::remote::ws::Client;
use surrealdb::engine::remote::ws::Ws;
static DB: LazyLock<Surreal<Client>> = LazyLock::new(Surreal::init);
DB.connect::<Ws>("localhost:8000").await?;
Source§impl<C> Surreal<C>where
C: Connection,
impl<C> Surreal<C>where
C: Connection,
Sourcepub fn init() -> Self
pub fn init() -> Self
Initialises a new unconnected instance of the client
This makes it easy to create a static singleton of the client. The static singleton pattern in the example below 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.
§Examples
Using a static, compile-time scheme
use std::sync::LazyLock;
use serde::{Serialize, Deserialize};
use surrealdb::Surreal;
use surrealdb::opt::auth::Root;
use surrealdb::engine::remote::ws::Ws;
use surrealdb::engine::remote::ws::Client;
// Creates a new static instance of the client
static DB: LazyLock<Surreal<Client>> = LazyLock::new(Surreal::init);
#[derive(Serialize, Deserialize)]
struct Person {
name: String,
}
#[tokio::main]
async fn main() -> surrealdb::Result<()> {
// Connect to the database
DB.connect::<Ws>("localhost:8000").await?;
// Log into the database
DB.signin(Root {
username: "root",
password: "root",
}).await?;
// Select a namespace/database
DB.use_ns("namespace").use_db("database").await?;
// Create or update a specific record
let tobie: Option<Person> = DB.update(("person", "tobie"))
.content(Person {
name: "Tobie".into(),
}).await?;
Ok(())
}
Using a dynamic, run-time scheme
use std::sync::LazyLock;
use serde::{Serialize, Deserialize};
use surrealdb::Surreal;
use surrealdb::engine::any::Any;
use surrealdb::opt::auth::Root;
// Creates a new static instance of the client
static DB: LazyLock<Surreal<Any>> = LazyLock::new(Surreal::init);
#[derive(Serialize, Deserialize)]
struct Person {
name: String,
}
#[tokio::main]
async fn main() -> surrealdb::Result<()> {
// Connect to the database
DB.connect("ws://localhost:8000").await?;
// Log into the database
DB.signin(Root {
username: "root",
password: "root",
}).await?;
// Select a namespace/database
DB.use_ns("namespace").use_db("database").await?;
// Create or update a specific record
let tobie: Option<Person> = DB.update(("person", "tobie"))
.content(Person {
name: "Tobie".into(),
}).await?;
Ok(())
}
Sourcepub fn new<P>(address: impl IntoEndpoint<P, Client = C>) -> Connect<C, Self>
pub fn new<P>(address: impl IntoEndpoint<P, Client = C>) -> Connect<C, Self>
Connects to a local or remote database endpoint
§Examples
use surrealdb::Surreal;
use surrealdb::engine::remote::ws::{Ws, Wss};
// Connect to a local endpoint
let db = Surreal::new::<Ws>("localhost:8000").await?;
// Connect to a remote endpoint
let db = Surreal::new::<Wss>("cloud.surrealdb.com").await?;
Sourcepub fn set(
&self,
key: impl Into<String>,
value: impl Serialize + 'static,
) -> Set<'_, C>
pub fn set( &self, key: impl Into<String>, value: impl Serialize + 'static, ) -> Set<'_, C>
Assigns a value as a parameter for this connection
§Examples
use serde::Serialize;
#[derive(Serialize)]
struct Name {
first: String,
last: String,
}
// Assign the variable on the connection
db.set("name", Name {
first: "Tobie".into(),
last: "Morgan Hitchcock".into(),
}).await?;
// Use the variable in a subsequent query
db.query("CREATE person SET name = $name").await?;
// Use the variable in a subsequent query
db.query("SELECT * FROM person WHERE name.first = $name.first").await?;
Sourcepub fn unset(&self, key: impl Into<String>) -> Unset<'_, C>
pub fn unset(&self, key: impl Into<String>) -> Unset<'_, C>
Removes a parameter from this connection
§Examples
use serde::Serialize;
#[derive(Serialize)]
struct Name {
first: String,
last: String,
}
// Assign the variable on the connection
db.set("name", Name {
first: "Tobie".into(),
last: "Morgan Hitchcock".into(),
}).await?;
// Use the variable in a subsequent query
db.query("CREATE person SET name = $name").await?;
// Remove the variable from the connection
db.unset("name").await?;
Sourcepub fn signup<R>(
&self,
credentials: impl Credentials<Signup, R>,
) -> Signup<'_, C, R>
pub fn signup<R>( &self, credentials: impl Credentials<Signup, R>, ) -> Signup<'_, C, R>
Signs up a user with a specific record access method
§Examples
use serde::Serialize;
use surrealdb::opt::auth::Root;
use surrealdb::opt::auth::Record;
#[derive(Debug, Serialize)]
struct AuthParams {
email: String,
password: String,
}
// Sign in as root
db.signin(Root {
username: "root",
password: "root",
})
.await?;
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// Define the user record access
let surql = r#"
DEFINE ACCESS user_access ON DATABASE TYPE RECORD DURATION 24h
SIGNUP ( CREATE user SET email = $email, password = crypto::argon2::generate($password) )
SIGNIN ( SELECT * FROM user WHERE email = $email AND crypto::argon2::compare(password, $password) )
"#;
db.query(surql).await?.check()?;
// Sign a user up
db.signup(Record {
namespace: "namespace",
database: "database",
access: "user_access",
params: AuthParams {
email: "john.doe@example.com".into(),
password: "password123".into(),
},
}).await?;
Sourcepub fn signin<R>(
&self,
credentials: impl Credentials<Signin, R>,
) -> Signin<'_, C, R>
pub fn signin<R>( &self, credentials: impl Credentials<Signin, R>, ) -> Signin<'_, C, R>
Signs this connection in to a specific authentication level
§Examples
Namespace signin
use surrealdb::opt::auth::Root;
use surrealdb::opt::auth::Namespace;
// Sign in as root
db.signin(Root {
username: "root",
password: "root",
})
.await?;
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// Define the user
let surql = "DEFINE USER johndoe ON NAMESPACE PASSWORD 'password123'";
db.query(surql).await?.check()?;
// Sign a user in
db.signin(Namespace {
namespace: "namespace",
username: "johndoe",
password: "password123",
}).await?;
Database signin
use surrealdb::opt::auth::Root;
use surrealdb::opt::auth::Database;
// Sign in as root
db.signin(Root {
username: "root",
password: "root",
})
.await?;
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// Define the user
let surql = "DEFINE USER johndoe ON DATABASE PASSWORD 'password123'";
db.query(surql).await?.check()?;
// Sign a user in
db.signin(Database {
namespace: "namespace",
database: "database",
username: "johndoe",
password: "password123",
}).await?;
Record signin
use serde::Serialize;
use surrealdb::opt::auth::Root;
use surrealdb::opt::auth::Record;
#[derive(Debug, Serialize)]
struct AuthParams {
email: String,
password: String,
}
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// Sign a user in
db.signin(Record {
namespace: "namespace",
database: "database",
access: "user_access",
params: AuthParams {
email: "john.doe@example.com".into(),
password: "password123".into(),
},
}).await?;
Sourcepub fn invalidate(&self) -> Invalidate<'_, C>
pub fn invalidate(&self) -> Invalidate<'_, C>
Sourcepub fn authenticate(&self, token: impl Into<Jwt>) -> Authenticate<'_, C>
pub fn authenticate(&self, token: impl Into<Jwt>) -> Authenticate<'_, C>
Sourcepub fn query(&self, query: impl IntoQuery) -> Query<'_, C>
pub fn query(&self, query: impl IntoQuery) -> Query<'_, C>
Runs a set of SurrealQL statements against the database
§Examples
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// Run queries
let mut result = db
.query("CREATE person")
.query("SELECT * FROM type::table($table)")
.bind(("table", "person"))
.await?;
// Get the first result from the first query
let created: Option<Person> = result.take(0)?;
// Get all of the results from the second query
let people: Vec<Person> = result.take(1)?;
#[derive(serde::Deserialize)]
struct Country {
name: String
}
// The .take() method can be used for error handling
// If the table has no defined schema, this query will
// create a `country` on the SurrealDB side, but...
let mut result = db
.query("CREATE country")
.await?;
// It won't deserialize into a Country struct
if let Err(e) = result.take::<Option<Country>>(0) {
println!("Failed to make a country: {e:#?}");
assert!(e.to_string().contains("missing field `name`"));
}
Sourcepub fn select<O>(&self, resource: impl IntoResource<O>) -> Select<'_, C, O>
pub fn select<O>(&self, resource: impl IntoResource<O>) -> Select<'_, C, O>
Selects all records in a table, or a specific record
§Examples
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// Select all records from a table
let people: Vec<Person> = db.select("person").await?;
// Select a range of records from a table
let people: Vec<Person> = db.select("person").range("jane".."john").await?;
// Select a specific record from a table
let person: Option<Person> = db.select(("person", "h5wxrf2ewk8xjxosxtyc")).await?;
// To listen for updates as they happen on a record, a range of records
// or entire table use a live query. This is done by simply calling `.live()`
// after this method. That gives you a stream of notifications you can listen on.
let mut stream = db.select(resource).live().await?;
while let Some(notification) = stream.next().await {
// Use the notification
}
Sourcepub fn create<R>(&self, resource: impl CreateResource<R>) -> Create<'_, C, R>
pub fn create<R>(&self, resource: impl CreateResource<R>) -> Create<'_, C, R>
Creates a record in the database
§Examples
use serde::Serialize;
#[derive(Serialize)]
struct Settings {
active: bool,
marketing: bool,
}
#[derive(Serialize)]
struct User {
name: &'static str,
settings: Settings,
}
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// Create a record with a random ID
let person: Option<Person> = db.create("person").await?;
// Create a record with a specific ID
let record: Option<Person> = db.create(("person", "tobie"))
.content(User {
name: "Tobie",
settings: Settings {
active: true,
marketing: true,
},
})
.await?;
Sourcepub fn insert<O>(&self, resource: impl IntoResource<O>) -> Insert<'_, C, O>
pub fn insert<O>(&self, resource: impl IntoResource<O>) -> Insert<'_, C, O>
Insert a record or records into a table
§Examples
use serde::{Serialize, Deserialize};
use surrealdb::RecordId;
#[derive(Serialize)]
struct Settings {
active: bool,
marketing: bool,
}
#[derive(Serialize)]
struct User<'a> {
name: &'a str,
settings: Settings,
}
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// Insert a record with a specific ID
let person: Option<Person> = db.insert(("person", "tobie"))
.content(User {
name: "Tobie",
settings: Settings {
active: true,
marketing: true,
},
})
.await?;
// Insert multiple records into the table
let people: Vec<Person> = db.insert("person")
.content(vec![
User {
name: "Tobie",
settings: Settings {
active: true,
marketing: false,
},
},
User {
name: "Jaime",
settings: Settings {
active: true,
marketing: true,
},
},
])
.await?;
// Insert multiple records with pre-defined IDs
#[derive(Serialize)]
struct UserWithId<'a> {
id: RecordId,
name: &'a str,
settings: Settings,
}
let people: Vec<Person> = db.insert("person")
.content(vec![
UserWithId {
id: ("person", "tobie").into(),
name: "Tobie",
settings: Settings {
active: true,
marketing: false,
},
},
UserWithId {
id: ("person", "jaime").into(),
name: "Jaime",
settings: Settings {
active: true,
marketing: true,
},
},
])
.await?;
// Insert multiple records into different tables
#[derive(Serialize)]
struct WithId<'a> {
id: RecordId,
name: &'a str,
}
let people: Vec<Person> = db.insert(())
.content(vec![
WithId {
id: ("person", "tobie").into(),
name: "Tobie",
},
WithId {
id: ("company", "surrealdb").into(),
name: "SurrealDB",
},
])
.await?;
// Insert relations
#[derive(Serialize, Deserialize)]
struct Founded {
#[serde(rename = "in")]
founder: RecordId,
#[serde(rename = "out")]
company: RecordId,
}
let founded: Vec<Founded> = db.insert("founded")
.relation(vec![
Founded {
founder: ("person", "tobie").into(),
company: ("company", "surrealdb").into(),
},
Founded {
founder: ("person", "jaime").into(),
company: ("company", "surrealdb").into(),
},
])
.await?;
Sourcepub fn upsert<O>(&self, resource: impl IntoResource<O>) -> Upsert<'_, C, O>
pub fn upsert<O>(&self, resource: impl IntoResource<O>) -> Upsert<'_, C, O>
Updates all records in a table, or a specific record
§Examples
Replace the current document / record data with the specified data.
use serde::Serialize;
#[derive(Serialize)]
struct Settings {
active: bool,
marketing: bool,
}
#[derive(Serialize)]
struct User {
name: &'static str,
settings: Settings,
}
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// Update all records in a table
let people: Vec<Person> = db.upsert("person").await?;
// Update a record with a specific ID
let person: Option<Person> = db.upsert(("person", "tobie"))
.content(User {
name: "Tobie",
settings: Settings {
active: true,
marketing: true,
},
})
.await?;
Merge the current document / record data with the specified data.
use serde::Serialize;
use time::OffsetDateTime;
#[derive(Serialize)]
struct UpdatedAt {
updated_at: OffsetDateTime,
}
#[derive(Serialize)]
struct Settings {
active: bool,
}
#[derive(Serialize)]
struct User {
updated_at: OffsetDateTime,
settings: Settings,
}
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// Update all records in a table
let people: Vec<Person> = db.upsert("person")
.merge(UpdatedAt {
updated_at: OffsetDateTime::now_utc(),
})
.await?;
// Update a record with a specific ID
let person: Option<Person> = db.upsert(("person", "tobie"))
.merge(User {
updated_at: OffsetDateTime::now_utc(),
settings: Settings {
active: true,
},
})
.await?;
Apply JSON Patch changes to all records, or a specific record, in the database.
use serde::Serialize;
use surrealdb::opt::PatchOp;
use time::OffsetDateTime;
#[derive(Serialize)]
struct UpdatedAt {
updated_at: OffsetDateTime,
}
#[derive(Serialize)]
struct Settings {
active: bool,
}
#[derive(Serialize)]
struct User {
updated_at: OffsetDateTime,
settings: Settings,
}
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// Update all records in a table
let people: Vec<Person> = db.upsert("person")
.patch(PatchOp::replace("/created_at", OffsetDateTime::now_utc()))
.await?;
// Update a record with a specific ID
let person: Option<Person> = db.upsert(("person", "tobie"))
.patch(PatchOp::replace("/settings/active", false))
.patch(PatchOp::add("/tags", ["developer", "engineer"]))
.patch(PatchOp::remove("/temp"))
.await?;
Sourcepub fn update<O>(&self, resource: impl IntoResource<O>) -> Update<'_, C, O>
pub fn update<O>(&self, resource: impl IntoResource<O>) -> Update<'_, C, O>
Updates all records in a table, or a specific record
§Examples
Replace the current document / record data with the specified data.
use serde::Serialize;
#[derive(Serialize)]
struct Settings {
active: bool,
marketing: bool,
}
#[derive(Serialize)]
struct User {
name: &'static str,
settings: Settings,
}
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// 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(User {
name: "Tobie",
settings: Settings {
active: true,
marketing: true,
},
})
.await?;
Merge the current document / record data with the specified data.
use serde::Serialize;
use time::OffsetDateTime;
#[derive(Serialize)]
struct UpdatedAt {
updated_at: OffsetDateTime,
}
#[derive(Serialize)]
struct Settings {
active: bool,
}
#[derive(Serialize)]
struct User {
updated_at: OffsetDateTime,
settings: Settings,
}
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// Update all records in a table
let people: Vec<Person> = db.update("person")
.merge(UpdatedAt {
updated_at: OffsetDateTime::now_utc(),
})
.await?;
// Update a record with a specific ID
let person: Option<Person> = db.update(("person", "tobie"))
.merge(User {
updated_at: OffsetDateTime::now_utc(),
settings: Settings {
active: true,
},
})
.await?;
Apply JSON Patch changes to all records, or a specific record, in the database.
use serde::Serialize;
use surrealdb::opt::PatchOp;
use time::OffsetDateTime;
#[derive(Serialize)]
struct UpdatedAt {
updated_at: OffsetDateTime,
}
#[derive(Serialize)]
struct Settings {
active: bool,
}
#[derive(Serialize)]
struct User {
updated_at: OffsetDateTime,
settings: Settings,
}
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// Update all records in a table
let people: Vec<Person> = db.update("person")
.patch(PatchOp::replace("/created_at", OffsetDateTime::now_utc()))
.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?;
Sourcepub fn delete<O>(&self, resource: impl IntoResource<O>) -> Delete<'_, C, O>
pub fn delete<O>(&self, resource: impl IntoResource<O>) -> Delete<'_, C, O>
Deletes all records, or a specific record
§Examples
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// 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?;
Sourcepub fn run<R>(&self, function: impl IntoFn) -> Run<'_, C, R>
pub fn run<R>(&self, function: impl IntoFn) -> Run<'_, C, R>
Runs a function
§Examples
// Specify no args by not calling `.args()`
let foo = db.run("fn::foo").await?; // fn::foo()
// A single value will be turned into one argument
let bar = db.run("fn::bar").args(42).await?; // fn::bar(42)
// Arrays are treated as single arguments
let count = db.run("count").args(vec![1,2,3]).await?;
// Specify multiple args using a tuple
let two = db.run("math::log").args((100, 10)).await?; // math::log(100, 10)
Sourcepub async fn wait_for(&self, event: WaitFor)
pub async fn wait_for(&self, event: WaitFor)
Wait for the selected event to happen before proceeding
Sourcepub fn export<R>(
&self,
target: impl IntoExportDestination<R>,
) -> Export<'_, C, R>
pub fn export<R>( &self, target: impl IntoExportDestination<R>, ) -> Export<'_, C, R>
Dumps the database contents to a file
§Support
Currently only supported by HTTP and the local engines. Not supported on WebAssembly.
§Examples
// Select the namespace/database to use
db.use_ns("namespace").use_db("database").await?;
// Export to a file
db.export("backup.sql").await?;
// Export to a stream of bytes
let mut backup = db.export(()).await?;
while let Some(result) = backup.next().await {
match result {
Ok(bytes) => {
// Do something with the bytes received...
}
Err(error) => {
// Handle the export error
}
}
}