Skip to content

Commit 6f1007c

Browse files
fix
1 parent 272671c commit 6f1007c

File tree

7 files changed

+65
-26
lines changed

7 files changed

+65
-26
lines changed

services/api-server/src/simcore_service_api_server/api/routes/solvers_jobs_getters.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ async def list_jobs(
141141
)
142142
_logger.debug("Listing Jobs in Solver '%s'", solver.name)
143143

144-
projects_page = await webserver_api.get_projects_w_solver_page(
144+
projects_page = await webserver_api.get_projects_w_solver_page( # MD: Call RPC
145145
solver_name=solver.name, limit=20, offset=0
146146
)
147147

@@ -186,7 +186,7 @@ async def get_jobs_page(
186186
)
187187
_logger.debug("Listing Jobs in Solver '%s'", solver.name)
188188

189-
projects_page = await webserver_api.get_projects_w_solver_page(
189+
projects_page = await webserver_api.get_projects_w_solver_page( # MD: Call RPC
190190
solver_name=solver.name, limit=page_params.limit, offset=page_params.offset
191191
)
192192

services/api-server/src/simcore_service_api_server/services_http/webserver.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# pylint: disable=too-many-public-methods
22

3+
import json
34
import logging
45
import urllib.parse
56
from collections.abc import Mapping
@@ -185,14 +186,16 @@ async def _page_projects(
185186
limit: int,
186187
offset: int,
187188
show_hidden: bool,
188-
search: str | None = None,
189+
project_name_search: str | None = None,
189190
) -> Page[ProjectGet]:
190191
assert 1 <= limit <= MAXIMUM_NUMBER_OF_ITEMS_PER_PAGE # nosec
191192
assert offset >= 0 # nosec
192193

193194
optional: dict[str, Any] = {}
194-
if search is not None:
195-
optional["search"] = search
195+
if project_name_search is not None:
196+
optional["filters"] = json.dumps(
197+
{"project_name_search": project_name_search}
198+
)
196199

197200
with service_exception_handler(
198201
service_name="Webserver",
@@ -353,9 +356,7 @@ async def get_projects_w_solver_page(
353356
limit=limit,
354357
offset=offset,
355358
show_hidden=True,
356-
# WARNING: better way to match jobs with projects (Next PR if this works fine!)
357-
# WARNING: search text has a limit that I needed to increase for the example!
358-
search=solver_name,
359+
project_name_search=solver_name,
359360
)
360361

361362
async def get_projects_page(self, *, limit: int, offset: int):

services/web/server/src/simcore_service_webserver/projects/_crud_api_read.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,14 @@ async def list_projects( # pylint: disable=too-many-arguments
6060
project_type: ProjectTypeAPI,
6161
show_hidden: bool,
6262
trashed: bool | None,
63+
# search
64+
multi_column_search: str | None = None,
65+
project_name_search: str | None = None,
6366
# pagination
6467
offset: NonNegativeInt,
6568
limit: int,
69+
# ordering
6670
order_by: OrderBy,
67-
# search
68-
search: str | None,
6971
) -> tuple[list[ProjectDict], int]:
7072
app = request.app
7173
db = ProjectDBAPI.get_from_app_context(app)
@@ -116,7 +118,8 @@ async def list_projects( # pylint: disable=too-many-arguments
116118
filter_trashed=trashed,
117119
filter_hidden=show_hidden,
118120
# composed attrs
119-
filter_by_text=search,
121+
multi_column_search=multi_column_search,
122+
project_name_search=project_name_search,
120123
# pagination
121124
offset=offset,
122125
limit=limit,
@@ -154,7 +157,8 @@ async def list_projects_full_depth(
154157
limit: int,
155158
order_by: OrderBy,
156159
# search
157-
text: str | None,
160+
multi_column_search: str | None,
161+
project_name_search: str | None,
158162
) -> tuple[list[ProjectDict], int]:
159163
db = ProjectDBAPI.get_from_app_context(request.app)
160164

@@ -169,9 +173,10 @@ async def list_projects_full_depth(
169173
folder_query=FolderQuery(folder_scope=FolderScope.ALL),
170174
filter_trashed=trashed,
171175
filter_by_services=user_available_services,
172-
filter_by_text=text,
173176
filter_tag_ids_list=tag_ids_list,
174177
filter_by_project_type=ProjectType.STANDARD,
178+
multi_column_search=multi_column_search,
179+
project_name_search=project_name_search,
175180
offset=offset,
176181
limit=limit,
177182
order_by=order_by,

services/web/server/src/simcore_service_webserver/projects/_crud_handlers.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,13 @@ async def list_projects(request: web.Request):
203203
project_type=query_params.project_type,
204204
show_hidden=query_params.show_hidden,
205205
trashed=query_params.filters.trashed,
206-
limit=query_params.limit,
207-
offset=query_params.offset,
208-
search=query_params.search,
209-
order_by=OrderBy.model_construct(**query_params.order_by.model_dump()),
210206
folder_id=query_params.folder_id,
211207
workspace_id=query_params.workspace_id,
208+
multi_column_search=query_params.search,
209+
project_name_search=query_params.filters.project_name_search,
210+
offset=query_params.offset,
211+
limit=query_params.limit,
212+
order_by=OrderBy.model_construct(**query_params.order_by.model_dump()),
212213
)
213214

214215
page = Page[ProjectDict].model_validate(
@@ -246,10 +247,11 @@ async def list_projects_full_search(request: web.Request):
246247
product_name=req_ctx.product_name,
247248
trashed=query_params.filters.trashed,
248249
tag_ids_list=tag_ids_list,
250+
multi_column_search=query_params.text,
251+
project_name_search=None,
249252
offset=query_params.offset,
250253
limit=query_params.limit,
251254
order_by=OrderBy.model_construct(**query_params.order_by.model_dump()),
252-
text=query_params.text,
253255
)
254256

255257
page = Page[ProjectDict].model_validate(

services/web/server/src/simcore_service_webserver/projects/_crud_handlers_models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ class ProjectFilters(Filters):
9898
default=False,
9999
description="Set to true to list trashed, false to list non-trashed (default), None to list all",
100100
)
101+
project_name_search: str | None = Field(
102+
default=None,
103+
description="A search query to filter projects by their name. This field performs a case-insensitive partial match against the project name field.",
104+
)
101105

102106

103107
ProjectsListOrderParams = create_ordering_query_model_class(

services/web/server/src/simcore_service_webserver/projects/db.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,10 @@ async def list_projects( # pylint: disable=too-many-arguments,too-many-statemen
372372
filter_published: bool | None = False,
373373
filter_hidden: bool | None = False,
374374
filter_trashed: bool | None = False,
375-
filter_by_text: str | None = None,
376375
filter_tag_ids_list: list[int] | None = None,
376+
# search
377+
multi_column_search: str | None = None,
378+
project_name_search: str | None = None,
377379
# pagination
378380
offset: int | None = 0,
379381
limit: int | None = None,
@@ -464,7 +466,7 @@ async def list_projects( # pylint: disable=too-many-arguments,too-many-statemen
464466
& (projects_to_products.c.product_name == product_name)
465467
)
466468
)
467-
if filter_by_text is not None:
469+
if multi_column_search is not None:
468470
private_workspace_query = private_workspace_query.join(
469471
users, users.c.id == projects.c.prj_owner, isouter=True
470472
)
@@ -538,7 +540,7 @@ async def list_projects( # pylint: disable=too-many-arguments,too-many-statemen
538540
== workspace_query.workspace_id # <-- Specific shared workspace
539541
)
540542

541-
if filter_by_text is not None:
543+
if multi_column_search is not None:
542544
# NOTE: fields searched with text include user's email
543545
shared_workspace_query = shared_workspace_query.join(
544546
users, users.c.id == projects.c.prj_owner, isouter=True
@@ -574,12 +576,16 @@ async def list_projects( # pylint: disable=too-many-arguments,too-many-statemen
574576
# not marked as trashed
575577
else projects.c.trashed.is_(None)
576578
)
577-
if filter_by_text is not None:
579+
if multi_column_search is not None:
578580
attributes_filters.append(
579-
(projects.c.name.ilike(f"%{filter_by_text}%"))
580-
| (projects.c.description.ilike(f"%{filter_by_text}%"))
581-
| (projects.c.uuid.ilike(f"%{filter_by_text}%"))
582-
| (users.c.name.ilike(f"%{filter_by_text}%"))
581+
(projects.c.name.ilike(f"%{multi_column_search}%"))
582+
| (projects.c.description.ilike(f"%{multi_column_search}%"))
583+
| (projects.c.uuid.ilike(f"%{multi_column_search}%"))
584+
| (users.c.name.ilike(f"%{multi_column_search}%"))
585+
)
586+
if project_name_search is not None:
587+
attributes_filters.append(
588+
projects.c.name.like(f"%{project_name_search}%")
583589
)
584590
if filter_tag_ids_list:
585591
attributes_filters.append(

services/web/server/tests/unit/with_dbs/02/test_projects_crud_handlers__list_with_query_params.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,27 @@ async def test_list_projects_with_search_parameter(
184184
data, 1, 0, 1, "/v0/projects?search=nAmE+5&offset=0&limit=20", 1
185185
)
186186

187+
# Now we will test specific project name search (used by the API server)
188+
query_parameters = {"filters": '{"project_name_search": "Yoda"}'}
189+
url = base_url.with_query(**query_parameters)
190+
assert (
191+
f"{url}"
192+
== f"/{api_version_prefix}/projects?filters=%7B%22project_name_search%22:+%22Yoda%22%7D"
193+
)
194+
195+
resp = await client.get(f"{url}")
196+
data = await resp.json()
197+
198+
assert resp.status == 200
199+
_assert_response_data(
200+
data,
201+
1,
202+
0,
203+
1,
204+
"/v0/projects?filters=%7B%22project_name_search%22:+%22Yoda%22%7D&offset=0&limit=20",
205+
1,
206+
)
207+
187208
# Now we will test part of uuid search
188209
query_parameters = {"search": "2-fe1b-11ed-b038-cdb1"}
189210
url = base_url.with_query(**query_parameters)

0 commit comments

Comments
 (0)