Recently I was fixing some bug related to pagination. It happened because of reverse join and a target rows appeared because of it. Like this:
class User(Base):
__tablename__ = "users"
id = sa.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
email = Column(String, index=True, nullable=False, unique=True)
class UserPermission(Base):
__tablename__ = "users_permissions"
id = sa.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
user_id = Column(
UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False
)
permission = Column(String, nullable=False, index=True)
__table_args__ = (UniqueConstraint("user_id", "permission"),)
# results = db.execute(
# select(User).join(UserPermission).where(UserPermission.permission.in_(
# ["can_access_first_thing", "can_access_second_thing"]
# )
# ).unique().scalars().all()
Sometimes, a query that executes to fill results would contain more rows than existing Users because for each user there will be more than one UserPermission. That breaks any pagination that is based on offset/limit approach. My solution for this pagination problem was to query users table again after determining all required user ids:
base_query = select(User).join(UserPermission).where(UserPermission.permission.in_(
["can_access_first_thing", "can_access_second_thing"]
).with_only_columns(User.id)
results = db.execute(select(User).where(User.id.in_(base_query.subquery())))
Now SQLAlchemy throws a warning for this line: SAWarning: Coercing Subquery object into a select() for use in IN(); please pass a select() construct explicitly. My question is how to properly rewrite existing query so it returns the same result without throwing this warning.