-
Pierre Kraemer authoredd646aa83
Many-to-many
Ajout d'une nouvelle entité
Ajouter la définition d'une nouvelle entité Tag
qui contient :
- un champ
name
qui est une chaîne de caractères unique
Associer cette nouvelle entité avec l'entité Book
de sorte que :
- un
Book
est associé à plusieursTag
- un
Tag
est associé à plusieursBook
La relation entre Book
et Tag
est une relation n:n
ou Many-to-many (un livre peut avoir plusieurs tags, un tag peut être associé à plusieurs livres).
La documentation de Prisma
sur les relations Many-to-many se trouve ici : https://www.prisma.io/docs/orm/prisma-schema/data-model/relations/many-to-many-relations.
Mettre en place une relation Many-to-many implicite entre
Book
etTag
(la table d'association est générée automatiquement parPrisma
).
Générer la migration.
Afin d'avoir des données de test, mettre à jour le script de seeding
pour créer des Tags
et les associer à des Books
.
La documentation relative à la connexion d'entités existantes lors de la création d'une entité : https://www.prisma.io/docs/orm/prisma-client/queries/relation-queries#connect-multiple-records.
On peut connecter une entité à une autre en utilisant son identifiant ou un autre champ unique.
Si vous voulez avoir vos données de
seeding
dans la base de données, il faut la réinitialiser avec la commandenpx prisma migrate reset
.
Nouvelles routes
Ajouter les routes suivantes :
-
GET /tags
: retourne la liste des tags -
GET /tags/:tag_id
: retourne le tag dont l'identifiant est:tag_id
-
GET /books/:book_id/tags
: retourne la liste des tags associés au livre dont l'identifiant est:book_id
-
POST /tags
: crée un nouveau tag -
PATCH /tags/:tag_id
: met à jour le tag dont l'identifiant est:tag_id
-
DELETE /tags/:tag_id
: supprime le tag dont l'identifiant est:tag_id
-
POST /books/:book_id/tags/:tag_id
: associe le tag dont l'identifiant est:tag_id
au livre dont l'identifiant est:book_id
-
DELETE /books/:book_id/tags/:tag_id
: supprime l'association entre le tag dont l'identifiant est:tag_id
et le livre dont l'identifiant est:book_id
Comme pour les routes précédentes, on écrira les fonctions de gestion des requêtes dans un fichier dédié.
Pour la route GET /books/:book_id/tags
, on pourra utiliser le filtre de relation some
: https://www.prisma.io/docs/orm/prisma-client/queries/relation-queries#relation-filters.
Pour les routes POST /books/:book_id/tags/:tag_id
et DELETE /books/:book_id/tags/:tag_id
, on pourra utiliser les fonctionnalités connect
(https://www.prisma.io/docs/orm/prisma-client/queries/relation-queries#connect-a-single-record) et disconnect
(https://www.prisma.io/docs/orm/prisma-client/queries/relation-queries#disconnect-a-related-record).
Filtrage et tri
Prisma
permet d'exprimer facilement des filtres et du tri sur les requêtes de récupération d'entités.
La documentation relative à ces fonctionnalités se trouve ici : https://www.prisma.io/docs/orm/prisma-client/queries/filtering-and-sorting.
On peut par exemple filtrer les Author
selon que leur lastname
contient la chaîne de caractères donnée, et trier les Author
selon leur lastname
de manière croissante :
const authors = await prisma.author.findMany({
where: {
lastname: { contains: "bla" }
},
orderBy: {
lastname: 'asc'
}
});
Il faut un moyen de permettre au client de spécifier les filtres qu'il souhaite appliquer sur les requêtes de récupération d'entités.
Pour cela, on peut par exemple exploiter la query string
de l'URL.
Une requête de la forme GET /authors?lastname=bla
permet alors de récupérer les auteurs dont le lastname
contient bla
.
Dans express
, on a accès à la query string
de l'URL via la propriété query
de l'objet Request
(https://expressjs.com/en/5x/api.html#req.query).
Mettre en place le filtrage par
lastname
pour la routeGET /authors
et partitle
pour les routesGET /books
etGET /authors/:author_id/books
.Trier systématiquement les résultats par ordre croissant de
lastname
outitle
.
Pour satisfaire la vérification des types par TypeScript, vous pourrez avoir besoin de récupérer le type des objets que l'on peut affecter à la propriété where
de la fonction findMany
(les détails à ce sujet se trouvent ici : https://www.prisma.io/docs/orm/prisma-client/type-safety).
Pour le modèle Author
par exemple, ce type est récupérable et utilisable de la façon suivante :
import { Prisma } from '@prisma/client';
// on peut initialiser un objet de ce type vide
const filter: Prisma.AuthorWhereInput = {};
// puis en fonction des paramètres de la requête, ajouter des filtres
if (/* ... */) {
filter.lastname = { contains: String(...) } // là aussi, on type clairement la valeur en type String
};
On peut aussi filtrer les entités selon l'existence d'autres entités associées (https://www.prisma.io/docs/orm/prisma-client/queries/relation-queries#filter-on-presence-of-related-records).
Par exemple, ajouter un filtre qui permet la récupération des
Author
qui ont au moins unBook
associé. On pourra tester la présence d'un champhasBooks=true
dans laquery string
de la requête.
Données associées
Prisma
permet de récupérer tout ou partie des entités associées à une entité donnée lors de la récupération de cette entité (https://www.prisma.io/docs/orm/prisma-client/queries/relation-queries#nested-reads).
Par exemple, on peut récupérer les Book
(ici, uniquement leur propriété title
) associés à un Author
lors de la récupération de cet Author
:
const author = await prisma.author.findUnique({
where: { id: 1 },
include: { books: {
select: { title: true }
} }
});
Ajouter le support d'une option
include
dans laquery string
des routesGET /authors
etGET /books
qui permet de récupérer les(id, title)
(triés dans l'ordre croissant destitle
) desBook
associés auxAuthor
et les(id, firstname, lastname)
de l'Author
associé auxBook
.
Là aussi, on peut récupérer le type des objets que l'on peut affecter à la propriété include
de la fonction findMany
.
Par exemple pour le modèle Author
:
import { Prisma } from '@prisma/client';
const assoc: Prisma.AuthorInclude = {};
Pagination
Quand le nombre de résultats d'une requête est important, il est nécessaire de mettre en place un système de pagination pour éviter de surcharger le client avec un volume de données trop important.
La documentation de Prisma
sur la pagination se trouve ici : https://www.prisma.io/docs/orm/prisma-client/queries/pagination.
Parmi les 2 méthodes de pagination proposées par Prisma
, on va utiliser la méthode offset
.
Ajouter le support d'options
skip
ettake
dans laquery string
des routesGET /authors
etGET /books
qui permettent de paginer les résultats de la requête.
Afin de donner des informations au client sur le nombre total de résultats potentiels (et ainsi lui permettre de calculer le nombre de pages en fonction du nombre d'éléments par page), ajouter à la réponse un en-tête
X-Total-Count
qui contient le nombre total de résultats de la requête.
La documentation de Prisma
sur la récupération du nombre total de résultats d'une requête se trouve ici, avec l'ensemble des fonctionnalités liées à l'aggrégation de données : https://www.prisma.io/docs/orm/prisma-client/queries/aggregation-grouping-summarizing#count.
Notamment, vous trouverez qu'il est possible de filtrer le résultat d'un comptage en fonction de critères de filtre, ce qu'il est important de faire ici pour que le total annoncé corresponde bien à la requête.
En ce qui concerne l'ajout d'un en-tête à la réponse avec express
, on peut utiliser la fonction set
(aussi disponible sous l'alias header
) de l'objet Response
(https://expressjs.com/en/5x/api.html#res.set).