You are currently viewing Reylo: import file .sql vào TypeScript với type inference đầy đủ, không cần codegen

Reylo: import file .sql vào TypeScript với type inference đầy đủ, không cần codegen

Bạn viết SQL trong file .sql cho gọn, rồi phải chép tay type của kết quả trả về vào TypeScript. Đổi một cột trong file SQL là type bên TS lệch ngay, mà tsc không biết gì để báo. Reylo giải quyết đúng cái đau đó: import file .sql thẳng vào code TS, type được suy ra từ chính câu query, kiểm tra với database thật lúc chạy type check.

Nó làm gì, cụ thể

Repo colinhacks/reylo là engine viết bằng Rust (629 sao, license MIT) do colinhacks làm, tác giả của Zod. Cách dùng rất trực tiếp. Bạn có file query:

-- get_author.sql
select u.id, u.name, count(p.id)::int as post_count
from users u
left join posts p on p.user_id = u.id
where u.id = :id::int
group by u.id

Import nó vào TypeScript:

// main.ts
import postgres from "postgres";
import getAuthor from "./get_author.sql";

const db = postgres(process.env.DATABASE_URL);

const author = await getAuthor.run(db, { id: 1 });
// { id: number; name: string; post_count: number } | null

Không có bước generate file, không watcher, không schema file phải đồng bộ. Type checker gọi thẳng Reylo để lấy type. Cơ chế đứng sau là TypeScript content mappers, tính năng mới trong TypeScript 7.1 (đang beta), cho phép định nghĩa static type động cho các loại file bên ngoài và nhét vào quá trình compile của TS.

Reylo cho database thật prepare câu query (không chạy), rồi đọc lại type của từng cột và từng parameter. Trên nền đó nó suy thêm: cột nào nullable, cardinality (match theo primary key hay unique key thì trả Row | null, aggregate không group by thì trả đúng một Row, insert/update/delete không returning thì void), union từ enum hoặc check constraint liệt kê giá trị, và shape của JSON nếu cột có JSON Schema check.

Cái hay về mặt lý thuyết: mỗi sự thật nằm đúng một chỗ. Cột đổi tên trong DB thành type error ngay trong tsc và trong editor. Agent viết code cũng không để lại được một type cũ mèm, vì type check sẽ lôi ra mọi caller bị ảnh hưởng.

Vì sao đang được chú ý

629 sao trong khoảng một ngày (tạo 2026-10-21, cập nhật 2026-10-22) là con số đáng để ý, nhưng lý do thực tế hơn nằm ở chỗ nó đánh trúng một khoảng trống có thật. Các hướng hiện tại đều có vấn đề riêng: ORM thì phải viết query bằng API riêng, mất tự do SQL; query builder thì vẫn phải khai báo type tay; còn codegen (kiểu sinh type từ schema) thì thêm một bước build, thêm file sinh ra, thêm chỗ để lệch.

Reylo chọn hướng khác: SQL là nguồn sự thật duy nhất. Bạn giữ nguyên dialect, giữ nguyên function, operator, cú pháp đặc thù của Postgres, MySQL hay SQLite. Không cần viết lại query sang API của thư viện nào. Với người đã quen viết SQL tay, đây là điểm cộng rõ ràng.

Cài đặt và chạy thử

Yêu cầu: TypeScript 7.1 (bản beta, bản đầu tiên có content mappers), Node 24 trở lên, và một dev database đang chạy (Postgres, MySQL 8.0.22+ hoặc file SQLite). Reylo đọc schema hiện tại từ database đó.

npm install reylo
npm install -D @reylosql/postgres # or mysql, sqlite
npm install -D typescript@beta

Khai báo trong tsconfig.json, cho file .sql và file project .reylo.yaml hoặc .reylo.yml:

// tsconfig.json
{
 "compilerOptions": { /* ... */ },
 "contentMappers": [
 { "package": "reylo", "extensions": [".sql", ".reylo.yaml", ".reylo.yml"] }
 ]
}

Type check với --runExternalCode để tsc được phép chạy content mappers:

// package.json
{
 "scripts": {
 "typecheck": "tsc --noEmit --runExternalCode"
 }
}

Trỏ Reylo vào dev database qua DATABASE_URL, đặt trong environment hoặc .env. Scheme của URL cho biết bạn dùng database nào:

# .env
DATABASE_URL=postgres://localhost:5432/app # or mysql://…, or file:./app.db for SQLite

Để import .sql chạy được cả lúc runtime, nạp Reylo ở chỗ code chạy. Trên Node:

node --env-file=.env --import reylo/register main.ts

Còn với Bun, Vite, Next.js, esbuild, webpack, Rspack, Cloudflare Workers hay Jest thì thêm plugin tương ứng, hoặc copy example project có sẵn trong tài liệu. Query viết trong file .sql, đặt tên parameter bằng dấu hai chấm, cast type khi query chưa xác định được:

-- get_user.sql
select id, name, email from users where id = :id::int
import getUser from "./get_user.sql";

const user = await getUser.run(db, { id: 1 });
// { id: number; name: string; email: string | null } | null

