Invalidate
Descreve entidades a serem marcadas como INVALID. Isso remove itens de uma collection ou força o suspense em endpoints nos quais a entidade é obrigatória.
Construtor
new Invalidate(entity)
new Invalidate(union)
new Invalidate(entityMap, schemaAttribute)
entity: Uma Entity singular a invalidar.union: Um schema Union para invalidação polimórfica.entityMap: Um mapeamento de chaves de schema para Entities.schemaAttribute: opcional (obrigatório seentityMapfor usado) O atributo de cada entidade encontrada que define qual schema, conforme o entityMap, usar na normalização. Pode ser uma string ou uma função. Se for uma função, recebe os seguintes argumentos:value: O valor de entrada da entidade.parent: O objeto pai do array de entrada.key: A chave sob a qual o array de entrada aparece no objeto pai.
Uso
[{"id":"123","name":"Jim"},{"id":"456","name":"Jane"},{"id":"555","name":"Phone"}]
import { Entity, RestEndpoint, Collection, Invalidate } from '@data-client/rest'; class User extends Entity { id = ''; name = ''; } export const getUsers = new RestEndpoint({ path: '/users', schema: new Collection([User]), }); export const deleteUser = new RestEndpoint({ path: '/users/:id', method: 'DELETE', schema: new Invalidate(User), });
import { useSuspense, useController } from '@data-client/react'; import { getUsers, deleteUser } from './api/User'; function UsersPage() { const users = useSuspense(getUsers); const ctrl = useController(); return ( <div> {users.map(user => ( <div key={user.pk()}> {user.name}{' '} <span style={{ cursor: 'pointer' }} onClick={() => ctrl.fetch(deleteUser, { id: user.id })} > ❌ </span> </div> ))} </div> ); } render(<UsersPage />);
Invalidação em lote
Aqui adicionamos outro endpoint para excluir várias entidades de uma só vez, envolvendo
Invalidate em um array. O Data Client pode então fazer invalidate de cada
entidade da resposta.
import { resource, Invalidate } from '@data-client/rest'; import Post from './Post'; export const PostResource = resource({ schema: Post, path: '/posts/:id', }).extend('deleteMany', { path: '/posts', body: [] as string[], method: 'DELETE', schema: [new Invalidate(Post)], });
import { PostResource } from './Resource'; PostResource.deleteMany(['5', '13', '7']);
DELETE /posts
content-type: application/json
Body: ["5","13","7"]
[
{
"id": "5"
},
{
"id": "13"
},
{
"id": "7"
}
]
Às vezes o nosso backend não retorna nada para 'DELETE'. Nesse
caso, podemos usar process para construir
uma resposta utilizável a partir do argumento body.
import { resource, Invalidate } from '@data-client/rest'; import Post from './Post'; export const PostResource = resource({ schema: Post, path: '/posts/:id', }).extend('deleteMany', { path: '/posts', body: [] as string[], method: 'DELETE', schema: [new Invalidate(Post)], process(value, body) { // use the body payload to inform which entities to delete return body.map(id => ({ id })); } });
import { PostResource } from './Resource'; PostResource.deleteMany(['5', '13', '7']);
DELETE /posts
content-type: application/json
Body: ["5","13","7"]
NO CONTENT
Para excluir várias entidades sem um endpoint, como a partir de uma mensagem de websocket, passe o mesmo schema para Controller.set():
ctrl.set([new Invalidate(Post)], [{ id: '5' }, { id: '13' }, { id: '7' }]);
Ou exclua uma única entidade:
ctrl.set(new Invalidate(Post), { id: '5' });
Tipos polimórficos
Se o seu endpoint pode excluir mais de um tipo de entidade, você pode usar a invalidação polimórfica.
Com o schema Union
A abordagem mais simples é passar diretamente um schema Union existente:
import { Entity, RestEndpoint, Union, Invalidate } from '@data-client/rest';
class User extends Entity {
id = '';
name = '';
readonly type = 'users';
}
class Group extends Entity {
id = '';
groupname = '';
readonly type = 'groups';
}
const MemberUnion = new Union(
{ users: User, groups: Group },
'type'
);
const deleteMember = new RestEndpoint({
path: '/members/:id',
method: 'DELETE',
schema: new Invalidate(MemberUnion),
});
schemaAttribute string
Como alternativa, defina o mapeamento polimórfico inline com um atributo string:
import { RestEndpoint, Invalidate } from '@data-client/rest';
const deleteMember = new RestEndpoint({
path: '/members/:id',
method: 'DELETE',
schema: new Invalidate(
{ users: User, groups: Group },
'type'
),
});
schemaAttribute função
Os valores retornados devem corresponder a uma chave no mapa de entidades. Isso é útil para lógicas de discriminação mais complexas:
import { RestEndpoint, Invalidate } from '@data-client/rest';
const deleteMember = new RestEndpoint({
path: '/members/:id',
method: 'DELETE',
schema: new Invalidate(
{ users: User, groups: Group },
(input, parent, key) => input.memberType === 'user' ? 'users' : 'groups'
),
});
Impacto no useSuspense()
Quando entidades são invalidadas em um resultado que está sendo apresentado no React, useSuspense() as considerará inválidas
- Para Entities opcionais, elas são simplesmente removidas
- Para Entities obrigatórias, isso invalida a resposta inteira, disparando o suspense novamente.