/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

syntax = "proto3";

package datafusion;

option java_multiple_files = true;
option java_package = "org.apache.arrow.datafusion.protobuf";
option java_outer_classname = "DatafusionProto";

message ColumnRelation {
  string relation = 1;
}

message Column {
  string name = 1;
  ColumnRelation relation = 2;
}

message DfField{
  Field field = 1;
  ColumnRelation qualifier = 2;
}

message DfSchema {
  repeated DfField columns = 1;
  map<string, string> metadata = 2;
}

// logical plan
// LogicalPlan is a nested type
message LogicalPlanNode {
  oneof LogicalPlanType {
    ListingTableScanNode listing_scan = 1;
    ProjectionNode projection = 3;
    SelectionNode selection = 4;
    LimitNode limit = 5;
    AggregateNode aggregate = 6;
    JoinNode join = 7;
    SortNode sort = 8;
    RepartitionNode repartition = 9;
    EmptyRelationNode empty_relation = 10;
    CreateExternalTableNode create_external_table = 11;
    ExplainNode explain = 12;
    WindowNode window = 13;
    AnalyzeNode analyze = 14;
    CrossJoinNode cross_join = 15;
    ValuesNode values = 16;
    LogicalExtensionNode extension = 17;
    CreateCatalogSchemaNode create_catalog_schema = 18;
    UnionNode union = 19;
    CreateCatalogNode create_catalog = 20;
    SubqueryAliasNode subquery_alias = 21;
    CreateViewNode create_view = 22;
    DistinctNode distinct = 23;
    ViewTableScanNode view_scan = 24;
    CustomTableScanNode custom_scan = 25;
    PrepareNode prepare = 26;
    DropViewNode drop_view = 27;
  }
}

message LogicalExtensionNode {
  bytes node = 1;
  repeated LogicalPlanNode inputs = 2;
}

message ProjectionColumns {
  repeated string columns = 1;
}

message CsvFormat {
  bool has_header = 1;
  string delimiter = 2;
}

message ParquetFormat {
  // Used to be bool enable_pruning = 1;
  reserved 1;
}

message AvroFormat {}

message LogicalExprNodeCollection {
  repeated LogicalExprNode logical_expr_nodes = 1;
}

message ListingTableScanNode {
  reserved 1; // was string table_name
  OwnedTableReference table_name = 14;
  repeated string paths = 2;
  string file_extension = 3;
  ProjectionColumns projection = 4;
  Schema schema = 5;
  repeated LogicalExprNode filters = 6;
  repeated string table_partition_cols = 7;
  bool collect_stat = 8;
  uint32 target_partitions = 9;
  oneof FileFormatType {
    CsvFormat csv = 10;
    ParquetFormat parquet = 11;
    AvroFormat avro = 12;
  }
  repeated LogicalExprNodeCollection file_sort_order = 13;
}

message ViewTableScanNode {
  reserved 1; // was string table_name
  OwnedTableReference table_name = 6;
  LogicalPlanNode input = 2;
  Schema schema = 3;
  ProjectionColumns projection = 4;
  string definition = 5;
}

// Logical Plan to Scan a CustomTableProvider registered at runtime
message CustomTableScanNode {
  reserved 1; // was string table_name
  OwnedTableReference table_name = 6;
  ProjectionColumns projection = 2;
  Schema schema = 3;
  repeated LogicalExprNode filters = 4;
  bytes custom_table_data = 5;
}

message ProjectionNode {
  LogicalPlanNode input = 1;
  repeated LogicalExprNode expr = 2;
  oneof optional_alias {
    string alias = 3;
  }
}

message SelectionNode {
  LogicalPlanNode input = 1;
  LogicalExprNode expr = 2;
}

message SortNode {
  LogicalPlanNode input = 1;
  repeated LogicalExprNode expr = 2;
  // Maximum number of highest/lowest rows to fetch; negative means no limit
  int64 fetch = 3;
}

message RepartitionNode {
  LogicalPlanNode input = 1;
  oneof partition_method {
    uint64 round_robin = 2;
    HashRepartition hash = 3;
  }
}

message HashRepartition {
  repeated LogicalExprNode hash_expr = 1;
  uint64 partition_count = 2;
}

message EmptyRelationNode {
  bool produce_one_row = 1;
}

message CreateExternalTableNode {
  reserved 1; // was string name
  OwnedTableReference name = 12;
  string location = 2;
  string file_type = 3;
  bool has_header = 4;
  DfSchema schema = 5;
  repeated string table_partition_cols = 6;
  bool if_not_exists = 7;
  string delimiter = 8;
  string definition = 9;
  string file_compression_type = 10;
  repeated LogicalExprNodeCollection order_exprs = 13;
  bool unbounded = 14;
  map<string, string> options = 11;
}

