Files
osiris/docs/DERIVE_MACRO.md
Timur Gordon 097360ad12 first commit
2025-10-20 22:24:25 +02:00

196 lines
4.9 KiB
Markdown

# 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
```rust
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:
1. **`object_type()`** - Returns the struct name as a string
2. **`base_data()`** - Returns a reference to `base_data`
3. **`base_data_mut()`** - Returns a mutable reference to `base_data`
4. **`index_keys()`** - Generates index keys for all `#[index]` fields
5. **`indexed_fields()`** - Returns a list of indexed field names
## Supported Field Types
### Option<T>
```rust
#[index]
pub title: Option<String>,
```
Generates: `IndexKey { name: "title", value: <string_value> }` (only if Some)
### BTreeMap<String, String>
```rust
#[index]
pub tags: BTreeMap<String, String>,
```
Generates: `IndexKey { name: "tags:tag", value: "key=value" }` for each entry
### Vec<T>
```rust
#[index]
pub items: Vec<String>,
```
Generates: `IndexKey { name: "items:item", value: "0:value" }` for each item
### OffsetDateTime
```rust
#[index]
pub start_time: OffsetDateTime,
```
Generates: `IndexKey { name: "start_time", value: "2025-10-20" }` (date only)
### Enums and Other Types
```rust
#[index]
pub status: EventStatus,
```
Generates: `IndexKey { name: "status", value: "Debug(status)" }` (using Debug format)
## Complete Example
```rust
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:00Z`
- `location = Some("Room 101")`
- `status = EventStatus::Published`
- `category = Some("work")`
The generated index keys would be:
```rust
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
```rust
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
1. **Must have `base_data` field**: The struct must have a field named `base_data` of type `BaseData`
2. **Must derive standard traits**: `Debug`, `Clone`, `Serialize`, `Deserialize`
3. **Fields marked with `#[index]`**: Only fields with the `#[index]` attribute will be indexed
## Limitations
- The macro currently uses `Debug` formatting for enums and complex types
- BTreeMap indexing assumes `String` keys 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")]`)