Skip to content

Commit f3b9f65

Browse files
committed
✨ Refactor service filters application and enhance service key prefix handling in SQL queries
1 parent 9c6e533 commit f3b9f65

File tree

3 files changed

+55
-47
lines changed

3 files changed

+55
-47
lines changed

services/catalog/src/simcore_service_catalog/repository/_services_sql.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,9 @@ def apply_services_filters(
125125
if prefix is None:
126126
msg = f"Undefined service type {filters.service_type}. Please update prefix expressions"
127127
raise ValueError(msg)
128-
prefix = prefix.rstrip("/") # safety
129-
stmt = stmt.where(services_meta_data.c.service_key.like(f"{prefix}/%"))
128+
129+
assert not prefix.endswith("/") # nosec
130+
return stmt.where(services_meta_data.c.key.like(f"{prefix}/%"))
130131
return stmt
131132

132133

@@ -155,7 +156,7 @@ def latest_services_total_count_stmt(
155156
)
156157

157158
if filters:
158-
apply_services_filters(stmt, filters)
159+
stmt = apply_services_filters(stmt, filters)
159160

160161
return stmt
161162

@@ -199,7 +200,7 @@ def list_latest_services_stmt(
199200
)
200201

201202
if filters:
202-
apply_services_filters(cte_stmt, filters)
203+
cte_stmt = apply_services_filters(cte_stmt, filters)
203204

204205
cte = cte_stmt.cte("cte")
205206

services/catalog/src/simcore_service_catalog/repository/services.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,11 @@ async def list_latest_services(
411411
filters=filters,
412412
)
413413

414+
from simcore_postgres_database.utils import as_postgres_sql_query_str
415+
416+
print(as_postgres_sql_query_str(stmt_total))
417+
print(as_postgres_sql_query_str(stmt_page))
418+
414419
async with self.db_engine.connect() as conn:
415420
result = await conn.execute(stmt_total)
416421
total_count = result.scalar() or 0
@@ -514,7 +519,7 @@ async def get_service_history_page(
514519
)
515520

516521
if filters:
517-
apply_services_filters(base_stmt, filters)
522+
base_stmt = apply_services_filters(base_stmt, filters)
518523

519524
base_subquery = base_stmt.subquery()
520525

services/catalog/tests/unit/with_dbs/test_repositories.py

Lines changed: 44 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
import pytest
1515
from models_library.products import ProductName
1616
from models_library.services_enums import ServiceType # Import ServiceType enum
17+
from models_library.services_regex import (
18+
COMPUTATIONAL_SERVICE_KEY_PREFIX,
19+
DYNAMIC_SERVICE_KEY_PREFIX,
20+
SERVICE_TYPE_PREFIXES,
21+
)
1722
from models_library.users import UserID
1823
from packaging import version
1924
from pydantic import EmailStr, HttpUrl, TypeAdapter
@@ -416,49 +421,46 @@ async def test_list_latest_services_with_filters(
416421
await services_db_tables_injector(
417422
[
418423
create_fake_service_data(
419-
f"simcore/services/dynamic/service-type-a-{i}",
424+
f"{DYNAMIC_SERVICE_KEY_PREFIX}/service-name-a-{i}",
420425
"1.0.0",
421426
team_access=None,
422427
everyone_access=None,
423428
product=target_product,
424-
service_type=ServiceType.DYNAMIC.value,
425429
)
426430
for i in range(3)
427431
]
428432
+ [
429433
create_fake_service_data(
430-
f"simcore/services/dynamic/service-type-b-{i}",
434+
f"{COMPUTATIONAL_SERVICE_KEY_PREFIX}/service-name-b-{i}",
431435
"1.0.0",
432436
team_access=None,
433437
everyone_access=None,
434438
product=target_product,
435-
service_type=ServiceType.COMPUTATIONAL.value,
436439
)
437440
for i in range(2)
438441
]
439442
)
440443

441-
# Test: Apply filter for service_type=ServiceType.DYNAMIC
444+
# Test: Apply filter for ServiceType.DYNAMIC
442445
filters = ServiceFiltersDB(service_type=ServiceType.DYNAMIC)
443446
total_count, services_items = await services_repo.list_latest_services(
444447
product_name=target_product, user_id=user_id, filters=filters
445448
)
446449
assert total_count == 3
447450
assert len(services_items) == 3
448451
assert all(
449-
service.key.startswith("simcore/services/dynamic/service-type-a")
450-
for service in services_items
452+
service.key.startswith(DYNAMIC_SERVICE_KEY_PREFIX) for service in services_items
451453
)
452454

453-
# Test: Apply filter for service_type=ServiceType.COMPUTATIONAL
455+
# Test: Apply filter for ServiceType.COMPUTATIONAL
454456
filters = ServiceFiltersDB(service_type=ServiceType.COMPUTATIONAL)
455457
total_count, services_items = await services_repo.list_latest_services(
456458
product_name=target_product, user_id=user_id, filters=filters
457459
)
458460
assert total_count == 2
459461
assert len(services_items) == 2
460462
assert all(
461-
service.key.startswith("simcore/services/dynamic/service-type-b")
463+
service.key.startswith(COMPUTATIONAL_SERVICE_KEY_PREFIX)
462464
for service in services_items
463465
)
464466

@@ -551,6 +553,15 @@ async def test_can_get_service(
551553
)
552554

553555

556+
def _create_fake_release_versions(num_versions: int) -> set[str]:
557+
release_versions = set()
558+
while len(release_versions) < num_versions:
559+
release_versions.add(
560+
f"{random.randint(0, 2)}.{random.randint(0, 9)}.{random.randint(0, 9)}" # noqa: S311
561+
)
562+
return release_versions
563+
564+
554565
async def test_get_service_history_page(
555566
target_product: ProductName,
556567
create_fake_service_data: Callable,
@@ -562,12 +573,7 @@ async def test_get_service_history_page(
562573
service_key = "simcore/services/dynamic/test-some-service"
563574
num_versions = 10
564575

565-
release_versions = set()
566-
while len(release_versions) < num_versions:
567-
release_versions.add(
568-
f"{random.randint(0, 2)}.{random.randint(0, 9)}.{random.randint(0, 9)}" # noqa: S311
569-
)
570-
576+
release_versions = _create_fake_release_versions(num_versions)
571577
await services_db_tables_injector(
572578
[
573579
create_fake_service_data(
@@ -626,22 +632,23 @@ async def test_get_service_history_page(
626632
assert paginated_history == history[offset : offset + limit]
627633

628634

635+
@pytest.mark.parametrize(
636+
"expected_service_type,service_prefix", SERVICE_TYPE_PREFIXES.items()
637+
)
629638
async def test_get_service_history_page_with_filters(
630639
target_product: ProductName,
631640
create_fake_service_data: Callable,
632641
services_db_tables_injector: Callable,
633642
services_repo: ServicesRepository,
634643
user_id: UserID,
644+
expected_service_type: ServiceType,
645+
service_prefix: str,
635646
):
636647
# Setup: Inject services with multiple versions and types
637-
service_key = "simcore/services/dynamic/test-service"
648+
service_key = f"{service_prefix}/test-service"
638649
num_versions = 10
639650

640-
release_versions = set()
641-
while len(release_versions) < num_versions:
642-
release_versions.add(
643-
f"{random.randint(0, 2)}.{random.randint(0, 9)}.{random.randint(0, 9)}" # noqa: S311
644-
)
651+
release_versions = _create_fake_release_versions(num_versions)
645652

646653
await services_db_tables_injector(
647654
[
@@ -651,13 +658,8 @@ async def test_get_service_history_page_with_filters(
651658
team_access=None,
652659
everyone_access=None,
653660
product=target_product,
654-
service_type=(
655-
ServiceType.DYNAMIC.value
656-
if i % 2 == 0
657-
else ServiceType.COMPUTATIONAL.value
658-
),
659661
)
660-
for i, service_version in enumerate(release_versions)
662+
for _, service_version in enumerate(release_versions)
661663
]
662664
)
663665
# Sort versions after injecting
@@ -673,33 +675,33 @@ async def test_get_service_history_page_with_filters(
673675
assert len(history) == num_versions
674676
assert [release.version for release in history] == release_versions
675677

676-
# Test: Apply filter for service_type=ServiceType.DYNAMIC
677-
filters = ServiceFiltersDB(service_type=ServiceType.DYNAMIC)
678+
# Test: Apply filter for
679+
filters = ServiceFiltersDB(service_type=expected_service_type)
678680
total_count, filtered_history = await services_repo.get_service_history_page(
679681
product_name=target_product,
680682
user_id=user_id,
681683
key=service_key,
682684
filters=filters,
683685
)
684-
assert total_count == num_versions // 2
685-
assert len(filtered_history) == num_versions // 2
686-
assert all(
687-
int(release.version.split(".")[0]) % 2 == 0 for release in filtered_history
688-
)
686+
assert total_count == num_versions
687+
assert len(filtered_history) == num_versions
688+
assert [release.version for release in filtered_history] == release_versions
689689

690-
# Test: Apply filter for service_type=ServiceType.COMPUTATIONAL
691-
filters = ServiceFiltersDB(service_type=ServiceType.COMPUTATIONAL)
692-
total_count, filtered_history = await services_repo.get_service_history_page(
690+
# Final check: filter by a different service type expecting no results
691+
different_service_type = (
692+
ServiceType.COMPUTATIONAL
693+
if expected_service_type != ServiceType.COMPUTATIONAL
694+
else ServiceType.DYNAMIC
695+
)
696+
filters = ServiceFiltersDB(service_type=different_service_type)
697+
total_count, no_history = await services_repo.get_service_history_page(
693698
product_name=target_product,
694699
user_id=user_id,
695700
key=service_key,
696701
filters=filters,
697702
)
698-
assert total_count == num_versions // 2
699-
assert len(filtered_history) == num_versions // 2
700-
assert all(
701-
int(release.version.split(".")[0]) % 2 != 0 for release in filtered_history
702-
)
703+
assert total_count == 0
704+
assert no_history == []
703705

704706

705707
async def test_list_services_from_published_templates(

0 commit comments

Comments
 (0)