CodeWorlds
Powrót do kolekcji
Przewodnik17 min czytaniaZespół CodeWorlds

Kysely, konstruktor zapytań SQL z typami

Kysely buduje zapytania SQL w TypeScripcie z pełnym wyprowadzaniem typów, bez warstwy ORM. Wersja 0.29.5, licencja MIT, skąd wziąć schemat typów.

Kysely, konstruktor zapytań SQL z typami

Kysely to biblioteka do budowania zapytań SQL w TypeScripcie, która podpowiada nazwy tabel i kolumn oraz wylicza typ wyniku, ale nie próbuje ukryć przed Tobą samego SQL. Bieżąca wersja to 0.29.5 z 10 sierpnia 2026 roku, licencja MIT, repozytorium kysely-org/kysely ma około 14,1 tysiąca gwiazdek i zero zależności w czasie wykonania.

Co Kysely właściwie robi

Zaczynasz od instancji klasy Kysely sparametryzowanej interfejsem opisującym Twoją bazę, a potem wywołujesz metody, które odwzorowują kolejne części zapytania: selectFrom, innerJoin, where, orderBy, limit. Na końcu wywołujesz execute albo executeTakeFirstOrThrow i dostajesz tablicę obiektów o typie policzonym z tego, co wybrałeś w select. Nie ma tu żadnej sesji, żadnego leniwego ładowania i żadnego zapytania, które poleci do bazy bez Twojej wiedzy.

To rozróżnienie jest sednem całej biblioteki. W typowym ORM piszesz user.projects i nie wiesz, czy właśnie odczytałeś pole z pamięci, czy wysłałeś zapytanie do bazy. W Kysely każde zapytanie jest widoczne w kodzie jako łańcuch wywołań, który da się przeczytać jak SQL, bo nazwy metod są nazwami klauzul. Klasyczny problem zapytań powielonych w pętli nie znika sam z siebie, ale przynajmniej widzisz go w kodzie, zamiast odkrywać w logach bazy.

Zamiast typów wyniku pisanych ręcznie dostajesz je z inferencji. Jeśli w select podasz ['projects.id', 'users.email'], wynikiem będzie tablica obiektów z dokładnie tymi dwoma polami, a próba odczytania czegokolwiek innego jest błędem kompilacji. Jeśli kolumna w schemacie jest opisana jako string | null, to null pojawi się w typie wyniku i kompilator wymusi jego obsługę. Jeśli w leftJoin dołączysz tabelę, kolumny z niej staną się opcjonalne, bo dopasowanie mogło się nie znaleźć.

Wbudowane dialekty to PostgreSQL, MySQL, SQLite, MS SQL Server oraz PGlite, ten ostatni dodany w wydaniu 0.29.0. Dialekt to warstwa tłumacząca drzewo zapytania na konkretny wariant SQL i zarządzająca połączeniami, a sterownik podłącza się z zewnątrz: dla PostgreSQL jest to zwykle pakiet pg z własną pulą połączeń. Sama paczka nie deklaruje żadnych zależności w czasie wykonania, waży 323 kilobajty w archiwum i zawiera 610 plików.

Mapa exports w pliku package.json wystawia sześć punktów wejścia poza głównym: kysely/migration, kysely/readonly oraz cztery zestawy pomocników dla poszczególnych baz. Pomocniki dla PostgreSQL to jsonArrayFrom, jsonObjectFrom, jsonBuildObject i mergeAction, czyli funkcje do składania wyników zagnieżdżonych w jednym zapytaniu zamiast w kilku. Wtyczek jest kilka i włącza się je przy tworzeniu instancji: CamelCasePlugin tłumaczy nazwy między zapisem podkreśleniowym w bazie a wielbłądzim w kodzie, ParseJSONResultsPlugin parsuje kolumny JSON zwracane przez sterownik jako tekst, DeduplicateJoinsPlugin usuwa powtórzone złączenia.