message PrepareNode {
  string name = 1;
  repeated ArrowType data_types = 2;
  LogicalPlanNode input = 3;
}

message CreateCatalogSchemaNode {
  string schema_name = 1;
  bool if_not_exists = 2;
  DfSchema schema = 3;
}

message CreateCatalogNode {
  string catalog_name = 1;
  bool if_not_exists = 2;
  DfSchema schema = 3;
}

message DropViewNode {
  OwnedTableReference name = 1;
  bool if_exists = 2;
  DfSchema schema = 3;
}

message CreateViewNode {
  reserved 1; // was string name
  OwnedTableReference name = 5;
  LogicalPlanNode input = 2;
  bool or_replace = 3;
  string definition = 4;
}

// a node containing data for defining values list. unlike in SQL where it's two dimensional, here
// the list is flattened, and with the field n_cols it can be parsed and partitioned into rows
message ValuesNode {
  uint64 n_cols = 1;
  repeated LogicalExprNode values_list = 2;
}

message AnalyzeNode {
  LogicalPlanNode input = 1;
  bool verbose = 2;
}

message ExplainNode {
  LogicalPlanNode input = 1;
  bool verbose = 2;
}

message AggregateNode {
  LogicalPlanNode input = 1;
  repeated LogicalExprNode group_expr = 2;
  repeated LogicalExprNode aggr_expr = 3;
}

message WindowNode {
  LogicalPlanNode input = 1;
  repeated LogicalExprNode window_expr = 2;
}

enum JoinType {
  INNER = 0;
  LEFT = 1;
  RIGHT = 2;
  FULL = 3;
  LEFTSEMI = 4;
  LEFTANTI = 5;
  RIGHTSEMI = 6;
  RIGHTANTI = 7;
}

enum JoinConstraint {
  ON = 0;
  USING = 1;
}

message JoinNode {
  LogicalPlanNode left = 1;
  LogicalPlanNode right = 2;
  JoinType join_type = 3;
  JoinConstraint join_constraint = 4;
  repeated LogicalExprNode left_join_key = 5;
  repeated LogicalExprNode right_join_key = 6;
  bool null_equals_null = 7;
  LogicalExprNode filter = 8;
}

message DistinctNode {
  LogicalPlanNode input = 1;
}

message UnionNode {
  repeated LogicalPlanNode inputs = 1;
}

message CrossJoinNode {
  LogicalPlanNode left = 1;
  LogicalPlanNode right = 2;
}

message LimitNode {
  LogicalPlanNode input = 1;
  // The number of rows to skip before fetch; non-positive means don't skip any
  int64 skip = 2;
  // Maximum number of rows to fetch; negative means no limit
  int64 fetch = 3;
}

message SelectionExecNode {
  LogicalExprNode expr = 1;
}

message SubqueryAliasNode {
  reserved 2; // Was string alias
  LogicalPlanNode input = 1;
  OwnedTableReference alias = 3;
}

// logical expressions
message LogicalExprNode {
  oneof ExprType {
    // column references
    Column column = 1;

    // alias
    AliasNode alias = 2;

    ScalarValue literal = 3;

    // binary expressions
    BinaryExprNode binary_expr = 4;

    // aggregate expressions
    AggregateExprNode aggregate_expr = 5;

    // null checks
    IsNull is_null_expr = 6;
    IsNotNull is_not_null_expr = 7;
    Not not_expr = 8;

    BetweenNode between = 9;
    CaseNode case_ = 10;
    CastNode cast = 11;
    SortExprNode sort = 12;
    NegativeNode negative = 13;
    InListNode in_list = 14;
    bool wildcard = 15;
    ScalarFunctionNode scalar_function = 16;
    TryCastNode try_cast = 17;

    // window expressions
    WindowExprNode window_expr = 18;

    // AggregateUDF expressions
    AggregateUDFExprNode aggregate_udf_expr = 19;

    // Scalar UDF expressions
    ScalarUDFExprNode scalar_udf_expr = 20;

    GetIndexedField get_indexed_field = 21;

    GroupingSetNode grouping_set = 22;

    CubeNode cube = 23;

    RollupNode rollup = 24;

    IsTrue is_true = 25;
    IsFalse is_false = 26;
    IsUnknown is_unknown = 27;
    IsNotTrue is_not_true = 28;
    IsNotFalse is_not_false = 29;
    IsNotUnknown is_not_unknown = 30;
    LikeNode like = 31;
    ILikeNode ilike = 32;
    SimilarToNode similar_to = 33;

    PlaceholderNode placeholder = 34;

  }
}

message PlaceholderNode {
  string id = 1;
  ArrowType data_type = 2;
}

message LogicalExprList {
  repeated LogicalExprNode expr = 1;
}

message GroupingSetNode {
  repeated LogicalExprList expr = 1;
}

