1717from psycopg2 .errors import ForeignKeyViolation
1818from pydantic import PositiveInt , TypeAdapter , ValidationError
1919from simcore_postgres_database .utils_services import create_select_latest_services_query
20- from sqlalchemy import literal_column
2120from sqlalchemy .dialects .postgresql import insert as pg_insert
2221from sqlalchemy .sql import and_ , or_
2322from sqlalchemy .sql .expression import tuple_
2423
2524from ...models .services_db import (
2625 ReleaseFromDB ,
2726 ServiceAccessRightsAtDB ,
28- ServiceMetaDataAtDB ,
27+ ServiceMetaDataDBCreate ,
28+ ServiceMetaDataDBGet ,
29+ ServiceMetaDataDBPatch ,
2930 ServiceWithHistoryFromDB ,
3031)
3132from ...models .services_specifications import ServiceSpecificationsAtDB
3233from ..tables import services_access_rights , services_meta_data , services_specifications
3334from ._base import BaseRepository
3435from ._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