Czego Kysely nie robi, jest tu ważniejsze niż lista funkcji. Nie zna Twojej bazy. Nie łączy się z nią, żeby odczytać schemat. Nie generuje migracji z różnicy między modelem a stanem faktycznym. Nie ma studia do przeglądania danych. Wszystko, co wie o Twoich tabelach, pochodzi z interfejsu TypeScript, który musisz dostarczyć.

Wersja, licencja i stan projektu

Pakiet kysely ma na dziś 187 opublikowanych wersji, pierwszą z lutego 2021 roku, a bieżącą 0.29.5 z 10 sierpnia 2026. Numer główny wciąż wynosi zero, po ponad pięciu latach rozwoju i przy wyraźnie produkcyjnym zastosowaniu. Repozytorium ma 432 rozgałęzienia, 172 otwarte zgłoszenia, 158 stron listy współtwórców przy jednym wpisie na stronę, nie jest zarchiwizowane, a ostatnia zmiana pochodzi z 17 sierpnia 2026 roku.

Licencję sprawdziłem w trzech miejscach, bo to właśnie tam bywa niespodzianka. Plik LICENSE w gałęzi głównej repozytorium zawiera tekst MIT z formułą „Copyright (c) 2022 Sami Koskimäki". Pole license w rejestrze npm dla wersji 0.29.5 ma wartość MIT. Opublikowane archiwum zawiera plik package/LICENSE z dokładnie tym samym tekstem. Interfejs programistyczny GitHuba raportuje MIT. Cztery źródła, jeden wynik, żadnej rozbieżności. To brzmi jak rzecz oczywista, a nie jest: w tej samej kolekcji opisane są pakiety, w których repozytorium mówi jedno, rejestr drugie, a opublikowane archiwum nie zawiera pliku licencyjnego w ogóle. Kysely wypada tu wzorowo i przy audycie zależności możesz zamknąć temat na pierwszym sprawdzeniu.

Wariantu płatnego nie ma. Nie ma też firmy sprzedającej wsparcie ani planu z gwarantowanym czasem odpowiedzi, co odróżnia projekt od tych, w których za biblioteką stoi spółka z usługą hostowaną. Zysk jest taki, że nic Cię nie przywiązuje do dostawcy i nikt nie zmieni Ci warunków cennika. Koszt jest taki, że przy poważnym błędzie masz do dyspozycji zgłoszenie na GitHubie i kanał na Discordzie, a nie umowę.

Dwa ograniczenia środowiskowe rzucają się w oczy przy aktualizacji. Pierwsze to Node: pole engines wymaga wersji co najmniej 22, podczas gdy w 0.28.17 było to 20, w 0.28.0 osiemnaście, a w 0.27.0 czternaście. Próg rośnie w wydaniach mniejszych, bo przy numerze głównym zero każde wydanie formalnie jest mniejsze. Drugie to TypeScript. Mapa exports zawiera wpis types@<5.4 prowadzący do pliku outdated-typescript.d.ts, który zamiast prawdziwych typów eksportuje Kysely, RawBuilder i sql jako specjalny typ błędu z komunikatem o konieczności aktualizacji do wersji 5.4 lub nowszej. Nie dostaniesz więc niejasnego błędu inferencji, tylko czytelne zdanie, co jest nie tak, ale i tak musisz podnieść wersję kompilatora.

Skąd wziąć schemat typów

To jest najważniejsza decyzja przy wchodzeniu w Kysely i zarazem jego największa słabość. Biblioteka nie wie nic o Twojej bazie, więc opis tabel musisz jej podać sam. Wygląda to tak.

Code
TypeScript
import { Pool } from 'pg'
import {
  Kysely,
  PostgresDialect,
  type ColumnType,
  type Generated,
  type Insertable,
  type Selectable,
  type Updateable
} from 'kysely'

interface UserTable {
  id: Generated<number>
  email: string
  display_name: string | null
  plan: 'free' | 'pro'
  created_at: ColumnType<Date, string | undefined, never>
}

interface ProjectTable {
  id: Generated<string>
  owner_id: number
  slug: string
  archived_at: Date | null
}

