Saltar al contenido principal

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 enlaceDónde queda fijadoCómo se escribe
Un pool sortea de un poolpor miembro — este médico trabaja en esa clínica, siempre<gen type="pool"> dentro de un <pool>
Dos referencias de una fila concuerdanpor fila — la enfermera de este paciente es de la clínica de su médicofilter= 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>
./run clinics.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)
La salida es ilustrativa

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. at nombra 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:

./run clinics.tdc
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>
./run team.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>
./run clinic.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