Skip to content

Commit

Permalink
generalized
Browse files Browse the repository at this point in the history
  • Loading branch information
pcrespov committed Oct 30, 2024
1 parent 3a484a9 commit 8239f77
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
root_validator,
validator,
)
from simcore_service_webserver.db.base_repository import UserID

from ..emails import LowerCaseEmailStr
from ..users import UserID
from ..utils.common_validators import create__only_one_is_set__root_validator
from ._base import InputSchema, OutputSchema


Expand Down Expand Up @@ -182,15 +183,18 @@ class GroupUserAdd(InputSchema):
uid: UserID | None = None
email: LowerCaseEmailStr | None = None

@root_validator
@classmethod
def _check_uid_or_email(cls, values):
uid, email = values.get("uid"), values.get("email")
# Ensure exactly one of uid or email is set
if not (bool(uid is not None) ^ bool(email is not None)):
msg = f"Either 'uid' or 'email' must be set, but not both. Got {uid=} and {email=}"
raise ValueError(msg)
return values
_check_uid_or_email = root_validator(allow_reuse=True)(
create__only_one_is_set__root_validator(["uid", "email"])
)
# @root_validator
# @classmethod
# def _check_uid_or_email(cls, values):
# uid, email = values.get("uid"), values.get("email")
# # Ensure exactly one of uid or email is set
# if not (bool(uid is not None) ^ bool(email is not None)):
# msg = f"Either 'uid' or 'email' must be set, but not both. Got {uid=} and {email=}"
# raise ValueError(msg)
# return values


class GroupUserUpdate(InputSchema):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ class MyModel(BaseModel):
"""

import enum
import functools
import operator
from typing import Any


Expand Down Expand Up @@ -69,3 +71,33 @@ def null_or_none_str_to_none_validator(value: Any):
if isinstance(value, str) and value.lower() in ("null", "none"):
return None
return value


def create__only_one_is_set__root_validator(alternative_field_names: list[str]):
"""Ensure exactly one and only one of the alternatives is set
This is useful when you want to give the client alternative
ways to set the same thing e.g. set the user by email or id or username
and each of those has a different field
NOTE: Alternatevely, the previous example can also be solved using a
single field as `user: Email | UserID | UserName`
SEE test_uid_or_email_are_set.py for more details
"""

def _validator(cls, values):
assert set(alternative_field_names).issubset(cls.__fields__) # nosec

got = {
field_name: values.get(field_name) for field_name in alternative_field_names
}

if not functools.reduce(operator.xor, (v is not None for v in got.values())):
msg = (
f"Either { 'or'.join(got.keys()) } must be set, but not both. Got {got}"
)
raise ValueError(msg)
return values

return _validator

0 comments on commit 8239f77

Please sign in to comment.