export interface Database {
  users: UserTable
  projects: ProjectTable
}

export type User = Selectable<UserTable>
export type NewUser = Insertable<UserTable>
export type UserUpdate = Updateable<UserTable>

export const db = new Kysely<Database>({
  dialect: new PostgresDialect({
    pool: new Pool({ connectionString: process.env.DATABASE_URL, max: 10 })
  })
})

Cała siła tego zapisu siedzi w typie ColumnType, który przyjmuje trzy parametry: typ przy odczycie, typ przy wstawianiu i typ przy aktualizacji. Kolumna created_at opisana jako ColumnType<Date, string | undefined, never> zwraca obiekt daty przy odczycie, przyjmuje tekst albo nic przy wstawianiu i nie daje się zmienić przy aktualizacji. Typ Generated<number> to skrót dla kolumny, którą baza wypełnia sama, więc przy wstawianiu jest opcjonalna. Jest jeszcze GeneratedAlways dla kolumn, do których nie wolno pisać w ogóle, oraz JSONColumnType dla danych zwracanych przez sterownik jako tekst. Pomocnicy Selectable, Insertable i Updateable przeliczają opis tabeli na trzy osobne kształty obiektu i to ich używasz w sygnaturach własnych funkcji, nigdy surowego interfejsu tabeli.

Dróg do zdobycia tego schematu są trzy. Pierwsza to pisanie ręczne, sensowne przy małej bazie i przy pełnej kontroli nad migracjami, męczące przy sześćdziesięciu tabelach. Druga to kysely-codegen, obecnie w wersji 0.20.0 na licencji MIT, który łączy się z żywą bazą i zapisuje gotowy plik z typami. Trzecia to prisma-kysely w wersji 3.2.1, generator wpinany w Prismę, który bierze plik schema.prisma jako źródło prawdy i wypluwa typy dla Kysely, co ma sens, jeśli migracje prowadzisz Prismą, a zapytania chcesz pisać bez jej silnika.

Code
Bash
npx kysely-codegen \
  --dialect postgres \
  --url "$DATABASE_URL" \
  --out-file ./src/db/schema.d.ts \
  --camel-case \
  --exclude-pattern "public._prisma*" \
  --type-only-imports

npx kysely-codegen --dialect postgres --url "$DATABASE_URL" --verify

Drugie polecenie jest tym, o którym najłatwiej zapomnieć, a jest w tej układance kluczowe. Flaga --verify nie zapisuje pliku, tylko sprawdza, czy istniejący odpowiada bieżącemu stanowi bazy, i kończy się niezerowym kodem wyjścia przy rozjeździe. Bez tego kroku w potoku ciągłej integracji zdarzy się prędzej czy później sytuacja, w której ktoś dodał kolumnę migracją, nie przegenerował typów, a kompilator dalej twierdzi, że wszystko jest w porządku. Typy w Kysely nie są sprawdzane wobec bazy w czasie wykonania, więc jeśli skłamiesz w interfejsie, biblioteka uwierzy Ci na słowo i błąd wyjdzie dopiero jako wyjątek sterownika na produkcji.

Generator obsługuje dialekty postgres, mysql, sqlite, mssql, libsql, bun-sqlite i worker-bun-sqlite, a poza wymienionymi flagami ma między innymi --overrides, --type-mapping, --include-pattern, --singularize, --runtime-enums, --date-parser, --numeric-parser, --default-schema i --config-file. To odrębny pakiet z odrębnym utrzymującym, więc jego tempo wydań nie jest tempem wydań Kysely i przy większej zmianie w bibliotece może przez chwilę zostawać w tyle.

Pisanie zapytań

Poniżej typowe odczytanie z warunkiem opcjonalnym i złączeniem, czyli zapytanie, które w każdej aplikacji wygląda podobnie.

Code
TypeScript
import { sql } from 'kysely'

