Pular para o conteúdo principal

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 um queryKey (Entity, Collection, etc.), delega para ele. Caso contrário, retorna args[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 paths e countRef próprios. Mudanças em entities lazy só re-renderizam os componentes que chamaram useQuery, 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.