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

9.2 KiB

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):

// 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:

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:

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:

@[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:

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:

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:

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:

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:

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.