Files
herolib/aiprompts/ai_instructions_hero_models.md

6.5 KiB

HeroDB Model Creation Instructions for AI

Overview

This document provides clear instructions for AI agents to create new HeroDB models similar to message.v. These models are used to store structured data in Redis using the HeroDB system. The message.v example can be found in lib/hero/heromodels/message.v.

Key Concepts

  • Models must implement serialization/deserialization using the encoder module
  • Models inherit from the Base struct which provides common fields
  • The database uses a factory pattern for model access

File Structure

Create a new file in lib/hero/heromodels/ with the model name (e.g., calendar.v).

Required Components

1. Model Struct Definition

Define your model struct with the following pattern:

@[heap]
pub struct Calendar {
 db.Base // Inherit from Base struct
pub mut:
 // Add your specific fields here
 title       string
 start_time  i64
 end_time    i64
 location    string
 attendees   []string
}

2. Type Name Method

Implement a method to return the model's type name:

pub fn (self Calendar) type_name() string {
 return 'calendar'
}

3. Serialization (dump) Method

Implement the dump method to serialize your struct's fields using the encoder:

pub fn (self Calendar) dump(mut e &encoder.Encoder) ! {
 e.add_string(self.title)
 e.add_i64(self.start_time)
 e.add_i64(self.end_time)
 e.add_string(self.location)
 e.add_list_string(self.attendees)
}

4. Deserialization (load) Method

Implement the load method to deserialize your struct's fields:

fn (mut self DBCalendar) load(mut o Calendar, mut e &encoder.Decoder) ! {
 o.title = e.get_string()!
 o.start_time = e.get_i64()!
 o.end_time = e.get_i64()!
 o.location = e.get_string()!
 o.attendees = e.get_list_string()!
}

5. Model Arguments Struct

Define a struct for creating new instances of your model:

@[params]
pub struct CalendarArg {
pub mut:
 title      string @[required]
 start_time i64
 end_time   i64
 location   string
 attendees  []string
}

6. Database Wrapper Struct

Create a database wrapper struct for your model:

pub struct DBCalendar {
pub mut:
 db &db.DB @[skip; str: skip]
}

7. Factory Integration

Add your model to the ModelsFactory struct in factory.v:

pub struct ModelsFactory {
pub mut:
 calendar DBCalendar
 // ... other models
}

And initialize it in the new() function:

pub fn new() !ModelsFactory {
 mut mydb := db.new()!
 return ModelsFactory{
  messages: DBCalendar{
   db: &mydb
  }
  // ... initialize other models
 }
}

Encoder Methods Reference

Use these methods for serialization/deserialization:

Encoder (Serialization)

  • e.add_bool(val bool)
  • e.add_u8(val u8)
  • e.add_u16(val u16)
  • e.add_u32(val u32)
  • e.add_u64(val u64)
  • e.add_i8(val i8)
  • e.add_i16(val i16)
  • e.add_i32(val i32)
  • e.add_i64(val i64)
  • e.add_f32(val f32)
  • e.add_f64(val f64)
  • e.add_string(val string)
  • e.add_list_bool(val []bool)
  • e.add_list_u8(val []u8)
  • e.add_list_u16(val []u16)
  • e.add_list_u32(val []u32)
  • e.add_list_u64(val []u64)
  • e.add_list_i8(val []i8)
  • e.add_list_i16(val []i16)
  • e.add_list_i32(val []i32)
  • e.add_list_i64(val []i64)
  • e.add_list_f32(val []f32)
  • e.add_list_f64(val []f64)
  • e.add_list_string(val []string)

Decoder (Deserialization)

  • e.get_bool()!
  • e.get_u8()!
  • e.get_u16()!
  • e.get_u32()!
  • e.get_u64()!
  • e.get_i8()!
  • e.get_i16()!
  • e.get_i32()!
  • e.get_i64()!
  • e.get_f32()!
  • e.get_f64()!
  • e.get_string()!
  • e.get_list_bool()!
  • e.get_list_u8()!
  • e.get_list_u16()!
  • e.get_list_u32()!
  • e.get_list_u64()!
  • e.get_list_i8()!
  • e.get_list_i16()!
  • e.get_list_i32()!
  • e.get_list_i64()!
  • e.get_list_f32()!
  • e.get_list_f64()!
  • e.get_list_string()!

CRUD Methods Implementation

Create New Instance

pub fn (mut self DBCalendar) new(args CalendarArg) !Calendar {
 mut o := Calendar{
  title:      args.title
  start_time: args.start_time
  end_time:   args.end_time
  location:   args.location
  attendees:  args.attendees
  updated_at: ourtime.now().unix()
 }
 return o
}

Save to Database

pub fn (mut self DBCalendar) set(o Calendar) !Calendar {
 return self.db.set[Calendar](o)!
}

Retrieve from Database

pub fn (mut self DBCalendar) get(id u32) !Calendar {
 mut o, data := self.db.get_data[Calendar](id)!
 mut e_decoder := encoder.decoder_new(data)
 self.load(mut o, mut e_decoder)!
 return o
}

Delete from Database

pub fn (mut self DBCalendar) delete(id u32) ! {
 self.db.delete[Calendar](id)!
}

Check Existence

pub fn (mut self DBCalendar) exist(id u32) !bool {
 return self.db.exists[Calendar](id)!
}

List All Objects

pub fn (mut self DBCalendar) list() ![]Calendar {
 return self.db.list[Calendar]()!.map(self.get(it)!)
}

Example Usage Script

Create a .vsh script in examples/hero/heromodels/ to demonstrate usage:

#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run

import incubaid.herolib.core.redisclient
import incubaid.herolib.hero.heromodels

mut mydb := heromodels.new()!

// Create a new object
mut o := mydb.calendar.new(
 title: 'Meeting'
 start_time: 1672531200
 end_time: 1672534800
 location: 'Conference Room'
 attendees: ['john@example.com', 'jane@example.com']
)!

// Save to database
oid := mydb.calendar.set(o)!
println('Created object with ID: ${oid}')

// Retrieve from database
mut o2 := mydb.calendar.get(oid)!
println('Retrieved object: ${o2}')

// List all objects
mut objects := mydb.calendar.list()!
println('All objects: ${objects}')

Best Practices

  1. Always inherit from db.Base struct
  2. Implement all required methods (type_name, dump, load)
  3. Use the encoder methods for consistent serialization
  4. Handle errors appropriately with ! or or blocks
  5. Keep field ordering consistent between dump and load methods
  6. Use snake_case for field names
  7. Add @[required] attribute to mandatory fields in argument structs
  8. Initialize timestamps using ourtime.now().unix()

Implementation Steps Summary

  1. Create model struct inheriting from db.Base
  2. Implement type_name() method
  3. Implement dump() method using encoder
  4. Implement load() method using decoder
  5. Create argument struct with @[params] attribute
  6. Create database wrapper struct
  7. Add model to ModelsFactory in factory.v
  8. Implement CRUD methods
  9. Create example usage script
  10. Test the implementation with the example script