builder/specs.md

199 lines
5.5 KiB
Markdown

Here's an updated full project specification including:
1. ✅ Unified builder for both creation and filtering
2. ✅ with_...() methods used for both creation and filtering
3. ✅ Auto-generated CRUD + list + filter + find methods
4. ✅ Database interface for persistence operations
5. ✅ Auto-generated registration code
6. ✅ 📜 Example Rhai script
7. ✅ 🔍 build.rs should output to src/gen/meeting_builder.rs
🧾 Project Spec: Rust → Rhai Builder Code Generator
🎯 Goal
Build a build.rs script that parses Rust structs annotated with #[builder] and generates Rhai-compatible unified builders with with_...() methods that populate a single field map used for both creation and filtering. Also generate CRUD operations that use a database interface.
📥 Input Example: src/models.rs
#[derive(Debug)]
pub struct Meeting {
pub id: String,
pub title: String,
pub description: String,
pub participants: Vec<String>,
pub start: String,
}
📤 Generated Code: src/gen/meeting_builder.rs
✅ 1. MeetingBuilder Struct
#[derive(Clone)]
pub struct MeetingBuilder {
pub fields: std::collections::HashMap<String, rhai::Dynamic>,
}
✅ 2. with_...() Methods (for each field)
impl MeetingBuilder {
pub fn with_title(mut self, value: &str) -> Self {
self.fields.insert("title".into(), value.into());
self
}
pub fn with_participants(mut self, value: Vec<rhai::Dynamic>) -> Self {
self.fields.insert("participants".into(), value.into());
self
}
pub fn get_fields(&mut self) -> rhai::Map {
self.fields.clone()
}
// CRUD operations
pub fn create(&mut self, db: &dyn Database) -> rhai::Dynamic {
db.create("meetings", self.get_fields())
}
pub fn find_by_id(&mut self, db: &dyn Database, id: &str) -> rhai::Dynamic {
db.find_by_id("meetings", id)
}
pub fn update(&mut self, db: &dyn Database, id: &str) -> rhai::Dynamic {
db.update("meetings", id, self.get_fields())
}
pub fn delete(&mut self, db: &dyn Database, id: &str) -> rhai::Dynamic {
db.delete("meetings", id)
}
pub fn list(&mut self, db: &dyn Database) -> rhai::Dynamic {
db.list("meetings")
}
pub fn filter(&mut self, db: &dyn Database) -> rhai::Dynamic {
db.filter("meetings", self.get_fields())
}
pub fn find(&mut self, db: &dyn Database) -> rhai::Dynamic {
db.find("meetings", self.get_fields())
}
}
✅ 3. Database Interface
pub trait Database {
fn create(&self, collection: &str, fields: rhai::Map) -> rhai::Dynamic;
fn find_by_id(&self, collection: &str, id: &str) -> rhai::Dynamic;
fn update(&self, collection: &str, id: &str, fields: rhai::Map) -> rhai::Dynamic;
fn delete(&self, collection: &str, id: &str) -> rhai::Dynamic;
fn list(&self, collection: &str) -> rhai::Dynamic;
fn filter(&self, collection: &str, query: rhai::Map) -> rhai::Dynamic;
fn find(&self, collection: &str, query: rhai::Map) -> rhai::Dynamic;
}
✅ 4. Rhai Registration
pub fn register_meeting_module(engine: &mut rhai::Engine) {
engine.register_type::<MeetingBuilder>();
engine.register_fn("meeting", MeetingBuilder::new);
engine.register_fn("with_title", MeetingBuilder::with_title);
engine.register_fn("with_participants", MeetingBuilder::with_participants);
engine.register_fn("get_fields", MeetingBuilder::get_fields);
// Register CRUD operations
engine.register_fn("create", MeetingBuilder::create);
engine.register_fn("find_by_id", MeetingBuilder::find_by_id);
engine.register_fn("update", MeetingBuilder::update);
engine.register_fn("delete", MeetingBuilder::delete);
engine.register_fn("list", MeetingBuilder::list);
engine.register_fn("filter", MeetingBuilder::filter);
engine.register_fn("find", MeetingBuilder::find);
}
✅ Example Rhai Script
// Create a meeting
let meeting_id = meeting()
.with_title("Project Sync")
.with_description("Check in with the team")
.with_participants(["timur", "eda"])
.with_start("2024-06-01T10:00")
.create(db);
// Find a meeting by ID
let meeting = meeting().find_by_id(db, meeting_id);
// Update a meeting
meeting()
.with_description("Updated description")
.update(db, meeting_id);
// Delete a meeting
meeting().delete(db, meeting_id);
// List all meetings
let all_meetings = meeting().list(db);
// Filter meetings by description
let filtered_meetings = meeting()
.with_description("Project Sync")
.filter(db);
// Find a specific meeting
let found_meeting = meeting()
.with_title("Project Sync")
.with_start("2024-06-01T10:00")
.find(db);
This script uses the same builder for all operations.
📂 Output File
Write generated code to:
src/gen/meeting_builder.rs
And include it in main.rs:
#[path = "gen/meeting_builder.rs"]
mod meeting_builder;
🔨 build.rs Responsibilities
• Use syn to parse src/models.rs
• Extract structs and fields
• Generate:
• MeetingBuilder struct with fields map
• All with_...() methods for Rhai
• get_fields() method
• CRUD + list + filter + find methods
• Database trait
• register_meeting_module(engine: &mut Engine) function
Output to src/gen/meeting_builder.rs.
✅ Success Criteria
• No duplication between filter/create logic
• Fluent API in Rhai
• Generated code compiles and integrates
• build.rs works as part of standard Rust build pipeline
• Easy to extend to more models (e.g., User, Task)
• Complete CRUD operations available
• Database abstraction for persistence