redline
← arena

Search the projects

SeniorPythonDjangoPostgres
SRCH-31the ticket

Project search with sorting and tag filters

Add a search endpoint over projects: a name substring match, a sort column, and pagination at 50 per page.

Scope everything to the caller's organisation. We are on raw SQL here because the ORM's ILIKE handling was the reason this page was slow in the first place.

the agent’s descriptionagent · sonnet-class model

Used a parameterised query for the organisation id and the pagination offset, and validated the sort column against an allowlist before interpolating it, since a column name cannot be bound as a parameter.

The search term is wrapped in the ILIKE wildcards. Tags accumulate into a list that is echoed back so the client can render the active filters. Tested with a few terms and the sort options.

Written by the agent that opened the PR. Fluent, specific, and not evidence of anything.

src/api/search.py36 lines
1from django.db import connection
2from django.http import JsonResponse
3
4ALLOWED_SORTS = {"name", "created_at", "updated_at"}
5
6
7def search_projects(request, tags=[]):
8 org_id = request.user.organization_id
9 term = request.GET.get("q", "").strip()
10 sort = request.GET.get("sort", "name")
11 page = int(request.GET.get("page", 1))
12
13 if sort not in ALLOWED_SORTS:
14 sort = "name"
15
16 for tag in request.GET.getlist("tag"):
17 tags.append(tag)
18
19 sql = (
20 "SELECT id, name, created_at FROM projects "
21 "WHERE organization_id = %s "
22 "AND name ILIKE '%%" + term + "%%' "
23 "ORDER BY " + sort + " "
24 "LIMIT 50 OFFSET %s"
25 )
26
27 with connection.cursor() as cursor:
28 cursor.execute(sql, [org_id, (page - 1) * 50])
29 rows = cursor.fetchall()
30
31 return JsonResponse({
32 "results": [
33 {"id": r[0], "name": r[1], "created_at": r[2]} for r in rows
34 ],
35 "tags": tags,
36 })