async function findActiveProjects(ownerId: number, search?: string) {
  return db
    .selectFrom('projects')
    .innerJoin('users', 'users.id', 'projects.owner_id')
    .select([
      'projects.id',
      'projects.slug',
      'users.email',
      sql<number>`count(*) over ()`.as('total_count')
    ])
    .where('projects.owner_id', '=', ownerId)
    .where('projects.archived_at', 'is', null)
    .$if(search !== undefined, (qb) =>
      qb.where('projects.slug', 'like', `%${search}%`)
    )
    .orderBy('projects.slug', 'asc')
    .limit(50)
    .execute()
}

const owner = await db
  .selectFrom('users')
  .selectAll()
  .where((eb) =>
    eb.or([eb('users.email', '=', 'ada@example.com'), eb('users.id', '=', 1)])
  )
  .executeTakeFirstOrThrow()

Metoda $if rozwiązuje problem, który w konstruktorach zapytań zwykle kończy się rozgałęzieniem kodu i utratą typu. Warunek podajesz jako wartość logiczną, a rozszerzenie zapytania jako funkcję, i typ wyniku zostaje policzony poprawnie w obu przypadkach. Metody zaczynające się od znaku dolara to konsekwentna konwencja dla operacji działających na poziomie typów, a nie na poziomie SQL: obok $if są $castTo, $narrowType, $assertType, $asScalar i $call.

Funkcja przekazana do where dostaje konstruktor wyrażeń, zwyczajowo nazywany eb. Sam jest wywoływalny jako trójargumentowe porównanie, a poza tym daje and, or, not, between, exists, ref, val, lit, cast, case, selectFrom i kilka innych. To tym mechanizmem składa się warunki zagnieżdżone, których nie da się zapisać płaskim łańcuchem wywołań.

Znacznik szablonowy sql jest furtką do wszystkiego, czego biblioteka nie opakowała. Parametr typu w zapisie sql<number> mówi kompilatorowi, czego się spodziewasz, i tu odpowiedzialność przechodzi na Ciebie, bo nikt tego nie zweryfikuje. Wartości wstawione w szablon przez interpolację trafiają do zapytania jako parametry, a nie jako tekst, więc podstawowy przypadek jest bezpieczny. Znacznik ma też pomocników: sql.ref dla odwołania do kolumny, sql.table dla tabeli, sql.id dla identyfikatora, sql.lit dla literału, sql.join dla listy oraz sql.raw dla surowego tekstu. Ten ostatni wkleja łańcuch znaków do zapytania bez żadnego przetwarzania i jest jedynym miejscem w całym interfejsie, w którym łatwo o wstrzyknięcie SQL.

Zapis danych wygląda symetrycznie, z obsługą konfliktu wprost przez odpowiednik klauzuli on conflict.

Code
TypeScript
const inserted = await db
  .insertInto('users')
  .values({ email: 'ada@example.com', display_name: 'Ada', plan: 'pro' })
  .onConflict((oc) =>
    oc.column('email').doUpdateSet({ display_name: 'Ada', plan: 'pro' })
  )
  .returningAll()
  .executeTakeFirstOrThrow()

const { sql: text, parameters } = db
  .selectFrom('users')
  .select('id')
  .where('plan', '=', 'pro')
  .compile()

Konstruktor konfliktu daje column, columns, constraint, doNothing, doUpdateSet i where, czyli komplet potrzebny do wstawienia z aktualizacją. Metoda compile kończy budowanie bez wysyłania czegokolwiek i zwraca obiekt z polami sql, parameters, query i queryId. Przydaje się w dwóch sytuacjach: kiedy chcesz zobaczyć wygenerowany tekst w teście zamiast zgadywać, i kiedy potrzebujesz zapytania przygotowanego raz, a wykonywanego wielokrotnie.

Transakcje, migracje i granice biblioteki

Transakcja jest zamknięta w wywołaniu zwrotnym, a zatwierdzenie i wycofanie dzieją się automatycznie na podstawie tego, czy funkcja zakończyła się wyjątkiem. Obiekt przekazany do środka ma ten sam interfejs co instancja główna, więc kod zapytań nie wie, czy działa w transakcji.

