Skip to content

Commit aac0db2

Browse files
committed
DB models
1 parent 95e5bff commit aac0db2

File tree

8 files changed

+191
-88
lines changed

8 files changed

+191
-88
lines changed

packages/models-library/src/models_library/services_metadata_editable.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ class ServiceMetaDataEditable(ServiceBaseDisplay):
2828
version_display: str | None = None
2929

3030
# Below fields only in the database ----
31-
deprecated: datetime | None = Field(
32-
default=None,
33-
description="Owner can set the date to retire the service. Three possibilities:"
34-
"If None, the service is marked as `published`;"
35-
"If now<deprecated the service is marked as deprecated;"
36-
"If now>=deprecated, the service is retired",
37-
)
31+
deprecated: Annotated[
32+
datetime | None,
33+
Field(
34+
description="Owner can set the date to retire the service. Three possibilities:"
35+
"If None, the service is marked as `published`;"
36+
"If now<deprecated the service is marked as deprecated;"
37+
"If now>=deprecated, the service is retired",
38+
),
39+
] = None
3840
classifiers: list[str] | None
3941
quality: Annotated[
4042
dict[str, Any], Field(default_factory=dict, json_schema_extra={"default": {}})

services/catalog/src/simcore_service_catalog/api/rest/_services.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
)
2323
from ...db.repositories.groups import GroupsRepository
2424
from ...db.repositories.services import ServicesRepository
25-
from ...models.services_db import ServiceAccessRightsAtDB, ServiceMetaDataAtDB
25+
from ...models.services_db import ServiceAccessRightsAtDB, ServiceMetaDataDBGet
2626
from ...services.director import DirectorApi
2727
from ..dependencies.database import get_repository
2828
from ..dependencies.director import get_director_api
@@ -35,7 +35,7 @@
3535

3636
def _compose_service_details(
3737
service_in_registry: dict[str, Any], # published part
38-
service_in_db: ServiceMetaDataAtDB, # editable part
38+
service_in_db: ServiceMetaDataDBGet, # editable part
3939
service_access_rights_in_db: list[ServiceAccessRightsAtDB],
4040
service_owner: str | None,
4141
) -> ServiceGet | None:

services/catalog/src/simcore_service_catalog/core/background_tasks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from ..db.repositories.groups import GroupsRepository
2929
from ..db.repositories.projects import ProjectsRepository
3030
from ..db.repositories.services import ServicesRepository
31-
from ..models.services_db import ServiceAccessRightsAtDB, ServiceMetaDataAtDB
31+
from ..models.services_db import ServiceAccessRightsAtDB, ServiceMetaDataDBGet
3232
from ..services import access_rights
3333

3434
_logger = logging.getLogger(__name__)
@@ -89,7 +89,7 @@ def _by_version(t: tuple[ServiceKey, ServiceVersion]) -> Version:
8989

9090
# set the service in the DB
9191
await services_repo.create_or_update_service(
92-
ServiceMetaDataAtDB(**service_metadata.model_dump(), owner=owner_gid),
92+
ServiceMetaDataDBGet(**service_metadata.model_dump(), owner=owner_gid),
9393
service_access_rights,
9494
)
9595

services/catalog/src/simcore_service_catalog/db/repositories/_services_sql.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
from models_library.products import ProductName
55
from models_library.services_types import ServiceKey, ServiceVersion
66
from models_library.users import UserID
7+
from simcore_postgres_database.utils_repos import get_columns_from_db_model
78
from sqlalchemy.dialects.postgresql import ARRAY, INTEGER, array_agg
89
from sqlalchemy.sql import and_, or_
910
from sqlalchemy.sql.expression import func
1011
from sqlalchemy.sql.selectable import Select
1112

13+
from ...models.services_db import ServiceMetaDataDBGet
1214
from ..tables import (
1315
services_access_rights,
1416
services_compatibility,
@@ -17,6 +19,10 @@
1719
users,
1820
)
1921

22+
SERVICES_META_DATA_COLS = get_columns_from_db_model(
23+
services_meta_data, ServiceMetaDataDBGet
24+
)
25+
2026

