diff --git a/src/viur/core/bones/base.py b/src/viur/core/bones/base.py index 498ba72f3..01fd939a8 100644 --- a/src/viur/core/bones/base.py +++ b/src/viur/core/bones/base.py @@ -9,12 +9,13 @@ import hashlib import inspect import logging -from dataclasses import dataclass, field -from datetime import datetime, timedelta +import typing as t from collections.abc import Iterable +from dataclasses import dataclass, field +from datetime import timedelta from enum import Enum -import typing as t -from viur.core import db, utils, i18n + +from viur.core import db, i18n, utils from viur.core.config import conf if t.TYPE_CHECKING: @@ -1013,7 +1014,10 @@ def buildDBSort(self, dbFilter.order(order) return dbFilter - def _hashValueForUniquePropertyIndex(self, value: str | int) -> list[str]: + def _hashValueForUniquePropertyIndex( + self, + value: str | int | float | db.Key | list[str | int | float | db.Key], + ) -> list[str]: """ Generates a hash of the given value for creating unique property indexes. @@ -1021,16 +1025,17 @@ def _hashValueForUniquePropertyIndex(self, value: str | int) -> list[str]: for constructing unique property indexes. Derived bone classes should overwrite this method to implement their own logic for hashing values. - :param value: The value to be hashed, which can be a string, integer, or a float. + :param value: The value(s) to be hashed. :return: A list containing a string representation of the hashed value. If the bone is multiple, the list may contain more than one hashed value. """ - def hashValue(value: str | int) -> str: + + def hashValue(value: str | int | float | db.Key) -> str: h = hashlib.sha256() h.update(str(value).encode("UTF-8")) res = h.hexdigest() - if isinstance(value, int) or isinstance(value, float): + if isinstance(value, int | float): return f"I-{res}" elif isinstance(value, str): return f"S-{res}" @@ -1047,9 +1052,9 @@ def keyHash(key): if not value and not self.unique.lockEmpty: return [] # We are zero/empty string and these should not be locked - if not self.multiple: + if not self.multiple and not isinstance(value, list): return [hashValue(value)] - # We have an multiple bone here + # We have a multiple bone or multiple values here if not isinstance(value, list): value = [value] tmpList = [hashValue(x) for x in value] diff --git a/src/viur/core/bones/string.py b/src/viur/core/bones/string.py index d59968c1b..813456422 100644 --- a/src/viur/core/bones/string.py +++ b/src/viur/core/bones/string.py @@ -351,6 +351,13 @@ def getUniquePropertyIndexValues(self, skel: "SkeletonInstance", name: str) -> l # Not yet implemented as it's unclear if we should keep each language distinct or not raise NotImplementedError() + if not self.caseSensitive and (value := skel[name]) is not None: + if self.multiple: + value = [v.lower() for v in value] + else: + value = value.lower() + return self._hashValueForUniquePropertyIndex(value) + return super().getUniquePropertyIndexValues(skel, name) def refresh(self, skel: "SkeletonInstance", bone_name: str) -> None: