Saltar al contenido principal
J
JSORM
MPL-2.0 · ESM-only · Node · Browser · Edge

Modelos que generan tipos.
Queries que llegan tipadas.

Defines tu modelo una vez; jsorm gen genera los tipos y el runtime; y consultas con una API declarativa que compila a AST y SQL según el provider. El resultado llega tipado —relaciones incluidas— en Node, en el browser y en el edge.

Get started Ver la API completa
$ pnpm dlx @jsorm/cli configure

Playground — del modelo al resultado

models/user.ts

lp.playground.model.blurb

1 import { defineModel, t, r } from "@jsorm/core";
2
3 export const User = defineModel("users", {
4 db: "main",
5 fields: {
6 id: t.uuid().primary().autoCreate(),
7 name: t.string(100),
8 email: t.string(255).unique(),
9 active: t.boolean().default(true),
10 createdAt: t.dateTime().autoCreate(),
11 updatedAt: t.dateTime().autoUpdate(),
12 },
13 relations: {
14 posts: r.hasMany("post"),
15 role: r.belongsTo("role"),
16 roles: r.manyToMany("role", {
17 through: "user_roles",
18 extra: { role: t.string(50) },
19 }),
20 },
21 });

Modelo definido → AST → Provider → Base de datos → Resultado tipado

Por qué JSORM

No es un query builder más: es una capa que borra el trabajo repetitivo entre tu esquema, tus tipos y tu base de datos.

Developer experience

El flujo es corto y siempre el mismo: escribes el modelo, corresjsorm gen(o lo dejas en watch) y el editor ya sabe todo lo demás.

terminal
pnpm dlx @jsorm/cli configure
pnpm add @jsorm/client @jsorm/core
pnpm add -D @jsorm/cli
pnpm jsorm gen

// → .jsorm/types.ts + runtime files
// → jsorm.users.get() ya está tipado

watch mode

pnpm jsorm watch
// regenera tipos al guardar el modelo

Core capabilities

Todo lo que necesitas para modelar y consultar, con la API real de JSORM.

email: t.string(255).unique(),
role: t.enum(["admin", "user"]),
meta: t.json().nullable(),

await jsorm.users.first({
select: { name: { as: "Nombre" } },
where: { email: "juan@test.com" },
});

roles: r.manyToMany("role", {
through: "user_roles",
extra: { role: t.string(50) },
}),

await jsorm.users.get();
await jsorm.cache.sessions.get();
await jsorm.analytics.event.get();

pnpm jsorm configure
pnpm jsorm gen
pnpm jsorm watch

--provider sqlite-node
--provider postgres-node
--provider indexeddb

Antes vs. con JSORM

La misma tarea: traer usuarios activos con sus roles, tipados.

a manoboilerplate
1 interface UserRow {
2 id: string;
3 name: string;
4 role_name: string | null;
5 }
6
7 const rows = await db.query<UserRow>(
8 `SELECT u.id, u.name, r.name AS role_name
9 FROM users u
10 LEFT JOIN user_roles ur ON ur.user_id = u.id
11 LEFT JOIN roles r ON r.id = ur.role_id
12 WHERE u.active = $1
13 ORDER BY u.created_at DESC`,
14 [true],
15 );
16
17 const users = groupRows(rows) as User[]; // cast manual
  • Esquema duplicado en SQL y en TypeScript
  • Joins y agrupado escritos a mano en cada query
  • El cast oculta errores hasta runtime
con JSORMexpresivo
1 const { data: users } = await jsorm.users.get({
2 select: { id: true, name: true, roles: { name: true } },
3 where: { active: true },
4 orderBy: { createdAt: "desc" },
5 });
  • Una definición como fuente de verdad
  • Relaciones resueltas por la relación declarada
  • Tipo exacto inferido del select, sin casts

Empieza en un comando

El asistente configura provider, naming y rutas. Después solo defines modelos y consultas.

$pnpm dlx @jsorm/cli configure