0Pricing
TypeScript Academy · Lezione

Progettare una DSL fluente per le query

Costruisca una API per query concatenabile e auto-validante.

Progettare una DSL fluente per le query è una lezione TypeScript Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento TypeScript Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso TypeScript Academy include 4 lezioni in totale.

Progettare un DSL fluente per le query

Progettiamo un DSL per query concatenabile, in cui ogni passaggio raffina i passaggi successivi consentiti tramite i tipi restituiti. Il risultato è simile a SQL e rifiuta gli ordinamenti non validi in fase di compilazione.

La grammatica obiettivo

Vogliamo: from, quindi where opzionale e ripetibile, e infine select. Non è possibile usare select prima di from né usare from due volte.

Interfacce degli stati

Modelli ogni fase come un'interfaccia che restituisce la fase successiva.

interface Builder {
  from(table: string): FromStage;
}
interface FromStage {
  where(cond: string): FromStage; // repeatable
  select(...cols: string[]): Result;
}
interface Result { sql: string; }

Imporre l'ordine

Poiché select esiste solo in FromStage, chiamarlo sull'elemento iniziale Builder genera un errore di compilazione. L'ordine viene imposto esclusivamente dai metodi esposti da ogni fase.

declare const db: Builder;
db.from("users").select("id"); // ok
db.select("id");               // Error: select missing on Builder

Tenere traccia delle colonne selezionate

Aggiunga un generic fantasma per ricordare quali colonne sono state selezionate, così il tipo del risultato è preciso.

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[]; }

Raffinare a ogni chiamata

Anche ogni where può accumulare vincoli nel tipo. Qui manteniamo le cose semplici, ma lo schema può essere generalizzato per tenere traccia dei parametri associati.

const q = db.from("users").where("age > 18").where("active = true");
// still FromStage; select remains available

Impedire from ripetuti

Poiché FromStage non espone from, non è possibile chiamarlo due volte. La grammatica lo vieta strutturalmente, senza bisogno di un controllo a runtime.

db.from("a").from("b"); // Error: from does not exist on FromStage

Un passaggio terminale

select restituisce Result, che non espone né where né from, terminando la catena. Restano disponibili solo le operazioni di lettura del risultato.

const r = db.from("users").select("id", "name");
r.columns; // ("id" | "name")[]
// r.where(...) -> Error: where not on Result

Vincoli tipizzati sulle colonne

Vincoli le colonne a uno schema di tabella noto con un altro generic, così le colonne sconosciute vengono rifiutate, combinando questo DSL con le idee ORM della lezione precedente.

interface Table<Cols extends string> {
  select<C extends Cols>(...cols: C[]): Result<C>;
}
// db.from gives Table<"id" | "name" | "age">

Passaggi facoltativi e obbligatori

Renda obbligatorio un passaggio esponendo il metodo successivo solo dopo averlo eseguito. Ad esempio, imponga almeno un where restituendo una fase in cui select compare solo dopo la chiamata a where. Gli stessi tipi concatenati possono anche inferire il tipo della riga del risultato dell'esecuzione della query, collegando la grammatica in fase di compilazione ai dati a runtime.

Perché è importante

Un DSL fluente progettato in questo modo si documenta da solo ed è impossibile da usare in modo improprio: il completamento automatico mostra solo i passaggi successivi validi e le sequenze non consentite non vengono mai compilate. Questa è la base delle librerie builder ergonomiche.

Verifica rapida

Verifichi la Sua comprensione della progettazione di DSL fluenti.

Riepilogo

Ha progettato un DSL fluente per query come una macchina a stati a livello di tipo: ogni interfaccia di fase restituisce la successiva ed espone solo i metodi validi. I generics fantasma tengono traccia delle colonne selezionate, le fasi terminali concludono la catena e i vincoli sulle colonne rifiutano i nomi sconosciuti; tutto viene imposto dai tipi restituiti.

Domande Frequenti

La lezione «Progettare una DSL fluente per le query» è gratuita?

Sì — il testo completo di «Progettare una DSL fluente per le query» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso TypeScript Academy, passa a CoddyKit PRO. Il corso TypeScript Academy include 4 lezioni in totale.

Cosa imparerò in «Progettare una DSL fluente per le query»?

Costruisca una API per query concatenabile e auto-validante. Eserciti TypeScript Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare TypeScript Academy?

Non è richiesta alcuna esperienza precedente. TypeScript Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «Progettare una DSL fluente per le query»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione TypeScript Academy?

Sì. Ogni lezione TypeScript Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Che cos’è una DSL a livello di tipo
  2. Progettare una DSL fluente per le query
  3. Validazione degli input in fase di compilazione
  4. Messaggi di errore nelle DSL a livello di tipo
← Torna a TypeScript Academy