Queries
Construcción
Sección titulada «Construcción»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.
Operadores where escalares
Sección titulada «Operadores where escalares»| Operador | Comportamiento |
|---|---|
{ 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 |
Operadores lógicos
Sección titulada «Operadores lógicos»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' } } }, ], },});Paginación por cursor
Sección titulada «Paginación por cursor»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
cursorrequiereorderBy - jsorm agrega automáticamente un tie-breaker de clave primaria si es necesario
cursor.takeestá limitado porJSORM_CURSOR_HARD_MAX_LIMIT(default1000)
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 }Insert masivo
Sección titulada «Insert masivo»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: numberPrimer registro
Sección titulada «Primer registro»const user = await jsorm.first(User, { select: { id: true, name: true }, where: { email: { eq: 'alice@example.com' } },});// user: { id: number; name: string } | nullMutaciones de relaciones
Sección titulada «Mutaciones de relaciones»// manyToMany: array de IDs (shorthand)await jsorm.insert(User, { name: 'Bob', createdAt: new Date(), roles: [1, 2],});
// manyToMany: connect/disconnect en updateawait jsorm.update(User, { data: { roles: { connect: [3], disconnect: [1] }, }, where: { id: { eq: 5 } },});Precompilar queries
Sección titulada «Precompilar queries»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 },});SQL directo
Sección titulada «SQL directo»const rows = await jsorm.executeSql( 'SELECT id, name FROM users WHERE active = $1 AND created_at > $2', [true, new Date('2024-01-01')],);Buenas prácticas
Sección titulada «Buenas prácticas»- Mantén
whereexplícito en todas las operaciones de escritura. - Prefiere filtros de relación anidados sobre joins en SQL directo.
- Usa
orderByconpaginationpara endpoints de lista estables. - Usa paginación
cursorpara scroll infinito o datasets muy grandes. - Usa
count()ofirst()en lugar de traer todos los registros solo para verificar existencia.