Code
TypeScript
await db.transaction().execute(async (trx) => {
  const user = await trx
    .insertInto('users')
    .values({ email: 'ada@example.com', plan: 'free' })
    .returning('id')
    .executeTakeFirstOrThrow()

  await trx
    .insertInto('projects')
    .values({ owner_id: user.id, slug: 'default' })
    .execute()
})

Migracje są w bibliotece obecne, ale w wersji minimalnej i całkowicie ręcznej. Plik migracji to moduł eksportujący dwie funkcje, up i down, a budowanie schematu odbywa się tym samym stylem łańcuchowym co zapytania.

Code
TypeScript
import { Kysely, sql } from 'kysely'

export async function up(db: Kysely<any>): Promise<void> {
  await db.schema
    .createTable('projects')
    .addColumn('id', 'uuid', (col) => col.primaryKey().defaultTo(sql`gen_random_uuid()`))
    .addColumn('owner_id', 'integer', (col) =>
      col.notNull().references('users.id').onDelete('cascade')
    )
    .addColumn('slug', 'varchar(64)', (col) => col.notNull())
    .addColumn('archived_at', 'timestamptz')
    .execute()

  await db.schema
    .createIndex('projects_owner_id_index')
    .on('projects')
    .column('owner_id')
    .execute()
}

export async function down(db: Kysely<any>): Promise<void> {
  await db.schema.dropTable('projects').execute()
}

Uruchamianiem zajmuje się klasa Migrator, której podajesz instancję bazy i dostawcę plików.

Code
TypeScript
import { promises as fs } from 'node:fs'
import path from 'node:path'
import { Migrator, FileMigrationProvider } from 'kysely'

const migrator = new Migrator({
  db,
  provider: new FileMigrationProvider({
    fs,
    path,
    migrationFolder: path.join(process.cwd(), 'migrations')
  }),
  migrationTableName: 'kysely_migration',
  allowUnorderedMigrations: true
})

const { error, results } = await migrator.migrateToLatest()

Poza migrateToLatest dostępne są migrateUp, migrateDown, migrateTo i getMigrations, a konfiguracja pozwala zmienić nazwę tabeli migracji, nazwę tabeli blokady oraz schemat, w którym obie mają powstać. Opcja allowUnorderedMigrations przydaje się w zespole pracującym na kilku gałęziach jednocześnie, bo bez niej migracja z wcześniejszym znacznikiem czasu, dodana po scaleniu, zostanie odrzucona. Wynik wywołania to obiekt z polami error i results, oba opcjonalne, więc obsłuż oba, a nie tylko wyjątek.

Tu przebiega główna granica względem pełnych narzędzi. Kysely nie policzy różnicy między stanem bazy a Twoim modelem i nie napisze migracji za Ciebie. Każdą zmianę schematu piszesz ręcznie, a potem osobno przegenerowujesz typy, więc jedna zmiana kolumny to dwie czynności zamiast jednej. Polecenia z wiersza poleceń w samej bibliotece też nie ma, do tego służy odrębny pakiet kysely-ctl w wersji 0.21.0.

Koszt po stronie kompilatora

Ta biblioteka liczy niemal wszystko na poziomie typów i za to się płaci. Typ wyniku zapytania powstaje przez przetworzenie interfejsu bazy, listy złączeń i listy wybranych kolumn, a każde z tych przetworzeń to praca kompilatora, wykonywana ponownie przy każdym sprawdzeniu pliku w edytorze. Przy bazie z kilkudziesięcioma tabelami i zapytaniach z kilkoma złączeniami czas odpowiedzi serwera języka staje się odczuwalny.

Zespół mówi o tym otwarcie. Notatki do wydania 0.29.5 zaczynają się od stwierdzenia, że TypeScript w wersji 7 dopuszcza głębsze obliczenia, przez co w różnych scenariuszach powstaje znacznie więcej instancjacji typów i rośnie czas rzeczywisty, a jedna z poprawek w tym wydaniu dotyczy właśnie optymalizacji sprawdzania przypisywalności między konstruktorami. Osobna poprawka nosi tytuł mówiący o naprawie nieskończonej rekurencji przy sprawdzaniu typów. To nie są problemy teoretyczne.

