Files
mabibli/MaBibli.Shared/Entites/LivreSouhaite.cs
T
Mathieu LimonierandClaude Opus 5 6a6d745af4 MaBibli 1.0.0
Gestion de bibliothèque personnelle auto-hébergée : catalogue, prêts,
scan de code-barres, consultation hors-ligne.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 22:36:16 +02:00

100 lines
4.5 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; }
/// <summary>
/// Rang dans la liste, <b>du plus désiré (0) au moins désiré</b>.
/// </summary>
/// <remarks>
/// L'ordre est choisi à la main : c'est une préférence, elle ne se calcule pas. Il est
/// <b>personnel comme le reste de la table</b> — le rang n'a de sens qu'à l'intérieur de la
/// liste d'une personne, et deux utilisateurs numérotent la leur indépendamment.
/// <para>
/// Une envie nouvelle se pose <b>en fin</b> de liste, jamais en tête : on vient de la noter,
/// on n'a pas dit qu'on la voulait plus que les autres. C'est à l'utilisateur de la remonter.
/// </para>
/// </remarks>
public int Rang { get; set; }
public void RecalculerFormes()
{
Titre = Titre.Trim();
TitreNormalise = CleOeuvre.Cle(Titre);
Auteur = string.IsNullOrWhiteSpace(Auteur) ? null : Auteur.Trim();
AuteurNormalise = RapprochementAuteurs.Cle(Auteur);
}
}