golem
golem copied to clipboard
Evaluate a concept of field selector for the `hseq`
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)
}