refactor: match provider identity lookups via JSON subscript (#28624)
Both the OAuth and SCIM user lookups now compare the nested JSON value with SQLAlchemy's subscript operator, which emits the correct SQL for each supported database on its own. This replaces the hand-written sqlite and postgresql branches and the column-level contains() call they used.
This commit is contained in:
1 parent
90724cdee0
commit
73c1f5806a
1 file changed
+6
-19
@@ -27,7 +27,6 @@ from sqlalchemy import (
|
|||||||
select,
|
select,
|
||||||
update,
|
update,
|
||||||
)
|
)
|
||||||
from sqlalchemy.dialects.postgresql import JSONB
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
####################
|
####################
|
||||||
@@ -360,16 +359,10 @@ class UsersTable:
|
|||||||
sub: str,
|
sub: str,
|
||||||
db: AsyncSession | None = None,
|
db: AsyncSession | None = None,
|
||||||
) -> UserModel | None:
|
) -> UserModel | None:
|
||||||
"""Look up a user by OAuth provider + subject claim (dialect-aware JSON filter)."""
|
"""Look up a user by OAuth provider + subject claim."""
|
||||||
async with get_async_db_context(db) as session:
|
async with get_async_db_context(db) as session:
|
||||||
dialect = session.bind.dialect.name
|
# Subscript, never contains(): on a JSON column contains() degrades to a substring LIKE.
|
||||||
query = select(User)
|
query = select(User).where(User.oauth[provider]['sub'].as_string() == sub)
|
||||||
if dialect == 'sqlite':
|
|
||||||
oauth_match = User.oauth.contains({provider: {'sub': sub}})
|
|
||||||
query = query.where(oauth_match)
|
|
||||||
elif dialect == 'postgresql':
|
|
||||||
oauth_match = User.oauth[provider].cast(JSONB)['sub'].astext == sub
|
|
||||||
query = query.where(oauth_match)
|
|
||||||
row = (await session.execute(query)).scalars().first()
|
row = (await session.execute(query)).scalars().first()
|
||||||
return UserModel.model_validate(row) if row else None
|
return UserModel.model_validate(row) if row else None
|
||||||
|
|
||||||
@@ -379,16 +372,10 @@ class UsersTable:
|
|||||||
external_id: str,
|
external_id: str,
|
||||||
db: AsyncSession | None = None,
|
db: AsyncSession | None = None,
|
||||||
) -> UserModel | None:
|
) -> UserModel | None:
|
||||||
"""Look up a user by SCIM provider + external ID (dialect-aware JSON filter)."""
|
"""Look up a user by SCIM provider + external ID."""
|
||||||
async with get_async_db_context(db) as session:
|
async with get_async_db_context(db) as session:
|
||||||
dialect = session.bind.dialect.name
|
# Subscript, never contains(): on a JSON column contains() degrades to a substring LIKE.
|
||||||
query = select(User)
|
query = select(User).where(User.scim[provider]['external_id'].as_string() == external_id)
|
||||||
if dialect == 'sqlite':
|
|
||||||
scim_match = User.scim.contains({provider: {'external_id': external_id}})
|
|
||||||
query = query.where(scim_match)
|
|
||||||
elif dialect == 'postgresql':
|
|
||||||
scim_match = User.scim[provider].cast(JSONB)['external_id'].astext == external_id
|
|
||||||
query = query.where(scim_match)
|
|
||||||
row = (await session.execute(query)).scalars().first()
|
row = (await session.execute(query)).scalars().first()
|
||||||
return UserModel.model_validate(row) if row else None
|
return UserModel.model_validate(row) if row else None
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user