Files
herolib/lib/threefold/models_ledger/fix.md
2025-10-12 16:02:34 +04:00

347 lines
9.2 KiB
Markdown

# Issues and Fixes for models_ledger Package
After reviewing the code in the models_ledger package, the following issues need to be fixed to align with the guidelines in the HeroModel instructions.
## 1. Missing API Description and Example Methods
### Issue
All model structs are missing the required `description()` and `example()` methods that are necessary for API documentation and testing.
### Fix
Add the following methods to each model struct (Account, Asset, DNSZone, Group, Member, Notary, Signature, Transaction, User, UserKVS, UserKVSItem):
```v
// API description method
pub fn (self ModelName) description(methodname string) string {
match methodname {
'set' { return 'Create or update a [model]. Returns the ID of the [model].' }
'get' { return 'Retrieve a [model] by ID. Returns the [model] object.' }
'delete' { return 'Delete a [model] by ID.' }
'exist' { return 'Check if a [model] exists by ID. Returns true or false.' }
'list' { return 'List all [models]. Returns an array of [model] objects.' }
else { return 'This is a method for [model] object' }
}
}
// API example method
pub fn (self ModelName) example(methodname string) (string, string) {
match methodname {
'set' {
return '{"model": {...}}', '1'
}
'get' {
return '{"id": 1}', '{...}'
}
'delete' {
return '{"id": 1}', 'true'
}
'exist' {
return '{"id": 1}', 'true'
}
'list' {
return '{}', '[{...}]'
}
else {
return '{}', '{}'
}
}
}
```
Replace `[model]` and fill in the example data with appropriate values for each model.
## 2. Missing API Handler Functions
### Issue
Each model requires an API handler function that processes RPC requests. These are missing for all models.
### Fix
Add handler functions for each model following this pattern:
```v
pub fn modelname_handle(mut f ModelsFactory, rpcid int, servercontext map[string]string, userref UserRef, method string, params string) !Response {
match method {
'get' {
id := db.decode_u32(params)!
res := f.modelname.get(id)!
return new_response(rpcid, json.encode_pretty(res))
}
'set' {
mut args := db.decode_generic[ModelNameArg](params)!
mut o := f.modelname.new(args)!
if args.id != 0 {
o.id = args.id
}
o = f.modelname.set(o)!
return new_response_int(rpcid, int(o.id))
}
'delete' {
id := db.decode_u32(params)!
f.modelname.delete(id)!
return new_response_true(rpcid)
}
'exist' {
id := db.decode_u32(params)!
if f.modelname.exist(id)! {
return new_response_true(rpcid)
} else {
return new_response_false(rpcid)
}
}
'list' {
ids := f.modelname.list()!
mut result := []ModelName{}
for id in ids {
result << f.modelname.get(id)!
}
return new_response(rpcid, json.encode_pretty(result))
}
else {
return new_error(rpcid,
code: 32601
message: 'Method ${method} not found on modelname'
)
}
}
}
```
## 3. Missing Import for json Module
### Issue
The API handler functions require the json module for encoding responses, but this import is missing.
### Fix
Add the following import to each model file:
```v
import json
```
## 4. Incomplete List Method Implementation
### Issue
The current list method simply returns all models without filtering capabilities or pagination.
### Fix
Update the list method to support filtering and pagination:
```v
@[params]
pub struct ModelNameListArg {
pub mut:
filter string
status int = -1
limit int = 20
offset int = 0
}
pub fn (mut self DBModelName) list(args ModelNameListArg) ![]ModelName {
mut all_models := self.db.list[ModelName]()!.map(self.get(it)!)
mut filtered_models := []ModelName{}
for model in all_models {
// Add filter logic based on model properties
if args.filter != '' && !model.name.contains(args.filter) && !model.description.contains(args.filter) {
continue
}
if args.status >= 0 && int(model.status) != args.status {
continue
}
filtered_models << model
}
// Apply pagination
mut start := args.offset
if start >= filtered_models.len {
start = 0
}
mut limit := args.limit
if limit > 100 {
limit = 100
}
if start + limit > filtered_models.len {
limit = filtered_models.len - start
}
if limit <= 0 {
return []ModelName{}
}
return filtered_models[start..start+limit]
}
```
Adapt the filtering logic based on the specific fields of each model.
## 5. Missing or Incomplete Tests
### Issue
The test_utils.v file exists but there are no actual test files for the models.
### Fix
Create test files for each model following the patterns described in README_TESTS.md:
1. Create files named `modelname_test.v` for each model
2. Implement CRUD tests for each model
3. Implement encoding/decoding tests
4. Add error handling tests
5. Add performance tests for complex models
Example test file structure:
```v
module models_ledger
fn test_modelname_crud() {
mut db := setup_test_db()!
mut model_db := DBModelName{db: db}
// Create test
mut model := model_db.new(ModelNameArg{...})!
model = model_db.set(model)!
assert model.id > 0
// Get test
retrieved := model_db.get(model.id)!
assert retrieved.field == model.field
// Update test
model.field = new_value
model = model_db.set(model)!
retrieved = model_db.get(model.id)!
assert retrieved.field == new_value
// Delete test
model_db.delete(model.id)!
assert model_db.exist(model.id)! == false
}
```
## 6. Missing ModelsFactory Integration
### Issue
There's no ModelsFactory implementation to initialize and manage all models together.
### Fix
Create a `models_factory.v` file with the following structure:
```v
module models_ledger
import incubaid.herolib.hero.db
pub struct ModelsFactory {
pub mut:
db &db.DB
account &DBAccount
asset &DBAsset
dnszone &DBDNSZone
group &DBGroup
member &DBMember
notary &DBNotary
signature &DBSignature
transaction &DBTransaction
user &DBUser
userkvs &DBUserKVS
userkvsitem &DBUserKVSItem
}
pub fn new_models_factory(mut database db.DB) !&ModelsFactory {
mut factory := &ModelsFactory{
db: database
}
factory.account = &DBAccount{db: database}
factory.asset = &DBAsset{db: database}
factory.dnszone = &DBDNSZone{db: database}
factory.group = &DBGroup{db: database}
factory.member = &DBMember{db: database}
factory.notary = &DBNotary{db: database}
factory.signature = &DBSignature{db: database}
factory.transaction = &DBTransaction{db: database}
factory.user = &DBUser{db: database}
factory.userkvs = &DBUserKVS{db: database}
factory.userkvsitem = &DBUserKVSItem{db: database}
return factory
}
```
## 7. Update delete() Method Return Type
### Issue
Current delete() methods don't return a boolean value indicating success, which is needed for API handlers.
### Fix
Update the delete() method in all models:
```v
pub fn (mut self DBModelName) delete(id u32) !bool {
if !self.db.exists[ModelName](id)! {
return false
}
self.db.delete[ModelName](id)!
return true
}
```
## 8. Missing Validation in Model Creation
### Issue
The new() methods don't validate input data before creating models.
### Fix
Add validation logic to each new() method:
```v
pub fn (mut self DBModelName) new(args ModelNameArg) !ModelName {
// Validate required fields
if args.required_field.trim_space() == '' {
return error('required_field cannot be empty')
}
// Validate numeric ranges
if args.numeric_field < min_value || args.numeric_field > max_value {
return error('numeric_field must be between ${min_value} and ${max_value}')
}
// Create the object
mut o := ModelName{...}
return o
}
```
## 9. Fix Imports in test_utils.v
### Issue
The test_utils.v file uses a simplified db.new() call that may not work correctly.
### Fix
Update the setup_test_db() function:
```v
fn setup_test_db() !db.DB {
return db.new(path: ':memory:')!
}
```
## Implementation Plan
1. First, fix test_utils.v to ensure tests can run properly
2. Create a models_factory.v file
3. Update each model file to:
- Add missing imports
- Add description() and example() methods
- Update the list() method with filtering capabilities
- Fix the delete() method return type
- Add validation to new() methods
4. Create test files for each model
5. Create API handler functions for each model
6. Create an integration test file to test the entire models factory
This approach ensures all models are consistent with the required patterns and properly integrated.