|
| 1 | +import dataclasses |
| 2 | +import datetime |
1 | 3 | import itertools
|
2 | 4 | import math
|
3 | 5 | import sqlite3
|
|
15 | 17 | from .short_release_info import ReleaseInfoModel, ShortReleaseInfo
|
16 | 18 |
|
17 | 19 |
|
| 20 | +@dataclasses.dataclass(frozen=True) |
| 21 | +class SearchResultItem: |
| 22 | + canonical_name: str |
| 23 | + summary: str | None = None |
| 24 | + release_version: str | None = None |
| 25 | + release_date: datetime.datetime | None = None |
| 26 | + |
| 27 | + |
18 | 28 | class RepositoryStatsModel(typing.TypedDict):
|
19 | 29 | n_packages: int
|
20 | 30 | n_dist_info: int
|
21 | 31 | n_packages_w_dist_info: int
|
22 | 32 |
|
23 | 33 |
|
24 | 34 | class QueryResultModel(typing.TypedDict):
|
25 |
| - exact: tuple[str, str, str, str] | None |
26 | 35 | search_query: str
|
27 |
| - results: list[tuple[str, str, str, str]] |
| 36 | + results: list[SearchResultItem] |
28 | 37 | results_count: int # May be more than in the results list (since paginated).
|
29 |
| - single_name_proposal: str | None |
30 | 38 | page: int # Note: starts at 1.
|
31 | 39 | n_pages: int
|
32 | 40 |
|
@@ -102,7 +110,9 @@ def _compatibility_matrix(
|
102 | 110 | # Compute the compatibility matrix for the given files.
|
103 | 111 | return compatibility_matrix.compatibility_matrix(files)
|
104 | 112 |
|
105 |
| - def project_query(self, query: str, page_size: int, page: int) -> QueryResultModel: |
| 113 | + async def project_query( |
| 114 | + self, query: str, page_size: int, page: int |
| 115 | + ) -> QueryResultModel: |
106 | 116 | try:
|
107 | 117 | search_terms = _search.parse(query)
|
108 | 118 | except _search.ParseError:
|
@@ -133,27 +143,34 @@ def project_query(self, query: str, page_size: int, page: int) -> QueryResultMod
|
133 | 143 | f"Requested page (page: {page}) is beyond the number of pages ({n_pages})",
|
134 | 144 | )
|
135 | 145 |
|
136 |
| - if single_name_proposal: |
137 |
| - exact = cursor.execute( |
138 |
| - "SELECT canonical_name, summary, release_version, release_date FROM projects WHERE canonical_name == ?", |
139 |
| - (single_name_proposal,), |
140 |
| - ).fetchone() |
141 | 146 | results = cursor.execute(
|
142 | 147 | "SELECT canonical_name, summary, release_version, release_date FROM projects WHERE "
|
143 | 148 | f"{condition_query} LIMIT ? OFFSET ?",
|
144 | 149 | condition_terms + (page_size, offset),
|
145 | 150 | ).fetchall()
|
146 | 151 |
|
147 |
| - # Drop the duplicate. |
148 |
| - if exact in results: |
149 |
| - results.remove(exact) |
| 152 | + # Convert results to SearchResultItem objects |
| 153 | + results = [SearchResultItem(*result) for result in results] |
| 154 | + |
| 155 | + # Check if single_name_proposal is already in the results |
| 156 | + if single_name_proposal and page == 1: |
| 157 | + exact_found = any(r.canonical_name == single_name_proposal for r in results) |
| 158 | + if not exact_found: |
| 159 | + # Not in results, check if it exists in repository |
| 160 | + try: |
| 161 | + await self.source.get_project_page(single_name_proposal) |
| 162 | + # Package exists in repository! Add it to the beginning |
| 163 | + results.insert( |
| 164 | + 0, SearchResultItem(canonical_name=single_name_proposal) |
| 165 | + ) |
| 166 | + n_results += 1 |
| 167 | + except PackageNotFoundError: |
| 168 | + pass |
150 | 169 |
|
151 | 170 | return QueryResultModel(
|
152 |
| - exact=exact, |
153 | 171 | search_query=query,
|
154 | 172 | results=results,
|
155 | 173 | results_count=n_results,
|
156 |
| - single_name_proposal=single_name_proposal, |
157 | 174 | page=page,
|
158 | 175 | n_pages=n_pages,
|
159 | 176 | )
|
|
0 commit comments