feat(api): sort supporté sur colonnes groupby en mode agrégation (#78)
Testé contre tabular-api data.gouv.fr : sort sur une colonne groupby est honoré (200), sort sur un alias d'agrégat retourne 400 (colonne inconnue). aggregate_marches reçoit order_by ; doc Swagger mise à jour. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+8
-3
@@ -141,9 +141,12 @@ def schema():
|
|||||||
"la colonne de sortie est nommée `colonne__count`, `colonne__sum`, "
|
"la colonne de sortie est nommée `colonne__count`, `colonne__sum`, "
|
||||||
"`colonne__avg`, `colonne__min`, `colonne__max`\n\n"
|
"`colonne__avg`, `colonne__min`, `colonne__max`\n\n"
|
||||||
"En mode agrégation, la réponse contient des lignes groupées, "
|
"En mode agrégation, la réponse contient des lignes groupées, "
|
||||||
"`columns` est interdit et `meta` ne contient pas `total`.\n\n"
|
"`columns` est interdit et `meta` ne contient pas `total`. "
|
||||||
|
"`sort` peut être appliqué sur une colonne `groupby` (ex. `acheteur_departement_code__sort=asc`) ; "
|
||||||
|
"il n'est pas supporté sur les alias d'agrégats (ex. `uid__count__sort=desc` → 400).\n\n"
|
||||||
"Exemples : `acheteur_id__contains=VILLE`, `montant__greater=10000`, "
|
"Exemples : `acheteur_id__contains=VILLE`, `montant__greater=10000`, "
|
||||||
"`acheteur_departement_code__groupby&montant__sum`."
|
"`acheteur_departement_code__groupby&montant__sum`, "
|
||||||
|
"`acheteur_departement_code__groupby&uid__count&acheteur_departement_code__sort=asc`."
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -159,7 +162,8 @@ def data():
|
|||||||
Agrégation (drapeaux sans valeur) : `<colonne>__groupby`,
|
Agrégation (drapeaux sans valeur) : `<colonne>__groupby`,
|
||||||
`<colonne>__count|sum|avg|min|max`. Les colonnes agrégées sont nommées
|
`<colonne>__count|sum|avg|min|max`. Les colonnes agrégées sont nommées
|
||||||
`<colonne>__<opérateur>`. `columns` est interdit avec une agrégation et
|
`<colonne>__<opérateur>`. `columns` est interdit avec une agrégation et
|
||||||
`meta` ne contient alors pas `total`.
|
`meta` ne contient alors pas `total`. `sort` est supporté sur les colonnes
|
||||||
|
`groupby` ; non supporté sur les alias d'agrégats (→ 400).
|
||||||
|
|
||||||
Paramètres réservés : page (défaut 1), page_size (défaut 50, max 1000),
|
Paramètres réservés : page (défaut 1), page_size (défaut 50, max 1000),
|
||||||
columns (csv), count_results (true|false ; mettre false pour économiser
|
columns (csv), count_results (true|false ; mettre false pour économiser
|
||||||
@@ -193,6 +197,7 @@ def data():
|
|||||||
where_sql=where_sql,
|
where_sql=where_sql,
|
||||||
params=params,
|
params=params,
|
||||||
group_by=agg.group_by_sql,
|
group_by=agg.group_by_sql,
|
||||||
|
order_by=order_sql or None,
|
||||||
limit=page_size,
|
limit=page_size,
|
||||||
offset=(page - 1) * page_size,
|
offset=(page - 1) * page_size,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -198,18 +198,21 @@ def aggregate_marches(
|
|||||||
where_sql: str = "TRUE",
|
where_sql: str = "TRUE",
|
||||||
params: tuple | list = (),
|
params: tuple | list = (),
|
||||||
group_by: str | None = None,
|
group_by: str | None = None,
|
||||||
|
order_by: str | None = None,
|
||||||
limit: int | None = None,
|
limit: int | None = None,
|
||||||
offset: int | None = None,
|
offset: int | None = None,
|
||||||
) -> pl.DataFrame:
|
) -> pl.DataFrame:
|
||||||
"""SELECT agrégé paramétré contre la table decp.
|
"""SELECT agrégé paramétré contre la table decp.
|
||||||
|
|
||||||
`select_sql` et `group_by` sont des fragments SQL construits depuis des
|
`select_sql`, `group_by` et `order_by` sont des fragments SQL construits
|
||||||
noms de colonnes validés (jamais de valeur utilisateur libre). Les
|
depuis des noms de colonnes validés (jamais de valeur utilisateur libre).
|
||||||
valeurs de filtre passent par le binding `?` via `params`.
|
Les valeurs de filtre passent par le binding `?` via `params`.
|
||||||
"""
|
"""
|
||||||
sql = f"SELECT {select_sql} FROM decp WHERE {where_sql}"
|
sql = f"SELECT {select_sql} FROM decp WHERE {where_sql}"
|
||||||
if group_by:
|
if group_by:
|
||||||
sql += f" GROUP BY {group_by}"
|
sql += f" GROUP BY {group_by}"
|
||||||
|
if order_by:
|
||||||
|
sql += f" ORDER BY {order_by}"
|
||||||
if limit is not None:
|
if limit is not None:
|
||||||
sql += f" LIMIT {int(limit)}"
|
sql += f" LIMIT {int(limit)}"
|
||||||
if offset is not None:
|
if offset is not None:
|
||||||
|
|||||||
Reference in New Issue
Block a user