Concevoir un DSL de requêtes fluide
Créer une API de requêtes chaînable qui se valide elle-même.
Concevoir un DSL de requêtes fluide est une leçon TypeScript Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage TypeScript Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours TypeScript Academy comprend 4 leçons au total.
Concevoir un langage de requêtes fluide
Nous concevons un langage de requêtes chaînable dans lequel chaque étape précise les étapes suivantes autorisées grâce aux types de retour. Le résultat ressemble au langage SQL et rejette les ordres invalides à la compilation.
La grammaire cible
Nous voulons : from, puis éventuellement where (répétable), puis un select terminal. Vous ne pouvez pas utiliser select avant from et vous ne pouvez pas utiliser from deux fois.
Interfaces d'état
Modélisez chaque étape comme une interface qui renvoie l'étape suivante.
interface Builder {
from(table: string): FromStage;
}
interface FromStage {
where(cond: string): FromStage; // repeatable
select(...cols: string[]): Result;
}
interface Result { sql: string; }Imposer l'ordre
Comme select n'existe que sur FromStage, l'appeler sur le Builder initial provoque une erreur de compilation. L'ordre est imposé uniquement par les méthodes exposées par chaque étape.
declare const db: Builder;
db.from("users").select("id"); // ok
db.select("id"); // Error: select missing on BuilderSuivre les colonnes sélectionnées
Ajoutez un type générique fantôme pour mémoriser les colonnes sélectionnées, afin que le type du résultat soit précis.
interface FromStage<T extends string = never> {
where(c: string): FromStage<T>;
select<C extends string>(...cols: C[]): Result<C>;
}
interface Result<C extends string> { columns: C[]; }Affiner à chaque appel
Chaque appel à where peut également accumuler des contraintes dans le type. Nous gardons ici une approche simple, mais ce modèle se généralise au suivi des paramètres liés.
const q = db.from("users").where("age > 18").where("active = true");
// still FromStage; select remains availableEmpêcher la répétition de from
Comme FromStage n'expose pas from, vous ne pouvez pas l'appeler deux fois. La grammaire l'interdit structurellement, sans nécessiter de garde à l'exécution.
db.from("a").from("b"); // Error: from does not exist on FromStageUne étape terminale
select renvoie Result, qui n'expose ni where ni from, ce qui termine la chaîne. Il ne reste que les opérations de lecture du résultat.
const r = db.from("users").select("id", "name");
r.columns; // ("id" | "name")[]
// r.where(...) -> Error: where not on ResultContraintes typées sur les colonnes
Contraignez les colonnes à un schéma de table connu avec un autre type générique, afin que les colonnes inconnues soient rejetées, en combinant ce langage avec les concepts ORM précédents.
interface Table<Cols extends string> {
select<C extends Cols>(...cols: C[]): Result<C>;
}
// db.from gives Table<"id" | "name" | "age">Étapes facultatives ou obligatoires
Rendez une étape obligatoire en n'exposant la méthode suivante qu'après cette étape. Par exemple, imposez au moins un where en renvoyant une étape dont le select n'apparaît qu'après l'appel à where. Les mêmes types chaînés peuvent également déduire le type de ligne du résultat de l'exécution de la requête, reliant ainsi la grammaire à la compilation aux données d'exécution.
Pourquoi est-ce important
Un langage spécifique à un domaine fluide conçu de cette manière s'auto-documente et ne peut pas être mal utilisé : la complétion automatique n'affiche que les étapes suivantes valides et les séquences illégales ne se compilent jamais. C'est la base des bibliothèques de constructeurs ergonomiques.
Vérification rapide
Vérifiez votre compréhension de la conception de langages spécifiques à un domaine fluides.
Récapitulatif
Vous avez conçu un langage de requêtes fluide comme une machine à états au niveau des types : chaque interface d'étape renvoie la suivante et n'expose que les méthodes valides. Les types génériques fantômes suivent les colonnes sélectionnées, les étapes terminales terminent la chaîne et les contraintes de colonnes rejettent les noms inconnus, le tout étant imposé par les types de retour.
Questions Fréquemment Posées
La leçon « Concevoir un DSL de requêtes fluide » est-elle gratuite ?
Oui — le texte complet de « Concevoir un DSL de requêtes fluide » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours TypeScript Academy, passe à CoddyKit PRO. Le cours TypeScript Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Concevoir un DSL de requêtes fluide » ?
Créer une API de requêtes chaînable qui se valide elle-même. Tu pratiques TypeScript Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer TypeScript Academy ?
Aucune expérience préalable n'est requise. TypeScript Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.
Combien de temps prend la leçon « Concevoir un DSL de requêtes fluide » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon TypeScript Academy ?
Oui. Chaque leçon TypeScript Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Qu’est-ce qu’un DSL au niveau des types
- Concevoir un DSL de requêtes fluide
- Validation des entrées à la compilation
- Messages d’erreur dans les DSL au niveau des types