Constraints e índices¶
column(unique=True) y column(index=True) hablan de una columna. Lo que abarca varias va
en __constraints__:
class Asignacion(Table):
__tablename__ = 'asignacion'
__constraints__ = [
unique_constraint('usuario_id', 'rol_id'),
index_constraint('usuario_id', 'creado_en'),
]
class Usuario(Table):
__tablename__ = 'usuario'
__constraints__ = unique_constraint('tenant_id', 'email') # uno solo, sin lista
method es el tipo de índice del motor ('btree', 'hash', 'gin', 'hnsw'…), cuando el
motor lo admite.
Las reglas duras¶
El orden de las columnas es significativo
Y se preserva. En un índice, el prefijo por la izquierda decide para qué consultas sirve:
('a','b') no es lo mismo que ('b','a').
Una sola forma de decir cada cosa
- Una
unique_constraintde una sola columna es un error: para eso estácolumn(unique=True). - Un
index_constraintde una sola columna solo vale si pideunique=Trueomethod=..., que es justo lo quecolumn(index=True)no sabe expresar.
Una lista de cadenas se rechaza
__constraints__ = ['a', 'b'] no dice si es una constraint sobre las dos columnas o dos
constraints de una columna. Hay que usar los constructores.
Además:
- Se declaran sobre columnas físicas, no sobre relaciones:
usuario_id, nousuario. El análisis detecta ese caso concreto y lo dice. - El nombre no se declara: lo fija tai-sql de forma determinista, y es el mismo que emiten el DDL y el cliente generado.
Cómo se nombran¶
| Objeto | Patrón |
|---|---|
| Restricción de unicidad | uq_<tabla>_<col1>_<col2> |
| Índice | ix_<tabla>_<col1>_<col2> |
| Índice único | uix_<tabla>_<col1>_<col2> |
Que el nombre sea determinista es lo que permite que push sepa qué eliminar: un nombre
inventado por el motor hacía que el DROP CONSTRAINT no acertara nunca.
Un índice ajeno no se elimina nunca
Si un índice no lleva esa convención de nombres, push da por hecho que lo creó alguien a
mano y lo respeta, aunque el schema no lo declare. Es deliberado.
Una unique compuesta es también la clave natural¶
tai-sql feed hace upsert sobre la clave natural de la tabla, y esa clave es una
unique_constraint. Una tabla sin ninguna, cuya clave primaria sea autoincremental, no tiene
clave de conflicto: el feed corta con un error en vez de duplicar filas en cada pasada.
class Rol(Table):
__tablename__ = 'rol'
__constraints__ = unique_constraint('nombre', 'tenant_id') # ← clave natural
Ver feed().
Lo que push valida antes de crear una unique¶
Añadir una restricción de unicidad sobre una columna que ya tiene duplicados es una operación
BLOCKED: push corta y te dice cómo resolverlo, en vez de fallar a mitad. Lo mismo con una
FK nueva que dejaría filas huérfanas. Ver tai-sql push.