golem icon indicating copy to clipboard operation
golem copied to clipboard

Evaluate a concept of field selector for the `hseq`

Open fogfish opened this issue 7 months ago • 0 comments

The idea of field selector has been discussed within https://github.com/fogfish/dynamo library

The core idea: The string literal is replaced with function. However, this might bring unnecessary complexity for solving small problem.

var (
    // These are completely type-safe - no strings!
    UpStoryPhoto = fieldsafe.UpdateForSafe(func(s *Story) **core.PhotoIRI { return &s.Photo })
    UpStoryEntry = fieldsafe.UpdateForSafe(func(s *Story) **core.EssayIRI { return &s.Essay })
)
package fieldsafe

import (
    "reflect"
    "strings"
    "unsafe"
)

// FieldPath extracts the DynamoDB field name from a field selector
func FieldPath[T any, F any](selector func(*T) *F) string {
    // Create a zero value of T
    var zero T
    ptr := &zero
    
    // Call the selector to get the field pointer
    fieldPtr := selector(ptr)
    
    // Calculate field offset
    basePtr := uintptr(unsafe.Pointer(ptr))
    fieldOffset := uintptr(unsafe.Pointer(fieldPtr)) - basePtr
    
    // Use reflection to find the field by offset
    t := reflect.TypeOf(zero)
    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        if field.Offset == fieldOffset {
            // Extract DynamoDB field name from tag
            tag := field.Tag.Get("dynamodbav")
            if tag != "" {
                name := strings.Split(tag, ",")[0]
                if name != "" {
                    return name
                }
            }
            return field.Name
        }
    }
    panic("field not found")
}

// Type-safe UpdateFor
func UpdateForSafe[T any, F any](selector func(*T) *F) ddb.UpdateItemExpression[T] {
    fieldName := FieldPath(selector)
    return ddb.UpdateFor[T, F](fieldName)
}

fogfish avatar Jun 28 '25 11:06 fogfish