query()
Runs one or more SurrealQL statements against the database.
Method Syntaxdb.query(query)
Argument | Type | Description | |||
---|---|---|---|---|---|
query | query | Specifies the SurrealQL statements. |
The .query()
method serves as a default way to pass queries into the Rust SDK. The simplest usage of this method is by passing in a &str
and returning a Response
.
use surrealdb::engine::any::connect; use surrealdb::opt::auth::Root; async fn main() -> surrealdb::Result<()> { let db = connect("ws://localhost:8000").await?; db.signin(Root { username: "root", password: "root", }) .await?; db.use_ns("ns").use_db("db").await?; let query = r#" LET $data = ["J. Jonah Jameson", "James Earl Jones"]; RETURN $data.map(|$name| { LET $names = $name.split(' '); { first_name: $names[0], middle_name: $names[1], last_name: $names[2] } }); "#; let result = db.query(query).await?; println!("Number of statements: {}", result.num_statements()); dbg!(result); Ok(()) }
The .take()
method can be used to pull out one of the responses into a deserialized format. Note that in the next example the LET
statement is the first statement received by the database, and thus .take(1)
is used to grab the output of the second statement to deserialize into a Person
struct.
use serde::Deserialize; use surrealdb::engine::any::connect; use surrealdb::opt::auth::Root; struct Person { first_name: String, middle_name: String, last_name: String, } async fn main() -> surrealdb::Result<()> { let db = connect("ws://localhost:8000").await?; db.signin(Root { username: "root", password: "root", }) .await?; db.use_ns("ns").use_db("db").await?; let query = r#" LET $data = ["J. Jonah Jameson", "James Earl Jones"]; RETURN $data.map(|$name| { LET $names = $name.split(' '); { first_name: $names[0], middle_name: $names[1], last_name: $names[2] } });"#; let mut result = db.query(query).await?; let people: Vec<Person> = result.take(1)?; dbg!(people); Ok(()) }
As the .query()
method can be used to pass any SurrealQL query on to the database, it is an easy go-to when using complex queries. However, be sure to keep the following best practices in mind when doing so.
When using SurrealDB as a traditional backend database, your application will usually build SurrealQL queries that may need to contain some untrusted input, such as that provided by the users of your application. To do so, SurrealDB offers bind as a method to query, which should always be used when including untrusted input into queries. Otherwise, SurrealDB will be unable to separate the actual query syntax from the user input, resulting in the well-known SQL injection vulnerabilities. This practice is known as prepared statements or parameterised queries.
Thus, instead of using user input to directly construct a string:
let bad_sql = format!(" CREATE {user_input}; SELECT * FROM {user_input};");
You can insert a parameter using SurrealQL’s $
parameter syntax,
let sql = " CREATE person; SELECT * FROM type::table($table); ";
And then apply the .bind()
method to pass the parameter in.
use serde::Deserialize; use surrealdb::engine::any::connect; use surrealdb::opt::auth::Root; use surrealdb::RecordId; struct Person { id: RecordId, } async fn main() -> surrealdb::Result<()> { let db = connect("ws://localhost:8000").await?; db.signin(Root { username: "root", password: "root", }) .await?; db.use_ns("ns").use_db("db").await?; let sql = " CREATE person; SELECT * FROM type::table($table); "; let mut result = db.query(sql).bind(("table", "person")).await?; // Get the first result from the first query let created: Option<Person> = result.take(0)?; dbg!(created); // Get all of the results from the second query let people: Vec<Person> = result.take(1)?; dbg!(people); Ok(()) }