I'm using Gorm ORM and have a polymorphic association set up between Items and the subtypes Weapon/Armor/Jewelry.
type Item struct {
models.Model
// see https://gorm.io/docs/has_many.html#Polymorphism-Association
SubID string
SubType string
CraftedBy string
}
type ItemWeaponSubtype struct {
models.Model
Items []Item `gorm:"polymorphic:Sub;polymorphicValue:weapon"`
Name string
Quality string `gorm:"type:varchar(20)""`
Material string `gorm:"type:varchar(20)""`
EquipmentSlotId string
DamageBonuses
}
I want to be able to have a list of item names (e.g. for an inventory listing). Ultimately I want to be able to get out any other common attributes that are shared between all the subtypes (like maybe a weight, cost, etc).
I'm not happy with the "solution" that I have and I think that there has to be a better way to do this. Could anybody with more experience than me show me a pattern that accomplishes this?
My idea was to have a nested function that is able to build up the DTO that has the common attributes.
But I will need a switch statement for every item type that I want to support.
// ItemCommonDetails contains fields that all subtypes have and is useful for displaying inventory lists etc
type ItemCommonDetails struct {
Name string
}
func (ir *ItemRepository) GetItemCommonDetailsFromId(itemId string) (ItemCommonDetails, error) {
var item models.Item
result := ir.db.First(&item, "id = ?", itemId)
if 0 == result.RowsAffected {
return ItemCommonDetails{Name: "Err!"}, &common_dto.StatusError{Code: http.StatusNotFound, Message: "Item [" + itemId + "] not found"}
}
defineReturn := func(result *gorm.DB, name string) (ItemCommonDetails, error) {
if result.RowsAffected == 0 {
return ItemCommonDetails{Name: "Err!"}, &common_dto.StatusError{Code: http.StatusNotFound, Message: "Item [" + itemId + "] not found"}
}
return ItemCommonDetails{Name: name}, nil
}
switch item.SubType {
case "weapon":
var weapon models.ItemWeaponSubtype
result := ir.db.First(&weapon, "id = ?", item.SubID)
return defineReturn(result, weapon.Name)
case "armor":
var armor models.ItemArmorSubtype
result := ir.db.First(&armor, "id = ?", item.SubID)
return defineReturn(result, armor.Name)
case "jewelry":
var jewelry models.ItemJewelrySubtype
result := ir.db.First(&jewelry, "id = ?", item.SubID)
return defineReturn(result, jewelry.Name)
default:
return ItemCommonDetails{Name: "Err!"}, &common_dto.StatusError{Code: http.StatusNotFound, Message: "Item [" + itemId + "] not found"}
}
}
Is there a more general way to do this? I can't find anything in the Gorm documentation that lets you magically pull the subtype from the Item. I think this would be hard to type hint properly, but maybe some sort of reflection method exists that would let me pull out common attributes?