# API de consultas PQL

> Ejecuta una consulta PQL sobre los datos de pruebas de la organización y consulta el esquema con el que se valida, a través de la API para integradores.

PQL (Probara Query Language) lee los datos de pruebas de la organización: casos, suites, ejecuciones, casos de ejecución, resultados, defectos, hitos, planes y pasos compartidos. Una consulta indica una entidad, la filtra y puede agruparla y agregarla. Esta página describe los endpoints, lo que responden y sus límites.

Cada entidad, campo, operador, función y código de error del lenguaje está en la [referencia del lenguaje PQL](https://docs.probara.net/es/guides/pql-reference/).

Las consultas están disponibles en los planes **Pro** y **Enterprise**, los mismos que los dashboards. En cualquier otro plan, todos los endpoints de esta página responden `403 forbidden`. `dashboardsEnabled` en [`GET /api/v1/orgs/current`](https://docs.probara.net/es/developers/api-reference/) muestra la configuración del plan.

| Método y ruta              | Qué hace                                                      |
| -------------------------- | ------------------------------------------------------------- |
| `POST /api/v1/query`       | Ejecuta una consulta y responde una página de filas o grupos. |
| `GET /api/v1/query/schema` | Responde el esquema con el que se valida una consulta.        |

Todo miembro puede ejecutar consultas, incluidos los lectores. Para guardar una consulta y reutilizarla, consulta [Consultas guardadas](https://docs.probara.net/es/developers/api/saved-queries/).

## Ejecutar una consulta

`POST /api/v1/query` recibe un cuerpo JSON:

```json
{ "query": "FROM results WHERE status = failed", "offset": 0 }
```

- `query` es obligatorio: de 1 a 4.000 caracteres.
- `offset` es opcional. Sustituye el OFFSET de la consulta para paginar, de 0 a 10.000.

Los resultados solo incluyen los proyectos que puedes abrir, y nunca incluyen proyectos archivados. `scope.hiddenProjectCount` cuenta los demás proyectos de la organización que no puedes abrir, así que un resultado nunca parece completo cuando hay proyectos ocultos.

## Formas de respuesta

Una consulta sin agregados responde **filas**. Cada fila es un registro, con un `link` hacia él y sus `values`, uno por columna:

- `mode` es `rows`, y `columns` describe cada columna con su `key`, `label` y `type`.
- `total` cuenta las filas que coinciden, de forma exacta hasta 10.000. A partir de ahí, `total` es 10.000 y `totalCapped` es `true`.
- `limit` es el tamaño de página: el LIMIT de la consulta, 50 por defecto y 500 como máximo.
- `offset`, `scope` y `timeZone` repiten la página, el recuento de proyectos y la zona horaria con la que se leyeron las fechas.
- `timeZoneFallback` es `true` solo cuando no se pudo leer la zona horaria guardada del usuario, así que respondió la zona por defecto.

Una consulta con un `SELECT` de agregados, o con un `GROUP BY`, responde **grupos**:

- `mode` es `aggregate`. Cada columna tiene un `role`: `group` para una clave de agrupación, o `measure` para un valor calculado por grupo.
- Cada fila tiene `values` y no tiene `link`.
- Los grupos se limitan a 1.000. `total` cuenta los grupos hasta ese límite, y `truncated` es `true` cuando hay más.
- `passRate()` es el porcentaje de filas ejecutadas que pasaron: un número de 0 a 100, redondeado a un decimal, o `null` cuando no se ejecutó nada. Un resultado cuenta como ejecutado salvo que su estado sea `untested`. En las ejecuciones, lo ejecutado suma los casos aprobados, fallidos, bloqueados y omitidos. `passRate()` solo se aplica a resultados y ejecuciones.

## Referencias a consultas guardadas

`in query("nombre")` y `not in query("nombre")` filtran el `id` visible de la entidad según las filas de otra consulta guardada. Los nombres se comparan sin distinguir mayúsculas.

- El nombre se resuelve entre las consultas guardadas que puedes ver. Una consulta que no puedes ver es desconocida, y su nombre nunca aparece en una sugerencia.
- La consulta referenciada debe ser una consulta de filas sobre la misma entidad. Su WHERE se aplica con tu propio acceso a proyectos. Sus `ORDER BY`, `LIMIT` y `OFFSET` se ignoran.
- Una consulta referenciada puede referenciar otra, hasta tres referencias de profundidad desde la consulta que se ejecuta. Un ciclo se rechaza.
- El texto referenciado se valida contra los campos actuales cada vez que se ejecuta la consulta, así que una referencia siempre usa el texto vigente de la consulta guardada. Una referencia que ya no valida responde `pql_invalid` con `referenced_query_invalid`.
- Los rechazos aparecen en `details.errors`: `unknown_value` (ninguna consulta visible tiene ese nombre), `query_entity_mismatch`, `query_not_rows`, `query_depth_exceeded`, `query_cycle` y `referenced_query_invalid`.

## Esquema

`GET /api/v1/query/schema` responde con lo que se valida en una consulta, para quien hace la llamada:

- `customFields`: los campos personalizados que aplican a tus proyectos, con sus opciones.
- `members` y `groups`: los miembros activos y los grupos de usuarios.
- `savedQueries`: los nombres de las consultas guardadas que puedes ver, ordenados por nombre. El esquema devuelve como máximo 500 y `savedQueriesTruncated` es `true` cuando hay más. Una referencia a cualquier nombre visible sigue resolviéndose.
- `hints`: las listas de valores de suites, hitos, planes, entornos, proyectos y etiquetas. Cada lista se limita a 500 nombres, con `truncated` activo cuando hay más.

## Errores

Cada error responde `{ "error": { "code", "message" } }`, con un objeto `details` cuando tiene más que decir.

| Estado | Código              | Cuándo                                                                                                           |
| ------ | ------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `403`  | `forbidden`         | El plan de la organización no incluye dashboards, así que las consultas están desactivadas.                      |
| `422`  | `validation_failed` | El cuerpo no es JSON, la consulta está vacía o supera los 4.000 caracteres, o `offset` está fuera de 0 a 10.000. |
| `422`  | `pql_invalid`       | La consulta no se analiza o no valida. `details.errors` lista cada error.                                        |
| `422`  | `pql_unsupported`   | La consulta usa una construcción que añade una versión posterior. `details.construct` la nombra.                 |

Cada entrada de `details.errors` tiene un `code` estable, un `message` localizado, un `span` (`offset`, `line`, `column` y `length`) que señala el texto con el error, los `expected` (tokens o campos esperados) y un `hint` opcional, como un nombre que la consulta pudo querer decir.

## Exportar como CSV

`POST /api/v1/query/export` recibe solo el texto de la consulta y responde sus filas como CSV:

```json
{ "query": "SELECT title, created FROM cases ORDER BY title" }
```

- La exportación tiene las mismas comprobaciones, el mismo ámbito y el mismo acceso que una ejecución, y rechaza lo mismo con los mismos códigos y estados.
- Una consulta de filas escribe sus filas en su orden, hasta 10.000. La cabecera `X-Pql-Export-Truncated` vale `true` cuando hay más filas que coinciden.
- Una consulta con agregados escribe hasta 1.000 grupos, con sus claves de agrupación y sus medidas como columnas.
- El `OFFSET` y el `LIMIT` propios de la consulta no se aplican a una exportación.
- El cuerpo está en UTF-8 con marca de orden de bytes y finales de registro CRLF. El primer registro contiene las etiquetas de las columnas.
- Los valores son valores de máquina: una fecha es su instante ISO-8601 en UTC, una duración son milisegundos, una persona, una opción o una referencia es su nombre, y las etiquetas de una fila se unen con `; `.
- Un texto que una hoja de cálculo interpretaría como fórmula, es decir, que empieza por `=`, `+`, `-`, `@`, un tabulador o un retorno de carro, se escribe con una comilla inicial.
- `Content-Disposition` nombra el archivo `query-AAAA-MM-DD.csv`. `X-Pql-Time-Zone-Fallback` vale `true` cuando no se pudo leer la zona horaria guardada.

La exportación de una consulta guardada se documenta en la [API de consultas guardadas](https://docs.probara.net/es/developers/api/saved-queries/).

## Límites

| Límite                     | Valor                                                          |
| -------------------------- | -------------------------------------------------------------- |
| Texto de la consulta       | 4.000 caracteres                                               |
| `OFFSET`                   | 10.000 como máximo                                             |
| `LIMIT` (tamaño de página) | 50 por defecto, 500 como máximo                                |
| `total` de filas           | Se cuenta de forma exacta hasta 10.000; después, `totalCapped` |
| Grupos                     | 1.000 como máximo; después, `truncated`                        |
