Invalidate
Describe las entities que se marcarán como INVALID. Esto elimina elementos de una colección, o fuerza el suspense en los endpoints donde la entity es obligatoria.
Constructor
new Invalidate(entity)
new Invalidate(union)
new Invalidate(entityMap, schemaAttribute)
entity: Una única Entity que se invalidará.union: Un schema Union para la invalidación polimórfica.entityMap: Una asociación de claves de schema a Entities.schemaAttribute: opcional (obligatorio si se usaentityMap) El atributo de cada entity encontrada que define qué schema, según el entityMap, se usará al normalizar. Puede ser un string o una función. Si se le da una función, acepta los siguientes argumentos:value: El valor de entrada de la entity.parent: El objeto padre del array de entrada.key: La clave con la que el array de entrada aparece en el objeto padre.
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 />);
Invalidación por lotes
Aquí agregamos otro endpoint para eliminar varias entities a la vez envolviendo
Invalidate en un array. Data Client puede entonces usar invalidate en cada
entity de la respuesta.
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"
}
]
A veces nuestro backend no devuelve nada para 'DELETE'. En este
caso, podemos usar process para construir
una respuesta utilizable a partir del 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 eliminar varias entities sin un endpoint, por ejemplo desde un mensaje de websocket, pasa el mismo schema a Controller.set():
ctrl.set([new Invalidate(Post)], [{ id: '5' }, { id: '13' }, { id: '7' }]);
O elimina una sola entity:
ctrl.set(new Invalidate(Post), { id: '5' });
Tipos polimórficos
Si tu endpoint puede eliminar más de un tipo de entity, puedes usar la invalidación polimórfica.
Con un schema Union
El enfoque más simple es pasar directamente un 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 de tipo string
Como alternativa, define la asociación polimórfica en línea con un atributo de tipo 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 de tipo función
Los valores devueltos deben coincidir con una clave del mapa de entities. Esto es útil para una lógica de discriminación más compleja:
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 en useSuspense()
Cuando se invalidan entities en un resultado que se está presentando actualmente en React, useSuspense() las considerará inválidas
- Las Entities opcionales simplemente se eliminan
- En el caso de las Entities obligatorias, se invalida la respuesta completa y se vuelve a activar el suspense.