Lazy
Lazy envolve um schema para evitar a desnormalização antecipada de campos de relacionamento. Durante a desnormalização da entity pai, o campo mantém seu valor normalizado bruto (chaves primárias/IDs). O relacionamento pode então ser resolvido sob demanda via useQuery, usando o acessor .query.
Isso é útil para:
- Grafos bidirecionais grandes que estourariam a call stack durante a desnormalização recursiva
- Otimização de desempenho, adiando a resolução de relacionamentos que nem sempre são necessários
- Isolamento de memoização — mudanças em entities lazy não invalidam a forma desnormalizada do pai
Construtor
new Lazy(innerSchema)
innerSchema: Qualquer Schema — uma Entity, uma forma abreviada de array como[MyEntity], uma Collection, etc.
Uso
Relacionamento de array (mais comum)
import { Entity, Lazy } from '@data-client/rest';
class Building extends Entity {
id = '';
name = '';
}
class Department extends Entity {
id = '';
name = '';
buildings: string[] = [];
static schema = {
buildings: new Lazy([Building]),
};
}
Quando um Department é desnormalizado, dept.buildings conterá chaves primárias brutas (por exemplo, ['bldg-1', 'bldg-2']) em vez de instâncias de Building resolvidas.
Para resolver os buildings, use useQuery com o acessor .query:
import { useQuery } from '@data-client/react';
import { Department } from './Department';
function DepartmentBuildings({ dept }: { dept: Department }) {
// dept.buildings contains raw IDs: ['bldg-1', 'bldg-2']
const buildings = useQuery(Department.schema.buildings.query, dept.buildings);
// buildings: Building[] | undefined
if (!buildings) return null;
return (
<ul>
{buildings.map(b => <li key={b.id}>{b.name}</li>)}
</ul>
);
}
Relacionamento com uma única entity
class Department extends Entity {
id = '';
name = '';
mainBuilding = '';
static schema = {
mainBuilding: new Lazy(Building),
};
}
// dept.mainBuilding is a raw PK string: 'bldg-1'
const building = useQuery(
Department.schema.mainBuilding.query,
{ id: dept.mainBuilding },
);
Quando o schema interno é uma Entity (ou qualquer schema com queryKey), LazyQuery delega para o queryKey dele — então você passa os mesmos args que usaria para consultar essa entity diretamente.
Relacionamento com Collection
class Department extends Entity {
id = '';
static schema = {
buildings: new Lazy(buildingsCollection),
};
}
const buildings = useQuery(
Department.schema.buildings.query,
...collectionArgs,
);
.query
Retorna uma instância de LazyQuery adequada para o useQuery. O LazyQuery:
queryKey(args)— Se o schema interno tem umqueryKey(Entity, Collection, etc.), delega para ele. Caso contrário, retornaargs[0]diretamente (para schemas de array/objeto, nos quais você passa o valor normalizado bruto).denormalize(input, delegate)— Delega para o schema interno, resolvendo IDs em instâncias completas de entity.
O getter .query sempre retorna a mesma instância (em cache).
Como funciona
Normalização
Lazy.normalize delega para o schema interno. As entities são armazenadas nas tabelas de entities normalizadas como de costume — Lazy não tem efeito na normalização.
Desnormalização (caminho do pai)
Lazy.denormalize é uma operação nula — retorna a entrada inalterada. Quando EntityMixin.denormalize itera sobre os campos do schema e encontra um campo Lazy, o dispatch de unvisit chama Lazy.denormalize, que simplesmente repassa as PKs brutas. Nenhuma entity aninhada é visitada e nenhuma dependência é registrada no cache.
Desnormalização (caminho do useQuery)
Ao usar useQuery(lazyField.query, ...), LazyQuery.denormalize delega para o schema interno via unvisit, resolvendo IDs em instâncias completas de entity por meio do pipeline normal de desnormalização. Isso roda em seu próprio escopo de MemoCache.query(), com rastreamento de dependências e GC independentes.
Características de desempenho
- Desnormalização do pai: Menos saltos de dependência (entities lazy são excluídas das deps). Hits de cache mais rápidos. Sem invalidação quando entities lazy mudam.
- Acesso via useQuery: Escopo de memo próprio, com
pathsecountRefpróprios. Mudanças em entities lazy só re-renderizam os componentes que chamaramuseQuery, não o pai. - Sem overhead de Proxy/getter: IDs brutos são valores simples. A resolução completa só acontece por meio de
useQuery, usando o caminho normal de desnormalização.