Enlazar pools entre sí
Un pool le da a una fila un registro coherente. Varios pools le dan a una fila un mundo coherente: clínicas que existen, médicos que trabajan en una de ellas, enfermeras que trabajan junto a esos médicos. Esta página trata de cómo se conectan las piezas.
Hay exactamente dos maneras de enlazar, y responden preguntas distintas:
| El enlace | Dónde queda fijado | Cómo se escribe |
|---|---|---|
| Un pool sortea de un pool | por miembro — este médico trabaja en esa clínica, siempre | <gen type="pool"> dentro de un <pool> |
| Dos referencias de una fila concuerdan | por fila — la enfermera de este paciente es de la clínica de su médico | filter= nombrando el campo de otra referencia |
La primera construye el mundo. La segunda mantiene unida una fila.
Un pool que sortea de un pool
Un miembro de un pool puede contener un miembro entero de otro. Los médicos pertenecen a clínicas:
<tdc>
<env count="8" seed="probe" local="en">
<pool name="Clinics" count="3">
<sequence name="city" uniq="true"><gen type="text" value="North,South,East"/></sequence>
<sequence name="phone"><gen type="number" value="100..999"/></sequence>
</pool>
<pool name="Doctors" count="5">
<sequence name="name"><gen type="template" value="person.lastName"/></sequence>
<sequence name="at"><gen type="pool" value="Clinics"/></sequence>
</pool>
<sequence name="Seen"><gen type="pool" value="Doctors"/></sequence>
</env>
<block>
<line><data>Dr. ${{Seen.name}} @ ${{Seen.at.city}} (tel ${{Seen.at.phone}})</data></line>
</block>
</tdc>
Dr. Johnson @ North (tel 825) Dr. Johnson @ North (tel 825) Dr. Williams @ East (tel 997) Dr. Brown @ South (tel 415) Dr. Brown @ South (tel 415) Dr. Williams @ East (tel 997) Dr. Smith @ East (tel 997) Dr. Williams @ East (tel 997)
Los valores vienen de un seed fijo, así que son reproducibles, pero las cadenas exactas
pueden cambiar entre versiones del núcleo. Tómalos como ejemplo de forma, no como
garantía.
Tres hechos que se leen en esa salida:
- El punto baja un nivel más.
atnombra una clínica entera, así que no tiene valor propio; sus campos son${{Seen.at.city}}y${{Seen.at.phone}}. Escribir${{Seen.at}}se rechaza por la misma razón que${{Seen}}. - El enlace queda fijado por miembro, no por fila. El Dr. Jones está en la clínica East en todas las filas donde aparece, porque la clínica se decidió cuando se construyó el médico.
- Los campos de la clínica viajan juntos. East siempre es 300 — el teléfono pertenece al registro de la clínica, no a la fila.
La regla del orden
Un pool solo puede sortear de un pool declarado encima. Los pools se construyen en el orden en que se escriben, así que un pool nombrado más abajo todavía no tiene tabla:
error[TDC236]: pool "Doctors" draws from "Clinics", which is not declared above it --> clinics.tdc:5:7 | 5 | <sequence name="at"><gen type="pool" value="Clinics"/></sequence> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: Pools are built in declaration order, so a pool can only read the pools above it. Move "Clinics" above "Doctors". That order is also why a cycle between pools cannot be written down.
Esa regla hace un segundo trabajo gratis: un ciclo entre pools no se puede escribir. No
hay detección de ciclos en ninguna parte de TDC, porque no hay nada que detectar —
Doctors alcanzando a Clinics es una búsqueda en una tabla, y Clinics alcanzando a
Doctors es un nombre que todavía no existe. Un pool que se nombra a sí mismo recibe el
mismo código, por la misma razón.
Hasta qué profundidad llega
Hasta donde la escriba. Cada nivel es un pool corriente que resulta contener una
referencia, así que ${{Seen.at.region.name}} no es un caso especial: son tres tablas y dos
enlaces.
El coste se queda donde uno querría: cada pool se construye una vez, antes de la ejecución, así que una cadena de tres niveles son tres tablas pequeñas y ningún trabajo por fila más allá de las elecciones.
Dos referencias que concuerdan
El segundo tipo de enlace es entre dos referencias de la misma fila. Un filter lee
las columnas de la fila actual, y los campos de una referencia son columnas como
cualquiera — así que una enfermera puede acotarse a la clínica en la que trabaja el médico
de la fila:
<tdc>
<env count="8" seed="clinic" local="en">
<pool name="Clinics" count="3">
<sequence name="city" uniq="true"><gen type="text" value="North,South,East"/></sequence>
</pool>
<pool name="Doctors" count="6">
<sequence name="name"><gen type="template" value="person.lastName"/></sequence>
<sequence name="at"><gen type="pool" value="Clinics"/></sequence>
</pool>
<pool name="Nurses" count="9">
<sequence name="name"><gen type="template" value="person.female.firstName"/></sequence>
<sequence name="city"><gen type="text" value="North,South,East"/></sequence>
</pool>
<sequence name="Seen"><gen type="pool" value="Doctors"/></sequence>
<sequence name="Assisted"><gen type="pool" value="Nurses" filter="city == Seen.at.city"/></sequence>
</env>
<block>
<line><data>Dr. ${{Seen.name}} (${{Seen.at.city}}) + nurse ${{Assisted.name}} (${{Assisted.city}})</data></line>
</block>
</tdc>
Dr. Smith (South) + nurse Margaret (South) Dr. Garcia (East) + nurse Linda (East) Dr. Williams (South) + nurse Margaret (South) Dr. Brown (North) + nurse Dorothy (North) Dr. Garcia (East) + nurse Linda (East) Dr. Garcia (East) + nurse Linda (East) Dr. Jones (East) + nurse Jennifer (East) Dr. Smith (South) + nurse Susan (South)
El filtro atraviesa dos enlaces en una sola expresión: Seen.at.city es la ciudad de la
clínica del médico de la fila. Nada especial lo hace posible — Seen.at.city ya es una
columna de la fila cuando se construye Assisted, porque las referencias se resuelven en
orden de declaración, igual que las secuencias.
Lo que significa que aquí rige la misma regla que en todo <env>: la referencia por la
que filtras tiene que estar declarada encima de la que filtra. Intercambia Seen y
Assisted y el filtro leerá un nombre que nada ha producido todavía.
Un ejemplo completo
Tres niveles, cuatro tipos de enlace, una configuración. Las clínicas existen; los médicos pertenecen a una clínica y tienen una especialidad en una proporción fija; un paciente necesita una especialidad y le atiende un médico que la tiene.
<tdc>
<env count="10" seed="clinic" local="en">
<pool name="Clinics" count="3">
<sequence name="city" uniq="true"><gen type="text" value="North,South,East"/></sequence>
<sequence name="phone"><gen type="number" value="200..299"/></sequence>
</pool>
<pool name="Doctors" count="8">
<sequence name="name"><gen type="template" value="person.lastName"/></sequence>
<mix name="role" percent="25,75">
<case><gen type="text" value="surgeon"/></case>
<case><gen type="text" value="therapist"/></case>
</mix>
<sequence name="at"><gen type="pool" value="Clinics"/></sequence>
</pool>
<sequence name="Patient"><gen type="template" value="person.female.firstName"/></sequence>
<sequence name="Needs"><gen type="text" value="surgeon,therapist" percent="30,70"/></sequence>
<sequence name="Seen"><gen type="pool" value="Doctors" filter="role == Needs"/></sequence>
</env>
<block>
<line><data>${{Patient}} needs a ${{Needs}} -> Dr. ${{Seen.name}}, ${{Seen.at.city}} clinic, tel ${{Seen.at.phone}}</data></line>
</block>
</tdc>
Barbara needs a therapist -> Dr. Jones, South clinic, tel 233 Mary needs a therapist -> Dr. Garcia, East clinic, tel 255 Dorothy needs a therapist -> Dr. Davis, South clinic, tel 233 Jennifer needs a therapist -> Dr. Brown, North clinic, tel 233 Elizabeth needs a surgeon -> Dr. Williams, South clinic, tel 233 Patricia needs a surgeon -> Dr. Williams, South clinic, tel 233 Susan needs a therapist -> Dr. Miller, East clinic, tel 255 Sarah needs a surgeon -> Dr. Williams, South clinic, tel 233 Margaret needs a therapist -> Dr. Davis, South clinic, tel 233 Linda needs a therapist -> Dr. Brown, North clinic, tel 233
Cada restricción de esa configuración se cumple en todas las filas, y ninguna se escribió dos veces:
- Dos de los ocho médicos son cirujanos, porque
percent="25,75"se aplica a los miembros. - El treinta por ciento de los pacientes necesita un cirujano, porque
percent="30,70"se aplica a las filas. Son poblaciones distintas y las dos son exactas. - Un paciente que necesita un cirujano recibe uno, porque
filter="role == Needs"acota los candidatos. - El teléfono siempre pertenece a la ciudad nombrada, porque la clínica es un registro que el médico lleva consigo.
Añada un cuarto nivel — una región a la que pertenece cada clínica — y la forma de la configuración no cambia. De eso trata la construcción.
Lo que no está soportado
- Un
<pool>dentro de un<pool>. Rechazado (TDC230). Un pool sigue siendo una tabla plana que podría imprimir; anidarlo lo convertiría en un árbol, y cada pregunta posterior — unicidad, filtrado, el techo de memoria — tendría que preguntar «¿a qué profundidad?». En su lugar, un pool apunta a otro, que es de lo que trata esta página. - Un pool que sortea de un pool por debajo, o de sí mismo. Rechazado (
TDC236), como arriba. - Pesos en los miembros. Un pool no tiene peso por miembro. Use un
<mix>dentro del pool — es lo mismo dicho en el idioma que el pool ya habla, y es exacto en vez de aproximado. - Una referencia con
parent=en un motor de streaming. No se rechaza: la configuración se encamina al motor en memoria, que necesita la columna entera del padre para saber qué filas existen.
Relacionado
- Resumen — qué es un pool, y el techo de tamaño
- Acotar con
filter— el lenguaje de expresiones en el que se escribe un enlace - Dependencias jerárquicas —
parent, la otra manera de relacionar filas entre sí