Skip to content

Commit

Permalink
squashme: use relationships to get data connectors
Browse files Browse the repository at this point in the history
  • Loading branch information
olevski committed Oct 27, 2024
1 parent a261af3 commit 6b27170
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 38 deletions.
54 changes: 16 additions & 38 deletions components/renku_data_services/data_connectors/db.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Adapters for data connectors database classes."""

from collections.abc import AsyncIterator, Callable
from typing import TypeVar, cast
from typing import TypeVar

from cryptography.hazmat.primitives.asymmetric import rsa
from sqlalchemy import Select, delete, func, or_, select
Expand Down Expand Up @@ -503,49 +503,27 @@ async def get_data_connectors_with_secrets(

async with self.session_maker() as session:
stmt = (
select(schemas.DataConnectorORM, schemas.DataConnectorSecretORM)
.select_from(schemas.DataConnectorORM) # NOTE: Makes sure the FROM statement is as expected
.join(
target=schemas.DataConnectorToProjectLinkORM,
onclause=schemas.DataConnectorORM.id == schemas.DataConnectorToProjectLinkORM.data_connector_id,
)
.join(
target=schemas.DataConnectorSecretORM,
onclause=schemas.DataConnectorORM.id == schemas.DataConnectorSecretORM.data_connector_id,
isouter=True, # NOTE: enables us to select data connectors with and without secrets
select(schemas.DataConnectorORM)
.where(
schemas.DataConnectorORM.project_links.any(
schemas.DataConnectorToProjectLinkORM.project_id == project_id
)
)
.where(schemas.DataConnectorToProjectLinkORM.project_id == project_id)
.where(
or_(
schemas.DataConnectorSecretORM.user_id == user.id,
# NOTE: the user_id field on a connector secret is non-nullable, but
# since we are doing an outer join this allows us to include data connectors
# without secrets.
schemas.DataConnectorSecretORM.user_id.is_(None),
# Data connectors with secrets for the specific user
schemas.DataConnectorORM.secrets.any(
schemas.DataConnectorSecretORM.user_id == user.id,
),
# Data connectors without any secrets
# See: https://docs.sqlalchemy.org/en/20/orm/queryguide/select.html#exists-forms-has-any
~schemas.DataConnectorORM.secrets.any(),
)
)
# NOTE: The order is important for the processing of the data below
.order_by(schemas.DataConnectorORM.id)
.order_by(schemas.DataConnectorSecretORM.secret_id)
)
results = await session.stream(stmt)
dc_current: models.DataConnector | None = None
dc_secrets: list[models.DataConnectorSecret] = []
async for res in results:
# NOTE: sqlalchemy does not set the types right for outer joins
dc, sec = cast(tuple[schemas.DataConnectorORM, schemas.DataConnectorSecretORM | None], res.t)
if dc_current is not None and dc.id != dc_current.id:
yield models.DataConnectorWithSecrets(dc_current, dc_secrets)
if dc_current is None or dc.id != dc_current.id:
dc_current = dc.dump()
dc_secrets = [sec.dump()] if sec else []
continue
if sec:
dc_secrets.append(sec.dump())
if dc_current is None:
# There are no data connectors at all returned from the DB
return
yield models.DataConnectorWithSecrets(dc_current, dc_secrets)
results = await session.stream_scalars(stmt)
async for dc in results:
yield models.DataConnectorWithSecrets(dc.dump(), [secret.dump() for secret in dc.secrets])

async def get_data_connector_secrets(
self,
Expand Down
2 changes: 2 additions & 0 deletions components/renku_data_services/data_connectors/orm.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ class DataConnectorORM(BaseORM):
onupdate=func.now(),
nullable=False,
)
secrets: Mapped[list["DataConnectorSecretORM"]] = relationship(init=False, viewonly=True, lazy="selectin")
project_links: Mapped[list["DataConnectorToProjectLinkORM"]] = relationship(init=False, viewonly=True)

def dump(self) -> models.DataConnector:
"""Create a data connector model from the DataConnectorORM."""
Expand Down

0 comments on commit 6b27170

Please sign in to comment.