Files
mabibli/MaBibli.Shared/Entites/LivreSouhaite.cs
T
mathieuandClaude Opus 5 8b8fe3be6e Ajouter la liste d'envies personnelle, son export et la bibliographie par auteur
La liste d'envies vit dans une table séparée (LivreSouhaite) plutôt que dans un
statut de plus sur Livre : un livre souhaité n'est pas possédé, et le loger dans
Livres l'aurait fait entrer dans le catalogue, les compteurs et les prêts, au
prix d'un « et qui n'est pas souhaité » à répéter dans chaque lecture. La portée
est personnelle, comme le statut de lecture — mais ici Utilisateur est une vraie
frontière : toute lecture filtre dessus.

Bibliographie : SRU BnF interrogé par bib.author, vérifié le 2026-08-18. Deux
filtres mesurés sur des réponses réelles sont indispensables — le type de
document (l'index mêle livres audio, jeux et spectacles) et surtout l'auteur
réel de la notice, « all » rapprochant les mots sur l'ensemble des auteurs :
« Émile Zola » remonte sinon toute l'œuvre de sa fille Denise Le Blond-Zola.
Les rééditions sont regroupées par clé d'œuvre (183 notices Werber -> 51
œuvres). Le rapprochement avec l'étagère se fait par titre, pas par ISBN, qui
désigne une édition et non une œuvre ; ses limites sont dites à l'écran.

Export en deux formats, tous deux du texte sans dépendance : .txt groupé par
auteur pour la librairie, .csv à séparateur point-virgule et BOM pour le
tableur.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 13:59:06 +02:00

86 lines
3.9 KiB
C#

using MaBibli.Shared.Textes;
namespace MaBibli.Shared.Entites;
/// <summary>
/// Un livre que l'on aimerait acquérir. <b>Personnel</b> : chacun sa liste.
/// </summary>
/// <remarks>
/// <b>Pourquoi une entité séparée plutôt qu'un statut de plus sur <see cref="Livre"/> ?</b>
/// Un livre souhaité n'est pas un livre possédé. S'il était une ligne de <c>Livres</c>, il
/// entrerait mécaniquement dans le catalogue, dans les compteurs, dans les prêts et dans le
/// cache hors-ligne — et il faudrait ajouter « et qui n'est pas souhaité » à <b>chaque</b>
/// lecture du catalogue. Un invariant qu'il faut réécrire à chaque requête finit toujours par
/// être oublié quelque part ; ici l'inventaire et l'envie ne se croisent tout simplement pas,
/// parce qu'ils ne vivent pas dans la même table.
/// <para>
/// C'est aussi la seule forme qui accepte une envie <b>sans ISBN ni édition arrêtée</b> : on
/// souhaite une œuvre (« le dernier Werber »), on possède un exemplaire. Un souhait n'a donc
/// ni <see cref="Format"/> ni couverture obligatoire, et ne peut pas être prêté.
/// </para>
/// <para>
/// La portée personnelle suit <see cref="StatutLecture"/>, dont la documentation annonçait déjà
/// ce voisinage : <see cref="Utilisateur"/> <b>est</b> une frontière, contrairement à
/// <see cref="Livre.AjoutePar"/>. On ne lit jamais la liste d'envies de quelqu'un d'autre —
/// c'est précisément ce qui permet d'offrir un livre sans vendre la mèche.
/// </para>
/// </remarks>
public class LivreSouhaite
{
public int Id { get; set; }
/// <summary>
/// <c>YNH_USER</c> du propriétaire de l'envie. <b>Frontière</b> : toute lecture filtre dessus.
/// </summary>
public string Utilisateur { get; set; } = string.Empty;
public string Titre { get; set; } = string.Empty;
/// <summary>
/// Titre mis à plat, servant à la fois au dédoublonnage et au rapprochement avec le
/// catalogue (« ai-je déjà ce livre ? »). Recalculé à chaque écriture.
/// </summary>
public string TitreNormalise { get; set; } = string.Empty;
/// <summary>
/// Auteur en <b>texte libre</b>, volontairement pas une clé étrangère vers <see cref="Auteur"/>.
/// </summary>
/// <remarks>
/// La table <c>Auteurs</c> décrit qui est <i>dans la bibliothèque</i> : y insérer les auteurs
/// souhaités les ferait apparaître sur l'écran des auteurs avec « 0 livre », et exposerait la
/// liste d'envies d'une personne à tout le foyer — l'inverse de ce qu'on veut. Le texte libre
/// survit en outre à la disparition de l'auteur du catalogue.
/// </remarks>
public string? Auteur { get; set; }
/// <summary>
/// Auteur mis à plat. <b>Jamais <c>null</c></b> (chaîne vide si l'auteur est inconnu) :
/// SQLite considère deux <c>NULL</c> comme distincts, et l'index unique laisserait alors
/// passer des doublons d'envies sans auteur.
/// </summary>
public string AuteurNormalise { get; set; } = string.Empty;
public string? Editeur { get; set; }
/// <summary>Année de publication, telle que la source la donne. Texte : la BnF écrit « 2012 », mais aussi « [DL 2012] ».</summary>
public string? Annee { get; set; }
/// <summary>ISBN d'une édition repérée, quand il y en a une. Facultatif : on souhaite une œuvre, pas forcément une édition.</summary>
public string? Isbn { get; set; }
public string? CoverUrl { get; set; }
/// <summary>Note libre : « demandé à Noël », « en poche seulement », « chez Untel ».</summary>
public string? Note { get; set; }
public DateTime DateAjout { get; set; }
public void RecalculerFormes()
{
Titre = Titre.Trim();
TitreNormalise = CleOeuvre.Cle(Titre);
Auteur = string.IsNullOrWhiteSpace(Auteur) ? null : Auteur.Trim();
AuteurNormalise = RapprochementAuteurs.Cle(Auteur);
}
}