Struct fdb_rl::key_expression::well_formed_message_descriptor::MessageDescriptorValidatorVisitor
source · struct MessageDescriptorValidatorVisitor {
walked_message_descriptor: Vec<MessageDescriptor>,
}
Expand description
There are five valid forms of field descriptor that we want. They are numbered (1), (2), (a), (b.i), (b.ii). We also follow Java RecordLayer restrictions on unsigned types.
The form (a) is a special case of form (2).
Forms (1) and (2) describe most common field descriptor forms that
we want, which are fields containing optional
and repeated
.
-
cardinality: Optional
,supports_presence: true
,is_list: false
,is_map: false
,default_value: None
,containing_oneof: Some("...")
, where...
is the name of the oneof....
can be explicitly provided whenoneof
keyword is used. Alternatively, whenoptional
is specified, it is generated by the protobuf compiler. -
cardinality: Repeated
,supports_presence: false
,default_value: None
,containing_oneof: None
. Whenis_list: true
then the field is arepeated
. Whenis_map: true
, the field is amap
(with a compiler generated map entry message type).In proto3, there is no concept of
optional repeated
1 oroptional map
.
When cardinality: Optional
, support_presence: false
and
is_list: false
, and is_map: false
that is a round about way of
saying “required” with default value. We do not allow that for
form (1) described above.
The only way to specify that a field is “required” is by using key expression.
For all valid forms (i.e., form (1) and (2) described above and
map
form described below) and we outright reject cardinality: Required
. If we see cardinality: Required
, there is some
serious bug, as we are checking for proto3 from file descriptor.
For all valid forms, we reject is_group: true
, default_value: Some(...)
. There is no API from FileDescriptor
type to check
default_value
. Therefore we need to check using
FileDescriptorProto
type. Hence you will see the following code.
field_descriptor
.field_descriptor_proto()
.default_value
.is_some()
Protobuf packing can vary depending on the type. So, we do not
check is_packed
.
Protobuf message can have no fields. Together with oneof
this is
very useful in building up discriminated unions (tagged union, sum
types). We use this technique in cursor.proto
in
KeyValueContinuation
message.
We support oneof
keyword. Oneof fields are just fields in the
enclosing message descriptor 2 and they have containing_oneof: Some("...")
, where ...
specified in .proto
file rather than
being compiler generated. Fields that are part of oneof
keyword
have supports_presence: true
, cardinality: Optional
, which is
form (1) described above.
Additionally, within oneof, there cannot be a repeated
field
3. This ensures that we won’t see an empty repeated
field
within oneof.
Following message type gives us the correct field descriptor for form (1).
message HelloWorld {
optional fdb_rl.field.v1.UUID primary_key = 1;
optional string hello = 2;
optional string world = 3;
}
If we were to remove the optional
keyword, for example:
message HelloWorld {
fdb_rl.field.v1.UUID non_optional_primary_key = 4;
string non_optional_string = 5;
}
Then the field non_optional_primary_key
would have
containing_oneof: None
. The field non_optional_string
would
have containing_oneof: None
and supports_presence: false
.
The logic for checking form (1) and (2) is implemented in
visit_field_descriptor
.
Protobuf map type is a special case. The map
field is
implemented using with a protobuf generated message type. We will
refer to the generated protobuf message type as
GeneratedMapEntryMessage
.
In case of map
fields, there are three field descriptors to be
aware of.
a. The field descriptor where map
field is defined. This field
descriptor will have the kind of protobuf generated message
type (i.e., GeneratedMapEntryMessage
)
b. Within GeneratedMapEntryMessage
, there would be two field
descriptors whose names are:
i. key
ii. value
The map
field’s field descriptor (i.e., (a) above) will have
cardinality: Repeated
, supports_presence: false
,
containing_oneof: None
. It will have is_map: true
. This
scenario is taken care of by (2) above in
visit_field_descriptor
.
The GeneratedMapEntryMessage
message descriptor has
is_map_entry: true
. It has two field descriptors with name key
(key_type
) and value
(value_type
). How we walk a message
descriptor depends on if is_map_entry
is true
or false
. This
is handled in walk_message_descriptor
.
The field descriptor with name key
((b.i) above) has
cardinality: Optional
, supports_presence: false
, is_list: false
, is_map: false
, default_value: None
, containing_oneof: None
.
The field descriptor with name value
((b.ii) above) has
cardinality: Optional
, is_list: false
, is_map: false
,
default_value: None
, containing_oneof: None
. Note:
support_presence
would be false
if the value_type
is scalar
and it would be true
if the value_type
is a message
.
Protobuf allows key_type
to be any integral or string type
4. We however want to limit key_type
to be a string
. The
motivation for this is when necessary we want the key value to be
PartiQL tuple attribute, which is a string
.
The logic for checking field descriptor with name key
((b.i)
above) is implemented in
visit_map_entry_key_type_field_descriptor
and the logic for
checking field descriptor with name value
((b.ii) above) is
implemented in visit_map_entry_value_type_field_descriptor
.
Unsigned types (uint32
, uint64
, fixed32
and fixed64
) are
invalid 5.
Fields§
§walked_message_descriptor: Vec<MessageDescriptor>
Implementations§
Trait Implementations§
source§impl Visitor for MessageDescriptorValidatorVisitor
impl Visitor for MessageDescriptorValidatorVisitor
source§fn check_fdb_wkt(&self, message_descriptor: &MessageDescriptor) -> bool
fn check_fdb_wkt(&self, message_descriptor: &MessageDescriptor) -> bool
Checks if the message descriptor is a FDB Record Layer well known type.
source§fn previously_walked_check_or_update(
&mut self,
message_descriptor: &MessageDescriptor
) -> bool
fn previously_walked_check_or_update( &mut self, message_descriptor: &MessageDescriptor ) -> bool
Checks if we have seen the message descriptor before. If not,
we update that we have seen it and returns false
. Therefore,
next time we are called, we can return true
.
source§fn visit_parent_file_descriptor(&self, file_descriptor: FileDescriptor) -> bool
fn visit_parent_file_descriptor(&self, file_descriptor: FileDescriptor) -> bool
Returns true
if .proto
file was compiled using syntax = proto3
.
source§fn visit_field_descriptor(&mut self, field_descriptor: FieldDescriptor) -> bool
fn visit_field_descriptor(&mut self, field_descriptor: FieldDescriptor) -> bool
Returns true
if the field descriptor is considered
“valid”.
See documentation on type
MessageDescriptorValidatorVisitor
for details.
source§fn visit_map_entry_key_type_field_descriptor(
&self,
field_descriptor: FieldDescriptor
) -> bool
fn visit_map_entry_key_type_field_descriptor( &self, field_descriptor: FieldDescriptor ) -> bool
Returns true
if the field descriptor is considered
“valid”.
See documentation on type
MessageDescriptorValidatorVisitor
for details.
source§fn visit_map_entry_value_type_field_descriptor(
&mut self,
field_descriptor: FieldDescriptor
) -> bool
fn visit_map_entry_value_type_field_descriptor( &mut self, field_descriptor: FieldDescriptor ) -> bool
Returns true
if the field descriptor is considered
“valid”.
See documentation on type
MessageDescriptorValidatorVisitor
for details.