I have a Ship class, into which components can be added which change the performance of the ship.
The question is regarding modelling this. My first approach essentially was an EAV approach (a pseudocode example, roughly on Django Models, below).
class Item(model):
name = CharField
desc = TextField
class Attribute(model):
name = CharField
desc = TextField
class AttributeValue(model):
item = FKey(Item, related_name='attributes')
attribute = FKey(Attribute)
value = DecimalField(max_digits=100, decimal_places=2)
class Ship(model):
current_hp = Integer
vessel_class = FKey to a table containing the base attributes of a given class (hp, manoeuvre etc.)
@property
def max_hp(self):
base_hp = ship.vessel_class.hp
base_hp += reduce(lambda x, y: x+y, [item.attributes.get(attribute__name='modifies_hp').value for item in s.components.filter(attributes__attribute__name='modifies_hp')])
This requires a multitude of joins to get to the total hp of a given object.
An alternative (using postgres' JSONB)
class Item(model):
name = CharField
desc = TextField
attributes = JSONField
class Ship(model):
@property
def max_hp(self):
return self.vessel_class.base_hp + reduce(lambda x, y: x+y, [item.attributes['hp_modifier'] for item in self.components.filter(attributes__has_key='hp_modifier')])
This feels tidier as it keeps the attributes of each Item tied to the Item, and additionally doesn't require further database lookups (as the returned Item object has the data already loaded, rather than requiring a further database lookup for the value of the attribute).
Any preference on a given approach?