Coverage for /home/runner/work/viur-core/viur-core/viur/src/viur/core/db/overrides.py: 6%

49 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-09-13 11:04 +0000

1from google.cloud.datastore.helpers import _get_meaning, _get_value_from_value_pb 

2from google.cloud.datastore_v1.types import entity as entity_pb2 

3 

4from .types import Entity, Key 

5 

6 

7def key_from_protobuf(pb): # !!! 100% Copy, only uses our Key Class 

8 """Factory method for creating a key based on a protobuf. 

9 

10 The protobuf should be one returned from the Cloud Datastore 

11 Protobuf API. 

12 

13 :type pb: :class:`.entity_pb2.Key` 

14 :param pb: The Protobuf representing the key. 

15 

16 :rtype: :class:`google.cloud.datastore.key.Key` 

17 :returns: a new `Key` instance 

18 """ 

19 path_args = [] 

20 for element in pb.path: 

21 path_args.append(element.kind) 

22 if element.id: # Simple field (int64) 

23 path_args.append(element.id) 

24 # This is safe: we expect proto objects returned will only have 

25 # one of `name` or `id` set. 

26 if element.name: # Simple field (string) 

27 path_args.append(element.name) 

28 

29 project = None 

30 if pb.partition_id.project_id: # Simple field (string) 

31 project = pb.partition_id.project_id 

32 database = None 

33 

34 if pb.partition_id.database_id: # Simple field (string) 

35 database = pb.partition_id.database_id 

36 namespace = None 

37 if pb.partition_id.namespace_id: # Simple field (string) 

38 namespace = pb.partition_id.namespace_id 

39 

40 return Key(*path_args, namespace=namespace, project=project, database=database) 

41 

42 

43def entity_from_protobuf(pb): 

44 """Factory method for creating an entity based on a protobuf. 

45 

46 The protobuf should be one returned from the Cloud Datastore 

47 Protobuf API. 

48 

49 :type pb: :class:`.entity_pb2.Entity` 

50 :param pb: The Protobuf representing the entity. 

51 

52 :rtype: :class:`google.cloud.datastore.entity.Entity` 

53 :returns: The entity derived from the protobuf. 

54 """ 

55 if isinstance(pb, entity_pb2.Entity): 

56 pb = pb._pb 

57 

58 key = None 

59 if pb.HasField("key"): # Message field (Key) 

60 key = key_from_protobuf(pb.key) 

61 

62 entity_props = {} 

63 entity_meanings = {} 

64 exclude_from_indexes = [] 

65 

66 for prop_name, value_pb in pb.properties.items(): 

67 value = _get_value_from_value_pb(value_pb) 

68 entity_props[prop_name] = value 

69 

70 # Check if the property has an associated meaning. 

71 is_list = isinstance(value, list) 

72 meaning = _get_meaning(value_pb, is_list=is_list) 

73 if meaning is not None: 

74 entity_meanings[prop_name] = (meaning, value) 

75 

76 # Check if ``value_pb`` was excluded from index. Lists need to be 

77 # special-cased and we require all ``exclude_from_indexes`` values 

78 # in a list agree. 

79 if is_list and len(value) > 0: 

80 exclude_values = set( 

81 value_pb.exclude_from_indexes 

82 for value_pb in value_pb.array_value.values 

83 ) 

84 if len(exclude_values) != 1: 

85 raise ValueError( 

86 "For an array_value, subvalues must either " 

87 "all be indexed or all excluded from " 

88 "indexes." 

89 ) 

90 

91 if exclude_values.pop(): 

92 exclude_from_indexes.append(prop_name) 

93 else: 

94 if value_pb.exclude_from_indexes: 

95 exclude_from_indexes.append(prop_name) 

96 

97 entity = Entity(key=key, exclude_from_indexes=exclude_from_indexes) 

98 entity.update(entity_props) 

99 entity._meanings.update(entity_meanings) 

100 return entity