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
« 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
4from .types import Entity, Key
7def key_from_protobuf(pb): # !!! 100% Copy, only uses our Key Class
8 """Factory method for creating a key based on a protobuf.
10 The protobuf should be one returned from the Cloud Datastore
11 Protobuf API.
13 :type pb: :class:`.entity_pb2.Key`
14 :param pb: The Protobuf representing the key.
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)
29 project = None
30 if pb.partition_id.project_id: # Simple field (string)
31 project = pb.partition_id.project_id
32 database = None
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
40 return Key(*path_args, namespace=namespace, project=project, database=database)
43def entity_from_protobuf(pb):
44 """Factory method for creating an entity based on a protobuf.
46 The protobuf should be one returned from the Cloud Datastore
47 Protobuf API.
49 :type pb: :class:`.entity_pb2.Entity`
50 :param pb: The Protobuf representing the entity.
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
58 key = None
59 if pb.HasField("key"): # Message field (Key)
60 key = key_from_protobuf(pb.key)
62 entity_props = {}
63 entity_meanings = {}
64 exclude_from_indexes = []
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
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)
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 )
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)
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