Crates.io | easy-odm |
lib.rs | easy-odm |
version | 0.0.1 |
created_at | 2025-08-11 22:21:14.423537+00 |
updated_at | 2025-08-11 22:21:14.423537+00 |
description | A lightweight, async ORM for Elasticsearch in Rust |
homepage | https://gitlab.com/dev-francis-m/easy-odm/ |
repository | https://gitlab.com/dev-francis-m/easy-odm/ |
max_upload_size | |
id | 1791046 |
size | 83,724 |
A lightweight, async ORM for Elasticsearch in Rust that provides a simple trait-based interface for document operations.
⚠️ Development Status: This library is currently in heavy development. The API is unstable and subject to breaking changes. Not recommended for production use at this time. Please use for experimentation and development only.
Add this to your Cargo.toml
:
[dependencies]
easy-odm = "0.0.1"
use serde::{Serialize, Deserialize};
use elasticsearch_orm::{Document, EsOrmError};
use async_trait::async_trait;
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct User {
id: String,
name: String,
email: String,
age: Option<u32>,
}
#[async_trait]
impl Document for User {
fn index_name() -> &'static str {
"users"
}
fn id(&self) -> &str {
&self.id
}
}
use elasticsearch::Elasticsearch;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create Elasticsearch client
let client = Elasticsearch::default();
// Create a new user
let user = User {
id: "1".to_string(),
name: "John Doe".to_string(),
email: "john@example.com".to_string(),
age: Some(30),
};
// Save to Elasticsearch
let response = user.save(&client).await?;
println!("Saved user: {}", response.result);
// Fetch by ID
let fetched_user = User::get(&client, "1").await?;
println!("Fetched user: {:?}", fetched_user);
// Update with partial data
let update_data = serde_json::json!({
"age": 31,
"email": "john.doe@example.com"
});
let updated_user = User::update(&client, "1", &update_data).await?;
println!("Updated user: {:?}", updated_user);
// Delete the user
let delete_response = User::delete(&client, "1").await?;
println!("Deleted user: {}", delete_response.result);
Ok(())
}
// Create and save a user
let mut user = User {
id: "2".to_string(),
name: "Jane Doe".to_string(),
email: "jane@example.com".to_string(),
age: Some(25),
};
user.save(&client).await?;
// Later, refresh the instance with latest data from Elasticsearch
user.refresh(&client).await?;
The Document
trait provides the core functionality for Elasticsearch operations:
fn index_name() -> &'static str
- Returns the Elasticsearch index namefn id(&self) -> &str
- Returns the document's unique identifierasync fn save(&self, client: &Elasticsearch) -> Result<IndexResponse, EsOrmError>
- Save/update documentasync fn get(client: &Elasticsearch, id: &str) -> Result<Self, EsOrmError>
- Fetch document by IDasync fn delete(client: &Elasticsearch, id: &str) -> Result<DeleteResponse, EsOrmError>
- Delete document by IDasync fn update(client: &Elasticsearch, id: &str, partial_doc: &Value) -> Result<Self, EsOrmError>
- Update document with partial dataasync fn refresh(&mut self, client: &Elasticsearch) -> Result<(), EsOrmError>
- Refresh instance with latest dataThe crate provides comprehensive error handling through the EsOrmError
enum:
match User::get(&client, "nonexistent").await {
Ok(user) => println!("Found user: {:?}", user),
Err(EsOrmError::NotFound) => println!("User not found"),
Err(EsOrmError::Http(e)) => println!("HTTP error: {}", e),
Err(EsOrmError::Serde(e)) => println!("Serialization error: {}", e),
Err(EsOrmError::EsError(e)) => println!("Elasticsearch error: {}", e),
}
Serialize
, Deserialize
, and Sized
The crate includes comprehensive tests. To run them, you'll need a local Elasticsearch instance running on http://localhost:9200
:
# Start Elasticsearch (example with Docker)
docker run -d -p 9200:9200 -e "discovery.type=single-node" elasticsearch:8.0.0
# Run tests
cargo test