from __future__ import annotations
from typing import Any, Literal, NamedTuple, cast, overload
from ..entity_types import EntityType
from ..errors import InvalidSkuidError
from .core import N_LONG_FORM_PIECES, SEP, E, SnowflakeSkuid
from .strings import AnySkuidStr, LongSkuid, ShortSkuid
[docs]
class IntSkuid(NamedTuple):
prefix: str
uid: int
@overload
def int_skuid(
skuid_or_etype: str,
snowflake: int | None = ...,
*,
enforce_validation: Literal[False],
) -> IntSkuid: ...
@overload
def int_skuid(
skuid_or_etype: EntityType,
snowflake: int,
*,
enforce_validation: Literal[True] = ...,
) -> IntSkuid: ...
@overload
def int_skuid(
skuid_or_etype: AnySkuidStr[E] | str,
snowflake: None = ...,
*,
enforce_validation: Literal[True] = ...,
) -> IntSkuid: ...
[docs]
def int_skuid(
skuid_or_etype: E | AnySkuidStr[E] | str,
snowflake: int | None = None,
*,
enforce_validation: bool = True,
) -> IntSkuid:
"""Convert a SKUID string (short or long) to an ``(entity_type, integer)`` named tuple.
Useful for storing SKUIDs as ``int64`` values in a database.
:param skuid_or_etype: Either a full SKUID string or just the entity-type prefix
(when *snowflake* is also supplied).
:param snowflake: Pre-computed Snowflake integer. When provided, *skuid_or_etype*
is treated as the entity-type prefix rather than a full SKUID string.
:param enforce_validation: If ``False``, skip full SKUID validation (default ``True``).
:returns: A :class:`IntSkuid` named tuple ``(prefix, uid)``.
:raises InvalidSkuidError: If the SKUID string cannot be parsed and validation is enabled.
"""
if enforce_validation is False and snowflake is not None:
return IntSkuid(skuid_or_etype, snowflake)
elif snowflake is not None:
etype = cast(E, EntityType.validate(skuid_or_etype))
sk = SnowflakeSkuid(etype, snowflake)
return IntSkuid(sk.entity_type.value, sk.snowflake_id)
else:
skuid = cast(AnySkuidStr[E], skuid_or_etype)
parsed = SnowflakeSkuid.parse(skuid)
return IntSkuid(parsed.entity_type.value, parsed.snowflake_id)
@overload
def long_skuid(
skuid_or_etype: str, snowflake: int | None = ..., *, enforce_validation: Literal[False]
) -> str: ...
@overload
def long_skuid(
skuid_or_etype: E, snowflake: int, *, enforce_validation: Literal[True] = ...
) -> LongSkuid[E]: ...
@overload
def long_skuid(
skuid_or_etype: AnySkuidStr[E],
snowflake: None = ...,
*,
enforce_validation: Literal[True] = ...,
) -> LongSkuid[E]: ...
[docs]
def long_skuid(
skuid_or_etype: E | AnySkuidStr[E] | str,
snowflake: int | None = None,
*,
enforce_validation: bool = True,
) -> LongSkuid[E] | str:
"""Return the long-form (``type-<gen>-<YYYYMMDD>-<base32>``) representation of a SKUID.
:param skuid_or_etype: A short or long SKUID string, **or** just the entity-type
prefix when *snowflake* is also provided.
:param snowflake: Pre-computed Snowflake integer (optional).
:param enforce_validation: If ``False``, already-long strings are returned without
re-parsing (default ``True``).
:returns: The SKUID in long form.
:raises InvalidSkuidError: If the input cannot be parsed and validation is enabled.
"""
if enforce_validation is False and len(skuid_or_etype.split(SEP)) == N_LONG_FORM_PIECES:
return skuid_or_etype
elif snowflake is not None:
etype = cast(E, EntityType.validate(skuid_or_etype))
return SnowflakeSkuid(etype, snowflake).long()
else:
skuid_str = cast(AnySkuidStr[E], skuid_or_etype)
return SnowflakeSkuid.parse(skuid_str).long()
@overload
def short_skuid(
skuid_or_etype: str, snowflake: int | None = ..., *, enforce_validation: Literal[False]
) -> str: ...
@overload
def short_skuid(
skuid_or_etype: E, snowflake: int, *, enforce_validation: Literal[True] = ...
) -> ShortSkuid[E]: ...
@overload
def short_skuid(
skuid_or_etype: AnySkuidStr[E],
snowflake: None = ...,
*,
enforce_validation: Literal[True] = ...,
) -> ShortSkuid[E]: ...
[docs]
def short_skuid(
skuid_or_etype: E | AnySkuidStr[E] | str,
snowflake: int | None = None,
*,
enforce_validation: bool = True,
) -> ShortSkuid[E] | str:
"""Return the short-form (``type-<base32>``) representation of a SKUID.
:param skuid_or_etype: A short or long SKUID string, **or** just the entity-type
prefix when *snowflake* is also provided.
:param snowflake: Pre-computed Snowflake integer (optional).
:param enforce_validation: If ``False``, the base32 suffix is extracted directly
without full validation (default ``True``).
:returns: The SKUID in short form.
:raises InvalidSkuidError: If the input cannot be parsed and validation is enabled.
"""
if enforce_validation is False:
pieces = skuid_or_etype.split(SEP)
return f"{pieces[0]}{SEP}{pieces[-1]}"
elif snowflake is not None:
etype = cast(E, EntityType.validate(skuid_or_etype))
return SnowflakeSkuid(etype, snowflake).short()
else:
skuid_str = cast(AnySkuidStr[E], skuid_or_etype)
return SnowflakeSkuid.parse(skuid_str).short()
[docs]
def is_valid_skuid(skuid: str) -> bool:
"""Return ``True`` if *skuid* is a valid Snowflake-based SKUID string.
:param skuid: The string to validate.
:returns: ``True`` if the string is a valid short or long SKUID, ``False`` otherwise.
"""
try:
SnowflakeSkuid[Any].parse(cast(AnySkuidStr[Any], skuid))
return True
except InvalidSkuidError:
return False