// SPDX-License-Identifier: Apache-2.0
syntax = "proto3";

package substrait;

import "google/protobuf/empty.proto";

option csharp_namespace = "Substrait.Protobuf";
option go_package = "github.com/substrait-io/substrait-protobuf/go/substraitpb";
option java_multiple_files = true;
option java_package = "io.substrait.proto";

// Note: type_variation_reference fields within Type messages reference a
// type_variation_anchor defined in the plan's extension declarations.
//
// The value 0 represents the system-preferred variation and is a valid reference value.
message Type {
  reserved 14, 17, 29, 31;

  oneof kind {
    Boolean bool = 1;
    I8 i8 = 2;
    I16 i16 = 3;
    I32 i32 = 5;
    I64 i64 = 7;
    FP32 fp32 = 10;
    FP64 fp64 = 11;
    String string = 12;
    Binary binary = 13;
    Date date = 16;
    IntervalYear interval_year = 19;
    IntervalDay interval_day = 20;
    IntervalCompound interval_compound = 35;
    UUID uuid = 32;

    FixedChar fixed_char = 21;
    VarChar varchar = 22;
    FixedBinary fixed_binary = 23;
    Decimal decimal = 24;
    PrecisionTime precision_time = 36;
    PrecisionTimestamp precision_timestamp = 33;
    PrecisionTimestampTZ precision_timestamp_tz = 34; // value is since UNIX epoch in UTC

    Struct struct = 25;
    List list = 27;
    Map map = 28;
    Func func = 38;

    UserDefined user_defined = 30;

    // Reference an aliased type in `Plan.type_aliases`.
    TypeAliasReference alias = 37;
  }

  enum Nullability {
    NULLABILITY_UNSPECIFIED = 0;
    NULLABILITY_NULLABLE = 1;
    NULLABILITY_REQUIRED = 2;
  }

  message Boolean {
    uint32 type_variation_reference = 1;
    Nullability nullability = 2;
  }

  message I8 {
    uint32 type_variation_reference = 1;
    Nullability nullability = 2;
  }

  message I16 {
    uint32 type_variation_reference = 1;
    Nullability nullability = 2;
  }

  message I32 {
    uint32 type_variation_reference = 1;
    Nullability nullability = 2;
  }

  message I64 {
    uint32 type_variation_reference = 1;
    Nullability nullability = 2;
  }

  message FP32 {
    uint32 type_variation_reference = 1;
    Nullability nullability = 2;
  }

  message FP64 {
    uint32 type_variation_reference = 1;
    Nullability nullability = 2;
  }

  message String {
    uint32 type_variation_reference = 1;
    Nullability nullability = 2;
  }

  message Binary {
    uint32 type_variation_reference = 1;
    Nullability nullability = 2;
  }

  message Date {
    uint32 type_variation_reference = 1;
    Nullability nullability = 2;
  }

  // An interval consisting of years and months
  message IntervalYear {
    uint32 type_variation_reference = 1;
    Nullability nullability = 2;
  }

  // An interval consisting of days, seconds, and microseconds
  message IntervalDay {
    uint32 type_variation_reference = 1;
    Nullability nullability = 2;

    // Sub-second precision, 0 means the value given is in seconds, 3 is milliseconds, 6 microseconds, 9 is nanoseconds, etc.
    // if unset, treat as 6.
    optional int32 precision = 3;
  }

  // An interval consisting of the components of both IntervalYear and IntervalDay
  message IntervalCompound {
    uint32 type_variation_reference = 1;
    Nullability nullability = 2;
    // Sub-second precision, 0 means the value given is in seconds, 3 is milliseconds, 6 microseconds, 9 is nanoseconds, etc.
    int32 precision = 3;
  }

  message UUID {
    uint32 type_variation_reference = 1;
    Nullability nullability = 2;
  }

  // Start compound types.
  message FixedChar {
    int32 length = 1;
    uint32 type_variation_reference = 2;
    Nullability nullability = 3;
  }

  message VarChar {
    int32 length = 1;
    uint32 type_variation_reference = 2;
    Nullability nullability = 3;
  }

  message FixedBinary {
    int32 length = 1;
    uint32 type_variation_reference = 2;
    Nullability nullability = 3;
  }

  message Decimal {
    int32 scale = 1;
    int32 precision = 2;
    uint32 type_variation_reference = 3;
    Nullability nullability = 4;
  }

  message PrecisionTime {
    // Sub-second precision, 0 means the value given is in seconds, 3 is milliseconds, 6 microseconds, 9 is nanoseconds, 12 is picoseconds
    int32 precision = 1;
    uint32 type_variation_reference = 2;
    Nullability nullability = 3;
  }

  message PrecisionTimestamp {
    // Sub-second precision, 0 means the value given is in seconds, 3 is milliseconds, 6 microseconds, 9 is nanoseconds, 12 is picoseconds
    int32 precision = 1;
    uint32 type_variation_reference = 2;
    Nullability nullability = 3;
  }

  message PrecisionTimestampTZ {
    // Sub-second precision, 0 means the value given is in seconds, 3 is milliseconds, 6 microseconds, 9 is nanoseconds, 12 is picoseconds
    int32 precision = 1;
    uint32 type_variation_reference = 2;
    Nullability nullability = 3;
  }

  message Struct {
    repeated Type types = 1;
    uint32 type_variation_reference = 2;
    Nullability nullability = 3;
  }

  message List {
    Type type = 1;
    uint32 type_variation_reference = 2;
    Nullability nullability = 3;
  }

  message Map {
    Type key = 1;
    Type value = 2;
    uint32 type_variation_reference = 3;
    Nullability nullability = 4;
  }

  // A function type for higher-order functions.
  // Represents a function that takes parameters of specified types and
  // returns a value of a specified type.
  message Func {
    // Types of parameters this function type accepts.
    repeated Type parameter_types = 1;
    // Return type of the function.
    Type return_type = 2;
    // Nullability of the function value itself, not its return type.
    // A nullable function type (e.g., func?<i32 -> i32>) means the function
    // reference may be null. This is distinct from the return type's
    // nullability (e.g., func<i32 -> i32?> where the function always exists
    // but may return null).
    Nullability nullability = 3;
  }

  message UserDefined {
    // References a type_anchor defined in the plan's extension declarations.
    uint32 type_reference = 1;
    uint32 type_variation_reference = 2;
    Nullability nullability = 3;
    repeated Parameter type_parameters = 4;
  }

  message Parameter {
    oneof parameter {
      // Explicitly null/unspecified parameter, to select the default value (if
      // any).
      google.protobuf.Empty null = 1;

      // Data type parameters, like the i32 in LIST<i32>.
      Type data_type = 2;

      // Value parameters, like the 10 in VARCHAR<10>.
      bool boolean = 3;
      int64 integer = 4;
      string enum = 5;
      string string = 6;
    }
  }

  message TypeAliasReference {
    uint32 type_alias_reference = 1;
    // Nullability of the referenced type alias. Must be specified.
    Nullability nullability = 2;
  }
}

message TypeAlias {
  // A surrogate key used in the context of a single plan to reference a
  // specific type alias.
  // 0 is a valid anchor/reference, but prefer non-zero values for ergonomics.
  uint32 type_alias_anchor = 1;

  // A concrete type to be aliased.
  //
  // * All type parameters must be specified.
  // * Cannot directly be another alias.
  // * Type parameters can reference other aliased types as long as no circular dependencies are introduced.
  // * Nullability of aliased type is **ignored**. Nullability must be specified when the aliased type is referenced.
  // * Type variation may be specified in the aliased type.
  Type type = 2;
}

// A message for modeling name/type pairs.
//
// Useful for representing relation schemas.
//
// Notes:
//
// * The names field is in depth-first order.
//
// For example a schema such as:
//
// a: int64
// b: struct<c: float32, d: string>
//
// would have a `names` field that looks like:
//
// ["a", "b", "c", "d"]
//
// * Only struct fields are contained in this field's elements,
// * Map keys should be traversed first, then values when producing/consuming
// * When used to represent a relation schema, the outermost struct's
//   nullability should be NULLABILITY_REQUIRED.
message NamedStruct {
  // list of names in dfs order
  repeated string names = 1;
  Type.Struct struct = 2;
}
