Saltar a contenido

Columnas calculadas y jerarquías

Columnas calculadas

Una columna calculada es una columna física cuyo valor se deriva de otras columnas de la misma fila. No es una propiedad de Python: existe en la base de datos, se puede filtrar y se puede ordenar por ella.

Hay dos formas de declararla, equivalentes, y se pueden mezclar en la misma tabla:

El tipo de retorno col[...] ya la declara.

class Usuario(Table):
    __tablename__ = 'usuario'

    nombre: col[str]
    apellido: col[str]

    def nombre_completo(self) -> col[str]:
        return f'{self.nombre} {self.apellido}'

Obligatorio en v1, donde el retorno es un tipo desnudo.

class Tarea(Table):
    __tablename__ = 'tarea'

    inicio: Optional[datetime]
    fin: Optional[datetime]

    @calculated_column
    def duracion_horas(self) -> Optional[float]:
        if self.fin is None or self.inicio is None:
            return None
        return (self.fin - self.inicio).total_seconds() / 3600

Sin col[...] ni decorador, un método es solo un método

Un -> str desnudo y sin @calculated_column no declara una columna, y no avisa. Es justo lo que impide que feed() o cualquier helper de la tabla acaben convertidos en columnas.

Reglas

  • Una calculada que pida parámetros además de self es un error de análisis: el valor sale de la propia fila y no hay de dónde sacarlos.
  • El orden de las calculadas sigue al fichero, y afecta al orden de columnas en el DDL y en los DTOs.
  • Una columna que el feed() no rellena vale None dentro de la calculada, igual que es NULL en la base de datos.

Qué hace el generador con ellas

Transpila el cuerpo del método a dos cosas:

  1. El cuerpo Python que recalcula la columna cada vez que el cliente escribe la fila.
  2. Cuando la expresión es traducible —una expresión pura, sin pasos intermedios—, una expresión SQLAlchemy equivalente, con la que se puede filtrar y ordenar directamente en la consulta.

Si la expresión no es traducible, la columna sigue funcionando: solo pierde la segunda mitad.

tai-sql pull no las puede reconstruir

Una calculada es una columna física, y en la base de datos no queda rastro de cómo se calcula. Al adoptar una base de datos existente, aparecerá como una columna normal.

Jerarquías: self_reference

Una columna que apunta a la clave primaria de su propia tabla declara una jerarquía:

class Equipo(Table):
    __tablename__ = 'equipo'

    id: col[int] = column(primary_key=True, autoincrement=True)
    nombre: col[str]
    equipo_superior: col[int | None] = column(self_reference='id')

El valor de self_reference es el nombre de la columna a la que apunta, normalmente la clave primaria.

A cambio, el cliente generado gana consultas recursivas sobre esa tabla —ancestros, descendientes y árbol completo— y el diagrama ER la dibuja como jerarquía. Ver consultas jerárquicas.