message CubeNode {
  repeated LogicalExprNode expr = 1;
}

message RollupNode {
  repeated LogicalExprNode expr = 1;
}



message GetIndexedField {
  LogicalExprNode expr = 1;
  ScalarValue key = 2;
}

message IsNull {
  LogicalExprNode expr = 1;
}

message IsNotNull {
  LogicalExprNode expr = 1;
}

message IsTrue {
  LogicalExprNode expr = 1;
}

message IsFalse {
  LogicalExprNode expr = 1;
}

message IsUnknown {
  LogicalExprNode expr = 1;
}

message IsNotTrue {
  LogicalExprNode expr = 1;
}

message IsNotFalse {
  LogicalExprNode expr = 1;
}

message IsNotUnknown {
  LogicalExprNode expr = 1;
}

message Not {
  LogicalExprNode expr = 1;
}

message AliasNode {
  LogicalExprNode expr = 1;
  string alias = 2;
}

message BinaryExprNode {
  // Represents the operands from the left inner most expression
  // to the right outer most expression where each of them are chained
  // with the operator 'op'.
  repeated LogicalExprNode operands = 1;
  string op = 3;
}

message NegativeNode {
  LogicalExprNode expr = 1;
}

message InListNode {
  LogicalExprNode expr = 1;
  repeated LogicalExprNode list = 2;
  bool negated = 3;
}

enum ScalarFunction {
  Abs = 0;
  Acos = 1;
  Asin = 2;
  Atan = 3;
  Ascii = 4;
  Ceil = 5;
  Cos = 6;
  Digest = 7;
  Exp = 8;
  Floor = 9;
  Ln = 10;
  Log = 11;
  Log10 = 12;
  Log2 = 13;
  Round = 14;
  Signum = 15;
  Sin = 16;
  Sqrt = 17;
  Tan = 18;
  Trunc = 19;
  Array = 20;
  RegexpMatch = 21;
  BitLength = 22;
  Btrim = 23;
  CharacterLength = 24;
  Chr = 25;
  Concat = 26;
  ConcatWithSeparator = 27;
  DatePart = 28;
  DateTrunc = 29;
  InitCap = 30;
  Left = 31;
  Lpad = 32;
  Lower = 33;
  Ltrim = 34;
  MD5 = 35;
  NullIf = 36;
  OctetLength = 37;
  Random = 38;
  RegexpReplace = 39;
  Repeat = 40;
  Replace = 41;
  Reverse = 42;
  Right = 43;
  Rpad = 44;
  Rtrim = 45;
  SHA224 = 46;
  SHA256 = 47;
  SHA384 = 48;
  SHA512 = 49;
  SplitPart = 50;
  StartsWith = 51;
  Strpos = 52;
  Substr = 53;
  ToHex = 54;
  ToTimestamp = 55;
  ToTimestampMillis = 56;
  ToTimestampMicros = 57;
  ToTimestampSeconds = 58;
  Now = 59;
  Translate = 60;
  Trim = 61;
  Upper = 62;
  Coalesce = 63;
  Power = 64;
  StructFun = 65;
  FromUnixtime = 66;
  Atan2 = 67;
  DateBin = 68;
  ArrowTypeof = 69;
  CurrentDate = 70;
  CurrentTime = 71;
  Uuid = 72;
  Cbrt = 73;
  Acosh = 74;
  Asinh = 75;
  Atanh = 76;
  Sinh = 77;
  Cosh = 78;
  Tanh = 79;
  Pi = 80;
  Degrees = 81;
  Radians = 82;
  Factorial = 83;
  Lcm = 84;
  Gcd = 85;
  ArrayAppend = 86;
  ArrayConcat = 87;
  ArrayDims = 88;
  ArrayFill = 89;
  ArrayLength = 90;
  ArrayNdims = 91;
  ArrayPosition = 92;
  ArrayPositions = 93;
  ArrayPrepend = 94;
  ArrayRemove = 95;
  ArrayReplace = 96;
  ArrayToString = 97;
  Cardinality = 98;
  TrimArray = 99;
  ArrayContains = 100;
  Encode = 101;
  Decode = 102;
  Cot = 103;
}

message ScalarFunctionNode {
  ScalarFunction fun = 1;
  repeated LogicalExprNode args = 2;
}

enum AggregateFunction {
  MIN = 0;
  MAX = 1;
  SUM = 2;
  AVG = 3;
  COUNT = 4;
  APPROX_DISTINCT = 5;
  ARRAY_AGG = 6;
  VARIANCE = 7;
  VARIANCE_POP = 8;
  COVARIANCE = 9;
  COVARIANCE_POP = 10;
  STDDEV = 11;
  STDDEV_POP = 12;
  CORRELATION = 13;
  APPROX_PERCENTILE_CONT = 14;
  APPROX_MEDIAN = 15;
  APPROX_PERCENTILE_CONT_WITH_WEIGHT = 16;
  GROUPING = 17;
  MEDIAN = 18;
  BIT_AND = 19;
  BIT_OR = 20;
  BIT_XOR = 21;
  BOOL_AND = 22;
  BOOL_OR = 23;
  // When a function with the same name exists among built-in window functions,
  // we append "_AGG" to obey name scoping rules.
  FIRST_VALUE_AGG = 24;
  LAST_VALUE_AGG = 25;
}

message AggregateExprNode {
  AggregateFunction aggr_function = 1;
  repeated LogicalExprNode expr = 2;
  bool distinct = 3;
  LogicalExprNode filter = 4;
  repeated LogicalExprNode order_by = 5;
}

message AggregateUDFExprNode {
  string fun_name = 1;
  repeated LogicalExprNode args = 2;
  LogicalExprNode filter = 3;
  repeated LogicalExprNode order_by = 4;
}

message ScalarUDFExprNode {
  string fun_name = 1;
  repeated LogicalExprNode args = 2;
}

enum BuiltInWindowFunction {
  ROW_NUMBER = 0;
  RANK = 1;
  DENSE_RANK = 2;
  PERCENT_RANK = 3;
  CUME_DIST = 4;
  NTILE = 5;
  LAG = 6;
  LEAD = 7;
  FIRST_VALUE = 8;
  LAST_VALUE = 9;
  NTH_VALUE = 10;
}

message WindowExprNode {
  oneof window_function {
    AggregateFunction aggr_function = 1;
    BuiltInWindowFunction built_in_function = 2;
    string udaf = 3;
    string udwf = 9;
  }
  LogicalExprNode expr = 4;
  repeated LogicalExprNode partition_by = 5;
  repeated LogicalExprNode order_by = 6;
  // repeated LogicalExprNode filter = 7;
  WindowFrame window_frame = 8;
}

message BetweenNode {
  LogicalExprNode expr = 1;
  bool negated = 2;
  LogicalExprNode low = 3;
  LogicalExprNode high = 4;
}

message LikeNode {
  bool negated = 1;
  LogicalExprNode expr = 2;
  LogicalExprNode pattern = 3;
  string escape_char = 4;
}

message ILikeNode {
  bool negated = 1;
  LogicalExprNode expr = 2;
  LogicalExprNode pattern = 3;
  string escape_char = 4;
}

message SimilarToNode {
  bool negated = 1;
  LogicalExprNode expr = 2;
  LogicalExprNode pattern = 3;
  string escape_char = 4;
}

message CaseNode {
  LogicalExprNode expr = 1;
  repeated WhenThen when_then_expr = 2;
  LogicalExprNode else_expr = 3;
}

message WhenThen {
  LogicalExprNode when_expr = 1;
  LogicalExprNode then_expr = 2;
}

message CastNode {
  LogicalExprNode expr = 1;
  ArrowType arrow_type = 2;
}

message TryCastNode {
  LogicalExprNode expr = 1;
  ArrowType arrow_type = 2;
}

message SortExprNode {
  LogicalExprNode expr = 1;
  bool asc = 2;
  bool nulls_first = 3;
}

enum WindowFrameUnits {
  ROWS = 0;
  RANGE = 1;
  GROUPS = 2;
}

message WindowFrame {
  WindowFrameUnits window_frame_units = 1;
  WindowFrameBound start_bound = 2;
  // "optional" keyword is stable in protoc 3.15 but prost is still on 3.14 (see https://github.com/tokio-rs/prost/issues/430 and https://github.com/tokio-rs/prost/pull/455)
  // this syntax is ugly but is binary compatible with the "optional" keyword (see https://stackoverflow.com/questions/42622015/how-to-define-an-optional-field-in-protobuf-3)
  oneof end_bound {
    WindowFrameBound bound = 3;
  }
}

enum WindowFrameBoundType {
  CURRENT_ROW = 0;
  PRECEDING = 1;
  FOLLOWING = 2;
}

