4.9 KiB
4.9 KiB
OSIRIS Derive Macro
The #[derive(DeriveObject)] macro automatically implements the Object trait for your structs, generating index keys based on fields marked with #[index].
Usage
use osiris::{BaseData, DeriveObject};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
#[derive(Debug, Clone, Serialize, Deserialize, DeriveObject)]
pub struct Note {
pub base_data: BaseData,
#[index]
pub title: Option<String>,
pub content: Option<String>,
#[index]
pub tags: BTreeMap<String, String>,
}
What Gets Generated
The derive macro automatically implements:
object_type()- Returns the struct name as a stringbase_data()- Returns a reference tobase_database_data_mut()- Returns a mutable reference tobase_dataindex_keys()- Generates index keys for all#[index]fieldsindexed_fields()- Returns a list of indexed field names
Supported Field Types
Option
#[index]
pub title: Option<String>,
Generates: IndexKey { name: "title", value: <string_value> } (only if Some)
BTreeMap<String, String>
#[index]
pub tags: BTreeMap<String, String>,
Generates: IndexKey { name: "tags:tag", value: "key=value" } for each entry
Vec
#[index]
pub items: Vec<String>,
Generates: IndexKey { name: "items:item", value: "0:value" } for each item
OffsetDateTime
#[index]
pub start_time: OffsetDateTime,
Generates: IndexKey { name: "start_time", value: "2025-10-20" } (date only)
Enums and Other Types
#[index]
pub status: EventStatus,
Generates: IndexKey { name: "status", value: "Debug(status)" } (using Debug format)
Complete Example
use osiris::{BaseData, DeriveObject};
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum EventStatus {
Draft,
Published,
Cancelled,
}
#[derive(Debug, Clone, Serialize, Deserialize, DeriveObject)]
pub struct Event {
pub base_data: BaseData,
#[index]
pub title: String,
pub description: Option<String>,
#[index]
#[serde(with = "time::serde::timestamp")]
pub start_time: OffsetDateTime,
#[index]
pub location: Option<String>,
#[index]
pub status: EventStatus,
pub all_day: bool,
#[index]
pub category: Option<String>,
}
impl Event {
pub fn new(ns: String, title: impl ToString) -> Self {
let now = OffsetDateTime::now_utc();
Self {
base_data: BaseData::new(ns),
title: title.to_string(),
description: None,
start_time: now,
location: None,
status: EventStatus::Draft,
all_day: false,
category: None,
}
}
}
Generated Index Keys
For the Event example above with:
title = "Team Meeting"start_time = 2025-10-20T10:00:00Zlocation = Some("Room 101")status = EventStatus::Publishedcategory = Some("work")
The generated index keys would be:
vec![
IndexKey { name: "mime", value: "application/json" }, // from base_data
IndexKey { name: "title", value: "Team Meeting" },
IndexKey { name: "start_time", value: "2025-10-20" },
IndexKey { name: "location", value: "Room 101" },
IndexKey { name: "status", value: "Published" },
IndexKey { name: "category", value: "work" },
]
HeroDB Storage
These index keys are stored in HeroDB as:
idx:events:title:Team Meeting → {event_id}
idx:events:start_time:2025-10-20 → {event_id}
idx:events:location:Room 101 → {event_id}
idx:events:status:Published → {event_id}
idx:events:category:work → {event_id}
Querying by Index
use osiris::store::GenericStore;
let store = GenericStore::new(client);
// Get all events on a specific date
let ids = store.get_ids_by_index("events", "start_time", "2025-10-20").await?;
// Get all published events
let ids = store.get_ids_by_index("events", "status", "Published").await?;
// Get all events in a category
let ids = store.get_ids_by_index("events", "category", "work").await?;
Requirements
- Must have
base_datafield: The struct must have a field namedbase_dataof typeBaseData - Must derive standard traits:
Debug,Clone,Serialize,Deserialize - Fields marked with
#[index]: Only fields with the#[index]attribute will be indexed
Limitations
- The macro currently uses
Debugformatting for enums and complex types - BTreeMap indexing assumes
Stringkeys and values - Vec indexing uses numeric indices (may not be ideal for all use cases)
Future Enhancements
- Custom index key formatters via attributes
- Support for nested struct indexing
- Conditional indexing (e.g.,
#[index(if = "is_published")]) - Custom index names (e.g.,
#[index(name = "custom_name")])