Skip to content

Commit fb166e4

Browse files
committed
exposes interface
1 parent a117544 commit fb166e4

File tree

7 files changed

+171
-87
lines changed

7 files changed

+171
-87
lines changed

services/web/server/src/simcore_service_webserver/exporter/_formatter/_sds.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from ...projects._projects_service import get_project_for_user
1212
from ...projects.exceptions import BaseProjectError
1313
from ...projects.models import ProjectDict
14-
from ...scicrunch.repository import ResearchResourceRepository
14+
from ...scicrunch.scicrunch_service import ScicrunchResourcesService
1515
from ..exceptions import SDSException
1616
from .template_json import write_template_json
1717
from .xlsx.code_description import (
@@ -70,10 +70,10 @@ async def _add_rrid_entries(
7070
) -> None:
7171
rrid_entires: deque[RRIDEntry] = deque()
7272

73-
repo = ResearchResourceRepository(app)
73+
service = ScicrunchResourcesService(app)
7474
classifiers = project_data["classifiers"]
7575
for classifier in classifiers:
76-
scicrunch_resource = await repo.get(rrid=classifier)
76+
scicrunch_resource = await service.get_resource_atdb(rrid=classifier)
7777
if scicrunch_resource is None:
7878
continue
7979

services/web/server/src/simcore_service_webserver/groups/_classifiers_rest.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from .._meta import API_VTAG
1010
from ..login.decorators import login_required
1111
from ..scicrunch.models import ResearchResource, ResourceHit
12-
from ..scicrunch.repository import ResearchResourceRepository
12+
from ..scicrunch.scicrunch_service import ScicrunchResourcesService
1313
from ..scicrunch.service_client import SciCrunch
1414
from ..security.decorators import permission_required
1515
from ..utils_aiohttp import envelope_json_response
@@ -53,8 +53,8 @@ async def get_scicrunch_resource(request: web.Request):
5353
rrid = SciCrunch.validate_identifier(rrid)
5454

5555
# check if in database first
56-
repo = ResearchResourceRepository(request.app)
57-
resource: ResearchResource | None = await repo.get_resource(rrid)
56+
service = ScicrunchResourcesService(request.app)
57+
resource: ResearchResource | None = await service.get_resource(rrid)
5858
if not resource:
5959
# otherwise, request to scicrunch service
6060
scicrunch = SciCrunch.get_instance(request.app)
@@ -74,15 +74,15 @@ async def add_scicrunch_resource(request: web.Request):
7474
rrid = request.match_info["rrid"]
7575

7676
# check if exists
77-
repo = ResearchResourceRepository(request.app)
78-
resource: ResearchResource | None = await repo.get_resource(rrid)
77+
service = ScicrunchResourcesService(request.app)
78+
resource: ResearchResource | None = await service.get_resource(rrid)
7979
if not resource:
8080
# then request scicrunch service
8181
scicrunch = SciCrunch.get_instance(request.app)
8282
resource = await scicrunch.get_resource_fields(rrid)
8383

8484
# insert new or if exists, then update
85-
await repo.upsert(resource)
85+
await service.upsert_resource(resource)
8686

8787
return envelope_json_response(resource.model_dump())
8888

services/web/server/src/simcore_service_webserver/groups/_classifiers_service.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
)
2525

2626
from ..scicrunch.errors import ScicrunchError
27-
from ..scicrunch.repository import ResearchResourceRepository
27+
from ..scicrunch.scicrunch_service import ScicrunchResourcesService
2828
from ..scicrunch.service_client import SciCrunch
2929
from ._classifiers_repository import GroupClassifierRepository
3030

@@ -126,10 +126,10 @@ async def build_rrids_tree_view(
126126
)
127127

128128
scicrunch = SciCrunch.get_instance(app)
129-
repo = ResearchResourceRepository(app)
129+
service = ScicrunchResourcesService(app)
130130

