Archéo Lex/Base de données

De Wiki Seb35
Aller à la navigation Aller à la recherche
La version imprimable n’est plus prise en charge et peut comporter des erreurs de génération. Veuillez mettre à jour les signets de votre navigateur et utiliser à la place la fonction d’impression par défaut de celui-ci.

Archéo Lex importe les codes de la base LEGI dans un base de données SQLite. Cette base de données SQLite permet d’avoir de pouvoir requêter facilement afin de créer les textes de loi dans les formats demandés, ainsi que de pouvoir recréer des textes déjà compilés (reproductible data), sous réserve d’avoir encore les textes des articles dans leur version d’alors puisqu’ils ne sont pas enregistrés pour des questions de place.

Structure

La base de données comprend deux types d’informations :

  1. la base LEGI en tant que donnée brute importée : tables texte, section, article avec diverses métadonnées ;
  2. les versions consolidées des codes tels que calculés par le programme, puisque cette information n’est pas donnée explicitement dans la base LEGI (il faut rassembler toutes les dates de consolidation mentionnées pour obtenir l’ensemble des versions consolidées) : tables version_texte, version_section.

De plus, pour permettre de modifier de façon incrémentale les dépôts Git en sortie au fur et à mesure de la mise à jour de la base LEGI, chaque enregistrement dans la base de données est également étiqueté avec la date de la dernière mise à jour du code dans la base LEGI [il faut ajouter ces tags dans la BDD]. Ainsi, lorsqu’une section est mise à jour dans la base LEGI, un enregistrement dans version_section est créé ainsi qu’un nouveau lien entre article et version_section [il faut ajouter une table version_section_article ou version_article]. De même, lorsqu’un article est mis à jour dans la base LEGI, un enregistrement dans article [ou version_article] ainsi qu’un lien [même remarque que précédemment].

Schéma SQL 1.0

BDD Archéo Lex 1.0.svg
texte
CREATE TABLE "texte" (
  "cid" VARCHAR(20) NOT NULL PRIMARY KEY,
  "nor" VARCHAR(20) NOT NULL,
  "nature" VARCHAR(20) NOT NULL,
  "date_texte" DATE,
  "date_publi" DATE
);
version_texte
CREATE TABLE "version_texte" (
  "id" INTEGER NOT NULL PRIMARY KEY,
  "texte_id" VARCHAR(20) NOT NULL,
  "titre" VARCHAR(200) NOT NULL,
  "titre_long" VARCHAR(200) NOT NULL,
  "etat_juridique" VARCHAR(25) NOT NULL,
  "debut" DATE,
  "fin" DATE,
  "base_id" INTEGER,
  FOREIGN KEY ("texte_id") REFERENCES "texte" ("cid"),
  FOREIGN KEY ("base_id") REFERENCES "version_texte" ("id")
);
CREATE INDEX "version_texte_base_id" ON "version_texte" ("base_id");
CREATE INDEX "version_texte_texte_id" ON "version_texte" ("texte_id");
section
CREATE TABLE "section" (
  "cid" VARCHAR(20) NOT NULL PRIMARY KEY,
  "cid_parent_id" VARCHAR(20),
  "niveau" INTEGER NOT NULL,
  "texte_id" VARCHAR(20) NOT NULL,
  FOREIGN KEY ("cid_parent_id") REFERENCES "section" ("cid"),
  FOREIGN KEY ("texte_id") REFERENCES "texte" ("cid")
);
CREATE INDEX "section_cid_parent_id" ON "section" ("cid_parent_id");
CREATE INDEX "section_texte_id" ON "section" ("texte_id");
version_section
CREATE TABLE "version_section" (
  "id" VARCHAR(20) NOT NULL PRIMARY KEY,
  "cid_id" VARCHAR(20) NOT NULL,
  "id_parent_id" VARCHAR(20),
  "nom" VARCHAR(200) NOT NULL,
  "etat_juridique" VARCHAR(25) NOT NULL,
  "niveau" INTEGER NOT NULL,
  "numero" INTEGER NOT NULL,
  "debut" DATE NOT NULL,
  "fin" DATE, "texte_id" VARCHAR(20) NOT NULL,
  "version_texte_id" INTEGER,
  FOREIGN KEY ("cid_id") REFERENCES "section" ("cid"),
  FOREIGN KEY ("id_parent_id") REFERENCES "version_section" ("id"),
  FOREIGN KEY ("texte_id") REFERENCES "texte" ("cid"),
  FOREIGN KEY ("version_texte_id") REFERENCES "version_texte" ("id")
);
CREATE INDEX "version_section_cid_id" ON "version_section" ("cid_id");
CREATE INDEX "version_section_id_parent_id" ON "version_section" ("id_parent_id");
CREATE INDEX "version_section_texte_id" ON "version_section" ("texte_id");
CREATE INDEX "version_section_version_texte_id" ON "version_section" ("version_texte_id");
article
CREATE TABLE "article" (
  "id" VARCHAR(20) NOT NULL PRIMARY KEY,
  "nom" VARCHAR(200) NOT NULL,
  "etat_juridique" VARCHAR(25) NOT NULL,
  "num" VARCHAR(200) NOT NULL,
  "debut" DATE NOT NULL,
  "fin" DATE,
  "texte_id" VARCHAR(20) NOT NULL,
  "version_section_id" VARCHAR(20) NOT NULL,
  "version_texte_id" INTEGER NOT NULL,
  FOREIGN KEY ("texte_id") REFERENCES "texte" ("cid"),
  FOREIGN KEY ("version_section_id") REFERENCES "version_section" ("id"),
  FOREIGN KEY ("version_texte_id") REFERENCES "version_texte" ("id")
);
CREATE INDEX "article_texte_id" ON "article" ("texte_id");
CREATE INDEX "article_version_section_id" ON "article" ("version_section_id");
CREATE INDEX "article_version_texte_id" ON "article" ("version_texte_id");

