Coverage for /home/runner/work/viur-core/viur-core/viur/src/viur/core/bones/uid.py: 90%

42 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-09-18 12:33 +0000

1import typing as t 

2from viur.core import db 

3from viur.core.bones.base import BaseBone, Compute, ComputeInterval, ComputeMethod, UniqueValue, UniqueLockMethod 

4 

5 

6def generate_number(db_key: db.Key) -> int: 

7 """ 

8 The generate_number method generates a leading number that is always unique per entry. 

9 """ 

10 

11 def transact(_key: db.Key): 

12 # A commit conflict only surfaces when the surrounding transaction commits and is 

13 # retried by db.run_in_transaction, so it must propagate out of this function. 

14 if db_obj := db.get(_key): 

15 db_obj["count"] += 1 

16 else: 

17 db_obj = db.Entity(_key) 

18 db_obj["count"] = 0 

19 db.put(db_obj) 

20 return db_obj["count"] 

21 

22 if db.is_in_transaction(): 22 ↛ 25line 22 didn't jump to line 25 because the condition on line 22 was always true

23 return transact(db_key) 

24 else: 

25 return db.run_in_transaction(transact, db_key) 

26 

27 

28def generate_uid(skel, bone): 

29 db_key = db.Key("viur-uids", f"{skel.kindName}-{bone.name}-uid") 

30 count_value = generate_number(db_key) 

31 if bone.fillchar: 31 ↛ 37line 31 didn't jump to line 37 because the condition on line 31 was always true

32 # The wildcard itself is replaced, so it does not count towards the length of the prefix. 

33 length_to_fill = bone.length - (len(bone.pattern) - 1) 

34 res = str(count_value).rjust(length_to_fill, bone.fillchar) 

35 return bone.pattern.replace("*", res) 

36 else: 

37 return bone.pattern.replace("*", str(count_value)) 

38 

39 

40class UidBone(BaseBone): 

41 """ 

42 The "UidBone" represents a data field that contains text values. 

43 """ 

44 type = "uid" 

45 

46 def __init__( 

47 self, 

48 *, 

49 generate_fn: t.Callable = generate_uid, 

50 fillchar: str = "0", 

51 length: int = 13, 

52 pattern: str | t.Callable | None = "*", 

53 **kwargs 

54 ): 

55 """ 

56 Initializes a new UidBone. 

57 

58 :param generate_fn: The compute function to calculate the unique value, 

59 :param fillchar The char that are filed in when the uid has not the length. 

60 :param length: The length allowed for values of this bone. 

61 :param pattern: The pattern for this Bone. "*" will be replaced with the uid value. 

62 :param kwargs: Inherited arguments from the BaseBone. 

63 """ 

64 

65 super().__init__( 

66 compute=Compute(fn=generate_fn, interval=ComputeInterval(ComputeMethod.Once)), 

67 unique=UniqueValue(UniqueLockMethod.SameValue, False, "Unique Value already in use"), 

68 **kwargs 

69 ) 

70 if self.multiple or self.languages: 

71 raise ValueError("UidBone cannot be multiple or translated") 

72 

73 if not self.readOnly: 73 ↛ 74line 73 didn't jump to line 74 because the condition on line 73 was never true

74 raise ValueError("UidBone must be read-only") 

75 

76 self.fillchar = str(fillchar) 

77 self.length = length 

78 if isinstance(pattern, t.Callable): 

79 pattern = pattern() 

80 self.pattern = str(pattern) 

81 if self.pattern.count("*") != 1: 

82 raise ValueError("Only one wildcard (*) is allowed and required in the pattern") 

83 if len(self.fillchar) != 1: 

84 raise ValueError("Only one char is allowed as fillchar") 

85 

86 def structure(self) -> dict: 

87 ret = super().structure() | { 

88 "fillchar": self.fillchar, 

89 "length": self.length, 

90 "pattern": self.pattern 

91 } 

92 return ret