SQLite
Scrii cod SQL simplu SQLite în unul sau mai multe fișiere .sql. Platforma rulează o instanță SQLite în browser prin intermediul build-ului oficial @sqlite.org/sqlite-wasm — fiecare fișier .sql care nu este de testare se execută automat la salvare pe aceeași bază de date în memorie (in-memory), în ordine lexicografică.
Proiectul inițial (seed) vine cu un fișier script.sql care creează un tabel greetings, inserează rândul (1, 'Hello, World!') și îl selectează înapoi — extinde-l adăugând mai multe elemente de schemă, date de test (seed) și interogări.
Fișiere de intrare
Fișierele soluției se află în rădăcina proiectului:
script.sql— fișier de soluție editabil. Proiectul de pornire conține un ghid TODO pentru crearea tabeluluigreetingsși selectarea mesajului.- Poți redenumi
script.sqlîn orice dorești și poți crea fișiere.sqlsuplimentare (le poți organiza în submape dacă vrei). Instrumentul de rulare automată (auto-runner) descoperă fiecare fișier.sqlcare nu este de test din arborele de fișiere.
Fișierele rulează în ordine lexicografică după calea completă. Pune un prefix numelor de fișiere (01-schema.sql, 02-data.sql, 03-queries.sql) atunci când ordinea de execuție contează.
Database playground
Panoul din dreapta este o filă live Database care comunică cu aceeași instanță SQLite în memorie:
- Rezultatul rulării automate (Auto-run result) — fiecare SELECT (sau orice altă instrucțiune care returnează rânduri) din fișierele tale
.sqlse randează aici, grupat după fișierul sursă, la fiecare salvare. - Tabele (Tables) — bara laterală a schemei populată din
sqlite_mastercare listează fiecare tabel, plus coloanele și tipurile sale (prinPRAGMA table_info). Fă clic pe Preview pe un tabel pentru a rula instantaneuSELECT * FROM <table> LIMIT 20în fila de interogări ad-hoc. - Interogare ad-hoc (Ad-hoc query) — editor SQL bazat pe Monaco pentru interogări ocazionale pe baza de date live. Ctrl/⌘ + Enter rulează interogarea fără a modifica fișierele sursă.
Baza de date este în memorie: reîmprospătarea previzualizării o șterge. Pentru a curăța fără reîncărcare, rulează DROP TABLE … în orice fișier sursă sau în fila de interogări ad-hoc.
Versiune
Rulează sqlite-wasm v3.46.1-build3 (SQLite WASM) cu Vitest v3.2.4 pe Node v22.
Limbaje suportate
SQL (dialectul SQLite)
Cadru de testare
Vitest cu utilitarul @dojocode/sql-test-helpers.
Memento-uri speciale și detalii de implementare
- Dialect SQLite standard. Folosește
INTEGER PRIMARY KEY AUTOINCREMENT(NUSERIALdin PostgreSQL),INSERT OR IGNORE/INSERT OR REPLACEpentru operațiuni de tip upsert. - Introspecția schemei folosește
sqlite_master(SELECT name FROM sqlite_master WHERE type = 'table') șiPRAGMA table_info(<table>)pentru metadatele coloanelor. - Fișierele care se potrivesc cu modelul
*.test.sqlsunt ignorate de rularea automată — fiind rezervate pentru un viitor rulător de teste SQL brute. - Testele sunt scrise în TypeScript (
*.test.ts) folosind utilitarul partajatcreateSqliteTestDb(import.meta.url). Acesta pornește o instanță nouă de sqlite-wasm (cu avertismentul de inițializare OPFS dezactivat) și încarcă automat fiecare fișier.sqlcare nu este de test împreună cu testul, înainte de rularea aserțiunilor. query()șiexec()sunt sincrone aici — spre deosebire de utilitarul PGlite, nu este necesarawaitpentru apelurile individuale (utilitarul în sine este asincron doar pentru că inițializarea modulului sqlite-wasm de la bază returnează un Promise).
Exemplu cu Vitest:
import { describe, it, expect, beforeAll } from 'vitest';
import { createSqliteTestDb, type SqliteTestDb } from '@dojocode/sql-test-helpers/sqlite';
let db: SqliteTestDb;
beforeAll(async () => {
db = await createSqliteTestDb(import.meta.url);
});
describe('greetings', () => {
it("contains the row with message 'Hello, World!'", () => {
const rows = db.query<{ message: string }>(
'SELECT message FROM greetings WHERE id = 1'
);
expect(rows[0]?.message).toBe('Hello, World!');
});
it('has exactly one row', () => {
const rows = db.query<{ n: number }>('SELECT COUNT(*) AS n FROM greetings');
expect(rows[0].n).toBe(1);
});
});Utilitarul returnează { query<T>(sql): T[], exec(sql): void, raw: sqlite3.oo1.DB }. Atât query, cât și exec sunt sincrone — returnează rezultatele sau modifică baza de date imediat. Folosește raw doar pentru cazuri avansate (instrucțiuni pregătite cu parametri asociați, tranzacții, familia wasm.poke*).
Biblioteci incluse
- @sqlite.org/sqlite-wasm
- @dojocode/sql-test-helpers
- hono (timp de rulare de server in-WC)
- @hono/node-server
- vitest
Cum se depanează
Trei moduri de a verifica ce face codul tău SQL:
1. Fila de rezultate Auto-run (Auto-run result)
Fiecare rezultat SELECT este randat acolo cu eticheta fișierului său sursă. Dacă o interogare nu returnează nimic, secțiunea este omisă — acesta fiind în sine un semnal util că un rând nu a fost inserat sau că un filtru WHERE este prea restrictiv.
2. Fila Tabele (Tables)
Confirmă ce tabele există și tipurile coloanelor lor în acest moment. Dacă întâmpini erori de tip "no such table", înseamnă că tabelul nu a fost creat — de obicei din cauza unei erori de sintaxă într-o instrucțiune CREATE anterioară.
3. Fila de interogări ad-hoc (Ad-hoc query)
Rulează instrucțiuni SELECT punctuale pe baza de date live, fără a modifica fișierele sursă:
SELECT name FROM sqlite_master WHERE type = 'table';
PRAGMA table_info(greetings);
SELECT * FROM greetings WHERE id = 1;Greșeli frecvente
- Utilizarea sintaxei PostgreSQL —
SERIALnu există în SQLite; foloseșteINTEGER PRIMARY KEY AUTOINCREMENT.ON CONFLICT (col) DO NOTHINGfuncționează de asemenea, darINSERT OR IGNOREeste mai idiomatic în SQLite. - Omiterea
INSERT OR IGNORE— rularea repetată a scriptului va eșua cu erori de încălcare a constrângerilor de unicitate dacă o rulare anterioară a inserat deja aceleași rânduri. - Ordinea de execuție între directoare — fișierele sunt sortate după calea lor completă, deci
a/02-init.sqlrulează ÎNAINTE deb/01-init.sql. Pune prefixe și directoarelor atunci când ordinea contează între directoare diferite.