Schéma SQL 2.0

Graphique

BDD Archéo Lex 2.1.svg

Aperçu général

Cette version apporte principalement la prise en compte des livraisons, i.e. les mises à jour successives de la base LEGI. La version 1.0 de la base de données ne pouvait pas distinguer les livraisons et il aurait alors été nécessaire de modifier directement les divers enregistrements, ce qui aurait pu corrompu la base de donnée si le programme était arrêté au cours de la mise à jour. Cette version de la base de données voit principalement l’ajout de tables pour ces livraisons, ainsi que diverses modifications mineures améliorant la cohérence.

Il y a donc deux axes d’évolution des versions manipulés par cette base de données :

  • l’axe temporel (naturel) : les différentes évolutions du texte au cours du temps, par exemple les modifications d’un texte ou les différentes versions consolidées d’un code ; cet axe existait déjà dans la version 1.0 de la base de données et s’appuie entièrement sur les dates de vigueur
  • l’axe des livraisons : au fur et à mesure des livraisons (tables livraison) : introduction de nouvelles versions de textes à la suite de la version la plus récente (évolution normale), réécriture de versions existantes (en cas d’erreur sur un champ, faute de frappe, etc.), ajout ou suppression de versions intermédiaires (en cas d’erreur sur les dates de vigueur)

Les deux axes d’évolution ne sont pas traités de façon identique mais s’inspirent des branches Git. Cela s’illustre par l’exemple suivant :

