У меня есть следующая таблица в sqlalchemy:
class FieldType(enum.Enum):
INT_FIELD = 0
FLOAT_FIELD = 1
STRING_FIELD = 2
class EAVTable(Base):
__tablename__ = 'EAVTable'
field_name = Column(Stirng, primary_key=True)
field_type = Column(Enum(FieldType))
int_field = Column(Integer)
float_field = Column(Float)
string_field = Column(String)
Это модель EAV , которая соответствует моим бизнес-целям.
Теперь, чтобы легко использовать его в коде, у меня есть следующее hybrid_property
.
@hybrid_propderty
def value(self):
if self.field_type == FieldType.INT_FIELD:
return self.int_field
...
@value.setter
def value(self, value):
if type(value) == int:
self.field_type = FieldType.INT_FIELD
self.int_field = value
...
Это прекрасно работает, когда я пытаюсь получить и установить поля в коде Python. Но у меня все еще есть проблема:
session.query(EAVTable).filter(EAVTable.value == 123)
Это не работает "из коробки", но у меня была идея использовать hybrid.expression, где мы используем оператор case:
@value.expression
def value(cls):
return case(
[
(cls.field_type == FieldType.INT_FIELD, cls.int_field),
(cls.field_type == FieldType.FLOAT_FIELD, cls.float_field),
...
]
)
Теоретически это работает, например, SQL, сгенерированный для запроса session.query(EAVTable.value = 123
, выглядит следующим образом:
select * from where case
when field_type = INT_FIELD then int_field
when field_type = FLOAT_FIELD then float_field
when field_type = STRING_FIELD then string_field
end = 123;
Это семантически похоже на то, что мне нравится, но позже я обнаружил, что выражение case
требует, чтобы все случаи имели одинаковый тип, или они приводятся к одному и тому же типу.
Я понимаю, что это требование языка SQL и не имеет ничего общего с sqlachemy, но для более опытного пользователя sqlalchemy есть ли простой способ сделать то, чего я хочу достичь? Есть ли способ обойти это ограничение?