Ir al contenido

Consultar, actualizar y paginar

Article.query() y los accesos de clase como Article.where(...) crean builders nuevos y recuperan modelos. DB.table("articles") crea un builder que devuelve diccionarios. Ambos utilizan el mismo lenguaje de consultas, pero la tabla cruda no aplica scopes, eventos, ocultación ni eliminación lógica del modelo.

Las cláusulas son síncronas. Solo espera el terminal: await query.get(), no await query.where(...). Este plan se puede inspeccionar sin conexión:

from orionis.orm import Integer, Model, String
class Article(Model):
id = Integer().primary().autoIncrement()
title = String(180)
status = String(30)
timestamps = False
base = Article.where("status", "published")
recent = base.clone().whereContains("title", "Orionis").orderBy("id", "desc").limit(10)
assert recent.toPlan().limit_value == 10
assert len(base.toPlan().wheres) == 1

Los builders mutan su propio estado: usa clone() para ramificar consultas y no compartas uno entre tareas concurrentes.

where("status", "published") significa igualdad; where("id", ">", 10) especifica operador. Un callback agrupa condiciones:

async def search_articles():
return await (
Article.where("status", "published")
.where(lambda group: group.whereContains("title", "Python")
.orWhere("title", "Orionis"))
.whereIn("id", [1, 2, 3])
.orderBy("id")
.get()
)

Ejecuta esta función en una aplicación inicializada con la tabla articles. También están disponibles whereNull, whereNotNull, whereBetween, whereNotBetween, whereNotIn, comparaciones con whereColumn, subconsultas whereExists/whereNotExists y filtros whereLike, whereILike, whereStartsWith, whereEndsWith, whereRegexpMatch. No todos los dialectos admiten las mismas expresiones de regex.

Valores se enlazan como parámetros. whereRaw, selectRaw y havingRaw aceptan SQL confiable y bindings; no interpolan de forma segura texto arbitrario. Controla columnas, operadores y ordenación desde una lista permitida cuando provienen de una petición.

Este fragmento de aplicación produce un informe con tablas crudas existentes:

from orionis.support.facades import DB
async def articles_by_author():
return await (
DB.table("articles", alias="a")
.join("authors", "a.author_id", "=", "u.id", alias="u")
.select("u.id", "u.name")
.selectRaw("COUNT(*) AS article_count")
.groupBy("u.id", "u.name")
.havingRaw("COUNT(*) > :minimum", {"minimum": 1})
.orderBy("u.id")
.get()
)

leftJoin, rightJoin, fullJoin, crossJoin, joinSub y sus variantes permiten otras formas; su compatibilidad depende del motor. Usa nombres calificados para evitar ambigüedad. select, addSelect, selectSub, distinct, union y unionAll completan las proyecciones. Para modelos que después se guardarán o cargarán relaciones, conserva PK y claves de relación en la selección.

Terminal asyncResultado
get()Collection de modelos o diccionarios.
first() / find(key)Un resultado o None.
firstOrFail() / findOrFail(key)Modelo; error si no existe, solo en builder de modelos.
value(column) / pluck(column)Un valor o colección de valores.
count, exists, doesntExistEntero o booleano.
min, max, avg, sumAgregado; sum devuelve 0 sin resultados.
paginate(page=1, per_page=15)Paginator con items y metadatos.

limit, offset, take, skip y forPage componen límites sin ejecutar. Usa orden determinista, incluyendo una clave única, para páginas estables. Paginator expone items, total, page, perPage, lastPage, hasNext, hasPrevious y toDict()/toJson(). Recuento y lectura son dos consultas: fuera de una transacción pueden observar cambios distintos y ejecutarse concurrentemente; dentro se ejecutan en secuencia. Página y tamaño deben ser enteros positivos.

await DB.table("articles").insert({...}) devuelve InsertResult; admite también lista de filas. update(values) y delete() devuelven recuentos. Sin filtro afectan a todas las filas. No añadas limit() suponiendo que limita la escritura: los planes update/delete se construyen con las condiciones, no con la paginación de lectura.

Las escrituras masivas no hidratan cada modelo ni ejecutan su fillable, mutadores o eventos de instancia. Usa instancias cuando necesites esas reglas. El builder de modelos mantiene timestamps de actualización y políticas de soft delete; las tablas crudas no.

lockForUpdate() y sharedLock() se usan dentro de una transacción, siempre según soporte del backend. Redshift los rechaza. Una consulta limitada materializa su resultado; no existe aquí una promesa de cursor streaming. Los fallos de composición producen InvalidQueryException; ejecución/compilación SQL produce errores de la capa de base de datos.