2127
def list_services_stmt(
2228
*,
@@ -26,7 +32,7 @@ def list_services_stmt(
2632
combine_access_with_and: bool | None = True,
2733
product_name: str | None = None,
2834
) -> Select:
29-
stmt = sa.select(services_meta_data)
35+
stmt = sa.select(SERVICES_META_DATA_COLS)
3036
if gids or execute_access or write_access:
3137
conditions: list[Any] = []
3238

@@ -50,13 +56,9 @@ def list_services_stmt(
5056
if product_name:
5157
conditions.append(services_access_rights.c.product_name == product_name)
5258

53-
stmt = (
54-
sa.select(
55-
services_meta_data,
56-
)
57-
.distinct(services_meta_data.c.key, services_meta_data.c.version)
58-
.select_from(services_meta_data.join(services_access_rights))
59-
)
59+
stmt = stmt.distinct(
60+
services_meta_data.c.key, services_meta_data.c.version
61+
).select_from(services_meta_data.join(services_access_rights))
6062
if conditions:
6163
stmt = stmt.where(and_(*conditions))
6264
stmt = stmt.order_by(services_meta_data.c.key, services_meta_data.c.version)

services/catalog/src/simcore_service_catalog/db/repositories/services.py

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,23 @@
1717
from psycopg2.errors import ForeignKeyViolation
1818
from pydantic import PositiveInt, TypeAdapter, ValidationError
1919
from simcore_postgres_database.utils_services import create_select_latest_services_query
20-
from sqlalchemy import literal_column
2120
from sqlalchemy.dialects.postgresql import insert as pg_insert
2221
from sqlalchemy.sql import and_, or_
2322
from sqlalchemy.sql.expression import tuple_
2423

2524
from ...models.services_db import (
2625
ReleaseFromDB,
2726
ServiceAccessRightsAtDB,
28-
ServiceMetaDataAtDB,
27+
ServiceMetaDataDBCreate,
28+
ServiceMetaDataDBGet,
29+
ServiceMetaDataDBPatch,
2930
ServiceWithHistoryFromDB,
3031
)
3132
from ...models.services_specifications import ServiceSpecificationsAtDB
3233
from ..tables import services_access_rights, services_meta_data, services_specifications
3334
from ._base import BaseRepository
3435
from ._services_sql import (
36+
SERVICES_META_DATA_COLS,
3537
AccessRightsClauses,
3638
can_get_service_stmt,
3739
get_service_history_stmt,
@@ -79,11 +81,11 @@ async def list_services(
7981
write_access: bool | None = None,
8082
combine_access_with_and: bool | None = True,
8183
product_name: str | None = None,
82-
) -> list[ServiceMetaDataAtDB]:
84+
) -> list[ServiceMetaDataDBGet]:
8385

8486
async with self.db_engine.connect() as conn:
8587
return [
86-
ServiceMetaDataAtDB.model_validate(row)
88+
ServiceMetaDataDBGet.model_validate(row)
8789
async for row in await conn.stream(
8890
list_services_stmt(
8991
gids=gids,
@@ -102,7 +104,7 @@ async def list_service_releases(
102104
major: int | None = None,
103105
minor: int | None = None,
104106
limit_count: int | None = None,
105-
) -> list[ServiceMetaDataAtDB]:
107+
) -> list[ServiceMetaDataDBGet]:
106108
"""Lists LAST n releases of a given service, sorted from latest first
107109
108110
major, minor is used to filter as major.minor.* or major.*
@@ -124,7 +126,7 @@ async def list_service_releases(
124126
search_condition &= services_meta_data.c.version.like(f"{major}.%")
125127

126128
query = (
127-
sa.select(services_meta_data)
129+
sa.select(SERVICES_META_DATA_COLS)
128130
.where(search_condition)
129131
.order_by(sa.desc(services_meta_data.c.version))
130132
)
@@ -134,22 +136,22 @@ async def list_service_releases(
134136

135137
async with self.db_engine.connect() as conn:
136138
releases = [
137-
ServiceMetaDataAtDB.model_validate(row)
139+
ServiceMetaDataDBGet.model_validate(row)
138140
async for row in await conn.stream(query)
139141
]
140142

141143
# Now sort naturally from latest first: (This is lame, the sorting should be done in the db)
142-
def _by_version(x: ServiceMetaDataAtDB) -> packaging.version.Version:
144+
def _by_version(x: ServiceMetaDataDBGet) -> packaging.version.Version:
143145
return packaging.version.parse(x.version)
144146

145147
return sorted(releases, key=_by_version, reverse=True)
146148

147-
async def get_latest_release(self, key: str) -> ServiceMetaDataAtDB | None:
149+
async def get_latest_release(self, key: str) -> ServiceMetaDataDBGet | None:
148150
"""Returns last release or None if service was never released"""
149151
services_latest = create_select_latest_services_query().alias("services_latest")
150152

151153
query = (
152-
sa.select(services_meta_data)
154+
sa.select(SERVICES_META_DATA_COLS)
153155
.select_from(
154156
services_latest.join(
155157
services_meta_data,
@@ -163,7 +165,7 @@ async def get_latest_release(self, key: str) -> ServiceMetaDataAtDB | None:
163165
result = await conn.execute(query)
164166
row = result.first()
165167
if row:
166-
return ServiceMetaDataAtDB.model_validate(row)
168+
return ServiceMetaDataDBGet.model_validate(row)
167169
return None # mypy
168170

169171
async def get_service(
@@ -175,18 +177,11 @@ async def get_service(
175177
execute_access: bool | None = None,
176178
write_access: bool | None = None,
177179
product_name: str | None = None,
178-
) -> ServiceMetaDataAtDB | None:
180+
) -> ServiceMetaDataDBGet | None:
179181

180-
query = sa.select(services_meta_data).where(
181-
(services_meta_data.c.key == key)
182-
& (services_meta_data.c.version == version)
183-
)
184-
if gids or execute_access or write_access:
185-
186-
query = sa.select(services_meta_data).select_from(
187-
services_meta_data.join(services_access_rights)
188-
)
182+
query = sa.select(SERVICES_META_DATA_COLS)
189183

184+
if gids or execute_access or write_access:
190185
conditions = [
191186
services_meta_data.c.key == key,
192187
services_meta_data.c.version == version,
@@ -202,20 +197,27 @@ async def get_service(
202197
if product_name:
203198
conditions.append(services_access_rights.c.product_name == product_name)
204199

205-
query = query.where(and_(*conditions))
200+
query = query.select_from(
201+
services_meta_data.join(services_access_rights)
202+
).where(and_(*conditions))
203+
else:
204+
query = query.where(
205+
(services_meta_data.c.key == key)
206+
& (services_meta_data.c.version == version)
207+
)
206208

207209
async with self.db_engine.connect() as conn:
208210
result = await conn.execute(query)
209211
row = result.first()
210212
if row:
211-
return ServiceMetaDataAtDB.model_validate(row)
213+
return ServiceMetaDataDBGet.model_validate(row)
212214
return None # mypy
213215

214216
async def create_or_update_service(
215217
self,
216-
new_service: ServiceMetaDataAtDB,
218+
new_service: ServiceMetaDataDBCreate,
217219
new_service_access_rights: list[ServiceAccessRightsAtDB],
218-
) -> ServiceMetaDataAtDB:
220+
) -> ServiceMetaDataDBGet:
219221
for access_rights in new_service_access_rights:
220222
if (
221223
access_rights.key != new_service.key
@@ -229,12 +231,12 @@ async def create_or_update_service(
229231
result = await conn.execute(
230232
# pylint: disable=no-value-for-parameter
231233
services_meta_data.insert()
232-
.values(**new_service.model_dump(by_alias=True))
233-
.returning(literal_column("*"))
234+
.values(**new_service.model_dump(by_alias=True, exclude_unset=True))
235+
.returning(*SERVICES_META_DATA_COLS)
234236
)
235237
row = result.first()
236238
assert row # nosec
237-
created_service = ServiceMetaDataAtDB.model_validate(row)
239+
created_service = ServiceMetaDataDBGet.model_validate(row)
238240

239241
for access_rights in new_service_access_rights:
240242
insert_stmt = pg_insert(services_access_rights).values(
@@ -243,13 +245,18 @@ async def create_or_update_service(
243245
await conn.execute(insert_stmt)
244246
return created_service
245247

246-
async def update_service(self, patched_service: ServiceMetaDataAtDB) -> None:
248+
async def update_service(
249+
self,
250+
service_key: ServiceKey,
251+
service_version: ServiceVersion,
252+
patched_service: ServiceMetaDataDBPatch,
253+
) -> None:
247254

248255
stmt_update = (
249256
services_meta_data.update()
250257
.where(
251-
(services_meta_data.c.key == patched_service.key)
252-
& (services_meta_data.c.version == patched_service.version)
258+
(services_meta_data.c.key == service_key)
259+
& (services_meta_data.c.version == service_version)
253260
)
254261
.values(
255262
**patched_service.model_dump(

0 commit comments

Comments
 (0)