#sqlx #entity #primary-key #kali #kali-macros

macro kali-macros

Macros for kali, a query builder and orm-ish crate built on sqlx

1 unstable release

Uses new Rust 2024

new 0.1.0 May 15, 2025

#757 in Procedural macros

Download history 58/week @ 2025-05-10

58 downloads per month
Used in kali

MIT license

20KB
466 lines

kali

[!CAUTION] This is a work in progress and is not ready for even alpha use yet.

a query builder and orm-ish crate for rust, built on sqlx

todo

  • updating entities
  • optional relations
  • support for joins and preloading collections/relations with them
  • support for streaming collections
  • support for caching relations
    • try_unwrap() and unwrap()
    • load() and load_all() use cached data when available, otherwise loads and caches
  • codegen cli
    • generate entities from an existing database
    • avoids the entities getting out of sync with the database
    • allow mapping types
      • option 1: #[map_type(bool, optional_transformer)] which is read by the codegen before overwriting the file
      • option 2: toml config file that specifies custom mappings

example

#[kali::entity]
#[derive(Debug, sqlx::FromRow)]
struct User {
    // optional, defaults to `id`
    #[primary_key]
    id: i32,

    #[relation(referenced_by = user)]
    profile: Reference<Profile>,

    #[relation(referenced_by = user)]
    posts: Collection<Post>
}

#[kali::entity]
#[derive(Debug, sqlx::FromRow)]
struct Profile {
    #[primary_key]
    id: i32,

    nickname: Option<String>,
    
    // references is optional, defaults to the primary key of the referenced entity
    #[relation(foreign_key = id, references = id)]
    user: Reference<User>
}

#[kali::entity]
#[derive(Debug, sqlx::FromRow)]
struct Post {
    #[primary_key]
    id: i32,

    title: String,

    content: String,

    author_id: i32,

    #[relation(foreign_key = author_id, references = id)]
    author: Reference<User>
}

// Finding an entity
let user = User::fetch_one(&db, 1).await?;
let profile = user.profile().load(&db).await?;

// Finding an entity with a filter
let found_user = User::query()
    .where(User::Username.eq("test"))
    .where(User::Id.gt(1))
    .order_by(User::Id.asc())
    .fetch_one(&db)
    .await?;

// Deleting an entity by id
User::delete_one(&db, 1).await?;

// Escape hatch
let user: User = sqlx::query_as("SELECT * FROM users WHERE id = $1")
    .bind(1)
    .fetch_one(&db)
    .await?;

Dependencies

~185–610KB
~14K SLoC