Wydanie 0.29.0 dołożyło dwa narzędzia adresujące ten koszt wprost: $pickTables i $omitTables. Oba zawężają widok bazy dla dalszej części łańcucha, więc kompilator przetwarza opis dwóch tabel zamiast pięćdziesięciu. W tym samym wydaniu pojawił się typ ReadonlyKysely importowany z kysely/readonly, który na poziomie kompilacji odbiera instancji metody zapisujące, przez co insertInto, updateTable, deleteFrom i mergeInto stają się błędem. Przydaje się to w kodzie odczytującym replikę.

Praktyczny wniosek jest prosty. Jeśli baza jest duża, trzymaj plik z typami poza zakresem sprawdzania na bieżąco tam, gdzie to możliwe, dziel opis bazy na moduły i sięgaj po zawężanie widoku w miejscach, w których edytor zaczyna zwalniać. Przy małej i średniej bazie nie zauważysz niczego.

Kysely a alternatywy

CechaKyselyDrizzle ORMPrismaSterownik pg bez nakładki
Model pracymetody odwzorowujące klauzule SQLmetody odwzorowujące klauzule SQLwłasny język zapytań i relacjeSQL jako łańcuch znaków
Skąd schemat typówręcznie albo osobny generatorplik schematu w TypeScripcieplik schema.prismabrak typowania wyniku
Migracje z różnicy schematówbraktak, przez drizzle-kittak, przez prisma migratebrak
Zależności w czasie wykonaniabrakbraksześć pakietów w prismasześć pakietów w pg
Bieżąca wersja0.29.50.45.27.9.18.23.0
LicencjaMITApache 2.0Apache 2.0MIT

Wybór rozstrzyga się na jednym pytaniu: czy chcesz jedno źródło prawdy dla schematu, czy dwa. Drizzle i Prisma dają jedno, bo z tego samego opisu biorą się typy i migracje, i to jest ich realna przewaga, o której Kysely nie próbuje nawet dyskutować. Kysely daje dwa i wymaga, żebyś sam pilnował ich zgodności, w zamian nie narzucając niczego ani migracjom, ani sposobowi pisania zapytań.

Kysely wybiera się wtedy, gdy baza już istnieje i nie Ty nią rządzisz, gdy zapytania są nietrywialne i pisanie ich w cudzym języku zapytań byłoby walką, albo gdy chcesz mieć pewność, że nic nie poleci do bazy bez Twojej wiedzy. Sprawdza się jako warstwa dostępu do danych nad zwykłym PostgreSQL, a także nad bazami hostowanymi, na przykład w Supabase czy Neon, gdzie i tak łączysz się przez zwykły sterownik. Nie wybiera się jej wtedy, gdy zespół jest mały, baza nowa i priorytetem jest szybkie postawienie schematu razem z migracjami.

Typowe błędy

Pierwszy to opis tabel niezgodny z bazą. Typy nie są sprawdzane w czasie wykonania, więc literówka w nazwie kolumny albo pominięta możliwość wartości pustej daje kod, który się kompiluje i wywala się dopiero przy zapytaniu. Wpisz kysely-codegen --verify do potoku ciągłej integracji.

Drugi to używanie surowego interfejsu tabeli tam, gdzie powinien być Selectable. Typ UserTable zawiera Generated i ColumnType, czyli opisy trzech różnych kształtów naraz, i nie nadaje się na typ obiektu zwróconego z bazy. Funkcje przyjmujące i zwracające dane opisuj przez Selectable, Insertable i Updateable.

Trzeci to executeTakeFirst tam, gdzie brak wyniku jest błędem. Ta metoda zwraca wartość pustą, którą łatwo przeoczyć, bo typ wyniku pozwala pójść dalej. Jeśli rekord musi istnieć, użyj executeTakeFirstOrThrow.

