Type descriptors
This page describes the type descriptor formats as implemented in protocol version 2.0 (EdgeDB 4.0 and later). See Type descriptors (Protocol v1.0 and earlier) for type descriptor implementation in protocol versino 1.0 and earlier.
This section describes how type information for query input and results is encoded. Specifically, this is needed to decode the server response to the CommandDataDescription message.
The type descriptor is essentially a list of type information blocks:
-
each block encodes one type;
-
blocks can reference other blocks.
While parsing the blocks, a database driver can assemble an encoder or a decoder of the EdgeDB binary data.
An encoder is used to encode objects, native to the driver’s runtime, to binary data that EdgeDB can decode and work with.
A decoder is used to decode data from EdgeDB native format to data types native to the driver.
There is one special type with type id of zero:
00000000-0000-0000-0000-000000000000
. The describe result of this type
contains zero blocks. It’s used when a statement returns no meaningful
results, e.g. the CREATE BRANCH example
statement. It is also used to
represent the input descriptor when a query does not receive any arguments,
or the state descriptor for an empty/default state.
Descriptor and type IDs
The descriptor and type IDs in structures below are intended to be semi-stable
unique identifiers of a type. Fundamental types have globally stable known
IDs, and type IDs for schema-defined types (i.e. with
schema_defined = true
) persist. Ephemeral type ids are derived from
type structure and are not guaranteed to be stable, but are still useful
as cache keys.
Set Descriptor
struct SetDescriptor {
// Indicates that this is a Set value descriptor.
uint8 tag = 0;
// Descriptor ID.
uuid id;
// Set element type descriptor index.
uint16 type;
};
Set values are encoded on the wire as single-dimensional arrays.
Scalar Type Descriptor
struct ScalarTypeDescriptor {
// Indicates that this is a
// Scalar Type descriptor.
uint8 tag = 3;
// Schema type ID.
uuid id;
// Schema type name.
string name;
// Whether the type is defined in the schema
// or is ephemeral.
bool schema_defined;
// Number of ancestor scalar types.
uint16 ancestors_count;
// Indexes of ancestor scalar type descriptors
// in ancestor resolution order (C3).
uint16 ancestors[ancestors_count];
};
The descriptor IDs for fundamental scalar types are constant. The following table lists all EdgeDB fundamental type descriptor IDs:
ID |
Type |
---|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
Tuple Type Descriptor
struct TupleTypeDescriptor {
// Indicates that this is a
// Tuple Type descriptor.
uint8 tag = 4;
// Schema type ID.
uuid id;
// Schema type name.
string name;
// Whether the type is defined in the schema
// or is ephemeral.
bool schema_defined;
// Number of ancestor scalar types.
uint16 ancestors_count;
// Indexes of ancestor scalar type descriptors
// in ancestor resolution order (C3).
uint16 ancestors[ancestors_count];
// The number of elements in tuple.
uint16 element_count;
// Indexes of element type descriptors.
uint16 element_types[element_count];
};
An empty tuple type descriptor has an ID of
00000000-0000-0000-0000-0000000000FF
.
Named Tuple Type Descriptor
struct NamedTupleTypeDescriptor {
// Indicates that this is a
// Named Tuple Type descriptor.
uint8 tag = 5;
// Schema type ID.
uuid id;
// Schema type name.
string name;
// Whether the type is defined in the schema
// or is ephemeral.
bool schema_defined;
// Number of ancestor scalar types.
uint16 ancestors_count;
// Indexes of ancestor scalar type descriptors
// in ancestor resolution order (C3).
uint16 ancestors[ancestors_count];
// The number of elements in tuple.
uint16 element_count;
// Indexes of element descriptors.
TupleElement elements[element_count];
};
struct TupleElement {
// Field name.
string name;
// Field type descriptor index.
int16 type;
};
Array Type Descriptor
struct ArrayTypeDescriptor {
// Indicates that this is an
// Array Type descriptor.
uint8 tag = 6;
// Schema type ID.
uuid id;
// Schema type name.
string name;
// Whether the type is defined in the schema
// or is ephemeral.
bool schema_defined;
// Number of ancestor scalar types.
uint16 ancestors_count;
// Indexes of ancestor scalar type descriptors
// in ancestor resolution order (C3).
uint16 ancestors[ancestors_count];
// Array element type.
uint16 type;
// The number of array dimensions, at least 1.
uint16 dimension_count;
// Sizes of array dimensions, -1 indicates
// unbound dimension.
int32 dimensions[dimension_count];
};
Enumeration Type Descriptor
struct EnumerationTypeDescriptor {
// Indicates that this is an
// Enumeration Type descriptor.
uint8 tag = 7;
// Schema type ID.
uuid id;
// Schema type name.
string name;
// Whether the type is defined in the schema
// or is ephemeral.
bool schema_defined;
// Number of ancestor scalar types.
uint16 ancestors_count;
// Indexes of ancestor scalar type descriptors
// in ancestor resolution order (C3).
uint16 ancestors[ancestors_count];
// The number of enumeration members.
uint16 member_count;
// Names of enumeration members.
string members[member_count];
};
Range Type Descriptor
struct RangeTypeDescriptor {
// Indicates that this is a
// Range Type descriptor.
uint8 tag = 9;
// Schema type ID.
uuid id;
// Schema type name.
string name;
// Whether the type is defined in the schema
// or is ephemeral.
bool schema_defined;
// Number of ancestor scalar types.
uint16 ancestors_count;
// Indexes of ancestor scalar type descriptors
// in ancestor resolution order (C3).
uint16 ancestors[ancestors_count];
// Range type descriptor index.
uint16 type;
};
Ranges are encoded on the wire as ranges.
Object Type Descriptor
struct ObjectTypeDescriptor {
// Indicates that this is an
// object type descriptor.
uint8 tag = 10;
// Schema type ID.
uuid id;
// Schema type name (can be empty for ephemeral free object types).
string name;
// Whether the type is defined in the schema
// or is ephemeral.
bool schema_defined;
};
Compound Type Descriptor
struct CompoundTypeDescriptor {
// Indicates that this is a
// compound type descriptor.
uint8 tag = 11;
// Schema type ID.
uuid id;
// Schema type name.
string name;
// Whether the type is defined in the schema
// or is ephemeral.
bool schema_defined;
// Compound type operation, see TypeOperation below.
uint8<TypeOperation> op;
// Number of compound type components.
uint16 component_count;
// Compound type component type descriptor indexes.
uint16 components[component_count];
};
enum TypeOperation {
// Foo | Bar
UNION = 1;
// Foo & Bar
INTERSECTION = 2;
};
Object Output Shape Descriptor
struct ObjectShapeDescriptor {
// Indicates that this is an
// Object Shape descriptor.
uint8 tag = 1;
// Descriptor ID.
uuid id;
// Whether is is an ephemeral free shape,
// if true, then `type` would always be 0
// and should not be interpreted.
bool ephemeral_free_shape;
// Object type descriptor index.
uint16 type;
// Number of elements in shape.
uint16 element_count;
// Array of shape elements.
ShapeElement elements[element_count];
};
struct ShapeElement {
// Field flags:
// 1 << 0: the field is implicit
// 1 << 1: the field is a link property
// 1 << 2: the field is a link
uint32 flags;
// The cardinality of the shape element.
uint8<Cardinality> cardinality;
// Element name.
string name;
// Element type descriptor index.
uint16 type;
// Source schema type descriptor index
// (useful for polymorphic queries).
uint16 source_type;
};
enum Cardinality {
NO_RESULT = 0x6e;
AT_MOST_ONE = 0x6f;
ONE = 0x41;
MANY = 0x6d;
AT_LEAST_ONE = 0x4d;
};
Objects are encoded on the wire as tuples.
Input Shape Descriptor
struct InputShapeDescriptor {
// Indicates that this is an
// Object Shape descriptor.
uint8 tag = 8;
// Descriptor ID.
uuid id;
// Number of elements in shape.
uint16 element_count;
// Shape elements.
InputShapeElement elements[element_count];
};
struct InputShapeElement {
// Field flags, currently always zero.
uint32 flags;
// The cardinality of the shape element.
uint8<Cardinality> cardinality;
// Element name.
string name;
// Element type descriptor index.
uint16 type;
};
Input objects are encoded on the wire as sparse objects.