Axe temporel → T1   T2   T3   T4   T5   T6   T7   T8   ↓ Axe des livraisons
               v1.0 v2.0 v3.0 v4.0 v5.0                 -- livraison 0 : import initial
                            \          `v6.1            -- livraison 1 : ajout d’une nouvelle version normale
                             `v4.2 v5.2 v6.2      v7.2  -- livraison 2 : réécriture à partir de la version 4
                                            `v7.3 v8.3  -- livraison 3 : introduction d’une version intermédiaire

Du fait que les livraisons peuvent ajouter des versions intermédiaires sur l’axe temporel (cf livraison 2 dans l’exemple), il peut y avoir un décalage entre les numéros d’ordre des versions et leurs dates (cf dans l’exemple v7.2 et v8.3 qui n’ont pas le même numéro d’ordre (7 et 8) mais la même date (T8). En général, lorsqu’on comparera sur l’axe des livraisons, on préférera donc les comparaisons de versions à même date plutôt qu’à même numéro d’ordre.

Les réécritures, introductions ou suppressions de versions intermédiaires peuvent être soit :

  • normales : dans le cas de la manipulation des versions à venir (postérieures à la date de la livraison), lorsqu’une loi introduit une nouvelle version consolidée intermédiaire ; ou
  • éditoriales : dans le cas de la manipulation des versions passées (antérieures à la date de la livraison), lorsqu’une erreur est corrigée ou que les dates de vigueur sont modifiées

Cette version de la base de données ne distingue pas ces deux types de réécriture, mais cela sera probablement ajouté dans la version 3.0 de la base de données.

Notes de modification

Modifications de la base de données par rapport à la version 1.0 :

  • Ajouts, suppressions et modifications de tables :
    • Ajout de la table livraison contenant les dates des livraisons, leur type ("fondation" (=dump complet) ou "miseajour" (=dump incrémental)) et un lien vers la livraison fondation le cas échéant
    • Ajout de la table livraison_texte mettant en correspondance les textes, livraisons et versions de texte
    • Ajout des tables liste_sections et liste_articles listant les sections et articles inclus dans une version de texte ; ce lien était auparavant fait directement dans version_section et article
    • Retrait de la table section, inutilisée et inutile
    • Renommage de la table article en version_article pour cohérence, puisque son rôle est identique à version_section
  • Transferts de colonnes entre tables :
    • De texte à version_texte : nature, date_texte, date_publi : pour permettre la modification de ces champs d’une livraison à l’autre
  • Suppressions de colonnes :
    • version_section/cid_id : car suppression de la table section
    • version_section/version_texte_id et version_article/version_texte_id : il faut désormais passer par liste_sections et liste_articles
  • Renommage de colonnes :
    • debut et fin renommés en vigueur_debut et vigueur_fin : plus explicite étant donné que de multiples dates sont indiquées et manipulées
    • dans version_article, num en numero : plus explicite et cohérence avec version_section
  • Ajout de colonnes :
    • version_texte/date_modif : date de dernière modification indiquée dans la base LEGI
  • Modifications de colonnes :
    • dans version_texte, la colonne base_id (référent à la première version d’un texte sur l’axe temporel) est modifiée en version_prec_id (référent à la version précédente sur l’axe temporel)

Opérations classiques

Les opérations classiques et prévues sur la base de données sont :

  • Création ex nihilo de la base de données :
    1. Insertion d’une ligne dans la table livraison
    2. Insertion d’une ou plusieurs lignes dans la table texte
    3. Calcul des versions de texte et insertion de celles-ci dans les tables version_{texte,section,article}
    4. Insertion des lignes adéquates dans les tables livraison_texte et liste_{sections,articles}
  • Mise à jour après une mise à jour incrémentale de la base LEGI : similaire au point précédent en n’ajoutant que les versions de textes, sections et articles nécessaires et en faisant les liens adéquats dans les tables livraison
  • Mise à jour après un dump complet de la base LEGI : similaire aux premier et deuxième points en n’ajoutant que ce qui n’existe pas
  • Requêter toutes les versions temporelles correspondant à une livraison :
    1. Requête sur la table livraison_texte pour obtenir toutes les versions temporelles d’un texte
    2. Requête sur la table version_texte pour obtenir les métadonnées sur les versions temporelles
    3. Requête sur les tables liste_{sections,articles} pour obtenir les sections et articles
    4. Requête sur les tables version_{sections,articles} pour obtenir les métadonnées et données sur les sections et articles
  • Requêter les versions temporelles à une date donnée pour toutes les livraisons :
    1. Requête sur la table version_texte en fixant le champ vigueur_debut (on peut aussi fixer vigueur_fin si on préfère ou même un intervalle temporel puisque la date est directement gérée par SQL)
    2. Requête sur la table livraison_texte pour obtenir toutes les livraisons correspondantes à ces versions, si on veut
    3. Requête sur les tables liste_{sections,articles} pour obtenir les sections et articles
    4. Requête sur les tables version_{sections,articles} pour obtenir les métadonnées et données sur les sections et articles

Noter que pour la modification, l’ajout ou la suppression d’une section, il faut créer l’enregistrement dans version_section, puis créer des enregistrements de version_section pour toutes les sections enfants ainsi que les articles enfants, et ceci même si ceux-ci n’ont pas été changés. Cela est requis à cause du lien id_parent_id qui doit correspondre au nouveau élément. Je ne vois pas vraiment comment éviter cela, à part en créant une liste de sections alias, c’est-à-dire que si une section enfant a un id_parent_id qui n’existe pas dans la liste_sections de cette version de texte, on cherchera le bon id de section dans une table alias_section (dans ce cas, ça serait juste pour les sections, pas pour les articles).

Design et évolutions futures