easy-odm

Crates.ioeasy-odm
lib.rseasy-odm
version0.0.1
created_at2025-08-11 22:21:14.423537+00
updated_at2025-08-11 22:21:14.423537+00
descriptionA lightweight, async ORM for Elasticsearch in Rust
homepagehttps://gitlab.com/dev-francis-m/easy-odm/
repositoryhttps://gitlab.com/dev-francis-m/easy-odm/
max_upload_size
id1791046
size83,724
fknar (devfrank-m)

documentation

README

Elasticsearch ORM

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.

Features

  • 🚀 Async/await support - Built on tokio with async-trait
  • 📄 Simple Document trait - Easy to implement for your structs
  • 🔍 CRUD operations - Create, read, update, delete documents
  • Efficient updates - Partial document updates with automatic refresh
  • 🛡️ Error handling - Comprehensive error types for different failure scenarios
  • 📦 Lightweight - Minimal dependencies, focused on core functionality

Installation

Add this to your Cargo.toml:

[dependencies]
easy-odm = "0.0.1"

Quick Start

1. Define your document structure

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
    }
}

2. Perform CRUD operations

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(())
}

3. Instance methods

// 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?;

API Reference

Document Trait

The Document trait provides the core functionality for Elasticsearch operations:

Required Methods

  • fn index_name() -> &'static str - Returns the Elasticsearch index name
  • fn id(&self) -> &str - Returns the document's unique identifier

Provided Methods

  • async fn save(&self, client: &Elasticsearch) -> Result<IndexResponse, EsOrmError> - Save/update document
  • async fn get(client: &Elasticsearch, id: &str) -> Result<Self, EsOrmError> - Fetch document by ID
  • async fn delete(client: &Elasticsearch, id: &str) -> Result<DeleteResponse, EsOrmError> - Delete document by ID
  • async fn update(client: &Elasticsearch, id: &str, partial_doc: &Value) -> Result<Self, EsOrmError> - Update document with partial data
  • async fn refresh(&mut self, client: &Elasticsearch) -> Result<(), EsOrmError> - Refresh instance with latest data

Error Handling

The 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),
}

Requirements

  • Rust 1.60+
  • Elasticsearch 7.x or 8.x
  • Your document structs must implement Serialize, Deserialize, and Sized

Testing

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
Commit count: 0

cargo fmt