Skip to main content

Crate khan

Crate khan 

Source
Expand description

Khan is a MongoDB ORM (or, more precisely, an ODM) for Rust. It adds an entity API on top of the underlying MongoDB driver, with type-safe methods to create, query, update, and delete documents, as well as tools for maintaining consistency in multi-document transactions. It can also manage collection indexes and validation rules in a code-first manner.

§Why Khan?

Khan is designed for applications that want Rust’s type system around everyday MongoDB work without hiding MongoDB itself.

  • 🛡️ Typed where repetition is costly. Deriving Entity generates typed filters, updates, field names, projections, and CRUD methods from the same Serde model used for BSON.
  • 🧰 Explicit where MongoDB is powerful. Raw BSON filters and updates remain deliberate escape hatches, while the underlying mongodb API stays available for aggregation pipelines and specialized operations.
  • 🔄 Transaction-aware by construction. Entity operations work with either a database or a transaction context. DatabaseExt provides retry-aware transaction helpers, while Fence can express document-level reference requirements in function signatures.
  • 🧩 Code-first database metadata. Optional features let entity declarations define and enforce indexes, query-expression validators, and MongoDB JSON Schema validation.
  • 🎯 A focused, composable API. Khan handles common persistence and consistency concerns while application architecture, domain behavior, and advanced MongoDB operations remain ordinary Rust code.

§Example

// Define an entity
#[derive(Serialize, Deserialize, Entity, Debug, PartialEq, Eq)]
#[entity(
  skip_schema_validation,
  collection = "readme_user",
  // Define supported projections; respective structs are generated automatically.
  projections(Profile(id, email, password))
)]
struct User {
  #[serde(rename = "_id")]
  id: ObjectId,
  email: String,
  username: String,
  password: String,
}

// Insert an entity into the database
let user = User {
  id: ObjectId::new(),
  email: "mail@example.com".into(),
  username: "nikis05".into(),
  password: "somepassword".into(),
};
let user_id = user.id;

user.insert(mongo).await?;
assert_eq!(User::find_one(mongo, by_id(user_id)).await?, Some(user));

// Query an entity by id
let person: User = User::find_one(mongo, by_id(user_id)).await?.unwrap();
assert_eq!(person.email, "mail@example.com");

// Query an entity by custom fields
let recent_user: User = User::find_one(mongo, user::filter! {
  username: "nikis05"
}).await?.unwrap();
assert_eq!(recent_user.id, user_id);

// Query only the necessary fields of an entity
// into a custom projection struct
let user::Profile { email, password, .. } = user::Profile::find_one(mongo, by_id(user_id)).await?.unwrap();
assert_eq!(email, "mail@example.com");
assert_eq!(password, "somepassword");

// Update an entity in the database
User::update_one(mongo, by_id(user_id), user::update! {
  email: "new.email@example.com".into()
}).await?;
assert_eq!(User::find_one(mongo, by_id(user_id)).await?.unwrap().email, "new.email@example.com");

// Update an entity in the database and the corresponding struct
let mut user = User::find_one(mongo, by_id(user_id)).await?.unwrap();
user.patch(mongo, user::update! {
  email: "newer.email@example.com".into(),
  password: "someotherpassword".into()
}).await?;
assert_eq!(User::find_one(mongo, by_id(user_id)).await?.unwrap().password, "someotherpassword");
assert_eq!(user.password, "someotherpassword");

// Delete one entity matching the filter
let result = User::delete_one(mongo, by_id(user_id)).await?;
assert!(result.deleted());
assert!(User::find_one(mongo, by_id(user_id)).await?.is_none());

// Remove a document from the database that corresponds to an instance
let removable = User {
  id: ObjectId::new(),
  email: "remove@example.com".into(),
  username: "remove-me".into(),
  password: "temporary".into(),
};
let removable_id = removable.id;
removable.insert(mongo).await?;
removable.remove(mongo).await?;
assert!(User::find_one(mongo, by_id(removable_id)).await?.is_none());

See guides module to learn more!

§Crate features

  • meta - enables Khan to manage collection indexes and expression-based validation rules.
  • schema - enables generation of MongoDB JSON Schema validation rules. Participating entities must derive JsonSchema and use BSON-compatible types. Individual entities can opt out with #[entity(skip_schema_validation)]. Apply generated rules with meta::enforce_validation.
  • guides - internal feature for documentation purposes.

Re-exports§

pub use indexmap;
pub use mongodb;
pub use schemars;

Modules§

guides
High-level usage guides for Khan, covering core concepts like CRUD, filters, projections, transactions, and design patterns. Start here.
meta
Tools for managing indexes and validation rules on collections.
prelude
Convenient imports for Khan’s common entity and database operations.
types
BSON-compatible types for use with JSON Schema validation.

Structs§

DeleteResult
A wrapper around mongodb::results::DeleteResult, representing the outcome of a delete operation.
Fence
A type-level marker indicating that a document has been fenced in the current transaction.
FilterById
A simple filter that matches a document by its id field.
FindOptions
Options for Selectable::find_with_opts.
IndexMap
A hash table where the iteration order of the key-value pairs is independent of the hash values of the keys.
UntypedFilter
A raw BSON filter for an entity, bypassing Khan’s typed filter system.
UntypedUpdate
A raw BSON update for an entity, bypassing Khan’s typed update system.
UntypedUpdateApply
A raw BSON update paired with an in-memory update function.
UpdateResult
A wrapper around mongodb::results::UpdateResult that represents the result of an update operation on a MongoDB collection.

Enums§

Field
A wrapper used in Khan’s typed filters and updates to mark field usage.
FilterOperator
Represents a typed MongoDB comparison operator for a specific field.
Order
Sort direction for MongoDB queries and index definitions.

Traits§

DatabaseExt
Convenience methods for running transactions.
Entity
Core trait representing a MongoDB document.
Filter
Trait representing a MongoDB query filter for a given entity type.
JsonSchema
A type which can be described as a JSON Schema document.
Mongo
A MongoDB database, optionally paired with a transaction session.
Selectable
Trait that represents either a complete entity or a partial projection of it.
SelectableWithId
Extension of Selectable for projections that include the id field.
Transaction
A MongoDB database context with an active transaction session.
Update
Trait representing an update expression for a given entity type.
UpdateApply
Trait for applying an update to an in-memory projection.

Functions§

by_id
Creates a filter that matches a document by its id.

Derive Macros§

Entity
Derives Khan’s Entity trait for a struct and generates its typed CRUD helpers.
Fields
Generates a field-name enum for a struct without deriving Entity.
JsonSchema