Truyền vào .run() client của driver bạn dùng: pool, client, hoặc connection/transaction lấy từ đó. Query import còn có .runSync(), .with(), .sql và .raw.

Ai nên dùng

Hợp nhất với team viết SQL tay và muốn type an toàn mà không kéo theo ORM. Ví dụ: một service nhỏ dùng postgres.js, vài chục câu query đặt trong thư mục sql/, giờ có thể bỏ hẳn các interface Row viết tay. Cũng hợp với ai đang làm việc cùng coding agent: type check bắt được mọi chỗ gọi bị ảnh hưởng khi schema đổi, agent khó để lại type cũ.

Không hợp bằng nếu bạn cần chạy trên CI không có database. Reylo cần dev database sống để đọc schema, nên pipeline phải dựng Postgres/MySQL/SQLite trước khi type check. Cũng chưa hợp nếu team chưa sẵn sàng lên TypeScript beta.

So với lựa chọn khác

So với ORM kiểu Drizzle hay Prisma: hai bên đó có schema riêng, query viết bằng API của họ (hoặc qua raw SQL kèm type tay). Reylo không có schema file, type sinh từ chính câu SQL đã prepare trên database. Đổi lại, bạn không có migration tool hay relation API đi kèm. Với codegen truyền thống (kiểu pgtyped hay sqlc bên Go), khác biệt nằm ở chỗ Reylo bỏ hẳn bước sinh file: type checker hỏi trực tiếp. Đây là điểm mạnh về mặt DX nhưng cũng là lý do nó phụ thuộc vào TypeScript 7.1.

Ưu điểm và những chỗ cần cân nhắc

Ưu điểm rõ: giữ nguyên SQL gốc, không viết lại query; type đến từ database thật nên bắt được cột gõ sai, parameter sai, bảng bị drop; hỗ trợ nhiều driver (Postgres: pg, postgres.js, Bun.sql, PGlite, Neon, pg-promise, @vercel/postgres; MySQL: mysql2, PlanetScale, Bun.sql; SQLite: better-sqlite3, node:sqlite, Bun.sql, libSQL, Turso, Cloudflare D1, sqlite3, sqlite); license MIT, dùng thoải mái.

Hạn chế thì phải nói thẳng. Đây là dự án rất mới, mới một ngày tuổi, tài liệu mới ở dạng trang web reylo.dev và bản Markdown cho agent ở reylo.dev/llms.txt. Nó phụ thuộc TypeScript 7.1 beta, tức là chưa production-ready theo nghĩa TypeScript ổn định, và cần Node 24+. Yêu cầu dev database sống khi type check là điểm trừ với CI/CD. Engine viết bằng Rust nên cài đặt có thêm binary, cần kiểm tra tương thích với môi trường deploy của bạn. Chưa có nhiều thực chiến để đánh giá độ ổn định khi schema lớn hoặc query phức tạp.

Với 629 sao trong ngày đầu, Reylo đáng để thử ở một nhánh nhỏ trước, nhất là nếu bạn đang dùng postgres.js và đã chán việc viết tay type cho từng câu query. Còn đưa vào production ngay thì nên chờ TypeScript 7.1 ra bản ổn định. Repo ở đây: colinhacks/reylo.

Câu hỏi thường gặp

Reylo là gì và khác gì ORM như Drizzle hay Prisma?

Reylo là engine viết bằng Rust cho phép import file .sql thẳng vào TypeScript, type được suy ra từ chính câu query đã prepare trên database thật. Khác với Drizzle hay Prisma, nó không có schema file riêng và không bắt bạn viết query bằng API của thư viện, SQL gốc là nguồn sự thật duy nhất. Đổi lại bạn không có migration tool hay relation API đi kèm.

Reylo có cần database chạy khi type check không?

Có. Reylo cho database thật prepare câu query (không chạy) để đọc type của từng cột và từng parameter, nên cần một dev database đang chạy (Postgres, MySQL 8.0.22+ hoặc file SQLite). Vì vậy trên CI không có database thì pipeline phải dựng Postgres/MySQL/SQLite trước khi chạy type check, đây là điểm trừ với CI/CD.

Reylo cần phiên bản TypeScript và Node nào?

Reylo yêu cầu TypeScript 7.1 bản beta, bản đầu tiên có content mappers, và Node 24 trở lên. Bạn cài bằng npm install -D typescript@beta, khai báo contentMappers trong tsconfig.json và chạy type check với cờ --runExternalCode. Vì phụ thuộc TypeScript 7.1 beta nên nó chưa production-ready theo nghĩa TypeScript ổn định.

Chia sẻ bài này

TelegramXFacebookZalo
Đăng ngày 23/10/2026
Giang Na
Về tác giả: Giang Na
Người lập ra blog từ 2015 với những bài về Blogspot. Giờ tập trung vào cách đưa AI vào việc thường ngày, theo hướng thực dụng và dễ làm theo.

Giang Na

Người lập ra blog từ 2015 với những bài về Blogspot. Giờ tập trung vào cách đưa AI vào việc thường ngày, theo hướng thực dụng và dễ làm theo.