fr_refman

# Mocodo

In [1]:

    %reload_ext mocodo

    Mocodo 4.3.0 loaded.

In [2]:

    from IPython import display
    from pathlib import Path
    import os
    if Path.cwd().name != "mocodo_notebook":
        Path("mocodo_notebook").mkdir(parents=True, exist_ok=True)
        os.chdir("mocodo_notebook")

# Introduction¶

Mocodo est un logiciel d'aide à l'enseignement et à l'apprentissage des bases de données relationnelles.

- En entrée, il prend un MCD (modèle conceptuel de données) décrit dans un langage dédié minimaliste.
- En sortie, il produit un diagramme entité-association et, à la demande, un MLD (schéma relationnel, sous forme graphique ou textuelle), un DDL (script SQL de création de la base), un diagramme de classes UML, etc.
- En bonus, il est capable de réarranger automatiquement votre MCD de façon esthétique, et de lui appliquer des opérations de réécriture qui vont du mondain (typographie) à l'académique (décomposition d'associations), en passant par le merveilleux (inférence de types, génération d'exercices et d'exemples).

Vous pouvez utiliser Mocodo :

- à distance, sans rien installer, avec Mocodo online ;
- en local, comme n'importe quel programme Python ;
- dans un document Jupyter Notebook (à l'instar de cette documentation).

## Tracé du modèle conceptuel¶

Ci-dessous, un exemple d'utilisation sous Jupyter Notebook. L'appel du programme est en première ligne ; le texte-source proprement dit, lignes suivantes. En sortie, le diagramme conceptuel, égayé au passage par l'option `--colors` :

In [3]:

    %%mocodo --colors ocean
    Client: Réf. client [VARCHAR(8)], Nom [VARCHAR(255)], Prénom [VARCHAR(255)], Adresse [VARCHAR(255)]
    Passer, 0N Client, 11 Commande
    Commande: Num. commande [VARCHAR(8)], Date [DATE], Montant [DECIMAL(10,2)]
    Inclure, 1N Commande, 0N Produit: Quantité [INTEGER]
    Produit: Réf. produit [VARCHAR(8)], Libellé [VARCHAR(50)], Prix unitaire [DECIMAL(10,2)]

## Opérations de conversion¶

L'appel précédent a automatiquement enregistré le texte-source sous le nom de `sandbox.mcd`. Renommons-le `ccp.mcd` pour y avoir accès tout au long de ce document.

In [4]:

    Path("sandbox.mcd").rename("ccp.mcd");

On peut le récupérer avec `--input` pour lui appliquer diverses opérations. Ainsi, l'appel suivant génère et affiche son MLD, son diagramme relationnel et son DDL :

In [5]:

    %mocodo --input ccp --transform mld diagram ddl --colors mondrian

`ccp_mld.md`

- Client (Réf. client, Nom, Prénom, Adresse)
- Commande (Num. commande, Date, Montant, #Réf. client)
- Inclure (#Num. commande, #Réf. produit, Quantité)
- Produit (Réf. produit, Libellé, Prix unitaire)

`ccp_mld.svg`

`ccp_ddl.sql`

    CREATE TABLE Client (
      PRIMARY KEY (Ref_client),
      Ref_client VARCHAR(8) NOT NULL,
      Nom        VARCHAR(255),
      Prenom     VARCHAR(255),
      Adresse    VARCHAR(255)
    );

    CREATE TABLE Commande (
      PRIMARY KEY (Num_commande),
      Num_commande VARCHAR(8) NOT NULL,
      Date         DATE,
      Montant      DECIMAL(10,2),
      Ref_client   VARCHAR(8) NOT NULL
    );

    CREATE TABLE Inclure (
      PRIMARY KEY (Num_commande, Ref_produit),
      Num_commande VARCHAR(8) NOT NULL,
      Ref_produit  VARCHAR(8) NOT NULL,
      Quantite     INTEGER
    );

    CREATE TABLE Produit (
      PRIMARY KEY (Ref_produit),
      Ref_produit   VARCHAR(8) NOT NULL,
      Libelle       VARCHAR(50),
      Prix_unitaire DECIMAL(10,2)
    );

    ALTER TABLE Commande ADD FOREIGN KEY (Ref_client) REFERENCES Client (Ref_client);

    ALTER TABLE Inclure ADD FOREIGN KEY (Ref_produit) REFERENCES Produit (Ref_produit);
    ALTER TABLE Inclure ADD FOREIGN KEY (Num_commande) REFERENCES Commande (Num_commande);

Dans la suite, pour épargner la frappe, les options `--input` et `--transform` seront respectivement abrégées en `-i` et `-t`.

Les opérations de conversion ne se limitent pas forcément au schéma relationnel. En voici une qui extrait un dictionnaire des données, par défaut sous la forme d'un tableau Markdown à trois colonnes :

In [6]:

    %mocodo -i ccp -t data_dict

`ccp_data_dict_3.md`

Entité ou association | Libellé de l'attribut | Type
--- | --- | ---
Client | Adresse | VARCHAR(255)
" | Nom | VARCHAR(255)
" | Prénom | VARCHAR(255)
" | Réf. client | VARCHAR(8)
Commande | Date | DATE
" | Montant | DECIMAL(10,2)
" | Num. commande | VARCHAR(8)
Inclure | Quantité | INTEGER
Produit | Libellé | VARCHAR(50)
" | Prix unitaire | DECIMAL(10,2)
" | Réf. produit | VARCHAR(8)

Une autre qui transcrit le MCD dans la notation crow's foot (`crow`) pour Mermaid (`mmd`) :

In [7]:

    %mocodo -i ccp -t crow:mmd

`ccp_erd_crow.mmd`

    mmd
    erDiagram
      Client {
        VARCHAR(8) Ref_client PK
        VARCHAR(255) Nom
        VARCHAR(255) Prenom
        VARCHAR(255) Adresse
      }
      Commande {
        VARCHAR(8) Num_commande PK
        DATE Date
        DECIMAL(10-2) Montant
      }
      Inclure {
        INTEGER Quantite PK
      }
      Produit {
        VARCHAR(8) Ref_produit PK
        VARCHAR(50) Libelle
        DECIMAL(10-2) Prix_unitaire
      }
      Client ||--o{ Commande: Passer
      Inclure }|..|| Commande: DF
      Inclure }o..|| Produit: DF

Le rendu des diagrammes décrits dans des langages-tiers (comme Mermaid, PlantUML, etc.) n'est pas directement pris en charge, mais peut être délégué (`--defer`) de façon transparente au service web approprié. Dans ce cas, c'est la sortie graphique qui est affichée :

In [8]:

    %mocodo -i ccp -t crow:plantuml --defer

`ccp_erd_crow.svg`

## Opérations de réécriture¶

Une réécriture transforme un MCD Mocodo en un autre MCD Mocodo (au contraire d'une conversion, qui produit un animal d'une espèce différente).

Heureusement, l'utilisateur n'a pas à réfléchir si la transformation qu'il souhaite appliquer est une réécriture ou une conversion : dans les deux cas, il invoque `-t` (c'est-à-dire `--transform`), et Mocodo se débrouille.

En guise de premier exemple de réécriture, mettons les noms des entités et associations (`boxes`) en majuscules, et les libellés (`labels`) en ASCII et snake case :

In [9]:

    %mocodo -i ccp -t upper:boxes ascii:labels snake:labels --colors brewer+3

`ccp.mcd`

    %%mocodo --colors brewer+3
    CLIENT: Ref_client [VARCHAR(8)], Nom [VARCHAR(255)], Prenom [VARCHAR(255)], Adresse [VARCHAR(255)]
    PASSER, 0N CLIENT, 11 COMMANDE
    COMMANDE: Num_commande [VARCHAR(8)], Date [DATE], Montant [DECIMAL(10,2)]
    INCLURE, 1N COMMANDE, 0N PRODUIT: Quantite [INTEGER]
    PRODUIT: Ref_produit [VARCHAR(8)], Libelle [VARCHAR(50)], Prix_unitaire [DECIMAL(10,2)]

Remarquez que l'exécution d'une réécriture affiche, au-dessous du diagramme, le code-source résultant. Celui-ci est précédé de la commande magique originale, privée de l'option `-i` et de toute opération de réécriture. Ces dispositions permettent de continuer à travailler directement dessus si on le copie-colle dans une autre cellule.

Plusieurs opérations de réécriture de nature sémantique sont également offertes. Par exemple, on peut décomposer un MCD quelconque en un MCD équivalent, mais n'employant que des dépendances fonctionnelles et des entités faibles :

In [10]:

    %mocodo -i ccp -t explode:weak,arity=2 arrange:wide --seed=3 --colors brewer+3

`ccp.mcd`

    %%mocodo --seed=3 --colors brewer+3
    Client: Réf. client [VARCHAR(8)], Nom [VARCHAR(255)], Prénom [VARCHAR(255)], Adresse [VARCHAR(255)]
    Passer, 0N Client, 11 Commande
    Commande: Num. commande [VARCHAR(8)], Date [DATE], Montant [DECIMAL(10,2)]
    DF, _11 Inclure, 1N Commande
    Inclure: _Quantité [INTEGER]
    DF, _11 Inclure, 0N Produit
    Produit: Réf. produit [VARCHAR(8)], Libellé [VARCHAR(50)], Prix unitaire [DECIMAL(10,2)]

Notez l'argument `arrange:wide`. Il a procédé à une réorganisation aléatoire des boîtes, ce que l'insertion de deux nouvelles associations de dépendance fonctionnelles avait rendu nécessaire. Quant à l'option `--seed=3`, elle garantit que le résultat sera le même à chaque exécution.

Après cet aperçu de quelques-unes des fonctionnalités de Mocodo, entrons dans les détails.

# Installation et lancement du programme¶

Comme nous l'avons dit, vous pouvez utiliser Mocodo sans rien installer. Il vous suffit d'aller sur mocodo.net et de commencer à taper votre MCD. Appuyez à tout moment sur le ventilateur pour rafraîchir les diagrammes conceptuel et relationnel. Quand le résultat vous convient, appuyez sur le bouton de téléchargement pour récupérer une archive ZIP contenant tous les fichiers d'entrée et de sortie spécifiés.

Mocodo online est conçu pour une utilisation occasionnelle et/ou interactive, et son interface vise avant tout à la simplicité. Vous n'avez donc accès qu'aux options essentielles du programme. Si vous en voulez davantage, tant en termes de paramétrage que de calcul ou de fonctionnalités, nous vous conseillons d'installer Mocodo sur votre machine.

## Installation minimale¶

Mocodo est un programme écrit en Python 3. Si vous êtes sous macOS ou Linux, il est déjà installé. Dans le cas contraire, vous devrez peut-être le faire.

Une fois Python présent sur votre machine, tapez sous un terminal:

        python -m pip install mocodo

Puis testez-le :

        mocodo

Invoqué sous cette forme, Mocodo récupère le texte d'entrée du MCD dans le répertoire courant sous le nom de `sandbox.mcd`. Si ce fichier n'existe pas, il y sera automatiquement créé avec un MCD d'exemple. Par la suite, vous n'aurez qu'à le garder ouvert sous un éditeur de texte, afin de le modifier à votre fantaisie avant de relancer la commande.

Si votre système se plaint que cette commande n'existe pas, localisez le fichier `mocodo` et ajoutez à votre `PATH` le chemin du répertoire contenant:

- sous Linux ou macOS ;
- sous Windows.

## Installation complète (recommandé)¶

- Installez la distribution Anaconda, qui contient Python 3, Jupyter Notebook et bien plus encore.

- La ligne donnée précédemment installe en fait, en plus de Mocodo, sa « commande magique » pour Jupyter Notebook. Nous l'avons déjà invoquée plusieurs fois dans ce document :

        python -m pip install mocodo

- Mocodo fonctionne parfaitement sans aucune dépendance. Cependant, si vous souhaitez :

  - utiliser l'option `--svg_to` pour générer des figures en PDF ou en PNG ;
  - copier directement dans le presse-papier le résultat d'une réécriture ;

  ... vous pouvez installer les dépendances optionnelles aux bibliothèques CairoSVG et Pyperclip ainsi :

        python -m pip install mocodo[svg,clipboard]

Pour mettre la « commande magique » `mocodo` à disposition d'un notebook donné, évaluez dans celui-ci la cellule suivante:

    %reload_ext mocodo

Techniquement, `%load_ext mocodo` suffit, mais cette forme vous épargnera un message d'erreur si vous réévaluez ultérieurement la cellule.

Pour tester la commande :

In [11]:

    %%mocodo
    MISSION: accomplie

Pour charger automatiquement `mocodo` à chaque ouverture d'un notebook (ce qui dispense d'évaluer `%load_ext mocodo`) :

- exécutez sous un terminal :

    ipython profile create

- éditez le fichier créé (p. ex.: `~/.ipython/profile_default/ipython_config.py`) en remplaçant la ligne suivante :

    # c.TerminalIPythonApp.extensions = []

par celle-ci :

    c.InteractiveShellApp.extensions = ["mocodo"]

## Utilisation par importation¶

Nouveauté de la version 4.1.3. Un wrapper minimaliste permet de simuler programmatiquement l'appel à la commande `mocodo`.

In [12]:

    from mocodo.api import mocodo

Ainsi, l'équivalent de :

    mocodo -i ccp --colors mondrian

... s'écrira :

In [13]:

    messages = mocodo("-i ccp --colors mondrian")

Par défaut (second argument `quiet=True`), la fonction n'affiche pas les messages de succès, mais renvoie leur concaténation :

In [14]:

    print(messages)

    Fichier de sortie « ~/Dropbox/Sites/mocodo/doc/mocodo_notebook/ccp.svg » généré avec succès.

Plus important, les fichiers de sortie sont bel bien créés :

In [15]:

    display.SVG("ccp.svg")

Out[15]:

Si vous travaillez sous une implantation de Jupyter Notebook qui ne prend pas en charge les commandes magiques, l'importation conseillée est :

In [16]:

    from mocodo.magic import mocodo

Elle permet de simuler les commandes magiques, aussi bien celles qui sont réduites à une ligne :

In [17]:

    mocodo("%mocodo -i ccp --colors ocean")

... que celles qui portent sur toute une cellule :

In [18]:

    mocodo("""
    %%mocodo --colors pond
    Mission: accomplie
    """)

Le préfixe `"%mocodo"` ou `"%%mocodo"` est ignoré, mais l'autoriser permet de copier toute une ligne ou toute une cellule (vraiment) magique, et de la coller directement comme argument de la fonction.

Nouveauté de la version 4.2. Avec cette technique, Mocodo peut être utilisé sous Basthon v. 0.62.12 ou ultérieure. Basthon est une plateforme permettant de travailler sous Jupyter Notebook sans avoir à rien installer. Son auteur, Romain Casati, a ajouté un exemple d'utilisation de Mocodo dans la galerie du logiciel, à tester ici. Sous Mocodo online, cliquez sur le symbole de lecture de Basthon (dans le pied de page) pour ouvrir un notebook avec le MCD en cours d'édition.

# Syntaxe de description d'un MCD¶

## Notions élémentaires¶

### Entités, associations, attributs, identifiants, cardinalités¶

In [19]:

    %%mocodo
    CLIENT: Réf. client, Nom, Prénom, Adresse
    PASSER, 0N CLIENT, 11 COMMANDE
    COMMANDE: Num. commande, Date, Montant
    INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité
    PRODUIT: Réf. produit, Libellé, Prix unitaire

Passons en revue les principes de la syntaxe. Ils ne devraient pas poser trop de problèmes.

La première ligne ne fait pas partie de la définition du MCD. Sous Jupyter Notebook, elle dénote l'appel à une « commande magique », qui lance Mocodo sur le reste de la cellule. En dehors d'un notebook, vous n'en avez pas besoin, et toute ligne commençant par un pourcentage (`%`) sera considérée comme un commentaire.

Une entité est définie par :

$$ \overbrace{\texttt{COMMANDE}}^{\text{son nom}} \quad \overbrace{\texttt{:}}^{\text{deux-points}} \quad \overbrace{\texttt{Num. commande, Date, Montant}}^{\text{ses attributs séparés par des virgules}} $$

Notez que le premier attribut d'une entité est considéré par défaut comme son identifiant, et donc souligné.

Une association est définie par :

$$ \overbrace{\texttt{INCLURE}}^{\text{son nom}} \quad \overbrace{\texttt{,}}^{\text{une virgule}} \quad \overbrace{ \underbrace{\texttt{1N}}_{\text{cardinalités}} \underbrace{\texttt{COMMANDE}}_{\text{entité}} \quad , \quad \underbrace{\texttt{0N}}_{\text{cardinalités}} \underbrace{\texttt{PRODUIT}}_{\text{entité}} }^{\text{ses pattes séparées par des virgules}} \quad \overbrace{\texttt{:}}^{\text{deux-points}} \quad \overbrace{\texttt{Quantité}}^{\text{ses attributs séparés par des virgules}} $$

Notez que pour les associations sans attributs (comme PASSER), le deux-points est facultatif.

Astuce. Si vous recopiez un MCD ou que vous l'avez bien en tête, commencez par les associations et, à tout moment, faites apparaître les entités manquantes (double clic sur le lapin magique sous Mocodo online). Elles auront comme identifiant le nom de l'entité en minuscules, par défaut précédé de « id. » (sauf pour les entités DATE et PÉRIODE). Vous n'aurez plus qu'à remplir les autres attributs :

In [20]:

    %%mocodo -t guess:entities
    Réserver, 1N Client, 1N Chambre, 0N Date: Durée

`sandbox.mcd`

    %%mocodo
    Réserver, 1N Client, 1N Chambre, 0N Date: Durée

    Chambre: id. chambre,
    Client: id. client,
    Date: date

### Dépendances fonctionnelles entre entités¶

Lorsque l'une des cardinalités maximales d'une association binaire est 1 (ou quelquefois 0), on désigne cette association sous le nom de dépendance fonctionnelle. On la figure souvent par un cercle portant le symbole DF : cela évite de se creuser la tête pour trouver un nom à une association qui (spoiler) disparaîtra corps et biens au moment du passage au relationnel.

In [21]:

    %%mocodo
    CLIENT: Réf. client, Nom, Prénom, Adresse
    DF, 0N CLIENT, 11 COMMANDE
    COMMANDE: Num. commande, Date, Montant
    INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité
    PRODUIT: Réf. produit, Libellé, Prix unitaire

### Associations réflexives¶

