diff --git a/apis/datasets/v1/data_access.proto b/apis/datasets/v1/data_access.proto index cadfa7e..171668e 100644 --- a/apis/datasets/v1/data_access.proto +++ b/apis/datasets/v1/data_access.proto @@ -107,6 +107,8 @@ enum LogicalOperator { // Every comparison evaluates to null (unknown) when the field is absent or explicitly null, including NOT_EQUAL. // Consequently, both `field != value` and `NOT(field == value)` require the field to be present. To include absent or // null fields, explicitly combine the comparison with FieldNullCheck using OR. +// Enum fields support only EQUAL and NOT_EQUAL. Use a LogicalExpression with OR over equality comparisons to match +// any of several members. Unknown enum values, numeric enum literals, and ordering comparisons are invalid arguments. message FieldComparison { // Name of a top-level field in the dataset schema. string field_name = 1 [(buf.validate.field).string = { @@ -119,7 +121,8 @@ message FieldComparison { defined_only: true not_in: [0] }]; - // Literal value. Its kind must match the field's protobuf descriptor. + // Literal value, interpreted using the field's schema. For custom enums, use string_value with a value from + // FieldAnnotation.enum_values. FieldQueryValue value = 3 [(buf.validate.field).required = true]; } @@ -157,22 +160,25 @@ message FieldQueryValue { "string_value", "timestamp_value", "duration_value", - "enum_name", "bytes_value" ] required: true }; + reserved 8; + reserved enum_name; + // Exactly one typed literal must be set. Explicit presence preserves zero and empty values. bool bool_value = 1 [features.field_presence = EXPLICIT]; int64 int64_value = 2 [features.field_presence = EXPLICIT]; uint64 uint64_value = 3 [features.field_presence = EXPLICIT]; double double_value = 4 [features.field_presence = EXPLICIT]; + // Text for a string field, or a value from FieldAnnotation.enum_values for a custom enum, e.g. "L1". + // The server resolves enum values to their numbers. Matching is case-sensitive; unknown values are rejected. + // Generated protobuf names are not accepted here unless they are also declared public values. string string_value = 5 [features.field_presence = EXPLICIT]; google.protobuf.Timestamp timestamp_value = 6; google.protobuf.Duration duration_value = 7; - // Symbolic value from the field's enum descriptor. - string enum_name = 8 [features.field_presence = EXPLICIT]; bytes bytes_value = 9 [features.field_presence = EXPLICIT]; } diff --git a/apis/datasets/v1/dataset_type.proto b/apis/datasets/v1/dataset_type.proto index b0eb609..5f42857 100644 --- a/apis/datasets/v1/dataset_type.proto +++ b/apis/datasets/v1/dataset_type.proto @@ -16,11 +16,11 @@ option features.field_presence = IMPLICIT; // with its Tilebox annotation, matching the information represented separately by AnnotatedType. message Field { // The descriptor contains the name of the field, the type, optional labels (e.g. repeated) and other information. - // If the type is TYPE_MESSAGE, then the type_name must be a fully qualified name to a well known type, e.g. - // `datasets.v1.Vec3` or `google.protobuf.Timestamp`. + // For built-in message and enum types, set type_name to the full name with a leading dot, e.g. `.datasets.v1.Vec3`. + // For a custom enum, set TYPE_ENUM, leave type_name empty, and provide annotation.enum_values. google.protobuf.FieldDescriptorProto descriptor = 1 [(buf.validate.field).required = true]; - // Additional documentation, source mapping, and query metadata for the field. + // Documentation, source mapping, query metadata, and custom enum values for the field. FieldAnnotation annotation = 2; } @@ -47,6 +47,12 @@ enum FieldRole { FIELD_ROLE_PRIMARY_TITLE = 1; } +// EnumValue is one allowed value of a custom enum. +message EnumValue { + // The value users ingest, query, and receive, e.g. "L1". + string value = 1 [(buf.validate.field).string.min_len = 1]; +} + // FieldAnnotation contains additional information about a field in a dataset. message FieldAnnotation { string description = 1; @@ -58,6 +64,7 @@ message FieldAnnotation { // Whether the field is projected into query storage and may be used in server-side filter expressions. // Queryable fields are not necessarily backed by a secondary database index. + // Enum fields do not count toward the queryable string field limit. bool queryable = 4; // Optional JSON Schema reference for this field when it corresponds to a well known schema. @@ -73,6 +80,16 @@ message FieldAnnotation { not_in: [0] } ]; + + // Allowed values for a custom enum field. Values must be unique; leave this empty for other field types. + // The server generates the protobuf enum names and numbers. Clients do not need to know its naming rules. + // Updates may append values without changing existing numbers. Removing, renaming, or reordering values + // is not supported yet. + // + // In responses, entries match the enum descriptor's members in order, excluding the generated zero member. + // Pair each entry with the corresponding member's number to encode and decode datapoints. List positions + // are not enum numbers. The zero member is not a public value; missing fields remain distinct from zero. + repeated EnumValue enum_values = 7; } // DatasetType is the request representation of a dataset type, used when creating or updating a dataset. @@ -91,8 +108,9 @@ message DatasetType { // AnnotatedType is the resolved representation returned on Dataset messages, including GetDataset responses. // It combines the generated protobuf descriptors with the corresponding Tilebox field annotations. message AnnotatedType { + // Descriptors for the dataset's datapoint message, including its generated enums. google.protobuf.FileDescriptorSet descriptor_set = 1; - // the url of the type, one of the types defined in the descriptor + // Identifies the datapoint message in descriptor_set by name, independent of file or declaration order. string type_url = 2; reserved 3; // Annotations corresponding by index to the FieldDescriptorProto entries of the message selected by type_url.