Czwarty to sql.raw z danymi od użytkownika. Interpolacja w znaczniku sql tworzy parametr i jest bezpieczna, ale sql.raw wkleja tekst dosłownie. Do dynamicznej nazwy kolumny czy tabeli są sql.ref, sql.table i sql.id.

Piąty to CamelCasePlugin włączony w połowie projektu. Wtyczka tłumaczy nazwy w obie strony, więc po jej włączeniu interfejs bazy ma być zapisany wielbłądzio, a nie z podkreśleniami. Zmiana w działającym projekcie oznacza przepisanie opisu wszystkich tabel i przegenerowanie typów z flagą --camel-case.

Szósty to aktualizacja wersji mniejszej bez czytania notatek. Numer główny wynosi zero, więc zmiany niezgodne wstecz mieszczą się w regułach wersjonowania. Podniesienie progu Node z 20 na 22 przyszło właśnie w takim wydaniu i potrafi zatrzymać budowanie na serwerze.

Siódmy to zapytania powielone w pętli. Brak leniwego ładowania nie oznacza, że problem znika, tylko że to Ty go tworzysz jawnie. Do wyników zagnieżdżonych używaj jsonArrayFrom i jsonObjectFrom z kysely/helpers/postgres albo złączenia z agregacją.

FAQ

Czy Kysely to ORM?

Nie i celowo nim nie jest. Brakuje mu wszystkiego, co definiuje mapowanie obiektowo-relacyjne: nie ma sesji, nie ma jednostki pracy, nie ma leniwego ładowania i nie ma obiektów encji z tożsamością. Jest warstwą, która buduje SQL i typuje wynik, myślisz więc dalej tabelami i klauzulami.

Skąd wziąć interfejs opisujący bazę?

Z jednego z trzech miejsc: napisz go ręcznie, wygeneruj z żywej bazy przez kysely-codegen w wersji 0.20.0 albo z pliku schema.prisma przez prisma-kysely w wersji 3.2.1. Przy generowaniu dołóż krok --verify do potoku, żeby rozjazd między typami a bazą zatrzymywał budowanie.

Czy Kysely zrobi migracje za mnie?

Uruchomi je i zapisze historię w tabeli, ale nie napisze. Klasa Migrator wykonuje pliki eksportujące funkcje up i down, a treść tych funkcji piszesz sam, korzystając z konstruktora schematu. Różnicy między stanem bazy a modelem nikt tu nie policzy.

Dlaczego edytor zwalnia przy dużej bazie?

Bo typy wyniku są liczone przez kompilator przy każdym sprawdzeniu, a koszt rośnie z rozmiarem interfejsu bazy i liczbą złączeń. Zespół pracuje nad optymalizacją, o czym wprost mówią notatki do wydania 0.29.5. Doraźnie pomaga zawężenie widoku przez $pickTables albo $omitTables.

Czy Kysely jest płatne i czy licencja coś ogranicza?

Nie i nie. Pakiet jest na licencji MIT, co potwierdzają zgodnie plik w repozytorium, pole w rejestrze npm oraz plik LICENSE w opublikowanym archiwum. Nie ma wariantu płatnego, ale nie ma też firmy sprzedającej wsparcie, więc przy poważnym błędzie zostaje zgłoszenie w repozytorium.

Czy da się używać Kysely razem z Prismą?

Tak i jest to układ spotykany. Prisma prowadzi schemat i migracje, generator prisma-kysely przekłada plik schematu na typy dla Kysely, a zapytania trudniejsze piszesz konstruktorem. Kosztem jest utrzymywanie dwóch bibliotek w projekcie, więc ma to sens głównie przy migracji stopniowej.

Dokumentacja i przykłady są na stronie projektu, kod źródłowy w repozytorium na GitHubie, a metadane wydania w rejestrze npm. Do pełnego obrazu warto zestawić to z artykułem o TypeScripcie, bo część ograniczeń Kysely to po prostu ograniczenia kompilatora.

Czytaj dalej

Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie