// 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
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// 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.

include "../../format/Schema.fbs";
include "Literal.fbs";
include "Expression.fbs";

namespace org.apache.arrow.computeir.flatbuf;

/// An identifier for relations in a query.
///
/// A table is used here to allow plan implementations optionality.
table RelId {
  id: uint64;
}

/// Filter operation
table Filter {
  /// An identifiier for the relation. The identifier should be unique over the
  /// entire plan. Optional.
  id: RelId;
  /// Child relation
  rel: Relation (required);
  /// The expression which will be evaluated against input rows
  /// to determine whether they should be excluded from the
  /// filter relation's output.
  predicate: Expression (required);
}

/// Projection
table Project {
  /// An identifiier for the relation. The identifier should be unique over the
  /// entire plan. Optional.
  id: RelId;
  /// Child relation
  rel: Relation (required);
  /// Expressions which will be evaluated to produce to
  /// the rows of the project relation's output.
  expressions: [Expression] (required);
}

/// A set of grouping keys
table Grouping {
  /// Expressions to group by
  keys: [Expression] (required);
}

/// Aggregate operation
table Aggregate {
  /// An identifiier for the relation. The identifier should be unique over the
  /// entire plan. Optional.
  id: RelId;
  /// Child relation
  rel: Relation (required);
  /// Expressions which will be evaluated to produce to
  /// the rows of the aggregate relation's output.
  measures: [Expression] (required);
  /// Keys by which `aggregations` will be grouped.
  ///
  /// The nested list here is to support grouping sets
  /// eg
  ///
  /// SELECT a, b, c, sum(d)
  /// FROM t
  /// GROUP BY
  ///   GROUPING SETS (
  ///     (a, b, c),
  ///     (a, b),
  ///     (a),
  ///     ()
  ///   );
  groupings: [Grouping] (required);
}

enum JoinKind : uint8 {
  Anti,
  Cross,
  FullOuter,
  Inner,
  LeftOuter,
  LeftSemi,
  RightOuter,
}

/// Join between two tables
table Join {
  /// An identifiier for the relation. The identifier should be unique over the
  /// entire plan. Optional.
  id: RelId;
  /// Left relation
  left: Relation (required);
  /// Right relation
  right: Relation (required);
  /// The expression which will be evaluated against rows from each
  /// input to determine whether they should be included in the
  /// join relation's output.
  on_expression: Expression (required);
  /// The kind of join to use.
  join_kind: JoinKind;
}

/// Order by relation
table OrderBy {
  /// An identifiier for the relation. The identifier should be unique over the
  /// entire plan. Optional.
  id: RelId;
  /// Child relation
  rel: Relation (required);
  /// Define sort order for rows of output.
  /// Keys with higher precedence are ordered ahead of other keys.
  keys: [SortKey] (required);
}

/// Limit operation
table Limit {
  /// An identifiier for the relation. The identifier should be unique over the
  /// entire plan. Optional.
  id: RelId;
  /// Child relation
  rel: Relation (required);
  /// Starting index of rows
  offset: uint32;
  /// The maximum number of rows of output.
  count: uint32;
}

/// The kind of set operation being performed.
enum SetOpKind : uint8 {
  Union,
  Intersection,
  Difference,
}

/// A set operation on two or more relations
table SetOperation {
  /// An identifiier for the relation. The identifier should be unique over the
  /// entire plan. Optional.
  id: RelId;
  /// Child relations
  rels: [Relation] (required);
  /// The kind of set operation
  set_op: SetOpKind;
}

/// A single column of literal values.
table LiteralColumn {
  /// The literal values of the column
  elements: [Literal] (required);
}

/// Literal relation
table LiteralRelation {
  /// An identifiier for the relation. The identifier should be unique over the
  /// entire plan. Optional.
  id: RelId;
  /// The columns of this literal relation.
  columns: [LiteralColumn] (required);
}

/// An external source of tabular data
table Source {
  /// An identifiier for the relation. The identifier should be unique over the
  /// entire plan. Optional.
  id: RelId;
  name: string (required);
  /// An optional expression used to filter out rows directly from the source.
  ///
  /// Useful for consumers that implement predicate pushdown.
  ///
  /// A missing filter value indicates no filter, i.e., all rows are
  /// returned from the source.
  filter: Expression;
  /// Schemas are explicitly optional
  schema: org.apache.arrow.flatbuf.Schema;
  /// An optional list of field indices indicating which columns should be read
  /// from the source. Columns excluded from this listing will instead be replaced
  /// with all-null placeholders to guarantee that the schema of the source is
  /// unaffected by this projection.
  ///
  /// A missing value indicates all columns should be read.
  ///
  /// The behavior of an empty list is undefined.
  projection: [FieldIndex];
}

/// The varieties of relations
union RelationImpl {
  Aggregate,
  Filter,
  Join,
  Limit,
  LiteralRelation,
  OrderBy,
  Project,
  SetOperation,
  Source,
}

/// A table holding an instance of the possible relation types.
table Relation {
  impl: RelationImpl (required);
}

root_type Relation;
