{"id":13933009,"url":"https://github.com/aerospike/aerospike-client-rust","last_synced_at":"2026-05-01T14:02:52.588Z","repository":{"id":15315978,"uuid":"63725376","full_name":"aerospike/aerospike-client-rust","owner":"aerospike","description":"Rust client for the Aerospike database","archived":false,"fork":false,"pushed_at":"2026-04-29T17:54:17.000Z","size":2311,"stargazers_count":97,"open_issues_count":44,"forks_count":37,"subscribers_count":50,"default_branch":"main","last_synced_at":"2026-04-29T19:33:58.219Z","etag":null,"topics":["aerospike","database-driver","nosql","rust"],"latest_commit_sha":null,"homepage":"https://www.aerospike.com/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aerospike.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2016-07-19T20:20:16.000Z","updated_at":"2026-02-17T14:37:52.000Z","dependencies_parsed_at":"2023-01-13T18:21:54.209Z","dependency_job_id":"48c64c19-082e-4dab-a424-9469f0a7c8c8","html_url":"https://github.com/aerospike/aerospike-client-rust","commit_stats":{"total_commits":298,"total_committers":15,"mean_commits":"19.866666666666667","dds":"0.43624161073825507","last_synced_commit":"6ac1a06a899d964bf3564e5b9fad746ba9c22411"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/aerospike/aerospike-client-rust","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aerospike%2Faerospike-client-rust","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aerospike%2Faerospike-client-rust/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aerospike%2Faerospike-client-rust/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aerospike%2Faerospike-client-rust/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aerospike","download_url":"https://codeload.github.com/aerospike/aerospike-client-rust/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aerospike%2Faerospike-client-rust/sbom","scorecard":{"id":169161,"data":{"date":"2025-08-11","repo":{"name":"github.com/aerospike/aerospike-client-rust","commit":"41312f30e392df90dd9900e0868f93dd49a06a3e"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.6,"checks":[{"name":"Code-Review","score":1,"reason":"Found 3/21 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/build.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/aerospike/aerospike-client-rust/build.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build.yml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/aerospike/aerospike-client-rust/build.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build.yml:35: update your workflow using https://app.stepsecurity.io/secureworkflow/aerospike/aerospike-client-rust/build.yml/master?enable=pin","Info:   0 out of   1 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":1,"reason":"branch protection is not maximal on development and all release branches","details":["Warn: branch protection not enabled for branch 'v2'","Info: 'allow deletion' disabled on branch 'master'","Info: 'force pushes' disabled on branch 'master'","Warn: 'branch protection settings apply to administrators' is disabled on branch 'master'","Info: 'stale review dismissal' is required to merge on branch 'master'","Warn: required approving review count is 1 on branch 'master'","Warn: codeowners review is required - but no codeowners file found in repo","Info: 'last push approval' is required to merge on branch 'master'","Warn: no status checks found to merge onto branch 'master'","Info: PRs are required in order to make changes on branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 13 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-16T15:54:22.317Z","repository_id":15315978,"created_at":"2025-08-16T15:54:22.317Z","updated_at":"2025-08-16T15:54:22.317Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32499691,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aerospike","database-driver","nosql","rust"],"created_at":"2024-08-07T21:01:28.498Z","updated_at":"2026-05-01T14:02:52.572Z","avatar_url":"https://github.com/aerospike.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"# Aerospike Rust Client \n\nWelcome to Aerospike's official [Rust client](https://aerospike.com/docs/develop/client/rust).\n\n## Feature highlights\n\n**Execution models:**\n\n- **Async-First:** Built for non-blocking IO, powered by \n  [Tokio](https://tokio.rs/) by default, with optional support for [async-std](https://async.rs/).\n- **Sync Support:** Blocking APIs are available using a sync sub-crate for \n  flexibility in legacy or mixed environments.\n\n**Advanced data operations:**\n\n- **Batch protocol:** full support for read, write, delete, and udf operations through the \n  new `BatchOperationAPI`.\n- **New query wire protocols:** implements updated query protocols for \n  improved consistency and performance.\n\n**Policy and expression enhancements:**\n\n- **Replica policies:** includes support for Replica, including PreferRack placement.\n- **Policy additions:** new fields such as `allow_inline_ssd`, `respond_all_keys` \n  in `BatchPolicy`, `read_touch_ttl`, and `QueryDuration` in `QueryPolicy`.\n- **Rate limiting:** supports `records_per_second` for query throttling.\n\n**Data model improvements:**\n\n- **Type support:** adds support for boolean particle type.\n- **New data constructs:** returns types such as `Exists`, \n  `OrderedMap`, `UnorderedMap` now supported for \n  [CDT](https://aerospike.com/docs/develop/data-types/collections/) reads.\n- **Value conversions:** implements `TryFromaerospike::Value` for seamless type interoperability.\n- **Infinity and wildcard:** supports `Infinity`, `Wildcard`, and \n  corresponding expression builders `expressions::infinity()` and \n  `expressions::wildcard()`.\n- **Size expressions:** adds `expressions::record_size()` and `expressions::memory_size()` \n  for granular control.\n\nTake a look at the [changelog](https://github.com/aerospike/aerospike-client-rust/blob/v2/CHANGELOG.md) for more details.\n\n## What’s coming next?\n\nWe are working toward full functional parity with our \nother officially supported clients. Features on the roadmap include:\n\n- Partition queries\n- Distributed ACID transactions\n- Strong consistency\n\n## Getting started\n\nPrerequisites:\n\n- [Aerospike Database](https://aerospike.com/download/server/community/) 6.4 or later.\n- [Rust](https://www.rust-lang.org/) version 1.87 or later \n- [Tokio runtime](https://tokio.rs/) or [async-std](https://async.rs/)\n\n## Installation\n\n### Build from source\n\n1. Clone the repository and change into the project directory:\n\n   ```\n   git clone --single-branch --branch v2 https://github.com/aerospike/aerospike-client-rust.git\n   cd aerospike-client-rust\n   ```\n\n2. Build the project:\n\n   ```\n   cargo build\n   ```\n\n### Use as a dependency\n\nTo use the client in your own project, add one of the following to your `Cargo.toml`:\n\n   ```\n   [dependencies]\n   # Async API with tokio Runtime\n   aerospike = { version = \"\u003cversion\u003e\", features = [\"rt-tokio\"]}\n\n   # OR\n\n   # Async API with async-std runtime\n   aerospike = { version = \"\u003cversion\u003e\", features = [\"rt-async-std\"]}\n\n   # The library still supports the old sync interface, but it will be deprecated in the future.\n   # This is only for compatibility reasons and will be removed in a later stage.\n\n   # Sync API with tokio\n   aerospike = { version = \"\u003cversion\u003e\", default-features = false, features = [\"rt-tokio\", \"sync\"]}\n\n   # OR\n\n   # Sync API with async-std\n   aerospike = { version = \"\u003cversion\u003e\", default-features = false, features = [\"rt-async-std\", \"sync\"]}\n   ```\n\n   Then run `cargo build` in your project.\n\n## Core feature examples\n\nThe following code examples demonstrate some of the Rust client's new\nfeatures.\n\n### Client connection\n\nThe examples below use the **async** client (default). For a blocking API with no `.await`, see [Sync client](#sync-client) below.\n\n#### Standard connection\n\nConnect to an Aerospike cluster without TLS:\n\n```rust\nuse std::env;\nuse aerospike::{Client, ClientPolicy};\n\nlet policy = ClientPolicy::default();\nlet hosts = env::var(\"AEROSPIKE_HOSTS\")\n    .unwrap_or_else(|_| \"127.0.0.1:3000\".to_string());\nlet client = Client::new(\u0026policy, \u0026hosts)\n    .await\n    .expect(\"Failed to connect to cluster\");\n```\n\n#### Sync client\n\nThe `sync` feature exposes blocking APIs — no `async`/`.await` at call sites. However, the client still uses Tokio \ninternally for cluster management, so **a Tokio runtime must be running** for the duration of your program.\n\n**Cargo.toml**\n```toml\n[dependencies]\naerospike = { version = \"\u003cversion\u003e\", default-features = false, features = [\"rt-tokio\", \"sync\"] }\ntokio = { version = \"1\", features = [\"full\"] }  # required even for sync usage\n```\n\n\u003e Swap `rt-tokio` for `rt-async-std` if your project uses async-std instead.\n\n**Example:**\n```rust\n#[macro_use]\nextern crate aerospike;\n\nuse std::env;\nuse aerospike::{Bins, Client, ClientPolicy, ReadPolicy, WritePolicy};\n\n// #[tokio::main] is required — the sync client uses Tokio internally\n// for cluster tending, even though your code has no .await calls.\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let policy = ClientPolicy::default();\n    let hosts = env::var(\"AEROSPIKE_HOSTS\")\n        .unwrap_or_else(|_| \"127.0.0.1:3000\".to_string());\n\n    let client = Client::new(\u0026policy, \u0026hosts)?;\n\n    let key = as_key!(\"test\", \"myset\", \"sync-key\");\n    let bins = [as_bin!(\"name\", \"Alice\"), as_bin!(\"count\", 42)];\n    client.put(\u0026WritePolicy::default(), \u0026key, \u0026bins)?;\n\n    let record = client.get(\u0026ReadPolicy::default(), \u0026key, Bins::All)?;\n    println!(\"Record: {:?}\", record.bins);\n\n    client.close()?;\n    Ok(())\n}\n```\n\n\u003e **Why does sync need a Tokio runtime?** The `sync` feature wraps the async client and provides blocking call \n\u003e sites — it does not replace the underlying async runtime. Cluster tending (node discovery, connection pooling) runs \n\u003e as a background Tokio task regardless of which API surface you use. Calling `Client::new` outside of a runtime context\n\u003e will panic with `there is no reactor running`.\n\n#### TLS connection without client authentication\n\nConnect to an Aerospike cluster with TLS but without client certificate authentication:\n\n```rust\nuse aerospike::{Client, ClientPolicy};\nuse rustls::RootCertStore;\nuse rustls::pki_types::CertificateDer;\n\nfn tls_config_no_client_auth(ca_cert_path: \u0026str) -\u003e rustls::ClientConfig {\n    let mut root_store = RootCertStore {\n        roots: webpki_roots::TLS_SERVER_ROOTS.into(),\n    };\n\n    // Add custom CA certificate\n    root_store.add_parsable_certificates(\n        CertificateDer::pem_file_iter(ca_cert_path)\n            .expect(\"Cannot open CA file\")\n            .map(|result| result.unwrap()),\n    );\n\n    rustls::ClientConfig::builder()\n        .with_root_certificates(root_store)\n        .with_no_client_auth()\n}\n\nlet mut policy = ClientPolicy::default();\npolicy.tls_config = Some(tls_config_no_client_auth(\"/path/to/ca-cert.pem\"));\n\nlet hosts = \"tls-cluster.example.com:4333\";\nlet client = Client::new(\u0026policy, hosts).await\n    .expect(\"Failed to connect to cluster\");\n```\n\n#### TLS connection with client authentication\n\nConnect to an Aerospike cluster with TLS and mutual authentication using client certificates:\n\n```rust\nuse aerospike::{Client, ClientPolicy};\nuse rustls::RootCertStore;\nuse rustls::pki_types::{CertificateDer, PrivateKeyDer};\n\nfn tls_config_with_client_auth(\n    ca_cert_path: \u0026str,\n    client_cert_path: \u0026str,\n    client_key_path: \u0026str,\n) -\u003e rustls::ClientConfig {\n    let mut root_store = RootCertStore {\n        roots: webpki_roots::TLS_SERVER_ROOTS.into(),\n    };\n\n    // Add custom CA certificate\n    root_store.add_parsable_certificates(\n        CertificateDer::pem_file_iter(ca_cert_path)\n            .expect(\"Cannot open CA file\")\n            .map(|result| result.unwrap()),\n    );\n\n    // Load client certificate and private key\n    let client_cert = CertificateDer::from_pem_file(client_cert_path)\n        .expect(\"Cannot open client certificate file\");\n    let client_key = PrivateKeyDer::from_pem_file(client_key_path)\n        .expect(\"Cannot open client key file\");\n\n    rustls::ClientConfig::builder()\n        .with_root_certificates(root_store)\n        .with_client_auth_cert(vec![client_cert], client_key)\n        .expect(\"Failed to configure client authentication\")\n}\n\nlet mut policy = ClientPolicy::default();\npolicy.tls_config = Some(tls_config_with_client_auth(\n    \"/path/to/ca-cert.pem\",\n    \"/path/to/client-cert.pem\",\n    \"/path/to/client-key.pem\",\n));\n\nlet hosts = \"tls-cluster.example.com:4333\";\nlet client = Client::new(\u0026policy, hosts).await\n    .expect(\"Failed to connect to cluster\");\n```\n\n**Note**: To use TLS features, enable the `tls` feature in your `Cargo.toml`:\n\n```toml\n[dependencies]\naerospike = { version = \"...\", features = [\"tls\"] }\n```\n\n### CRUD operations\n\n```rust\n#[macro_use]\nextern crate aerospike;\nextern crate tokio;\n\nuse std::env;\nuse std::time::Instant;\n\nuse aerospike::{Bins, Client, ClientPolicy, ReadPolicy, WritePolicy};\nuse aerospike::operations;\n\n#[tokio::main]\nasync fn main() {\n    let cpolicy = ClientPolicy::default();\n    let hosts = env::var(\"AEROSPIKE_HOSTS\")\n        .unwrap_or(String::from(\"127.0.0.1:3000\"));\n    let client = Client::new(\u0026cpolicy, \u0026hosts).await\n        .expect(\"Failed to connect to cluster\");\n\n    let now = Instant::now();\n    let rpolicy = ReadPolicy::default();\n    let wpolicy = WritePolicy::default();\n    let key = as_key!(\"test\", \"test\", \"test\");\n\n    let bins = [\n        as_bin!(\"int\", 999),\n        as_bin!(\"str\", \"Hello, World!\"),\n    ];\n    client.put(\u0026wpolicy, \u0026key, \u0026bins).await.unwrap();\n    let rec = client.get(\u0026rpolicy, \u0026key, Bins::All).await;\n    println!(\"Record: {}\", rec.unwrap());\n\n    client.touch(\u0026wpolicy, \u0026key).await.unwrap();\n    let rec = client.get(\u0026rpolicy, \u0026key, Bins::All).await;\n    println!(\"Record: {}\", rec.unwrap());\n\n    let rec = client.get(\u0026rpolicy, \u0026key, Bins::None).await;\n    println!(\"Record Header: {}\", rec.unwrap());\n\n    let exists = client.exists(\u0026rpolicy, \u0026key).await.unwrap();\n    println!(\"exists: {}\", exists);\n\n    let bin = as_bin!(\"int\", \"123\");\n    let ops = \u0026vec![operations::put(\u0026bin), operations::get()];\n    let op_rec = client.operate(\u0026wpolicy, \u0026key, ops).await;\n    println!(\"operate: {}\", op_rec.unwrap());\n\n    let existed = client.delete(\u0026wpolicy, \u0026key).await.unwrap();\n    println!(\"existed (should be true): {}\", existed);\n\n    let existed = client.delete(\u0026wpolicy, \u0026key).await.unwrap();\n    println!(\"existed (should be false): {}\", existed);\n\n    println!(\"total time: {:?}\", now.elapsed());\n}\n```\n\n### Batch operations\n\n```rust\n    let mut bpolicy = BatchPolicy::default();\n    let apolicy = AdminPolicy::default();\n\n    let udf_body = r#\"\n\tfunction echo(rec, val)\n  \t\treturn val\n\tend\n\t\"#;\n\n    let task = client\n        .register_udf(\u0026apolicy, udf_body.as_bytes(), \"test_udf.lua\", UDFLang::Lua)\n        .await\n        .unwrap();\n    task.wait_till_complete(None).await.unwrap();\n\n    let bin1 = as_bin!(\"a\", \"a value\");\n    let bin2 = as_bin!(\"b\", \"another value\");\n    let bin3 = as_bin!(\"c\", 42);\n\n    let key1 = as_key!(namespace, set_name, 1);\n    let key2 = as_key!(namespace, set_name, 2);\n    let key3 = as_key!(namespace, set_name, 3);\n\n    let key4 = as_key!(namespace, set_name, -1);\n    // key does not exist\n\n    let selected = Bins::from([\"a\"]);\n    let all = Bins::All;\n    let none = Bins::None;\n\n    let wops = vec![\n        operations::put(\u0026bin1),\n        operations::put(\u0026bin2),\n        operations::put(\u0026bin3),\n    ];\n\n    let rops = vec![\n        operations::get_bin(\u0026bin1.name),\n        operations::get_bin(\u0026bin2.name),\n        operations::get_header(),\n    ];\n\n    let bpr = BatchReadPolicy::default();\n    let bpw = BatchWritePolicy::default();\n    let bpd = BatchDeletePolicy::default();\n    let bpu = BatchUDFPolicy::default();\n\n    let batch = vec![\n        BatchOperation::write(\u0026bpw, key1.clone(), wops.clone()),\n        BatchOperation::write(\u0026bpw, key2.clone(), wops.clone()),\n        BatchOperation::write(\u0026bpw, key3.clone(), wops.clone()),\n    ];\n    let mut results = client.batch(\u0026bpolicy, \u0026batch).await.unwrap();\n\n    dbg!(\u0026results);\n\n    // READ Operations\n    let batch = vec![\n        BatchOperation::read(\u0026bpr, key1.clone(), selected),\n        BatchOperation::read(\u0026bpr, key2.clone(), all),\n        BatchOperation::read(\u0026bpr, key3.clone(), none.clone()),\n        BatchOperation::read_ops(\u0026bpr, key3.clone(), rops),\n        BatchOperation::read(\u0026bpr, key4.clone(), none),\n    ];\n    let mut results = client.batch(\u0026bpolicy, \u0026batch).await.unwrap();\n\n    dbg!(\u0026results);\n\n    // DELETE Operations\n    let batch = vec![\n        BatchOperation::delete(\u0026bpd, key1.clone()),\n        BatchOperation::delete(\u0026bpd, key2.clone()),\n        BatchOperation::delete(\u0026bpd, key3.clone()),\n        BatchOperation::delete(\u0026bpd, key4.clone()),\n    ];\n    let mut results = client.batch(\u0026bpolicy, \u0026batch).await.unwrap();\n\n    dbg!(\u0026results);\n\n    // Read\n    let args1 = \u0026[as_val!(1)];\n    let args2 = \u0026[as_val!(2)];\n    let args3 = \u0026[as_val!(3)];\n    let args4 = \u0026[as_val!(4)];\n    let batch = vec![\n        BatchOperation::udf(\u0026bpu, key1.clone(), \"test_udf\", \"echo\", Some(args1)),\n        BatchOperation::udf(\u0026bpu, key2.clone(), \"test_udf\", \"echo\", Some(args2)),\n        BatchOperation::udf(\u0026bpu, key3.clone(), \"test_udf\", \"echo\", Some(args3)),\n        BatchOperation::udf(\u0026bpu, key4.clone(), \"test_udf\", \"echo\", Some(args4)),\n    ];\n    let mut results = client.batch(\u0026bpolicy, \u0026batch).await.unwrap();\n\n    dbg!(\u0026results);\n```\n\nA complete working example can be found in [examples/batch_operations.rs](./examples/batch_operations.rs).\n\n### Query operations\n\nThe Rust client supports various query patterns for retrieving data from Aerospike. Below are examples demonstrating different query capabilities.\n\n#### Simple equality query\n\nQuery records where a bin equals a specific value:\n\n```rust\nuse aerospike::{QueryPolicy, Statement, Bins};\nuse aerospike::query::PartitionFilter;\n\nlet policy = QueryPolicy::default();\nlet mut stmt = Statement::new(namespace, set_name, Bins::All);\nstmt.add_filter(as_eq!(\"bin_name\", 5));\n\nlet rs = client.query(\u0026policy, PartitionFilter::all(), stmt).await.unwrap();\nlet mut rs = rs.into_stream();\n\nwhile let Some(r) = rs.next().await {\n    println!(\"Record: {:?}\", r.unwrap());\n}\n```\n\n#### Range query\n\nQuery records where a bin value falls within a range:\n\n```rust\nlet policy = QueryPolicy::default();\nlet mut stmt = Statement::new(namespace, set_name, Bins::All);\nstmt.add_filter(as_range!(\"bin_name\", 0, 100));\n\nlet rs = client.query(\u0026policy, PartitionFilter::all(), stmt).await.unwrap();\nlet mut rs = rs.into_stream();\n\nwhile let Some(r) = rs.next().await {\n    println!(\"Record: {:?}\", r.unwrap());\n}\n```\n\n#### Metadata-only query\n\nQuery records but only retrieve metadata (no bin data):\n\n```rust\nlet policy = QueryPolicy::default();\nlet mut stmt = Statement::new(namespace, set_name, Bins::None);\nstmt.add_filter(as_range!(\"bin_name\", 0, 100));\n\nlet rs = client.query(\u0026policy, PartitionFilter::all(), stmt).await.unwrap();\nlet mut rs = rs.into_stream();\n\nwhile let Some(r) = rs.next().await {\n    let rec = r.unwrap();\n    println!(\"Generation: {}, TTL: {}\", rec.generation, rec.expiration);\n}\n```\n\n#### Cursor-based pagination\n\nQuery records in batches using partition cursors for pagination:\n\n```rust\nlet policy = QueryPolicy::default();\nlet mut pf = PartitionFilter::all();\n\nwhile !pf.done() {\n    let stmt = Statement::new(namespace, set_name, Bins::All);\n    let rs = client.query(\u0026policy, pf, stmt).await.unwrap();\n    let mut rs = rs.into_stream();\n    \n    while let Some(r) = rs.next().await {\n        println!(\"Record: {:?}\", r.unwrap());\n    }\n    \n    // Get the next partition filter to continue pagination\n    pf = rs.partition_filter().await.unwrap();\n}\n```\n\n#### Parallel query with multiple consumers\n\nProcess query results in parallel using multiple async tasks:\n\n```rust\nuse std::sync::Arc;\nuse std::sync::atomic::{AtomicUsize, Ordering};\n\nlet policy = QueryPolicy::default();\nlet mut stmt = Statement::new(namespace, set_name, Bins::All);\nstmt.add_filter(as_range!(\"bin_name\", 0, 100));\n\nlet rs = client.query(\u0026policy, PartitionFilter::all(), stmt).await.unwrap();\nlet count = Arc::new(AtomicUsize::new(0));\nlet mut handles = vec![];\n\n// Spawn 4 worker tasks to process results in parallel\nfor _ in 0..4 {\n    let rs_clone = rs.clone();\n    let count = count.clone();\n    \n    handles.push(tokio::spawn(async move {\n        let mut rs_stream = rs_clone.into_stream();\n        while let Some(record) = rs_stream.next().await {\n            if record.is_ok() {\n                count.fetch_add(1, Ordering::Relaxed);\n            }\n        }\n    }));\n}\n\nfutures::future::join_all(handles).await;\nprintln!(\"Total processed: {}\", count.load(Ordering::Relaxed));\n```\n\n#### Query with expression filter\n\nUse filter expressions for more complex filtering logic:\n\n```rust\nuse aerospike_core::expressions::{eq, int_bin, int_val};\n\nlet mut policy = QueryPolicy::default();\npolicy.base_policy.filter_expression.replace(\n    eq(int_bin(\"bin_name\".to_string()), int_val(42))\n);\n\nlet stmt = Statement::new(namespace, set_name, Bins::All);\nlet rs = client.query(\u0026policy, PartitionFilter::all(), stmt).await.unwrap();\nlet mut rs = rs.into_stream();\n\nwhile let Some(r) = rs.next().await {\n    println!(\"Record: {:?}\", r.unwrap());\n}\n```\n\n#### Rate-limited query\n\nControl query throughput by limiting records per second:\n\n```rust\nlet mut policy = QueryPolicy::default();\npolicy.records_per_second = 100;  // Limit to 100 records/second\n\nlet mut stmt = Statement::new(namespace, set_name, Bins::All);\nstmt.add_filter(as_range!(\"bin_name\", 0, 1000));\n\nlet rs = client.query(\u0026policy, PartitionFilter::all(), stmt).await.unwrap();\nlet mut rs = rs.into_stream();\n\nwhile let Some(r) = rs.next().await {\n    match r {\n        Ok(rec) =\u003e println!(\"Record: {:?}\", rec),\n        Err(err) =\u003e eprintln!(\"Error: {:?}\", err),\n    }\n}\n```\n\n#### Prerequisites for queries\n\nBefore running queries, you need to create a secondary index on the bin you want to query:\n\n```rust\nuse aerospike_core::{AdminPolicy, IndexType, CollectionIndexType};\n\nlet policy = AdminPolicy::default();\nlet task = client\n    .create_index_on_bin(\n        \u0026policy,\n        namespace,\n        set_name,\n        \"bin_name\",\n        \"idx_bin_name\",\n        IndexType::Numeric,\n        CollectionIndexType::Default,\n        None,\n    )\n    .await\n    .expect(\"Failed to create index\");\n\n// Wait for index creation to complete\ntask.wait_till_complete(None).await.unwrap();\n```\n\nFor a complete working example with all query patterns, see [`examples/query.rs`](./examples/query.rs).\n\n### Timeout configuration\n\nThe Rust client provides flexible timeout configuration through `socket_timeout` and `total_timeout` parameters in policies. Understanding how these interact is crucial for handling network issues and controlling command execution time.\n\n#### Timeout parameters\n\n- **`socket_timeout`**: Socket idle timeout when processing a database command (in milliseconds). Default value 5000 (5 seconds).\n- **`total_timeout`**: Total command timeout, including retries (in milliseconds). Default value 0.\n\n#### Timeout behavior rules\n\n1. **Both zero (0, 0)**: No timeout limits - commands wait indefinitely\n2. **Socket zero, total non-zero (0, N)**: `socket_timeout` inherits `total_timeout` value\n3. **Socket non-zero, total zero (N, 0)**: Socket idle timeout of N ms, no total limit\n4. **Both non-zero, socket \u003e total (N, M where N \u003e M)**: `socket_timeout` capped at `total_timeout`\n5. **Both non-zero, socket ≤ total (N, M where N ≤ M)**: Both timeouts enforced independently\n\nWhen a socket timeout occurs, the client checks `max_retries` and `total_timeout`. If neither is exceeded, the command is automatically retried.\n\nRust client exposes these parameters through the Read/Write policy, and can be tuned as below:\n\n```rust\nuse aerospike::{ReadPolicy, Bins};\n\nlet mut policy = ReadPolicy::default();\npolicy.base_policy.socket_timeout = 0;\npolicy.base_policy.total_timeout = 0;\n\nlet rec = client.get(\u0026policy, \u0026key, Bins::All).await;\n```\n\n#### Socket recovery with timeout_delay\n\nThe `timeout_delay` parameter controls how the client handles sockets after a read timeout. This is particularly important for cloud deployments.\n\n```rust\nlet mut policy = ReadPolicy::default();\npolicy.base_policy.socket_timeout = 2000;  // 2 second socket timeout\npolicy.base_policy.total_timeout = 10000;  // 10 second total timeout\npolicy.base_policy.timeout_delay = 3000;   // 3 second delay for socket recovery\n\nlet rec = client.get(\u0026policy, \u0026key, Bins::All).await;\n```\n\n**How `timeout_delay` works:**\n\n1. **When `timeout_delay = 0` (default)**: Socket is immediately closed on timeout\n2. **When `timeout_delay \u003e 0`**: After a socket read timeout, the client attempts to drain remaining data from the socket in the background for up to `timeout_delay` milliseconds\n    - If all data is drained within the delay: Socket returned to connection pool (reusable)\n    - If delay expires before draining completes: Socket is closed\n\n**Why use `timeout_delay`?**\n\nMany cloud providers experience performance issues when clients close sockets while the server still has data to write (results in TCP RST packets). Draining the socket before closing avoids this penalty.\n\n**Trade-offs:**\n\n- ✓ Avoids TCP RST performance penalties on cloud platforms\n- ✓ Allows socket reuse when recovery is successful\n- ✗ Requires extra processing to drain sockets\n- ✗ May need additional connections for command retries during recovery\n\n**Recommended value:** If enabling `timeout_delay`, 3000ms (3 seconds) is a reasonable starting point.\n\nFor a complete working example demonstrating timeout scenarios, see [`examples/timeout_configuration.rs`](./examples/timeout_configuration.rs).\n## Feedback wanted\n\nWe need your help with:\n\n- Real-world async patterns in your codebase\n- Ergonomic pain points in API design\n\nYou’re not just testing this new client - you’re shaping the future of Rust in databases!\n\nYou can reach us through [Github Issues](https://github.com/aerospike/aerospike-client-rust/issues)\nor schedule a meeting to speak directly with our product team using\n[this scheduling link](https://calendar.app.google/sDseJu6vUg8da5Kw5).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faerospike%2Faerospike-client-rust","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faerospike%2Faerospike-client-rust","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faerospike%2Faerospike-client-rust/lists"}