Dans un client de base de données, la grille de résultats est le composant le plus sollicité. C'est là que le développeur passe l'essentiel de son temps : parcourir des résultats, trier des colonnes, modifier une valeur. Si la grille rame sur 10 000 lignes ou si le tri recharge toute la page, l'outil devient un frein. Dans QoreDB, le Data Grid est conçu pour rester fluide sur des jeux de données volumineux, tout en offrant des interactions riches comme le tri délégué au moteur et l'édition inline.
Virtualisation DOM : ne rendre que ce qui est visible
Le principe de la virtualisation est simple : si l'écran affiche 30 lignes, inutile de créer 100 000 nœuds DOM. QoreDB utilise TanStack Virtual pour ne matérialiser dans le DOM que les lignes visibles, plus un buffer de 10 lignes en amont et en aval (l'overscan). Le reste de l'espace est occupé par deux éléments espaceurs dont la hauteur correspond à la somme des lignes non rendues. Quand l'utilisateur scrolle, les lignes sortantes sont détruites et de nouvelles sont créées de l'autre côté. Le tout repose sur une estimation fixe de 32 pixels par ligne, ce qui permet au moteur de virtualisation de calculer instantanément quelles lignes rendre pour une position de scroll donnée.
Cette approche a un coût : les lignes de hauteur variable ne sont pas supportées nativement. En pratique, pour un Data Grid tabulaire, les lignes ont une hauteur constante, ce qui rend l'estimation fixe parfaitement adaptée. Le gain est immédiat : un tableau de 200 000 lignes ne génère jamais plus de 50 nœuds DOM en même temps.
L'optimisation mémoire par Proxy
Un résultat de requête contient N lignes et M colonnes. La conversion naïve en objets JavaScript créerait N fois M propriétés, soit une allocation proportionnelle au produit des deux. QoreDB utilise une approche différente : chaque ligne est un Proxy ES6 adossé au tableau de valeurs brutes retourné par le backend Rust. L'accès à une propriété (par exemple le nom d'une colonne) est résolu via une map partagée qui associe chaque nom de colonne à son index. Le Proxy ne stocke rien de plus que la référence au tableau original.
L'avantage est double. D'une part, l'empreinte mémoire reste linéaire par rapport au nombre de valeurs réelles (N fois M valeurs, pas N fois M propriétés d'objet avec leurs métadonnées). D'autre part, seules les cellules effectivement lues par le rendu déclenchent du travail. Si la virtualisation n'affiche que 30 lignes sur 100 000, les 99 970 autres restent sous forme de tableaux compacts sans aucune résolution de propriété.
Tri server-side : déléguer au moteur
Le Data Grid supporte deux modes de tri selon le contexte. En mode pagination classique (le résultat tient dans une page chargée en mémoire), le tri est effectué côté client par TanStack Table, avec une fonction de comparaison qui gère les types numériques, les chaînes (tri locale-aware) et les valeurs NULL (toujours en dernier). Ce mode est instantané puisque les données sont déjà en mémoire.
En mode infinite scroll, le tri bascule automatiquement côté serveur. Quand l'utilisateur clique sur un en-tête de colonne, le composant n'essaie pas de trier les N lignes chargées localement. Il notifie le parent via un callback, qui relance la requête avec un ORDER BY sur la colonne choisie. Le moteur de base de données fait le tri sur l'ensemble du jeu de données, et les premiers résultats sont rechargés. C'est le seul moyen d'obtenir un tri correct quand les données sont chargées par morceaux de 100 lignes.
La bascule entre les deux modes est transparente pour l'utilisateur. La configuration de TanStack Table passe en mode manualSorting quand l'infinite scroll est actif, ce qui désactive le tri local et laisse le backend piloter l'ordre. Quand le tri change, le scroll revient en haut et les données sont rechargées depuis le début.
Infinite scroll et chargement progressif
L'infinite scroll charge les données par morceaux (chunks de 100 lignes par défaut). Un listener sur l'événement scroll du conteneur détecte quand l'utilisateur approche du bas de la grille (seuil de 500 pixels). À ce moment, le chunk suivant est demandé au backend avec la pagination, le tri et les filtres courants. Les nouvelles lignes sont concaténées aux données existantes, et la virtualisation prend le relais pour ne rendre que ce qui est visible. Le chargement s'arrête automatiquement quand le total de lignes annoncé par le serveur est atteint.
Édition inline : modifier une cellule directement
L'inline edit permet de cliquer sur une cellule, modifier sa valeur et valider. Le hook useInlineEdit gère l'ensemble du cycle : activation de l'édition, parsing de la valeur saisie selon le type de la colonne, comparaison avec la valeur originale, et envoi de la mutation au backend. La saisie est un champ texte simple qui apparaît dans la cellule. La validation se fait au blur ou à l'appui sur Entrée, l'annulation sur Escape.
Le parsing est sensible au type de données déclaré par le moteur. Un champ booléen interprète les chaînes "true" et "false". Un champ numérique convertit la saisie en nombre. Un champ JSON tente un JSON.parse. Si la conversion échoue, la valeur brute est conservée comme chaîne. La valeur "null" (insensible à la casse) est toujours interprétée comme un NULL SQL.
Avant d'envoyer la mutation, le hook vérifie plusieurs conditions : la table doit avoir une clé primaire (sinon l'UPDATE ne peut pas cibler une ligne précise), le driver doit supporter les mutations, et la connexion ne doit pas être en lecture seule. La clé primaire de la ligne en cours est extraite pour construire la clause WHERE de l'UPDATE. Côté Rust, la commande update_row passe par l'Universal Query Interceptor qui vérifie les règles de sécurité (environnement, politique de mutation) avant d'exécuter la requête sur le driver.
Comportement adapté à l'environnement
L'édition inline se comporte différemment selon l'environnement de la connexion. En développement, la modification est appliquée immédiatement après validation. En staging ou production, une boîte de dialogue de confirmation s'affiche avant d'envoyer la mutation. Ce comportement n'est pas une option configurable : il est intégré dans le flux d'édition et s'appuie sur la classification d'environnement définie lors de la configuration de la connexion.
Quand le mode sandbox est actif, l'inline edit ne touche pas la base du tout. Les modifications sont stockées localement et affichées comme des différences visuelles dans la grille. L'utilisateur peut ensuite générer un script SQL contenant toutes les modifications accumulées, ou tout annuler sans qu'aucune écriture n'ait atteint le serveur.
Le pattern dual state et refs
Un détail d'implémentation qui mérite d'être mentionné : le hook d'édition inline maintient l'état de la cellule en cours de modification à la fois dans un useState React (pour déclencher les re-renders) et dans un useRef (pour l'accès synchrone). Ce pattern est nécessaire parce que les handlers de blur et de keydown doivent lire la valeur courante au moment exact de l'événement, pas celle du dernier render. Sans ce double stockage, un blur rapide après une frappe pourrait lire une valeur périmée et produire une mutation incorrecte.
Le Data Grid de QoreDB combine virtualisation, tri adaptatif et édition inline typée pour offrir une expérience fluide sur des volumes de données réels. Chaque couche a un rôle précis : TanStack Virtual gère le DOM, TanStack Table gère l'état tabulaire, le backend Rust applique les règles de sécurité et délègue au bon driver. Le résultat est un composant qui reste réactif sur 200 000 lignes, qui trie correctement en mode chargement progressif, et qui permet de modifier une cellule en un clic sans sacrifier la sécurité.
Restez informé des nouveautés
Rejoignez notre newsletter pour recevoir les mises à jour majeures, les nouveaux drivers et nos coulisses techniques.