message WindowFrameBound {
  WindowFrameBoundType window_frame_bound_type = 1;
  ScalarValue bound_value = 2;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Arrow Data Types
///////////////////////////////////////////////////////////////////////////////////////////////////

message Schema {
  repeated Field columns = 1;
  map<string, string> metadata = 2;
}

message Field {
  // name of the field
  string name = 1;
  ArrowType arrow_type = 2;
  bool nullable = 3;
  // for complex data types like structs, unions
  repeated Field children = 4;
  map<string, string> metadata = 5;
}

message FixedSizeBinary{
  int32 length = 1;
}

message Timestamp{
  TimeUnit time_unit = 1;
  string timezone = 2;
}

enum DateUnit{
  Day = 0;
  DateMillisecond = 1;
}

enum TimeUnit{
  Second = 0;
  Millisecond = 1;
  Microsecond = 2;
  Nanosecond = 3;
}

enum IntervalUnit{
  YearMonth = 0;
  DayTime = 1;
  MonthDayNano = 2;
}

message Decimal{
  reserved 1, 2;
  uint32 precision = 3;
  int32 scale = 4;
}

message List{
  Field field_type = 1;
}

message FixedSizeList{
  Field field_type = 1;
  int32 list_size = 2;
}

message Dictionary{
  ArrowType key = 1;
  ArrowType value = 2;
}

message Struct{
  repeated Field sub_field_types = 1;
}

message Map {
  Field field_type = 1;
  bool keys_sorted = 2;
}

enum UnionMode{
  sparse = 0;
  dense = 1;
}

message Union{
  repeated Field union_types = 1;
  UnionMode union_mode = 2;
  repeated int32 type_ids = 3;
}

message ScalarListValue{
  // encode null explicitly to distinguish a list with a null value
  // from a list with no values)
  bool is_null = 3;
  Field field = 1;
  repeated ScalarValue values = 2;
}

message ScalarTime32Value {
  oneof value {
    int32 time32_second_value = 1;
    int32 time32_millisecond_value = 2;
  };
}

message ScalarTime64Value {
  oneof value {
    int64 time64_microsecond_value = 1;
    int64 time64_nanosecond_value = 2;
  };
}

message ScalarTimestampValue {
  oneof value {
    int64 time_microsecond_value = 1;
    int64 time_nanosecond_value = 2;
    int64 time_second_value = 3;
    int64 time_millisecond_value = 4;
  };
  string timezone = 5;
}

message ScalarDictionaryValue {
  ArrowType index_type = 1;
  ScalarValue value = 2;
}

message IntervalMonthDayNanoValue {
  int32 months = 1;
  int32 days = 2;
  int64 nanos = 3;
}

message StructValue {
  // Note that a null struct value must have one or more fields, so we
  // encode a null StructValue as one witth an empty field_values
  // list.
  repeated ScalarValue field_values = 2;
  repeated Field fields = 3;
}

message ScalarFixedSizeBinary{
  bytes values = 1;
  int32 length = 2;
}

message ScalarValue{
  // was PrimitiveScalarType null_value = 19;
  reserved 19;

  oneof value {
    // was PrimitiveScalarType null_value = 19;
    // Null value of any type
    ArrowType null_value = 33;

    bool   bool_value = 1;
    string utf8_value = 2;
    string large_utf8_value = 3;
    int32  int8_value = 4;
    int32  int16_value = 5;
    int32  int32_value = 6;
    int64  int64_value = 7;
    uint32 uint8_value = 8;
    uint32 uint16_value = 9;
    uint32 uint32_value = 10;
    uint64 uint64_value = 11;
    float  float32_value = 12;
    double float64_value = 13;
    // Literal Date32 value always has a unit of day
    int32  date_32_value = 14;
    ScalarTime32Value time32_value = 15;
    ScalarListValue list_value = 17;
    //WAS: ScalarType null_list_value = 18;

    Decimal128 decimal128_value = 20;
    int64 date_64_value = 21;
    int32 interval_yearmonth_value = 24;
    int64 interval_daytime_value = 25;

    int64 duration_second_value = 35;
    int64 duration_millisecond_value = 36;
    int64 duration_microsecond_value = 37;
    int64 duration_nanosecond_value = 38;

    ScalarTimestampValue timestamp_value = 26;
    ScalarDictionaryValue dictionary_value = 27;
    bytes binary_value = 28;
    bytes large_binary_value = 29;
    ScalarTime64Value time64_value = 30;
    IntervalMonthDayNanoValue interval_month_day_nano = 31;
    StructValue struct_value = 32;
    ScalarFixedSizeBinary fixed_size_binary_value = 34;
  }
}

message Decimal128{
  bytes value = 1;
  int64 p = 2;
  int64 s = 3;
}

// Serialized data type
message ArrowType{
  oneof arrow_type_enum {
    EmptyMessage NONE = 1;     // arrow::Type::NA
    EmptyMessage BOOL = 2;     // arrow::Type::BOOL
    EmptyMessage UINT8 = 3;    // arrow::Type::UINT8
    EmptyMessage INT8 = 4;     // arrow::Type::INT8
    EmptyMessage UINT16 = 5;   // represents arrow::Type fields in src/arrow/type.h
    EmptyMessage INT16 = 6;
    EmptyMessage UINT32 = 7;
    EmptyMessage INT32 = 8;
    EmptyMessage UINT64 = 9;
    EmptyMessage INT64 = 10 ;
    EmptyMessage FLOAT16 = 11 ;
    EmptyMessage FLOAT32 = 12 ;
    EmptyMessage FLOAT64 = 13 ;
    EmptyMessage UTF8 = 14 ;
    EmptyMessage LARGE_UTF8 = 32;
    EmptyMessage BINARY = 15 ;
    int32 FIXED_SIZE_BINARY = 16 ;
    EmptyMessage LARGE_BINARY = 31;
    EmptyMessage DATE32 = 17 ;
    EmptyMessage DATE64 = 18 ;
    TimeUnit DURATION = 19;
    Timestamp TIMESTAMP = 20 ;
    TimeUnit TIME32 = 21 ;
    TimeUnit TIME64 = 22 ;
    IntervalUnit INTERVAL = 23 ;
    Decimal DECIMAL = 24 ;
    List LIST = 25;
    List LARGE_LIST = 26;
    FixedSizeList FIXED_SIZE_LIST = 27;
    Struct STRUCT = 28;
    Union UNION = 29;
    Dictionary DICTIONARY = 30;
    Map MAP = 33;
  }
}

//Useful for representing an empty enum variant in rust
// E.G. enum example{One, Two(i32)}
// maps to
// message example{
//    oneof{
//        EmptyMessage One = 1;
//        i32 Two = 2;
//   }
//}
message EmptyMessage{}

message AnalyzedLogicalPlanType {
  string analyzer_name = 1;
}

message OptimizedLogicalPlanType {
  string optimizer_name = 1;
}

message OptimizedPhysicalPlanType {
  string optimizer_name = 1;
}

message PlanType {
  oneof plan_type_enum {
    EmptyMessage InitialLogicalPlan = 1;
    AnalyzedLogicalPlanType AnalyzedLogicalPlan = 7;
    EmptyMessage FinalAnalyzedLogicalPlan = 8;
    OptimizedLogicalPlanType OptimizedLogicalPlan = 2;
    EmptyMessage FinalLogicalPlan = 3;
    EmptyMessage InitialPhysicalPlan = 4;
    OptimizedPhysicalPlanType OptimizedPhysicalPlan = 5;
    EmptyMessage FinalPhysicalPlan = 6;
  }
}

message StringifiedPlan {
  PlanType plan_type = 1;
  string plan = 2;
}

message BareTableReference {
  string table = 1;
}

message PartialTableReference {
  string schema = 1;
  string table = 2;
}

message FullTableReference {
  string catalog = 1;
  string schema = 2;
  string table = 3;
}

message OwnedTableReference {
  oneof table_reference_enum {
    BareTableReference bare = 1;
    PartialTableReference partial = 2;
    FullTableReference full = 3;
  }
}

/////////////////////////////////////////////////////////////////////////////////////////////////

// PhysicalPlanNode is a nested type
message PhysicalPlanNode {
  oneof PhysicalPlanType {
    ParquetScanExecNode parquet_scan = 1;
    CsvScanExecNode csv_scan = 2;
    EmptyExecNode empty = 3;
    ProjectionExecNode projection = 4;
    GlobalLimitExecNode global_limit = 6;
    LocalLimitExecNode local_limit = 7;
    AggregateExecNode aggregate = 8;
    HashJoinExecNode hash_join = 9;
    SortExecNode sort = 10;
    CoalesceBatchesExecNode coalesce_batches = 11;
    FilterExecNode filter = 12;
    CoalescePartitionsExecNode merge = 13;
    RepartitionExecNode repartition = 14;
    WindowAggExecNode window = 15;
    CrossJoinExecNode cross_join = 16;
    AvroScanExecNode avro_scan = 17;
    PhysicalExtensionNode extension = 18;
    UnionExecNode union = 19;
    ExplainExecNode explain = 20;
    SortPreservingMergeExecNode sort_preserving_merge = 21;
    NestedLoopJoinExecNode nested_loop_join = 22;
  }
}

message PhysicalExtensionNode {
  bytes node = 1;
  repeated PhysicalPlanNode inputs = 2;
}

// physical expressions
message PhysicalExprNode {
  oneof ExprType {
    // column references
    PhysicalColumn column = 1;

    ScalarValue literal = 2;

    // binary expressions
    PhysicalBinaryExprNode binary_expr = 3;

    // aggregate expressions
    PhysicalAggregateExprNode aggregate_expr = 4;

    // null checks
    PhysicalIsNull is_null_expr = 5;
    PhysicalIsNotNull is_not_null_expr = 6;
    PhysicalNot not_expr = 7;

    PhysicalCaseNode case_ = 8;
    PhysicalCastNode cast = 9;
    PhysicalSortExprNode sort = 10;
    PhysicalNegativeNode negative = 11;
    PhysicalInListNode in_list = 12;
    PhysicalScalarFunctionNode scalar_function = 13;
    PhysicalTryCastNode try_cast = 14;

    // window expressions
    PhysicalWindowExprNode window_expr = 15;

    PhysicalScalarUdfNode scalar_udf = 16;

    PhysicalDateTimeIntervalExprNode date_time_interval_expr = 17;

    PhysicalLikeExprNode like_expr = 18;

    PhysicalGetIndexedFieldExprNode get_indexed_field_expr = 19;
  }
}

message PhysicalScalarUdfNode {
  string name = 1;
  repeated PhysicalExprNode args = 2;
  ArrowType return_type = 4;
}

message PhysicalAggregateExprNode {
  oneof AggregateFunction {
    AggregateFunction aggr_function = 1;
    string user_defined_aggr_function = 4;
  }
  repeated PhysicalExprNode expr = 2;
  repeated PhysicalSortExprNode ordering_req = 5;
  bool distinct = 3;
}

message PhysicalWindowExprNode {
  oneof window_function {
    AggregateFunction aggr_function = 1;
    BuiltInWindowFunction built_in_function = 2;
    // udaf = 3
  }
  PhysicalExprNode expr = 4;
}

message PhysicalIsNull {
  PhysicalExprNode expr = 1;
}

message PhysicalIsNotNull {
  PhysicalExprNode expr = 1;
}

message PhysicalNot {
  PhysicalExprNode expr = 1;
}

message PhysicalAliasNode {
  PhysicalExprNode expr = 1;
  string alias = 2;
}

message PhysicalBinaryExprNode {
  PhysicalExprNode l = 1;
  PhysicalExprNode r = 2;
  string op = 3;
}

message PhysicalDateTimeIntervalExprNode {
  PhysicalExprNode l = 1;
  PhysicalExprNode r = 2;
  string op = 3;
}

message PhysicalLikeExprNode {
  bool negated = 1;
  bool case_insensitive = 2;
  PhysicalExprNode expr = 3;
  PhysicalExprNode pattern = 4;
}

message PhysicalSortExprNode {
  PhysicalExprNode expr = 1;
  bool asc = 2;
  bool nulls_first = 3;
}

message PhysicalWhenThen {
  PhysicalExprNode when_expr = 1;
  PhysicalExprNode then_expr = 2;
}

message PhysicalInListNode {
  PhysicalExprNode expr = 1;
  repeated PhysicalExprNode list = 2;
  bool negated = 3;
}

message PhysicalCaseNode {
  PhysicalExprNode expr = 1;
  repeated PhysicalWhenThen when_then_expr = 2;
  PhysicalExprNode else_expr = 3;
}

message PhysicalScalarFunctionNode {
  string name = 1;
  ScalarFunction fun = 2;
  repeated PhysicalExprNode args = 3;
  ArrowType return_type = 4;
}

message PhysicalTryCastNode {
  PhysicalExprNode expr = 1;
  ArrowType arrow_type = 2;
}

message PhysicalCastNode {
  PhysicalExprNode expr = 1;
  ArrowType arrow_type = 2;
}

message PhysicalNegativeNode {
  PhysicalExprNode expr = 1;
}

message FilterExecNode {
  PhysicalPlanNode input = 1;
  PhysicalExprNode expr = 2;
}

message FileGroup {
  repeated PartitionedFile files = 1;
}

message ScanLimit {
  // wrap into a message to make it optional
  uint32 limit = 1;
}

message PhysicalSortExprNodeCollection {
  repeated PhysicalSortExprNode physical_sort_expr_nodes = 1;
}

message FileScanExecConf {
  // Was repeated ConfigOption options = 10;
  reserved 10;

  repeated FileGroup file_groups = 1;
  Schema schema = 2;
  repeated uint32 projection = 4;
  ScanLimit limit = 5;
  Statistics statistics = 6;
  repeated string table_partition_cols = 7;
  string object_store_url = 8;
  repeated PhysicalSortExprNodeCollection output_ordering = 9;
}

message ParquetScanExecNode {
  FileScanExecConf base_conf = 1;

  // Was pruning predicate based on a logical expr.
  reserved 2;

  PhysicalExprNode predicate = 3;
}

message CsvScanExecNode {
  FileScanExecConf base_conf = 1;
  bool has_header = 2;
  string delimiter = 3;
}

message AvroScanExecNode {
  FileScanExecConf base_conf = 1;
}

enum PartitionMode {
  COLLECT_LEFT = 0;
  PARTITIONED = 1;
  AUTO = 2;
}

message HashJoinExecNode {
  PhysicalPlanNode left = 1;
  PhysicalPlanNode right = 2;
  repeated JoinOn on = 3;
  JoinType join_type = 4;
  PartitionMode partition_mode = 6;
  bool null_equals_null = 7;
  JoinFilter filter = 8;
}

message UnionExecNode {
  repeated PhysicalPlanNode inputs = 1;
}

message ExplainExecNode {
  Schema schema = 1;
  repeated StringifiedPlan stringified_plans = 2;
  bool verbose = 3;
}

message CrossJoinExecNode {
  PhysicalPlanNode left = 1;
  PhysicalPlanNode right = 2;
}

message PhysicalColumn {
  string name = 1;
  uint32 index = 2;
}

message JoinOn {
  PhysicalColumn left = 1;
  PhysicalColumn right = 2;
}

message EmptyExecNode {
  bool produce_one_row = 1;
  Schema schema = 2;
}

message ProjectionExecNode {
  PhysicalPlanNode input = 1;
  repeated PhysicalExprNode expr = 2;
  repeated string expr_name = 3;
}

enum AggregateMode {
  PARTIAL = 0;
  FINAL = 1;
  FINAL_PARTITIONED = 2;
  SINGLE = 3;
  SINGLE_PARTITIONED = 4;
}

message WindowAggExecNode {
  PhysicalPlanNode input = 1;
  repeated PhysicalExprNode window_expr = 2;
  repeated string window_expr_name = 3;
  Schema input_schema = 4;
}

message MaybeFilter {
  PhysicalExprNode expr = 1;
}

message MaybePhysicalSortExprs {
  repeated PhysicalSortExprNode sort_expr = 1;
}

message AggregateExecNode {
  repeated PhysicalExprNode group_expr = 1;
  repeated PhysicalExprNode aggr_expr = 2;
  AggregateMode mode = 3;
  PhysicalPlanNode input = 4;
  repeated string group_expr_name = 5;
  repeated string aggr_expr_name = 6;
  // we need the input schema to the partial aggregate to pass to the final aggregate
  Schema input_schema = 7;
  repeated PhysicalExprNode null_expr = 8;
  repeated bool groups = 9;
  repeated MaybeFilter filter_expr = 10;
  repeated MaybePhysicalSortExprs order_by_expr = 11;
}

message GlobalLimitExecNode {
  PhysicalPlanNode input = 1;
  // The number of rows to skip before fetch
  uint32 skip = 2;
  // Maximum number of rows to fetch; negative means no limit
  int64 fetch = 3;
}

message LocalLimitExecNode {
  PhysicalPlanNode input = 1;
  uint32 fetch = 2;
}

message SortExecNode {
  PhysicalPlanNode input = 1;
  repeated PhysicalExprNode expr = 2;
  // Maximum number of highest/lowest rows to fetch; negative means no limit
  int64 fetch = 3;
  bool preserve_partitioning = 4;
}

message SortPreservingMergeExecNode {
  PhysicalPlanNode input = 1;
  repeated PhysicalExprNode expr = 2;
  // Maximum number of highest/lowest rows to fetch; negative means no limit
  int64 fetch = 3;
}

message NestedLoopJoinExecNode {
  PhysicalPlanNode left = 1;
  PhysicalPlanNode right = 2;
  JoinType join_type = 3;
  JoinFilter filter = 4;
}

message CoalesceBatchesExecNode {
  PhysicalPlanNode input = 1;
  uint32 target_batch_size = 2;
}

message CoalescePartitionsExecNode {
  PhysicalPlanNode input = 1;
}

message PhysicalHashRepartition {
  repeated PhysicalExprNode hash_expr = 1;
  uint64 partition_count = 2;
}

message RepartitionExecNode{
  PhysicalPlanNode input = 1;
  oneof partition_method {
    uint64 round_robin = 2;
    PhysicalHashRepartition hash = 3;
    uint64 unknown = 4;
  }
}

message JoinFilter{
  PhysicalExprNode expression = 1;
  repeated ColumnIndex column_indices = 2;
  Schema schema = 3;
}

message ColumnIndex{
  uint32 index = 1;
  JoinSide side = 2;
}

enum JoinSide{
  LEFT_SIDE = 0;
  RIGHT_SIDE = 1;
}

message PartitionedFile {
  string path = 1;
  uint64 size = 2;
  uint64 last_modified_ns = 3;
  repeated ScalarValue partition_values = 4;
  FileRange range = 5;
}

message FileRange {
  int64 start = 1;
  int64 end = 2;
}

message PartitionStats {
  int64 num_rows = 1;
  int64 num_batches = 2;
  int64 num_bytes = 3;
  repeated ColumnStats column_stats = 4;
}

message Statistics {
  int64 num_rows = 1;
  int64 total_byte_size = 2;
  repeated ColumnStats column_stats = 3;
  bool is_exact = 4;
}

message ColumnStats {
  ScalarValue min_value = 1;
  ScalarValue max_value = 2;
  uint32 null_count = 3;
  uint32 distinct_count = 4;
}

message PhysicalGetIndexedFieldExprNode {
  PhysicalExprNode arg = 1;
  ScalarValue key = 2;
}
