Skip to content

Commit b6a5ac2

Browse files
committed
feat(api): add pagination support to /rest/v1/tags endpoint
1 parent 8413a80 commit b6a5ac2

4 files changed

Lines changed: 96 additions & 6 deletions

File tree

application/database/db.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,34 @@ def get_by_tags(self, tags: List[str]) -> List[cre_defs.Document]:
884884
)
885885
return documents
886886

887+
def get_by_tags_with_pagination(
888+
self, tags: List[str], page: int = 1, items_per_page: int = 20
889+
) -> Tuple[Optional[int], List[cre_defs.Document]]:
890+
891+
if not tags:
892+
return 0, []
893+
894+
# Get all documents matching tags (reuse existing logic)
895+
all_documents = self.get_by_tags(tags)
896+
897+
# Apply manual pagination since we have mixed types
898+
total_items = len(all_documents)
899+
total_pages = (
900+
total_items + items_per_page - 1
901+
) // items_per_page # Ceiling division
902+
903+
if total_pages == 0:
904+
return 0, []
905+
906+
# Calculate slice indices
907+
start_idx = (page - 1) * items_per_page
908+
end_idx = start_idx + items_per_page
909+
910+
# Return paginated slice
911+
paginated_documents = all_documents[start_idx:end_idx]
912+
913+
return total_pages, paginated_documents
914+
887915
def get_nodes_with_pagination(
888916
self,
889917
name: str,

application/tests/db_test.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,54 @@ def test_get_by_tags(self) -> None:
125125
self.assertEqual(self.collection.get_by_tags([]), [])
126126
self.assertEqual(self.collection.get_by_tags(["this should not be a tag"]), [])
127127

128+
def test_get_by_tags_with_pagination(self) -> None:
129+
130+
for i in range(5):
131+
dbcre = db.CRE(
132+
description=f"Pagiation CRE {i}",
133+
name=f"PaginationCRE{i}",
134+
tags="pagination-test",
135+
external_id=f"500-{i:03d}",
136+
)
137+
self.collection.session.add(dbcre)
138+
self.collection.session.commit()
139+
140+
total_pages, docs = self.collection.get_by_tags_with_pagination(
141+
["pagination-test"], page=1, items_per_page=10
142+
)
143+
self.assertEqual(len(docs), 5)
144+
self.assertEqual(total_pages, 1)
145+
146+
total_pages, docs = self.collection.get_by_tags_with_pagination(
147+
["pagination-test"], page=1, items_per_page=2
148+
)
149+
self.assertEqual(len(docs), 2)
150+
self.assertEqual(total_pages, 3)
151+
152+
total_pages, docs = self.collection.get_by_tags_with_pagination(
153+
["pagination-test"], page=2, items_per_page=2
154+
)
155+
self.assertEqual(len(docs), 2)
156+
self.assertEqual(total_pages, 3)
157+
158+
total_pages, docs = self.collection.get_by_tags_with_pagination(
159+
["pagination-test"], page=3, items_per_page=2
160+
)
161+
self.assertEqual(len(docs), 1)
162+
self.assertEqual(total_pages, 3)
163+
164+
total_pages, docs = self.collection.get_by_tags_with_pagination(
165+
[], page=1, items_per_page=1
166+
)
167+
self.assertEqual(total_pages, 0)
168+
self.assertEqual(docs, [])
169+
170+
total_pages, docs = self.collection.get_by_tags_with_pagination(
171+
["non-existent-tag"], page=1, items_per_page=10
172+
)
173+
self.assertEqual(total_pages, 0)
174+
self.assertEqual(docs, [])
175+
128176
def test_get_standards_names(self) -> None:
129177
result = self.collection.get_node_names()
130178
expected = [("Standard", "BarStand"), ("Standard", "Unlinked")]

application/tests/web_main_test.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,11 @@ def test_find_document_by_tag(self) -> None:
400400
response = client.get(f"/rest/v1/tags?tag=CW")
401401
self.assertEqual(404, response.status_code)
402402

403-
expected = {"data": [cres["ca"].todict(), cres["cb"].todict()]}
403+
expected = {
404+
"data": [cres["ca"].todict(), cres["cb"].todict()],
405+
"total_pages": 1,
406+
"page": 1,
407+
}
404408

405409
response = client.get(f"/rest/v1/tags?tag=ta")
406410
self.assertEqual(200, response.status_code)

application/web/web_main.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -242,16 +242,26 @@ def find_node_by_name(
242242
@app.route("/rest/v1/tags", methods=["GET"])
243243
def find_document_by_tag() -> Any:
244244
tags = request.args.getlist("tag")
245+
opt_format = request.args.get("format")
246+
247+
page = 1
248+
if request.args.get("page") is not None and int(request.args.get("page")) > 0:
249+
page = int(request.args.get("page"))
250+
251+
items_per_page = int(request.args.get("items_per_page") or ITEMS_PER_PAGE)
252+
245253
if posthog:
246-
posthog.capture(f"find_document_by_tag", f"tags:{tags}")
254+
posthog.capture(f"find_document_by_tag", f"tags:{tags};page:{page}")
247255

248256
database = db.Node_collection()
249-
# opt_osib = request.args.get("osib")
250-
opt_format = request.args.get("format")
251-
documents = database.get_by_tags(tags)
257+
total_pages, documents = database.get_by_tags_with_pagination(
258+
tags, page=page, items_per_page=items_per_page
259+
)
260+
252261
if documents:
253262
res = [doc.todict() for doc in documents]
254-
result = {"data": res}
263+
result = {"data": res, "total_pages": total_pages, "page": page}
264+
255265
# if opt_osib:
256266
# result["osib"] = odefs.cre2osib(documents).todict()
257267
if opt_format == SupportedFormats.Markdown.value:

0 commit comments

Comments
 (0)