tag:linuxfr.org,2005:/users/lovasoa/newsLinuxFr.org : les dépêches de lovasoa2024-03-11T10:53:13+01:00/favicon.pngtag:linuxfr.org,2005:News/419072024-03-06T10:58:04+01:002024-03-06T10:58:04+01:00École Inclusive: une application libre pour la prise en charge des élèves en situation de handicapLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>Directeur adjoint d’un collège en Occitanie, chargé de la SEGPA et de l’accueil des élèves en situation de handicap, je me suis retrouvé dans une situation où le suivi des élèves et de leurs accompagnants devenait difficile, notamment par manque d’outils adaptés.</p>
<p>Loin de me décourager, j’ai créé ma propre application de suivi, <em>École Inclusive</em>, en utilisant le cadriciel libre <a href="https://sql.ophir.dev">SQLPage</a> et la publie aujourd’hui sous licence GPLv3. Ce projet a été possible grâce au support proposé par la documentation en ligne et à de fréquents échanges avec Ophir Lojkine, créateur de SQLPage.</p>
<p>Sans aucune connaissance préalable en programmation, j’ai réalisé toute cette application en <em>SQL</em>. Cela permet un large panel de fonctionnalités pour <em>École Inclusive</em>, qui gère tout le suivi horaire des élèves, des classes et des accompagnants, les emplois du temps, les statistiques, les notifications, l’identification des utilisateurs avec plusieurs niveaux de permission. </p>
<p><img src="//img.linuxfr.org/img/68747470733a2f2f636f6c6c6567652d626f757272696c6c6f6e2e66722f73716c706167652f6c6f676f2e706e67/logo.png" alt="Logo" title="Source : https://college-bourrillon.fr/sqlpage/logo.png"></p>
</div><ul><li>lien nᵒ 1 : <a title="https://github.com/DSMejantel/Ecole_inclusive" hreflang="fr" href="https://linuxfr.org/redirect/113490">Le code source d'École Inclusive sur Github (licence GPLv3)</a></li><li>lien nᵒ 2 : <a title="https://sql.ophir.dev/" hreflang="en" href="https://linuxfr.org/redirect/113491">SQLPage, le framework pour construire des applications en SQL sur lequel s'appuie École Inclusive</a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<a href="#toc-lapplication-%C3%89cole-inclusive">L’application « École inclusive »</a><ul>
<li><a href="#toc-une-application-pour-am%C3%A9liorer-la-prise-en-charge-p%C3%A9dagogique-des-%C3%A9l%C3%A8ves-en-situation-de-handicap">Une application pour améliorer la prise en charge pédagogique des élèves en situation de handicap</a></li>
<li>
<a href="#toc-de-professeur-dhistoire-g%C3%A9o-%C3%A0-cr%C3%A9ateur-dapplications">De professeur d’histoire-géo à créateur d’applications</a><ul>
<li><a href="#toc-un-d%C3%A9but-de-carri%C3%A8re-d%C3%A9j%C3%A0-marqu%C3%A9-par-les-logiciels-libres">Un début de carrière déjà marqué par les logiciels libres</a></li>
<li><a href="#toc-changement-de-cap">Changement de cap</a></li>
<li>
<a href="#toc-rentrer-dans-une-nouvelle-logique">Rentrer dans une nouvelle logique</a><ul>
<li><a href="#toc-quelles-devront-%C3%AAtre-les-grandes-fonctions-de-la-nouvelle-application">Quelles devront être les grandes fonctions de la nouvelle application ?</a></li>
<li><a href="#toc-qui-sy-connectera">Qui s’y connectera ?</a></li>
<li><a href="#toc-comment-%C3%A7a-marche">Comment ça marche ?</a></li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#toc-un-besoin-au-tout-d%C3%A9but--le-suivi-de-laide-humaine-dans-le-cadre-des-pial">Un besoin au tout début : le suivi de l’aide humaine dans le cadre des PIAL</a><ul>
<li>
<a href="#toc-le-suivi">Le suivi</a><ul>
<li><a href="#toc-quelles-donn%C3%A9es-est-il-utile-de-rassembler">Quelles données est-il utile de rassembler ?</a></li>
<li><a href="#toc-pourquoi-enregistrer-ces-donn%C3%A9es">Pourquoi enregistrer ces données ?</a></li>
</ul>
</li>
<li>
<a href="#toc-un-mod%C3%A8le-de-gestion-%C3%A0-perfectionner">Un modèle de gestion à perfectionner…</a><ul>
<li><a href="#toc-comment-se-faisait-le-suivi-avant-la-cr%C3%A9ation-du-nouvel-outil">Comment se faisait le suivi avant la création du nouvel outil ?</a></li>
<li><a href="#toc-quelles-%C3%A9taient-les-limitations">Quelles étaient les limitations ?</a></li>
<li><a href="#toc-pourquoi-cela-nexiste-t-il-pas">Pourquoi cela n’existe-t-il pas ?</a></li>
</ul>
</li>
<li><a href="#toc-sqlpage--cr%C3%A9er-une-application-web-rapidement-sans-exp%C3%A9rience-de-d%C3%A9veloppeur-web">SQLPage : créer une application web rapidement sans expérience de développeur web</a></li>
<li>
<a href="#toc-principes-g%C3%A9n%C3%A9raux-de-sqlpage">Principes généraux de SQLPage</a><ul>
<li><a href="#toc-un-outil-pertinent-pour-cr%C3%A9er-%C3%A9cole-inclusive">Un outil pertinent pour créer « école inclusive »</a></li>
<li><a href="#toc-un-sqlpager-averti-en-vaut-deux">Un SQLpager averti en vaut deux</a></li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#toc-cr%C3%A9ation-de-lapplication">Création de l’application</a><ul>
<li>
<a href="#toc-les-grandes-%C3%A9tapes-du-d%C3%A9veloppement">Les grandes étapes du développement</a><ul>
<li><a href="#toc-principales-fonctionnalit%C3%A9s-et-rythme-de-d%C3%A9veloppement">Principales fonctionnalités et rythme de développement</a></li>
<li><a href="#toc-comment-est-structur%C3%A9e-lapplication">Comment est structurée l’application ?</a></li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#toc-une-interface-utilisateur-simplifi%C3%A9e">Une interface utilisateur simplifiée</a><ul>
<li><a href="#toc-un-code-puissant-et-dynamique">Un code puissant et dynamique</a></li>
<li>
<a href="#toc-les-points-techniques-int%C3%A9ressants">Les points techniques intéressants</a><ul>
<li><a href="#toc-les-fonctionnalit%C3%A9s-de-sqlpage-utilis%C3%A9es">Les fonctionnalités de sqlpage utilisées</a></li>
<li><a href="#toc-publication-en-open-source">Publication en open-source</a></li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#toc-r%C3%A9ception-de-lapplication">Réception de l’application</a><ul>
<li><a href="#toc-par-les-services-de-l%C3%89ducation-nationale">par les services de l’Éducation Nationale</a></li>
<li><a href="#toc-par-les-coll%C3%A8gues">par les collègues</a></li>
</ul>
</li>
<li>
<a href="#toc-le-futur-de-lapplication-%C3%89cole-inclusive">Le futur de l’application École Inclusive</a><ul>
<li><a href="#toc-%C3%A9volutions-techniques-envisag%C3%A9es">évolutions techniques envisagées</a></li>
<li><a href="#toc-vers-un-d%C3%A9ploiement-de-lapplication-dans-un-cadre-l%C3%A9gal">Vers un déploiement de l’application dans un cadre légal…</a></li>
<li><a href="#toc--et-dans-le-respect-des-donn%C3%A9es-priv%C3%A9es">… et dans le respect des données privées</a></li>
<li><a href="#toc-vers-un-%C3%A9largissement-de-lutilisation-%C3%A0-dautres-%C3%A9tablissements">Vers un élargissement de l’utilisation à d’autres établissements ?</a></li>
<li><a href="#toc-exemple-de-code-affichage-du-profil-dun-%C3%A9l%C3%A8ve-dans-lespace-aesh">Exemple de code: affichage du profil d’un élève dans l’espace AESH</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="toc-lapplication-École-inclusive">L’application « École inclusive »</h2>
<h3 id="toc-une-application-pour-améliorer-la-prise-en-charge-pédagogique-des-élèves-en-situation-de-handicap">Une application pour améliorer la prise en charge pédagogique des élèves en situation de handicap</h3>
<p>Tout a commencé pendant un match de la dernière coupe du monde de rugby, un dimanche soir à une heure déjà tardive.</p>
<p>Énième appel à l’arbitre vidéo dans cette compétition. Les données et leur gestion, leur analyse, leur partage, l’aide à la décision. Cette problématique m’a rappelé que, dans le cadre d’une de mes missions, j’étais moi aussi confronté à une vague d’informations pas toujours très claires et toujours plus nombreuses ne rendant pas mes arbitrages très faciles dans la prise en charge des élèves que je suivais.</p>
<p>Profitant de cet arrêt de jeu, je tapotais sur le site de Framasoft à la recherche d’une Webapp libre pour la gestion de mes données. C’est ainsi que je laissais les Springboks s’envoler au score et que je fis la connaissance de SQLpage.</p>
<h3 id="toc-de-professeur-dhistoire-géo-à-créateur-dapplications">De professeur d’histoire-géo à créateur d’applications</h3>
<h4 id="toc-un-début-de-carrière-déjà-marqué-par-les-logiciels-libres">Un début de carrière déjà marqué par les logiciels libres</h4>
<p>Le problème à résoudre avant tout, c’est que je ne suis pas un programmeur et que je n’ai suivi aucune formation dans ce domaine. Formé dans les dernières années du XXᵉ siècle au métier de professeur d’histoire-géographie, j’avais intégré l’usage d’outils numériques à mes pratiques dès le départ. Dans le cadre de mes missions de référent numérique dans mon collège, j’avais déjà mis la main à la pâte pour monter un logiciel de traitement de texte collaboratif (<a href="https://framapad.org/abc/fr/">Framapad</a>) sur un petit serveur privé, installer des logiciels en ligne libres comme <a href="https://moodle.com/fr/">Moodle</a>, <a href="https://www.joomla.fr/">Joomla</a> ou <a href="https://wordpress.com/fr/">Wordpress</a>, adapter de-ci de-là quelques lignes de PHP ou de CSS. À titre personnel, fervent adepte du libre, je ne travaille plus que sur des versions d’Ubuntu depuis 2005 et il m’arrive d’utiliser régulièrement la ligne de commande.</p>
<h4 id="toc-changement-de-cap">Changement de cap</h4>
<p>Retour au collège. La crise sanitaire est passée par là et les restrictions ne me permettent plus de travailler de manière collaborative entre élèves de niveaux ou de profils différents. C’est notamment le cas pour les travaux par groupes de compétences que j’organisais avec le logiciel libre <a href="https://sacoche.sesamath.net/">Sacoche</a>, projet très actif sur l’évaluation par compétences et l’analyse des résultats des élèves. </p>
<p>Mes missions vont alors se diversifier encore et je n’enseigne plus directement depuis l’automne 2020. Toujours dans le même établissement, en raison de la vacance de ces postes, je vais remplir les fonctions de principal-adjoint ou de directeur de SEGPA (Section d’Enseignement Général et Professionnel Adapté pour des élèves ayant des difficultés d’apprentissages importantes). Parmi les dossiers suivis dans ces postes figure la gestion des « pôles inclusifs d’accompagnement localisé » (PIAL) et de leur AESH, les Accompagnants d’Élèves en Situation de Handicap. Le sujet de l’École Inclusive pour tous les élèves ayant besoin d’aménagements est ainsi devenu un axe majeur dans mon implication sur notre collège. Avec des élèves toujours plus nombreux… </p>
<h4 id="toc-rentrer-dans-une-nouvelle-logique">Rentrer dans une nouvelle logique</h4>
<p>Et cette année, j’ai rajouté une corde à mon arc en m’essayant à la programmation d’applications. Pendant les quelques minutes où les directeurs de jeu visionnaient l’action au ralenti, j’ai concentré ma réflexion sur trois points importants, sur trois arbitrages plus personnels : </p>
<h5 id="toc-quelles-devront-être-les-grandes-fonctions-de-la-nouvelle-application">Quelles devront être les grandes fonctions de la nouvelle application ?</h5>
<p>Je cherchais avant tout un outil qui fournisse des informations claires et précises en m’échappant des documents de tableur reçus tous les mois avec des actualisations ou des suppressions, des erreurs possibles, de transcription de nom, des propositions de responsables impossibles à respecter et surtout des données non croisées avec la réalité du terrain. Des collègues avaient tenté de revenir au classeur papier avec un côté élève et un autre adulte. Mais tout changement d’un côté demandait la même charge de travail de l’autre.</p>
<h5 id="toc-qui-sy-connectera">Qui s’y connectera ?</h5>
<p>Si à l’origine j’envisageai un usage mono-utilisateur avec un outil hors-ligne, la possibilité d’avoir un outil collaboratif avait son charme et une utilité justifiée pour suivre les différents besoins de nos élèves. Je n’oublie pas non plus le sentiment de frustration en tant que professeur quand – au début des inclusions dans les années 2000 – j’accueillais des élèves en situation de handicap sans avoir suffisamment de précisions ou de solutions d’aides à ma disposition. Élargir la communauté d’utilisateur n’est pas un sujet à exclure.</p>
<h5 id="toc-comment-ça-marche">Comment ça marche ?</h5>
<p>Je devais pouvoir croiser plusieurs données qui ne se recouvraient qu’en partie : celles reçues via les parents d’élèves notifiés par la MDA-MDPH (Maison De l’Autonomie – Maison des Personnes Handicapées), celles transmises par les services de la DSDEN (Direction des Services De l’Éducation Nationale), avec nos informations ou décisions internes provenant de plusieurs coordonnateurs. Au vu de l’augmentation incessante des demandes et des aménagements attribués, un outil puissant et numérique ne pouvait être que la solution pour éviter des erreurs et rationaliser les suivis. En quelques clics Framasoft me suggérait SQLpage.</p>
<h3 id="toc-un-besoin-au-tout-début--le-suivi-de-laide-humaine-dans-le-cadre-des-pial">Un besoin au tout début : le suivi de l’aide humaine dans le cadre des PIAL</h3>
<ul>
<li>
<strong>Qu’est-ce que le PIAL ?</strong> Cela correspond pour nous à une zone géographique avec des écoles primaires urbaines et rurales, un collège et deux lycées. À la dernière rentrée de septembre 2023 cela représente 85 élèves et 42 accompagnants.</li>
<li>
<strong>Les accompagnants</strong>, terme que je préfère à l’acronyme AESH ou AVS, sont devenus des pièces essentielles à la bonne scolarisation d’élèves toujours plus nombreux. Sur notre collège de 700 élèves, 12 accompagnants interviennent. Certains ont une quotité de travail de 35h mais les plus récents n’ont des contrats que de 24h. Deux d’entre eux exercent une partie de leur mission sur un lycée ou sur une école.</li>
<li>
<strong>Leurs missions.</strong> Ils aident les élèves dans leurs apprentissages mais parfois pour des actes de la vie quotidienne ou sociale (repas, toilette, relations sociales…). Ils suivent en général plusieurs élèves, de 2 à 4, individuellement ou de manière mutualisée quand les élèves à besoin ont pu être placés dans la même classe. La plupart des élèves du PIAL font la totalité de leur temps scolaire sur une classe de référence avec un accompagnement qui ne cible que quelques matières. Les AESH positionnés sur les dispositifs ULIS peuvent suivre sur la semaine la totalité des élèves de leur groupe : 10 maximum d’après les textes, de 13 à 15 en réalité. Les élèves de ces dispositifs ont une scolarité partagée entre la classe de référence et l’enseignement d’un coordonnateur de l’ULIS.</li>
<li>
<strong>Comment sont attribuées les aides ?</strong> Toutes les notifications d’aménagements ou accompagnements attribués en compensation d’un handicap sont issues d’un long parcours administratif de plusieurs mois. Ce délai qui part du dépôt de la demande par la famille se termine par une commission qui a pris l’avis de professionnels du monde médico-social et de l’éducation. Dans notre collège 84 élèves ont une notification MDPH, pas nécessairement un accompagnant. Cela représente 1 élève sur 8. Si l’on ajoute les autres dispositifs d’aides attribués en interne ou par la médecine scolaire nous arrivons à 1 élève sur 4 soit 6 élèves par classe en moyenne.</li>
</ul>
<h4 id="toc-le-suivi">Le suivi</h4>
<h5 id="toc-quelles-données-est-il-utile-de-rassembler">Quelles données est-il utile de rassembler ?</h5>
<p>Au-delà des données basiques d’identification des élèves, il est important de noter la nature des aménagements (AESH, ULIS, Ordinateur, etc.), la date de fin d’attribution et le nom de l’enseignant-référent auprès de la MDPH. Ensuite, nous devons relier l’élève à un (ou plusieurs dans quelques cas) accompagnants sur un certain nombre d’heures. De plus, au début de l’année les coordonnateurs des ULIS ou du PIAL donnent des conseils de mise en œuvre des aides et des objectifs progressifs à atteindre. Ces éléments peuvent être réactualisés régulièrement.</p>
<h5 id="toc-pourquoi-enregistrer-ces-données">Pourquoi enregistrer ces données ?</h5>
<p>Les premières données sont indispensables pour programmer des réunions de suivis et de renouvellement dans les temps. Les suivantes ont tout leur intérêt pour donner du sens et du contenu à l’accompagnement. En cas de remplacement ponctuel d’un AESH, on pourrait ainsi facilement lui transmettre les informations essentielles.</p>
<p>Enfin dans un cadre plus administratif, les services de l’Éducation Nationale nous contactent afin de vérifier que les accompagnants sont bien sollicités à la hauteur de leur quotité de travail et pour des statistiques comparant les aides individuelles ou mutualisées. Cela permet aussi de motiver des demandes de recrutement.</p>
<h4 id="toc-un-modèle-de-gestion-à-perfectionner">Un modèle de gestion à perfectionner…</h4>
<h5 id="toc-comment-se-faisait-le-suivi-avant-la-création-du-nouvel-outil">Comment se faisait le suivi avant la création du nouvel outil ?</h5>
<p>Pendant trois ans, les coordonnateurs du PIAL mettaient à jour un lutin<sup id="fnref1"><a href="#fn1">1</a></sup> avec les emplois du temps élèves et ceux des accompagnants. Mais aussi, quand on les recevait, les notifications de la MDPH ; en effet, ce n’est pas automatique voire souvent non autorisé par certains inspecteurs. Ces derniers préférant que l’information soit donnée par les parents, ce qui n’est pas toujours le cas et ce qui ne permet pas d’anticipation des besoins.</p>
<h5 id="toc-quelles-étaient-les-limitations">Quelles étaient les limitations ?</h5>
<p>Si la mise à jour d’emploi du temps peut se faire régulièrement dans le classeur, la diffusion de l’information auprès de l’ensemble des acteurs n’est pas forcément rapide quand il y a plusieurs acteurs pédagogiques dans le suivi. Enfin, si une gestion classique peut suffire sur de tous petits effectifs, elle ne permet pas de vue d’ensemble dès que l’on atteint des effectifs d’élèves et d’AESH importants et elle ne permet pas de rationaliser certaines aides. Transmettre rapidement des informations précises restait un défi dans le cas de remplacements de dernière minute.</p>
<p>Un détail qui a également son importance, la fonction de pilotage et de coordination du PIAL reste une mission qui s’ajoute aux tâches de sa fonction d’origine. Cela est rémunéré à hauteur d’une indemnité correspondant très rarement au temps réellement passé sur cette gestion de plus en plus lourde.</p>
<p>Comme dans l’exemple de notre arbitre, avoir un outil moderne, réactif, croisant les regards ne peut qu’être la solution !</p>
<h5 id="toc-pourquoi-cela-nexiste-t-il-pas">Pourquoi cela n’existe-t-il pas ?</h5>
<p>J’ai débuté comme enseignant l’année où le ministre de l’Éducation Nationale comparait notre institution à un mammouth. Nous avons (souvent) changé de dirigeant mais pas forcément de rythme. Et j’ai parfois l’impression que nous n’avançons pas très vite. J’ai posé la question en 2020 et l’on m’a répondu qu’un logiciel était en préparation pour la gestion des AESH. Depuis, rien. Cela bouge un peu côté suivi des élèves avec le Livret de Parcours Inclusif. J’ai bien vu un menu apparaître dans notre Intranet mais aucune directive ne nous est parvenue pour l’activer. La MDPH devrait pouvoir nous communiquer les notifications via cette interface, en contradiction d’ailleurs avec les recommandations actuelles. Depuis octobre dernier, rien de plus. Cela reste une coquille vide…</p>
<h4 id="toc-sqlpage--créer-une-application-web-rapidement-sans-expérience-de-développeur-web">SQLPage : créer une application web rapidement sans expérience de développeur web</h4>
<h4 id="toc-principes-généraux-de-sqlpage">Principes généraux de SQLPage</h4>
<p>J’ai tout de suite été séduit par l’idée de pouvoir me concentrer sur les données et sur la personnalisation de leur traitement sans avoir à perdre du temps sur de la mise en page. SQLpage fonctionne comme un petit serveur web. Le binaire de l’application pèse un peu moins de 20 Mo. Quant aux fichiers créés, l’ensemble reste vraiment très léger</p>
<h5 id="toc-un-outil-pertinent-pour-créer-école-inclusive">Un outil pertinent pour créer « école inclusive »</h5>
<p>Maitriser ses propres données et avoir le choix dans la mise en relation et l’affichage des informations me semblait primordial. De plus SQLpage apparait être un outil léger dont on peut utiliser plusieurs briques au choix suivant ses besoins. Et, en tant qu’adepte du logiciel libre, le fait de pouvoir utiliser un programme ouvert, avec une communauté naissante et active correspondait bien à ma philosophie. Détail important à mes yeux, pouvoir retrouver ses données en cas de changement de support à l’avenir était plutôt rassurant. En effet les données stockées dans un fichier de base de données peuvent être facilement exportées au format tableur.</p>
<h5 id="toc-un-sqlpager-averti-en-vaut-deux">Un SQLpager averti en vaut deux</h5>
<p>Comme je vais le détailler dans la partie suivante, s’engager sur SQLpage ne s’est pas révélé aussi simple que cela pour quelqu’un qui n’est pas habitué à coder et qui ne maitrise pas le langage SQL. Ceci dit, je ne regrette pas d’avoir franchi le cap et cela m’a permis de me familiariser avec la plateforme github et de faire d’indéniables progrès tant dans le langage SQL, très accessible au demeurant, que dans la langue de Shakespeare. Si on est prêt à perdre un peu de son temps sur la documentation de SQLpage et quelques tutoriels sur le SQL, on gagne en rapidité de codage par la suite…</p>
<h3 id="toc-création-de-lapplication">Création de l’application</h3>
<h4 id="toc-les-grandes-étapes-du-développement">Les grandes étapes du développement</h4>
<h5 id="toc-principales-fonctionnalités-et-rythme-de-développement">Principales fonctionnalités et rythme de développement</h5>
<p>Lorsque j’ai suivi le lien de Framasoft, je m’attendais à trouver un logiciel avec une interface utilisateur qui permette par glisser déposer de construire des formulaires, un peu sur le modèle d’extensions que j’avais parfois utilisées sur Joomla ou Wordpress. Se retrouver devant un dossier avec un fichier nommé index.sql à rédiger soi-même est plutôt déstabilisant quand, comme moi, on ne maitrise pas le langage SQL. J’ai testé pendant deux jours en fonctionnant par copier-coller depuis la documentation ou depuis les exemples mis à disposition sur Github. Mon inexpérience dans le domaine du codage et ma connaissance de l’anglais sommaire dans ce domaine ont failli me pousser à abandonner SQLpage très rapidement. Heureusement, j’ai trouvé ce tutoriel dans la langue de Molière : <a href="//linuxfr.org/news/ecrire-une-appli-web-en-une-journee-avec-sqlpage">Écrire une appli web en une journée avec SQLPage <em>(publié sur linuxfr)</em></a>. Il m’a permis de bien comprendre les rudiments à la fois du langage SQL et du fonctionnement de SQLpage.</p>
<p>Après ces deux jours de tâtonnements, je me suis donné quatre semaines pour parvenir à un logiciel basé autour de trois pages principales en SQL, une pour recenser les élèves, une autre pour leurs accompagnants et une dernière pour mettre en relation les notifications et aménagements accordés. En ne travaillant qu’à temps perdu, c’est-à-dire très tard le soir ou très tôt le matin, j’ai pu parvenir en deux semaines à un premier logiciel, encore imparfait mais répondant à une grande partie du cahier des charges que je m’étais fixé. Pour cela, je me suis appuyé principalement sur des fonctionnalités de base comme les composants <a href="https://sql.ophir.dev/documentation.sql?component=form#component"><code>form</code></a> pour insérer des informations via un formulaire, et <a href="https://sql.ophir.dev/documentation.sql?component=list#component"><code>list</code></a>, <a href="https://sql.ophir.dev/documentation.sql?component=card#component"><code>card</code></a> ou <a href="https://sql.ophir.dev/documentation.sql?component=table#component"><code>table</code></a> pour afficher les données et <a href="https://sql.ophir.dev/documentation.sql?component=csv#component"><code>csv</code></a> pour les exporter. On se prend au jeu et on progresse très vite. Il est possible de voir très rapidement le résultat de ses requêtes et d’affiner les composants à utiliser ainsi que leurs paramétrages. </p>
<p>Pour un débutant, comme pour un programmeur plus chevronné, on apprécie grandement l’interprétation des erreurs de code éventuelles que ce soit dans la syntaxe SQL (Ah, les virgules oubliées par-ci par-là !) ou dans la mauvaise utilisation des composants de SQLpage…</p>
<p>La mise en place de mon projet s’est déroulée en parallèle d’une phase de développement intense de SQLpage avec une version nouvelle par semaine et une documentation enrichie au même rythme. Plusieurs nouvelles fonctionnalités sont ainsi venues enrichir le code d’École Inclusive. Au bout de quatre semaines, je tenais un logiciel fonctionnel, enrichi par des composants mis à jour comme <a href="https://sql.ophir.dev/documentation.sql?component=map#component"><code>map</code></a>, <a href="https://sql.ophir.dev/documentation.sql?component=datagrid#component"><code>datagrid</code></a> ou nouveaux comme <a href="https://sql.ophir.dev/documentation.sql?component=button#component"><code>button</code></a>.</p>
<p>Entre-temps, j’ai opté pour une version en ligne du logiciel et des données. Cela m’a obligé à me pencher sur les composants <a href="https://sql.ophir.dev/documentation.sql?component=authentication#component"><code>authentication</code></a> et <a href="https://sql.ophir.dev/documentation.sql?component=cookie#component"><code>cookie</code></a>.</p>
<p>Huit semaines après ma découverte de SQLpage, je pouvais déployer une version aboutie, collaborative et en ligne via un protocole HTTPS grâce à <a href="https://sql.ophir.dev/blog.sql?post=SQLPage%20v0.17">la version majeure 0.17 de SQLpage</a>.</p>
<h5 id="toc-comment-est-structurée-lapplication">Comment est structurée l’application ?</h5>
<p>La <strong>structure de la base de données</strong>, c’est l’étape la plus importante avant de débuter le codage. Même s’il reste possible de modifier, rajouter des tables ou des champs en cours de projet, établir un schéma clair et détaillé de la structure des données utiles aide à anticiper la construction future du logiciel.</p>
<p>Pour ma part, j’avais besoin de plusieurs tables pour respectivement les élèves, les accompagnants, les enseignants-référents, les établissements scolaires, les notifications, les aménagements et enfin une pour rassembler les suivis. Cela se calquait sur le fonctionnement classique des procédures.</p>
<p>Au fil de l’avancée du projet, j’ai ajouté des tables pour gérer les utilisateurs et leurs sessions. Et afin de faciliter la gestion des notifications ou aménagements, j’ai construit deux tables "many to many" pour enregistrer de manière plus lisible les notifications multiples (par exemples AESH et Matériel pédagogique) ainsi que les pluri-dispositifs qui peuvent en découler (comme SEGPA et AESH). Cette étape a bénéficié du développement du composant 'form' et de sa fonction multi-select.</p>
<p>Enfin, j’ai créé des tables supplémentaires pour pouvoir utiliser les fonctions 'upload' du composant 'form' et stocker des fichiers images contenant des photos des élèves et les emplois du temps de chaque accompagnant.</p>
<p><img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f44534d656a616e74656c2f45636f6c655f696e636c75736976652f6173736574732f3535323632392f31613431626435372d663930342d346535652d613066312d376466363438653337623938/1a41bd57-f904-4e5e-a0f1-7df648e37b98" alt="Schéma de la base de données d’École Inclusive" title="Source : https://github.com/DSMejantel/Ecole_inclusive/assets/552629/1a41bd57-f904-4e5e-a0f1-7df648e37b98"></p>
<h3 id="toc-une-interface-utilisateur-simplifiée">Une interface utilisateur simplifiée</h3>
<p>Le principal avantage de SQLpage est de pouvoir se focaliser sur le travail de codage du contenu sans se soucier de la mise en page. Pas de temps perdu sur des fichiers css ou html pour organiser la présentation, ceci est délégué à SQLpage qui propose une mise en forme par défaut pour chaque composant. Ceci est très appréciable et le rendu est sobre et élégant dès le début de la construction du projet. </p>
<p>Au niveau de la charte graphique d’<em>École Inclusive</em>, j’ai choisi d’avoir un menu horizontal en haut de page pour accéder aux pages consacrées à chaque catégorie d’acteurs. L’autre choix a été sur le code couleur où j’ai opté pour des tonalités vertes et orange.</p>
<p><img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f6173736574732f3535323632392f63303261303437652d356563342d343436382d383562612d386333613630646565656630/c02a047e-5ec4-4468-85ba-8c3a60deeef0" alt="page_Classes" title="Source : https://github.com/lovasoa/SQLpage/assets/552629/c02a047e-5ec4-4468-85ba-8c3a60deeef0"></p>
<p>Au fur et à mesure de l’avancement du logiciel et de son enrichissement en fonctionnalités, j’ai prévu d’autres outils de navigation. Si au départ je m’étais focalisé sur des onglets, qui renvoient en réalité sur des pages différentes. Il est possible d’utiliser des variables et de construire un système d’onglet sur un seul et même fichier sql. Le composant <code>button</code> a grandement facilité la tâche. Ceci d’autant plus que l’on peut générer des boutons de façon dynamique. Ainsi, je peux avoir des listes de boutons qui reprennent l’ensemble des classes ou des dispositifs créés pour chaque collège ou lycée du PIAL.</p>
<p>Vers la fin du projet, j’ai mis en place l’appel à un menu stocké dans un fichier json ce qui évite d’avoir à modifier le composant shell sur chacune des pages, ce qui est - pour l’avoir testé à mes dépens - une tâche très fastidieuse.</p>
<h4 id="toc-un-code-puissant-et-dynamique">Un code puissant et dynamique</h4>
<p>La seule limite à l’interface et au codage est celle de notre imagination, en effet SQLpage m’a permis de mettre en œuvre chacune de mes idées à chaque fois que je cherchais à améliorer les fonctionnalités « d’École Inclusive ». Ainsi d’une structure prévue sur 4 fichiers sql je suis passé à une structure de 94 fichiers dans la version actuelle. Maintenant que je maîtrise mieux SQLpage, je pense qu’il serait possible de réduire le nombre de pages, mais, dans ma découverte du code à mes débuts, il était plus facile d’écrire des pages plus courtes.</p>
<p>En s’appuyant sur la documentation en ligne, il est facile d’utiliser les composants de bases pour rentrer les données et les afficher sous forme de listes, de tables (avec fonction de recherche) ou de cartes (avec l’ajout d’images ou de photos) de manière dynamique en étant redirigé vers un contenu spécifique grâce à l’écriture de requêtes sur une variable comme l’id d’un élève ou d'un établissement scolaire ou d’une classe. <br>
<img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f6173736574732f3535323632392f37323661363933662d313433342d343861372d613462312d383563363065666232666532/726a693f-1434-48a7-a4b1-85c60efb2fe2" alt="page_Eleve_ajout" title="Source : https://github.com/lovasoa/SQLpage/assets/552629/726a693f-1434-48a7-a4b1-85c60efb2fe2"><br>
<img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f6173736574732f3535323632392f34653964636334312d656135352d343561382d613364652d616630336666376461356636/4e9dcc41-ea55-45a8-a3de-af03ff7da5f6" alt="page_Eleve" title="Source : https://github.com/lovasoa/SQLpage/assets/552629/4e9dcc41-ea55-45a8-a3de-af03ff7da5f6"></p>
<p>Ce qui m’a demandé davantage de réflexion a été de me lancer dans l’édition et la modification de données existantes. Depuis une icône présente sur une ligne de données d’un tableau, je voulais pouvoir, suivant les cas, éditer ou supprimer une entrée. J’avoue qu’il m’a fallu quelques jours pour arriver à un résultat correct pour dans l’ordre : afficher le formulaire, appeler les données concernées et lancer une mise à jour de la table dans la base. Pour cela j’ai contourné certaines difficultés en faisant appel à des variables afin de stocker certaines données et les réutiliser plusieurs fois sur la page, par exemple pour créer des liens dynamiques.</p>
<p>Dans les tables, j’ai souhaité mettre en évidence des situations demandant une vigilance comme une date d’expiration de notification proche de l’échéance ou l’ayant dépassée ou une fiche incomplète. Il est possible de mettre en place des conditions pour jouer soit sur la couleur d’une ligne soit sur l’affichage d’une icône particulière.</p>
<p>Enfin, la sécurisation du site dans le cadre d’une authentification avec des droits d’accès, des codes d’activation et des mots de passe forts a demandé une réflexion plus poussée et l’aide du concepteur de SQLpage.</p>
<h4 id="toc-les-points-techniques-intéressants">Les points techniques intéressants</h4>
<h5 id="toc-les-fonctionnalités-de-sqlpage-utilisées">Les fonctionnalités de sqlpage utilisées</h5>
<p>Au-delà des fonctionnalités alliant formulaires et données en liste ou en tableau, SQLpage offre des possibilités puissantes à la fois sur le plan fonctionnel et sur le plan esthétique.</p>
<p>Ainsi, il est possible de générer un trombinoscope ou des fiches de synthèse des élèves de chaque AESH. Cela se base sur le composant 'card' qui permet une présentation claire et concise des informations.</p>
<p>Le composant 'map' permet de situer chaque établissement scolaire, de différencier par des icônes les différents types de structures et bien évidemment de créer un lien vers leur page respective.</p>
<p>La visualisation des données sous forme de graphiques avec le composant 'chart' est un des points que je voulais pouvoir afficher pour analyser le temps de suivi de chaque élève et la répartition des missions des AESH.</p>
<p><img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f6173736574732f3535323632392f31643531383164302d643531642d343561342d386231612d613863313362646436393735/1d5181d0-d51d-45a4-8b1a-a8c13bdd6975" alt="page_AESH" title="Source : https://github.com/lovasoa/SQLpage/assets/552629/1d5181d0-d51d-45a4-8b1a-a8c13bdd6975"><br>
<img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f6173736574732f3535323632392f34323662613261362d336461332d346138352d396239312d373866626362313063306264/426ba2a6-3da3-4a85-9b91-78fbcb10c0bd" alt="page_AESH_2" title="Source : https://github.com/lovasoa/SQLpage/assets/552629/426ba2a6-3da3-4a85-9b91-78fbcb10c0bd"></p>
<p>En termes d’import/export, SQLpage permet de récupérer le résultat de requêtes sous forme de fichiers au format csv avec un composant dédié. L’importation à travers le composant 'form' autorise des envois de fichiers uniquement ou des traitements par lots comme dans le cas d’importations d’utilisateurs.</p>
<p>Enfin, les composants 'autenthication' et 'cookie' sont très efficaces pour mettre en place un site sécurisé.</p>
<p>Dernier point fondamental dans le cadre de la sécurisation des données, SQLpage qui reste un mini-serveur web supporte directement le protocole https.</p>
<h5 id="toc-publication-en-open-source">Publication en open-source</h5>
<p>Un simple outil comme SQLpage permet ainsi de développer relativement facilement des applications en open-source qui sont facilement fonctionnelles et attrayantes d’un point de vue graphique. De plus, l’ensemble logiciel, fichiers et base de données reste très léger et l’affichage des pages est instantanée même dans le cas de requêtes complexes.</p>
<h3 id="toc-réception-de-lapplication">Réception de l’application</h3>
<h4 id="toc-par-les-services-de-lÉducation-nationale">par les services de l’Éducation Nationale</h4>
<p>L’École Inclusive me parait naturellement devoir se pencher sur le suivi des élèves. Aussi ai-je fait part rapidement de mon projet aux enseignants-référents qui suivent les dossiers des élèves sur l’ensemble du département. Ils ont été séduits par l’idée car, eux aussi, font face à une échelle encore plus vaste à l’augmentation du nombre d’enfants à besoins particuliers. Intégrer leur rôle dans l’application était une évidence car ce sont eux qui programment et dirigent les réunions de suivis de la scolarité. Chaque début d’année, nous organisons une rencontre pour croiser nos données qui peuvent être parfois divergentes quant à des dates de fin de notification ou des aménagements multiples.</p>
<p>Mais les services de l’École Inclusive revêtent également des aspects administratifs à travers le déploiement et la gestion des accompagnements humains. Je suis rentré en contact avec les services administratifs de la DSDEN de la Lozère. L’accueil du logiciel (encore en version de test) a été bon, notamment sur son volet administratif avec les possibilités de quantifier en heures les accompagnements et la différenciation entre les accompagnements individuels ou mutualisés mais aussi sur son volet de traitement et de croisement des bases de données élèves et AESH.</p>
<h4 id="toc-par-les-collègues">par les collègues</h4>
<p>Dans notre collège, où plusieurs dispositifs coexistent et où un quart des élèves bénéficient d’un aménagement particulier, nous avions l’habitude depuis trois ans de distribuer une fiche A4 par classe avec la liste des élèves et trois colonnes recensant de manière synthétique le constat des difficultés, les aménagements et les objectifs. La mise à jour du tableur était complexe avant la rentrée ou en cours d’année. Certains renseignements sur les suivis manquaient sans parler des oublis ou petites erreurs d’actualisation ou problèmes de mise en page qui pouvaient se glisser dans les listes.</p>
<p>Aussi, proposer à tous les coordonnateurs de dispositifs un outil en ligne, collaboratif, plus complet et toujours à jour les a convaincus immédiatement. Sans tutoriel, ni formation, la prise en main a été très facile du fait de la navigation simplifiée et très intuitive. En moins de trois semaines, l’ensemble des fiches de 184 élèves a été mis à jour.</p>
<p>Cela a permis d’avoir un retour constructif de mes collègues et de recueillir des suggestions pour améliorer le logiciel. L’ajout d’une icône pour ajouter un premier aménagement, masquer des onglets inutiles pour des élèves sans accompagnement, la création d’un champ précisant le rôle de l’accompagnant ou encore l’import des emplois du temps des AESH.</p>
<p>Le logiciel a été testé lors de remplacements d’AESH, dans un premier temps en faisant des captures d’écran des pages des consignes de suivis puis avec un compte actif pour une AESH. Cela s’est révélé très pratique et très facile d’utilisation.</p>
<p>Il reste à franchir le pas de l’ouverture à l’ensemble des équipes pédagogiques et cela sera facilité par les récentes fonctionnalités d’importation permise par SQLPage.</p>
<h3 id="toc-le-futur-de-lapplication-École-inclusive">Le futur de l’application École Inclusive</h3>
<h4 id="toc-évolutions-techniques-envisagées">évolutions techniques envisagées</h4>
<p>Pour répondre à une utilisation pratique pour tous et plus particulièrement pour les enseignants, une sortie au format PDF pour chaque classe permettrait une diffusion claire aux équipes pédagogiques. Une gestion plus fine des droits avec un mode d’édition intermédiaire est à envisager pour que chaque professeur principal puisse intervenir sur les informations des élèves de sa classe.</p>
<h4 id="toc-vers-un-déploiement-de-lapplication-dans-un-cadre-légal">Vers un déploiement de l’application dans un cadre légal…</h4>
<p>La mise en ligne d’École Inclusive sur un serveur reste une démarche relativement simple chez un hébergeur qui offrirait une solution dédiée ou virtualisée. Il est possible de déployer un serveur Linux sur lequel on lance SQLpage comme service. Pour une utilisation sur un seul établissement et par un seul coordonnateur, 'École Inclusive' peut tourner hors-réseau sur différents systèmes d’exploitation. Pour rester dans un strict cadre légal, il faut que le logiciel soit déployé sur une machine ou un hébergement pris en charge par l’Éducation Nationale.</p>
<h4 id="toc--et-dans-le-respect-des-données-privées">… et dans le respect des données privées</h4>
<p>Les services du Rectorat chargés de la Protection des Données nous accompagnent dans cette démarche afin de respecter les préconisations de la CNIL. Le type de données utilisé par le logiciel ne pose pas de problème. Pour les utilisateurs de l’application dont des données personnelles sont conservées dans la base de donnée, il faut prévoir un droit de regard et de rectification conformes au standard du RGPD. Mais, rappelons que cet outil permet déjà une gestion des droits à plusieurs niveaux en tant qu’administrateur, éditeur ou consultant. Dans ce dernier cas, certaines données comme les numéros de téléphone personnels sont masqués.</p>
<h4 id="toc-vers-un-élargissement-de-lutilisation-à-dautres-établissements">Vers un élargissement de l’utilisation à d’autres établissements ?</h4>
<p>Le logiciel 'École Inclusive' va être présenté mi-mars aux chefs d’établissements publics de Lozère (13 collèges et 3 lycées). Cette démarche trouve sa pertinence dans le fait que les PIAL regroupent plusieurs établissements et que les enseignants-référents sont déployés à l’échelle du département. Cependant il sera difficile de mettre en concurrence cette application avec le Livret de Parcours Inclusif quand il sera un jour opérationnel. École Inclusive devra peut-être se recentrer sur la gestion des accompagnants et sur le suivi horaire dans une optique plus administrative que pédagogique. Mais il faut noter une plus grande souplesse et une saisie plus simple et plus directe dans École Inclusive qui ne se limite pas aux situations classiques des PPRE, PAP et Gevasco mais qui peut s’adapter à la physionomie des établissements. Chaque accueil réalisé dans la structure peut être suivi avec par exemple les élèves inclus venant d’établissements médico-sociaux, les élèves allophones, les PAI pour situations médicales…</p>
<p>En conclusion, le plus important n’est pas l’arrivée mais la quête. Celle qui m’a conduit à me poser des questions et à construire École Inclusive dans l’intérêt des élèves à besoins particuliers et des membres des équipes éducatives qui les suivent. Cette application est disponible en open-source sur Github (<a href="https://github.com/DSMejantel/Ecole_inclusive">https://github.com/DSMejantel/Ecole_inclusive</a>). Elle reste encore en évolution et elle se perfectionne au fur et à mesure de l’apparition de nouvelles fonctionnalités de SQLpage. Elle demeure très perfectible : code et interface pourront évoluer en fonction des retours des utilisateurs et de mes progrès en programmation… Pour cela SQLpage reste un allié puissant et très didactique dans les exemples de sa documentation.</p>
<h4 id="toc-exemple-de-code-affichage-du-profil-dun-élève-dans-lespace-aesh">Exemple de code: affichage du profil d’un élève dans l’espace AESH</h4>
<pre><code class="sql"><span class="c1">-- Résumé de suivis des élèves</span>
<span class="k">SELECT</span> <span class="s1">'card'</span> <span class="k">AS</span> <span class="n">component</span><span class="p">,</span> <span class="mi">4</span> <span class="k">AS</span> <span class="n">columns</span> <span class="k">WHERE</span> <span class="err">$</span><span class="n">tab</span> <span class="o">=</span> <span class="s1">'Profils'</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="n">eleve</span><span class="p">.</span><span class="n">nom</span> <span class="o">||</span> <span class="s1">' '</span> <span class="o">||</span> <span class="n">eleve</span><span class="p">.</span><span class="n">prenom</span> <span class="o">||</span> <span class="s1">' ('</span> <span class="o">||</span> <span class="n">eleve</span><span class="p">.</span><span class="n">classe</span> <span class="o">||</span> <span class="s1">') '</span> <span class="k">AS</span> <span class="n">title</span><span class="p">,</span>
<span class="s1">'green'</span> <span class="k">AS</span> <span class="n">color</span><span class="p">,</span>
<span class="k">CASE</span>
<span class="k">WHEN</span> <span class="k">EXISTS</span> <span class="p">(</span><span class="k">SELECT</span> <span class="n">eleve</span><span class="p">.</span><span class="n">id</span> <span class="k">FROM</span> <span class="n">image</span> <span class="k">WHERE</span> <span class="n">eleve</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">image</span><span class="p">.</span><span class="n">eleve_id</span><span class="p">)</span> <span class="k">THEN</span> <span class="n">image_url</span>
<span class="k">ELSE</span> <span class="s1">'./icons/profil.png'</span>
<span class="k">END</span> <span class="k">AS</span> <span class="n">top_image</span><span class="p">,</span>
<span class="n">COALESCE</span><span class="p">(</span><span class="s1">'Mission de l''AESH : '</span> <span class="o">||</span> <span class="n">suivi</span><span class="p">.</span><span class="n">mission</span><span class="p">,</span>
<span class="s1">'non saisi'</span><span class="p">)</span> <span class="k">AS</span> <span class="n">description</span><span class="p">,</span>
<span class="n">group_concat</span><span class="p">(</span><span class="k">DISTINCT</span> <span class="n">dispositif</span><span class="p">.</span><span class="n">dispo</span><span class="p">)</span> <span class="k">AS</span> <span class="n">footer</span><span class="p">,</span>
<span class="s1">'[</span>
<span class="s1"> ![](./icons/list-check.svg)</span>
<span class="s1"> ](notification.sql?id='</span> <span class="o">||</span> <span class="n">eleve</span><span class="p">.</span><span class="n">id</span> <span class="o">||</span> <span class="s1">'&tab=Profil)</span>
<span class="s1"> [</span>
<span class="s1"> ![](./icons/user-plus.svg)</span>
<span class="s1"> ](notification.sql?id='</span> <span class="o">||</span> <span class="n">eleve</span><span class="p">.</span><span class="n">id</span> <span class="o">||</span> <span class="s1">'&tab=Suivi)'</span> <span class="k">AS</span> <span class="n">footer_md</span><span class="p">,</span>
<span class="s1">'notification.sql?id='</span> <span class="o">||</span> <span class="n">eleve</span><span class="p">.</span><span class="n">id</span> <span class="o">||</span> <span class="s1">'&tab=Profil'</span> <span class="k">AS</span> <span class="n">link</span>
<span class="k">FROM</span> <span class="n">eleve</span>
<span class="k">INNER</span> <span class="k">JOIN</span> <span class="n">affectation</span> <span class="k">ON</span> <span class="n">eleve</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">affectation</span><span class="p">.</span><span class="n">eleve_id</span>
<span class="k">LEFT</span> <span class="k">JOIN</span> <span class="n">amenag</span> <span class="k">ON</span> <span class="n">amenag</span><span class="p">.</span><span class="n">eleve_id</span> <span class="o">=</span> <span class="n">eleve</span><span class="p">.</span><span class="n">id</span>
<span class="k">JOIN</span> <span class="n">dispositif</span> <span class="k">ON</span> <span class="n">dispositif</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">affectation</span><span class="p">.</span><span class="n">dispositif_id</span>
<span class="k">JOIN</span> <span class="n">etab</span> <span class="k">ON</span> <span class="n">eleve</span><span class="p">.</span><span class="n">etab_id</span> <span class="o">=</span> <span class="n">etab</span><span class="p">.</span><span class="n">id</span>
<span class="k">JOIN</span> <span class="n">suivi</span> <span class="k">ON</span> <span class="n">suivi</span><span class="p">.</span><span class="n">eleve_id</span> <span class="o">=</span> <span class="n">eleve</span><span class="p">.</span><span class="n">id</span>
<span class="k">LEFT</span> <span class="k">JOIN</span> <span class="n">image</span> <span class="k">ON</span> <span class="n">eleve</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">image</span><span class="p">.</span><span class="n">eleve_id</span>
<span class="k">JOIN</span> <span class="n">aesh</span> <span class="k">ON</span> <span class="n">suivi</span><span class="p">.</span><span class="n">aesh_id</span> <span class="o">=</span> <span class="n">aesh</span><span class="p">.</span><span class="n">id</span>
<span class="k">WHERE</span> <span class="n">aesh_id</span> <span class="o">=</span> <span class="err">$</span><span class="n">id</span> <span class="k">AND</span> <span class="err">$</span><span class="n">tab</span> <span class="o">=</span> <span class="s1">'Profils'</span>
<span class="k">GROUP</span> <span class="k">BY</span> <span class="n">eleve</span><span class="p">.</span><span class="n">id</span>
<span class="k">ORDER</span> <span class="k">BY</span> <span class="n">eleve</span><span class="p">.</span><span class="n">nom</span> <span class="k">ASC</span><span class="p">;</span></code></pre>
<p><img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f6173736574732f3535323632392f30366134343430662d636632612d346563342d393161652d653736333165623561353532/06a4440f-cf2a-4ec4-91ae-e7631eb5a552" alt="carte_eleve" title="Source : https://github.com/lovasoa/SQLpage/assets/552629/06a4440f-cf2a-4ec4-91ae-e7631eb5a552"></p>
<p>Cet élément fait partie de la page du profil d’un AESH. Dans un premier paragraphe, on appelle le composant 'card' avec ses paramètres. Ici, il y aura quatre cartes affichées par ligne si l’on se trouve sur l’onglet nommé « Profils ».<br>
Ensuite on trouve le contenu de chaque fiche élève. Son identité et sa photo si elle existe dans la base ; cela est déterminé par le <code>CASE WHEN</code>. Dans le cas inverse une image par défaut est affichée.<br>
Si le rôle de l’AESH a été renseigné, il est affiché en dessous. Puis viennent les dispositifs d’aide auxquels l’élève est rattaché.<br>
Enfin, trois icônes renvoient vers différents onglets de la fiche personnelle de l’élève.<br>
Cet affichage est dynamique et s’adapte au profil de chaque AESH comme le définit la condition <code>WHERE aesh_id=$id</code>. Le contenu de la fiche va piocher les différentes informations dans les tables.</p>
<p>Exemple d’alertes et d’informations personnalisées</p>
<pre><code class="sql"><span class="c1">-- Liste des notifications</span>
<span class="k">SELECT</span> <span class="s1">'table'</span> <span class="k">as</span> <span class="n">component</span><span class="p">,</span>
<span class="s1">'actions'</span> <span class="k">as</span> <span class="n">markdown</span><span class="p">,</span>
<span class="mi">1</span> <span class="k">as</span> <span class="n">sort</span><span class="p">,</span>
<span class="mi">1</span> <span class="k">as</span> <span class="k">search</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="n">eleve</span><span class="p">.</span><span class="n">nom</span> <span class="k">as</span> <span class="n">Nom</span><span class="p">,</span>
<span class="n">eleve</span><span class="p">.</span><span class="n">prenom</span> <span class="k">as</span> <span class="n">Pr</span><span class="err">é</span><span class="n">nom</span><span class="p">,</span>
<span class="n">notification</span><span class="p">.</span><span class="n">Departement</span> <span class="k">as</span> <span class="n">Dpt</span><span class="p">,</span>
<span class="n">group_concat</span><span class="p">(</span><span class="k">DISTINCT</span> <span class="n">modalite</span><span class="p">.</span><span class="k">type</span><span class="p">)</span> <span class="k">as</span> <span class="n">Droits</span><span class="p">,</span>
<span class="n">etab</span><span class="p">.</span><span class="n">nom_etab</span> <span class="k">as</span> <span class="err">É</span><span class="n">tablissement</span><span class="p">,</span>
<span class="n">strftime</span><span class="p">(</span><span class="s1">'%d/%m/%Y'</span><span class="p">,</span> <span class="n">datefin</span><span class="p">)</span> <span class="k">AS</span> <span class="n">Fin</span><span class="p">,</span>
<span class="k">CASE</span>
<span class="k">WHEN</span> <span class="n">notification</span><span class="p">.</span><span class="n">datefin</span> <span class="o"><</span> <span class="n">datetime</span><span class="p">(</span><span class="nb">date</span><span class="p">(</span><span class="s1">'now'</span><span class="p">,</span> <span class="s1">'+1 day'</span><span class="p">))</span> <span class="k">THEN</span> <span class="s1">'red'</span>
<span class="k">WHEN</span> <span class="n">notification</span><span class="p">.</span><span class="n">datefin</span> <span class="o"><</span> <span class="n">datetime</span><span class="p">(</span><span class="nb">date</span><span class="p">(</span><span class="s1">'now'</span><span class="p">,</span> <span class="s1">'+350 day'</span><span class="p">))</span> <span class="k">THEN</span> <span class="s1">'orange'</span>
<span class="k">ELSE</span> <span class="s1">'green'</span>
<span class="k">END</span> <span class="k">AS</span> <span class="n">_sqlpage_color</span><span class="p">,</span>
<span class="n">coalesce</span><span class="p">(</span><span class="s1">'[ ![](./icons/user-plus.svg) ](aesh_suivi.sql?id='</span> <span class="o">||</span> <span class="n">suivi</span><span class="p">.</span><span class="n">aesh_id</span> <span class="o">||</span> <span class="s1">'&tab=Profils)'</span><span class="p">,</span> <span class="s1">'[ ![](./icons/user-off.svg) ]()'</span><span class="p">)</span> <span class="k">AS</span> <span class="n">actions</span><span class="p">,</span>
<span class="s1">'[ ![](./icons/briefcase.svg) ](notification.sql?id='</span> <span class="o">||</span> <span class="n">eleve</span><span class="p">.</span><span class="n">id</span> <span class="o">||</span> <span class="s1">'&tab=Profil)'</span> <span class="k">as</span> <span class="n">actions</span>
<span class="k">FROM</span> <span class="n">notification</span>
<span class="k">INNER</span> <span class="k">JOIN</span> <span class="n">eleve</span> <span class="k">on</span> <span class="n">notification</span><span class="p">.</span><span class="n">eleve_id</span> <span class="o">=</span> <span class="n">eleve</span><span class="p">.</span><span class="n">id</span>
<span class="k">LEFT</span> <span class="k">JOIN</span> <span class="n">suivi</span> <span class="k">on</span> <span class="n">eleve</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">suivi</span><span class="p">.</span><span class="n">eleve_id</span>
<span class="k">LEFT</span> <span class="k">join</span> <span class="n">notif</span> <span class="k">on</span> <span class="n">notif</span><span class="p">.</span><span class="n">notification_id</span> <span class="o">=</span> <span class="n">notification</span><span class="p">.</span><span class="n">id</span>
<span class="k">LEFT</span> <span class="k">join</span> <span class="n">modalite</span> <span class="k">on</span> <span class="n">modalite</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">notif</span><span class="p">.</span><span class="n">modalite_id</span>
<span class="k">JOIN</span> <span class="n">referent</span> <span class="k">on</span> <span class="n">eleve</span><span class="p">.</span><span class="n">referent_id</span> <span class="o">=</span> <span class="n">referent</span><span class="p">.</span><span class="n">id</span>
<span class="k">JOIN</span> <span class="n">etab</span> <span class="k">on</span> <span class="n">eleve</span><span class="p">.</span><span class="n">etab_id</span> <span class="o">=</span> <span class="n">etab</span><span class="p">.</span><span class="n">id</span>
<span class="k">Where</span> <span class="n">referent</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="err">$</span><span class="n">id</span>
<span class="k">GROUP</span> <span class="k">BY</span> <span class="n">notification</span><span class="p">.</span><span class="n">eleve_id</span>
<span class="k">ORDER</span> <span class="k">BY</span> <span class="n">eleve</span><span class="p">.</span><span class="n">nom</span> <span class="k">ASC</span><span class="p">;</span></code></pre>
<p><img src="//img.linuxfr.org/img/68747470733a2f2f636f6c6c6567652d626f757272696c6c6f6e2e66722f73716c706167652f706167655f5265666572656e742e706e67/page_Referent.png" alt="Tableau de suivi par référent" title="Source : https://college-bourrillon.fr/sqlpage/page_Referent.png"></p>
<p>Cet élément fait partie de la page du profil d’un enseignant-référent de la MDA-MDPH. <br>
Dans un premier paragraphe, on appelle le composant <code>table</code> avec ses paramètres. On trouve le formatage d’une colonne en markdown et les options de recherche et de tri qui sont activées.<br>
Ensuite on trouve le contenu de chaque ligne avec l’élève dont le dossier est suivi par ce référent. <br>
Afin de planifier avec lui les priorités pour les dates de réunions de suivi, il est possible d’attribuer une couleur de ligne en fonction de la date de fin de notification avec : <br>
<code>CASE<br>
WHEN notification.datefin < datetime(date('now', '+1 day')) THEN 'red'<br>
WHEN notification.datefin < datetime(date('now', '+350 day')) THEN 'orange'<br>
ELSE 'green'</code><br>
De même les icônes sont personnalisables pour indiquer si l’élève bénéficie d’un AESH ou non. Et bien sûr des liens permettent de passer sur la fiche de l’élève ou de son AESH.</p>
<p>Licence de l’article: <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a></p>
<div class="footnotes">
<hr>
<ol>
<li id="fn1">
<p>[NDM] : lutin est le nom d’une marque de protège-documents à pochettes en plastique, par extension celui des protège-documents similaires d’autres marques. <a href="#fnref1">↩</a></p>
</li>
</ol>
</div>
</div><div><a href="https://linuxfr.org/news/ecole-inclusive-une-application-libre-pour-la-prise-en-charge-des-eleves-en-situation-de-handicap.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/135028/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/ecole-inclusive-une-application-libre-pour-la-prise-en-charge-des-eleves-en-situation-de-handicap#comments">ouvrir dans le navigateur</a>
</p>
lovasoaDSMejantelYsabeau 🧶 🧦https://linuxfr.org/nodes/135028/comments.atomtag:linuxfr.org,2005:News/416392023-08-25T08:26:12+02:002023-08-25T08:26:12+02:00Désolé, j'ai forkéLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>Forker un logiciel libre (en créer une nouvelle version indépendante de l’original) est une décision difficile, qui risque de diviser sa communauté. Je propose ici la traduction en français d’un article que j’avais initialement écrit en anglais et publié sur le blog du <a href="https://sql.ophir.dev">logiciel de création de sites web SQLPage</a> à propos du <a href="https://sql.ophir.dev/blog.sql?post=I%E2%80%99m%20sorry%20I%20forked%20you">fork d’une bibliothèque populaire du langage de programmation <em>Rust</em></a>.</p>
</div><ul></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<ul>
<li><a href="#toc-largent-dans-le-monde-du-logiciel">L’argent dans le monde du logiciel</a></li>
<li>
<a href="#toc-sqlx--une-merveille-du-monde-de-rust"><em>SQLx</em> : Une merveille du monde de Rust</a><ul>
<li><a href="#toc-la-fameuse-version-07">La fameuse version 0.7</a></li>
</ul>
</li>
<li><a href="#toc-sqlpage">SQLPage</a></li>
<li><a href="#toc-d%C3%A9sol%C3%A9-jai-fork%C3%A9">Désolé, j’ai forké</a></li>
<li><a href="#toc-notes-de-conclusion">Notes de conclusion</a></li>
<li><a href="#toc-r%C3%A9actions-%C3%A0-larticle-original">Réactions à l’article original</a></li>
</ul>
</li>
</ul>
<p>Je suis plongé dans le milieu du logiciel libre depuis mon adolescence, et aujourd’hui, je ne peux pas imaginer un monde sans lui.</p>
<p>Tout au long de ma carrière d’ingénieur logiciel, je n’ai jamais rencontré d’entreprise technologique qui ne soit pas fondée sur les logiciels libres et open source. Chaque entreprise ajoute en général sa propre touche propriétaire à ce vaste paysage open source, mais elles ne font en fin de compte que former un petit mélange privateur au sommet d’un colossal iceberg de système d’exploitation, d’outils, et surtout de bibliothèques logicielles partagées et libres. Dans le monde du logiciel, l’open source est véritablement la force motrice de l’innovation.</p>
<h3 id="toc-largent-dans-le-monde-du-logiciel">L’argent dans le monde du logiciel</h3>
<p>Les courants financiers qui parcourent l’industrie du logiciel défient toutes les normes conventionnelles.</p>
<p>Contrairement à d’autres secteurs où des acteurs clés du début de la chaîne de production tels que les compagnies pétrolières s’enrichissent en fournissant des produits essentiels à d’autres entreprises, le domaine du logiciel renverse le scénario.</p>
<p>Dans ce domaine, ce sont les géants de l’informatique qui font face aux clients finaux, comme Google, qui récoltent les bénéfices; et il arrive souvent que les créateurs des logiciels libres qui forment les fondations de Google et d’innombrables autres entreprises travaillent gratuitement.</p>
<p>Les développeurs de logiciels libres observent cette dynamique intrigante, parfois même satisfaits de voir leurs logiciels libres développés gratuitement alimenter la création d’entreprises qui font des millions de dollars de bénéfices.</p>
<h3 id="toc-sqlx--une-merveille-du-monde-de-rust">
<em>SQLx</em> : Une merveille du monde de Rust</h3>
<p><a href="https://crates.io/crates/sqlx">SQLx</a> est l’une des nombreuses bibliothèques logicielles qui se trouvent dans la partie immergée de cet iceberg logiciel. Il s’agit d’un formidable pilote de base de données SQL pour le langage de programmation <em>Rust</em>, qui harmonise la connexion à une multitude de bases de données. Il est téléchargé environ 20 000 fois par jour.</p>
<h4 id="toc-la-fameuse-version-07">La fameuse version 0.7</h4>
<p>Le principal mainteneur de <em>SQLx</em> a cherché à trouver un juste milieu – créer un bon logiciel libre tout en cherchant la pérennité économique de son projet. Cet effort a conduit à une décision cruciale : extraire les pilotes de base de données de la bibliothèque de base. Tout en conservant la plupart des pilotes en tant que logiciels libres sous la licence permissive <em>MIT</em>, <strong>la compatibilité avec Microsoft SQL Server a été abandonnée</strong>. Ce changement architectural significatif a également nécessité la suppression d’autres fonctionnalités du cadre de base, et l’introduction d’une nouvelle API, rendant la migration depuis la version précédente non triviale.</p>
<h3 id="toc-sqlpage">SQLPage</h3>
<p>En tant que principal responsable du <a href="https://sql.ophir.dev">serveur d’applications web SQLPage</a>, qui repose sur sqlx, j’ai été confronté à un tournant décisif. Deux possibilités s’offraient à moi :</p>
<ol>
<li>une migration difficile vers SQLx v0.7, en faisant une croix sur la possibilité d’utiliser SQLPage avec Microsoft SQL Server;</li>
<li>attendre, et rester sous SQLx v0.6, une solution qui impliquait de conserver des dépendances obsolètes, contenant potentiellement des failles de sécurité rendant le logiciel vulnérable.<br>
</li>
</ol>
<p>Après beaucoup d’hésitations, j’ai choisi une troisième voie : <strong>forker SQLx</strong>.</p>
<h3 id="toc-désolé-jai-forké">Désolé, j’ai forké</h3>
<p>La situation me désole. Je suis vraiment en faveur d’un monde du logiciel libre financièrement viable. J’espère que l’auteur original arrivera à commercialiser ses futurs nouveaux pilotes de base de données et qu’ils le compenseront dûment pour les contributions inestimables qu’il a apportées.</p>
<p>Mais, j’ai vraiment besoin d’un bon ensemble de pilotes de base de données sous une licence permissive pour Rust, j’ai besoin de certaines des fonctionnalités qui ont été supprimées dans la v0.7, et je veux que les bases <em>SQL Server</em> fonctionnent avec SQLPage. J’ai donc créé <a href="https://lib.rs/crates/sqlx-oldapi">sqlx-oldapi</a>, un fork de SQLx v0.6.</p>
<p>Dans le fork :</p>
<ul>
<li>J’ai méticuleusement mis à jour toutes les dépendances vers leurs dernières itérations, m'assurant ainsi que les fondations restent robustes et sûres.</li>
<li>Les fonctionnalités essentielles qui manquaient ont été incorporées pour répondre à des besoins spécifiques, et des bogues de longue date ont été résolus. Notamment, le support des types de données a été renforcé, avec par exemple un décodage efficace avec perte des valeurs <code>DECIMAL</code> en tant que flottants dans tous les pilotes, et un décodage sans perte vers les types natifs de rust.</li>
<li>Mes efforts se sont concentrés sur l’élévation du pilote SQL Server au même niveau que ses pairs. Cela a impliqué la correction de bugs et de crashs, et le support de nouveaux types de données comme <code>DATETIME</code> et <code>DECIMAL</code>.</li>
</ul>
<p>La liste complète des changements peut être trouvée dans le <a href="https://github.com/lovasoa/sqlx/blob/main/CHANGELOG.md">changelog</a>.</p>
<h3 id="toc-notes-de-conclusion">Notes de conclusion</h3>
<ul>
<li>J’espère sincèrement que sqlx réussira à financer son développement. </li>
<li>Aux développeurs et développeuses qui se trouvent à la même croisée des chemins que moi avec SQLPage, sachez que <a href="https://lib.rs/crates/sqlx-oldapi">sqlx-oldapi</a> vous attend, prêt à vous aider dans vos efforts, librement. Les contributions et les rapports de bogues sont les bienvenus <a href="https://github.com/lovasoa/sqlx-oldapi">sur github</a>.</li>
</ul>
<p>Et si vous voulez savoir pourquoi l’URL de cette page se termine par <code>.sql</code>, jetez un œil à <a href="https://sql.ophir.dev">SQLPage</a>. [NdT : l’URL de l’article original est <a href="https://sql.ophir.dev/blog.sql?post=I%E2%80%99m%20sorry%20I%20forked%20you"><code>https://sql.ophir.dev/blog.sql?post=I’m sorry I forked you</code></a> ]</p>
<hr>
<h3 id="toc-réactions-à-larticle-original">Réactions à l’article original</h3>
<p>L’article traduit ci-dessus a suscité <a href="https://www.reddit.com/r/rust/comments/15pudt2/im_sorry_i_forked_you/">de nombreuses réactions</a> sur le forum de discussion anglophone reddit. La plus importante est probablement celle de l’auteur principal de sqlx, qui était mécontent de la présentation que l’article faisait de la situation, et qui a notamment apporté deux corrections importantes.</p>
<ol>
<li>L’auteur principal développe SQLx durant son temps de travail, et prend les décisions concernant cette bibliothèque libre en accord avec son employeur. Si la commercialisation de pilotes de base de données rapporte de l’argent, il n’ira pas directement au développeur, mais à son employeur. L’objectif affiché serait de pouvoir justifier d’accorder plus de temps exclusivement au développement de sqlx. </li>
<li>Il y avait bien eu une annonce originale du passage du pilote de base de données pour SQL Server sous une licence propriétaire, mais une nouvelle annonce avait déjà été faite, depuis longtemps, lorsque l’article de blog a été publié. SQLx n’a désormais plus l’intention de publier les futurs nouveaux pilotes de base de données sous une licence privatrice, mais de les publier sous la licence libre (mais restrictive) AGPL, et de vendre des exemptions à la licence aux entreprises qui le souhaitent. Pour le moment, rien n’a encore été publié, il n’y a pas de pilote, ni libre ni propriétaire, pour SQL Server avec SQLx v0.7.</li>
</ol>
<p>Et vous, qu’en pensez-vous ? Que pensez-vous de l’idée viabiliser le développement d’un logiciel en le publiant sous une licence libre, mais restrictive, en commercialisant des exceptions à la licence ? Est-il correct de forker un logiciel libre dont l’auteur essaie de rendre son projet plus pérenne en le monétisant ?</p>
</div><div><a href="https://linuxfr.org/news/desole-j-ai-forke.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/133052/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/desole-j-ai-forke#comments">ouvrir dans le navigateur</a>
</p>
lovasoaBAudYsabeau 🧶 🧦ArkemNils Ratusznikhttps://linuxfr.org/nodes/133052/comments.atomtag:linuxfr.org,2005:News/415632023-07-04T09:28:24+02:002023-07-04T10:57:44+02:00Écrire une appli web en une journée avec SQLPageLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>Aujourd'hui, je souhaite vous présenter le logiciel <a href="https://sql.ophir.dev">SQLPage</a>, un outil open-source (MIT) qui permet de développer des applications web complètes, avec une belle interface graphique et une base de données, entièrement en SQL.</p>
<p>Le SQL est un langage très simple, qui permet de faire des recherches dans des base de données. Il est utilisé depuis les années 80, et est encore omniprésent aujourd'hui. Contrairement aux langages de programmation traditionnels, on peut apprendre les bases de SQL en une journée, et commencer à faire des requêtes complexes croisant plusieurs tables de données très rapidement. </p>
<p>Dans une application web traditionnelle, on développe aujourd'hui en général trois composants :</p>
<ul>
<li>un <em>front-end</em>, qui gère uniquement l'interface utilisateur,</li>
<li>un <em>back-end</em>, qui traite les requêtes du <em>front-end</em> et contient le cœur de la logique de l'application lorsque celle-ci est complexe,</li>
<li>une <em>base de données</em> qui va stocker et structurer les données, s'assurant de leur cohérence et de leur bonne organisation. </li>
</ul>
<p>Les deux premiers éléments sont en général ceux sur lesquels les programmeurs passent le plus de temps lors du développement d'une application. Et pourtant, c'est souvent le dernier, la base de données, qui contient la substantifique moelle de l'application !</p>
<p>Ce que propose SQLPage, c'est de s'abstraire complètement du <em>back-end</em> et du <em>front-end</em>, et générer toute une application entièrement en SQL. Nous allons voir ici comment c'est possible, avec un exemple concret d'application que nous allons construire ensemble en SQL : à la Tricount.com, une petite application qui permet de gérer ses comptes entre amis.</p>
</div><ul><li>lien nᵒ 1 : <a title="https://sql.ophir.dev" hreflang="en" href="https://linuxfr.org/redirect/112360">Site officiel du projet SQLPage</a></li><li>lien nᵒ 2 : <a title="https://github.com/lovasoa/sqlpage" hreflang="en" href="https://linuxfr.org/redirect/112361">Code source du projet sur Github </a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><a href="#toc-est-ce-de-la-sorcellerie">Est-ce de la sorcellerie ?</a></li>
<li><a href="#toc-comment-%C3%A7a-marche">Comment ça marche ?</a></li>
<li>
<a href="#toc-construisons-une-application">Construisons une application</a><ul>
<li>
<a href="#toc-notre-application--une-application-opensource-pour-faire-ses-comptes-entre-amis">Notre application : une application opensource pour faire ses comptes entre amis</a><ul>
<li><a href="#toc-premi%C3%A8re-%C3%A9tape--choisir-un-sch%C3%A9ma-pour-notre-base-de-donn%C3%A9es">Première étape : choisir un schéma pour notre base de données</a></li>
<li><a href="#toc-deuxi%C3%A8me-%C3%A9tape--cr%C3%A9ation-de-la-base-de-donn%C3%A9es-et-lancement-de-sqlpage">Deuxième étape : création de la base de données et lancement de SQLPage</a></li>
<li><a href="#toc-troisi%C3%A8me-%C3%A9tape--cr%C3%A9ation-de-notre-premi%C3%A8re-page-web">Troisième étape : création de notre première page web</a></li>
<li><a href="#toc-insertion-de-donn%C3%A9es-dans-la-base-de-donn%C3%A9es">Insertion de données dans la base de données</a></li>
</ul>
</li>
<li>
<a href="#toc-am%C3%A9lioration-de-lapplication-cr%C3%A9ation-de-nouvelles-pages">Amélioration de l'application, création de nouvelles pages</a><ul>
<li><a href="#toc-cerise-sur-le-g%C3%A2teau--calcul-des-dettes">Cerise sur le gâteau : calcul des dettes</a></li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#toc-conclusion">Conclusion</a><ul>
<li>
<ul>
<li><a href="#toc-pour-r%C3%A9sumer-ce-que-nous-avons-vu">Pour résumer ce que nous avons vu</a></li>
<li><a href="#toc-pour-aller-plus-loin">Pour aller plus loin</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="toc-est-ce-de-la-sorcellerie">Est-ce de la sorcellerie ?</h2>
<p>Tout d'abord, mettons les choses au clair : votre application aura bien un backend et un frontend, il n'y a pas de miracle. Mais pour les applications simples, le frontend est souvent juste un assemblage de composants standards, et le backend qu'une sorte de passe-plats entre le frontend et la base de données. Ce que permet SQLPage, et que nous allons étudier ici c'est :</p>
<ul>
<li>d'invoquer des composants prédéfinis d'interface graphique en donnant simplement leur nom et quelques paramètres,</li>
<li>de faire le lien entre l'interface graphique et la base de données avec de simples fichiers SQL qui sont exécutés automatiquement lorsque l'utilisateur charge une page. </li>
</ul>
<h2 id="toc-comment-ça-marche">Comment ça marche ?</h2>
<p>SQLPage est un simple serveur web : c'est un programme qui tourne en continu, attend des requêtes HTTP, et dès qu'il en reçoit une, fournit une réponse.</p>
<p>Si SQLPage reçoit une requête vers <code>/site/contenu.sql?article=42</code>, il va chercher un fichier nommé <code>contenu.sql</code>, dans un dossier nommé <code>site</code>. Il va ensuite lire le contenu du fichier, et l'interpréter comme une série de requêtes SQL, qui vont être préparées. Elles seront ensuite exécutées une par une. Si l'une de ces requêtes fait référence à une variable nommée <code>$article</code>, la valeur <code>42</code> venant de la requête de l'utilisateur lui sera associée.</p>
<p><img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f626c6f622f6d61696e2f646f63732f6172636869746563747572652e706e673f7261773d74727565/architecture.png?raw=true" alt="architecture sqlpage" title="Source : https://github.com/lovasoa/SQLpage/blob/main/docs/architecture.png?raw=true"></p>
<p>Les requêtes sont envoyées à la base de données, et celle-ci commence à retourner des lignes de données, une par une.</p>
<p>Les lignes vont ensuite être analysées <em>au fil de l'eau</em> par SQLPage, qui va décider quel composant graphique renvoyer au navigateur web, et quelles données utiliser pour remplir le composant. </p>
<h2 id="toc-construisons-une-application">Construisons une application</h2>
<p>Pour rendre tout ce discours plus concret, créons ensemble une petite application, entièrement en SQL, et en vingt minutes. </p>
<p>Pour vous donner un avant-goût, voilà ce à quoi nous allons arriver au final</p>
<table>
<thead>
<tr>
<th>Page d'accueil</th>
<th>Gestion d'utilisateurs</th>
<th>Liste de dépenses</th>
<th>Graphique de dettes</th>
</tr>
</thead>
<tbody>
<tr>
<td><img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f6173736574732f3535323632392f33373762326161632d656332372d343238322d383962392d626432366664373737643961/377b2aac-ec27-4282-89b9-bd26fd777d9a" alt="image" title="Source : https://github.com/lovasoa/SQLpage/assets/552629/377b2aac-ec27-4282-89b9-bd26fd777d9a"></td>
<td><img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f6173736574732f3535323632392f37613564343666312d666564382d346532392d613862362d336638633139656136336165/7a5d46f1-fed8-4e29-a8b6-3f8c19ea63ae" alt="image" title="Source : https://github.com/lovasoa/SQLpage/assets/552629/7a5d46f1-fed8-4e29-a8b6-3f8c19ea63ae"></td>
<td><img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f6173736574732f3535323632392f33646339306138352d613563322d343464392d616133332d646265383634373061653339/3dc90a85-a5c2-44d9-aa33-dbe86470ae39" alt="image" title="Source : https://github.com/lovasoa/SQLpage/assets/552629/3dc90a85-a5c2-44d9-aa33-dbe86470ae39"></td>
<td><img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f6173736574732f3535323632392f31613866623865342d336461642d343030612d626535342d656235623534656339303162/1a8fb8e4-3dad-400a-be54-eb5b54ec901b" alt="image" title="Source : https://github.com/lovasoa/SQLpage/assets/552629/1a8fb8e4-3dad-400a-be54-eb5b54ec901b"></td>
</tr>
</tbody>
</table>
<p>Il n'y a pas toutes les fonctionnalités de l'application originelle, mais c'est seulement 83 lignes de code, grâce à tout ce que SQLPage gère automatiquement. Et le résultat est quand même plus joli que l'original.</p>
<h3 id="toc-notre-application--une-application-opensource-pour-faire-ses-comptes-entre-amis">Notre application : une application opensource pour faire ses comptes entre amis</h3>
<p>Nous allons créer une application pour faire ses comptes entre amis. Elle aura les fonctionnalités suivantes :</p>
<ul>
<li>créer un nouveau compte de dépenses partagé</li>
<li>ajouter des participants et visualiser la liste des participants existants</li>
<li>pour chaque participant :
<ul>
<li>ajouter une dépense</li>
<li>voir les dépenses des autres</li>
<li>voir combien il doit au reste du groupe ou combien lui est dû</li>
</ul>
</li>
</ul>
<h4 id="toc-première-étape--choisir-un-schéma-pour-notre-base-de-données">Première étape : choisir un schéma pour notre base de données</h4>
<p>Et oui, on ne va pas passer quatre jours à choisir un framework JavaScript, un framework CSS, un ORM, ou autres choses compliquées que l'on fait quand on commence une application web classique. Avec SQLPage, on rentre tout de suite dans le cœur du sujet, et ce qui sera important pour la suite: quelles données stockerons-nous, et sous quelle forme. </p>
<p>Ici, je propose le schéma suivant :</p>
<ul>
<li>une table <code>expense_group</code> pour nos comptes de dépenses partagés, avec un identifiant numérique et un nom. </li>
<li>une table <code>group_member</code> pour les utilisateurs, avec un identifiant numérique, un nom, et l'identifiant du compte partagé auquel il appartient. </li>
<li>une table <code>expense</code> pour les dépenses, avec l'identifiant de l'utilisateur ayant fait la dépense, une description, et un montant. Pour cet exemple, nous ne prendrons pas en compte le cas où une dépense peut ne concerner qu'une partie du groupe; ce sera simple à ajouter dans un second temps. </li>
</ul>
<h4 id="toc-deuxième-étape--création-de-la-base-de-données-et-lancement-de-sqlpage">Deuxième étape : création de la base de données et lancement de SQLPage</h4>
<p>C'est parti ! <a href="https://github.com/lovasoa/SQLpage/releases">Téléchargeons SQLPage sur le site officiel</a>. </p>
<p>Créons un dossier pour notre application, et dans ce dossier créons la structure de fichiers suivante:</p>
<pre><code>├── sqlpage
│ ├── migrations
│ │ └── 000_base.sql
│ └── sqlpage.json
└── sqlpage.bin
</code></pre>
<p>Nous créons donc les fichiers suivants:</p>
<ul>
<li>
<code>sqlpage/migrations/000_base.sql</code> dans lequel nous définirons la structure de notre base de données</li>
<li>
<code>sqlpage/sqlpage.json</code> dans lequel nous mettrons pour l'instant simplement la ligne suivante: <code>{"database_url": "sqlite://:memory:"}</code>. Cela nous permet de travailler avec une base de données temporaire en mémoire. Nous le modifierons plus tard pour nous connecter à une base de données plus pérenne.</li>
</ul>
<p>Intéressons-nous d'abord à <code>sqlpage/migrations/000_base.sql</code>. Pour créer la structure de base de données définie plus tôt, utilisons quelques <a href="https://www.sqlite.org/lang_createtable.html">instructions de création de table</a> :</p>
<pre><code class="sql"><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">expense_group</span><span class="p">(</span>
<span class="n">id</span> <span class="nb">INTEGER</span> <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="n">AUTOINCREMENT</span><span class="p">,</span>
<span class="n">name</span> <span class="nb">TEXT</span>
<span class="p">);</span>
<span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">group_member</span><span class="p">(</span>
<span class="n">id</span> <span class="nb">INTEGER</span> <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="n">AUTOINCREMENT</span><span class="p">,</span>
<span class="n">group_id</span> <span class="nb">INTEGER</span> <span class="k">REFERENCES</span> <span class="n">expense_group</span><span class="p">(</span><span class="n">id</span><span class="p">),</span>
<span class="n">name</span> <span class="nb">TEXT</span>
<span class="p">);</span>
<span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">expense</span><span class="p">(</span>
<span class="n">id</span> <span class="nb">INTEGER</span> <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="n">AUTOINCREMENT</span><span class="p">,</span>
<span class="n">spent_by</span> <span class="nb">INTEGER</span> <span class="k">REFERENCES</span> <span class="n">group_member</span><span class="p">(</span><span class="n">id</span><span class="p">),</span> <span class="c1">-- identifiant du membre qui a fait la dépense</span>
<span class="nb">date</span> <span class="k">TIMESTAMP</span> <span class="k">DEFAULT</span> <span class="k">CURRENT_TIMESTAMP</span><span class="p">,</span> <span class="c1">-- date et heure de la dépense</span>
<span class="n">name</span> <span class="nb">TEXT</span><span class="p">,</span> <span class="c1">-- intitulé</span>
<span class="n">amount</span> <span class="nb">DECIMAL</span> <span class="c1">-- montant en euros</span>
<span class="p">);</span></code></pre>
<p>On peut maintenant lancer l'exécutable <code>sqlpage.bin</code> (ou <code>sqlpage.exe</code> sous Windows 😬) depuis le dossier de notre site.</p>
<p>Il doit se lancer, et afficher dans le terminal le message suivant : <code>Applying migrations from 'sqlpage/migrations [...] Found 1 migrations</code>. Cela signifie qu'il a créé avec succès notre base de données selon le schéma demandé.</p>
<p>En ouvrant la page <code>http://localhost:8080</code> sur notre navigateur web, nous devrions voir le message suivant:</p>
<p><img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f6173736574732f3535323632392f34616533643165372d303366322d343230302d616537632d373061636134303537346238/4ae3d1e7-03f2-4200-ae7c-70aca40574b8" alt="Screenshot 2023-06-28 at 16-46-40 SQLpage" title="Source : https://github.com/lovasoa/SQLpage/assets/552629/4ae3d1e7-03f2-4200-ae7c-70aca40574b8"></p>
<h4 id="toc-troisième-étape--création-de-notre-première-page-web">Troisième étape : création de notre première page web</h4>
<p>Le moment tant attendu est arrivé : nous allons créer notre première page web et pouvoir l'ouvrir dans notre navigateur.</p>
<p>Pour cela, créons un fichier nommé <code>index.sql</code> à la racine du dossier de notre site web. À l'intérieur, nous allons écrire une série de requêtes SQL.</p>
<p>SQLPage marche de la manière suivante : on fait une première requête pour invoquer un composant graphique, comme une liste, un formulaire, du texte, ou un graphique. Ensuite, on fait une seconde requête pour définir comment peupler notre composant : les éléments de la liste, les champs du formulaire, les paragraphes de texte, ou les points de notre graphique.</p>
<p>Dans notre cas, notre premier composant sera un formulaire pour créer un nouveau groupe de dépenses à partager entre amis. Pour cela, nous allons invoquer le composant <a href="https://sql.ophir.dev/documentation.sql?component=form#component"><code>form</code></a>. Dans <code>index.sql</code>, écrivons :</p>
<pre><code class="sql"><span class="k">SELECT</span>
<span class="s1">'form'</span> <span class="k">as</span> <span class="n">component</span><span class="p">,</span>
<span class="s1">'Nouveau compte partagé'</span> <span class="k">as</span> <span class="n">title</span><span class="p">,</span>
<span class="s1">'Créer le compte de dépenses partagé !'</span> <span class="k">as</span> <span class="n">validate</span><span class="p">;</span></code></pre>
<p>Cela crée un formulaire, vide, que l'on peut déjà voir dans notre navigateur ! Maintenant, ajoutons un champ dans le formulaire. Immédiatement à la suite de la requête précédente, ajoutons:</p>
<pre><code class="sql"><span class="k">SELECT</span> <span class="s1">'Nom du compte'</span> <span class="k">AS</span> <span class="n">label</span><span class="p">,</span> <span class="s1">'shared_expense_name'</span> <span class="k">AS</span> <span class="n">name</span><span class="p">;</span></code></pre>
<p>Rouvrons notre navigateur, et nous devrions maintenant voir cela :</p>
<p><img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f6173736574732f3535323632392f34643333636562302d343830642d346633342d616465362d356561666333303233383839/4d33ceb0-480d-4f34-ade6-5eafc3023889" alt="sqlpage form" title="Source : https://github.com/lovasoa/SQLpage/assets/552629/4d33ceb0-480d-4f34-ade6-5eafc3023889"></p>
<h4 id="toc-insertion-de-données-dans-la-base-de-données">Insertion de données dans la base de données</h4>
<p>Pour l'instant, lorsque l'on clique sur le bouton <em>Créer le compte de dépenses partagées</em>, il ne se passe rien. Corrigeons cela !</p>
<p>Toujours dans <code>index.sql</code>, à la fin de notre fichier, ajoutons une nouvelle requête SQL :</p>
<pre><code class="sql"><span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">expense_group</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
<span class="k">SELECT</span> <span class="p">:</span><span class="n">shared_expense_name</span> <span class="k">WHERE</span> <span class="p">:</span><span class="n">shared_expense_name</span> <span class="k">IS</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">;</span></code></pre>
<p>Ici, on utilise une requête de type <a href="https://www.sqlite.org/lang_insert.html"><code>INSERT INTO ... SELECT</code></a> pour insérer une nouvelle ligne dans la table <code>expense_group</code>. On ajoute une clause <code>WHERE</code> pour qu'une ligne ne soit insérée que lorsque l'utilisateur a rempli une valeur dans le formulaire, et pas à chaque fois que la page se charge.</p>
<p>La variable SQL <code>:shared_expense_name</code> sera associée à la valeur que l'utilisateur aura rentré dans le champ de texte que nous avons appelé <code>shared_expense_name</code> à l'étape précédente.</p>
<p>Maintenant, chaque validation de formulaire crée une nouvelle ligne dans notre base de données. Il est temps de créer notre premier composant dynamique, dont le contenu va dépendre de ce qu'il y a dans notre base de données. Toujours à la suite, dans <code>index.sql</code>:</p>
<pre><code class="sql"><span class="k">SELECT</span> <span class="s1">'list'</span> <span class="k">as</span> <span class="n">component</span><span class="p">;</span>
<span class="k">SELECT</span>
<span class="n">name</span> <span class="k">AS</span> <span class="n">title</span><span class="p">,</span>
<span class="s1">'group.sql?id='</span> <span class="o">||</span> <span class="n">id</span> <span class="k">AS</span> <span class="n">link</span>
<span class="k">FROM</span> <span class="n">expense_group</span><span class="p">;</span></code></pre>
<p>Ici, nous utilisons un nouvel élément issu de la <a href="https://sql.ophir.dev/documentation.sql">bibliothèque standard de SQLPage</a>: le composant <a href="https://sql.ophir.dev/documentation.sql?component=list#component"><code>list</code></a>. Après l'avoir sélectionné, nous le peuplons avec des données qui viennent de la table <code>expense_group</code> de notre base de données. Pour chaque élément de la liste, nous spécifions un lien vers lequel l'utilisateur sera emmené lorsqu'il cliquera dessus. Pour créer ce lien, nous <a href="https://www.geeksforgeeks.org/sql-concatenation-operator/">concaténons</a> le nom d'un nouveau fichier SQL que nous allons créer, avec une variable qui contient l'identifiant du groupe à afficher.</p>
<p><img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f6173736574732f3535323632392f38653331626633632d663132362d343738392d393231652d376134303364643164333166/8e31bf3c-f126-4789-921e-7a403dd1d31f" alt="Liste dynamique avec SQLPage" title="Source : https://github.com/lovasoa/SQLpage/assets/552629/8e31bf3c-f126-4789-921e-7a403dd1d31f"></p>
<h3 id="toc-amélioration-de-lapplication-création-de-nouvelles-pages">Amélioration de l'application, création de nouvelles pages</h3>
<p>Nous avons maintenant vu tous les éléments nécessaires à la construction d'une application. Il ne nous reste plus qu'à les appliquer à la création des pages restantes de notre application opensource.</p>
<p>Dans <code>group.sql</code>, réutilisons les composants from et list que nous connaissons maintenant :</p>
<pre><code class="sql"><span class="k">SELECT</span> <span class="s1">'title'</span> <span class="k">as</span> <span class="n">component</span><span class="p">,</span> <span class="n">name</span> <span class="k">as</span> <span class="n">contents</span>
<span class="k">FROM</span> <span class="n">expense_group</span> <span class="k">WHERE</span> <span class="n">id</span> <span class="o">=</span> <span class="err">$</span><span class="n">id</span><span class="p">;</span>
<span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">group_member</span><span class="p">(</span><span class="n">group_id</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
<span class="k">SELECT</span> <span class="err">$</span><span class="n">id</span><span class="p">,</span> <span class="p">:</span><span class="n">new_member_name</span> <span class="k">WHERE</span> <span class="p">:</span><span class="n">new_member_name</span> <span class="k">IS</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="s1">'list'</span> <span class="k">as</span> <span class="n">component</span><span class="p">,</span> <span class="s1">'Membres'</span> <span class="k">as</span> <span class="n">title</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="n">name</span> <span class="k">AS</span> <span class="n">title</span> <span class="k">FROM</span> <span class="n">group_member</span> <span class="k">WHERE</span> <span class="n">group_id</span><span class="o">=</span><span class="err">$</span><span class="n">id</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="s1">'form'</span> <span class="k">as</span> <span class="n">component</span><span class="p">,</span> <span class="s1">'Ajouter un membre au groupe'</span> <span class="k">as</span> <span class="n">validate</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="s1">'Nom du membre'</span> <span class="k">AS</span> <span class="s1">'label'</span><span class="p">,</span> <span class="s1">'new_member_name'</span> <span class="k">AS</span> <span class="n">name</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="s1">'title'</span> <span class="k">as</span> <span class="n">component</span><span class="p">,</span> <span class="s1">'Dépenses'</span> <span class="k">as</span> <span class="n">contents</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="s1">'form'</span> <span class="k">as</span> <span class="n">component</span><span class="p">,</span> <span class="s1">'Ajouter une dépense'</span> <span class="k">as</span> <span class="n">title</span><span class="p">,</span> <span class="s1">'Ajouter'</span> <span class="k">as</span> <span class="n">validate</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="s1">'Description'</span> <span class="k">AS</span> <span class="n">name</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="s1">'Montant'</span> <span class="k">AS</span> <span class="n">name</span><span class="p">,</span> <span class="s1">'number'</span> <span class="k">AS</span> <span class="k">type</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="s1">'select'</span> <span class="k">as</span> <span class="k">type</span><span class="p">,</span> <span class="s1">'Dépensé par'</span> <span class="k">AS</span> <span class="n">name</span><span class="p">,</span>
<span class="n">json_group_array</span><span class="p">(</span><span class="n">json_object</span><span class="p">(</span><span class="ss">"label"</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="ss">"value"</span><span class="p">,</span> <span class="n">id</span><span class="p">))</span> <span class="k">as</span> <span class="k">options</span>
<span class="k">FROM</span> <span class="n">group_member</span> <span class="k">WHERE</span> <span class="n">group_id</span> <span class="o">=</span> <span class="err">$</span><span class="n">id</span><span class="p">;</span>
<span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">expense</span><span class="p">(</span><span class="n">spent_by</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">amount</span><span class="p">)</span>
<span class="k">SELECT</span> <span class="p">:</span><span class="ss">"Dépensé par"</span><span class="p">,</span> <span class="p">:</span><span class="n">Description</span><span class="p">,</span> <span class="p">:</span><span class="n">Montant</span> <span class="k">WHERE</span> <span class="p">:</span><span class="n">Montant</span> <span class="k">IS</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="s1">'card'</span> <span class="k">as</span> <span class="n">component</span><span class="p">,</span> <span class="s1">'Dépenses'</span> <span class="k">as</span> <span class="n">title</span><span class="p">;</span>
<span class="k">SELECT</span>
<span class="n">expense</span><span class="p">.</span><span class="n">name</span> <span class="k">as</span> <span class="n">title</span><span class="p">,</span>
<span class="s1">'Par '</span> <span class="o">||</span> <span class="n">group_member</span><span class="p">.</span><span class="n">name</span> <span class="o">||</span> <span class="s1">', le '</span> <span class="o">||</span> <span class="n">expense</span><span class="p">.</span><span class="nb">date</span> <span class="k">as</span> <span class="n">description</span><span class="p">,</span>
<span class="n">expense</span><span class="p">.</span><span class="n">amount</span> <span class="o">||</span> <span class="s1">' €'</span> <span class="k">as</span> <span class="n">footer</span><span class="p">,</span>
<span class="k">CASE</span> <span class="k">WHEN</span> <span class="n">expense</span><span class="p">.</span><span class="n">amount</span> <span class="o">></span> <span class="mi">100</span> <span class="k">THEN</span> <span class="s1">'red'</span> <span class="k">WHEN</span> <span class="n">expense</span><span class="p">.</span><span class="n">amount</span> <span class="o">></span> <span class="mi">50</span> <span class="k">THEN</span> <span class="s1">'orange'</span> <span class="k">ELSE</span> <span class="s1">'blue'</span> <span class="k">END</span> <span class="k">AS</span> <span class="n">color</span>
<span class="k">FROM</span> <span class="n">expense</span>
<span class="k">INNER</span> <span class="k">JOIN</span> <span class="n">group_member</span> <span class="k">on</span> <span class="n">expense</span><span class="p">.</span><span class="n">spent_by</span> <span class="o">=</span> <span class="n">group_member</span><span class="p">.</span><span class="n">id</span>
<span class="k">WHERE</span> <span class="n">group_member</span><span class="p">.</span><span class="n">group_id</span> <span class="o">=</span> <span class="err">$</span><span class="n">id</span><span class="p">;</span></code></pre>
<p>Nous avons ici créé une seule page, qui contient plusieurs listes et plusieurs formulaires, juste en écrivant nos requêtes SQL les unes après les autres dans notre fichier. </p>
<p>Le seul point particulier à noter, qui est différent de ce que nous avons vu avant, est l'utilisation de la fonction sql <a href="https://www.sqlite.org/json1.html#jgrouparray"><code>json_group_array</code></a> pour remplir la valeur du champ de formulaire à choix multiple, qui prend un tableau json comme valeur.</p>
<p>Nous arrivons au résultat suivant :</p>
<p><img src="//img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6c6f7661736f612f53514c706167652f6173736574732f3535323632392f31316338366331652d336261642d343364312d393162622d326538396465313731613037/11c86c1e-3bad-43d1-91bb-2e89de171a07" alt="screenshot sqlpage" title="Source : https://github.com/lovasoa/SQLpage/assets/552629/11c86c1e-3bad-43d1-91bb-2e89de171a07"></p>
<h4 id="toc-cerise-sur-le-gâteau--calcul-des-dettes">Cerise sur le gâteau : calcul des dettes</h4>
<p>Une fonctionnalité pratique de l'application originelle est le calcul du tableau de dette. L'application fait elle-même le calcul final de qui doit combien. C'est un peu moins trivial que les requêtes classiques de listage de données que l'on a vues jusqu'ici, mais on peut aussi implémenter cela entièrement en SQL.</p>
<p>On crée quelques <a href="https://fr.wikipedia.org/wiki/Vue_(base_de_donn%C3%A9es)">vues</a> qui nous seront utiles pour nos calculs. </p>
<p>Dans SQLPage, on ne crée en général pas de fonctions, et on n'importe pas des bibliothèques. Pour construire une fonctionnalité complexe, le plus simple est de construire des vues successives de nos données, dans lesquelles on les groupe et les filtre comme on le suite. Ici, on construit les trois vues simples suivantes, chacune avec sa fonction SQL :</p>
<ul>
<li>
<a href="https://github.com/lovasoa/SQLpage/blob/main/examples/splitwise/sqlpage/migrations/0001_views.sql#L3-L9"><code>members_with_expenses</code></a>, qui va lier nos tables entre elles pour associer les noms des membres à leurs montants de dépenses.</li>
<li>
<a href="https://github.com/lovasoa/SQLpage/blob/main/examples/splitwise/sqlpage/migrations/0001_views.sql#L12-L16"><code>average_debt_per_person</code></a> qui va diviser le montant total dépensé par le groupe par le nombre de participants.</li>
<li>
<a href="https://github.com/lovasoa/SQLpage/blob/main/examples/splitwise/sqlpage/migrations/0001_views.sql#L19-L27"><code>individual_debts</code></a> qui va soustraire la dépense moyenne aux dépenses personnelles de chacun, pour savoir combien il doit ou combien on lui doit. </li>
</ul>
<p>Ici c'est du SQL classique, il n'y a rien qui soit propre à SQLPage. Je vous laisse lire <a href="https://github.com/lovasoa/SQLpage/blob/main/examples/splitwise/sqlpage/migrations/0001_views.sql">les 27 lignes de code sur github</a>. </p>
<h2 id="toc-conclusion">Conclusion</h2>
<p>Nous avons vu comment construire une application web complète entièrement en SQL grâce à SQLPage. Nous pouvons maintenant la faire tourner sur un tout petit serveur chez nous, dans le cloud, ou même <a href="https://github.com/lovasoa/SQLpage#serverless">en mode sans-serveur</a>. SQLPage est écrit dans le langage de programmation <em>rust</em> et consomme très peu de resources par rapport à une application web classique, l'application sera donc très peu chère à héberger.</p>
<h4 id="toc-pour-résumer-ce-que-nous-avons-vu">Pour résumer ce que nous avons vu</h4>
<p>Nous avons tout d'abord <a href="#toc-premi%C3%A8re-%C3%A9tape-choisir-un-sch%C3%A9ma-pour-notre-base-de-donn%C3%A9es">créé une structure de base de données grâce aux migrations</a>.</p>
<p>Ensuite, nous avons affiché des composants graphiques grâce à la <a href="https://sql.ophir.dev/documentation.sql">bibliothèque de composants intégrés</a> de SQLPage.</p>
<p>Enfin, nous avons inséré des données dynamiquement dans notre base de données grâce au système de variables de SQLPage.</p>
<h4 id="toc-pour-aller-plus-loin">Pour aller plus loin</h4>
<p>SQLPage est un logiciel libre et gratuit. Si vous rencontrez des problèmes lors de son utilisation, n'hésitez pas à <a href="https://github.com/lovasoa/SQLpage/issues">rapporter un bug ou demander une fonctionnalité sur github</a>, ou à discuter de son utilisation sur les <a href="https://github.com/lovasoa/SQLpage/discussions">pages de discussion</a>.</p>
<p>Et si vous cherchez une idée pour vous entraîner… Pourquoi pas un <a href="//linuxfr.org/wiki/taptempo">TapTempo</a> entièrement en SQL ?</p>
</div><div><a href="https://linuxfr.org/news/ecrire-une-appli-web-en-une-journee-avec-sqlpage.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/131690/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/ecrire-une-appli-web-en-une-journee-avec-sqlpage#comments">ouvrir dans le navigateur</a>
</p>
lovasoaNÿcoBenoît SibaudgUIBAudbobble bubblehttps://linuxfr.org/nodes/131690/comments.atomtag:linuxfr.org,2005:News/404832021-05-17T00:30:22+02:002021-05-17T00:30:22+02:00Sanipasse : le déconfinement libre !Licence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>Je suis fier de vous présenter aujourd’hui l’application <a href="https://sanipasse.fr"><strong>sanipasse</strong></a>.</p>
<h3 id="toc-les-passes-sanitaires">Les passes sanitaires</h3>
<p>Aujourd’hui, lorsque l’on se fait tester ou vacciner contre le COVID-19, on reçoit une attestation numérique, sous forme d’un QR code, qui prouve que l’on n’est pas contagieux.</p>
<p>Jusqu’à aujourd’hui, la seule application qui permettait de lire ces codes était le fameux TousAntiCovid, qui permet seulement d’importer son certificat sanitaire dans son application, et n’affiche pas la totalité des informations contenues dans le certificat. </p>
<p>L’application officielle de vérification de ces certificats, <em>TousAntiCovid-Vérif</em> est propriétaire, n’est pas publique, et la sécurité de son implémentation ne peut pas être vérifiée. Elle n’est, aujourd’hui, pas disponible aux petits organisateurs d’évènements privés, qui souhaiteraient pouvoir vérifier les certificats de leurs invités.</p>
<p>J’ai donc décidé de créer une nouvelle application, et je l’ai appelée <a href="https://sanipasse.fr">sanipasse</a>.</p>
</div><ul><li>lien nᵒ 1 : <a title="https://sanipasse.fr" hreflang="fr" href="https://linuxfr.org/redirect/108515">Site Officiel</a></li><li>lien nᵒ 2 : <a title="https://github.com/lovasoa/sanipasse" hreflang="en" href="https://linuxfr.org/redirect/108516">Code Source</a></li></ul><div><h3 id="toc-lapplication">L’application</h3>
<p>Sanipasse, c’est un logiciel libre de lecture des passes sanitaires. C’est un logiciel qui s’utilise directement depuis son navigateur web, et a deux usages principaux.</p>
<h4 id="toc-usage-personnel">Usage personnel</h4>
<p>Avec sanipasse, on peut désormais consulter et vérifier toutes les informations contenues dans les codes barres de son passe sanitaire.<br>
Si quelqu’un vous demande votre passe sanitaire, vous saurez désormais exactement quelles informations vous lui fournissez.</p>
<h4 id="toc-usage-pour-organiser-un-évènement-privé">Usage pour organiser un évènement privé</h4>
<p>En tant qu’organisateur d’évènement privé, on peut créer une liste d’invités sur sanipasse.<br>
L’application va alors générer un lien à communiquer aux invités, pour qu’ils puissent s’enregistrer. Ils ne pourront s’enregistrer qu’avec un passe sanitaire valide.<br>
Ensuite, on n’a plus à vérifier manuellement les passes à l’entrée de l’évènement: on peut simplement consulter la liste des invités validés sur sanipasse. </p>
<h3 id="toc-données-personnelles">Données personnelles</h3>
<p>Lorsque vous vérifiez un passe sanitaire, tout le processus se déroule dans votre navigateur, et votre passe sanitaire n’est jamais envoyé au serveur de sanipasse.</p>
<p>Lorsque vous participez à un évènement, le passe doit être envoyé au serveur pour pouvoir être vérifié sans qu’il soit possible de frauder, mais il n’est jamais stocké. Il reste juste en mémoire sur le serveur pendant quelques millisecondes le temps de la vérification.<br>
L’organisateur de l’évènement ne voit pas votre passe sanitaire, il voit uniquement une donnée binaire : si oui ou non il a été validé. </p>
<p>Et si vous êtes paranoïaque, vous pouvez même héberger sanipasse sur votre propre serveur. </p>
<h4 id="toc-plus-dinformations">Plus d’informations</h4>
<p>J’ai écrit une petite documentation pour l’application, qui répond aux questions que l’on peut se poser sur son fonctionnement. Elle est disponible sur <a href="https://sanipasse.fr/apropos">https://sanipasse.fr/apropos</a></p>
<h5 id="toc-partagez">Partagez</h5>
<p>Si vous connaissez des associations, des commerçants, ou d’autres personnes susceptibles d’être intéressées, n’hésitez pas à leur donner le lien de sanipasse.</p>
<p>Je serais ravi de recevoir des retours d’expérience et des suggestions d’amélioration sur <code>contact at ophir.dev</code></p>
<h3 id="toc-réalisation-technique">Réalisation technique</h3>
<p>L’application utilise le formidable compilateur <a href="https://svelte.dev">svelte</a>, qui permet à un développeur seul d’être très productif, et génère des webapps très performantes.<br>
J’utilise <a href="https://kit.svelte.dev/">SvelteKit</a> pour le partage très simple de code entre le serveur et le client.</p>
<p>J’ai implémenté le standard DataMatrix <a href="https://ants.gouv.fr/Les-solutions/2D-Doc">2DDOC</a> de l’Agence nationale des titres sécurisés en une centaine de lignes de typescript seulement, et la vérification des signatures numériques utilise <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API">WebCrypto</a>, l’ensemble de primitives de cryptographie fourni par les navigateurs web.</p>
</div><div><a href="https://linuxfr.org/news/sanipasse-le-deconfinement-libre.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/124290/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/sanipasse-le-deconfinement-libre#comments">ouvrir dans le navigateur</a>
</p>
lovasoaYsabeau 🧶 🧦https://linuxfr.org/nodes/124290/comments.atomtag:linuxfr.org,2005:News/389232018-11-28T19:14:18+01:002018-11-29T20:05:17+01:00WBO : un tableau blanc interactifLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>WBO est une application Web de <strong>dessin collaboratif</strong> en temps réel (licence GPL v3). Est‐ce qu’il vous est déjà arrivé de passer plusieurs minutes à expliquer un concept simple lors d’une vidéoconférence alors qu’un petit schéma aurait suffi ? WBO résout ce problème en permettant la création de croquis partagés <em>en temps réel</em> entre plusieurs utilisateurs.</p>
</div><ul><li>lien nᵒ 1 : <a title="https://wbo.openode.io/" hreflang="fr" href="https://linuxfr.org/redirect/103133">Démonstration de l’application Web WBO</a></li><li>lien nᵒ 2 : <a title="https://github.com/lovasoa/whitebophir" hreflang="fr" href="https://linuxfr.org/redirect/103134">Le code source sur GitHub</a></li></ul><div><h2 id="toc-fonctionnalités">Fonctionnalités</h2>
<p>WBO est un outil de dessin <strong>vectoriel</strong>, ce qui signifie que l’on peut zoomer autant que l’on veut sur le tableau blanc sans qu’il n’apparaisse jamais pixelisé. L’interface graphique est très simple et essaie de laisser beaucoup de place au contenu.</p>
<p><img src="//img.linuxfr.org/img/68747470733a2f2f757365722d696d616765732e67697468756275736572636f6e74656e742e636f6d2f3535323632392f34393134303136332d64643632393430302d663266332d313165382d396664652d3638653263326430616163652e706e67/49140163-dd629400-f2f3-11e8-9fde-68e2c2d0aace.png" alt="Capture d’écran de l’interface graphique de Whitebophir" title="Source : https://user-images.githubusercontent.com/552629/49140163-dd629400-f2f3-11e8-9fde-68e2c2d0aace.png"></p>
<p>Il y a pour l’instant six outils disponibles :</p>
<ol>
<li>le <em>crayon</em>, pour dessiner à main levée ;</li>
<li>l’outil de <em>texte</em>, pour écrire de courtes lignes de texte ;</li>
<li>l’<em>effaceur</em>, comme le dessin est vectoriel, l’effaceur efface le dessin « par morceaux », il supprime tout l’élément sur lequel il est appliqué ;</li>
<li>
<em>ligne droite</em>, qui permet de dessiner une ligne ; la ligne apparaît immédiatement sur le tableau de tous les participants dès qu’elle est commencée ;</li>
<li>
<em>rectangle</em>, pour dessiner des rectangles.</li>
</ol>
<p>On peut en outre choisir la taille et la couleur de l’élément que l’on dessine.</p>
<h2 id="toc-détails-techniques">Détails techniques</h2>
<p>L’application est entièrement réalisée en JavaScript, sans cadriciel, ni du côté client, ni du côté serveur. Son architecture est très simple.</p>
<h3 id="toc-serveur">Serveur</h3>
<p>Le serveur est écrit en <em>Node.js</em>. Il utilise la bibliothèque <em><a href="https://socket.io/">socket.io</a></em> pour communiquer en temps réel avec tous les clients connectés. Cela permet d’établir une connexion en temps réel avec les navigateurs récents qui gèrent les <a href="https://fr.wikipedia.org/wiki/WebSocket">WebSockets</a>, mais aussi de prendre en charge les navigateurs anciens en mode dégradé.</p>
<p>Chaque fois qu’un client émet un évènement (parce que l’utilisateur a ajouté un nouveau point dans la ligne qu’il est en train de tracer, par exemple), le serveur se contente de le diffuser à tous les autres clients connectés et d’enregistrer l’évènement dans un fichier.</p>
<p>Lorsqu’un nouveau client se connecte à un tableau, le serveur lui envoie la liste de tous les évènements passés associés à ce tableau. C’est le client qui se chargera de transformer les évènements en dessin.</p>
<p>Le serveur est aussi capable de générer lui‐même une image à partir des évènements d’un tableau, ce qui lui permet de fournir des <em>aperçus</em> des tableaux.</p>
<h3 id="toc-client">Client</h3>
<p>Le client est plus complexe que le serveur. C’est lui qui doit se charger du dessin en temps réel, à la fois de la part de l’utilisateur du navigateur et des autres utilisateurs connectés de la part desquels il reçoit des évènements.</p>
<p>Le code du client est autant que possible séparé en <em>outils</em> indépendants, chacun correspondant à un type de dessin (ligne, texte, rectangle…). Chaque outil peut déclarer les propriétés suivantes :</p>
<ul>
<li>un nom ;</li>
<li>une icône ;</li>
<li>un <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/cursor">style de curseur</a> ;</li>
<li>une <strong>fonction de dessin</strong> ;</li>
<li>un triplet de fonctions à appeler respectivement lorsque le bouton de la souris est pressé, lorsque la souris se déplace et lorsque le bouton de la souris est relâché.</li>
</ul>
<p>La <strong>fonction de dessin</strong> prend en paramètre un évènement (qui peut venir de l’utilisateur local ou d’un autre utilisateur connecté) et modifie l’élément <em>SVG</em> de la page actuelle pour refléter les modifications décrites dans l’évènement (comme ajouter un point à une ligne, par exemple).</p>
<p>Les fonctions appelées lors d’un appui de souris ne dessinent rien. Elles se contentent d’émettre des évènements. Ces évènements seront alors, d’une part, émis vers le serveur et, d’autre part, envoyés vers les fonctions de dessin local. Chaque évènement contient l’identifiant de l’outil qui l’a émis, de manière à pouvoir l’envoyer à la bonne fonction de dessin.</p>
<h2 id="toc-conclusion">Conclusion</h2>
<p>J’espère que cet outil pourra vous être utile. Je vous encourage également à <a href="https://github.com/lovasoa/whitebophir">aller regarder son code source</a> : il est plutôt court et simple ; ajouter un nouvel outil se fait en quelques heures tout au plus. Toutes les demandes d’intégration (<em>pull requests</em>) sont les bienvenues ! Je suis également preneur de toute suggestion que vous pourriez faire en commentaire.</p>
</div><div><a href="https://linuxfr.org/news/wbo-un-tableau-blanc-interactif.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/115837/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/wbo-un-tableau-blanc-interactif#comments">ouvrir dans le navigateur</a>
</p>
lovasoaZeroHeureDavy DefaudJulien Jorgepalm123https://linuxfr.org/nodes/115837/comments.atomtag:linuxfr.org,2005:News/354612014-06-15T11:33:49+02:002014-06-15T13:22:55+02:00Retour d'expérience sur sql.jsLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>J'aimerais parler ici de mon expérience lors du développement de <a href="https://github.com/lovasoa/sql.js">sql.js</a>, un port de <a href="http://sqlite.org">SQLite</a> en JavaScript. Pour ceux qui ne s’intéressent pas aux technologies du web, la deuxième partie de cette dépêche pourrait quand même vous intéresser, on va parler de SQLite.</p>
<p>Note : cette dépêche a initialement été postée <a href="//linuxfr.org/users/lovasoa/journaux/web-moderne-bases-de-donnees-et-beaute-logiciel-libre">en tant que journal</a>.</p></div><ul><li>lien nᵒ 1 : <a title="https://github.com/lovasoa/sql.js" hreflang="en" href="https://linuxfr.org/redirect/90784">Page GitHub du Projet</a></li><li>lien nᵒ 2 : <a title="http://lovasoa.github.io/sql.js/GUI" hreflang="en" href="https://linuxfr.org/redirect/90785">Démonstation, qui permet d’exécuter du SQL, mais aussi de lire, modifier, puis sauvegarder des bases</a></li><li>lien nᵒ 3 : <a title="http://emscripten.org" hreflang="en" href="https://linuxfr.org/redirect/90786">Page officielle de emscripten</a></li><li>lien nᵒ 4 : <a title="http://sqlite.org" hreflang="en" href="https://linuxfr.org/redirect/90787">SQLite, le SGBD le plus cool qui soit</a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><a href="#web-moderne">Web moderne</a></li>
<li><a href="#sqlite">SQLite</a></li>
<li>
<a href="#quand-on-m%C3%A9lange-les-deux">Quand on mélange les deux…</a><ul>
<li><a href="#sqljs-avant">sql.js, avant</a></li>
<li><a href="#sqljs-maintenant">sql.js, maintenant</a></li>
<li><a href="#comment-%C3%A7a-marche">Comment ça marche</a></li>
</ul>
</li>
<li><a href="#conclusion">Conclusion</a></li>
</ul><h2 id="web-moderne">Web moderne</h2>
<p>Ceux d'entre vous qui s'intéressent aux technologies modernes du web ont certainement entendu parler d’<a href="http://emscripten.org">emscripten</a> et d’<a href="http://asmjs.org">asm.js</a>.</p>
<p>Emscripten est un compilateur de bytecode LLVM en JavaScript. Il permet de compiler du code C ou C++ en JavaScript, très simplement. Le code JavaScript généré n’est bien sûr pas aussi rapide que le code natif équivalent, mais les performances sont assez bonnes. Sur Firefox, avec asm.js, le code tourne à peu près deux fois plus lentement que la version native. Le principal inconvénient que je trouve à emscripten est qu'il faut, pour l'utiliser sous Linux, télécharger et compiler <a href="https://github.com/kripken/emscripten-fastcomp">sa propre version de LLVM et de clang</a>, ce qui est long et pas pratique à mettre à jour.</p>
<p><a href="http://asmjs.org">asm.js</a>, quant à lui, est un sous-ensemble de JavaScript conçu pour être facile à optimiser, et ainsi pouvoir s'exécuter rapidement. La syntaxe est <a href="http://asmjs.org/spec/latest/#putting-it-all-together">dégueulasse</a>, mais c'est pas grave, emscripten génère du code asm.js pour nous.</p>
<h2 id="sqlite">SQLite</h2>
<p>Vous connaissez certainement déjà <a href="https://fr.wikipedia.org/wiki/Sqlite">SQLite3</a>, le moteur de bases de données le plus utilisé au monde. Si vous vous y êtes déjà un peu intéressé, vous connaissez sûrement ses caractéristiques, qui le rendent unique :</p>
<ul>
<li>Une base de données est stockée dans un seul fichier.</li>
<li>Le binaire SQLite est minuscule (moins d'un Mo), et la bibliothèque SQLite peut être liée statiquement dans votre programme. Tout le code source tient dans un fichier <code>sqlite3.c</code> de 5 Mo.</li>
<li>Le code a été placé dans le domaine public.</li>
<li>Les données sont typées dynamiquement. Une même colonne peut contenir un entier, un nombre à virgule flottante, et une chaîne de caractères, par exemple.</li>
</ul><p>Par contre, vous ne connaissez peut-être pas <a href="http://sqlite.org/src4/doc/trunk/www/design.wiki">SQLite4</a>, une évolution de SQLite3 (par les mêmes développeurs), qui n’a pas encore de version stable (et que j’ai aussi <a href="https://github.com/lovasoa/sql.js/tree/sqlite4">porté en JavaScript</a>). Cette version apporte de bien meilleures performances, et surtout, elle utilise un système de base de données de type clef-valeur, que l'on peut changer à la volée.</p>
<p>Et ça, c’est génial ! Cela signifie que l'on pourra bientôt profiter de tous les avantages de SQLite même pour de grosses bases de données. Il suffira d’utiliser un système de base de données clef-valeur qui supporte les grands ensembles de données, comme <a href="http://leveldb.googlecode.com/svn/trunk/doc/index.html">LevelDB</a>.</p>
<h2 id="quand-on-mélange-les-deux">Quand on mélange les deux…</h2>
<h3 id="sqljs-avant">sql.js, avant</h3>
<p><code>sql.js</code>, un port de SQLite en JavaScript, était au départ un projet de <a href="https://github.com/kripken">kripken</a>, le créateur et principal mainteneur d’emscripten, qui date de début 2012. Le port fonctionnait, mais question fonctionnalités, on restait un peu sur sa faim : une seule méthode <code>db.exec</code>, qui exécutait du SQL et retournait les résultats dans un format pas pratique. Les données étaient toujours converties en chaînes de caractères avant d’être retournées. Le projet n’avait aucun test unitaire, le dernier commit date d’il y a plus d’un an, et l’auteur ne répond plus sur le bugtracker… (NdM.: voir le commentaire indiquant que l'auteur <a href="//linuxfr.org/news/retour-d-experience-sur-sql-js#comment-1543841">a depuis incorporé la contribution</a>)</p>
<p>Pourtant, le projet semble avoir des utilisateurs. 104 forks et 883 <em>stars</em> sur github, et plusieurs téléchargements par jour sur <a href="https://www.npmjs.org/package/node-sqlite-purejs">npm</a> à l’heure où j’écris ces lignes.</p>
<h3 id="sqljs-maintenant">sql.js, maintenant</h3>
<p>Je suis étudiant, et lors d’un TD, j’ai eu besoin de pouvoir tester des commandes en SQL, sur un ordi avec rien du tout d’installé. Je ne connaissais pas encore <a href="http://sqlfiddle.com/">SQLfiddle</a>, mais j’avais déjà entendu parler de sql.js, donc j’ai utilisé sa <a href="http://kripken.github.io/sql.js/test/demo.html">démonstration en ligne</a>.</p>
<p>Le soir, en rentrant chez moi, très agaçé des petits défauts de la démonstration que j'avais utilisée, j'ai <em>forké</em> le projet, et commencé à travailler sur une meilleure interface graphique. Quand j'ai été content de moi, j’ai fait une <em>pull request</em>. Comme l’auteur tardait à répondre, j’ai commencé à bidouiller le reste du code. Et de fil en aiguille, j'ai fini par réécrire tout le code, à changer l’API pour avoir quelque chose de facile à utiliser, à ajouter des tests, de la documentation… Et je suis assez fier de l’état du projet aujourd’hui.</p>
<p>Il est utilisable sans modification à la fois depuis node.js, dans le navigateur, et en tant que web worker. Il est <a href="https://npmjs.org/package/sql.js">disponible sur npm</a>, et s’utilise avec un simple :</p>
<pre><code class="javascript"><span class="kd">var</span> <span class="nx">sql</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'sql.js'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">db</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">sql</span><span class="p">.</span><span class="nx">Database</span><span class="p">();</span></code></pre>
<p>Il retourne les données dans leur format original, y-compris les BLOBs, retournés sous forme de tableau d’octets :</p>
<pre><code class="javascript"><span class="kd">var</span> <span class="nx">res</span> <span class="o">=</span> <span class="nx">db</span><span class="p">.</span><span class="nx">exec</span><span class="p">(</span><span class="s2">"SELECT * FROM table1; SELECT * FROM table2"</span><span class="p">);</span>
<span class="c1">// Ce qui peut retourner:</span>
<span class="p">[</span>
<span class="p">{</span><span class="nx">columns</span><span class="o">:</span><span class="p">[</span><span class="s1">'a'</span><span class="p">,</span><span class="s1">'b'</span><span class="p">],</span> <span class="nx">values</span><span class="o">:</span><span class="p">[[</span><span class="mi">0</span><span class="p">,</span><span class="s1">'hello'</span><span class="p">],[</span><span class="mi">1</span><span class="p">,</span><span class="s1">'world'</span><span class="p">]]},</span> <span class="c1">//Le contenu de table1</span>
<span class="p">{</span><span class="nx">columns</span><span class="o">:</span><span class="p">[</span><span class="s1">'c'</span><span class="p">,</span><span class="s1">'d'</span><span class="p">],</span> <span class="nx">values</span><span class="o">:</span><span class="p">[[</span><span class="kc">null</span><span class="p">,[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">]],[</span><span class="mi">42</span><span class="p">,</span><span class="s1">'blabla'</span><span class="p">],[</span><span class="mi">666</span><span class="p">,</span><span class="mi">666</span><span class="p">]]}</span> <span class="c1">//Celui de table2</span>
<span class="c1">// Et oui, la colonne d contient des données de types différents. C’est possible grâce à SQLite. C’est impossible avec presque tous les autres SGBD</span>
<span class="p">]</span></code></pre>
<p>Et il permet d'utiliser des requêtes préparées (<em>prepared statements</em>), auxquelles on associe les paramètres que l'on veut, sans risquer de vilaines injections SQL :</p>
<pre><code class="javascript"><span class="nx">db</span><span class="p">.</span><span class="nx">run</span><span class="p">(</span><span class="s2">"INSERT INTO table1 VALUES (?,?)"</span><span class="p">,</span> <span class="p">[</span><span class="mi">3</span><span class="p">,[</span><span class="mi">121</span><span class="p">,</span><span class="mi">111</span><span class="p">,</span><span class="mi">117</span><span class="p">,</span><span class="mi">99</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">97</span><span class="p">,</span><span class="mi">99</span><span class="p">,</span><span class="mi">107</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">116</span><span class="p">]]);</span></code></pre>
<p>Mais aussi :</p>
<pre><code class="javascript"><span class="kd">var</span> <span class="nx">stmt</span> <span class="o">=</span> <span class="nx">db</span><span class="p">.</span><span class="nx">prepare</span><span class="p">(</span><span class="s2">"SELECT * FROM table1 WHERE a=$aval AND b=$bval"</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">stmt</span><span class="p">.</span><span class="nx">getAsObject</span><span class="p">({</span><span class="nx">$aval</span> <span class="o">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">$bval</span> <span class="o">:</span> <span class="s1">'world'</span><span class="p">});</span>
<span class="c1">// result contient maintenant:</span>
<span class="p">{</span><span class="nx">a</span><span class="o">:</span><span class="mi">1</span><span class="p">,</span> <span class="nx">b</span><span class="o">:</span><span class="s1">'world'</span><span class="p">}</span></code></pre>
<h3 id="comment-ça-marche">Comment ça marche</h3>
<p>SQLite est distribué sous différentes formes, dont une qui est particulièrement pratique : l’<em>amalgamation</em>. C’est un unique fichier <code>.c</code> de 5Mo qui contient tout le code, et que l’on peut compiler sans aucune bibliothèque externe:</p>
<p><code>gcc -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_THREADSAFE=0 -c sqlite3.c</code></p>
<p>Et on peut aussi le compiler, sans aucune modification, avec emscripten. Il suffit de remplacer <code>gcc</code> par <code>emcc</code> dans la commande précédente, et le tour est joué.</p>
<p>Vous allez peut-être trouver bizarre que ça <em>juste marche</em>. En effet, le code de SQLite fait plein de trucs que l’on ne peut pas faire de base en JavaScript dans un navigateur, comme par exemple ouvrir des fichiers, ou simplement accéder à la mémoire à partir de pointeurs.</p>
<p>Heureusement, emscripten s’occupe de tout ça pour nous. Il fabrique un grand tableau d’entiers en JavaScript qui contiendra toute la mémoire de notre programme. Les performances ne sont pas trop mauvaises grâce aux <em>[typed arrays (<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays</a>)</em>. Les pointeurs ne sont dès lors plus que des index dans ce tableau. Il implémente également les fonctions <code>fopen</code>, <code>fwrite</code>, etc. en émulant un système de fichiers entièrement en mémoire. L’inconvénient étant bien sûr que l’on a beaucoup moins de place pour stocker ses données.</p>
<p>Mon travail consiste alors uniquement à définir les bonnes options de compilation, et à écrire le code qui va faire l’interface entre les programmes en JavaScript et le code compilé, en JavaScript lui aussi. En effet, appeler directement le code résultant de la compilation par emscripten serait terriblement rebutant : ça parle de pointeurs partout, il faut allouer et désallouer de la mémoire dès que l’on veut faire des trucs compliqués, on n’a accès qu’à une série de fonctions, et pas à des objets qui contiennent des méthodes…</p>
<p>Pour avoir un code un peu plus léger, j’ai choisi le <a href="http://coffeescript.org">CoffeeScript</a>, langage par excellence du web moderne.</p>
<p>Pour vous donner un exemple du genre de code qui fait l’interface, voilà la fonction <code>prepare</code>, qui permet de créer une requête préparée :</p>
<pre><code class="coffeescript"> <span class="s">'prepare'</span><span class="o">:</span> <span class="nf">(sql, params) -></span>
<span class="nx">setValue</span> <span class="nx">apiTemp</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">'i32'</span>
<span class="nx">@handleError</span> <span class="nx">sqlite3_prepare_v2</span> <span class="nx">@db</span><span class="p">,</span> <span class="nx">sql</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="nx">apiTemp</span><span class="p">,</span> <span class="nx">NULL</span>
<span class="nv">pStmt = </span><span class="nx">getValue</span> <span class="nx">apiTemp</span><span class="p">,</span> <span class="s">'i32'</span> <span class="c1"># pointer to a statement, or null</span>
<span class="k">if</span> <span class="nx">pStmt</span> <span class="o">is</span> <span class="nx">NULL</span> <span class="k">then</span> <span class="k">throw</span> <span class="s">'Nothing to prepare'</span>
<span class="nv">stmt = </span><span class="k">new</span> <span class="nx">Statement</span> <span class="nx">pStmt</span><span class="p">,</span> <span class="k">this</span>
<span class="k">if</span> <span class="nx">params</span><span class="o">?</span> <span class="k">then</span> <span class="nx">stmt</span><span class="p">.</span><span class="nx">bind</span> <span class="nx">params</span>
<span class="nx">@statements</span><span class="p">.</span><span class="nx">push</span> <span class="nx">stmt</span>
<span class="k">return</span> <span class="nx">stmt</span></code></pre>
<p>On voit bien que tout le vrai travail est fait par les fonctions compilées de SQLite, mon code se contentant de la gestion des erreurs, de la mémoire, et de la conversion des données dans un format utile au programmeur JavaScript.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Aujourd’hui, on fait tout ce qu’on veut sur le web, et bientôt, ce sera encore mieux. Les trucs funs qui sont pour bientôt : <a href="http://tc39wiki.calculist.org/es6/">ECMASCRIPT 6, aka Harmony</a>, <a href="https://github.com/kripken/emscripten/wiki/Emscripten-SDK">emscripten SDK</a> pour Linux, <a href="https://github.com/lovasoa/sql.js/tree/sqlite4">sqlite4.js</a>…</p></div><div><a href="https://linuxfr.org/news/retour-d-experience-sur-sql-js.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/102471/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/retour-d-experience-sur-sql-js#comments">ouvrir dans le navigateur</a>
</p>
lovasoaNÿcoZeroHeurepalm123Benoît SibaudNils Ratusznikhttps://linuxfr.org/nodes/102471/comments.atom