Quelquefois appelées circulaires, unaires ou récursives, elles associent une entité à elle-même. Voici par exemple une représentation des filiations patrilinéaires (le 01 permet d'« arrêter » la remontée des ancêtres) :

In [22]:

    %%mocodo
    HOMME: Num. SS, Nom, Prénom
    ENGENDRER, 0N HOMME, 01 HOMME

### Identifiants composites¶

Préfixez d'un tiret bas (`_`) les second, troisième, etc. attributs pour les inclure dans l'identifiant.

In [23]:

    %%mocodo
    GRATTE-CIEL: latitude, _longitude, nom, hauteur, année de construction

### Flèches sur les pattes¶

Suffixez d'un chevron (`<` ou `>`) les cardinalités de la patte concernée. La direction indiquée se lit en partant de l'association et en allant vers l'entité.

In [24]:

    %%mocodo
    Peut recevoir, 1N> Groupe sanguin, 1N< Groupe sanguin
    Groupe sanguin: type de sang
    Appartient, 11> Personne, 0N Groupe sanguin
    Personne: Num. SS, Nom, Prénom, Sexe
    Engendre, 0N< Personne, 22> Personne

### Types de données¶

Comme on l'a vu dans l'introduction, chaque attribut peut être assorti d'un type entre crochets, qui servira lors de la conversion en SQL. À partir de la version 4.0, Mocodo est capable de deviner le type des attributs usuels à partir de leur nom :

In [21]:

    %%mocodo -t guess:types data_dict --select cv
    CLIENT: Réf. client, Nom, Prénom, Adresse
    PASSER, 0N CLIENT, 11 COMMANDE
    COMMANDE: Num. commande, Date, Montant
    INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité
    PRODUIT: Réf. produit, Libellé, Prix unitaire

`mocodo_notebook/sandbox_data_dict_3.md`

Entité ou association | Libellé de l'attribut | Type
--- | --- | ---
CLIENT | Adresse | VARCHAR(30)
" | Nom | VARCHAR(255)
" | Prénom | VARCHAR(255)
" | Réf. client | VARCHAR(8)
COMMANDE | Date | DATE
" | Montant | DECIMAL(10,2)
" | Num. commande | VARCHAR(8)
INCLURE | Quantité | INTEGER
PRODUIT | Libellé | VARCHAR(50)
" | Prix unitaire | DECIMAL(10,2)
" | Réf. produit | VARCHAR(8)

Nouveauté de la version 4.3. Avec l'option `-t prompt:types`, Mocodo compose un prompt à copier-coller sous ChatGPT (ou autre) pour compléter le MCD avec les types manquants. Ce prompt est trop long pour être reproduit ici : il consiste en une présentation de la syntaxe de Mocodo, des instructions sur le travail demandé, plusieurs exemples corrigés, et enfin le MCD à compléter. Voici par exemple les types générés par DeepSeek pour le MCD de la page d'accueil de Mocodo online :

In [22]:

    %%mocodo -t data_dict
    AYANT-DROIT: nom ayant-droit [VARCHAR(255)], lien [VARCHAR(50)]
    DIRIGER, 0N [responsable] EMPLOYÉ, 01 PROJET
    REQUÉRIR, 1N PROJET, 0N PIÈCE: qté requise [INTEGER]
    PIÈCE: réf. pièce [VARCHAR(8)], libellé pièce [VARCHAR(255)]
    COMPOSER, 0N [composée] PIÈCE, 0N [composante] PIÈCE: quantité [INTEGER]

    DF, _11 AYANT-DROIT, 0N EMPLOYÉ
    EMPLOYÉ: matricule [VARCHAR(10)], nom employé [VARCHAR(255)]
    PROJET: num. projet [VARCHAR(8)], nom projet [VARCHAR(255)]
    FOURNIR, 1N PROJET, 1N PIÈCE, 1N SOCIÉTÉ: qté fournie [INTEGER]

    DÉPARTEMENT: num. département [VARCHAR(8)], nom département [VARCHAR(255)]
    EMPLOYER, 11 EMPLOYÉ, 1N DÉPARTEMENT
    TRAVAILLER, 0N EMPLOYÉ, 1N PROJET
    SOCIÉTÉ: num. société [VARCHAR(8)], raison sociale [VARCHAR(255)]
    CONTRÔLER, 0N< [mère] SOCIÉTÉ, 01 [filiale] SOCIÉTÉ

`mocodo_notebook/sandbox_data_dict_3.md`

Entité ou association | Libellé de l'attribut | Type
--- | --- | ---
AYANT-DROIT | lien | VARCHAR(50)
" | nom ayant-droit | VARCHAR(255)
COMPOSER | quantité | INTEGER
DÉPARTEMENT | nom département | VARCHAR(255)
" | num. département | VARCHAR(8)
EMPLOYÉ | matricule | VARCHAR(10)
" | nom employé | VARCHAR(255)
FOURNIR | qté fournie | INTEGER
PIÈCE | libellé pièce | VARCHAR(255)
" | réf. pièce | VARCHAR(8)
PROJET | nom projet | VARCHAR(255)
" | num. projet | VARCHAR(8)
REQUÉRIR | qté requise | INTEGER
SOCIÉTÉ | num. société | VARCHAR(8)
" | raison sociale | VARCHAR(255)

Ce problème d'inférence n'est pas très difficile pour une IA. Les résultats devraient être très bons, surtout en comparaison de ceux de la version purement algorithmique, qui sont généralement incomplets :

In [20]:

    %%mocodo -t guess:types data_dict --select cv
    AYANT-DROIT: nom ayant-droit, lien
    DIRIGER, 0N [responsable] EMPLOYÉ, 01 PROJET
    REQUÉRIR, 1N PROJET, 0N PIÈCE: qté requise
    PIÈCE: réf. pièce, libellé pièce
    COMPOSER, 0N [composée] PIÈCE, 0N [composante] PIÈCE: quantité

    DF, _11 AYANT-DROIT, 0N EMPLOYÉ
    EMPLOYÉ: matricule, nom employé
    PROJET: num. projet, nom projet
    FOURNIR, 1N PROJET, 1N PIÈCE, 1N SOCIÉTÉ: qté fournie

    DÉPARTEMENT: num. département, nom département
    EMPLOYER, 11 EMPLOYÉ, 1N DÉPARTEMENT
    TRAVAILLER, 0N EMPLOYÉ, 1N PROJET
    SOCIÉTÉ: num. société, raison sociale
    CONTRÔLER, 0N< [mère] SOCIÉTÉ, 01 [filiale] SOCIÉTÉ

`mocodo_notebook/sandbox_data_dict_3.md`

Entité ou association | Libellé de l'attribut | Type
--- | --- | ---
AYANT-DROIT | lien |
" | nom ayant-droit | VARCHAR(255)
COMPOSER | quantité | INTEGER
DÉPARTEMENT | nom département | VARCHAR(255)
" | num. département | VARCHAR(8)
EMPLOYÉ | matricule |
" | nom employé | VARCHAR(255)
FOURNIR | qté fournie | INTEGER
PIÈCE | libellé pièce |
" | réf. pièce | VARCHAR(8)
PROJET | nom projet | VARCHAR(255)
" | num. projet | VARCHAR(8)
REQUÉRIR | qté requise | INTEGER
SOCIÉTÉ | num. société | VARCHAR(8)
" | raison sociale |

### Tracé d'un MCD : principes¶

Mocodo combine les avantages de l'approche diagram as code (comme PlantUML, Mermaid ou Graphviz), avec la liberté de positionnement offerte par les logiciels WYSIWYG (what you see is what you get).

Sa grande originalité est de se baser sur l'ordre et la séparation des lignes de la description pour définir une mise en page qui se révèle suffisante dans la majorité des cas.

#### Le pont aux ânes du langage Mocodo¶

Premier principe : les boîtes (entités et associations) définies sur des lignes consécutives sont tracées sur une seule rangée.

Si l'on écrit les définitions sur des lignes consécutives, on se retrouve donc vite avec des chevauchements qui ne sautent pas forcément aux yeux :

In [26]:

    %%mocodo
    CLIENT: Réf. client, Nom, Prénom, Adresse
    COMMANDE: Num. commande, Date, Montant
    PRODUIT: Réf. produit, Libellé, Prix unitaire
    PASSER, 0N CLIENT, 11 COMMANDE
    INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité

L'option `--detect_overlaps` (active par défaut sous Mocodo online) signale le problème et donne la solution :

In [27]:

    %mocodo -i sandbox --detect_overlaps

    Mocodo Err.29 - Mauvaise disposition des boîtes :
      - La patte « INCLURE — COMMANDE » chevauche « PRODUIT ».
      - La patte « INCLURE — PRODUIT » chevauche « PASSER ».
      - La patte « PASSER — CLIENT » chevauche « COMMANDE ».
      - Les pattes  « PASSER — COMMANDE » et « INCLURE — COMMANDE » se chevauchent.
    Pour corriger cela, réordonnez et/ou sautez des lignes dans le texte-source, soit à la
    main, soit à l'aide de l'option -t arrange (tablette de chocolat sous Mocodo online).

Limitation. Seuls les chevauchements mettant en jeu des pattes horizontales ou verticales sont détectés.

#### MCD sur plusieurs lignes¶

Deuxième principe : pour commencer une nouvelle rangée, il faut sauter une ligne :

In [28]:

    %%mocodo
    SCELERISQUE LOREM: blandit, elit, ligula
    EROS, 11 SCELERISQUE LOREM, 1N PELLENTESQUE IPSUM: metus, congue

    NIBH, 1N SCELERISQUE LOREM, 11 PELLENTESQUE IPSUM
    PELLENTESQUE IPSUM: tincidunt, bibendum, consequat, integer

Les centres des boîtes sont placés aux intersections d'une grille invisible. Ils sont donc alignés aussi bien horizontalement que verticalement. De plus, dans un but esthétique, le dessin fait l'objet d'une compression dans les deux dimensions. Par exemple, ci-dessus, un espace horizontal négatif a été créé entre le bord droit de l'entité de gauche et le bord gauche de l'entité de droite.

#### Mise en miroir¶

Mocodo permet de calculer facilement les symétriques d'un MCD :

- verticalement : `-t flip:v` ;
- horizontalement : `-t flip:h` ;
- selon la seconde diagonale (transposition) : `-t flip:d`.
- selon la première diagonale (transposition) : `-t flip:vhd`.

In [29]:

    %mocodo -i sandbox --select mcd -t flip:h

Corrections de la version 4.0.

- Les sens de « horizontal » et « vertical » sont permutés pour être plus conformes à l'intuition.
- La documentation parlait de première diagonale, c'était la seconde, et vice-versa.

Astuce. Transposez le MCD temporairement pour réaliser plus facilement certaines opérations d'édition en colonne, en particulier sous Mocodo online.

#### Insertion d'espacements¶

Mocodo centre les rangées qui contiennent moins de boîtes que les autres. Ce comportement n'est pas toujours idéal :

In [30]:

    %%mocodo
    Ultrices, 01 Aliquet, 0N Aliquet
    Aliquet: hendrerit, metus, lacus, quis
    Risus, 1N Aliquet, 0N Massa
    Massa: metus, posuere
    Euismod, 0N Massa, 0N Massa

    Convallis, 0N Aliquet, 0N Ante: vestibulum
    Tincidunt, 11 Ante, 0N Massa

    Gravida: ornare
    Rutrum, 0N Gravida, 0N Ante, 0N Aliquet: faucibus, curae
    Ante: vitae, tempor

L'utilisateur peut alors spécifier les espacements qu'il désire en complétant les rangées par des boîtes invisibles dont le seul rôle est de « pousser » les autres à l'emplacement voulu. Cela se fait en insérant manuellement des lignes réduites au caractère deux-points :

In [31]:

    %%mocodo
    Ultrices, 01 Aliquet, 0N Aliquet
    Aliquet: hendrerit, metus, lacus, quis
    Risus, 1N Aliquet, 0N Massa
    Massa: metus, posuere
    Euismod, 0N Massa, 0N Massa

    :
    :
    Convallis, 0N Aliquet, 0N Ante: vestibulum
    Tincidunt, 11 Ante, 0N Massa

    Gravida: ornare
    Rutrum, 0N Gravida, 0N Ante, 0N Aliquet: faucibus, curae
    :
    Ante: vitae, tempor

#### Réarrangement automatique¶

Cependant, en général, ces manipulations sont inutiles : Mocodo est capable de calculer tout seul des plongements à la fois compacts et esthétiques. Voici une compilation des réarrangements automatiques du MCD précédent produits par :

    %mocodo -i sandbox -t arrange --seed 1
    %mocodo -i sandbox -t arrange --seed 2
    %mocodo -i sandbox -t arrange --seed 3
    %mocodo -i sandbox -t arrange --seed 4

In [32]:

    %mocodo -i ../examples/four_random_layouts --scale 0.8

## Extensions du modèle¶

### Entité faible (ou identification relative)¶

Préfixez d'un tiret bas (`_`) une cardinalité 11 pour indiquer que l'entité distinguée est faible.

In [33]:

    %%mocodo
    ŒUVRE: Cote œuvre, Titre, Date parution
    DF, 1N ŒUVRE, _11 EXEMPLAIRE
    EXEMPLAIRE: Num. exemplaire, État du livre, Date d'achat

Dans le diagramme, les identifiants (ou plutôt, discriminateurs) d'une telle entité seront soulignés en pointillés, tandis que le 11 sera par défaut souligné d'un trait plein.

Notez qu'un discriminateur n'est pas toujours obligatoire :

In [34]:

    %%mocodo
    Employé: Num. employé, Nom employé, Prénom employé
    Df, _11 Conjoint, 01 Employé
    Conjoint: _Nom conjoint, Prénom conjoint

Son absence implique cependant que l'occurrence de l'entité forte qui « renforce » une occurrence de l'entité faible ne peut en renforcer une autre : d'où la cardinalité maximale 1 sur la patte distinguant EMPLOYÉ.

Mocodo rejettera donc la version « polygame » du MCD précédent (avec 0N à la place de 01) :

In [35]:

    %%mocodo
    Employé: Num. employé, Nom employé, Prénom employé
    Df, _11 Conjoint, 0N Employé
    Conjoint: _Nom conjoint, Prénom conjoint

    Mocodo Err.50 - L'entité faible « CONJOINT » devrait avoir un discriminateur.

### Héritage (généralisation / spécialisation)¶

L'héritage permet de regrouper dans une entité, dite « mère », les attributs communs à plusieurs autres entités, dites « filles », qui se distinguent les unes des autres par des attributs spécifiques.

Pour définir une spécialisation, insérez une ligne spécifiant :

$$ \overbrace{\texttt{/}\,\texttt{XT}\,\texttt{\\}}^{\text{sa nature entre barres obliques}} \qquad \overbrace{\texttt{<}\,\texttt{-}}^{\text{son type de flèche}} \qquad \overbrace{\texttt{mère}}^{\text{une entité}} \qquad \overbrace{\texttt{,}}^{\text{une virgule}} \qquad \overbrace{\texttt{fille 1, fille 2, fille 3}}^{\text{des entités séparées par des virgules}} \qquad \overbrace{\texttt{: discriminateur}}^{\text{optionnellement, un attribut}} $$

In [36]:

    %%mocodo
    Personne: num SS, nom, prénom

    /XT\ Personne <- Homme, Femme: sexe

    Homme:
    :
    Femme: nom de jeune fille

Inscrivez dans le triangle les symboles de votre choix pour prendre une part active aux guerres culturelles de notre temps :

Totalité | Exclusion | Symboles | Exemple de population | Toute personne est :
--- | --- | --- | --- | ---
oui | oui | `/XT\` | ♂♂♂♂♂♂♂ ♀♀♀♀♀♀♀♀♀♀ | - soit un homme - soit une femme
non | oui | `/X\` | ♂♂♂♂♂♂♂♂ ♀♀♀♀♀♀ ○○○○ | - soit un homme - soit une femme - soit aucun des deux
oui | non | `/T\` | ♂♂♂♂♂♂ ♀♀♀♀♀♀♀♀ ⚥⚥⚥⚥ | - soit un homme - soit une femme - soit les deux à la fois
non | non | `/\` | ♂♂♂♂♂ ♀♀♀♀♀♀ ○○○○ ⚥⚥⚥⚥ | - soit un homme - soit une femme - soit aucun des deux - soit les deux à la fois

### Contrainte inter-associations¶

Pour définir une telle contrainte, ajoutez n'importe où une ligne spécifiant :

$$ \overbrace{\texttt{(}\,\texttt{FOO}\,\texttt{)}}^{\text{son nom entre parenthèses}} \quad \overbrace{ \texttt{-}\,\texttt{>} \texttt{boîte 1,} \quad \texttt{.}\,\texttt{.} \texttt{boîte 2,} \quad \texttt{-}\,\texttt{-} \texttt{boîte 3,} \quad \texttt{boîte 4} }^{\text{les types de liens et les boîtes qu'elle met en jeu, séparés par des virgules}} \quad \overbrace{\texttt{:}\,\,\texttt{horizontale, verticale}}^{\text{optionnellement, ses coordonnées}} $$

Précisions.

- Comme leur nom ne l'indique pas, ces contraintes peuvent aussi bien porter sur des entités que des associations.
- Le nom d'une contrainte peut être formé de zéro à trois symboles quelconques.
- Un lien est soit vide (trait invisible), soit formé d'un ou plusieurs symboles `-` (trait plein) ou `.` (trait pointillé), optionnellement précédés d'un symbole `<` (flèche vers la contrainte) et/ou suivis d'un symbole `>` (flèche vers la boîte).
- Au contraire des boîtes (entités et associations), les contraintes ne sont pas... contraintes par la grille sous-jacente : la mise en page du MCD n'en tient absolument pas compte. Celui de l'exemple ci-dessous a donc dû être « aéré » avec des `:` pour leur faire de la place.
- Les clauses de définition des contraintes peuvent apparaître n'importe où. Notez cependant que tout réarrangement automatique les enverra systématiquement à la fin du texte-source.
- Chaque coordonnée du centre de la contrainte peut être exprimée sous la forme :
  - d'une référence à une boîte sur laquelle l'aligner horizontalement ou verticalement (respectivement) ;
  - d'un pourcentage de la largeur ou de la hauteur (respectivement) du MCD.
- En l'absence de coordonnées, la contrainte est placée au barycentre des boîtes qu'elle relie.

Voici un exemple concret, adapté de la Fig. 7.37 de Merise, deuxième génération (Dominique Nanci et Bernard Espinasse, 4e éd., 2001) :

In [37]:

    %%mocodo -t
    :::
    Dépôt: num dépôt, surface

    :
    Louer, 11 Commande, 0N Dépôt
    :
    Stocker, 1N Dépôt, 1N Article: quantité

    Commande: num. commande, date
    Composer, 1N Commande, 0N Article
    :
    Article: réf. article, prix

    (I) ->Stocker, ..Dépôt, ..Article, --Composer, --Louer, Commande

- Article (réf. article, prix)
- Commande (num. commande, date, #num dépôt)
- Composer (#num. commande, #réf. article)
- Dépôt (num dépôt, surface)
- Stocker (#num dépôt, #réf. article, quantité)

Notez que pour Mocodo, ces contraintes sont purement décoratives : le passage au niveau relationnel ou physique n'en tient pas compte.

### Agrégat (ou pseudo-entité)¶

Dans le MCD ci-dessous, le petit rond et l'enveloppe pointillée indiquent qu'une réservation d'une chambre donnée à une date donnée ne peut être faite que par un seul client :

In [38]:

    %%mocodo --colors ocean # changement de palette pour faire apparaître un fond semi-transparent
    Date: Date
    Réserver, /1N Client, 1N Chambre, 0N Date: Durée
    Chambre: Num. chambre, Prix

    Client: Id. client

La syntaxe est minimale : une simple barre oblique `/` avant la cardinalité de l'entité-cible.

S'il y a au maximum deux entités à agréger, et que l'angle formé par l'association et les entités est plat ou rectangle, une enveloppe de points matérialise la pseudo-entité.

Sinon, pour des raisons de simplicité du code et de clarté du diagramme, l'enveloppe n'est pas affichée. Cependant, le petit rond subsiste et le reste des traitements est bien sûr inchangé.

Remarques.

- La représentation traditionnelle demanderait à insérer une association DF entre CLIENT et RÉSERVER. Mais permettre l'association d'une entité et d'une association demanderait à apporter au code de Mocodo des changements conséquents, pour un bénéfice qui ne nous saute pas forcément aux yeux.
- Les agrégats sur association binaire sont soit inutiles (sur une DF), soit impossibles (sur une non-DF, ils reviennent à permettre à une même occurrence d'entité de renforcer plusieurs occurrences d'une entité faible sans discriminateur). Mocodo les interdit dans les deux cas.

### CIF à unicité complète¶

La notion d'agrégation n'a pas très bonne presse dans les milieux autorisés. Ceux-ci lui préfèrent généralement celle (équivalente) de contrainte d'intégrité fonctionnelle à unicité complète. Pour rentrer dans leurs bonnes grâces (et désactiver du même coup la visualisation de l'enveloppe et du petit rond), il suffit d'expliciter la contrainte correspondante dans le MCD précédent. Mocodo peut le faire pour vous :

In [39]:

    %mocodo -i sandbox -t create:cifs arrange --seed=12 --colors ocean

`sandbox.mcd`

    %%mocodo --seed=12 --colors ocean
    Date: Date
    Réserver, /1N Client, 1N Chambre, 0N Date: Durée
    Chambre: Num. chambre, Prix

    -INVISIBLE_1, XX Client, XX Client
    Client: Id. client
    :

    (CIF) ..Réserver, ->Client, --Chambre, --Date: INVISIBLE_1, INVISIBLE_1

Remarquez que la visibilité de la CIF est assurée par le positionnement de celle-ci sur une boîte invisible introduite à cet effet : si vous rectifiez ce positionnement, vous pouvez bien sûr supprimer cette boîte.

Vous avez également le droit d'alléger la visualisation des CIFs complètes en transformant les traits pleins `"--"` des entités émettrices en traits invisibles `""`. Là encore, Mocodo peut le faire pour vous :

In [40]:

    %mocodo -i sandbox -t create:cifs=light arrange --seed=12 --colors ocean

`sandbox.mcd`

    %%mocodo --seed=12 --colors ocean
    Date: Date
    Réserver, /1N Client, 1N Chambre, 0N Date: Durée
    Chambre: Num. chambre, Prix

    -INVISIBLE_1, XX Client, XX Client
    Client: Id. client
    :

    (CIF) ..Réserver, ->Client, Chambre, Date: INVISIBLE_1, INVISIBLE_1

Limitation. Au niveau fonctionnel, c'est toujours la barre oblique qui conditionne le traitement des CIF. Par conséquent, les CIF à unicité incomplète ne sont prises en charge qu'au niveau visuel.

### Identifiants explicites dans les associations¶

Mocodo 4.1.1 relaxe par défaut (sauf dans la version en ligne) la contrainte de Merise restreignant aux entités la présence d'identifiants. Si vous l'osez, vous pouvez donc obtenir le même schéma relationnel avec le MCD « allégé » suivant :

In [41]:

    %%mocodo -t
    Client: Id. client
    Réserver, 1N Client, 0N Chambre: _Date, Durée
    Chambre: Num. chambre, Prix

- Chambre (Num. chambre, Prix)
- Réserver (Id. client, #Num. chambre, Date, Durée)

L'introduction de cette possibilité, surtout destinée à simplifier le plongement des MCD touffus, est discutée ici.

# Conversion d'un MCD¶

## Passage au relationnel¶

Il se fait en deux étapes:

- la création d'une représentation interne complète du MLD ;
- la traduction de celle-ci en une représentation externe dans le ou les formats de sortie souhaités.

Pour construire la représentation interne, l'algorithme de base réalise la séquence d'opérations suivante :

1. Pour chaque entité, une relation (table) de même nom et de mêmes attributs est créée. Le ou les identifiants de l'entité constituent la clé primaire de la relation.
2. Toute relation issue d'une entité faible est renforcée, c'est-à-dire que la clé primaire de l'entité qu'elle détermine fonctionnellement vient s'adjoindre à sa clé primaire, au besoin de façon récursive.
3. Les associations sont traitées ainsi :
4. si toutes les pattes de l'association portent la cardinalité maximale N, une relation de même nom et de mêmes attributs est créée. Sa clé primaire est constituée de l'ensemble des clés primaires des relations issues des entités mises en jeu ;
5. dans le cas contraire, c'est-à-dire si l'une des pattes de l'association porte la cardinalité (1,1), ou à défaut (0,1), l'entité distinguée se voit adjoindre : 1. en tant que clés étrangères, l'ensemble des clés primaires des autres entités mises en jeu; 2. en tant que simples attributs, l'ensemble des attributs de l'association.

Remarque. Un couple de cardinalités non standard, c'est-à-dire distinct de (0,1), (1,1), (0,N) et (1,N), est traité comme (0,1) si son deuxième symbole est un 1, et comme (0,N) sinon. Cela couvre en particulier les cas (*, 1), (*,N), (?,?) et (X,X).

Pour construire la représentation externe, Mocodo formate la représentation interne à l'aide d'un gabarit. Près d'une centaine de gabarits sont fournis, qui permettent de produire quatre grandes catégories de résultats :

1. le schéma relationnel dans toutes les combinaisons de formats (HTML, Markdown, texte brut, $\LaTeX$) et d'options (avec ou sans explications, avec ou sans boilerplate, avec ou sans visualisation des contraintes d'unicité et d'optionalité) ;
2. le diagramme relationnel au format Mocodo, avec ou sans visualisation des contraintes d'unicité et d'optionalité, ou dans des formats externes, comme DBML ou D2.
3. le DDL en SQL ANSI et dans les principaux dialectes (Microsoft SQL Server, MySQL, Oracle DB, PostgreSQL, SQLite), avec ou sans boilerplate de création de la base ;
4. le graphe des dépendances.

### Niveau logique¶

#### Schéma relationnel¶

La transformation `-t mld` opère la conversion d'un MCD (modèle conceptuel de données) en un MLD (modèle logique de données), autrement appelé schéma relationnel :

In [42]:

    %mocodo -i ccp -t mld

`ccp_mld.md`

- Client (Réf. client, Nom, Prénom, Adresse)
- Commande (Num. commande, Date, Montant, #Réf. client)
- Inclure (#Num. commande, #Réf. produit, Quantité)
- Produit (Réf. produit, Libellé, Prix unitaire)

Sous Jupyter Notebook, comme pour toutes les opérations de conversion, le tracé du MCD est omis par défaut. Dans le cas très fréquent où l'on a besoin de visualiser simultanément le MCD et le MLD, on peut invoquer l'option `-t` sans arguments (ou encore `--mld`) :

In [43]:

    %mocodo -i ccp -t

- Client (Réf. client, Nom, Prénom, Adresse)
- Commande (Num. commande, Date, Montant, #Réf. client)
- Inclure (#Num. commande, #Réf. produit, Quantité)
- Produit (Réf. produit, Libellé, Prix unitaire)

#### Diagramme relationnel¶

La plupart des SGBD offrent une représentation hybride (graphique / texte) de la base sous la forme de tables liées par des flèches. Nous l'appelons diagramme relationnel. Sous Mocodo :

In [44]:

    %mocodo -i ccp --colors mondrian -t diagram

`ccp_mld.svg`

Le nom du fichier généré avant rendu graphique se termine par `_mld.mcd`. L'extension `.mcd` signifie que Mocodo peut le prendre comme texte-source (bien que ce ne soit pas un schéma conceptuel). Examinons son contenu :

In [45]:

    display.Code("ccp_mld.mcd", language="text")

Out[45]:

    %%mocodo
    :
    Client: Réf. client, Nom, Prénom, Adresse
    :
    Commande: Num. commande, Date, Montant, #Réf. client > Client > Réf. client
    :
    Inclure: #Num. commande > Commande > Num. commande, _#Réf. produit > Produit > Réf. produit, Quantité
    :
    Produit: Réf. produit, Libellé, Prix unitaire
    :

La syntaxe d'un MLD est effectivement la même que celle d'un MCD, à ceci près que les associations sont remplacées par des liens allant de l'attribut `a1` de l'entité `E1` à l'attribut `a2` de l'entité `E2`, et notés : `E1: ... a1 > E2 > a2`.

Les relations sont placées dans le même ordre que les boîtes du MCD d'origine. Vous devrez quelquefois les réarranger (automatiquement ou manuellement) pour obtenir un résultat plus esthétique. Notez que des boîtes invisibles ont été automatiquement insérées une colonne sur deux afin de laisser de la place aux flèches.

Limitation. Les clés étrangères composites sont actuellement représentées comme si elles étaient séparées (autant de flèches que de parties).

Nouveautés de la version 4.0.

- Ce qui se notait `E1: ... a1->E2->a2` se note maintenant `E1: ... a1 > E2 > a2`.
- Sous Jupyter Notebook, un seule étape suffit pour visualiser le diagramme relationnel.
- Le nom du fichier intermédiaire se termine par `_mld.mcd` au lieu de `.mld`. L'ancienne extension est abandonnée.

### Niveau physique : DDL¶

#### SQL¶

La principale raison de vivre d'un MCD est de se métamorphoser in fine en une chatoyante base de données relationnelles. Cela se fait au moyen d'un sous-ensemble du langage SQL appelé DDL (Data Definition Language). Sous Mocodo :

In [46]:

    %mocodo -i ccp -t sql

`ccp_ddl.sql`

    CREATE TABLE Client (
      PRIMARY KEY (Ref_client),
      Ref_client VARCHAR(8) NOT NULL,
      Nom        VARCHAR(255),
      Prenom     VARCHAR(255),
      Adresse    VARCHAR(255)
    );

    CREATE TABLE Commande (
      PRIMARY KEY (Num_commande),
      Num_commande VARCHAR(8) NOT NULL,
      Date         DATE,
      Montant      DECIMAL(10,2),
      Ref_client   VARCHAR(8) NOT NULL
    );

    CREATE TABLE Inclure (
      PRIMARY KEY (Num_commande, Ref_produit),
      Num_commande VARCHAR(8) NOT NULL,
      Ref_produit  VARCHAR(8) NOT NULL,
      Quantite     INTEGER
    );

    CREATE TABLE Produit (
      PRIMARY KEY (Ref_produit),
      Ref_produit   VARCHAR(8) NOT NULL,
      Libelle       VARCHAR(50),
      Prix_unitaire DECIMAL(10,2)
    );

    ALTER TABLE Commande ADD FOREIGN KEY (Ref_client) REFERENCES Client (Ref_client);

    ALTER TABLE Inclure ADD FOREIGN KEY (Ref_produit) REFERENCES Produit (Ref_produit);
    ALTER TABLE Inclure ADD FOREIGN KEY (Num_commande) REFERENCES Commande (Num_commande);

Notez le `NOT NULL` des clés primaires. Il s'agit d'une redondance, mais aussi d'une bonne pratique. Non seulement parce qu'explicit is better than implicit : elle peut se révéler utile, par exemple pour désactiver les contraintes de clé primaire pendant une maintenance tout en continuant à interdire le remplissage avec des `NULL`. Si cela vous gêne, nous montrons en annexe comment l'éliminer.

Principales nouveautés de la version 4.0.

- Génération automatique des contraintes `UNIQUE`, `NOT NULL` et `NULL` appropriées.
- Les libellés sont convertis en ASCII, et toute suite de caractères qui ne sont ni des lettres, ni des chiffres, ni des tirets bas sont remplacés par un unique tiret bas. Cela simplifie la référence aux tables et aux champs, et évite de noyer le DDL sous un essaim de délimiteurs (qui plus est spécifiques à chaque dialecte). Ainsi, « Réf. client » se trouvera transformé en `Ref_client`.
- Vos choix de casse (minuscules, MAJUSCULES, snake_case, camelCase, PascalCase, etc.) sont respectés.

#### Inférence de type¶

Avec l'option de réécriture `-t create:types` Mocodo essaiera d'inférer des libellés des attributs tout type manquant. La langue définie avec l'option `--language` est prioritaire, mais l'anglais prend la relève en cas d'échec.

In [47]:

    %%mocodo -t create:types --select rw
    Customer: Customer ID, Last Name, First Name, Address
    Make Order, 0N Customer, 11 Order
    Order: Order Number, Date, Amount
    INCLUDE, 1N Order, 0N Product: Quantity
    Product: Product ID, Description, Unit Price

`sandbox.mcd`

    %%mocodo --select rw
    Customer: Customer ID [VARCHAR(8)], Last Name [VARCHAR(255)], First Name [VARCHAR(255)], Address [VARCHAR(30)]
    Make Order, 0N Customer, 11 Order
    Order: Order Number [VARCHAR(8)], Date [DATE], Amount [DECIMAL(10,2)]
    INCLUDE, 1N Order, 0N Product: Quantity [INTEGER]
    Product: Product ID [VARCHAR(8)], Description [TEXT], Unit Price [DECIMAL(10,2)]

Il va de soi que les types inférés devront être systématiquement contrôlés, et parfois corrigés ou complétés. Une discussion sur StackOverflow, Common MySQL fields and their appropriate data types, a servi de point de départ. La liste des types utilisée est celle de Wikipedia. Consultez les correspondances spécifiées dans `mocodo/resources/default_datatypes_fr.tsv`, etc. pour plus de détails, et n'hésitez pas à ouvrir le débat si vous avez des corrections ou des suggestions.

Si vous préférez tout typer à la main, vous pouvez au moins créer les « cases » à remplir :

In [48]:

    %%mocodo -t create:types=[] --select rw
    Customer: Customer ID, Last Name, First Name, Address
    Make Order, 0N Customer, 11 Order
    Order: Order Number, Date, Amount
    INCLUDE, 1N Order, 0N Product: Quantity
    Product: Product ID, Description, Unit Price

`sandbox.mcd`

    %%mocodo --select rw
    Customer: Customer ID [], Last Name [], First Name [], Address []
    Make Order, 0N Customer, 11 Order
    Order: Order Number [], Date [], Amount []
    INCLUDE, 1N Order, 0N Product: Quantity []
    Product: Product ID [], Description [], Unit Price []

#### Dialectes de SQL¶

L'argument `sql` peut être remplacé par un nom de dialecte parmi `mysql`, `oracle`, `postgresql`, `sqlite` et (nouveauté de la version 4) `mssql`. Quelques transformations seront alors appliquées au code-source généré. Du fait de l'uniformisation de la syntaxe apportée par la version 4, elles sont assez minimes.

Notez les points suivants :

- Mocodo ne touche pas aux types spécifiés par l'utilisateur. Une traduction inter-dialectes automatique est envisageable dans le futur, mais c'est un problème qui n'a en réalité aucune solution satisfaisante.
- Mocodo protège les noms de tables ou de colonnes qui se trouveraient faire partie des mots réservés par le dialecte-cible. Par exemple, ci-dessous, les noms `USER` et `MEMBER` sont réservés en MySQL. Les listes viennent du site modern-sql.com de Markus Winand, et plus précisément de la page https://modern-sql.com/reserved-words-empirical-list.
- Avec la sous-sous-option `b`, un boilerplate de création de la base est ajouté en préambule.

In [49]:

    %%mocodo -t mysql:b
    USER: username, mail, member

`sandbox_ddl_mysql.sql`

    CREATE DATABASE IF NOT EXISTS `MCD`
      CHARACTER SET utf8mb4
      COLLATE utf8mb4_general_ci
    ;
    USE `MCD`;

    CREATE TABLE `USER` (
      PRIMARY KEY (username),
      username VARCHAR(42) NOT NULL,
      mail     VARCHAR(42),
      `member` VARCHAR(42)
    );

### Notes sur les règles de passage¶

#### Génération de contraintes d'optionalité et d'unicité¶

Avec la sous-sous-option `c`, Mocodo peut faire apparaître dès le niveau logique certaines contraintes du niveau physique. Les notations sont les suivantes :

Contrainte | niveau logique | niveau physique
--- | --- | ---
non-optionalité | attribut! | `NOT NULL`
optionalité | attribut? | `NULL`
unicité | attribut $^{u1\ u2...}$ | `UNIQUE`

Par exemple, ci-dessous, la clé étrangère #Réf_client est maintenant marquée comme non optionnelle :

In [50]:

    %mocodo -i ccp -t mld:c

`ccp_mld.md`

- Client (Réf. client, Nom, Prénom, Adresse)
- Commande (Num. commande, Date, Montant, #Réf. client!)
- Inclure (#Num. commande, #Réf. produit, Quantité)
- Produit (Réf. produit, Libellé, Prix unitaire)

La clé étrangère #id entreprise est marquée comme optionnelle :

In [51]:

    %%mocodo --select all -t mld:c
    Entreprise: id. entreprise, raison, activité, adresse
    Envoyer, 0N Entreprise, 01 Participant
    Participant: id. inscrit, nom, adresse

`sandbox_mld.md`

- Entreprise (id. entreprise, raison, activité, adresse)
- Participant (id. inscrit, nom, adresse, #id. entreprise?)

La clé étrangère #id employé est marquée comme unique :

In [52]:

    %%mocodo --select all -t mld:c
    EMPLOYÉ: id. employé, nom employé
    DIRIGER, 11 DÉPARTEMENT, 01 EMPLOYÉ
    DÉPARTEMENT: id. département, nom département

`sandbox_mld.md`

- DÉPARTEMENT (id. département, nom département, #id. employé! u1)
- EMPLOYÉ (id. employé, nom employé)

#### Ajout manuel de contraintes d'optionalité et d'unicité¶

Les contraintes `NOT NULL` ou `NULL` spécifiées dans les types peuvent également faire l'objet d'une visualisation au niveau relationnel :

In [53]:

    %%mocodo -t mld:c
    Personne: id. personne [VARCHAR(8)], nom [VARCHAR(255) NOT NULL], prénom [VARCHAR(255)], nom de jeune fille [VARCHAR(255) NULL]

`sandbox_mld.md`

- Personne (id. personne, nom!, prénom, nom de jeune fille?)

Pour les contraintes d'unicité, qui peuvent s'appliquer à plusieurs groupes d'attributs potentiellement non disjoints, la notation est un peu plus complexe. Voici un exemple proposé par Fabien Duchateau :

In [54]:

    %%mocodo --select all -t mld:c --shapes trebuchet # changement de police de caractères pour mieux distinguer les 1 des I
    CLIENT: Réf. client, 1_Nom, 1_Prénom, Adresse, 2_Mail

`sandbox_mld.md`

- CLIENT (Réf. client, Nom u1, Prénom u1, Adresse, Mail u2)

C'est l'occasion d'introduire quelques définitions :

- On appelle identifiant candidat d'une entité tout sous-ensemble minimal d'attributs dont chaque occurrence est unique.
- Parmi ces sous-ensembles, l'un est élu identifiant (tout court), souligné, et appelé à devenir clé primaire lors du passage au relationnel.
- Les candidats malheureux sont appelés identifiants alternatifs.

Ainsi, dans l'exemple précédent, l'ensemble des identifiants candidats de CLIENT est constitué de :

- l'identifiant proprement dit Réf. client ;
- l'identifiant alternatif (Nom, Prénom) (dont on supposera pour les besoins de la cause qu'il assure l'unicité) ;
- l'identifiant alternatif Mail.

Par défaut, dès la première déclaration d'un identifiant alternatif, Mocodo fait apparaître une gouttière à gauche des attributs de toutes les entités. Y sont portés :

- un symbole « ID » (resp. « id ») pour l'identifiant fort (resp. faible).
- des chiffres de 1 à 9 correspondant aux numéros des identifiants alternatifs.

La notation de Mocodo permet de faire de n'importe quels sous-ensembles d'attributs des identifiants alternatifs. Ci-dessous, le premier identifiant alternatif est le triplet (bar, biz, quux), le second (biz, buz, quux) et le troisième (qux, quux) :

In [55]:

    %%mocodo --select all -t markdown:c sql --shapes trebuchet
    FOO: foo, 1_bar, 12_biz, 2_buz, 3_qux, 123_quux

`sandbox_mld.md`

- FOO (foo, bar u1, biz u1 u2, buz u2, qux u3, quux u1 u2 u3)

`sandbox_ddl.sql`

    CREATE TABLE FOO (
      PRIMARY KEY (foo),
      foo  VARCHAR(42) NOT NULL,
      bar  VARCHAR(42),
      biz  VARCHAR(42),
      buz  VARCHAR(42),
      qux  VARCHAR(42),
      quux VARCHAR(42),
      UNIQUE (bar, biz, quux),
      UNIQUE (biz, buz, quux),
      UNIQUE (qux, quux)
    );

Examinons le cas exceptionnel où l'identifiant à souligner a un attribut commun avec un identifiant alternatif. Ce dernier devant être distinct et minimal, cela implique que l'identifiant est composite.

In [56]:

    %%mocodo --shapes trebuchet
    Entité 1_: 1_foo, _bar, 1_biz
    Entité 2_: foo, 1_bar, 1_biz
    Entité 3_: foo, 01_bar, 1_biz

- Si l'attribut commun est en tête de liste (ici, foo, entité 1), rien ne change, on écrit `1_foo`.
- S'il n'est pas en tête de liste (ici, bar, entité 2), l'écriture `1_bar` dénote déjà l'appartenance à un identifiant alternatif. Elle ne peut dénoter simultanément l'appartenance à l'identifiant à souligner.
- C'est pourquoi on doit donc expliciter l'appartenance à l'identifiant à souligner qui, comme on l'a vu, est numéroté `0` (entité 3).

Un sous-cas demande encore réflexion : celui où le premier attribut ne fait pas partie de l'identifiant à souligner (entité 4). Si l'on veut alors que ce premier attribut appartienne à une clé alternative, il faut expliciter le `0` (entité 5).

In [57]:

    %%mocodo --shapes trebuchet
    Entité 40: _foo, _bar, biz
    Entité 50: 01_foo, _bar, 1_biz

En résumé, on explicite le `0`, soit pour empêcher le soulignement du premier attribut, soit pour forcer le soulignement d'un attribut suivant.

Cela devrait vous rappeler quelque chose… Remplacez `0` par `_` dans la phrase précédente et vous retrouverez la règle que vous avez appris à connaître et à aimer : on explicite le `_`, soit pour empêcher le soulignement du premier attribut, soit pour forcer le soulignement d'un attribut suivant.

#### Gestion des entités faibles (identification relative)¶

Dans ce joli exemple dû à Idris NEUMANN, Initiation à la conception de bases de données relationnelles avec MERISE, les renforcements successifs aboutissent à faire entrer l'identifiant de RUE dans celui de APPARTEMENT, alors même que ces entités sont séparées par non moins de trois associations :

In [58]:

    %%mocodo -t
    Appartement: num appart., nb pièces
    Composer, 0N Étage, _11 Appartement
    Étage: num étage, nb appartements
    Appartenir, 1N Immeuble, _11 Étage
    Immeuble: num immeuble, nb étages
    Se situer, 0N Rue, _11 Immeuble
    Rue: code rue, nom rue

- Appartement (#code rue, #num immeuble, #num étage, num appart., nb pièces)
- Étage (#code rue, #num immeuble, num étage, nb appartements)
- Immeuble (#code rue, num immeuble, nb étages)
- Rue (code rue, nom rue)

Le résultat apparaît plus clairement sur le diagramme relationnel :

In [59]:

    %mocodo -i sandbox -t diagram --colors mondrian

`sandbox_mld.svg`

Une phase préliminaire de l'algorithme de passage au relationnel consiste à « renforcer » les entités faibles de façon à traiter uniquement des identifiants forts dans la suite. Cela permet la gestion des renforcements en cascade comme ci-dessus, ainsi que la détection des problèmes de renforcement cyclique :

In [60]:

    %%mocodo
    Pick, 0N Land, _11 Peer
    Land: true, hold

    Peer: foot, city
    Zone, 1N Peer, _11 Land

In [61]:

    %mocodo -i sandbox -t

    Mocodo Err.17 - Cycle d'entités faibles dans "Land", "Peer".

#### Gestion de l'héritage¶

La bonne gestion d'un héritage est primordiale, tant du point de vue de la préservation du patrimoine, que de l'optimisation des ressources financières, de la minimisation des conflits familiaux et du respect des dernières volontés du défunt. Je blague.

Adaptons ici un exemple d'un cours de Stéphane Crozat. Nous reprenons sa terminologie et donnons en parallèle celle introduite par Martin Fowler dans Patterns of Enterprise Application Architecture, Addison-Wesley (2003).

Ci-dessous, l'héritage est considéré comme total (tout document est soit un ouvrage, soit une thèse, soit les deux). Crozat passe en revue trois mécanismes possibles pour le passage au relationnel.

L'héritage par référence (en anglais, Class Table Inheritance ou Table Per Type Inheritance) se note en Mocodo par une flèche simple allant vers les filles. Une référence à la table-mère sera ajoutée dans chaque table-fille comme clé étrangère. L'intérêt de cette solution est en raison directe du nombre d'attributs non identifiants de l'entité-mère.

In [62]:

    %%mocodo --select all -t mld:c
    DOCUMENT: cote, titre, auteur

    OUVRAGE: éditeur
    /T\ DOCUMENT -> OUVRAGE, THÈSE
    THÈSE: discipline, université

`sandbox_mld.md`

- DOCUMENT (cote, titre, auteur)
- OUVRAGE (#cote, éditeur)
- THÈSE (#cote, discipline, université)

L'héritage par absorption dans les tables-filles (en anglais, Concrete Table Inheritance ou Table Per Concrete Inheritance) se note en doublant la flèche :

1. les attributs de la table-mère sont reproduits dans chacune des filles. Pour chaque document qui est à la fois un ouvrage et une thèse, il y aura donc duplication des triplets (cote, titre, auteur).
2. la table-mère disparaît. Pour éviter de perdre les informations sur les documents qui ne seraient ni des ouvrages, ni des thèses, Mocodo lève une erreur si l'héritage n'est pas total (T ou XT).

In [63]:

    %%mocodo --select all -t mld:c
    DOCUMENT: cote, titre, auteur

    OUVRAGE: éditeur
    /T\ DOCUMENT => OUVRAGE, THÈSE
    THÈSE: discipline, université

`sandbox_mld.md`

- OUVRAGE (cote, titre, auteur, éditeur)
- THÈSE (cote, titre, auteur, discipline, université)

L'héritage par absorption dans la table-mère (en anglais, Single Table Inheritance ou Table Per Hierarchy Inheritance) se note par une flèche simple allant vers la mère. Les tables-filles disparaissent, et leurs attributs migrent dans la mère avec une contrainte d'optionalité (point d'interrogation en relationnel, `NULL` en SQL).

In [64]:

    %%mocodo --select all -t mld:c sql
    DOCUMENT: cote, titre, auteur

    OUVRAGE: éditeur
    /X\ DOCUMENT <- OUVRAGE, THÈSE: discriminateur [ENUM ('OUVRAGE', 'THÈSE')]
    THÈSE: discipline, université

`sandbox_mld.md`

- DOCUMENT (cote, titre, auteur, discriminateur?, éditeur?, discipline?, université?)

`sandbox_ddl.sql`

    CREATE TABLE DOCUMENT (
      PRIMARY KEY (cote),
      cote           VARCHAR(42) NOT NULL,
      titre          VARCHAR(42),
      auteur         VARCHAR(42),
      discriminateur ENUM ('OUVRAGE', 'THÈSE') NULL,
      editeur        VARCHAR(42) NULL,
      discipline     VARCHAR(42) NULL,
      universite     VARCHAR(42) NULL
    );

Ci-dessus, nous avons donné comme « attribut » au triangle d'héritage un « discriminateur » de type `ENUM`. Cela ajoute à la table un champ optionnel ou non (selon que l'héritage est partiel ou total) permettant de déterminer à quel type concret d'une occurrence on a affaire.

C'est par défaut un `UNSIGNED INT`, qui pourra prendre les valeurs :

- 1 = OUVRAGE, 2 = THÈSE, pour l'héritage exclusif ;
- 1 ($2^0$) = OUVRAGE, 2 ($2^1$) = THÈSE, 3 ($2^0 | 2^1$) = OUVRAGE + THÈSE, pour l'héritage non exclusif.

Alternativement à l'emploi d'un discriminateur, Mocodo peut ajouter un drapeau booléen par table-fille. Cela se note en doublant la flèche :

In [65]:

    %%mocodo --select all -t mld:c sql
    DOCUMENT: cote, titre, auteur

    OUVRAGE: éditeur
    /T\ DOCUMENT <= OUVRAGE, THÈSE
    THÈSE: discipline, université

`sandbox_mld.md`

- DOCUMENT (cote, titre, auteur, est ouvrage!, éditeur?, est these!, discipline?, université?)

`sandbox_ddl.sql`

    CREATE TABLE DOCUMENT (
      PRIMARY KEY (cote),
      cote        VARCHAR(42) NOT NULL,
      titre       VARCHAR(42),
      auteur      VARCHAR(42),
      est_ouvrage BOOLEAN NOT NULL,
      editeur     VARCHAR(42) NULL,
      est_these   BOOLEAN NOT NULL,
      discipline  VARCHAR(42) NULL,
      universite  VARCHAR(42) NULL
    );

#### Gestion de l'agrégation¶

Un agrégat simple autour d'une association dont toutes les cardinalités maximales sont N se traduit en relationnel comme la même association non agrégée, mais avec une clé primaire réduite :

In [66]:

    %%mocodo --select all -t mld:c
    DATE: date
    RÉSERVER, /1N CLIENT, 1N CHAMBRE, 0N DATE: durée
    CHAMBRE: num. chambre, prix

    CLIENT: id. client, nom client

`sandbox_mld.md`

- CHAMBRE (num. chambre, prix)
- CLIENT (id. client, nom client)
- RÉSERVER (#num. chambre, date, #id. client!, durée)

Un agrégat simple autour d'une association dont la cardinalité maximale « de sortie » est 1 se traduit en relationnel comme la même association non agrégée, mais avec une contrainte d'unicité sur la clé étrangère. Ci-dessous, au lieu d'avoir simplement num résa $\implies$ (num voilier, num semaine), on a donc en plus (num voilier, num semaine) $\implies$ num résa :

In [67]:

    %%mocodo --select all -t mld:c
    Voilier: num voilier, longueur
    Offrir, /11 Réservation, 0N Voilier, 0N Semaine: tarif
    Semaine: num semaine, date début

    Réservation: num résa, arrhes, date résa

`sandbox_mld.md`

- Réservation (num résa, arrhes, date résa, #num voilier! u1, #num semaine! u1, tarif)
- Semaine (num semaine, date début)
- Voilier (num voilier, longueur)

Le cas des agrégats multiples, plus rare, est étudié en annexe.

### Ajustement des règles de passage¶

#### Supprimer ou maintenir une table facultative¶

Le passage au relationnel supprime automatiquement les tables réduites à une clé primaire, pourvu qu'aucun composant de celle-ci ne soit clé étrangère. Si l'on souhaite maintenir certaines de ces tables, on préfixe d'un `+` l'entité concernée. Ainsi, ci-dessous, Date est supprimée, mais pas Thème.

In [68]:

    %%mocodo --select mld mcd -t mld:e
    Animateur: num. animateur, nom animateur
    Intervenir, 1N Animateur, 1N Formation, 1N Date: nb heures
    Formation: id. formation, durée
    Aborder, 1N Thème, 1N Formation
    +Thème: thème

    Date: date
    :

`sandbox_mld.md`

- Aborder (#thème, #id. formation)

  - Le champ thème fait partie de la clé primaire de la table. C'est une clé étrangère qui a migré directement à partir de l'entité Thème.
  - Le champ id. formation fait partie de la clé primaire de la table. C'est une clé étrangère qui a migré directement à partir de l'entité Formation.

- Animateur (num. animateur, nom animateur)

  - Le champ num. animateur constitue la clé primaire de la table. C'était déjà un identifiant de l'entité Animateur.
  - Le champ nom animateur était déjà un simple attribut de l'entité Animateur.

- Formation (id. formation, durée)

  - Le champ id. formation constitue la clé primaire de la table. C'était déjà un identifiant de l'entité Formation.
  - Le champ durée était déjà un simple attribut de l'entité Formation.

- Intervenir (#num. animateur, #id. formation, date, nb heures)

  - Le champ num. animateur fait partie de la clé primaire de la table. C'est une clé étrangère qui a migré directement à partir de l'entité Animateur.
  - Le champ id. formation fait partie de la clé primaire de la table. C'est une clé étrangère qui a migré directement à partir de l'entité Formation.
  - Le champ date fait partie de la clé primaire de la table. Sa table d'origine (Date) ayant été supprimée, il n'est pas considéré comme clé étrangère.
  - Le champ nb heures était déjà un simple attribut de l'association Intervenir.

- Thème (thème)

  - Le champ thème constitue la clé primaire de la table. C'était déjà un identifiant de l'entité Thème.

NB. La table Date a été supprimée car elle était réduite à la clé primaire de son entité d'origine. Pour conserver de telles tables, préfixez d'un « + » la définition des entités d'origine.

Notez l'explication de la suppression (en NB) et celle de la perte du caractère étranger de l'attribut date (dans la table Intervenir). Pour une discussion sur cette problématique, cf. issue #66.

#### Forcer une table pour éviter un champ optionnel¶

Une association de dépendance fonctionnelle ne donne normalement pas lieu à une création de table. Pour reprendre un exemple vu plus haut :

In [69]:

    %%mocodo --select all -t mld:c
    Entreprise: id. entreprise, raison, activité, adresse
    Envoyer, 0N Entreprise, 01 Participant
    Participant: id. inscrit, nom, adresse

`sandbox_mld.md`

- Entreprise (id. entreprise, raison, activité, adresse)
- Participant (id. inscrit, nom, adresse, #id. entreprise?)

Dans le cas où les particuliers sont beaucoup plus nombreux que les employés d'entreprise, la clé étrangère #id. entreprise est presque toujours à `NULL`. C'est une perte d'espace de stockage. On peut entourer l'association de crochets droits préfixer d'un `+` (à partir de la version 4) l'association pour forcer sa conversion en table. Mocodo produit alors une visualisation intermédiaire entre entité et association :

In [70]:

    %%mocodo --select all -t mld:c --colors mondrian
    Entreprise: id. entreprise, raison, activité, adresse
    +Envoyer, 0N Entreprise, 01 Participant
    Participant: id. inscrit, nom, adresse

`sandbox_mld.md`

- Entreprise (id. entreprise, raison, activité, adresse)
- Envoyer (#id. inscrit, #id. entreprise!)
- Participant (id. inscrit, nom, adresse)

Cela permet du même coup d'éviter un champ optionnel, dont la gestion peut être délicate (notamment sous Microsoft SQL Server qui, au mépris du standard SQL, ne semble pas convaincu qu'une colonne `UNIQUE` peut contenir plus d'un `NULL` !).

#### Préciser le rôle d'une clé étrangère¶

Ce MCD modélise la soutenance de stage des étudiants, ainsi que la visite d'amitié et de contrôle dont les honore leur enseignant responsable :

In [71]:

    %%mocodo -t
    Soutenir, 01 Étudiant, 0N Date: note stage
    Étudiant: num. étudiant, nom, coordonnées

    Date: date
    Répondre de, 0N Date, 11 Étudiant, 0N Enseignant
    Enseignant: num. enseignant, nom, coordonnées

- Enseignant (num. enseignant, nom, coordonnées)
- Étudiant (num. étudiant, nom, coordonnées, date 1, note stage, date 2, #num. enseignant)

Force est de constater que la table Étudiant laisse quelque peu à désirer du point de vue sémantique :

- on ne sait pas à quoi correspondent les attributs date 1 et date 2 : ils ne peuvent en tout cas certainement pas être laissés en l'état ;
- ensuite, on pourrait avoir envie d'expliciter la raison pour laquelle un enseignant apparaît parmi les attributs d'un étudiant.

Ces précisions peuvent être apportées en insérant, entre la cardinalité et l'entité des pattes appropriées, une note entre crochets, appelée rôle. Ces rôles seront utilisés pour compléter le nom des clés étrangères correspondantes. Cela permet de réintroduire la sémantique perdue lors de la disparition des associations de dépendance fonctionnelle par lesquelles elle ont migré :

In [72]:

    %%mocodo -t mld
    Soutenir, 01 Étudiant, 0N [soutenance] Date: note stage
    Étudiant: num. étudiant, nom, coordonnées

    Date: date
    Répondre de, 0N [+ visite resp] Date, 11 Étudiant, 0N [-num. ens. resp.] Enseignant
    Enseignant: num. enseignant, nom, coordonnées

`sandbox_mld.md`

- Enseignant (num. enseignant, nom, coordonnées)
- Étudiant (num. étudiant, nom, coordonnées, date soutenance, note stage, date visite resp, #num. ens. resp.)

La composition du rôle est entièrement paramétrable :

- date soutenance : par défaut, le rôle est concaténé à la clé, avec un séparateur dépendant du gabarit (espace par défaut, tiret bas pour SQL).
- date visite resp. : `+` en préfixe supprime le séparateur.
- num. ens. resp. : `-` en préfixe supprime le nom de la clé et le remplace par le rôle.

Pour ne pas surcharger le dessin, le rôle n'est pas affiché à côté du lien, mais il apparaît au survol de la cardinalité.

Correction de la version 4.0. Dans une association réflexive hiérarchique, c'est désormais le rôle porté par la patte `*N` qui sert à rétablir la sémantique. Auparavant c'était l'inverse, en contradiction avec le traitement des associations binaires et n-aires : si vous avez utilisé des rôles dans une association réflexive avant la version 4.0.0, vous devez donc les permutez pour que Mocodo les traite correctement. Reprenons la filiation patrilinéaire :

In [73]:

    %%mocodo -t
    HOMME: num. SS, nom, prénom
    ENGENDRER, 0N [père] HOMME, 01 [fils] HOMME

- HOMME (num. SS, nom, prénom, #num. SS père)

#### Orienter la migration dans les DF à double sens¶

Lorsque toutes les cardinalités d'une dépendance fonctionnelle sont 11 (ou toutes 01), le sens de migration est spécifié à coût zéro en référençant l'entité réceptrice en tête de la liste des entités énumérées dans la clause de définition de l'association :

In [74]:

    %%mocodo -t mld diagram sql --colors mondrian
    USER: user id [VARCHAR(8)], name [VARCHAR(100)], pseudo [VARCHAR(100)]
    DF, 11 USER, 11 AUTHENTICATION
    AUTHENTICATION: email [VARCHAR(255)], password hash [BINARY(64)], salt [BINARY(16)]

`sandbox_mld.md`

- AUTHENTICATION (email, password hash, salt)
- USER (user id, name, pseudo, #email)

`sandbox_mld.svg`

`sandbox_ddl.sql`

    CREATE TABLE AUTHENTICATION (
      PRIMARY KEY (email),
      email         VARCHAR(255) NOT NULL,
      password_hash BINARY(64),
      salt          BINARY(16)
    );

    CREATE TABLE USER (
      PRIMARY KEY (user_id),
      user_id VARCHAR(8) NOT NULL,
      name    VARCHAR(100),
      pseudo  VARCHAR(100),
      email   VARCHAR(255) NOT NULL,
      UNIQUE (email)
    );

    ALTER TABLE USER ADD FOREIGN KEY (email) REFERENCES AUTHENTICATION (email);

Dans la version avec identification relative, c'est l'entité faible qui doit être placée en tête :

In [75]:

    %%mocodo -t mld diagram sql --colors mondrian
    USER: user id [VARCHAR(8)], name [VARCHAR(100)], pseudo [VARCHAR(100)]
    DF, _11 AUTHENTICATION, 11 USER
    AUTHENTICATION: email [VARCHAR(255)], password hash [BINARY(64)], salt [BINARY(16)]

`sandbox_mld.md`

- AUTHENTICATION (#user id, email, password hash, salt)
- USER (user id, name, pseudo)

`sandbox_mld.svg`

`sandbox_ddl.sql`

    CREATE TABLE AUTHENTICATION (
      PRIMARY KEY (user_id, email),
      user_id       VARCHAR(8) NOT NULL,
      email         VARCHAR(255) NOT NULL,
      password_hash BINARY(64),
      salt          BINARY(16)
    );

    CREATE TABLE USER (
      PRIMARY KEY (user_id),
      user_id VARCHAR(8) NOT NULL,
      name    VARCHAR(100),
      pseudo  VARCHAR(100)
    );

    ALTER TABLE AUTHENTICATION ADD FOREIGN KEY (user_id) REFERENCES USER (user_id);

Les traitements alternatifs (fusion en une seule table ou migration dans les deux sens) ne sont pas pris en charge par Mocodo. La dernière pratique ressortit à la phase d'optimisation et de dénormalisation de la base, qui est en dehors de sa juridiction. La seule chose que vous pouvez faire, à des fins d'illustration, est de reprendre le MLD généré pour y ajouter à la main la migration inverse. Notez cependant que les schémas logique et physique générés seront alors dépourvus de toute clé étrangère (et nécessiteront donc également d'être retouchés à la main).

In [76]:

    %%mocodo -t mld sql --colors mondrian --select all
    :
    USER: user id [VARCHAR(8)], name [VARCHAR(100)], pseudo [VARCHAR(100)], #email > AUTHENTICATION > email
    :
    AUTHENTICATION: email [VARCHAR(255)], password hash [BINARY(64)], salt [BINARY(16)], #user id > USER > user id
    :

`sandbox_mld.md`

- AUTHENTICATION (email, password hash, salt, user id)
- USER (user id, name, pseudo, email)

`sandbox_ddl.sql`

    CREATE TABLE AUTHENTICATION (
      PRIMARY KEY (email),
      email         VARCHAR(255) NOT NULL,
      password_hash BINARY(64),
      salt          BINARY(16),
      user_id       VARCHAR(42)
    );

    CREATE TABLE USER (
      PRIMARY KEY (user_id),
      user_id VARCHAR(8) NOT NULL,
      name    VARCHAR(100),
      pseudo  VARCHAR(100),
      email   VARCHAR(42)
    );

### Autres sorties relationnelles¶

#### Graphe des dépendances¶

La table A dépend de la table B lorsque A possède une clé étrangère qui est clé primaire de B. Cette notion est utile dans le cas où l'on doit importer une base de données à partir d'un ensemble de fichiers CSV (ou autres). Si l'on veut éviter de perdre le bénéfice du contrôles de clés étrangères (en faisant, p. ex. sous MySQL, `SET FOREIGN_KEY_CHECKS = 0`), il conviendra de lire ces fichiers dans un ordre topologique quelconque. Mocodo peut générer un graphe des dépendances qui met cet ordre en évidence :

In [77]:

    %mocodo -i ccp -t dependencies --defer

`ccp_dependencies.svg`

Même si un tel graphe n'est pas forcément sans circuits, remplir les tables dans le sens de lecture des langues latines minimisera le recours à la désactivation des contraintes de clés étrangères.

#### Diagramme relationnel / DDL BDML¶

D'après son site officiel :

> DBML (Database Markup Language) est un DSL (langage dédié) open-source conçu pour définir et documenter les schémas et structures de base de données. Il vise la simplicité, la cohérence et la lisibilité.

Mocodo parle maintenant DBML :

In [78]:

    %mocodo -i ccp -t dbml --title CCP

`ccp_ddl.dbml`

    dbml
    Table "Client" {
      "Réf. client" VARCHAR(8) [pk, NOT NULL]
      "Nom"         VARCHAR(255)
      "Prénom"      VARCHAR(255)
      "Adresse"     VARCHAR(255)
    }

    Table "Commande" {
      "Num. commande" VARCHAR(8) [pk, NOT NULL]
      "Date"          DATE
      "Montant"       DECIMAL(10,2)
      "Réf. client"   VARCHAR(8) [NOT NULL]
    }

    Table "Inclure" {
      "Num. commande" VARCHAR(8) [NOT NULL]
      "Réf. produit"  VARCHAR(8) [NOT NULL]
      "Quantité"      INTEGER
      Indexes {
        ("Num. commande", "Réf. produit") [pk]
      }
    }

    Table "Produit" {
      "Réf. produit"  VARCHAR(8) [pk, NOT NULL]
      "Libellé"       VARCHAR(50)
      "Prix unitaire" DECIMAL(10,2)
    }

    Ref:"Commande"."Réf. client" > "Client"."Réf. client"
    Ref:"Inclure"."Num. commande" > "Commande"."Num. commande"
    Ref:"Inclure"."Réf. produit" > "Produit"."Réf. produit"

À notre connaissance, il n'existe pas actuellement d'API publique de rendu des diagrammes DBML. Pour les visualiser, copiez-collez la sortie sur Dbdiagram.io, ou installez un plugin VS-Code :

In [79]:

    display.SVG("../examples/dbml.svg")

Out[79]:

#### Diagramme relationnel D2¶

D2 est un langage de description de diagrammes de différents types. La prise en charge des diagrammes relationnels est minimale, mais le projet est jeune (actuellement en version 0.6.1, open source depuis novembre 2022). Son point fort est TALA, son algorithme de plongement propriétaire, que vous pouvez tester ici. Celui-ci requérant une licence payante, si vous déférez le rendu, c'est le plongement par défaut (Dagre, celui de Mermaid) qui sera utilisé.

In [80]:

    %mocodo -i ccp -t d2

`ccp_ddl.d2`

    d2
    "Client": { shape: sql_table
      "Réf. client": VARCHAR(8) {constraint: PK}
      "Nom":         VARCHAR(255)
      "Prénom":      VARCHAR(255)
      "Adresse":     VARCHAR(255)
    }

    "Commande": { shape: sql_table
      "Num. commande": VARCHAR(8) {constraint: PK}
      "Date":          DATE
      "Montant":       DECIMAL(10,2)
      "Réf. client":   VARCHAR(8) {constraint: [FK; NOT NULL]}
    }

    "Inclure": { shape: sql_table
      "Num. commande": VARCHAR(8) {constraint: [PK; FK]}
      "Réf. produit":  VARCHAR(8) {constraint: [PK; FK]}
      "Quantité":      INTEGER
    }

    "Produit": { shape: sql_table
      "Réf. produit":  VARCHAR(8) {constraint: PK}
      "Libellé":       VARCHAR(50)
      "Prix unitaire": DECIMAL(10,2)
    }

    "Commande"."Réf. client" -> "Client"."Réf. client"
    "Inclure"."Num. commande" -> "Commande"."Num. commande"
    "Inclure"."Réf. produit" -> "Produit"."Réf. produit"

In [81]:

    %mocodo -i ccp -t d2 --defer

`ccp_ddl.svg`

## Autres conversions¶

### Diagramme de classes UML¶

À tout seigneur tout honneur, Mocodo peut traduire votre MCD en UML. Ce formalisme graphique n'a, curieusement, pas de DSL textuel officiel. Nous nous rabattons donc sur le standard de fait, PlantUML :

In [82]:

    %mocodo -i ccp --title CCP -t uml:plantuml=- # '-' supprime un préambule par défaut qui ne nous intéresse pas ici

`ccp_uml.puml`

    puml
    @startuml "CCP"

    !define Table(x) class "x" << (T,#FFFFFF) >>
    !define pk(x) <b>x</b>

    Table("Client") {
        {field} + pk(Réf. client) VARCHAR(8)
        {field} + Nom         VARCHAR(255)
        {field} + Prénom      VARCHAR(255)
        {field} + Adresse     VARCHAR(255)
    }

    "Client" "1" --- "*" "Commande": "Passer"

    Table("Commande") {
        {field} + pk(Num. commande) VARCHAR(8)
        {field} + Date          DATE
        {field} + Montant       DECIMAL(10,2)
    }

    "Commande" "*" --- "1..*" "Produit": "Inclure"
    ("Commande", "Produit") .. "Inclure"
    Table("Inclure") {
        {field} + Quantité INTEGER
    }

    Table("Produit") {
        {field} + pk(Réf. produit)  VARCHAR(8)
        {field} + Libellé       VARCHAR(50)
        {field} + Prix unitaire DECIMAL(10,2)
    }

    @enduml

In [83]:

    %mocodo -i ccp -t uml --defer --colors brewer+5

`ccp_uml.svg`

### ERD avec la convention Look across¶

Nouveauté de la version 4.0. Force est de reconnaître que de nos jours, les MCD à la sauce Merise ne sont plus goûtés que par une poignée d'irréductibles Gaulois (et contractuellement leurs étudiants). Dans le cadre de son projet secret de domination planétaire, Mocodo commence à faire du pied à des notations mieux comprises du reste de l'univers.

#### Notation de Chen¶

Un MCD peut être converti en un ERD (Entity-Relationship Diagram) dans la notation de Chen, sans ses attributs ou avec :

In [84]:

    %mocodo -i ccp -t chen --defer --colors ocean

`ccp_erd_chen.svg`
In [85]:

    %mocodo -i ccp -t chen:attrs --defer --colors ocean

`ccp_erd_chen.svg`

#### Notation crow's foot¶

Dans le même ordre d'idées, Mocodo peut générer des ERD dans l'astucieuse notation introduite en 1976 par Gordon Everest. Par défaut, le format du fichier intermédiaire est là encore Graphviz :

In [86]:

    %mocodo -i ccp -t crow --defer --colors brewer+3

`ccp_erd_crow.svg`

Il est également possible de demander une sortie au format Mermaid. Vous en avez un exemple dans l'introduction, nous ne le répétons pas ici. Le DSL de Mermaid est de plus haut niveau, non encombré d'informations de style. Cependant, le format Graphviz peut être préféré pour plusieurs raisons :

- on peut lui appliquer une palette de couleurs de Mocodo (cf. ci-dessus) ;
- il gère les accents ;
- il admet la virgule dans les types (Mermaid demande actuellement à transformer `DECIMAL(10,2)` en `DECIMAL(10-2)`) ;
- il peut produire de meilleurs plongements (notamment en jouant sur la valeur de l'option `--seed`) ;
- ceux-ci peuvent-être rectifiés à la main (quoique péniblement).

### Dictionnaire des données¶

Vous pouvez extraire sous forme de table diverses informations sur les attributs de votre MCD.

Un format possible est TSV. Dans ce cas, sous Jupyter Notebook, si la bibliothèque `pandas` est installée, elle sera rendue comme un dataframe :

In [87]:

    %mocodo -i ccp -t data_dict:tsv

`ccp_data_dict_3.tsv`

    Entité ou association	Libellé de l'attribut	Type
    Client	Adresse	VARCHAR(255)
    Client	Nom	VARCHAR(255)
    Client	Prénom	VARCHAR(255)
    Client	Réf. client	VARCHAR(8)
    Commande	Date	DATE
    Commande	Montant	DECIMAL(10,2)
    Commande	Num. commande	VARCHAR(8)
    Inclure	Quantité	INTEGER
    Produit	Libellé	VARCHAR(50)
    Produit	Prix unitaire	DECIMAL(10,2)
    Produit	Réf. produit	VARCHAR(8)

Le format par défaut est Markdown. Vous pouvez préciser en sous-sous-option tout ou partie des colonnes suivantes dans l'ordre où vous les souhaitez :

- `label`: le libellé de l'attribut ;
- `type` : son type ou un descriptif (auquel cas il conviendra de changer le nom de la colonne) ;
- `box` : le nom de l'entité ou association où il se trouve.

Entourez ces noms de colonnes de balises Markdown pour les mettre en forme (pas d'incidence en TSV). Faites-les suivre de `="Nom de colonne personnalisé"` pour éviter la valeur par défaut (dépendante de l'option `language`). Dans l'exemple ci-dessous, les sous-sous-options se décodent ainsi :

- `**box**="Entité ou association"` : boîtes en colonne 1, en-tête personnalisé, cellules en gras ;
- `label` : libellé des attributs en colonne 2 ;
- ``type```=```Type`` : types en colonne 3, en-tête personnalisé et cellules dans une police non proportionnelle.

In [88]:

    %mocodo -i ccp -t data_dict:**box**="Entité ou<br>association",label,`type`=`"Type de données"`

`ccp_data_dict_3.md`

Entité ou association | Libellé de l'attribut | `Type de données`
--- | --- | ---
Client | Adresse | `VARCHAR(255)`
" | Nom | `VARCHAR(255)`
" | Prénom | `VARCHAR(255)`
" | Réf. client | `VARCHAR(8)`
Commande | Date | `DATE`
" | Montant | `DECIMAL(10,2)`
" | Num. commande | `VARCHAR(8)`
Inclure | Quantité | `INTEGER`
Produit | Libellé | `VARCHAR(50)`
" | Prix unitaire | `DECIMAL(10,2)`
" | Réf. produit | `VARCHAR(8)`

Aménités.

- Au format Markdown, les répétitions de cellules de la première colonne sont remplacées par un guillemet itératif.
- Le tableau est automatiquement trié selon sa première, puis éventuellement deuxième et troisième colonnes.
- Si une seule colonne est demandée, la ligne d'en-tête n'est pas générée et, en Markdown, c'est une liste qui est produite.

In [89]:

    %mocodo -i ccp -t data_dict:label

`ccp_data_dict_1.md`

- Adresse
- Date
- Libellé
- Montant
- Nom
- Num. commande
- Prix unitaire
- Prénom
- Quantité
- Réf. client
- Réf. produit

Nouveautés de la version 4.0.

- Sélection, ordre et nommage des colonnes, mise en forme Markdown, tri, guillemets itératifs.
- Remplacement par un algorithme dédié du gabarit relationnel utilisé (abusivement) dans les versions antérieures.

### URL de partage¶

Vous pouvez demander à encoder le texte-source de votre MCD dans un lien vers Mocodo online, qui le composera automatiquement dans la zone d'entrée :

In [90]:

    %mocodo -i ccp -t share

`ccp_url.url`

    https://www.mocodo.net/?mcd=eNptkMEKgkAQhu89xRwLJDQQwtuySgm5mEgX6bDlBgu6xrYLvZLP4Ys1ahZYt_m_Yeb_Z2glhTIBZF17W8N1UFCcSEb3JFtuV2cHWFN_ycb3e5bqrlV_OCm1eDzEjC9SjlA74DKgg4UDnge0qWuuSrGYigCYrTHFW85yhNwgCkkeoUgaZXgfNYxonJDD0nOdDTrF6lpZLXA_--wffFPdlFbipUeLc9J0LRQxy6NdlGG-qTm-4T7Kmf9BXkRV9XMT9t3xF_IJVknDpRY_gV4LRG5Z

# Mocodo pour la pédagogie¶

## Vue en extension¶

Un chiffre ou tiret bas à la fin du nom d'une boîte (entité ou association) est utilisé en interne pour distinguer cette boîte des autres, mais n'est pas affiché dans le diagramme conceptuel. Cela peut servir à produire une vue en extension d'un MCD.

Voici par exemple le MCD que j'utilise en cours pour introduire la notion d'entité faible (à gauche, vue en compréhension, à droite vue en extension):

In [91]:

    %%mocodo
    ŒUVRE1: cote, titre, date de publication
    :::
    ŒUVRE2: 612.NAT.34, J'apprends à lire à mes souris blanches, mai 1975
    :

    DF, 1N ŒUVRE1, _11 EXEMPLAIRE1
    ::
    DF, XX ŒUVRE2, XX EXEMPLAIRE2
    DF, XX ŒUVRE2, XX EXEMPLAIRE3
    DF, XX ŒUVRE2, XX EXEMPLAIRE4

    EXEMPLAIRE1: numéro d'exemplaire, état, date d'achat
    ::
    EXEMPLAIRE2: 1, bon état, 12/6/1975
    EXEMPLAIRE3: 2, bon état, 1/8/1977
    EXEMPLAIRE4: 3, reliure rongée, 3/4/2005

Mocodo n'interdit pas la conversion en relationnel d'un tel MCD, mais celle-ci n'a aucun sens.

Si l'on veut garder les cardinalités sans les afficher, on peut les préfixer d'un `-`. Le résultat de la conversion en relationnel peut alors être interprété comme l'ensemble des lignes des différentes tables.

In [92]:

    %%mocodo -t
    ŒUVRE: 612.NAT.34, J'apprends à lire à mes souris blanches, mai 1975

    DF, -1N ŒUVRE, -_11 EXEMPLAIRE1
    DF, -1N ŒUVRE, -_11 EXEMPLAIRE2
    DF, -1N ŒUVRE, -_11 EXEMPLAIRE3

    EXEMPLAIRE1: 1, bon état, 12/6/1975
    EXEMPLAIRE2: 2, bon état, 1/8/1977
    EXEMPLAIRE3: 3, reliure rongée, 3/4/2005

- EXEMPLAIRE (#612.NAT.34, 1, bon état, 12/6/1975)
- EXEMPLAIRE (#612.NAT.34, 2, bon état, 1/8/1977)
- EXEMPLAIRE (#612.NAT.34, 3, reliure rongée, 3/4/2005)
- ŒUVRE (612.NAT.34, J'apprends à lire à mes souris blanches, mai 1975)

## MCD interactif¶

### Afficher des explications au survol¶

Les débutants ont souvent des doutes sur la sémantique de telle ou telle cardinalité. Cette information peut être incluse dans le texte-source en annotant les pattes correspondantes. Survolez les cardinalités du MCD ci-dessous pour faire apparaître leur description.

In [3]:

    %%mocodo
    Produit: réf. produit, libellé, prix unitaire
    Inclure, 1N [Une commande inclut au moins un produit.] Commande, 0N [Un produit peut être commandé un nombre quelconque de fois.] Produit: quantité
    Commande: num. commande, date, montant
    DF, 0N [Un client peut passer zéro (prospect) ou plusieurs commandes.] Client, 11 [Une commande est passée par un et un seul client.] Commande
    Client: réf. client, nom, adresse
    Parrainer, 01 [Un client peut avoir été parrainé ou non.] Client, 0N [Un client peut parrainer d'autres clients.] Client : date parrainage

Nouveauté de la version 4.3. Avec l'option `-t prompt:cards`, Mocodo compose un prompt à copier-coller sous ChatGPT (ou autre) pour compléter le MCD avec de telles descriptions. Ce prompt est trop long pour être reproduit ici : il consiste en une présentation de la syntaxe de Mocodo, des instructions sur le travail demandé, plusieurs exemples corrigés, et enfin le MCD à compléter. Voici par exemple les explications générées par DeepSeek pour le MCD de la page d'accueil de Mocodo online :

In [4]:

    %%mocodo
    AYANT-DROIT: nom ayant-droit, lien
    DIRIGER, 0N [Un employé peut diriger zéro ou un projet.] EMPLOYÉ, 01 [Un projet est dirigé par au plus un employé.] PROJET
    REQUÉRIR, 1N [Un projet requiert au moins une pièce.] PROJET, 0N [Une pièce peut être requise par plusieurs projets.] PIÈCE: qté requise
    PIÈCE: réf. pièce, libellé pièce
    COMPOSER, 0N [Une pièce peut être composée de plusieurs autres pièces.] PIÈCE, 0N [Une pièce peut entrer dans la composition de plusieurs autres pièces.] PIÈCE: quantité

    DF, _11 [Un ayant-droit est associé à un et un seul employé.] AYANT-DROIT, 0N [Un employé peut avoir plusieurs ayants-droit.] EMPLOYÉ
    EMPLOYÉ: matricule, nom employé
    PROJET: num. projet, nom projet
    FOURNIR, 1N [Un projet est fourni par au moins une société.] PROJET, 1N [Une pièce est fournie par au moins une société.] PIÈCE, 1N [Une société fournit au moins une pièce pour un projet.] SOCIÉTÉ: qté fournie

    DÉPARTEMENT: num. département, nom département
    EMPLOYER, 11 [Un employé appartient à un et un seul département.] EMPLOYÉ, 1N [Un département emploie au moins un employé.] DÉPARTEMENT
    TRAVAILLER, 0N [Un employé peut travailler sur plusieurs projets.] EMPLOYÉ, 1N [Un projet implique au moins un employé.] PROJET
    SOCIÉTÉ: num. société, raison sociale
    CONTRÔLER, 0N< [Une société peut en contrôler une autre.] SOCIÉTÉ, 01 [Une société est contrôlée par au plus une autre société.] SOCIÉTÉ

Le résultat est en général plus qu'honorable, mais demande à être relu attentivement pour vérifier l'adhérence au MCD original, corriger d'éventuelles hallucinations ou apporter des précisions. Ci-dessus, en l'occurrence, une société peut en contrôler plusieurs autres (et non une autre).

Différence syntaxique entre rôles et explications. Remarquez que la syntaxe est la même que pour les rôles, qui sont en plus utilisés lors du passage au relationnel. Comment Mocodo fait-il la différence ? En appliquant les règles suivantes :

- si la note de patte commence par `+` ou `-`, ou qu'elle ne contient aucun espace, c'est un rôle.
- sinon, c'est une description de cardinalité.

Explication de contraintes. Le même principe s'applique aux contraintes (survolez le Ⓘ) :

In [94]:

    %%mocodo
    Projet: num. projet, nom projet
    :
    Fournir, 1N Projet, 1N Pièce, 1N Société: quantité
    Société: num. société, raison sociale

    Requérir, 1N Projet, 0N Pièce: quantité
    :
    Pièce: réf. pièce, libellé pièce

    (I) [Toute pièce fournie doit avoir été requise.] ..Pièce, ->Requérir, --Fournir, Projet

Limitations.

- Non pris en charge par les éditeurs de SVG comme Inkscape.
- Ne semble pas fonctionner dans une page HTML statique (comme la version HTML de ce document sous GitHub).
- Nécessite de faire confiance à un notebook (Trust notebook) pour s'afficher à la réouverture.

### Dévoiler un MCD par étapes¶

Nouveauté de la version 3. Il est possible de faire apparaître progressivement les différentes « boîtes » constituant un MCD. Pour cela, il suffit d'indenter (décaler vers la droite à l'aide d'espaces ou de tabulations) au moins une ligne. Les éléments correspondants seront alors répartis sur autant de « calques » qu'il y a de niveaux d'indentations.

Voici par exemple un exercice consistant en la description du « réel perçu » d'une entreprise de VPC :

> 1. Un produit est connu par une référence, un libellé et un prix unitaire.
> 2. Toute commande inclut un produit ou plusieurs, chacun en une certaine quantité.
> 3. Un client peut passer zéro (client potentiel) ou plusieurs commandes.
> 4. Un client peut entrer dans la base par parrainage d'un autre client.

L'enseignant peut le présenter pas à pas en suivant les étapes de l'énoncé :

In [95]:

    %%mocodo --colors ocean
          Parrainer, 01 Client, 0N Client : date parrainage
    Produit: Réf. produit, Libellé, Prix unitaire
      Inclure, 1N Commande, 0N Produit: Quantité

        Client: Réf. client, Nom, Prénom, Adresse
        DF, 0N Client, 11 Commande
      Commande: Num. commande, Date, Montant

Remarques.

- Pas de règle sur la taille de l'indentation. Pour Mocodo, autant de niveaux d'indentation distincts, autant de calques.

- Les différents calques sont codés directement dans le SVG. L'interaction ne nécessite donc aucun logiciel spécifique.

- Sous Mocodo online, le MCD est toujours présenté entièrement dévoilé. Cela permet de voir directement le résultat d'une modification du texte-source.

- Pour ajouter facilement de l'interactivité à un MCD existant :

  1. commencez par indenter au maximum toutes les lignes ;
  2. effacez l'indentation des lignes du premier calque ;
  3. décalez votre curseur de $n$ caractères vers la droite ;
  4. placez-vous tour à tour sur les lignes à intégrer au deuxième calque et effacez les espaces surnuméraires ;
  5. recommencez à l'étape 3 jusqu'au dernier calque.

  Depuis la version 4.0, l'éditeur de Mocodo online vous permet de créer des curseurs multiples, ce qui simplifie encore ces opérations.

Limitations.

- Pas de granularité plus fine que la ligne (entité ou association avec toutes ses pattes et cardinalités).
- Pas de prise en charge des touches directionnelles. Cela serait sans doute possible, mais difficilement compatible avec la présence de plusieurs MCD interactifs sur une même page (comme dans cette documentation).

Éviter qu'une interaction sur un SVG ne s'applique à un autre.

Dans le cas très rare où plusieurs SVG interactifs générés à partir du même texte-source coexistent sur une même page web, une interaction opérée sur l'un s'applique également à tous les autres. Par exemple, cliquer sur l'un des ronds gris de l'une des figures ci-dessous agira sur les deux figures :

In [96]:

    %%mocodo
    FOO: foo
      BAR: bar

In [97]:

    %%mocodo
    FOO: foo
      BAR: bar

Ce problème trahit une « collision » : différents éléments du DOM se sont vus attribuer la même empreinte (obtenue par hachage du texte-source). La solution est de passer un entier discriminant qui, par concaténation, fera de ces empreintes de véritables identifiants.

In [98]:

    %%mocodo --uid_suffix 1
    FOO: foo
      BAR: bar

In [99]:

    %%mocodo --uid_suffix 2
    FOO: foo
      BAR: bar

## Explications du passage au relationnel¶

Les gabarits de conversion en MLD (à savoir `html`, `markdown`, `latex` et `text`) admettent une sous-sous-option `e` qui accompagne le résultat par des explications détaillées du mécanisme de passage :

In [100]:

    %mocodo -i ccp -t markdown:e

`ccp_mld.md`

- Client (Réf. client, Nom, Prénom, Adresse)

  - Le champ Réf. client constitue la clé primaire de la table. C'était déjà un identifiant de l'entité Client.
  - Les champs Nom, Prénom et Adresse étaient déjà de simples attributs de l'entité Client.

- Commande (Num. commande, Date, Montant, #Réf. client)

  - Le champ Num. commande constitue la clé primaire de la table. C'était déjà un identifiant de l'entité Commande.
  - Les champs Date et Montant étaient déjà de simples attributs de l'entité Commande.
  - Le champ Réf. client est une clé étrangère. Il a migré par l'association de dépendance fonctionnelle Passer à partir de l'entité Client en perdant son caractère identifiant.

- Inclure (#Num. commande, #Réf. produit, Quantité)

  - Le champ Num. commande fait partie de la clé primaire de la table. C'est une clé étrangère qui a migré directement à partir de l'entité Commande.
  - Le champ Réf. produit fait partie de la clé primaire de la table. C'est une clé étrangère qui a migré directement à partir de l'entité Produit.
  - Le champ Quantité était déjà un simple attribut de l'association Inclure.

- Produit (Réf. produit, Libellé, Prix unitaire)

  - Le champ Réf. produit constitue la clé primaire de la table. C'était déjà un identifiant de l'entité Produit.
  - Les champs Libellé et Prix unitaire étaient déjà de simples attributs de l'entité Produit.

Nous avons essayé d'être aussi précis que possible, tout en « factorisant » avec soin les lignes consécutives suseptibles de l'être. Vous pouvez adapter ces explications à votre enseignement en modifiant une copie du gabarit `html-ce.yaml`, dont les autres sont dérivés.

## MCD à compléter¶

Les MCD à trous sont des exercices classiques d'introduction aux bases de données.

### Supprimer le marquage d'un identifiant¶

Pour éviter le marquage automatique du premier attribut d'une entité comme identifiant, il suffit de le préfixer par un tiret bas (`_`) : ce caractère est donc un commutateur, qui souligne un attribut non souligné par défaut, et désouligne un attribut souligné par défaut.

In [101]:

    %%mocodo
    CLIENT: _Réf. client, Nom, Prénom, Adresse
    PASSER, 0N CLIENT, 11 COMMANDE
    COMMANDE: _Num. commande, Date, Montant
    INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité
    PRODUIT: _Réf. produit, Libellé, Prix unitaire

### Masquer un couple de cardinalités¶

Vous pouvez masquer n'importe quelles cardinalités en les remplaçant par `XX` ou en les préfixant d'un `-` :

In [102]:

    %%mocodo
    CLIENT: Réf. client, Nom, Prénom, Adresse
    PASSER, XX CLIENT, XX COMMANDE
    COMMANDE: Num. commande, Date, Montant
    INCLURE, -1N COMMANDE, -0N PRODUIT: Quantité
    PRODUIT: Réf. produit, Libellé, Prix unitaire

Nouveauté de la version 4.0. Si la cardinalité comporte un et un seul `X`, l'autre caractère sera affiché tout seul.

### Masquer un attribut¶

Vous pouvez mettre deux virgules consécutives pour réserver la place d'un attribut manquant. Les espaces insécables sont préservés, ce qui permet de réserver plus d'espace horizontal, cf. ci-dessous premier attribut vide de INCLURE.

In [103]:

    %%mocodo
    CLIENT: Réf. client,,,
    PASSER, XX CLIENT, XX COMMANDE
    COMMANDE: , Date, Montant
    INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité,,,,
    PRODUIT: Réf. produit, Libellé, Prix unitaire

Régression de la version 4.0. Les espaces insécables ne sont plus préservés. Il n'y a donc plus d'autre moyen de réserver davantage d'espace horizontal que d'employer le style `blank` (paragraphe suivant).

### Ne faire apparaître que le squelette du schéma conceptuel¶

Vous pouvez transformer en exercice à trous n'importe quel MCD en rendant complètement transparentes les couleurs des attributs, associations et cardinalités. Le style `blank` a été prédéfini à cet effet:

In [104]:

    %mocodo -i ccp --colors=blank

Attention, n'utilisez cette méthode que pour la projection : l'information textuelle est toujours présente, susceptible d'être sélectionnée et collée ailleurs. Vous pouvez bien sûr empêcher cette possibilité en convertissant le SVG en PNG, mais le plus simple est d'appliquer une réécriture `empty` :

In [105]:

    %mocodo -i ccp -t empty # équivalent de "delete:types,notes,attrs,cards"

`ccp.mcd`

    %%mocodo
    Client:  ,  ,  ,
    Passer, XX Client, XX Commande
    Commande:  ,  ,
    Inclure, XX Commande, XX Produit:
    Produit:  ,  ,

## Obfuscation d'un MCD donné¶

Obfusquer un MCD consiste à vider celui-ci de sa sémantique de surface en substituant des chaînes aléatoires à tous les libellés. Cela permet de créer des exemples d'illustration de telle ou telle notion « pure » sans risquer de voir son public se focaliser sur des détails-métier (c'est l'équivalent de la variable méta-syntaxique `foobar` dans le contexte de la pédagogie de la programmation).

In [106]:

    %mocodo -i ccp --seed=1 --select mcd -t obfuscate  # raccourci pour "obfuscate:labels"

En argument, vous pouvez ajouter le chemin d'un fichier texte quelconque où puiser les mots de substitution. Par exemple, le texte du `README` de ce projet :

In [107]:

    %mocodo -i ccp -t obfuscate:labels=../../README.md --seed=1 --select mcd

Mocodo essaie d'abord de trouver ce fichier à l'endroit indiqué. En cas d'échec, il le cherche (avec extension `.txt` facultative) parmi ceux distribués avec le logiciel, à savoir:

- `"lorem.txt"` (6464 mots) : le faux-texte le plus courant, augmenté d'une sélection des 10000 mots latins les plus courants compilés par Kyle P. Johnson, le tout privé de ses doublons et des mots de moins de 3 lettres (`"lorem_ipsum.txt"` avant la version 4.0).
- `"fr.txt"` (3396 mots) : une liste des 4000 mots français les plus courants, privée de ceux comportant une apostrophe ou moins de 4 lettres. Source : http://wortschatz.uni-leipzig.de/index.html via Wikitionary. Nouveauté de la version 4.0.
- `"fr5.txt"` (464 mots): la liste de `"fr.txt"`, restreinte aux mots de 5 lettres. Nouveauté de la version 4.0.
- `"en4.txt"` (640 mots): une sélection (SFW) de mots anglais de quatre lettres (`"four_letter_words.txt"` avant la version 4.0).
- `"disparition.txt"` (7489 mots) : le lexique du célèbre roman lipogrammatique de Georges Perec, privé des mots de moins de 4 lettres.

En cas de nouvel échec, il se rabat sur `"lorem.txt"`.

NB. L'algorithme s'assure que la distance de Damerau-Levenshtein entre deux libellés de substitution quelconques est d'au moins 3. En clair, cela signifie que, si vous donnez en examen un exercice de conversion en relationnel basé sur un tel MCD, les erreurs de transcription d'un étudiant stressé, inattentif, illettré, dyslexique, roublard, ou tout cela à la fois, ne devraient pas vous empêcher de lui octroyer les points qui lui reviennent.

## Croissance stochastique¶

Vous pouvez créer un MCD partiellement aléatoire à partir d'un MCD donné en lui ajoutant un nombre `n` d'associations (avec les entités nécessaires) :

In [108]:

    %mocodo -i ccp -t grow:n=4 arrange --seed=1 --select mcd

- Des sous-options pré-définies (données ci-dessous avec leur valeur par défaut après le `=`) permettent de spécifier finement le nombre désiré :

  - d'associations réflexives (`arity_1=2`) ;
  - d'associations ternaires (`arity_3=2`) ;
  - d'associations quaternaires (`arity_4=0`) ;
  - d'associations doubles, i.e., associant le même couple d'entités (`doubles=1`) ;
  - d'identifiants composites (`composites=1`) ;
  - d'attributs maximum par entité (`ent_attrs=4`) ;
  - d'attributs maximum par association (`assoc_attrs=2`).

- On ne peut pas préciser directement le nombre d'associations binaires : si le nombre total des autres associations spécifiées n'arrivent pas à `n`, elles viennent en complément.

- Des sous-options de forme plus ou moins libre décrivent les cardinalités. Par exemple, `_11-*N=2` créera deux entités faibles et `/*N-*N` un agrégat. Les associations de complément sont `*N-*N`.

Avec la sous-option `from_scratch`, le MCD de départ est vide. À titre d'exemple, voici la transformation complexe invoquée par Mocodo online pour créer un MCD d'entraînement à la conversion au relationnel, accompagné de cette dernière. Notez la création de rôles par défaut : ils permettent de simuler le rétablissement de la sémantique des associations disparues.

In [109]:

    %mocodo --seed=2 --mld -t grow:from_scratch,arity_3=1,_11-*N=1 obfuscate create:roles lower:roles arrange

- Absit (#faciendam, #insidiis)
- Ademptum (#insidiis, #interdum, #vasa, #tura)
- Aetatem (#cornua, #insidiis)
- Crebra (cornua, dimidio, mario, caecus, #cornua ceciderunt)
- Crudelitatem (faciendam, menses)
- Discipulus (vendidit, integris, alexandro)
- Occisus (magnus, ennius, capuam, quaestiones, #vendidit serum, #insidiis serum, putabant, #cornua iurandum)
- Periculosum (insidiis, amplexus, paret)
- Pisces (ageretur, status, societatem)
- Postremum (#sardiniam, #ageretur)
- Quoniam (sardiniam, claudio, infestus)
- Tenebant (#insidiis, #interdum, #vasa, #tura)
- Vellent (interdum rupit, vasa rupit, tura, gracchus, miraculo, #sardiniam virilem)

Il n'est pas impossible que le MCD résultant soit incorrect (p. ex., apparition d'une identification relative circulaire), mais les contrôles effectués a priori et a posteriori devraient dans la majorité des cas produire quelque chose de raisonnable.

## Génération d'un QR code¶

Impressionnez votre public en accompagnant l'option `-t share` de `--defer` :

In [110]:

    %mocodo -i ccp -t share --defer

`ccp_url.svg`

Limitation. Comme il faut un mobile pour scanner ce QR code, et que Mocodo online n'est pas vraiment adapté aux mobiles, l'intérêt réel de cette fonctionnalité est pour l'instant discutable.

## Bibliothèque de MCD en ligne¶

Vous avez créé avec Mocodo toute une bibliothèque de MCD, certains pour illustrer des points de votre cours, d'autres comme solutions d'exercices. À partir de la version 4.1, vous pouvez donner accès à tel ou tel de ces MCD en communiquant simplement son nom à vos étudiants.

### Accès sous Mocodo online¶

Pour comprendre le fonctionnement, accédons à un MCD de la bibliothèque par défaut : copiez-collez la chaîne `def_weak-974e` comme titre du MCD dans l'onglet Entrée de Mocodo online. Le texte-source est mis à jour avec le contenu d'un fichier `def_weak-974e.mcd` stocké en ligne :

Remarques.

- Vous avez sans doute déjà utilisé cette fonctionnalité sans le savoir en parcourant le tutoriel, dont les MCD, appelés `tuto-0000`, `tuto-0001`, etc., sont récupérés de la même manière.
- Tous les noms de fichiers de la bibliothèque par défaut se terminent par un code de quatre caractères alphanumériques : cette disposition évite qu'un utilisateur ne tombe dessus par hasard, et protège certains MCD (typiquement, les solutions d'exercices) de la curiosité naturelle des étudiants. Au moment de la correction, je leur donne simplement le nom complet, et ils récupèrent directement la solution, ce qui dégage du temps pour des activités plus éducatives que la recopie.

Bien sûr, la plupart des MCD de la bibliothèque par défaut n'intéressent que mon enseignement, et n'ont pas vocation à être diffusés au-delà du cercle très select des happy few qui en bénéficient.
Pour mettre votre propre bibliothèque à la disposition de vos propres étudiants :

1. placez-la dans un répertoire dédié d'un serveur sur lequel vous avez les droits ;
2. copiez-collez l'URL de ce répertoire dans le champ Bibliothèque de MCD (onglet Options). Désormais, c'est à cette adresse que Mocodo essaiera de trouver les MCD quand vous mettrez à jour leur titre ;
3. vos étudiants devront eux-mêmes avoir renseigné le champ en question, ce qui peut poser des problèmes à certains. Facilitez-leur la tâche en leur donnant le lien suivant (tout ce qui suit `lib=` doit bien sûr être remplacé par l'adresse de votre répertoire distant) :

    https://www.mocodo.net/?lib=https://your_server.com/path/to/your/mcd/directory

Ils n'auront plus qu'à cliquer pour remplir automatiquement le champ approprié, lequel persistera dans les cookies de leur navigateur.

### Accès sous terminal ou Jupyter Notebook¶

L'option `--input` (ou `-i`) est surchargée pour aller chercher un MCD sur internet s'il ne se trouve pas dans le répertoire local. Pour commencer la démonstration, assurons-nous que le fichier en question n'existe pas en local :

In [111]:

    path = Path("def_weak-974e.mcd")
    path.unlink(missing_ok=True)
    path.is_file()

Out[111]:

    False

Récupérons-le de façon transparente dans la bibliothèque par défaut (avec ou sans extension `.mcd`) :

In [112]:

    %mocodo -i def_weak-974e.mcd

Notez qu'au passage, pour le rendre disponible hors ligne, le fichier a été sauvegardé sur votre machine :

In [113]:

    path.is_file()

Out[113]:

    True

NB. Si le paramètre de `-i` est un chemin de la forme `path/to/file.mcd` (avec ou sans extension `.mcd`), c'est la dernière partie du chemin (à savoir `file.mcd`) qui sera récupérée sur le serveur. Par contre, c'est le chemin complet qui déterminera l'emplacement de la sauvegarde.

Pour utiliser votre propre répertoire distant, passez son URL à l'option `--lib` :

    mocodo -i your_diagram.mcd --lib https://your_server.com/path/to/your/mcd/directory

Nous vous conseillons d'ajouter cette option dans votre fichier de paramètres personnalisé `params.json`.

# Compléments sur l'aspect visuel¶

## Styles¶

Plusieurs styles prédéfinis sont distribués avec l'application. Un style se définit comme la combinaison d'une palette de couleurs (répertoire `colors`) avec un dictionnaire de polices et de dimensions (répertoire `shapes`).

Vous pouvez bien sûr créer vos propres styles en vous inspirant des fichiers fournis. Si vous êtes particulièrement content d'un style, soumettez-le pour inclusion dans une prochaine distribution.

Réglages. Une approximation de la largeur des caractères des différentes polices a été pré-calculée sous macOS. Il est possible qu'elle soit inexacte, en particulier sous Windows ou Linux. Dans ce cas, en particulier, les traits de soulignement n'atteindront pas ou excéderont la largeur des libellés soulignés. Vous pouvez contourner le problème en appliquant un facteur multiplicatif avec l'argument `--adjust_width`).

## Paramétrage du réarrangement automatique¶

Il est possible de demander à Mocodo de chercher tout seul une « bonne » permutation des définitions des boîtes, ce qui à la main deviendrait vite difficile.

Le critère que nous avons retenu pour évaluer la qualité du tracé est double :

1. les liens ne doivent pas se couper ;
2. leur longueur cumulée doit être minimale.

Actuellement, deux algorithmes d'arrangement sont fournis :

- un algorithme exact (`bb`, pour Branch & Bound), qui ne trouve que des solutions satisfaisant au premier critère ;
- un algorithme approché (`ga`, pour Genetic Algorithm), réservé aux cas où il est impossible d'y satisfaire. L'algorithme va alors chercher des solutions où les liens se coupent seulement le moins possible.

Remarque. Mocodo met en œuvre une technique de réarrangement originale : en contraignant la position des boîtes aux intersections d'une grille invisible, il transforme un classique problème de plongement en un problème d'affectation, ce qui permet de satisfaire de façon efficace à un certain nombre de contraintes esthétiques pertinentes (planarité, compacité, etc.).

Nous illustrerons les algorithmes et leurs paramètres sur le MCD d'accueil de Mocodo online.

Le réarrangement automatique peut se faire sans contraintes, ou dans les limites d'une grille spécifiée par l'utilisateur.

### Méthode exacte (branch & bound)¶

#### Arrangement non contraint (par défaut)¶

Le réarrangement dit organique consiste à choisir une première boîte au hasard, puis à essayer d'agréger les autres sans se préoccuper de contenir le tout dans une grille prédéterminée :

In [114]:

    %mocodo -i ../examples/landing --select mcd --seed=2 -t arrange

Cela donne un plongement sur une grille $5\times4$, ce qui est loin d'être optimal. Cependant, l'arrangement organique fournit souvent un bon point de départ pour chercher soi-même une permutation plus esthétique ou mettant en évidence certaines propriétés du MCD.

#### Arrangement dans la grille courante¶

Le réarrangement automatique des boîtes peut s'opérer dans les limites de la grille courante ; c'est-à-dire que le MCD résultant aura (au plus) le même nombre de colonnes et de rangées que le texte de départ (ici, $4\times5$) :

In [115]:

    %mocodo -i ../examples/landing --select mcd --seed=2 -t arrange:current

#### Arrangement en privilégiant la largeur¶

Dans un document paginé, on cherche en général à utiliser en priorité l'espace horizontal. La version 4.0 introduit à cet effet une option de réarrangement « en largeur d'abord ». Le MCD d'accueil s'y prête particulièrement bien :

In [116]:

    %mocodo -i ../examples/landing --select mcd --seed=2 -t arrange:wide=8 --scale 0.8

Ici, l'utilisateur a demandé $8$ boîtes en largeur (c'est aussi la valeur par défaut). L'algorithme commence par calculer le nombre de lignes minimal correspondant, sachant qu'il a $14$ boîtes à placer : c'est $\lceil14/8\rceil=2$. Il cherche donc un plongement sur une grille $8\times2$.

#### Arrangement dans une grille équilibrée minimale¶

On peut chercher à faire tenir le MCD dans la plus petite grille possible, tout en maintenant entre hauteur et largeur un rapport « équilibré » (ou proche du nombre d'or). Par exemple, un MCD de 13 boîtes (entités ou associations) peut tenir dans les grilles:

- $13\times1$;
- $7\times2$, ce qui laisse 1 case vide;
- $5\times3$, ce qui laisse 2 cases vides;
- $4\times4$, ce qui laisse 3 cases vides;
- etc.

Les deux premières grilles étant non équilibrées, on retiendra la plus petite des suivantes, de dimensions $5\times3$.

La table ci-dessous énumère les dimensions des grilles minimales d'équilibre supérieur à 0,5 pour tous les MCD comportant moins de 100 boîtes. On peut y vérifier par exemple que le MCD de taille 13 (en gras) se trouve effectivement aux coordonnées (5, 3).

| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13
--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---
1 | 1 | 2 | 3 |  |  |  |  |  |  |  |  |  |
2 |  | 4 | 5, 6 |  |  |  |  |  |  |  |  |  |
3 |  |  | 7, 8, 9 | 10, 11, 12 | 13, 14, 15 |  |  |  |  |  |  |  |
4 |  |  |  | 16 | 17, 18, 19, 20 | 21, 22, 23, 24 | 26, 27, 28 |  |  |  |  |  |
5 |  |  |  |  | 25 | 29, 30 | 31, 32, 33, 34, 35 | 37, 38, 39, 40 | 43, 44, 45 |  |  |  |
6 |  |  |  |  |  | 36 | 41, 42 | 46, 47, 48 | 50, 51, 52, 53, 54 | 57, 58, 59, 60 | 65, 66 |  |
7 |  |  |  |  |  |  | 49 | 55, 56 | 61, 62, 63 | 67, 68, 69, 70 | 73, 74, 75, 76, 77 | 82, 83, 84 | 91
8 |  |  |  |  |  |  |  | 64 | 71, 72 | 78, 79, 80 | 85, 86, 87, 88 | 92, 93, 94, 95, 96 |
9 |  |  |  |  |  |  |  |  | 81 | 89, 90 | 97, 98, 99 |  |
10 |  |  |  |  |  |  |  |  |  | 100 |  |  |

Le MCD d'accueil ayant déjà été arrangé avec l'option `-t arrange:balanced`, nous ne le reproduisons pas ici. Sachez cependant qu'au cas où, pour une raison ou une autre, la plus petite grille équilibrée ne convient pas, il est possible de passer à la $i^\text{e}$ suivante en mettant $i$ en sous-sous-argument. Ici, pour $14$ boîtes, `balanced=1` permet donc de passer de la grille $5\times3$ (prévue pour $13$, $14$ et $15$ boîtes) à la grille $4\times4$ (prévue pour $16$ boîtes).

In [117]:

    %mocodo -i ../examples/landing --select mcd --seed=1 -t arrange:balanced=1

#### Limitations de la méthode exacte¶

Le réarrangement exact ne fonctionnera jamais sur les MCD non planaires ou n'admettant aucun plongement planaire dans les limites de la grille spécifiée (par les sous-options `current`, `wide` ou `balanced`).

Rappelons qu'un graphe est dit planaire lorsqu'il en existe au moins un arrangement sans croisement. Le graphe non planaire comportant le plus petit nombre de liens est connu sous le doux nom de $K_{3,3}$ :

In [118]:

    %%mocodo
    DIGNISSIM: nec sem, nunc, vulputate
    IMPERDIET: a praesent, nibh, semper
    TINCIDUNT: faucibus, orci, cursus

    RHONCUS, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
    SODALES, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
    QUIS ENIM, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT

Son réarrangement par Branch & bound échouera donc nécessairement :

In [119]:

    %mocodo -i sandbox --seed=1 -t arrange:balanced

    Mocodo Err.9 - Impossible de calculer un plongement planaire satisfaisant la contrainte
    donnée.

Comme on voit, Mocodo ne cherche pas à savoir si la non-planarité est intrinsèque au graphe, ou résulte des dimensions de la grille imposée pour le plongement. Pour en avoir le cœur net, tentez un arrangement non contraint :

In [120]:

    %mocodo -i sandbox --seed=1 -t arrange

    Mocodo Err.41 - Impossible de calculer un plongement planaire.

NB. Plusieurs paramètres permettent de régler le fonctionnement de l'algorithme exact (Branch and Bound) :

- `call_limit` : nombre maximal d'appels pour une boîte de départ donnée (défaut: `10000`).
- `min_objective` : meilleur objectif esthétique pour la mise en page (défaut: `0`).
- `max_objective` : pire objectif esthétique pour la mise en page (défaut: `15`).

Réservés aux spécialistes, ils ne sont pas décrits dans cette documentation.

### Méthode heuristique (algorithme génétique)¶

Dans tous les cas où la méthode exacte ne produit pas de résultat satisfaisant, on pourra se rabattre sur une heuristique qui, au lieu d'interdire les croisements, cherchera simplement à en minimiser le nombre.

In [121]:

    %mocodo -i sandbox --seed=1 -t arrange:algo=ga

`sandbox.mcd`

    %%mocodo --seed=1
    DIGNISSIM: nec sem, nunc, vulputate
    RHONCUS, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
    IMPERDIET: a praesent, nibh, semper

    SODALES, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
    TINCIDUNT: faucibus, orci, cursus
    QUIS ENIM, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT

L'amélioration ne saute pas forcément aux yeux, mais il n'y a plus que trois croisements au lieu de neuf. Ce plongement constitue en tout cas un bon point de départ pour un réarrangement manuel. Il ne reste en effet plus qu'à insérer quelques boîtes invisibles:

In [122]:

    %%mocodo
    RHONCUS, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT

    DIGNISSIM: nec sem, nunc, vulputate
    :::
    IMPERDIET: a praesent, nibh, semper

    SODALES, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
    :::
    QUIS ENIM, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT

    TINCIDUNT: faucibus, orci, cursus

NB. Plusieurs paramètres permettent de régler le fonctionnement de l'algorithme génétique :

- `population_size` : nombre d'individus à faire évoluer (défaut: `1000`).
- `crossover_rate` : taux de croisement, entre 0 et 1 (défaut: `0.9`).
- `mutation_rate` : taux de mutation, entre 0 et 1 (défaut: `0.06`).
- `sample_size` : taille de l'échantillon pour les tournois (défaut: `7`).
- `max_generations` : nombre maximal de générations (défaut: `300`).
- `plateau` : nombre maximal de générations consécutives sans amélioration (défaut: `30`).

Réservés aux spécialistes, ils ne sont pas décrits dans cette documentation.

## Amélioration du plongement¶

Une entité liée à de nombreuses associations peut limiter ou même empêcher les possibilités de réarrangement sans croisements.

### Par duplication d'entités réduites à leur identifiant¶

Lorsque cette entité est indépendante et réduite à son identifiant, elle est vouée à disparaître lors du passage au relationnel. Il n'y a donc aucun inconvénient à en créer plusieurs, et cela peut avoir l'avantage de faciliter (ou même de rendre possible) l'obtention d'une bonne mise en page.

Prenons comme exemple un MCD extrait d'une étude de François de Sainte Marie, et présenté comme suit :

Le graphe sous-jacent étant non planaire, des croisements sont inévitables (ici entre certaines pattes des associations SHR, CT et THR). Cependant, cette non-planarité résulte elle-même de la mise en jeu d'une même entité Période dans quatre associations triples. La monnayer en quatre entités Période numérotées augmente l'ordre du graphe, mais le rend planaire, le tout sans impact sur le schéma relationnel :

In [123]:

    %%mocodo -t
    Étudiant: id. étudiant, nom étudiant
    :
    :
    SHR, 0N Période3, 0N Salle, 0N Étudiant
    Période3: heure

    :
    CSG, 0N Niveau, 1N Cours, 1N Étudiant
    Niveau: niveau
    :

    CHS, 0N Période2, 0N Cours, 0N Étudiant
    Cours: id. cours, nom cours
    CHR, 0N Période4, 0N Salle, 0N Cours
    Salle: id. salle, nom salle

    Période2: heure
    CT, 11 Cours, 1N Professeur
    Période4: heure
    :
    :

    :
    Professeur: id. professeur, nom professeur
    :
    THR, 0N Période1, 0N Salle, 0N Professeur
    Période1: heure

- CHR (heure, #id. salle, #id. cours)
- CHS (heure, #id. cours, #id. étudiant)
- Cours (id. cours, nom cours, #id. professeur)
- CSG (niveau, #id. cours, #id. étudiant)
- Étudiant (id. étudiant, nom étudiant)
- Professeur (id. professeur, nom professeur)
- Salle (id. salle, nom salle)
- SHR (heure, #id. salle, #id. étudiant)
- THR (heure, #id. salle, #id. professeur)

Ce genre de problème (et sa solution) se présente typiquement lorsqu'une entité DATE réduite à un identifiant date est associée à un grand nombre d'entités n'ayant rien à voir entre elles.

### Par suppression de ces mêmes entités¶

Inversement, toujours étant donné que ce type d'entité est destiné à disparaître lors du passage au relationnel, on peut décider de les supprimer par anticipation. Pour cela, il faut accepter que les associations puissent être porteuses d'identifiants (ce qui n'est pas prévu par Merise). Cela permet d'obtenir un schéma conceptuel beaucoup plus lisible, toujours sans impact sur le schéma relationnel :

In [124]:

    %%mocodo -t
    CSG, 1N Cours, 1N Étudiant: _niveau
    :
    Cours: id. cours, nom cours
    CT, 11 Cours, 1N Professeur

    :
    CHS, 0N Cours, 0N Étudiant: _heure
    CHR, 0N Salle, 0N Cours: _heure
    Professeur: id. professeur, nom professeur

    Étudiant: id. étudiant, nom étudiant
    SHR, 0N Salle, 0N Étudiant: _heure
    Salle: id. salle, nom salle
    THR, 0N Salle, 0N Professeur: _heure

- CHR (#id. salle, #id. cours, heure)
- CHS (#id. cours, #id. étudiant, heure)
- Cours (id. cours, nom cours, #id. professeur)
- CSG (#id. cours, #id. étudiant, niveau)
- Étudiant (id. étudiant, nom étudiant)
- Professeur (id. professeur, nom professeur)
- Salle (id. salle, nom salle)
- SHR (#id. salle, #id. étudiant, heure)
- THR (#id. salle, #id. professeur, heure)

Notez qu'avec cette technique, les cardinalités minimales des pattes distinguées par les entités supprimées sont perdues dès le niveau conceptuel (sachant qu'elles l'auraient été de toute façon lors du passage au relationnel).

Comme la notion d'identifiant explicite d'association enfreint le standard Merise, et risque de semer la discorde entre professeurs et étudiants, elle est par défaut désactivée sous Mocodo online. En ligne de commande, elle est interdite à la demande :

In [125]:

    %mocodo -i sandbox --no_assoc_ids

    Mocodo Err.52 - L'association « CSG » ne peut pas avoir d'identifiant.

## Ajustement de l'aspect de certains éléments¶

### Format des cardinalités¶

Par défaut, les cardinalités sont séparées par une virgule, et celles des entités faibles soulignées, mais cela peut être changé :

In [126]:

    %%mocodo  --card_format=({min_card}/{max_card}) --strengthen_card=(1/1)(R)
    ŒUVRE: Cote œuvre, Titre, Date parution
    DF, 1N ŒUVRE, _11 EXEMPLAIRE
    EXEMPLAIRE: Num. exemplaire, État du livre, Date d'achat

### Format des clés étrangères¶

La mise en forme des clés étrangères affichées dans le diagramme relationnel peut être paramétrée, par exemple pour enlever le préfixe par défaut (`#`) :

In [127]:

    %mocodo -i ccp -t diagram --fk_format={label}

`ccp_mld.svg`

### Symbole de dépendance fonctionnelle¶

Il est possible d'activer l'encerclement d'un autre sigle que DF. C'est ce sigle qui devra alors apparaître en entrée, par exemple:

In [128]:

    %%mocodo --df CIF
    CLIENT: Réf. client, Nom, Prénom, Adresse
    CIF, 0N CLIENT, 11 COMMANDE
    COMMANDE: Num. commande, Date, Montant
    INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité
    PRODUIT: Réf. produit, Libellé, Prix unitaire

Comme le cercle est alors un peu plus grand, on peut vouloir régler (a priori une fois pour toutes) le ratio défini dans l'objet `shapes` du fichier appelé par défaut `sandbox_geo.json`):

    "df_text_height_ratio" : 1.00,

### Basculement des cardinalités et inflexion des pattes rectilignes¶

Mocodo est capable de détecter certaines configurations de pattes dont les cardinalités présentent un risque élevé de collision. Il procède alors à deux types d'ajustements:

1. Issue 25. Les cardinalités d'une patte verticale ou horizontale sont envoyées de l'autre côté de la patte. Par exemple, dans le plongement du MCD précédent, la présence de la patte oblique BLANDIT-VIVAMUS envoie les cardinalités de VELIT-BLANDIT à l'opposé de leur position par défaut (à droite d'une patte verticale ou en bas d'une patte horizontale).
2. Issue 27. Les pattes obliques sont infléchies de façon à ménager plus d'espace pour afficher deux couples de cardinalités. Ici, l'inflexion de la patte DF-CONGUE permet à ses cardinalités de coexister sans problème avec celles de l'association réflexive.

Ces ajustements automatiques résolvent les problèmes les plus courants. Toutefois, étant antérieurs au tracé proprement dit, ils peuvent seulement réduire les risques de collision, et non les prévenir totalement. Ils peuvent même en produire d'autres. Ainsi, autour des entités monstrueusement pattues, des collisions qui ne se seraient pas produites par défaut seront parfois observées. L'utilisateur a alors deux possibilités:

- diminuer la valeur du paramètre `--flex` (par défaut, `0.75`) pour réduire la courbure de l'inflexion automatique, en allant jusqu'à `0` pour la désactiver totalement ;
- modifier à la main les positions des cardinalités en conflit, comme expliqué dans la section suivante.

### Positionnement des contraintes¶

#### En ajoutant des liens invisibles¶

La possibilité de rendre un trait invisible peut être exploitée pour « attirer » une contrainte vers telle ou telle boîte existante, soit en la répétant dans la définition de la contrainte, soit en l'y intégrant (fictivement) si elle n'en fait pas partie.

Par exemple, ci-dessous, répéter l'association Stocker et intégrer l'entité Commande permet de réduire la largeur du MCD sans compromettre sa lisibilité :

In [129]:

    %%mocodo
    :::
    Dépôt: num dépôt, surface

    :
    Louer, 11 Commande, 0N Dépôt
    :
    Stocker, 1N Dépôt, 1N Article: quantité

    Commande: num. commande, date
    Composer, 1N Commande, 0N Article
    :
    Article: réf. article, prix

    (I) ->Stocker, ..Dépôt, ..Article, --Composer, --Louer, Commande, Stocker

#### En ajoutant une boîte invisible¶

Ces réglages restent relativement fragiles. Une façon d'assurer qu'ils survivront à un réarrangement est de faire coïncider le centre d'une contrainte avec celui d'une boîte supplémentaire, que nous appelons ici « Z » :

In [130]:

    %%mocodo
    :::
    Dépôt: num dépôt, surface

    :
    Louer, 11 Commande, 0N Dépôt
    Z, XX Commande, XX Article, XX Dépôt
    Stocker, 1N Dépôt, 1N Article: quantité

    Commande: num. commande, date
    Composer, 1N Commande, 0N Article
    :
    Article: réf. article, prix

    (I) ->Stocker, ..Dépôt, ..Article, --Composer, --Louer: Z, Z

Il ne reste plus qu'à rendre invisibles l'association Z et ses pattes en préfixant Z d'un signe moins `-` :

In [131]:

    %%mocodo
    :::
    Dépôt: num dépôt, surface

    :
    Louer, 11 Commande, 0N Dépôt
    -Z, XX Commande, XX Article, XX Dépôt
    Stocker, 1N Dépôt, 1N Article: quantité

    Commande: num. commande, date
    Composer, 1N Commande, 0N Article
    :
    Article: réf. article, prix

    (I) ->Stocker, ..Dépôt, ..Article, --Composer, --Louer: Z, Z

Cette technique résiste très bien aux réarrangements automatiques.

### Gouttière d'identifiants¶

Elle apparaît automatiquement (`visibility=auto`) dès qu'il y a au moins un identifiant alternatif. Il est possible de l'en empêcher :

In [132]:

    %%mocodo --gutters ids:visibility=off
    CLIENT: Réf. client, 1_Nom, 1_Prénom, Adresse, 2_Mail

... ou au contraire de la forcer quand elle est superfétatoire :

In [133]:

    %%mocodo --gutters ids:visibility=on
    CLIENT: Réf. client, Nom, Prénom, Adresse, Mail

Vous pouvez aussi préciser quelles chaînes dénoteront un identifiant fort (par défaut, `strong=ID`), un identifiant faible (par défaut, `weak=id`) ainsi que les numéros des groupes d'identifiants alternatifs (par défaut, `alts=123456789`, mais vous pouvez lister moins de 9 symboles) :

In [134]:

    %%mocodo --gutters ids:strong=➤,alts=❶❷❸❹
    CLIENT: Réf. client, 1_Nom, 1_Prénom, Adresse, 2_Mail

### Style et direction des pattes de l'héritage¶

Le type de flèche spécifiant le mécanisme de passage au modèle relationnel (`<=`, `<-`, `->` ou `=>`) fait par défaut l'objet d'une visualisation dès le modèle conceptuel : la ou les pattes vers les entités de destination des attributs migrants sont orientées vers celles-ci ; et la ou les autres pattes sont doublées (pour `<=` et `=>`) ou non (pour `<-` et `->`).

In [135]:

    %%mocodo -t
    Personne: num SS, nom, prénom

    /XT\ Personne => Homme, Femme: sexe

    Homme:
    :
    Femme: nom de jeune fille

- Femme (num SS, nom, prénom, nom de jeune fille)
- Homme (num SS, nom, prénom)

Cette visualisation n'est pas conventionnelle : on se borne normalement à ajouter une flèche dirigée vers l'entité-mère.

Pour désactiver l'embellissement opéré par Mocodo, sans pour autant changer le mécanisme de passage au relationnel, prolongez simplement d'un caractère la flèche : `<==`, `<--`, `-->` ou `==>` :

In [136]:

    %%mocodo -t
    Personne: num SS, nom, prénom

    /XT\ Personne ==> Homme, Femme: sexe

    Homme:
    :
    Femme: nom de jeune fille

- Femme (num SS, nom, prénom, nom de jeune fille)
- Homme (num SS, nom, prénom)

Changement de la version 4.0. Précédemment, `-->` et `==>` s'écrivaient respectivement `->>` et `=>>`.

## Retouches fines¶

Lors du plongement, Mocodo génère systématiquement un fichier (intitulé par défaut `sandbox_geo.json`) répertoriant les positions les plus importantes du dessin. Les autres coordonnées sont calculées relativement à celles-ci.

In [137]:

    %%mocodo --colors brewer+1
    VELIT, 1N> BLANDIT, 11 NONUMMY: sollicitudin

    BLANDIT: consequat, ligula, nibh, consequat
    :::
    NONUMMY: consequat, ligula

    VIVAMUS, 0N NONUMMY, 0N BLANDIT: eleifend, iaculis

Ouvrons le fichier de géométrie généré :

In [138]:

    display.Code("sandbox_geo.json")

Out[138]:

    {
      "width": 444,
      "height": 242,
      "cx": [
        [ "VELIT", 214 ],
        [ "BLANDIT", 58 ],
        [ "NONUMMY", 378 ],
        [ "VIVAMUS", 214 ]
      ],
      "cy": [
        [ "VELIT", 38 ],
        [ "BLANDIT", 117 ],
        [ "NONUMMY", 117 ],
        [ "VIVAMUS", 196 ]
      ],
      "shift": [
        [ "VELIT,BLANDIT,0", 0 ],
        [ "VELIT,NONUMMY,0", 0 ],
        [ "VIVAMUS,NONUMMY,0", 0 ],
        [ "VIVAMUS,BLANDIT,0", 0 ]
      ],
      "ratio": [
        [ "VELIT,BLANDIT,0", 1.0 ]
      ]
    }

On y trouve :

- un couple de dimensions `width` et `height` définit la taille du MCD ;
- deux listes de couples `cx` et `cy`, les abscisses et ordonnées des centres des boîtes ;
- un dictionnaire `shift`, les positions relatives des cardinalités par rapport à leur position par défaut ;
- une liste `ratio`, les positions des flèches éventuelles : leur valeur peuvent varier de `0.0` (flèche cachée sous la boîte d'origine) à `1.0` (par défaut, pointe de la flèche au contact du bord de la boîte de destination, compte non tenu de l'arrondi s'il s'agit d'une association).

Copions-collons ce texte, apportons-lui quelques modifications et sauvegardons-le :

In [139]:

    %%file sandbox_geo.json
    {
      "width": 444,
      "height": 182,
      "cx": [
        [ "VELIT", 214 ],
        [ "BLANDIT", 58 ],
        [ "NONUMMY", 378 ],
        [ "VIVAMUS", 214 ]
      ],
      "cy": [
        [ "VELIT", 38 ],
        [ "BLANDIT", 87 ],
        [ "NONUMMY", 87 ],
        [ "VIVAMUS", 136 ]
      ],
      "shift": [
        [ "VELIT,BLANDIT,0", -30 ],
        [ "VELIT,NONUMMY,0", -30 ],
        [ "VIVAMUS,NONUMMY,0", 0 ],
        [ "VIVAMUS,BLANDIT,0", 0 ]
      ],
      "ratio": [
        [ "VELIT,BLANDIT,0", 0.5 ]
      ]
    }

    Overwriting sandbox_geo.json

Il suffit maintenant d'ajouter l'option `--reuse_geo` pour appliquer ces modifications :

In [140]:

    %mocodo -i sandbox --colors brewer+1 --reuse_geo

Bien entendu, ce genre de manipulations doit rester exceptionnel. Il est en tout cas à réserver à la toute dernière étape de production d'un MCD, puisque la plupart des évolutions subséquentes de son texte-source frapperaient d'obsolescence votre fichier de géométrie.

NB. Étant donné que Mocodo produit des SVG, rien ne vous empêche de retoucher ceux-ci avec un logiciel de dessin vectoriel dédié, comme Inkscape (libre) ou Adobe Illustrator, Freehand, CorelDRAW, etc. Attention, le SVG généré n'est pas spécialement pensé pour cet usage. Certains éléments sont groupés pour permettre leur déplacement en bloc, mais les liens ne suivent pas ces déplacements, ce qui peut vite devenir fastidieux.

## Conversion dans d'autres formats graphiques¶

Avec l'option `--svg_to` suivie de `pdf` et/ou `png`, Mocodo convertit en PDF et/ou PNG le SVG généré pour le MCD.

In [141]:

    %mocodo -i ccp --svg_to png pdf --select

    Mocodo Err.13 - Générer un PNG ou un PDF requiert une installation fonctionnelle de
    CairoSVG.

Le premier format est prévu pour inclusion dans des documents qui ne gèrent pas les SVG :

In [142]:

    display.IFrame("mocodo_notebook/ccp.pdf", width="100%", height="100%")

Out[142]:

Attention, seules les polices de caractères les plus courantes apparaîtront correctement sur toutes les plateformes.

Le second est un format bitmap, donc avec une certaine perte de qualité :

In [143]:

    display.Image("ccp.png")

Out[143]:

Mentionnons une possibilité amusante, actuellement non intégrée à Mocodo : Svg2Rough.js pourra donner à votre travail une touche finale plus informelle, dans un style « tracé à main levée ».

In [144]:

    display.Image("../examples/svg2roughjs.png")

Out[144]:

# Annexe A : Miscellanées académiques¶

## Décompositions d'un MCD¶

Aussi surprenant que cela puisse paraître, tout MCD peut être transformé en un MCD équivalent dont les seules associations sont des dépendances fonctionnelles binaires non porteuses d'attributs, telles que celle ci-dessous :

In [145]:

    %%mocodo
    ENTITÉ 1_: at 1 1, at 1 2, at 1 3
    DF, ?1 ENTITÉ 1_, XX ENTITÉ 2_
    ENTITÉ 2_: at 2 1, at 2 2, at 2 3

La transformation peut demander jusqu'à trois opérations que Mocodo appelle drain, split et explode, et que nous allons découvrir dans la suite.

### Vider les DF de leurs attributs¶

In [146]:

    %%mocodo -t
    Entreprise: nom entreprise, adresse, téléphone
    Proposer, 0N Entreprise, 11 Stage: date proposition
    Stage: num. stage, sujet
    Attribuer, 11 Étudiant, 01 Stage: date signature
    Étudiant: num étudiant, nom
    Soutenir, 01 Étudiant, 0N Date: note stage
    Date: date

- Entreprise (nom entreprise, adresse, téléphone)
- Étudiant (num étudiant, nom, #num. stage, date signature, date, note stage)
- Stage (num. stage, sujet, #nom entreprise, date proposition)

Le MCD ci-dessus comporte trois associations de dépendance fonctionnelle porteuses d'attributs. Certains auteurs considèrent cela comme une anomalie. En tout état de cause, Mocodo peut les déplacer dans les entités distinguées par les cardinalités 11. Nous appelons cette opération un « drainage des dépendances fonctionnelles » (option `-t drain`). Notez bien que ces deux MCD sont strictement équivalents, et produisent le même MLD.

In [147]:

    %mocodo -i sandbox --mld -t drain

- Entreprise (nom entreprise, adresse, téléphone)
- Étudiant (num étudiant, nom, date signature, #num. stage, date, note stage)
- Stage (num. stage, sujet, date proposition, #nom entreprise)

La première version peut être préférée pour des raisons de localité sémantique (date proposition dans PROPOSER), ou honnie parce qu'elle complique la définition d'identifiant d'association. Mocodo n'a pas d'opinion sur la question. Par contre, il se refuse à procéder au drainage via les cardinalités 01. Dans le MCD ci-dessus, le placement de note stage dans SOUTENIR indique qu'un étudiant peut ne pas se voir attribuer de note de stage ; si elle était mise dans ÉTUDIANT, la connaissance du fait que ce champ autorise la valeur `NULL` serait perdue.

### Décomposer les DF n-aires¶

De même, d'aucuns regardent de travers les dépendances fonctionnelles d'arité $n$ supérieure à 2 :

In [148]:

    %%mocodo -t
    Bataille: nom bataille, lieu, date
    Récolter, 0N Villageois, 0N Bataille, 11 Trophée
    Villageois: nom villageois, adresse, fonction

    Trophée: numéro, type, état

- Bataille (nom bataille, lieu, date)
- Trophée (numéro, type, état, #nom villageois, #nom bataille)
- Villageois (nom villageois, adresse, fonction)

Toute DF de ce type peut en effet être « fendue » en $n-1$ DF. L'option `-t split` génère le MCD équivalent :

In [149]:

    %mocodo -i sandbox --seed=3 --mld -t split arrange:wide

- Bataille (nom bataille, lieu, date)
- Trophée (numéro, type, état, #nom bataille, #nom villageois)
- Villageois (nom villageois, adresse, fonction)

### Décomposer les associations n-aires non DF¶

Toute association non DF d'arité $n$ peut être décomposée en un ensemble de $n$ associations DF : elle-même se voit alors remplacée par une entité liée aux $n$ entités originales. Cette nouvelle entité est appelée « entité-intersection », « entité-associative » ou « Gerund », cf. Song, Il-Yeol & Evans, Mary & Park, Eui Kyun. A Comparative Analysis of Entity-Relationship Diagrams. Journal of Computer and Software Engineering. 3 (1995). Dans les cours de Laurent Audibert ou de Patrick Bergougnoux, l'opération est illustrée à l'aide du MCD suivant :

In [150]:

    %%mocodo -t
    Film: id. film, titre, durée
    Projeter, 1N Salle, 1N Créneau, 1N Film: tarif
    Salle: num. salle, capacité

    Créneau: num. créneau, date, heure début

- Créneau (num. créneau, date, heure début)
- Film (id. film, titre, durée)
- Projeter (#num. salle, #num. créneau, #id. film, tarif)
- Salle (num. salle, capacité)

La décomposition est invoquée par l'option `-t explode` :

In [151]:

    %mocodo -i sandbox --seed=8 --mld -t explode arrange:balanced

- Créneau (num. créneau, date, heure début)
- Film (id. film, titre, durée)
- Projeter (id. projeter, tarif, #id. film, #num. salle, #num. créneau)
- Salle (num. salle, capacité)

Le nouveau MCD a vocation à être retouché pour :

- se rapprocher du plongement initial ;
- nommer judicieusement les nouveaux identifiant, entité et associations créés.

In [152]:

    %%mocodo -t
    Film: id. film, titre, durée
    Concerner, 11 Projection, 1N Film
    Projection: id. projection, tarif
    Avoir lieu dans, 11 Projection, 1N Salle
    Salle: num. salle, capacité

    Avoir lieu pendant, 11 Projection, 1N Créneau

    Créneau: num. créneau, date, heure début

- Créneau (num. créneau, date, heure début)
- Film (id. film, titre, durée)
- Projection (id. projection, tarif, #id. film, #num. salle, #num. créneau)
- Salle (num. salle, capacité)

### Décomposer les associations binaires non DF¶

Considérons le MCD suivant, qui comporte deux associations binaires non DF, l'une porteuse d'attribut, l'autre non :

In [153]:

    %%mocodo -t
    COMMANDE: num. commande, date, montant
    LIGNE COM., 1N COMMANDE, 0N PRODUIT: quantité
    PRODUIT: réf. produit, libellé, prix unitaire
    DISPONIBILITÉ, 1N PRODUIT, 0N PAYS
    PAYS: code pays, nom pays

- COMMANDE (num. commande, date, montant)
- DISPONIBILITÉ (#réf. produit, #code pays)
- LIGNE COM. (#num. commande, #réf. produit, quantité)
- PAYS (code pays, nom pays)
- PRODUIT (réf. produit, libellé, prix unitaire)

Par souci de concision, quand on parle d'associations $n$-aires dans ce document, c'est par opposition aux associations binaires ; mais bien sûr, la règle de décomposition énoncée à la section précédente est également valable pour $n=2$, même si par défaut elle ne s'applique qu'aux associations d'arité minimale 3. En réduisant la valeur de `arity` à 2, toutes les associations binaires non DF seront également décomposées :

In [154]:

    %mocodo -i=sandbox --seed=1 --scale=0.9 --mld -t explode:arity=2 arrange:wide=9

- COMMANDE (num. commande, date, montant)
- DISPONIBILITÉ (id. disponibilité, #réf. produit, #code pays)
- LIGNE COM. (id. ligne com., quantité, #num. commande, #réf. produit)
- PAYS (code pays, nom pays)
- PRODUIT (réf. produit, libellé, prix unitaire)

Cette décomposition devient un peu extrême ! Vous pouvez conserver certaines associations binaires non DF, à savoir celles qui ne portent aucun attribut, en mettant `arity` à `2.5` (à lire comme « intermédiaire entre `2` et `3` ») :

In [155]:

    %mocodo -i=sandbox --mld -t explode:arity=2.5 arrange:wide --seed=1

- COMMANDE (num. commande, date, montant)
- DISPONIBILITÉ (#réf. produit, #code pays)
- LIGNE COM. (id. ligne com., quantité, #réf. produit, #num. commande)
- PAYS (code pays, nom pays)
- PRODUIT (réf. produit, libellé, prix unitaire)

### Décomposer en créant des entités faibles¶

Ci-dessus, le processus de modification a créé un identifiant id. ligne com. qui peut sembler superfétatoire. Si l'on a introduit la notion d'entité faible, on aura ici avantage à utiliser l'option `weak` :

In [156]:

    %mocodo -i=sandbox --mld -t explode:arity=2.5,weak arrange:wide --seed=1

- COMMANDE (num. commande, date, montant)
- DISPONIBILITÉ (#réf. produit, #code pays)
- LIGNE COM. (#num. commande, #réf. produit, quantité)
- PAYS (code pays, nom pays)
- PRODUIT (réf. produit, libellé, prix unitaire)

Cas des agrégats. Comme on sait, la notion d'entité faible peut souvent permettre de se passer de celle d'agrégat. Ainsi, le MCD ci-dessous :

In [157]:

    %%mocodo -t --colors ocean
    Chambre: num. chambre, tarif
    Réservation, /1N Client, 1N Chambre, 0N Date: durée
    Client: réf. client, nom client

    Date: date

- Chambre (num. chambre, tarif)
- Client (réf. client, nom client)
- Réservation (#num. chambre, date, #réf. client, durée)

... se verra décomposé de la même façon que sans agrégat, à ceci près que la patte distinguée par le `"/"` produira une cardinalité `11` au lieu d'une cardinalité `_11` :

In [158]:

    %mocodo -i sandbox --mld -t explode:weak arrange:wide=5 --seed 21

- Chambre (num. chambre, tarif)
- Client (réf. client, nom client)
- Réservation (date, #num. chambre, durée, #réf. client)

Cette décomposition peut quelquefois se simplifier. Ici, on remarque que l'entité DATE est indépendante et réduite à son identifiant. Si l'on anticipe sur le passage au relationnel, on peut donc la supprimer, après avoir pris soin, bien sûr, de déplacer dans RÉSERVATION son unique attribut. Celui-ci renforçant une entité faible, il doit garder son caractère identifiant.

In [159]:

    %%mocodo -t
    Chambre: num. chambre, tarif
    DF, _11 Réservation, 1N Chambre
    Réservation: date, durée
    DF, 11 Réservation, 1N Client
    Client: réf. client, nom client

- Chambre (num. chambre, tarif)
- Client (réf. client, nom client)
- Réservation (#num. chambre, date, durée, #réf. client)

### Conclusion sur ces décompositions¶

Comme l'indique le nom que nous leur avons malicieusement attribué, certaines de ces décompositions peuvent littéralement faire exploser la taille du MCD. Cependant :

- elles sont intéressantes d'un point de vue terroriste théorique ;
- elles peuvent permettre la détection d'erreurs de conception ;
- elles peuvent conduire à des améliorations fines du MCD (c'est ce qu'on a fait sur celui des réservations de chambre) ;
- elles décrivent le MCD dans un langage volontairement appauvri, ce qui le rendra plus aisément portable dans une autre notation, comme UML ou crow's foot.

## Équivalences avec la convention Look Across¶

La convention Look Across s'oppose à la convention Look Here de Merise. Elle est plus répandue internationalement. Nous allons l'étudier par le biais du formalisme graphique de Chen, auquel cette section pourra du même coup servir d'introduction pour les personnes familières avec Merise.

### Associations binaires en Look Across¶

#### Cardinalités minimale et maximale¶

Considérons un MCD Merise avec une association de dépendance fonctionnelle :

In [160]:

    %%mocodo
    Employé: employé
    Travailler, 11 Département, 1N Employé
    Département: département

Dans le formalisme graphique de Chen, cela donnera :

In [161]:

    %mocodo -i sandbox -t chen:layout=circo --defer

`sandbox_erd_chen.svg`

Le 1 et le N correspondent aux cardinalités maximales du MCD Merise. Comme on voit, elles sont permutées. Merise suit la convention Look Here (LH) ; la notation de Chen, Look Across (LA). Comme cette dernière est la plus répandue dans le monde anglo-saxon, nous parlerons par commodité d'« ERD » (Entity-relationship diagram) pour les modèles conceptuels selon Chen, et toujours de « MCD » pour ceux de Merise.

Considérons maintenant les deux versions d'une association avec des cardinalités minimales distinctes :

In [162]:

    %%mocodo
    Mer: mer
    Recevoir, 01 Rivière, 1N Mer
    Rivière: rivière

In [163]:

    %mocodo -i sandbox -t chen:layout=circo --defer

`sandbox_erd_chen.svg`

Les cardinalités maximales sont toujours permutées ; par contre, les cardinalités minimales ne le sont pas. Dans l'ERD, elles sont figurées par un trait simple (0) ou double (1). On les appelle aussi des « participations » : une rivière peut ne participer (directement) à l'alimentation d'aucune mer (ce n'est pas un fleuve) ; toute mer participe à la réception d'une rivière (un fleuve) minimum. Les conventions sont donc les suivantes :

Cardinalités | MCD Merise | ERD Chen
--- | --- | ---
minimale | LH | LH
maximale | LH | LA

La notation Merise a l'avantage de la cohérence ; celle de Chen en a d'autres, que nous verrons un peu plus loin.

Avant cela, voyons un dernier point de détail : lorsque deux cardinalités N se trouvent de part et d'autre d'une association binaire, l'une est notée M :

In [164]:

    %%mocodo
    PROJET: projet
    REQUÉRIR, 1N PROJET, 0N PIÈCE
    PIÈCE: pièce
    COMPOSER, 0N PIÈCE, 0N PIÈCE

In [165]:

    %mocodo -i sandbox -t chen:layout=circo --defer

`sandbox_erd_chen.svg`

#### Entités faibles et entités associatives¶

Maintenant examinons le cas des entités faibles :

In [166]:

    %%mocodo
    Œuvre: œuvre
    DF, 0N Œuvre, _11 Exemplaire
    Exemplaire: exemplaire

In [167]:

    %mocodo -i sandbox -t chen:layout=circo --defer

`sandbox_erd_chen.svg`

L'entité faible, à l'instar de la DF « renforçante », sont entourées d'un double trait.

Le vocabulaire de Chen comporte encore un élément graphique, que Merise ne distingue pas spécialement. Nous avons vu que toute association non DF pouvait être décomposée de façon équivalente par l'insertion d'entités faibles :

In [168]:

    %%mocodo
    Produit: produit
    DF, _11 Ligne de commande, 0N Produit
    Ligne de commande: _quantité
    DF, _11 Ligne de commande, 1N Commande
    Commande: commande

LIGNE DE COMMANDE est quelquefois qualifiée d'« entité associative », et Chen la figure logiquement par un losange (association) inscrit dans un rectangle (entité). Graphviz ne prend actuellement pas en charge cette représentation. Nous l'approximons donc ainsi :

In [169]:

    %mocodo -i sandbox -t chen:layout=circo,mindist=2,scale=0.6 --defer

`sandbox_erd_chen.svg`

### Associations n-aires en Look Across¶

#### Triplet NNN¶

Passons maintenant aux choses sérieuses. Jusqu'ici, la différence entre les deux notations était purement cosmétique. Qu'en est-il des associations n-aires, et que signifie Look Across quand across peut désigner plusieurs endroits ?

In [170]:

    %%mocodo -t
    Employé: employé
    Appliquer, 0N Employé, 1N Projet, 1N Compétence
    Projet: projet

    Compétence: compétence

- Appliquer (employé, projet, compétence)

Dans ce cas (le plus usuel), la question ne se pose pas vraiment, ou du moins n'est pas tranchée de façon évidente :

In [171]:

    %mocodo -i sandbox -t chen:layout=circo,mindist=1,scale=0.4 --defer

`sandbox_erd_chen.svg`

Quels sont les autres cas ? Il ne s'agit pas de ceux où l'association n-aire est entourée d'une ou plusieurs cardinalités maximale 1, puisqu'on pourrait alors la décomposer en DF binaires (cf. argument `split`). En réalité, on touche ici aux limites de la notation Look Here, plus intuitive, mais moins puissante que Look Across, et que Merise n'a pu rattraper que dans sa version 2.

Pour répondre progressivement à la question, procédons désormais dans l'ordre inverse, en présentant d'abord l'ERD, et ensuite seulement le MCD équivalent.

Les exemples qui suivent (ainsi d'ailleurs que le précédent), sont adaptés des pages 28 sqq. et 96 sqq. de l'ouvrage de Toby J. Teorey, Sam S. Lightstone, Tom Nadeau, H.V. Jagadish, Database Modeling and Design - Logical Design, 5th Edition - February 10, 2011 (Elsevier).

#### Triplet 1NN¶

Le premier ERD apportant véritablement quelque chose de nouveau a cette structure :

In [172]:

    %%mocodo -t chen:layout=circo,mindist=1,scale=0.45 --defer
    Ingénieur: ingénieur
    Gérer, /1N Responsable, 1N Ingénieur, 1N Projet
    Projet: projet

    Responsable: responsable

`sandbox_erd_chen.svg`

Les auteurs explicitent ainsi ses règles de gestion :

> Chaque ingénieur travaillant sur un projet particulier a exactement un responsable, mais chaque responsable d'un projet peut gérer plusieurs ingénieurs, et chaque responsable d'un ingénieur peut gérer cet ingénieur sur plusieurs projets.

Reprenons ces trois assertions, et faisons-les correspondre au trois cardinalités dans le sens anti-horaire à partir du 1 :

- 1 : pour un couple (ingénieur, projet) donné, un seul responsable possible ;
- N : pour un couple (responsable, projet) donné, plusieurs ingénieurs possibles ;
- N : pour un couple (responsable, ingénieur) donné, plusieurs projets possibles.

Avec Merise, les assertions seraient plutôt du type : « pour un x donné, tant de couples (y, z) possibles ». Il y a donc bien permutation, mais permutation des références au singleton et au $n-1$-uplet.

C'est la réponse à notre question initiale, et nous verrons avec plaisir qu'elle reste valable quel que soit le triplet de cardinalités de l'association ternaire.

Pour l'instant, résumons les règles de gestion par cette unique dépendance fonctionnelle :

- (Ingénieur, Projet) $\implies$ Responsable.

Pour exprimer cela en (ou en dépit de) Look Here, on doit recourir à un agrégat :

In [173]:

    %mocodo -i sandbox --mld --colors pond

- Gérer (ingénieur, projet, responsable)

… ou à une CIF à unicité complète (ici en notation allégée) :

In [174]:

    %mocodo -i sandbox --mld -t create:cifs=light arrange:balanced --seed=3

- Gérer (ingénieur, projet, responsable)

... Ou encore à une entité faible :

In [175]:

    %mocodo -i sandbox --mld -t explode:weak,arity=2 arrange:balanced --seed=14

- Gérer (ingénieur, projet, responsable)

Les schémas relationnels produits permettent de se convaincre que ces différentes variantes respectent bien la dépendance fonctionnelle désirée : (Ingénieur, Projet) $\implies$ Responsable.

#### Triplet 11N¶

Passons à la deuxième combinaison intéressante :

In [176]:

    %%mocodo -t chen:layout=circo,mindist=1,scale=0.45 --defer
    Projet: projet
    Affecter, /1N Site, /1N Projet, 0N Employé
    Site: site

    Employé: employé

`sandbox_erd_chen.svg`

Règles de gestion :

> Chaque employé affecté à un projet travaille sur un seul site pour ce projet, mais peut se trouver sur différents sites pour différents projets. Sur un site donné, un salarié ne travaille que sur un seul projet. Sur un site donné, il peut y avoir plusieurs employés affectés à un projet donné.

Autrement dit (en partant du bas et dans le sens anti-horaire) :

1 : pour un couple (projet, employé) donné, un seul site possible ; 1 : pour un couple (employé, site) donné, un seul projet possible ; N : pour un couple (projet, site) donné, plusieurs employés possibles.

En résumé, deux dépendances fonctionnelles :

- (Projet, Employé) $\implies$ Site.
- (Employé, Site) $\implies$ Projet.

Voici le MCD correspondant, successivement avec des agrégats et des CIFS (plus de variante possible avec entité faible) :

In [177]:

    %mocodo -i sandbox --select all -t mld:c --colors pond

`sandbox_mld.md`

- Affecter (projet, employé u1, site! u1)

In [178]:

    %mocodo -i sandbox --select mcd mld -t mld:c create:cifs=light arrange:balanced --seed=3

`sandbox_mld.md`

- Affecter (projet, employé u1, site! u1)

On voit apparaître dans le schéma relationnel un « u1 » en exposant qui signifie : contrainte d'unicité n°1. Il y a en effet deux clés candidates : (projet, employé) et (employé, site). Seule l'une des deux est devenue clé primaire, mais cela ne veut pas dire qu'on a perdu la contrainte de dépendance fonctionnelle induite par l'autre. En SQL :

In [179]:

    %mocodo -i sandbox -t sql

`sandbox_ddl.sql`

    CREATE TABLE Affecter (
      PRIMARY KEY (projet, employe),
      projet  VARCHAR(42) NOT NULL,
      employe VARCHAR(42) NOT NULL,
      site    VARCHAR(42) NOT NULL,
      UNIQUE (employe, site)
    );

#### Triplet 111¶

La dernière combinaison obéit à la même logique :

In [180]:

    %%mocodo -t chen:layout=circo,mindist=1,scale=0.45 --defer
    Technicien: technicien
    Utiliser, /1N Technicien, /1N Carnet, /1N Projet
    Projet: projet

    Carnet: carnet

`sandbox_erd_chen.svg`

Règles de gestion :

> Un technicien utilise exactement un carnet pour chaque projet. Chaque carnet appartient à un technicien pour chaque projet. Notez qu'un technicien peut toujours travailler sur plusieurs projets et gérer différents carnets pour différents projets.

Autrement dit (en partant du haut et dans le sens horaire) :

- 1 : pour un couple (technicien, projet) donné, un seul carnet possible ;
- 1 : pour un couple (carnet, projet) donné, un seul technicien possible ;
- 1 : pour un couple (carnet, technicien) donné, un seul projet possible.

En résumé, trois dépendances fonctionnelles :

- (Technicien, Projet) $\implies$ Carnet.
- (Carnet, Technicien) $\implies$ Projet.
- (Carnet, Projet) $\implies$ Technicien.

In [181]:

    %mocodo -i sandbox --select all -t mld:c --colors pond

`sandbox_mld.md`

- Utiliser (carnet u1, projet u2, technicien! u1 u2)

In [182]:

    %mocodo -i sandbox --select mcd mld -t mld:c create:cifs=light arrange:balanced flip:d,v --seed=12

`sandbox_mld.md`

- Utiliser (carnet u1, projet u2, technicien! u1 u2)

Il y a maintenant trois clés candidates, correspondant à deux contraintes d'unicité. En SQL :

In [183]:

    %mocodo -i sandbox -t sql

`sandbox_ddl.sql`

    CREATE TABLE Utiliser (
      PRIMARY KEY (carnet, projet),
      carnet     VARCHAR(42) NOT NULL,
      projet     VARCHAR(42) NOT NULL,
      technicien VARCHAR(42) NOT NULL,
      UNIQUE (carnet, technicien),
      UNIQUE (projet, technicien)
    );

#### Conclusion sur les agrégats multiples¶

Notre syntaxe `/1N` pour les agrégats permet d'exprimer simplement toutes les combinaisons possibles de cardinalités d'une association n-aire dans la notation de Chen : il suffit de mettre un `/1N` partout où Chen met un `1`. Chaque `/1N` créera une nouvelle dépendance fonctionnelle, autrement dit, une nouvelle clé candidate.

Plus rigoureusement : supposons une association $n$-aire $A$ exclusivement entourée de 1N (ou 0N). Soient $E_1$, $E_2$, ..., $E_n$ les entités mises en jeu, et $k_1, k_2$, ..., $k_n$ leurs identifiants respectifs. Alors, noter `/1N` (ou `/0N`) la cardinalité de la patte de $E_i$ dénote l'existence de la dépendance fonctionnelle suivante : $(k_1, ..., k_{i-1}, k_{i+1}, ..., k_n) \implies k_i$, autrement dit : que $(k_1, ..., k_{i-1}, k_{i+1}, ..., k_n)$ est une clé candidate de la table $A$.

Notez pour finir que Mocodo permet de spécifier à coût zéro quelle clé candidate sera élue clé primaire. Il suffit pour cela de placer en tête de la liste des entités mises en jeu par $A$ celle dont l'identifiant ne doit pas entrer dans la clé primaire. Si c'est $E_1$, la clé primaire sera automatiquement $(k_2, ..., k_n)$.

# Annexe B : La commande `mocodo`¶

## Paramétrage¶

### `mocodo --help`¶

In [8]:

    %mocodo --help

    usage: mocodo [--language CODE] [--params_path PATH] [--input PATH] [--help]
                  [--version] [--restore] [--lib [URL]] [--output_dir PATH]
                  [--encodings [STR ...]] [--svg_to {png,pdf} [{png,pdf} ...]]
                  [--print_params] [--reuse_geo] [--uid_suffix INT]
                  [--select [{all,mcd,rw,source,text,code,mocodo,cv,mld,ddl,sql} ...]]
                  [--defer [STR ...]] [--mld] [--transform [STR ...]]
                  [--seed [FLOAT]] [--title STR] [--df STR] [--card_format [STR]]
                  [--fk_format [STR]] [--strengthen_card [STR]] [--flex FLOAT]
                  [--colors STEM_OR_PATH] [--shapes STEM_OR_PATH] [--scale RATE]
                  [--adjust_width RATE] [--detect_overlaps] [--no_assoc_ids]
                  [--gutters STR [STR ...]]

    NOM :
    Mocodo - Un générateur de diagrammes entité-association.

    DESCRIPTION :
    Mocodo est un outil libre destiné à l'enseignement des bases de données relationnelles.
    Il prend en entrée une description textuelle des entités et associations d'un diagramme
    entité-association (MCD). Il produit en sortie un dessin vectoriel en SVG et un schéma
    relationnel dans divers formats (SQL, LaTeX, Markdown, etc.).

    NOTE :
    Chacune des valeurs suivantes est :
    - spécifiée explicitement par l'utilisateur comme option de ligne de commande ;
    - sinon, récupérée depuis un fichier de chemin --params_path ;
    - sinon, récupérée depuis un fichier nommé « params.json » dans le répertoire d'entrée ;
    - sinon, calculée à partir d'une valeur par défaut, éventuellement dépendante de votre système.

    OPTIONS SUR MOCODO LUI-MÊME :
      --language CODE       force la localisation des messages avec le code de
                            langue donné (par exemple, « fr », « en », ...)
                            (default: fr)
      --help                affiche ce message d'aide, puis termine
      --version             affiche le numéro de version, puis termine
      --restore             recrée une version vierge des fichiers « sandbox.mcd »
                            et « params.json » dans le répertoire d'entrée, puis
                            termine (default: False)

    ENTRÉE/SORTIE :
      --params_path PATH    le chemin du fichier de paramètres. S'il est omis,
                            utilise « params.json » dans le répertoire d'entrée.
                            S'il n'existe pas, utilise les paramètres par défaut.
                            (default: params.json)
      --input PATH, -i PATH
                            le chemin du fichier d'entrée. Par défaut, les
                            fichiers de sortie seront générés dans le même
                            répertoire (default: /Users/aristide/Dropbox/Sites/moc
                            odo/doc/mocodo_notebook/sandbox.mcd)
      --lib [URL]           remote directory to use as fallback when the input
                            file is not found locally (default:
                            https://mocodo.net/web/lib)
      --output_dir PATH     le répertoire des fichiers de sortie (default: .)
      --encodings [STR ...]
                            un ou plusieurs encodages à essayer successivement
                            lors de la lecture du fichier d'entrée (default:
                            ['utf8', 'macroman'])
      --svg_to {png,pdf} [{png,pdf} ...]
                            génère une version PNG ou PDF de la sortie SVG
                            (requiert CairoSVG) (default: [])
      --print_params        affiche le contenu du fichier de paramètres, puis
                            termine (default: False)
      --reuse_geo           réutilise le fichier de géométrie de l'exécution
                            précédente (default: False)
      --uid_suffix INT      ajoute un discriminateur à un SVG interactif (default:
                            0)
      --select [{all,mcd,rw,source,text,code,mocodo,cv,mld,ddl,sql} ...]
                            sous Jupyter Notebook, spécifie explicitement les
                            catégories de résultats à afficher
      --defer [STR ...]     utilise un service web externe pour convertir les
                            résultats de la conversion dans les formats graphiques
                            donnés
      --mld                 alias de compatibilité ascendante pour « -t » (sans
                            arguments). Équivalent à « -t markdown » mais, sous
                            Jupyter Notebook, n'empêche pas le rendu du diagramme
                            conceptuel dans la sortie de la cellule (default:
                            False)
      --transform [STR ...], -t [STR ...]
                            crée une nouvelle version du MCD en appliquant
                            séquentiellement les opérations de réécriture données,
                            et/ou le convertit dans les formats ou langages
                            donnés. Sous Jupyter Notebook, « -T » remplace
                            respectivement la cellule courante par le résultat
                            textuel, ou le copie dans le presse-papier (pip3
                            install pyperclip)
      --seed [FLOAT]        valeur initiale pour le générateur de nombres
                            aléatoires (default: None)
      --title STR           nom du modèle, utilisé à divers endroits (système de
                            fichiers, base de données, etc.) (default: MCD)

    ASPECT DE LA SORTIE GRAPHIQUE :
      --df STR              l'acronyme à entourer dans une dépendance
                            fonctionnelle (default: DF)
      --card_format [STR]   chaîne de formatage pour les cardinalités minimales et
                            maximales (default: {min_card},{max_card})
      --fk_format [STR]     chaîne de formatage pour les clés étrangères dans le
                            diagramme relationnel (default: #{label})
      --strengthen_card [STR]
                            chaîne pour les cardinalités relatives (default:
                            _1,1_)
      --flex FLOAT          incurve les pattes rectilignes dont les cardinalités
                            peuvent se chevaucher (default: 0.75)
      --colors STEM_OR_PATH
                            la palette de couleurs à utiliser lors de la
                            génération du dessin. Nom (sans extension) d'un
                            fichier situé dans le répertoire « colors », ou chemin
                            vers un fichier personnel (default: bw)
      --shapes STEM_OR_PATH
                            spécification des polices, dimensions, etc. Nom (sans
                            extension) d'un fichier situé dans le répertoire
                            « shapes », ou chemin vers un fichier personnel
                            (default: copperplate)
      --scale RATE          applique au diagramme le facteur de mise à l'échelle
                            donné (default: 1)
      --adjust_width RATE   applique à tous les textes calculés le facteur de mise
                            à l'échelle donné (default: 1)
      --detect_overlaps     lève une erreur quand des pattes horizontales ou
                            verticales se chevauchent (default: False)
      --no_assoc_ids        interdit l'utilisation d'identifiants dans les
                            associations (conformément au standard Merise)
                            (default: False)
      --gutters STR [STR ...]
                            définit la visibilité et le contenu des gouttières
                            latérales

    VOIR AUSSI :
      Version en ligne      https://mocodo.net
      Code source           https://github.com/laowantong/mocodo
      Documentation         https://rawgit.com/laowantong/mocodo/master/doc/fr_refman.html
      Aide-mémoire pour -t  https://github.com/laowantong/mocodo/blob/master/doc/fr_cheat_sheet.md

    LICENCE :               MIT

    CONTACT :
      Auteur                Aristide Grange
      Adresse               Université de Lorraine
                            Laboratoire LCOMS - UFR MIM
                            3 rue Augustin Fresnel
                            57070 METZ Technopôle
                            France
      Courriel              <prénom.nom>@univ-lorraine.fr

### Paramétrage à long terme¶

Pour éviter d'avoir à invoquer Mocodo répétitivement avec une longue kyrielle d'options, vous pouvez mettre celles-ci dans un fichier `params.json` situé dans le répertoire de lancement de Mocodo. La commande:

    mocodo --restore

... le fait pour vous avec un fichier de paramètres vide, i.e., un fichier-texte réduit aux deux caractères `{}` (attention, elle rétablit aussi le fichier `sandbox.mcd` à son contenu par défaut).

Pour que le style de vos MCD soit maintenu à moindre frais à travers tous vos documents, vous êtes encouragés à modifier ce fichier de paramètres selon vos goûts et vos besoins. Mocodo peut même vous aider à le faire en exécutant la cellule suivante:

    %mocodo --print_params

Son évaluation remplace son propre contenu par des lignes de code similaires à :

In [185]:

    # You may edit and run the following lines
    import json, pathlib
    params = """\
    {
      "adjust_width": 1,
      "card_format": "{min_card},{max_card}",
      "colors": "bw",
      "detect_overlaps": false,
      "df": "DF",
      "encodings": [ "utf8", "macroman" ],
      "fk_format": "#{label}",
      "flex": 0.75,
      "language": "fr",
      "lib": "https://mocodo.net/web/lib",
      "mld": false,
      "no_assoc_ids": false,
      "output_dir": ".",
      "restore": false,
      "scale": 1,
      "seed": null,
      "shapes": "copperplate",
      "strengthen_card": "_1,1_",
      "svg_to": [],
      "title": "MCD",
      "uid_suffix": 0
    }"""
    try:
        json.loads(params)
    except:
        raise RuntimeError("Invalid JSON. Check your syntax on https://jsonlint.com.")
    pathlib.Path("./params.json").write_text(params, encoding="utf8");

Ensuite :

1. Modifiez la variable `params` à votre gré en respectant la syntaxe JSON.
2. Exécutez la cellule pour créer un fichier de nom et emplacement adéquats.

En cas de besoin, vous pourrez toujours ponctuellement passer outre ces réglages en en précisant d'autres en ligne de commande. Plus précisément, chaque paramètre est déterminé:

1. par sa valuation en ligne de commande;
2. à défaut, par sa valuation dans le fichier de paramètres indiqué par `--params_path`;
3. à défaut d'une telle indication, par sa valuation dans le fichier `params.json` du répertoire courant;
4. à défaut, par une valeur défaut éventuellement dépendante de votre système.

### Dissection de la commande¶

L'API de Mocodo a été revue de façon radicale pour la version 4.0. Le nombre d'options de premier niveau a été réduit ; en contrepartie, certaines sont devenues de véritables mini-commandes, avec leur propre liste d'arguments, et une syntaxe et un comportement uniformes. Voici leur définition en ABNF :

Introduisons, sur un exemple fictif, un vocabulaire que nous avons essayé d'employer le plus rigoureusement possible tout au long de cette documentation (et dans le code lui-même) :

    mocodo    --select all    --transform  drain  arrange:wide  explode:weak,arity=2.5

- La commande `mocodo` est invoquée avec les options `--select` et `--transform`.
- On passe à la seconde trois arguments de complexité croissante, `drain`, `arrange:wide` et `explode:weak,arity=2.5`. Notez que le séparateur des arguments est l'espace. Par conséquent, un argument ne peut contenir d'espaces qu'entre guillemets.
- Chacun des arguments consiste en un nom de sous-option (`drain`, `arrange` ou `explode`), suivi éventuellement d'un deux-points (`:`), suivi d'une liste de sous-arguments séparés par des virgules (`,`).
- Chacun des sous-arguments consiste en un nom de sous-sous-option, suivi éventuellement d'un signe égal (`=`), suivi d'un sous-sous-argument (éventuellement entre guillemets).

On n'ira pas plus loin et, heureusement, la plupart des commandes réelles n'atteignent pas ce degré d'imbrication. La décomposition suivante fixera peut-être les idées, ou pourra du moins servir de référence en cas de doute :

$$ \underbrace{\texttt{mocodo}}_{\text{command}} \qquad \texttt{-}\,\texttt{-} \underbrace{\texttt{select}}_{\text{option}} \underbrace{ \texttt{all} }_{\text{argument}} \qquad \texttt{-}\,\texttt{-} \underbrace{\texttt{transform}}_{\text{option}} \qquad \underbrace{ \underbrace{ \texttt{drain} }_{\text{sub-option}} }_{\text{argument}} \qquad \underbrace{ \underbrace{ \texttt{arrange} }_{\text{sub-option}} \texttt{:} \underbrace{ \underbrace{ \texttt{wide} }_{\text{sub-sub-opt}} }_{\text{sub-arg}} }_{\text{argument}} \qquad \underbrace{ \underbrace{ \texttt{explode} }_{\text{sub-option}} \texttt{:} \underbrace{ \underbrace{ \texttt{weak} }_{\text{sub-sub-opt}} }_{\text{sub-arg}} \texttt{,} \underbrace{ \underbrace{ \texttt{arity} }_{\text{sub-sub-opt}} \texttt{=} \underbrace{ \texttt{2.5} }_{\text{sub-sub-arg}} }_{\text{sub-argument}} }_{\text{argument}} $$

L'intérêt de cette structuration en arborescence est double. Elle permet :

- de créer des pipelines d'opérations : le résultat de l'application du premier argument est fourni en entrée au second, etc ;
- de regrouper les opérations interdépendantes. Par exemple, avant la version 4.0, l'argument `explode:weak,arity=2.5` aurait dû être mis à plat : `--explode --weak_explosion --explosion_arity=2.5`. Cela donne le même statut à toutes, masquant le fait que certaines n'ont de sens qu'en présence d'une autre.

## L'option `--transform` et ses arguments¶

### Triage et exécution des transformations¶

L'option à tout faire est `--transform`, que vous pouvez abréger `-t`. Avant de traiter ses arguments, Mocodo commence par les répartir en deux catégories :

- les réécritures, qui transforment le MCD original en un nouveau MCD avec, par exemple, les libellés mis en majuscules, ou les associations n-aires décomposées en DF, ou les boîtes réarrangées ;
- les conversions, qui produisent quelque chose qui n'est pas un MCD : ce peut être un dictionnaire des données, un diagramme de classes UML, un ERD dans la notation crow's foot, etc.

L'exécution se déroule alors en deux étapes :

1. les réécritures sont opérées en pipeline, c'est-à-dire que le MCD produit par la première réécriture est passé en entrée de la seconde, etc. Leur ordre a donc de l'importance ;
2. les conversions sont alors appliquées au résultat de la dernière réécriture. Leur ordre n'a pas d'importance.

### Aide-mémoire des transformations¶

L'option `-t` (ou `--transform`) permet d'accéder à un grand nombre d'opérations de conversion ou de réécriture.

Toutes les opérations de conversion ont déjà été décrites dans ce document :

- produits dérivés : `data_dict`, `share` ;
- schémas relationnels textuels : `html`, `latex`, `markdown`, `text` ;
- DDL : `sql` (et ses dialectes) ;
- autres sorties relationnelles : `diagram`, `dbml`, `d2`, `dependencies` ;
- conversions dans d'autres notations : `uml`, `crow`, `chen`.

Certaines opérations de réécriture ont été présentées, d'autres passées sous silence :

- réorganisation du MCD : `arrange`, `flip` ;
- obfuscation et randomisation d'éléments donnés : `randomize`, `drown` ;
- génération de MCD aléatoires : `grow` ;
- décomposition d'associations : `split`, `drain`, `explode` ;
- inférence d'informations manquantes : `create` ;
- suppression d'éléments donnés : `delete` ;
- traitement de chaînes de caractères : `truncate`, `slice`, `prefix`, `suffix`, `replace` ;
- homogénéisation de la mise en forme : `ascii`, `camel`, `snake`, `pascal`, `lower`, `upper`, etc.

L'aide-mémoire suivant devrait vous permettre de prendre en main les sous-options de `--transform` qui vous intéressent. Survolez une sous-option pour afficher ses alias éventuels.

In [7]:

    display.Markdown("../fr_cheat_sheet.md")

Out[7]:

### Opérations de conversion¶

Sous-option | Description | Exemples | Explications
--- | --- | --- | ---
ast | crée l'arbre de syntaxe abstraite du texte source (pour le débogage) |  |
chen | convertit le modèle conceptuel dans la notation de Chen | `chen` | sans attributs
|  | `chen:attrs` | avec attributs
|  | `chen:attrs --defer` | calcule le rendu graphique via un service web
|  | `chen:layout=circo,mindist=2,scale=0.6` | ajoute des options arbitraires pour Graphviz
crow | convertit le modèle conceptuel dans la notation crow's foot | `crow` | format Graphviz
|  | `crow --defer` | calcule le rendu graphique via un service web
|  | `crow:mmd` | format Mermaid
|  | `crow:mermaid` | idem
d2 | convertit le modèle conceptuel en un schéma relationnel au format D2 |  |
data_dict | extrait tous les attributs du MCD dans une table | `data_dict` | tableau Markdown, trois colonnes
|  | `data_dict:label` | liste Markdown, une colonne
|  | `data_dict:label,type='Description'` | deux colonnes, un libellé personnalisé
|  | `data_dict:label='Attribut',type='Description'` | deux colonnes, deux libellés personnalisés
|  | `data_dict:**box**='Entité ou<br>association',label,`type`=`'Type de données'`` | mise en forme de certains libellés
|  | `data_dict:tsv` | tableau TSV, trois colonnes
|  | `data_dict:tsv,label` | liste des attributs séparés par des retours à la ligne
dbml | convertit le modèle conceptuel en un schéma relationnel au format DBML | `dbml` | version de base
|  | `dbml:b` | avec boilerplate
debug | liste des informations internes relatives à la conversion en schéma relationnel |  |
dependencies | convertit le modèle conceptuel en un graphe de dépendances |  |
diagram | convertit le modèle conceptuel en un diagramme relationnel au format Mocodo | `diagram` | version de base
|  | `diagram:c` | avec contraintes d'unicité et d'optionalité
html | convertit le modèle conceptuel en un schéma relationnel au format HTML | `html` | version de base
|  | `html:b` | avec boilerplate
|  | `html:c` | avec contraintes d'unicité et d'optionalité
|  | `html:e` | avec explications
|  | `html:bce` | avec boilerplate, contraintes et explications
latex | convertit le modèle conceptuel en un schéma relationnel au format LaTeX | `latex` | version de base
|  | `latex:b` | avec boilerplate
|  | `latex:c` | avec contraintes d'unicité et d'optionalité
|  | `latex:e` | avec explications
|  | `latex:bce` | avec boilerplate, contraintes et explications
markdown | convertit le modèle conceptuel en un schéma relationnel au format Markdown | `markdown` | version de base
|  | `markdown:c` | avec contraintes d'unicité et d'optionalité
|  | `markdown:e` | avec explications
|  | `markdown:ce` | avec contraintes et explications
mssql | convertit le modèle conceptuel en un modèle physique pour Microsoft SQL Server | `mssql` | version de base
|  | `mssql:b` | avec boilerplate
mysql | convertit le modèle conceptuel en un modèle physique pour MySQL | `mysql` | version de base
|  | `mysql:b` | avec boilerplate
oracle | convertit le modèle conceptuel en un modèle physique pour Oracle DB | `oracle` | version de base
|  | `oracle:b` | avec boilerplate
postgresql | convertit le modèle conceptuel en un modèle physique pour PostgreSQL | `postgresql` | version de base
|  | `postgresql:b` | avec boilerplate
prompt | génère un prompt pour demander à une IA de compléter le MCD | `prompt:cards` | avec les explications des cardinalités
|  | `prompt:types` | avec les types des attributs
relation | convertit le modèle conceptuel en schéma relationnel avec le gabarit donné | `relation:path/to/my_template.yaml` | chemin relatif, extension obligatoire
share | encode le MCD dans une URL pour Mocodo online | `qr --defer` | génère un QR code via un service web
sql | convertit le modèle conceptuel en un modèle physique pour SQL |  |
sqlite | convertit le modèle conceptuel en un modèle physique pour SQLite | `sqlite` | version de base
|  | `sqlite:b` | avec boilerplate
text | convertit le modèle conceptuel en un schéma relationnel au format texte | `text` | version de base
|  | `text:c` | avec contraintes d'unicité et d'optionalité
|  | `html:e` | avec explications
|  | `html:ce` | avec contraintes et explications
uml | convertit le modèle conceptuel en diagramme de classes UML | `uml` | format PlantUML
|  | `uml:plantuml` | idem
|  | `uml --defer` | calcule le rendu graphique via un service web
|  | `uml:plantuml=-` | supprime les styles par défaut
|  | `uml:plantuml='skinparam backgroundColor yellow\nskinparam classAttributeFontName Arial\n'` | ajoute des styles personnalisés

### Opérations de réécriture¶

Sous-option | Description | Exemples | Explications
--- | --- | --- | ---
arrange | réarrange la disposition, soit par Branch & Bound, soit avec un algorithme génétique | `arrange` | B&B sans contraintes
|  | `arrange:timeout=60` | B&B limité à une minute
|  | `arrange:wide` | B&B privilégiant la largeur
|  | `arrange:current` | B&B sur la grille courante
|  | `arrange:balanced=0` | B&B sur la plus petite grille équilibrée
|  | `arrange:balanced=1` | B&B sur la seconde plus petite grille équilibrée
|  | `arrange:algo=ga` | algorithme génétique
ascii | réécrit les éléments donnés en ASCII | `ascii:roles,labels` | rôles, libellés des boîtes et des attributs en ASCII
camel | réécrit les éléments donnés en camelCase |  |
capitalize | réécrit les éléments donnés en capitalisant la première lettre de chaque mot |  |
casefold | réécrit les éléments donnés en minuscules, mais plus agressivement que « lower » |  |
create | essaie d'inférer les types, entités, CIFs ou flèches de DF à partir des éléments existants | `guess:types` | deviner les types manquants
|  | `create:types=` | remplacer les types manquants par `[]`
|  | `create:types=TODO` | remplacer les types manquants par `[TODO]`
|  | `make:entities` | réparer l'oubli d'entités référencées dans des associations
|  | `create:dfs` | mettre des DF partout où c'est possible
|  | `add:df_arrows` | ajouter des flèches aux DF 11
|  | `add:cifs` | ajouter les CIF correspondant aux agrégats
|  | `add:cifs=light` | même chose en visualisation allégée
|  | `add:roles` | mettre comme rôles le nom des associations partout où c'est utile
delete | supprime les éléments donnés quand c'est possible | `empty` | ne garde que la structure et le nom des boîtes
|  | `delete:types,notes,attrs,cards` | idem
|  | `delete:cards` | remplace les cardinalités par `XX`
|  | `delete:card_prefixes` | supprime les marqueurs d'entités faibles et d'agrégats
|  | `delete:dfs` | supprime les entités indépendantes dont tous les attributs sont identifiants (et les DF qui les relient)
drain | déplace tout attribut d'association (1,1) vers l'entité appropriée |  |
drown | remplace tous les noms d'éléments par un libellé générique numéroté |  |
echo | réécrit le texte source tel quel |  |
explode | décompose toute association n-aire (*,N) en n associations binaires | `explode arrange` | décomposer les non-DF ternaires et plus, puis réarranger
|  | `explode:arity=3 arrange` | idem
|  | `explode:weak arrange` | idem, avec création d'entités faibles
|  | `explode:arity=2.5 arrange` | étendre aux non-DF binaires porteuses d'attributs
|  | `explode:arity=2 arrange` | étendre à toutes les non-DF binaires
fix | essaie de corriger les erreurs courantes dans les éléments donnés | `fix:cards` | normaliser les cardinalités en 01, 11, 0N et 1N
flip | applique au diagramme une symétrie verticale, horizontale ou diagonale | `flip:v` | symétrie verticale
|  | `flip:h` | symétrie horizontale
|  | `flip:d` | symétrie selon la seconde diagonale
|  | `flip:vhd` | symétrie selon la première diagonale
|  | `flip:dhv` | idem (ordre indifférent)
grow | ajoute des entités et associations aléatoires (par défaut : 10 nouvelles associations) | `grow arrange` | ajouter des éléments avec les paramètres par défaut, puis réarranger
|  | `grow:n=10` | nombre total d'associations à ajouter (défaut)
|  | `grow:arity_1=2` | nombre d'associations réflexives (défaut)
|  | `grow:arity_3=2` | nombre d'associations ternaires (défaut)
|  | `grow:arity_4=0` | nombre d'associations quaternaires (défaut)
|  | `grow:doubles=1` | nombre d'associations liant deux mêmes entités (défaut)
|  | `grow:composite_ids=1` | nombre d'identifiants composites (défaut)
|  | `grow:ent_attrs=4` | nombre maximal d'attributs par entité (défaut)
|  | `grow:assoc_attrs=2` | nombre maximal d'attributs par association (défaut)
|  | `grow:'*1-*N'=3` | nombre d'associations `*1-*N` (défaut)
|  | `grow:'01-11'=1` | nombre d'associations `01-11` (défaut)
|  | `grow:'_11-*N'=1` | une entité faible (zéro par défaut)
|  | `grow:'/1N-*N'=1` | un agrégat (zéro par défaut)
|  | `grow:from_scratch arrange` | à partir d'un MCD vide
|  | `grow:grow:n=9,from_scratch,ent_attrs=3 obfuscate:labels=en4 create:roles lower:roles arrange` | créer un MCD d'entraînement à la conversion en relationnel
lower | réécrit les éléments donnés en minuscules | `lower:attrs,roles` | attributs et rôles en minuscules
pascal | réécrit les élements donnés en PascalCase |  |
prefix | préfixe les éléments donnés avec la chaîne donnée | `prefix:roles='-'` | force les rôles à remplacer le nom des clés étrangères lors du passage au relationnel
randomize | garde la structure, mais randomise les éléments donnés quand c'est possible | `obfuscate` | libellés remplacés par du Lorem Ipsum
|  | `obfuscate:labels=lorem` | idem
|  | `obfuscate:labels=disparition` | idem, lexique du roman de Perec
|  | `obfuscate:labels=en4` | idem, mots anglais de 4 lettres (SFW)
|  | `obfuscate:attrs=fr,boxes=fr5` | idem, mots français de longueur quelconque pour les attributs, de 5 lettres pour les boîtes
|  | `randomize:types` | types randomisés avec les fréquences de `default_datatypes_fr.tsv`.
replace | réécrit les éléments donnés en appliquant le motif « recherche/remplacement » donné | `replace:boxes='DIRIGER/RÉPONDRE DE'` | renomme une boîte
|  | `replace:texts='personel/personnel'` | corrige une faute d'orthographe
|  | `replace:replace:texts='_/ '` | remplace les tirets bas par des espaces
|  | `replace:types='VARCHAR/VARCHAR2'` | modifie un nom de type
|  | `replace:cards=0N/1N` | remplace toutes les cardinalités 0N par 1N
|  | `replace:cards=1N//1N` | crée des agrégats un peu partout
|  | `replace:cards='0/X' replace:cards='11/X1' replace:cards='1N/XN'` | masque les cardinalités minimales
|  | `delete:card_prefixes replace:cards=11/_11` | ajoute des marqueurs d'entités faibles
slice | réécrit les éléments donnés en n'en gardant qu'une tranche donnée | `slice:boxes=5:10` | de l'indice 5 (inclus) à l'indice 10 (exclu)
|  | `slice:boxes=5:` | supprime les 5 premiers caractères
|  | `slice:boxes=:5` | ne garde que les 5 premiers caractères
|  | `slice:boxes=:-5` | supprime les 5 derniers caractères
|  | `slice:boxes=:` | équivalent de `echo`
|  | `slice:boxes=` | idem
|  | `slice:boxes` | idem
snake | réécrit les éléments donnés en snake_case |  |
split | décompose toute association n-aire (*,1) en n-1 associations binaires | `split arrange` | décomposer, puis réarranger
suffix | suffixe les éléments donnés avec la chaîne donnée | `suffix:boxes=1` | Ajoute un suffixe numérique au nom des boîtes en vue de mettre un MCD et sa copie sur le même diagramme.
swapcase | réécrit les éléments donnés en inversant la casse de chaque lettre |  |
title | réécrit les éléments donnés en mettant la première lettre de chaque mot en majuscule |  |
truncate | tronque les éléments donnés à la longueur donnée (par défaut : 64) | `truncate:boxes=10` | tronque les noms des boîtes à 10 caractères
upper | réécrit les éléments donnés en majuscules | `upper:boxes` | noms des boîtes en majuscules

### Réécriture d'éléments donnés¶

Dans l'aide-mémoire, de nombreuses opérations de réécriture sont décrites comme s'appliquant à des « éléments donnés ». Il s'agit de certains ensembles de tokens produits par l'analyse syntaxique. Plus précisément :

- `arrows` : flèches de pattes (suffixes `<` ou `>` des cardinalités).
- `attrs` : libellés des attributs d'entités ou d'associations.
- `boxes` : libellés des entités et associations.
- `cards` : cardinalités (`11`, `1N`, etc., sans préfixe ni suffixe).
- `card_prefixes` : préfixes de cardinalités (`_` pour les entités faibles, `/` pour les agrégats).
- `constraint_notes` : messages affichés au survol d'une contrainte.
- `labels` : libellés des entités, des associations et des attributs.
- `leg_notes` : notes de pattes (rôles ou messages affichés au survol).
- `notes` : équivalent de `roles` + `constraint_notes`.
- `roles` : alias de `leg_notes`.
- `texts` : équivalent de `labels` + `notes`.
- `types` : types de données.

## Fonctionnement de la commande magique¶

Il peut être utile de comprendre ce qui se passe en coulisses lorsque l'on invoque la commande magique sur une cellule d'un notebook Jupyter :

- dans le répertoire courant est créé au besoin un sous-répertoire `mocodo_notebook` ;
- le texte d'entrée y est sauvegardé sous le nom de `sandbox.mcd` ;
- la commande est lancée sur ce fichier avec tous les paramètres donnés par l'utilisateur. Cela signifie que tous les fichiers générés le seront au même endroit sous les noms de `sandbox.svg`, `sandbox.html`, etc. (relisez-les avec la commande magique `%load`) ;
- certains des fichiers générés sont affichés dans la sortie de la cellule, d'autres pas, selon les règles suivantes (`rw` et `cv` dénotent respectivement une opération de réécriture et de conversion) :

commande | tracé du MCD | résultat des réécritures | résultats des conversions
--- | --- | --- | ---
`mocodo` | initial | - | -
`mocodo -t` ou `mocodo --mld` | initial | - | MLD en Markdown
`mocodo -t rw1 rw2 ...` | final | final | -
`mocodo -t cv1 cv2 ...` | - | - | tous
`mocodo -t rw1 rw2 ... cv1 cv2 ...` | final | - | tous

Ces règles d'affichage par défaut devraient répondre aux besoins les plus courants, mais l'option `--select` peut prendre le pas :

- sans arguments, rien n'est affiché ;
- l'argument `mcd` affiche le diagramme conceptuel ;
- l'argument `rw` (ou un alias de commodité parmi `source`, `text`, `code`, `mocodo`) affiche le résultat de la dernière réécriture ;
- l'argument `cv` (ou un alias de commodité parmi `mld`, `ddl`, `sql`) affiche les résultats des conversions ;
- ces arguments peuvent être librement combinés et ordonnés ;
- l'argument `all` affiche tout ce qui est disponible, dans l'ordre `mcd`, `rw` et `cv` ;

Les conversions génèrent par défaut un fichier-texte. Un dessin s'affichera à la place :

- pour l'argument `diagram` ;
- avec l'option `--defer`, pour autant qu'un web-service de rendu soit défini pour le fichier en question.

Il est possible de mettre `-t` en majuscule. Dans ce cas :

- s'il y a une ou plusieurs opérations de réécriture, le résultat de la dernière réécriture remplace le contenu de la cellule et la sortie est effacée ;
- sinon, s'il y a une ou plusieurs opérations de conversion et que Pyperclip est installé, le résultat de la dernière conversion est copié dans le presse-papier.

## Gabarits de passage au relationnel¶

L'algorithme convertissant la représentation interne d'un schéma relationnel en une représentation externe dans tel ou tel format est totalement découplé dudit format. Cela signifie que vous pouvez modifier ou créer un format sans écrire une seule ligne de code, mais en remplissant une espèce de formulaire, ou gabarit (template en anglais).

Si vous n'avez aucune velléité de le faire ou que vous n'êtes pas ami avec les expressions régulières, vous pouvez sauter cette section. Sinon, accrochez-vous, ça va devenir un peu technique.

### Format des gabarits¶

Les gabarits de Mocodo étaient à l'origine écrits en JSON. Par conséquent, un grand nombre des caractères utilisés dans les expressions régulières devaient être échappés, ce qui rendait celles-ci (encore) plus difficiles à écrire, à relire et à tester. La version 4 passe à YAML, qui n'a pas cet inconvénient. Voici par exemple un extrait de gabarit dans l'ancienne syntaxe :

        {
          "order": 400,
          "comment": "Move all foreign keys constraints at the end of the document",
          "search": "(?sm)(CREATE TABLE ([^\n]+) \\(\n(?:[^\n]+\n)*)  (FOREIGN KEY[^\n]+),\n(.*)",
          "replace": "\\1\\4\nALTER TABLE \\2 ADD \\3;",
          "iterated": true
        },

... et le même dans la nouvelle :

      - order: 400
        comment: 'Move all foreign keys constraints at the end of the document'
        search: '(?sm)(CREATE TABLE ([^\n]+) \(\n(?:[^\n]+\n)*)  (FOREIGN KEY[^\n]+),\n(.*)'
        replace: '\1\4\nALTER TABLE \2 ADD \3;'
        iterated: true

Si vous avez écrit vos propres gabarits JSON, vous pouvez les convertir automatiquement en YAML à l'aide du script `json_to_yaml_templates.py` fourni dans le répertoire `dev`.

Remarque. Si les gabarits de Mocodo constituent des fichiers YAML valides, l'inverse n'est pas forcément vrai. Mocodo utilise un sous-ensemble sain de YAML adapté à ses besoins. Il a son propre parser avec les particularités suivantes :

- Un gabarit est un dictionnaire dont les valeurs sont :
  - soit des types scalaires (chaînes, nombres, booléens, `null`) ;
  - soit des listes de dictionnaires à valeurs scalaires.
- Toute valeur chaîne doit être délimitée par des simples quotes (`'`). Les quotes internes sont échappées en les doublant (`''`).
- Les expressions régulières de recherche et de remplacement suivent les mêmes règles d'échappement que les r-strings de Python.
- Les autres chaînes (notamment les chaînes de composition) ne demandent pas à échapper les anti-slashes, mais à doubler les accolades (règles des fr-strings). Exception : pour les distinguer du retour-chariot et de la tabulation, il faudra échapper les `\n` et les `\t` si on veut les laisser littéralement. Vous en avez un exemple pour `\newcommand` et `\title` dans le boilerplate du gabarit pour $\LaTeX$.

### Dérivation de gabarits¶

Depuis la version 3.1, il est possible de définir un gabarit dérivé d'un autre (qui lui-même peut dériver d'un autre, etc.). Dans le but de réduire les redondances et de faciliter les tests et la maintenance, la version 4.0 fait un usage intensif de cette fonctionnalité :

In [187]:

    display.SVG("../../mocodo/resources/relation_templates/_graph.svg")

Out[187]:

Les teintes les plus foncées correspondent approximativement aux gabarits les plus complexes. Les autres ne sont souvent que des alias, par exemple, `tex.yaml` renvoie directement à `latex.yaml` :

In [188]:

    display.Code("../../mocodo/resources/relation_templates/tex.yaml")

Out[188]:

    parent: 'latex'

La clé `"parent"` donne le chemin ou le nom du gabarit dont on souhaite créer une version dérivée :

- une chaîne terminée par `.yaml` est interprétée comme un chemin ;
- sinon, comme le nom d'un gabarit de la distribution.

Tous les gabarits textuels (`text.yaml`, `latex.yaml`, `markdown.yaml`, `html.yaml` et leurs alias) dérivent des gabarits `html-c.yaml` (version avec affichage des contraintes) et `html-ce.yaml` (version avec affichage des contraintes et des explications).

Par exemple, le gabarit `latex` se borne à ajouter un message d'aide pour la ligne de commande et à empêcher l'ajout des contraintes d'unicité et d'optionalité :

In [189]:

    display.Code("../../mocodo/resources/relation_templates/latex.yaml")

Out[189]:

    help_en: 'convert the conceptual model into a relational schema in LaTeX format'
    help_fr: 'convertit le modèle conceptuel en un schéma relationnel au format LaTeX'
    help_zh: '将概念模型转换为 LaTeX 格式的关系模式'
    fr_examples:
      - order: 1
        example: 'latex'
        explanation: 'version de base'
      - order: 2
        example: 'latex:b'
        explanation: 'avec _boilerplate_'
      - order: 3
        example: 'latex:c'
        explanation: 'avec contraintes d''unicité et d''optionalité'
      - order: 4
        example: 'latex:e'
        explanation: 'avec explications'
      - order: 5
        example: 'latex:bce'
        explanation: 'avec _boilerplate_, contraintes et explications'
    parent: 'latex-c'
    add_unicity_constraints:
    add_optionality_constraints:

Si maintenant on regarde le contenu de son parent `latex-c` :

In [190]:

    display.Code("../../mocodo/resources/relation_templates/latex-c.yaml")

Out[190]:

    parent: 'html-c'
    extension: 'tex'
    highlight: 'latex'
    column_separator: ', '
    compose_relation: '  \item \relat{{{this_relation_name}}} ({columns})'
    compose_relational_schema: '% Generated by Mocodo {version}\n\n\begin{{itemize}}\n{relations}\n\end{{itemize}}\n'
    transform_relation:
      - order: 1000
        comment: 'Compose normal attributes'
        search: '<span class=''normal''>(.+?)</span>'
        replace: '\\attr{\1}'
      - order: 1100
        comment: 'Compose primary keys'
        search: '<span class=''primary''>(.+?)</span>'
        replace: '\\prim{\1}'
      - order: 1200
        comment: 'Compose foreign primary keys'
        search: '<span class=''foreign primary''>#(.+?)</span>'
        replace: '\\foreign{\\prim{\1}}'
      - order: 1300
        comment: 'Compose foreign attributes'
        search: '<span class=''foreign''>#(.+?)</span>'
        replace: '\\foreign{\1}'
      - order: 1400
        comment: 'Exponents'
        search: '(<sup>.*u)(\d)(.*</sup>)'
        replace: '\1_\2\3'
        iterated: true
      - order: 1500
        comment: 'Exponents'
        search: ' <sup>(.+?)</sup>'
        replace: '$^{\1}$'
      - order: 1600
        comment: 'Escape underlines'
        search: '_'
        replace: '\_'

... on voit que les opérations consistent simplement à modifier le séparateur de colonne, à composer les tables et le schéma relationnel complet avec un boilerplate, et enfin à remplacer les balises HTML par leur équivalent en $\LaTeX$. Toute la logique complexe est traitée dans le gabarit `html-c`.

### Exemples de création de gabarit dérivé ¶

Le gabarit SQL par défaut rend explicite la contrainte `NOT NULL` des clés primaires :

In [191]:

    %%mocodo -t sql
    PERSONNE: id. personne [VARCHAR(8)], nom [VARCHAR(255)]

`sandbox_ddl.sql`

    CREATE TABLE PERSONNE (
      PRIMARY KEY (id_personne),
      id_personne VARCHAR(8) NOT NULL,
      nom         VARCHAR(255)
    );

Supposons que cette redondance nous défrise, et voyons comment l'éliminer. Pour cela, examinons le contenu du gabarit `sql.yaml` :

La contrainte d'optionalité `{optionality}` apparaît à côté de `PRIMARY KEY` en lignes 28 et 31. Nous pouvons donc simplement remplacer les valeurs associées à `compose_primary_key` et `compose_primary_foreign_key` par des copies supprimant cette mention :

In [192]:

    %%file new_sql.yaml
    parent: 'sql'
    compose_primary_key: '{label} {datatype}\nPRIMARY KEY ({label})'
    compose_primary_foreign_key: '{label} {datatype}\nPRIMARY KEY ({label})\nFOREIGN KEY ({label}) REFERENCES {outer_source} ({non_disambiguated_label})'

    Overwriting new_sql.yaml

Pour tester ce nouveau gabarit, nous devons ajouter la sous-option `-t relation` avec en sous-argument le chemin complet du fichier créé :

In [193]:

    %mocodo -i sandbox -t relation:new_sql.yaml

`sandbox_ddl.sql`

    CREATE TABLE PERSONNE (
      PRIMARY KEY (id_personne),
      id_personne VARCHAR(8),
      nom         VARCHAR(255)
    );

Mission accomplie !

Nous aurions pu procéder autrement. Reprenons le gabarit original :

Le dictionnaire `transform_relation` spécifie une séquence de réécritures à appliquer à chacune des clauses `CREATE TABLE` (composées ligne 37). La première accumule toutes les lignes contenant `PRIMARY KEY` en fin de table (où elles seront concaténées avant d'être ramenées au début). Nous devons donc intervenir avant que `NOT NULL` ne soit séparé de `PRIMARY KEY`. Pour cela, définissons un gabarit qui se borne à insérer avant cette transformation (de numéro d'ordre 100) une suppression des `NOT NULL` incriminés :

In [194]:

    %%file new_sql.yaml
    parent: 'sql'
    transform_relation:
      - order: 50
        comment: 'Suppress PK NN redundancy.'
        search: ' NOT NULL\nPRIMARY KEY'
        replace: '\nPRIMARY KEY'

    Overwriting new_sql.yaml

Le résultat est le même :

In [195]:

    %mocodo -i sandbox -t relation:new_sql.yaml

`sandbox_ddl.sql`

    CREATE TABLE PERSONNE (
      PRIMARY KEY (id_personne),
      id_personne VARCHAR(8),
      nom         VARCHAR(255)
    );

NB. Les gabarits définis par l'utilisateur n'ont pas vocation à être placés dans le répertoire `relation_templates` de la distribution. Votre nouveau gabarit `new_sql` ne peut donc pas être invoqué aussi simplement que les gabarits officiels (i.e., avec `-t new_sql`). Si vous faites une modification ou un ajout que vous voulez voir inclus dans la distribution, n'hésitez pas à faire une PR.

### Mécanisme de mise à jour¶

Le mécanisme de mise à jour des clés dépend de la scalarité de leur valeur associée.

Cas scalaire.

Pour les valeurs scalaires (chaînes, nombres, booléens, `null`), selon la présence d'une entrée donnée dans le gabarit enfant et/ou le gabarit parent, l'association clé-valeur correspondante sera créée, mise à jour ou conservée :

enfant | parent | résultat
--- | --- | ---
oui | non | création
oui | oui | mise à jour
non | oui | conservation

Il n'y a pas de moyen de supprimer une association clé-valeur, mais étant donné que toutes celles qui sont absentes se voient substituer une association par défaut, il est équivalent de spécifier explicitement la valeur-défaut.

Cas non scalaire.

Dans les gabarits de relations de Mocodo, une seule catégorie de valeur non scalaire est possible : la liste de dictionnaires. Dans l'exemple précédent, c'est le cas de `transform_relation`.

Une clé `"order"` est systématiquement présente dans chacun des dictionnaires de la liste. Selon la présence d'un dictionnaire de numéro d'ordre donné dans le gabarit enfant et/ou le gabarit parent, ce dictionnaire sera inséré, supprimé, mis à jour ou conservé :

enfant | parent | résultat
--- | --- | ---
oui | non | insertion
oui | oui | si les clés sont parmi {`"order"`, `"comment"`} : suppression s'il y a plusieurs clés : mise à jour
non | oui | conservation

Nouveauté de la version 4.0. Si une clé d'un gabarit enfant est associée à une liste vide, cette association remplace l'éventuelle association existante.

Remarque. Les numéros d'ordre utilisés dans les dictionnaires sont des multiples de 100. Si vous voulez créer des gabarits dérivés, évitez par précaution les multiples de 10 : cela augmentera les chances que votre gabarit survive à une mise à jour de l'un de ses ancêtres. Vous pouvez aussi partir d'une copie de ceux-ci, sachant que vous renoncez alors aux bénéfices de leurs éventuelles mises à jour.

# Annexe C : Crédits¶

- Auteur
  - Aristide Grange, Université de Lorraine, Metz, LCOMS.
- Administration système
  - Cyril Minette.
- Outils
  - Aspect visuel
    - Color Brewer (Cynthia Brewer).
    - Real Favicon Generator (Philippe Bernard).
    - reset.css (Eric Meyer).
  - JavaScript
    - JQuery (John Resig).
    - JS-Cookie (Klaus Hartl).
    - Ace Editor (Cloud9 IDE et Mozilla).
  - Python
    - Distance de Damerau-Levenshtein (Michael Homer).
    - Lark Parser (Erez Shinan).
    - CairoSVG (CourtBouillon).
    - Pyperclip (Al Sweigart).
  - Services de rendu
    - Kroki.io (Guillaume Grossetie).
    - QR Code Generator (Foundata GmbH).
- Divers
  - Modern SQL (Markus Winand).
  - DBML (Holistics).
  - D2 (Terrastruct).
  - Basthon (Romain Casati).