Rust
The rust agdb API client is async only and can be used with any HTTP client that would implement the agdb_api::HttpClient
trait. The default implementation uses reqwest (opens in a new tab). The following is the quickstart guide for the agdb client in Rust (connecting to the server). It assumes an agdb_server
is running locally. Please refer to the server guide to learn how to run the server.
Looking for... how to run a server? | another language? | embedded db guide?
Usage
Install Rust
Please install the Rust toolchain from the official source (opens in a new tab).
Create an applicaiton
First we initialize an application called agdb_client
with cargo:
cargo init agdb_client
Add dependencies
cargo add agdb --features serde,openapi
cargo add agdb_api --features reqwest
cargo add tokio --features full
cargo add anyhow
Create the client
The client should point to a running agdb_server
:
use agdb_api::AgdbApi;
use agdb_api::ReqwestClient;
#[tokio:main]
async fn main() -> anyhow::Result<()> {
let mut client = AgdbApi::new(ReqwestClient::new(), "localhost:3000");
Ok(())
}
Create a database user
First we need to login as default admin user and create our database user and then login as them:
client.user_login("admin", "admin").await?; // The authentication login is stored in
// the client for subsequent API calls.
// Default admin credentials are "admin/admin".
client.admin_user_add("my_user", "password123").await?;
client.user_login("my_user", "password123").await?; // Login as our newly created user.
Create a database
use agdb_api::DbType;
client.db_add("my_user", "my_db", DbType::Mapped).await?; // Memory mapped database called "my_db"
// will be created under our "my_user".
Run our first queries
To run queries against the database we call exec
. In this case we will insert node "users" and 3 user nodes and connect them together.
Note that we can feed the result of a previous query directly to the next
one referencing it with an index into the (previous) results starting with
semicolon followed by the index, e.g. :0
, :1
.
// We derive from agdb::UserValue
// so we can use the type in the db.
#[derive(Debug, UserValue)]
struct User {
db_id: Option<DbId>, // The db_id member is optional but
// it allows querying your user type
// from the database.
username: String
age: u64,
}
let users = vec![User { db_id: None, username: "Alice".to_string(), age: 40 },
User { db_id: None, username: "Bob".to_string(), age: 30 },
User { db_id: None, username: "John".to_string(), age: 20 }];
// We can pass users directly as
// query paramter thanks to the
// implementation of the agdb::DbUserValue
// trait via #[derive(UserValue)].
let queries: Vec<QueryType> = vec![QueryBuilder::insert().nodes().aliases("users").query().into(),
QueryBuilder::insert().nodes().values(&users).query().into(),
QueryBuilder::insert().edges().from("users").to(":1").query().into(),
];
client.exec("my_user", "my_db", &queries).await?;
Run more queries
Run another query searching & selecting the users and converting them back to the native local object and printing the result:
let queries = vec![QueryBuilder::select()
.values(User::db_keys()) // Select only relevant properties for the User struct.
.ids(
QueryBuilder::search()
.from("users") // Start the search from the "users" node.
.where_()
.key("age") // Examine "age" property.
.value(LessThan(40.into())) // Include it in the search result if the value
// is less than 40.
.query(),
)
.query()];
// Runs the query against the db, grabs the first result and converts it to the collection of users.
let users: Vec<User> = client.exec("my_user", "my_db", &queries).await?[0].try_into()?;
println!("{:?}", users);
Run the program
cargo run
Full program
https://github.com/agnesoft/agdb/tree/main/examples/server_client_rust (opens in a new tab)