Ir al contenido

Queries

jsorm usa una forma de query estructurada en lugar de builders encadenados. Cada operación es un objeto plano pasado a jsorm.* — legible, serializable e inspectable.

import { jsorm } from 'jsorm';
import { User } from './src/schema/index.js';
const result = await jsorm.get(User, {
select: {
id: true,
name: true,
email: true,
role: { name: true },
_count: true,
},
where: {
AND: [
{ active: true },
{ role: { name: { eq: 'admin' } } },
],
},
orderBy: [{ createdAt: 'desc' }],
pagination: {
perPage: 10,
currentPage: 1,
},
});
// result.data: Array<{ id: number; name: string; email?: string; role: { name: string }; _count: number }>
// result.pagination: { perPage, currentPage, total, lastPage, firstPage }

Cuando se omite pagination, get() aplica un LIMIT 150 por defecto para evitar fetches accidentales de tabla completa. Puedes sobreescribir con JSORM_LIMIT_DEFAULT.

OperadorComportamiento
{ eq: value }Igual
{ ne: value }Distinto
{ gt: value }Mayor que
{ gte: value }Mayor o igual
{ lt: value }Menor que
{ lte: value }Menor o igual
{ in: [...] }Valor en lista
{ contains: string }LIKE %value%
{ startsWith: string }LIKE value%
{ endsWith: string }LIKE %value

Usa AND/OR en el nivel de where para agrupar condiciones:

const result = await jsorm.get(User, {
select: { id: true, name: true },
where: {
OR: [
{ email: { contains: '@corp.com' } },
{ role: { name: { eq: 'admin' } } },
],
},
});

La paginación cursor/keyset está disponible junto a la paginación por offset. Son mutuamente excluyentes:

const page = await jsorm.get(User, {
select: { id: true, name: true },
orderBy: [{ id: 'asc' }],
cursor: {
after: '...token-base64url-opaco...',
take: 25,
},
});
// page.pageInfo: { hasNextPage, hasPreviousPage, startCursor, endCursor }

Reglas del cursor:

  • El modo cursor requiere orderBy
  • jsorm agrega automáticamente un tie-breaker de clave primaria si es necesario
  • cursor.take está limitado por JSORM_CURSOR_HARD_MAX_LIMIT (default 1000)
await jsorm.insert(User, {
name: 'Alice',
email: 'alice@example.com',
createdAt: new Date(),
role: { connect: 1 },
});

Retornar el registro insertado con returning:

const inserted = await jsorm.insert(User, {
name: 'Bob',
createdAt: new Date(),
role: { connect: 2 },
returning: { id: true, name: true },
});
// inserted: { id: number; name: string }
await jsorm.insertMany(User, [
{ name: 'Alice', createdAt: new Date(), role: { connect: 1 } },
{ name: 'Bob', createdAt: new Date(), role: { connect: 2 } },
]);
await jsorm.update(User, {
data: { active: false },
where: { role: { name: { eq: 'guest' } } },
});
await jsorm.delete(User, {
where: { id: { eq: 10 } },
});
const count = await jsorm.count(User, {
where: { active: true },
});
// count: number
const user = await jsorm.first(User, {
select: { id: true, name: true },
where: { email: { eq: 'alice@example.com' } },
});
// user: { id: number; name: string } | null
// manyToMany: array de IDs (shorthand)
await jsorm.insert(User, {
name: 'Bob',
createdAt: new Date(),
roles: [1, 2],
});
// manyToMany: connect/disconnect en update
await jsorm.update(User, {
data: {
roles: { connect: [3], disconnect: [1] },
},
where: { id: { eq: 5 } },
});

Precompila al inicio para eliminar la planificación en el path frío de rutas calientes:

const compiledUsers = await jsorm.compileGet(User, {
select: { id: true, name: true },
});
const rows = await jsorm.executeSql(
'SELECT id, name FROM users WHERE active = $1 AND created_at > $2',
[true, new Date('2024-01-01')],
);
  1. Mantén where explícito en todas las operaciones de escritura.
  2. Prefiere filtros de relación anidados sobre joins en SQL directo.
  3. Usa orderBy con pagination para endpoints de lista estables.
  4. Usa paginación cursor para scroll infinito o datasets muy grandes.
  5. Usa count() o first() en lugar de traer todos los registros solo para verificar existencia.