diff --git a/app/pages/docs/merise/dictionnaire-de-donnees/DictionnaryTable.tsx b/app/pages/docs/merise/dictionnaire-de-donnees/DictionnaryTable.tsx index 76041ce..57addd5 100644 --- a/app/pages/docs/merise/dictionnaire-de-donnees/DictionnaryTable.tsx +++ b/app/pages/docs/merise/dictionnaire-de-donnees/DictionnaryTable.tsx @@ -1,87 +1,337 @@ -export default function DictionnaryTable() { +import { For } from "solid-js"; + +type DataTable = { + tableName: string; + hiddenInBasic?: boolean; + documentName: string; + columns: DataColumn[]; + primaryKeys?: string[]; + foreignKeys?: string[]; +}; + +type DataColumnType = + | "Alphanumérique" + | "Alphabétique" + | "Numérique" + | "Date" + | "Logique"; + +type DataColumn = { + name: string; + logical: string; + dbmsType: string; + dbmsLength?: number; + length?: string | number; + type: DataColumnType; + hiddenInTechnical?: boolean; + hiddenInBasic?: boolean; + dbmsConstraints: string[]; + constraints?: string[]; +}; + +const data: DataTable[] = [ + { + tableName: "musician", + documentName: "Musicien", + primaryKeys: ["id_musician"], + columns: [ + { + name: "code musicien", + logical: "id_musician", + dbmsType: "INTEGER", + type: "Numérique", + hiddenInBasic: true, + dbmsConstraints: ["AUTO_INCREMENT", "NOT_NULL", "UNIQUE"], + }, + { + name: "Nom", + logical: "lastname", + dbmsType: "VARCHAR", + type: "Numérique", + length: 30, + dbmsLength: 30, + dbmsConstraints: ["NOT_NULL"], + constraints: ["Obligatoire"], + }, + { + name: "Prénom", + logical: "firstname", + dbmsType: "VARCHAR", + type: "Numérique", + length: 30, + dbmsLength: 30, + dbmsConstraints: ["NOT_NULL"], + constraints: ["Obligatoire"], + }, + { + name: "Instruments", + logical: "instruments", + dbmsType: "VARCHAR[]", + type: "Alphabétique", + length: 30, + dbmsLength: 30, + dbmsConstraints: ["NOT_NULL"], + constraints: ["Obligatoire"], + }, + { + name: "Adresse e-mail", + logical: "email", + dbmsType: "VARCHAR[]", + type: "Alphanumérique", + length: 50, + dbmsLength: 50, + dbmsConstraints: ["NOT_NULL", "UNIQUE"], + constraints: ["Obligatoire", "Unique"], + }, + { + name: "Mot de passe", + logical: "password", + dbmsType: "VARCHAR", + type: "Alphanumérique", + length: "> 12", + dbmsLength: 32, + dbmsConstraints: ["NOT_NULL"], + constraints: ["Obligatoire"], + }, + ], + }, + { + tableName: "musician_participates_event", + documentName: "", + hiddenInBasic: true, + primaryKeys: ["id_musician", "event_id"], + foreignKeys: ["id_musician", "event_id"], + columns: [ + { + name: "", + logical: "event_id", + dbmsType: "INTEGER", + type: "Numérique", + dbmsConstraints: ["NOT_NULL"], + }, + { + name: "Lieu", + logical: "location", + dbmsType: "VARCHAR", + type: "Alphabétique", + dbmsLength: 30, + dbmsConstraints: ["NOT_NULL"], + }, + { + name: "Date et heure", + logical: "datetime", + dbmsType: "TIMESTAMPZ", + type: "Alphabétique", + dbmsLength: 30, + dbmsConstraints: ["NOT_NULL"], + }, + ], + }, + { + tableName: "event", + documentName: "", + hiddenInBasic: true, + primaryKeys: ["id_event"], + columns: [ + { + name: "", + logical: "id_event", + dbmsType: "INTEGER", + type: "Numérique", + dbmsConstraints: ["AUTO_INCREMENT", "NOT_NULL", "UNIQUE"], + }, + { + name: "Lieu", + logical: "location", + dbmsType: "VARCHAR", + type: "Alphabétique", + dbmsLength: 30, + dbmsConstraints: ["NOT_NULL"], + }, + { + name: "Date et heure", + logical: "datetime", + dbmsType: "TIMESTAMPZ", + type: "Alphabétique", + dbmsLength: 30, + dbmsConstraints: ["NOT_NULL"], + }, + ], + }, + { + tableName: "concert", + documentName: "Concert", + primaryKeys: ["id_concert"], + foreignKeys: ["event_id"], + columns: [ + { + name: "code concert", + logical: "id_concert", + dbmsType: "INTEGER", + type: "Numérique", + hiddenInBasic: true, + dbmsConstraints: ["AUTO_INCREMENT", "NOT_NULL", "UNIQUE"], + }, + { + name: "Date et heure", + logical: "datetime", + dbmsType: "TIMESTAMPZ", + type: "Date", + hiddenInTechnical: true, + dbmsConstraints: ["NOT_NULL"], + constraints: ["Obligatoire"], + }, + { + name: "Lieu", + logical: "location", + dbmsType: "VARCHAR", + type: "Alphabétique", + hiddenInTechnical: true, + dbmsConstraints: ["NOT_NULL"], + constraints: ["Obligatoire"], + }, + { + name: "Tarif", + logical: "price", + dbmsType: "CURRENCY", + type: "Numérique", + dbmsConstraints: ["NOT_NULL"], + constraints: ["Obligatoire"], + }, + { + name: "", + logical: "event_id", + dbmsType: "INTEGER", + type: "Numérique", + hiddenInBasic: true, + dbmsConstraints: ["NOT_NULL"], + }, + ], + }, + { + tableName: "rehearsal", + documentName: "Répétition", + primaryKeys: ["id_rehearsal"], + foreignKeys: ["event_id"], + columns: [ + { + name: "code répétition", + logical: "id_rehearsal", + dbmsType: "INTEGER", + type: "Numérique", + hiddenInBasic: true, + dbmsConstraints: ["AUTO_INCREMENT", "NOT_NULL", "UNIQUE"], + }, + { + name: "Date et heure", + logical: "datetime", + dbmsType: "TIMESTAMPZ", + type: "Date", + hiddenInTechnical: true, + dbmsConstraints: ["NOT_NULL"], + constraints: ["Obligatoire"], + }, + { + name: "Lieu", + logical: "location", + dbmsType: "VARCHAR", + type: "Alphabétique", + hiddenInTechnical: true, + dbmsConstraints: ["NOT_NULL"], + constraints: ["Obligatoire"], + }, + { + name: "", + logical: "event_id", + dbmsType: "INTEGER", + type: "Numérique", + hiddenInBasic: true, + dbmsConstraints: ["NOT_NULL"], + }, + ], + }, +]; + +type DictionnaryTableProps = { + isTechnical?: boolean; +}; + +export default function DictionnaryTable(props: DictionnaryTableProps) { return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Nom de la donnéeFormatLongueurContraintesDocument
NomAlphabétique30ObligatoireMusicien
PrénomAlphabétique30ObligatoireMusicien
InstrumentsAlphabétique30ObligatoireMusicien
Adresse e-mailAlphanumérique50Obligatoire, uniqueMusicien
Mot de passeAlphanumérique> 12ObligatoireMusicien
Date et heure de concertDate-ObligatoireConcert
Lieu de concertAlphabétique50ObligatoireConcert
TarifNumérique--Concert
Date et heure de répétitionDate-ObligatoireRépétition
Lieu de répétitionAlphabétique50ObligatoireRépétition
+ props.isTechnical || !table.hiddenInBasic)} + > + {(table) => ( + + + + + + + + + + + props.isTechnical || !column.hiddenInBasic, + )} + > + {(column) => ( + + + + + + + )} + + + + {props.isTechnical && ( + <> + {table.primaryKeys && table.primaryKeys.length > 0 && ( + + + + + )} + {table.foreignKeys && table.foreignKeys.length > 0 && ( + + + + + )} + + )} + + + + +
+ {props.isTechnical ? "Colonne" : "Nom de la donnée"} + {props.isTechnical ? "Type" : "Format"}LongueurContraintes
{props.isTechnical ? column.logical : column.name}{props.isTechnical ? column.dbmsType : column.type} + {props.isTechnical + ? column.dbmsLength || "-" + : column.length || "-"} + + {props.isTechnical + ? column.dbmsConstraints?.join(", ") || "-" + : column.constraints?.join(", ") || "-"} +
+ Clé primaire + + ({table.primaryKeys.join(", ")}) +
+ Clé(s) étrangère(s) + + {table.foreignKeys.join(", ")} +
+ {props.isTechnical + ? `Table : ${table.tableName}` + : `Document : ${table.documentName}`} +
+ )} +
); } diff --git a/app/pages/docs/merise/mld/+Page.mdx b/app/pages/docs/merise/mld/+Page.mdx index d9d6b93..a4a6c36 100644 --- a/app/pages/docs/merise/mld/+Page.mdx +++ b/app/pages/docs/merise/mld/+Page.mdx @@ -12,7 +12,7 @@ Le MLD est la suite normale et directe du MCD dans le processus Merise. Son but On parlera plus tard du MRD, mais globalement : c'est la même chose que le MLD ! -## Qu'est-ce que le MLD ? +## 🤔 Qu'est-ce que le MLD ? Le **MLD** est un schéma qui va nous permettre de représenter les données que l'on a récupérées dans le MCD, mais en ajoutant des détails techniques. @@ -20,7 +20,7 @@ Il va nous permettre de représenter les différentes données que l'on a, regro Contrairement au MCD, le MLD n'est pas destiné à être compris par le client. -## Exemple de MLD +## 🔍 Exemple de MLD Reprenons le premier exemple de MCD, dans l'article précédent : diff --git a/app/pages/docs/merise/mpd/+Page.mdx b/app/pages/docs/merise/mpd/+Page.mdx index a8e6ce7..13565f0 100644 --- a/app/pages/docs/merise/mpd/+Page.mdx +++ b/app/pages/docs/merise/mpd/+Page.mdx @@ -4,4 +4,68 @@ description: Apprenez à créer le MPD dans Merise, la dernière étape pour con tags: [Backend, Merise, BDD, MCD, MLD, MPD, SQL] --- -En cours de rédaction... +import DictionnaryTable from "../mcd/DictionnaryTable"; +import tabs from "./tabs"; + +Prêt·e pour la dernière étape de la méthodologie Merise ? 🎉 +Alors sans plus tarder, accueillons comme il se doit le **MPD** _(Modèle Physique de Données)_ ! + +## 🤔 Qu'est-ce que le MPD ? + +Le **MPD** est la dernière étape de la méthodologie Merise. +Il reprend les éléments du MLD en ajoutant les derniers **détails techniques** nécessaires +pour implémenter le modèle dans un **SGBD** _(Système de Gestion de Base de Données)_. + +**Ces détails techniques sont** : + +- Le type de données de chaque colonne _(ex: `VARCHAR`, `INT`, `DATE`, etc.)_ +- La taille de chaque colonne _(ex: `VARCHAR(255)`, `INT(11)`, etc.)_ +- Les contraintes d'intégrité _(ex: `NOT NULL`, `UNIQUE`, etc.)_ +- Les clés étrangères _(ex: `FOREIGN KEY`, `REFERENCES`, etc.)_ + +## 🔍 Exemple de MPD + +À partir du **MLD** _(et **MRD** si existant)_ et du **dictionnaire de données**, on va pouvoir créer le MPD. + +Faisons la transition de l'exemple de MLD basique que l'on a vu précédemment : + +![Exemple de MLD](/images/merise/mld-basic.webp) + +En prenant en considération que l'application va être développée avec **PostgreSQL**, on prendra soin d'utiliser +les **types de données** et les **contraintes d'intégrité** qui lui sont propres. + +Voici à quoi il ressemble : + +![Exemple de MPD](/images/merise/mpd-basic.webp) + +Avec ce schéma, il est facile d'identifier les différentes tables, leurs colonnes, les types de données, +les contraintes d'intégrité, ainsi que les clés primaires et étrangères qui relient les tables entre elles. + +Une fois le MPD créé, il est possible de le traduire en **SQL** pour créer les tables dans le SGBD. +Voici un exemple de code SQL pour créer les tables correspondantes au MPD ci-dessus : + + + +## 📊 Dictionnaire de données + +Tu te souviens du **dictionnaire de données** que l'on a créé lors du brief avec le client ? Juste avant de passer au MCD ? +Il est maintenant possible de le mettre jour avec les informations du SGBD utilisé ! + +Bien entendu ce n'est pas obligatoire, mais c'est une bonne source d'informations pour +les développeurs et les administrateurs de la base de données 😉 + +Pour rappel, voici le dictionnaire de données **non technique** que nous avions fait : + + + +En ajoutant les informations techniques, il devient : + + + +## 📜 Préparation du LDD + +Le **MPD** est la dernière étape avant de passer à la phase de **LDD** _(Langage de Définition de Données)_. +Il est donc important de bien le préparer pour éviter les erreurs lors de la création des tables. + +Le **LDD** correspond tout simplement à la création des tables dans le SGBD, par l'utilisation des commandes SQL +comme `CREATE TABLE`, `ALTER TABLE`, `DROP TABLE`, etc. \ No newline at end of file diff --git a/app/pages/docs/merise/mpd/tabs.tsx b/app/pages/docs/merise/mpd/tabs.tsx new file mode 100644 index 0000000..9e16921 --- /dev/null +++ b/app/pages/docs/merise/mpd/tabs.tsx @@ -0,0 +1,65 @@ +import { Snippet } from "@/components/Snippet"; + +const sqlExampleSnippets = [ + { + name: "Exemple de LDD", + codeLanguage: "sql", + withLineNumbers: true, + code: `CREATE TABLE "table_1" ( + "id_table_1" INTEGER NOT NULL UNIQUE, + "column_2" VARCHAR(50) NOT NULL, + "column_3" VARCHAR(50) NOT NULL, + "table_3_id" INTEGER NOT NULL, + PRIMARY KEY("id_table_1") +); +CREATE INDEX "table_1_index_0" +ON "table_1" ("id_table_3"); + +CREATE TABLE "table_3" ( + "id_table_3" INTEGER NOT NULL UNIQUE GENERATED BY DEFAULT AS IDENTITY, + "column_2" VARCHAR(50) NOT NULL, + "column_3" VARCHAR(50) NOT NULL, + "table_3_id" INTEGER, + PRIMARY KEY("id_table_3") +); +CREATE INDEX "table_3_index_0" +ON "table_3" ("id_table_3"); + +CREATE TABLE "table_2" ( + "id_table_2" INTEGER NOT NULL UNIQUE GENERATED BY DEFAULT AS IDENTITY, + "column_2" VARCHAR(50) NOT NULL, + "column_3" VARCHAR(50) NOT NULL, + PRIMARY KEY("id_table_2") +); +CREATE INDEX "table_2_index_0" +ON "table_2" ("id_table_2"); + +CREATE TABLE "table_1_contains_table_2" ( + "table_1_id" INTEGER NOT NULL, + "table_2_id" INTEGER NOT NULL, + PRIMARY KEY("table_1_id", "table_2_id") +); +CREATE UNIQUE INDEX "table_1_contains_table_2_index_0" +ON "table_1_contains_table_2" ("table_1_id", "table_2_id"); + +ALTER TABLE "table_1" +ADD FOREIGN KEY("table_3_id") REFERENCES "table_3"("id_table_3") +ON UPDATE NO ACTION ON DELETE NO ACTION; + +ALTER TABLE "table_3" +ADD FOREIGN KEY("id_table_3") REFERENCES "table_3"("table_3_id") +ON UPDATE NO ACTION ON DELETE NO ACTION; + +ALTER TABLE "table_1" +ADD FOREIGN KEY("id_table_1") REFERENCES "table_1_contains_table_2"("table_1_id") +ON UPDATE NO ACTION ON DELETE NO ACTION; + +ALTER TABLE "table_1_contains_table_2" +ADD FOREIGN KEY("table_2_id") REFERENCES "table_2"("id_table_2") +ON UPDATE NO ACTION ON DELETE NO ACTION;`, + }, +]; + +export default { + sqlExample: () => , +}; diff --git a/app/public/downloads/merise/example.lo1 b/app/public/downloads/merise/example.lo1 index a3bf205..cf3ba85 100644 Binary files a/app/public/downloads/merise/example.lo1 and b/app/public/downloads/merise/example.lo1 differ diff --git a/app/public/downloads/merise/example.loo b/app/public/downloads/merise/example.loo index cf3ba85..01b4ab5 100644 Binary files a/app/public/downloads/merise/example.loo and b/app/public/downloads/merise/example.loo differ diff --git a/app/public/images/merise/mpd-basic.webp b/app/public/images/merise/mpd-basic.webp new file mode 100644 index 0000000..917ae75 Binary files /dev/null and b/app/public/images/merise/mpd-basic.webp differ