0Pricing
TypeScript Academy · Lekcja

Projektowanie fluent query DSL

Buduj łańcuchowe API zapytań, które samo sprawdza poprawność

Projektowanie fluent query DSL to bezpłatna lekcja TypeScript Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej TypeScript Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs TypeScript Academy zawiera 4 lekcji w sumie.

Projektowanie fluent DSL zapytań

Projektujemy łańcuchowy DSL zapytań, w którym każdy krok uszczegóławia dozwolone kolejne kroki za pomocą typów zwracanych. Rezultat przypomina SQL, a niepoprawne kolejności są odrzucane podczas kompilacji.

Docelowa gramatyka

Celem jest: from, następnie opcjonalne, możliwe do powtórzenia where, a na końcu select. Nie można użyć select przed from ani użyć from dwukrotnie.

Interfejsy stanów

Każdy etap należy zamodelować jako interfejs zwracający kolejny etap.

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

Wymuszanie kolejności

Ponieważ select istnieje wyłącznie w FromStage, wywołanie go na początkowym Builder powoduje błąd kompilacji. Kolejność jest wymuszana wyłącznie przez metody udostępniane przez poszczególne etapy.

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

Śledzenie wybranych kolumn

Należy dodać fantomowy generyk, aby zapamiętać wybrane kolumny i zapewnić precyzyjny typ wyniku.

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

Uszczegóławianie przy każdym wywołaniu

Każde where może również dodawać ograniczenia do typu. Tutaj zachowujemy prostotę, ale ten wzorzec można uogólnić do śledzenia powiązanych parametrów.

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

Zapobieganie powtórnemu użyciu from

Ponieważ FromStage nie udostępnia from, nie można wywołać go dwukrotnie. Gramatyka zabrania tego strukturalnie, więc nie jest potrzebne zabezpieczenie w czasie działania.

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

Krok końcowy

select zwraca Result, który nie udostępnia ani where, ani from, kończąc łańcuch. Pozostają wyłącznie operacje odczytu wyniku.

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

Typowane ograniczenia kolumn

Należy ograniczyć kolumny do znanego schematu tabeli za pomocą kolejnego generyka, aby odrzucać nieznane kolumny i połączyć ten DSL z wcześniejszymi koncepcjami ORM.

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

Kroki opcjonalne a wymagane

Krok można uczynić wymaganym, udostępniając kolejną metodę dopiero po jego wykonaniu. Na przykład można wymusić co najmniej jedno where, zwracając etap, na którym select pojawia się dopiero po wywołaniu where. Te same typy łańcucha mogą również wywnioskować typ wiersza wyniku wykonania zapytania, łącząc gramatykę sprawdzaną podczas kompilacji z danymi w czasie działania.

Dlaczego to ma znaczenie

Zaprojektowany w ten sposób fluent DSL sam się dokumentuje i nie można go niewłaściwie użyć: autouzupełnianie pokazuje wyłącznie poprawne kolejne kroki, a nielegalne sekwencje nigdy się nie kompilują. To fundament ergonomicznych bibliotek builderów.

Szybki test

Proszę sprawdzić, czy rozumieją Państwo projektowanie fluent DSL.

Podsumowanie

Fluent DSL zapytań został zaprojektowany jako maszyna stanów na poziomie typów: każdy interfejs etapu zwraca kolejny i udostępnia wyłącznie poprawne metody. Fantomowe generyki śledzą wybrane kolumny, etapy końcowe zamykają łańcuch, a ograniczenia kolumn odrzucają nieznane nazwy — wszystko jest wymuszane przez typy zwracane.

Często zadawane pytania

Czy lekcja „Projektowanie fluent query DSL” jest bezpłatna?

Tak — pełny tekst „Projektowanie fluent query DSL” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu TypeScript Academy, przejdź na CoddyKit PRO. Kurs TypeScript Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Projektowanie fluent query DSL”?

Buduj łańcuchowe API zapytań, które samo sprawdza poprawność Ćwiczysz TypeScript Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć TypeScript Academy?

Nie wymagamy żadnego doświadczenia. TypeScript Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Projektowanie fluent query DSL”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji TypeScript Academy?

Tak. Każda lekcja TypeScript Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Czym jest DSL na poziomie typów
  2. Projektowanie fluent query DSL
  3. Walidacja danych wejściowych w czasie kompilacji
  4. Komunikaty błędów w DSL na poziomie typów
← Powrót do TypeScript Academy