TypeScript lambdas that turn into SQL (like dotnet ef core / linq). Would you use this?
TL;DR: I want to bring EF Core / LINQ-style querying to TypeScript: you write a normal lambda, a build step turns it into parameterized SQL, and the same query also runs on plain arrays in your tests. It'd be read-only, so you'd pair it with your existing writer, and the lambda becomes serializable data so it works beyond SQL too. Would you use it?
I've been writing .NET and TypeScript for about 10 years, and I'm a huge EF Core fan. I've always missed that style of querying in TS, so I put together the idea below and want to know if people would actually use it.
The idea: you write a normal lambda, and a build-time plugin turns it into two things at once: the function itself, and a small data tree describing it. A provider turns that tree into SQL.
const adults = await db.users
.where(u => u.age >= minAge && u.name.startsWith(prefix))
.select(u => ({ id: u.id, name: u.name }))
.toArray();
// runs as parameterized SQL:
// SELECT "id", "name" FROM "users"
// WHERE "age" >= $1 AND "name" LIKE $2
No special query syntax, no config objects, just a predicate you could pass to .filter(). The nice part: the same query runs against plain arrays in your tests (no database) and turns into SQL in production. Captured variables like minAge become bound parameters, so nothing gets pasted into the SQL string.
How it would work, short version:
- At build time the plugin reads your lambda and keeps both the function and a plain-object tree of it.
- Each step (
where,select, …) just adds to a query plan. Nothing runs yet. - When you call
toArray()(orfirst(),count()), the provider turns the tree into SQL, or in tests just runs your original lambda.
The inspiration is C#'s Expression<Func<T, bool>> + IQueryable<T> and EF Core's ideas (include/thenInclude, split queries, no silent client-side eval), rebuilt for TS. C# gets this from the compiler; TS doesn't, so a Vite/Rollup plugin would fill the gap.
Would you use it as your ORM? One honest catch: it'd be read-only (no writes, no migrations). You'd pair it with whatever already handles writes and use this for the reads. Deal-breaker, or fine by you?
It also works beyond SQL, since the lambda becomes plain JSON:
- Send a filter from the client to the server as data, and run it there.
- One rule can be both a SQL
WHEREand a per-object "can this user see this?" check. - Store rules as data (feature flags, alerts) and edit them in a UI.
- Run predicates in a Web Worker or under a strict CSP (no
eval).
So: would you use this for your DB queries? And which non-SQL use, if any, would actually make you try it?
Curious whether people would actually reach for this. Roast the idea.