{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "init_cell": true
   },
   "outputs": [],
   "source": [
    "%reload_ext mocodo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Basic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Tutoriel interactif (1/2)\n",
    "% Un petit zoo de la syntaxe de Mocodo, avec quelques possibilités de base :\n",
    "% entité, association, attribut, identifiant, cardinalité, patte, rôle.\n",
    "% \n",
    "% MCD adapté de : The entity-relationship model—toward a unified view of data\n",
    "% (Chen, 1976).\n",
    "\n",
    "AYANT-DROIT: num. ayant-droit, nom ayant-droit, lien\n",
    "DIRIGER, 0N [responsable] EMPLOYÉ, 01 PROJET\n",
    "REQUÉRIR, 1N PROJET, 0N PIÈCE: qté requise\n",
    "PIÈCE: réf. pièce, libellé pièce\n",
    "COMPOSER, 0N [composée] PIÈCE, 0N [composante] PIÈCE: quantité\n",
    "\n",
    "DF, 11 AYANT-DROIT, 0N EMPLOYÉ\n",
    "EMPLOYÉ: matricule, nom employé\n",
    "PROJET: num. projet, nom projet\n",
    "FOURNIR, 1N PROJET, 1N PIÈCE, 1N SOCIÉTÉ: qté fournie\n",
    "\n",
    "DÉPARTEMENT: num. département, nom département\n",
    "EMPLOYER, 11 EMPLOYÉ, 1N DÉPARTEMENT\n",
    "TRAVAILLER, 0N EMPLOYÉ, 1N PROJET\n",
    "SOCIÉTÉ: num. société, raison sociale\n",
    "CONTRÔLER, 0N [mère] SOCIÉTÉ, 01 [filiale] SOCIÉTÉ"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Entité\n",
    "% Pour créer une entité E, écrivez sur une ligne « E: ».\n",
    "% Bon à savoir : les lignes commençant par « % » sont des commentaires.\n",
    "\n",
    "Produit:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Identifiant et attributs d'entité\n",
    "% Donnez-lui des attributs en écrivant « E: attr_1, attr_2, ... ».\n",
    "% L'usage des espaces, accents et signes de ponctuation corrects est conseillé :\n",
    "% « Réf. produit » est plus lisible que « refproduit » et pourra toujours être\n",
    "% « appauvri » ultérieurement (bouton Éditer).\n",
    "%\n",
    "% Astuce : pour passer à l'exemple suivant, tapez [↓], [↓], [⏎] (ou seulement\n",
    "% [→] sous Firefox).\n",
    "\n",
    "Produit: Réf. produit, Libellé, Prix unitaire"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Identifiant composite\n",
    "% Vous avez remarqué que, par défaut, le premier attribut est considéré comme\n",
    "% un identifiant, et donc souligné. Pour souligner d'autres attributs, il faut\n",
    "% les préfixer d'un tiret bas.\n",
    "\n",
    "Gratte-ciel: latitude, _longitude, nom, hauteur, année de construction"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Association\n",
    "% Pour une association A entre plusieurs entités E1, E2, ..., écrivez sur une\n",
    "% ligne « A, XX E1, XX E2, ... ».\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, XX Commande, XX Produit\n",
    "Commande: num. commande, date, montant"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Cardinalités\n",
    "% Si vous connaissez le couple de cardinalités d'une patte, mettez 01, 11, 0N\n",
    "% ou 1N à la place du XX de l'entité distinguée par cette patte.\n",
    "%\n",
    "% NB. Cliquez sur le bouton Éditer et sélectionnez « Correction des fautes de\n",
    "% frappe dans le cardinalités » pour transformer « ON » en « 0N » ci-dessous.\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, 1N Commande, ON Produit\n",
    "Commande: num. commande, date, montant"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Attribut d'association\n",
    "% Pour ajouter des attributs à une association, faites comme pour une entité :\n",
    "% mettez un deux-points au bout de la ligne, puis listez les attributs en les\n",
    "% séparant par des virgules.\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, 1N Commande, 0N Produit: quantité\n",
    "Commande: num. commande, date, montant"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Association de dépendance fonctionnelle\n",
    "% Si votre association a une cardinalité 11, mais aucun attribut, vous pouvez\n",
    "% la nommer « DF » : Mocodo la représentera par un cercle.\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, 1N Commande, 0N Produit: quantité\n",
    "Commande: num. commande, date, montant\n",
    "DF, 0N Client, 11 Commande\n",
    "Client: réf. client, nom, prénom, adresse"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Association réflexive\n",
    "% En répétant le nom d'une entité dans la définition d'une association, vous\n",
    "% rendez celle-ci réflexive.\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, 1N Commande, 0N Produit: quantité\n",
    "Commande: num. commande, date, montant\n",
    "DF, 0N Client, 11 Commande\n",
    "Client: réf. client, nom, prénom, adresse\n",
    "Parrainer, 01 Client, 0N Client : date parrainage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo --mld\n",
    "% Schéma relationnel\n",
    "% Allez sous l'onglet Options, cochez « Schéma relationnel expliqué », puis\n",
    "% rafraîchissez la figure : une liste des tables apparaît au-dessous. Cliquez\n",
    "% sur n'importe quelle ligne pour mieux comprendre comment elle a été obtenue.\n",
    "%\n",
    "% Dans la table « Client », remarquez les colonnes « Réf. client » et « Réf.\n",
    "% client 2 » : ce n'est pas très satisfaisant...\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, 1N Commande, 0N Produit: quantité\n",
    "Commande: num. commande, date, montant\n",
    "DF, 0N Client, 11 Commande\n",
    "Client: réf. client, nom, prénom, adresse\n",
    "Parrainer, 01 Client, 0N Client : date parrainage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo -t mld\n",
    "% Rôles\n",
    "% Dans ce MCD, on a ajouté la chaîne « parrain » sur la patte 0,N de PARRAINER.\n",
    "% Cette technique permet de préserver la sémantique des associations disparues.\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, 1N Commande, 0N Produit: quantité\n",
    "Commande: num. commande, date, montant\n",
    "DF, 0N Client, 11 Commande\n",
    "Client: réf. client, nom, prénom, adresse\n",
    "Parrainer, 01 Client, 0N [parrain] Client : date parrainage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo -t diagram\n",
    "% Diagramme relationnel (1)\n",
    "% Cochez « Diagramme relationnel en Mocodo », rafraîchissez la figure et allez\n",
    "% sous l'onglet Autres sorties. Vous y trouvez un texte-source que vous pouvez\n",
    "% copier-coller (⧉) ici pour voir apparaître un autre type de schéma.\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, 1N Commande, 0N Produit: quantité\n",
    "Commande: num. commande, date, montant\n",
    "DF, 0N Client, 11 Commande\n",
    "Client: réf. client, nom, prénom, adresse\n",
    "Parrainer, 01 Client, 0N [parrain] Client : date parrainage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Diagramme relationnel (2)\n",
    "% Voici le résultat de la manipulation précédente. Les associations ont cédé la\n",
    "% place à des flèches entre les clés étrangères et les clés primaires d'origine.\n",
    "\n",
    ":\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    ":\n",
    "Inclure: #num. commande > Commande > num. commande, _#réf. produit > Produit > réf. produit, quantité\n",
    ":\n",
    "Commande: num. commande, date, montant, #réf. client > Client > réf. client\n",
    ":\n",
    "Client: réf. client, nom, prénom, adresse, #réf. client parrain > Client > réf. client, date parrainage\n",
    ":"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo -t guess:types\n",
    "% Inférence de types\n",
    "% Cliquez sur le lapin magique, puis sélectionnez : « deviner les types à\n",
    "% partir du nom des attributs » (en français ou en anglais). Bien sûr, vous\n",
    "% pourrez toujours rectifier ceux-ci au besoin.\n",
    "% Notez que l'inférence donne de meilleurs résultats si les libellés sont écrits\n",
    "% de façon standard : Mocodo proposera un type pour « réf. produit », mais pas\n",
    "% pour « refproduit ».\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, 1N Commande, 0N Produit: quantité\n",
    "Commande: num. commande, date, montant\n",
    "DF, 0N Client, 11 Commande\n",
    "Client: réf. client, nom, prénom, adresse\n",
    "Parrainer, 01 Client, 0N [parrain] Client : date parrainage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo -t sql\n",
    "% Génération du DDL\n",
    "% Maintenant que le MCD est typé, cochez « Script SQL de création des tables »,\n",
    "% rafraîchissez et allez voir le résultat sous l'onglet Autres sorties. Notez en\n",
    "% particulier les contraintes de clés étrangères à la fin. Notez aussi que les\n",
    "% les libellés originaux ont été automatiquement « appauvris » : ainsi, « réf.\n",
    "% produit » est devenu « ref_produit », etc. Cela rend le code SQL plus portable\n",
    "% et simplifie les références lors de l'utilisation de la base.\n",
    "\n",
    "Produit: réf. produit [VARCHAR(8)], libellé [VARCHAR(50)], prix unitaire [DECIMAL(10,2)]\n",
    "Inclure, 1N Commande, 0N Produit: quantité [INTEGER]\n",
    "Commande: num. commande [VARCHAR(8)], date [DATE], montant [DECIMAL(10,2)]\n",
    "DF, 0N Client, 11 Commande\n",
    "Client: réf. client [VARCHAR(8)], nom [VARCHAR(255)], prénom [VARCHAR(255)], adresse [VARCHAR(30)]\n",
    "Parrainer, 01 Client, 0N [parrain] Client : date parrainage [DATE]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Schéma sur plusieurs rangées\n",
    "% Pour finir la première partie du tutoriel, quelques notions de mise en page.\n",
    "% Les boîtes (entités et association) définies sur des lignes consécutives sont\n",
    "% alignées horizontalement sur la même rangée d'une grille invisible. Pour créer\n",
    "% une nouvelle rangée, il suffit de sauter une ligne entre deux clauses.\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, 1N Commande, 0N Produit: quantité\n",
    "Commande: num. commande, date, montant\n",
    "\n",
    "DF, 0N Client, 11 Commande\n",
    "Client: réf. client, nom, prénom, adresse\n",
    "Parrainer, 01 Client, 0N Client : date parrainage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Réarrangement automatique\n",
    "% Quand le schéma devient confus, faites un double clic sur la tablette de\n",
    "% chocolat pour le réarranger aléatoirement. L'algorithme veille à éviter\n",
    "% les croisements et à minimiser la longueur des pattes. Essayez !\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, 1N Commande, 0N Produit: quantité\n",
    "Commande: num. commande, date, montant\n",
    "\n",
    "DF, 0N Client, 11 Commande\n",
    "Client: réf. client, nom, prénom, adresse\n",
    "Parrainer, 01 Client, 0N Client : date parrainage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Réarrangement automatique avec contraintes\n",
    "% Cliquez sur la tablette de chocolat pour faire apparaître d'autres options de\n",
    "% réorganisation. Celles-ci tentent de plonger le MCD sur la grille actuelle, ou\n",
    "% en largeur d'abord (pour un document paginé), ou en équilibrant les dimensions\n",
    "% (pour un diaporama).\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, 1N Commande, 0N Produit: quantité\n",
    "Commande: num. commande, date, montant\n",
    "\n",
    "DF, 0N Client, 11 Commande\n",
    "Client: réf. client, nom, prénom, adresse\n",
    "Parrainer, 01 Client, 0N Client : date parrainage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Entraînement au passage au relationnel\n",
    "% Cochez l'option « Masquage et génération aléatoire », cliquez le bouton qui\n",
    "% vient d'apparaître et sélectionnez « Créer un MCD d'entraînement à la\n",
    "% conversion en relationnel ». Apparaît un MCD avec des libellés aléatoires,\n",
    "% et dont la structure met en œuvre une certaine diversité de cas. Essayez de\n",
    "% le convertir en relationnel, et comparez votre solution à celle de Mocodo.\n",
    "\n",
    "LOREM: ipsum, dolor, amet"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Pour aller plus loin...\n",
    "% Si vous débutez dans les bases de données, les exemples précédents devraient\n",
    "% suffire à votre bonheur. Dans le cas contraire, cochez l'option « Tutoriel\n",
    "% interactif (2/2) » et revenez ici.\n",
    "\n",
    "À suivre...: ou pas!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Advanced"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo --mld\n",
    "% Tutoriel interactif (2/2)\n",
    "% Une variation du MCD de Chen avec deux notions plus avancées : entité faible\n",
    "% et contrainte sur associations ; ainsi que trois nouvelles fonctionnalités :\n",
    "% flèches, calques, messages au survol.\n",
    "\n",
    "AYANT-DROIT: nom ayant-droit, lien\n",
    "DIRIGER, 0N [responsable] EMPLOYÉ, 01 PROJET\n",
    "REQUÉRIR, 1N PROJET, 0N PIÈCE: qté requise\n",
    "PIÈCE: réf. pièce, libellé pièce\n",
    "COMPOSER, 0N [composée] PIÈCE, 0N [composante] PIÈCE: quantité\n",
    "\n",
    "DF, _11 AYANT-DROIT, 0N EMPLOYÉ\n",
    "EMPLOYÉ: matricule, nom employé\n",
    "PROJET: num. projet, nom projet\n",
    "FOURNIR, 1N PROJET, 1N PIÈCE, 1N SOCIÉTÉ: qté fournie\n",
    "\n",
    "DÉPARTEMENT: num. département, nom département\n",
    "EMPLOYER, 11 EMPLOYÉ, 1N DÉPARTEMENT\n",
    "TRAVAILLER, 0N EMPLOYÉ, 1N PROJET\n",
    "SOCIÉTÉ: num. société, raison sociale\n",
    "CONTRÔLER, 0N< [mère] SOCIÉTÉ, 01 [filiale] SOCIÉTÉ\n",
    "\n",
    "  (I) [Les pièces fournies par une société pour un projet font partie de celles qu'il requiert.] ..PIÈCE, ->REQUÉRIR, --FOURNIR, PROJET"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Entité faible (ou identification relative)\n",
    "% Préfixez d'un tiret bas une cardinalité 11 pour « affaiblir » l'entité qu'elle\n",
    "% distingue, et dont l'identifiant sera alors souligné en pointillés.\n",
    "%\n",
    "% NB. De façon non conventionnelle, Mocodo souligne le 11 pour indiquer que le\n",
    "% « renforcement » de l'identifiant va passer par là. Voyez la documentation\n",
    "% pour des options alternatives.\n",
    "\n",
    "Œuvre: cote œuvre, titre, date parution\n",
    "DF, 1N Œuvre, _11 Exemplaire\n",
    "Exemplaire: num. exemplaire, état du livre, date d'achat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Entité faible sans identifiant\n",
    "% Préfixez d'un tiret bas le premier attribut pour l'exclure de l'identifiant,\n",
    "% p. ex. pour une entité faible sans discriminateur.\n",
    "\n",
    "Pavillon: id. pavillon, surface, nombre d'étages\n",
    "Posséder, 01 Pavillon, _11 Piscine\n",
    "Piscine: _surface, volume"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Identifiants candidats\n",
    "% Préfixez d'un « i_ » les attributs formant le ième identifiant alternatif.\n",
    "% Ce numéro apparaîtra dans une gouttière latérale, ainsi qu'un symbole ID en\n",
    "% face des attributs que vous aurez retenus pour l'identifiant. Le code SQL\n",
    "% généré inclura une contrainte d'unicité pour chacun des groupes concernés.\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, 1N Commande, 0N Produit: quantité\n",
    "Commande: num. commande, date, montant\n",
    "DF, 0N Client, 11 Commande\n",
    "Client: réf. client, 1_nom, 1_prénom, adresse, 2_mail\n",
    "Parrainer, 01 Client, 0N [parrain] Client : date parrainage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "%%mocodo -t mld sql\n",
    "% Héritage (ou spécialisation)\n",
    "% Pour spécialiser une entité E en une ou plusieurs autres entités E1, E2, ...\n",
    "% écrivez « /\\ E <- E1, E2, ... ».\n",
    "%\n",
    "% NB. Vous pouvez insérer X (exclusion) et/ou T (totalité) entre les barres\n",
    "% obliques, ajouter une liste d'attributs ou modifier la sémantique et/ou la\n",
    "% représentation graphique de l'héritage en remplaçant la flèche par <=, ->,\n",
    "% =>, <<=, <<-, ->> =>>. Voir la documentation.\n",
    "\n",
    "Client: réf. client, nom, prénom, adresse\n",
    "\n",
    "/X\\ Client <- Particulier, Employé, Administratif\n",
    "\n",
    "Particulier:\n",
    "Employé: siret entreprise\n",
    "Administratif: nom ministère"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo -t mld:c --select mcd mld\n",
    "% Agrégation (ou pseudo-entité)\n",
    "% Préfixez de « / » une cardinalité pour entourer d'une enveloppe pointillée\n",
    "% l'association et les autres entités participantes.\n",
    "% Ici, la dépendance fonctionnelle (date, numéro) => id. client se traduit au\n",
    "% niveau relationnel par un identifiant réduit pour Réserver, ainsi qu'une\n",
    "% contrainte de non-optionalité pour id. client. Les contraintes apparaissent\n",
    "% dans les sorties SQL, mais vous pouvez aussi les visualiser au niveau du MLD\n",
    "% en cochant l'option « Contraintes d'unicité et d'optionalité ».\n",
    "%\n",
    "% NB. La représentation usuelle (non prise en charge par Mocodo) insérerait\n",
    "% une association entre Client et Réserver.\n",
    "\n",
    "Date: date\n",
    "Réserver, /1N Client, 1N Chambre, 0N Date: durée\n",
    "Chambre: numéro, prix\n",
    "\n",
    "Client: id. client"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo -t mld:c sql --select mcd mld\n",
    "% Agrégation et contraintes d'unicité\n",
    "% La conversion en relationnel d'un agrégat avec une cardinalité maximale 1\n",
    "% ajoute une contrainte d'unicité sur la clé étrangère.\n",
    "\n",
    "Voilier: num voilier, longueur\n",
    "Offrir, 0N Voilier, 0N Semaine, /11 Réservation: tarif\n",
    "Semaine: num semaine, 1_date début\n",
    "\n",
    "Réservation: num résa, arrhes, date résa"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Agrégation multiple\n",
    "% Mocodo gère correctement les cas difficiles à modéliser dans la notation Look\n",
    "% Here de Merise. Par exemple, deux dépendances fonctionnelles simultanées :\n",
    "% - (Projet, Employé) => Site.\n",
    "% - (Employé, Site) => Projet.\n",
    "\n",
    "Projet: projet\n",
    "Affecter, /1N Site, /1N Projet, 0N Employé\n",
    "Site: site\n",
    "\n",
    "Employé: employé"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Contrainte d'intégrité fonctionnelle (CIF)\n",
    "% Les mêmes cas de figure peuvent aussi être rendus visuellement par des CIF à\n",
    "% unicité complète (le seul type de CIF pris en charge par Mocodo).\n",
    "\n",
    "Date: date\n",
    "Réserver, /1N Client, 1N Chambre, 0N Date: durée\n",
    "Chambre: numéro, prix\n",
    "    \n",
    "Client: id. client\n",
    "    \n",
    "(CIF) ->Client, --Chambre, --Date, ..Réserver: Date, Client"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Autres contraintes sur associations\n",
    "% Ajoutez à votre MCD diverses contraintes sous forme de lettres parenthésées\n",
    "% et liées aux boîtes par des traits fléchés ou non, pleins ou pointillés, ou\n",
    "% même invisibles. Ces contraintes sont purement décoratives, et ignorées lors\n",
    "% du passage au relationnel.\n",
    "%\n",
    "% NB : par défaut, le centre de la contrainte coïncide avec le barycentre des\n",
    "% boîtes qu'elle met en jeu.\n",
    "%\n",
    "% Source du MCD : Merise, deuxième génération (Nanci et Espinasse, 2001).\n",
    "\n",
    ":::\n",
    "Dépôt: num dépôt, surface\n",
    "\n",
    ":\n",
    "Louer, 11 Commande, 0N Dépôt\n",
    ":\n",
    "Stocker, 1N Dépôt, 1N Article: quantité\n",
    "\n",
    "Commande: num. commande, date\n",
    "Composer, 1N Commande, 0N Article\n",
    ":\n",
    "Article: réf. article, prix\n",
    "\n",
    "(I) ->Stocker, ..Dépôt, ..Article, --Composer, --Louer, Commande, Stocker"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Explication interactive d'une contrainte\n",
    "% Le survol d'une contrainte suivie d'un texte entre crochets affiche celui-ci\n",
    "% dans un bandeau. Essayez !\n",
    "\n",
    "Projet: num. projet, nom projet\n",
    ":\n",
    "Fournir, 1N Projet, 1N Pièce, 1N Société: quantité\n",
    "Société: num. société, raison sociale\n",
    "\n",
    "Requérir, 1N Projet, 0N Pièce: quantité\n",
    ":\n",
    "Pièce: réf. pièce, libellé pièce\n",
    "\n",
    "(I) [Toute pièce fournie doit avoir été requise.] ..Pièce, ->Requérir, --Fournir, Projet"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Explication interactive des cardinalités\n",
    "% Même fonctionnalité pour les cardinalités. Si l'élément survolé est en bas\n",
    "% du diagramme, le bandeau apparaît en haut, et vice versa.\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, 1N [Une commande inclut au moins un produit.] Commande, 0N [Un produit peut être commandé un nombre quelconque de fois.] Produit: quantité\n",
    "Commande: num. commande, date, montant\n",
    "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\n",
    "Client: réf. client, nom, adresse\n",
    "Parrainer, 01 [Un client peut avoir été parrainé ou non.] Client, 0N [Un client peut parrainer d'autres clients.] Client : date parrainage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Flèche sur une patte\n",
    "% En suffixant de « < » ou « > » des cardinalités, vous créez une flèche dont\n",
    "% la direction se lit de l'association à l'entité.\n",
    "\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "Inclure, 1N Commande, 0N> Produit: quantité\n",
    "Commande: num. commande, date, montant\n",
    "DF, 0N Client, 11> Commande\n",
    "Client: réf. client, nom, prénom, adresse\n",
    "Parrainer, 01> Client, 0N< Client : date parrainage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Dévoilement progressif du schéma\n",
    "% Indentez (i.e., insérez des espaces au début de) certaines clauses pour créer\n",
    "% des calques. Les boîtes définies avec la même indentation sont tracées sur le\n",
    "% même calque. Les calques sont ordonnés par indentation croissante. Sous Mocodo\n",
    "% online, pour faciliter la mise au point, le schéma est directement dévoilé.\n",
    "\n",
    "      Parrainer, 01 Client, 0N Client : date parrainage\n",
    "Produit: réf. produit, libellé, prix unitaire\n",
    "  Inclure, 1N Commande, 0N Produit: quantité\n",
    " \n",
    "    Client: réf. client, nom, prénom, adresse\n",
    "    DF, 0N Client, 11 Commande\n",
    "  Commande: num. commande, date, montant"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo \n",
    "% Boîtes homonymes\n",
    "% Le dernier chiffre ou tiret bas d'un nom d'entité ou d'association n'est pas\n",
    "% affiché. C'est bon à savoir, p. ex. pour monnayer une entité « fictive » trop\n",
    "% pattue : ici, on évite les croisements en créant deux entités Date.\n",
    "\n",
    "Association 9_, XX Entité 3_, XX Date1\n",
    "Date1: date\n",
    "Association 10_, XX Entité 1_, XX Date1\n",
    "Association 11_, XX Entité 1_, XX Entité 2_, XX Date2\n",
    ":\n",
    "\n",
    "Entité 3_:\n",
    "Association 8_, XX Entité 3_, XX Entité 1_, XX Date1\n",
    "Entité 1_:\n",
    "Entité 2_:\n",
    "Date2: date\n",
    "\n",
    "Association 5_, XX Entité 4_, XX Entité 3_\n",
    "Entité 4_:\n",
    "Association 6_, XX Entité 4_, XX Entité 1_\n",
    "Association 7_, XX Entité 1_, XX Entité 2_, XX Date2\n",
    ":"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Vue en extension\n",
    "% La même fonctionnalité permet de créer une vue en extension (à droite du MCD).\n",
    "% Notez qu'il n'y a pas besoin de suffixe pour créer plusieurs associations DF.\n",
    "% Notez également les lignes réduites à des deux-points : ceux-ci sont traités\n",
    "% comme des boîtes « fantômes », et jouent le rôle d'espaces horizontaux.\n",
    "\n",
    "ŒUVRE1: cote, titre, date de publication\n",
    ":::\n",
    "ŒUVRE2: 612.NAT.34, J'apprends à lire à mes souris blanches, mai 1975\n",
    ":\n",
    "  \n",
    "DF, 1N ŒUVRE1, _11 EXEMPLAIRE1\n",
    "::\n",
    "DF, XX ŒUVRE2, XX EXEMPLAIRE2\n",
    "DF, XX ŒUVRE2, XX EXEMPLAIRE3\n",
    "DF, XX ŒUVRE2, XX EXEMPLAIRE4\n",
    "\n",
    "EXEMPLAIRE1: numéro d'exemplaire, état, date d'achat\n",
    "::\n",
    "EXEMPLAIRE2: 1, bon état, 12/6/1975\n",
    "EXEMPLAIRE3: 2, bon état, 1/8/1977\n",
    "EXEMPLAIRE4: 3, reliure rongée, 3/4/2005"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "%%mocodo -t explode arrange sql --seed=1 --select mcd sql\n",
    "% Décomposition des associations ternaires (1)\n",
    "% Cochez l'option « Décomposition d'associations » et double-cliquez le bouton\n",
    "% qui vient d'apparaître : l'association Fournir est remplacée par une entité\n",
    "% de même nom pourvue d'un identifiant générique et assortie de trois DF.\n",
    "\n",
    "AYANT-DROIT: nom ayant-droit, lien\n",
    "DIRIGER, 0N [responsable] EMPLOYÉ, 01 PROJET\n",
    "REQUÉRIR, 1N PROJET, 0N PIÈCE: qté requise\n",
    "PIÈCE: réf. pièce, libellé pièce\n",
    "COMPOSER, 0N [composée] PIÈCE, 0N [composante] PIÈCE: quantité\n",
    "\n",
    "DF, _11 AYANT-DROIT, 0N EMPLOYÉ\n",
    "EMPLOYÉ: matricule, nom employé\n",
    "PROJET: num. projet, nom projet\n",
    "FOURNIR, 1N PROJET, 1N PIÈCE, 1N SOCIÉTÉ: qté fournie\n",
    "\n",
    "DÉPARTEMENT: num. département, nom département\n",
    "EMPLOYER, 11 EMPLOYÉ, 1N DÉPARTEMENT\n",
    "TRAVAILLER, 0N EMPLOYÉ, 1N PROJET\n",
    "SOCIÉTÉ: num. société, raison sociale\n",
    "CONTRÔLER, 0N< [mère] SOCIÉTÉ, 01 [filiale] SOCIÉTÉ"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "%%mocodo -t explode:weak arrange sql --seed=1 --select mcd sql\n",
    "% Décomposition des associations ternaires (2)\n",
    "% Cochez maintenant l'option « Entité faible » : l'entité Fournir devient une\n",
    "% entité faible sans identifiant. Vous pouvez vérifier que les schémas sont\n",
    "% conceptuellement équivalents, et produisent les mêmes sorties relationnelles\n",
    "% (MLD) et physiques (MPD).\n",
    "\n",
    "AYANT-DROIT: nom ayant-droit, lien\n",
    "DIRIGER, 0N [responsable] EMPLOYÉ, 01 PROJET\n",
    "REQUÉRIR, 1N PROJET, 0N PIÈCE: qté requise\n",
    "PIÈCE: réf. pièce, libellé pièce\n",
    "COMPOSER, 0N [composée] PIÈCE, 0N [composante] PIÈCE: quantité\n",
    "\n",
    "DF, _11 AYANT-DROIT, 0N EMPLOYÉ\n",
    "EMPLOYÉ: matricule, nom employé\n",
    "PROJET: num. projet, nom projet\n",
    "FOURNIR, 1N PROJET, 1N PIÈCE, 1N SOCIÉTÉ: qté fournie\n",
    "\n",
    "DÉPARTEMENT: num. département, nom département\n",
    "EMPLOYER, 11 EMPLOYÉ, 1N DÉPARTEMENT\n",
    "TRAVAILLER, 0N EMPLOYÉ, 1N PROJET\n",
    "SOCIÉTÉ: num. société, raison sociale\n",
    "CONTRÔLER, 0N< [mère] SOCIÉTÉ, 01 [filiale] SOCIÉTÉ"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%mocodo\n",
    "% Pour aller plus loin...\n",
    "% Chacune des opérations que Mocodo online présente sous la forme de bouton ou\n",
    "% de case à cocher consiste en un simple appel à la commande « mocodo » avec\n",
    "% une séquence fixe d'options. En installant Mocodo, vous pourrez composer ces\n",
    "% séquences librement, ce qui vous ouvrira d'autres perspectives : création de\n",
    "% jeux de tests, génération d'examens avec un sujet distinct par étudiant,\n",
    "% automatisation des corrections, etc. Pour l'heure, l'étape suivante semble\n",
    "% être la lecture de la documentation (lien en bas de page), qui vous donnera\n",
    "% un éventail complet des possibilités, et peut-être d'autres idées !\n",
    "\n",
    "À suivre...: ou pas!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "init_cell": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0. Tutoriel interactif (1/2)\n",
      "1. Entité\n",
      "2. Identifiant et attributs d'entité\n",
      "3. Identifiant composite\n",
      "4. Association\n",
      "5. Cardinalités\n",
      "6. Attribut d'association\n",
      "7. Association de dépendance fonctionnelle\n",
      "8. Association réflexive\n",
      "9. Schéma relationnel\n",
      "10. Rôles\n",
      "11. Diagramme relationnel (1)\n",
      "12. Diagramme relationnel (2)\n",
      "13. Inférence de types\n",
      "14. Génération du DDL\n",
      "15. Schéma sur plusieurs rangées\n",
      "16. Réarrangement automatique\n",
      "17. Réarrangement automatique avec contraintes\n",
      "18. Entraînement au passage au relationnel\n",
      "19. Pour aller plus loin...\n",
      "20. Tutoriel interactif (2/2)\n",
      "21. Entité faible (ou identification relative)\n",
      "22. Entité faible sans identifiant\n",
      "23. Identifiants candidats\n",
      "24. Héritage (ou spécialisation)\n",
      "25. Agrégation (ou pseudo-entité)\n",
      "26. Agrégation et contraintes d'unicité\n",
      "27. Agrégation multiple\n",
      "28. Contrainte d'intégrité fonctionnelle (CIF)\n",
      "29. Autres contraintes sur associations\n",
      "30. Explication interactive d'une contrainte\n",
      "31. Explication interactive des cardinalités\n",
      "32. Flèche sur une patte\n",
      "33. Dévoilement progressif du schéma\n",
      "34. Boîtes homonymes\n",
      "35. Vue en extension\n",
      "36. Décomposition des associations ternaires (1)\n",
      "37. Décomposition des associations ternaires (2)\n",
      "38. Pour aller plus loin...\n",
      "Updated 39 files in tutorial_lib folder.\n",
      "Updated mocodo.js.\n"
     ]
    }
   ],
   "source": [
    "from pathlib import Path\n",
    "import os\n",
    "import re\n",
    "import json\n",
    "\n",
    "def boxed_text(lines):\n",
    "    width = len(max(lines, key=len))\n",
    "    lines[0] = \" \" * max(0, (width - len(lines[0])) // 2) + lines[0].upper()\n",
    "    lines[0:0] = [\"\"]\n",
    "    lines[2:2] = [\"\"]\n",
    "    lines.append(\"\")\n",
    "    result = []\n",
    "    result.append(\"%\" * (width + 6))\n",
    "    for line in lines:\n",
    "        spaces = \" \" * (width - len(line))\n",
    "        result.append(\"%  \" + line + spaces + \"  %\")\n",
    "    result.append(\"%\" * (width + 6))\n",
    "    result.append(\"\")\n",
    "    return \"\\n\".join(result)\n",
    "\n",
    "\n",
    "os.system(\"rm tutorial_lib/*.mcd\")\n",
    "path = Path(\"tutorial.ipynb\")\n",
    "doc = json.loads(path.read_text())\n",
    "cells = []\n",
    "i = 0\n",
    "titles = []\n",
    "for cell in doc[\"cells\"]:\n",
    "    if cell[\"cell_type\"] == \"code\":\n",
    "        source = cell[\"source\"]\n",
    "        if source and source[0].startswith(\"%%mocodo\"):\n",
    "            title = source[1][1:].strip()\n",
    "            print(f\"{i}. {title}\")\n",
    "            titles.append(f'\"{title}\"')\n",
    "            lines = []\n",
    "            for (j, line) in enumerate(source[1:]):\n",
    "                if not line.startswith(\"%\"):\n",
    "                    text = boxed_text(lines) + \"\".join(source[j+1:])\n",
    "                    break\n",
    "                lines.append(line[2:-1])\n",
    "            Path(f\"tutorial_lib/tuto-{i:04d}.mcd\").write_text(text)\n",
    "            Path(f\"../web/box/tuto-{i:04d}.mcd\").write_text(text)\n",
    "            i += 1\n",
    "    elif cell[\"source\"] and cell[\"source\"][0].startswith(\"# Advanced\"):\n",
    "        basic_tutorial_limit = str(i)\n",
    "print(f\"Updated {i} files in tutorial_lib folder.\")\n",
    "js_path = Path(\"../web/mocodo.js\")\n",
    "code = js_path.read_text()\n",
    "(code, n) = re.subn(r'(?<=var tutorialOptions = )\\[.+?\\]', f\"[{', '.join(titles)}]\", code)\n",
    "if n == 0:\n",
    "    raise RuntimeError(\"Unable to update tutorialOptions!\")\n",
    "(code, n) = re.subn(r'(?<=var basicTutorialLimit = )\\d+', basic_tutorial_limit, code)\n",
    "if n == 0:\n",
    "    raise RuntimeError(\"Unable to update basicTutorialLimit!\")\n",
    "js_path.write_text(code)\n",
    "print(\"Updated mocodo.js.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "celltoolbar": "Initialization Cell",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": "block",
   "toc_window_display": true
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