131131
flat_tree_view: dict[TreePath, ClassifierItem] = {}
132-
for resource in await repo.list_resources():
132+
for resource in await service.list_resources():
133133
try:
134134
validated_item = ClassifierItem(
135135
classifier=resource.rrid,
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""
2+
Repository for scicrunch_resources table operations using asyncpg
3+
"""
4+
5+
import logging
6+
from typing import Any
7+
8+
import sqlalchemy as sa
9+
from simcore_postgres_database.models.scicrunch_resources import scicrunch_resources
10+
from simcore_postgres_database.utils_repos import (
11+
pass_or_acquire_connection,
12+
transaction_context,
13+
)
14+
from sqlalchemy.dialects.postgresql import insert as sa_pg_insert
15+
from sqlalchemy.engine import Row
16+
from sqlalchemy.ext.asyncio import AsyncConnection
17+
18+
from ..db.base_repository import BaseRepository
19+
20+
_logger = logging.getLogger(__name__)
21+
22+
23+
class ScicrunchResourcesRepository(BaseRepository):
24+
"""Repository for managing scicrunch_resources operations."""
25+
26+
async def list_all_resources(
27+
self, connection: AsyncConnection | None = None
28+
) -> list[Row]:
29+
"""List all research resources with basic fields."""
30+
async with pass_or_acquire_connection(self.engine, connection) as conn:
31+
stmt = sa.select(
32+
scicrunch_resources.c.rrid,
33+
scicrunch_resources.c.name,
34+
scicrunch_resources.c.description,
35+
)
36+
result = await conn.execute(stmt)
37+
return result.fetchall()
38+
39+
async def get_resource_by_rrid(
40+
self, rrid: str, connection: AsyncConnection | None = None
41+
) -> Row | None:
42+
"""Get a research resource by RRID."""
43+
async with pass_or_acquire_connection(self.engine, connection) as conn:
44+
stmt = sa.select(scicrunch_resources).where(
45+
scicrunch_resources.c.rrid == rrid
46+
)
47+
result = await conn.execute(stmt)
48+
return result.one_or_none()
49+
50+
async def upsert_resource(
51+
self, resource_data: dict[str, Any], connection: AsyncConnection | None = None
52+
) -> Row:
53+
"""Insert or update a research resource."""
54+
async with transaction_context(self.engine, connection) as conn:
55+
stmt = (
56+
sa_pg_insert(scicrunch_resources)
57+
.values(resource_data)
58+
.on_conflict_do_update(
59+
index_elements=[scicrunch_resources.c.rrid],
60+
set_=resource_data,
61+
)
62+
.returning(*scicrunch_resources.c)
63+
)
64+
result = await conn.execute(stmt)
65+
return result.one()
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"""
2+
Service layer for scicrunch research resources operations
3+
"""
4+
5+
import logging
6+
7+
from aiohttp import web
8+
from common_library.logging.logging_errors import create_troubleshooting_log_kwargs
9+
from pydantic import ValidationError
10+
11+
from ._repository import ScicrunchResourcesRepository
12+
from .models import ResearchResource, ResearchResourceAtdB
13+
14+
_logger = logging.getLogger(__name__)
15+
16+
17+
class ScicrunchResourcesService:
18+
"""Service layer handling business logic for scicrunch resources."""
19+
20+
def __init__(self, app: web.Application):
21+
self.app = app
22+
self._repo = ScicrunchResourcesRepository.create_from_app(app)
23+
24+
async def list_resources(self) -> list[ResearchResource]:
25+
"""List all research resources as domain models."""
26+
rows = await self._repo.list_all_resources()
27+
if not rows:
28+
return []
29+
30+
resources = []
31+
for row in rows:
32+
try:
33+
resource = ResearchResource.model_validate(dict(row))
34+
resources.append(resource)
35+
except ValidationError as err:
36+
_logger.warning(
37+
**create_troubleshooting_log_kwargs(
38+
f"Invalid data for resource {row.rrid}",
39+
error=err,
40+
error_context={"row_data": dict(row)},
41+
)
42+
)
43+
continue
44+
45+
return resources
46+
47+
async def get_resource_atdb(self, rrid: str) -> ResearchResourceAtdB | None:
48+
"""Get resource with all database fields."""
49+
row = await self._repo.get_resource_by_rrid(rrid)
50+
if not row:
51+
return None
52+
53+
try:
54+
return ResearchResourceAtdB.model_validate(dict(row))
55+
except ValidationError as err:
56+
_logger.exception(
57+
**create_troubleshooting_log_kwargs(
58+
f"Invalid data for resource {rrid}",
59+
error=err,
60+
error_context={"rrid": rrid, "row_data": dict(row)},
61+
)
62+
)
63+
return None
64+
65+
async def get_resource(self, rrid: str) -> ResearchResource | None:
66+
"""Get resource as domain model."""
67+
resource_atdb = await self.get_resource_atdb(rrid)
68+
if not resource_atdb:
69+
return None
70+
71+
try:
72+
return ResearchResource.model_validate(resource_atdb.model_dump())
73+
except ValidationError as err:
74+
_logger.exception(
75+
**create_troubleshooting_log_kwargs(
76+
f"Failed to convert resource {rrid} to domain model",
77+
error=err,
78+
error_context={
79+
"rrid": rrid,
80+
"resource_data": resource_atdb.model_dump(),
81+
},
82+
)
83+
)
84+
return None
85+
86+
async def upsert_resource(self, resource: ResearchResource) -> ResearchResource:
87+
"""Create or update a research resource."""
88+
values = resource.model_dump(exclude_unset=True)
89+
row = await self._repo.upsert_resource(values)
90+
return ResearchResource.model_validate(dict(row))

services/web/server/src/simcore_service_webserver/scicrunch/repository.py

Lines changed: 0 additions & 75 deletions
This file was deleted.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from ._service import ScicrunchResourcesService
2+
3+
__all__: tuple[str, ...] = ("ScicrunchResourcesService",)
4+
# nopycln: file

0 commit comments

Comments
 (0)