AerospikeDB: Read Specific Bins of a Record

Hello rust'ers I’m currently learning Rust to uncover its mysteries.

I’m experimenting with the AerospikeDB database. The documentation explains how to retrieve a specific field from the database, but for some reason, it’s not working. Could you explain what I might be doing wrong? Ideally, could you provide an example or a hint as to why the compiler is complaining about this line?

Write to DB:

use aerospike::{as_key, Bin, Client, Value, ClientPolicy, WritePolicy, ReadPolicy};
use chrono::Utc;
use std::env;

pub async fn create_db_project(
        ....
    ) -> Result<(), aerospike::Error> {

    let client = get_client().await?;

    let aerospike_namespace = env::var("AEROSPIKE_NAMESPACE").expect("AEROSPIKE_NAMESPACE must be set");
    let aerospike_set_name = env::var("AEROSPIKE_PROJECT_TABLE").expect("AEROSPIKE_PROJECT_TABLE must be set");

    let key = as_key!(aerospike_namespace, aerospike_set_name, project_id);

    let test = 0;

    let bins = vec![
        ...
        Bin::new("test", test.into()),
        ...
    ];

    client.put(&WritePolicy::default(), &key, &bins)
}

Read from DB (Read a record | Developer)

async fn get_db_number_build(
        project_id: &str,
        project_name: &str,
    ) -> Result<Option<i64>, aerospike::Error> {

    let client = get_client().await?;
    let aerospike_namespace = env::var("AEROSPIKE_NAMESPACE").expect("AEROSPIKE_NAMESPACE must be set");
    let aerospike_set_name = env::var("AEROSPIKE_PROJECT_TABLE").expect("AEROSPIKE_PROJECT_TABLE must be set");

    let key = as_key!(aerospike_namespace, aerospike_set_name, project_id);

    match client.get(&ReadPolicy::default(), &key, &["test"]) {
        Ok(record) => {
            if let Some(Value::Int(count)) = record.bins.get("test") {
                Ok(Some(*count))
            } else {
                Ok(None)
            }
        }
    }
}

cargo build:

error[E0277]: the trait bound `Bins: std::convert::From<&[&str; 1]>` is not satisfied
   --> src/db.rs:180:52
    |
180 |     match client.get(&ReadPolicy::default(), &key, &["test"]) {
    |                  ---                               ^^^^^^^^^^^^^^ the trait `std::convert::From<&[&str; 1]>` is not implemented for `Bins`, which is required by `&[&str; 1]: Into<Bins>`
    |                  |
    |                  required by a bound introduced by this call
    |
    = help: the following other types implement trait `std::convert::From<T>`:
              `Bins` implements `std::convert::From<&[&str]>`
              ...
    = note: required for `&[&str; 1]` to implement `Into<Bins>`
note: required by a bound in `Client::get`
   --> /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/aerospike-0.5.0/src/client.rs:186:12
    |
184 |     pub fn get<T>(&self, policy: &ReadPolicy, key: &Key, bins: T) -> Result<Record>
    |            --- required by a bound in this associated function
185 |     where
186 |         T: Into<Bins>,
    |            ^^^^^^^^^^ required by this bound in `Client::get`

For more information about this error, try `rustc --explain E0277`.

It seems like your usage falls into a gap in their implemented traits for Bins. If you look at the rustdoc page for Bins, in the list of trait implementations, you will see:

From<&'a [&'a str]>
From<[&'a str; 1]>
From<[&'a str; 2]>
From<[&'a str; 3]>
From<[&'a str; 4]>
From<[&'a str; 5]>
From<[&'a str; 6]>

What you wrote is a near miss; it would need From<&'a [&'a str; 1]>. So, you can make your code work by deleting the & to pass the [&'static str; 1] array without a reference:

match client.get(&ReadPolicy::default(), &key, ["test"]) {

Going by this, their documentation page seems to have an incorrect example.

Really, though, they should be using IntoIterator in this interface instead of From — it’s a lot more flexible, and their implementations are immediately converting to an iterator anyway.

1 Like

It worked for me. But yes, you're absolutely right. Here's the working version just in case.

async fn get_db_number(project_id: &str) -> Result<Option<i64>, aerospike::Error> {

    let client = get_client().await?;
    let aerospike_namespace = env::var("AEROSPIKE_NAMESPACE").expect("AEROSPIKE_NAMESPACE must be set");
    let aerospike_set_name = env::var("AEROSPIKE_PROJECT_TABLE").expect("AEROSPIKE_PROJECT_TABLE must be set");

    let key = as_key!(aerospike_namespace, aerospike_set_name, project_id);

    match client.get(&ReadPolicy::default(), &key, ["num"]) {
        Ok(record) => {
            if let Some(aerospike::Value::Int(count)) = record.bins.get("num") {
                Ok(Some(*count))
            } else {
                Ok(None)
            }
        }
        Err(err) => Err(err),
    }
}

Correct example: Client in aerospike - Rust