syntax = "proto3";

package wix.devcenter.plans.v1.upstream.wix.query;

import "google/protobuf/struct.proto";
import "google/protobuf/wrappers.proto";
import "wix/devcenter/plans/v1/upstream/wix/common/sorting.proto";
import "wix/devcenter/plans/v1/upstream/wix/common/paging.proto";
import "wix/api/annotations.proto";
import "wix/api/validations.proto";

option java_multiple_files = true;
option java_outer_classname = "QueryProto";
option java_package = "com.wix.plans.v1.upstream.wix.query";

message Query {
  option (.wix.api.decomposite_of) = "wix.common.Query";
  option (.wix.api.decomposition_minimum_fields) = {
    field: "filter"
    field: "sort"
    field: "paging"
  };
  //Filter object in the following format:
  //`"filter" : {
  //              "fieldName1": "value1",
  //              "fieldName2":{"$operator":"value2"}
  //  }`
  //Example of operators: `$eq`, `$ne`, `$lt`, `$lte`, `$gt`, `$gte`, `$in`, `$hasSome`, `$hasAll`, `$startsWith`, `$contains`
  google.protobuf.Value filter = 1;
  //Sort object in the following format:
  //`[{"fieldName":"sortField1","order":"ASC"},{"fieldName":"sortField2","order":"DESC"}]`
  repeated wix.common.Sorting sort = 2;
  //Paging options to limit and skip the number of items.
  wix.common.Paging paging = 3;
  //Array of projected fields. A list of specific field names to return. If `fieldsets` are also specified, the union of `fieldsets` and `fields` is returned.
  repeated string fields = 4;
  //Array of named, predefined sets of projected fields. A array of predefined named sets of fields to be returned. Specifying multiple `fieldsets` will return the union of fields from all sets. If `fields` are also specified, the union of `fieldsets` and `fields` is returned.
  repeated string fieldsets = 5;
}

message QueryV2 {
  option (.wix.api.decomposite_of) = "wix.common.QueryV2";
  option (.wix.api.decomposition_minimum_fields) = {
    field: "filter"
    field: "sort"
    field: "paging"
  };
  option (.wix.api.decomposition_minimum_fields) = {
    field: "filter"
    field: "sort"
    field: "cursor_paging"
  };
  //Filter object in the following format:
  //`"filter" : {
  //              "fieldName1": "value1",
  //              "fieldName2":{"$operator":"value2"}
  //  }`
  //Example of operators: `$eq`, `$ne`, `$lt`, `$lte`, `$gt`, `$gte`, `$in`, `$hasSome`, `$hasAll`, `$startsWith`, `$contains`
  google.protobuf.Struct filter = 1;
  //Sort object in the following format:
  //`[{"fieldName":"sortField1","order":"ASC"},{"fieldName":"sortField2","order":"DESC"}]`
  repeated wix.common.Sorting sort = 2;
  //Array of projected fields. A list of specific field names to return. If `fieldsets` are also specified, the union of `fieldsets` and `fields` is returned.
  repeated string fields = 4;
  //Array of named, predefined sets of projected fields. A array of predefined named sets of fields to be returned. Specifying multiple `fieldsets` will return the union of fields from all sets. If `fields` are also specified, the union of `fieldsets` and `fields` is returned.
  repeated string fieldsets = 5;
  oneof pagingMethod {
    //Paging options to limit and skip the number of items.
    wix.common.Paging paging = 3;
    //Cursor token pointing to a page of results. Not used in the first request. Following requests use the cursor token and not `filter` or `sort`.
    wix.common.CursorPaging cursor_paging = 6;
  }
}

message CursorQuery {
  option (.wix.api.decomposite_of) = "wix.common.CursorQuery";
  //Filter object in the following format:
  //`"filter" : {
  //              "fieldName1": "value1",
  //              "fieldName2":{"$operator":"value2"}
  //  }`
  //Example of operators: `$eq`, `$ne`, `$lt`, `$lte`, `$gt`, `$gte`, `$in`, `$hasSome`, `$hasAll`, `$startsWith`, `$contains`
  google.protobuf.Struct filter = 1;
  //Sort object in the following format:
  //`[{"fieldName":"sortField1","order":"ASC"},{"fieldName":"sortField2","order":"DESC"}]`
  repeated wix.common.Sorting sort = 2;
  reserved 3;
  reserved 4;
  reserved 5;
  oneof pagingMethod {
    //Cursor token pointing to a page of results. Not used in the first request. Following requests use the cursor token and not `filter` or `sort`.
    wix.common.CursorPaging cursor_paging = 6;
  }
}

message Search {
  option (.wix.api.decomposite_of) = "wix.common.Search";
  option (.wix.api.decomposition_minimum_fields) = {
    field: "filter"
    field: "sort"
    field: "paging"
  };
  option (.wix.api.decomposition_minimum_fields) = {
    field: "filter"
    field: "sort"
    field: "cursor_paging"
  };
  //A filter object. See documentation [here](https://bo.wix.com/wix-docs/rnd/platformization-guidelines/api-query-language#platformization-guidelines_api-query-language_defining-in-protobuf)
  google.protobuf.Struct filter = 1;
  //Sort object in the form [{"fieldName":"sortField1"},{"fieldName":"sortField2","direction":"DESC"}]
  repeated wix.common.Sorting sort = 2;
  //Projection on the result object - list of specific field names to return. If fieldsets are also specified, return the union of fieldsets and fields
  repeated string fields = 3;
  //Projection on the result object - list of named projections. E.g. "basic" will return id and name fields. Specifying multiple fieldsets will return the union of fields from all. Specifying fieldsets and fields will also return the union of fields.
  repeated string fieldsets = 4;
  //Aggregations | Faceted search: refers to a way to explore large amounts of data by displaying summaries about various partitions of the data and later allowing to narrow the navigation to a specific partition.
  repeated Aggregation aggregations = 5;
  //free text to match in searchable fields
  SearchDetails search = 6;
  oneof paging_method {
    //Pointer to page of results using offset. Can not be used together with 'cursor_paging'
    wix.common.Paging paging = 7;
    //Cursor pointing to page of results. Can't be used together with 'paging'. 'cursor_paging.cursor' can not be used together with 'filter' or 'sort'
    wix.common.CursorPaging cursor_paging = 8;
  }
}

message CursorSearch {
  option (.wix.api.decomposite_of) = "wix.common.CursorSearch";
  //A filter object. See documentation [here](https://bo.wix.com/wix-docs/rnd/platformization-guidelines/api-query-language#platformization-guidelines_api-query-language_defining-in-protobuf)
  google.protobuf.Struct filter = 1;
  //Sort object in the form [{"fieldName":"sortField1"},{"fieldName":"sortField2","direction":"DESC"}]
  repeated wix.common.Sorting sort = 2;
  reserved 3;
  reserved 4;
  reserved 7;
  //Aggregations | Faceted search: refers to a way to explore large amounts of data by displaying summaries about various partitions of the data and later allowing to narrow the navigation to a specific partition.
  repeated Aggregation aggregations = 5;
  //free text to match in searchable fields
  SearchDetails search = 6;
  oneof paging_method {
    //Cursor pointing to page of results. Can't be used together with 'paging'. 'cursor_paging.cursor' can not be used together with 'filter' or 'sort'
    wix.common.CursorPaging cursor_paging = 8;
  }
}

message SearchDetails {
  option (.wix.api.decomposite_of) = "wix.common.SearchDetails";
  enum Mode {
    OR = 0; // any
    AND = 1; // all
  }
  Mode mode = 1; // boolean search mode
  google.protobuf.StringValue expression = 2; // search term or expression
  repeated string fields = 3; // fields to search in. if empty - server will search in own default fields
  bool fuzzy = 4; // flag if should use auto fuzzy search (allowing typos by a managed proximity algorithm)
}

enum AggregationType {
  UNKNOWN_AGGREGATION_TYPE = 0;
  VALUE = 1;
  RANGE = 2;
  SCALAR = 3;
}

enum ScalarType {
  UNKNOWN_SCALAR_TYPE = 0;
  COUNT_DISTINCT = 1;
  MIN = 2;
  MAX = 3;
  SUM = 4 [(.wix.api.enum_exposure) = PRIVATE];
  AVG = 5 [(.wix.api.enum_exposure) = PRIVATE];
}

message Aggregation {
  option (.wix.api.decomposite_of) = "wix.common.Aggregation";
  message RangeAggregation {
    option (.wix.api.decomposite_of) = "wix.common.Aggregation.RangeAggregation";
    message RangeBucket {
      option (.wix.api.decomposite_of) = "wix.common.Aggregation.RangeAggregation.RangeBucket";
      google.protobuf.Int32Value from = 1; // Inclusive lower bound of the range. Required if to is not given.
      google.protobuf.Int32Value to = 2; // Exclusive upper bound of the range. Required if from is not given.
    }
    repeated RangeBucket buckets = 1;
  }

  message ValueAggregation {
    option (.wix.api.decomposite_of) = "wix.common.Aggregation.ValueAggregation";
    enum SortType {
      COUNT = 0;
      VALUE = 1;
    }
    enum SortDirection {
      DESC = 0;
      ASC = 1;
    }
    SortType sort_type = 1;
    SortDirection sort_direction = 2;
    google.protobuf.Int32Value limit = 3; // How many aggregations would you like to return? Can be between 1 and 250. 10 is the default.
  }

  message ScalarAggregation {
    option (.wix.api.decomposite_of) = "wix.common.ScalarAggregation";
    ScalarType type = 1;
  }

  google.protobuf.StringValue name = 1;
  AggregationType type = 2;
  string field_path = 3;
  oneof kind {
    ValueAggregation value = 4;
    RangeAggregation range = 5;
    ScalarAggregation scalar = 6;
  }
}

message AggregationData {
  option (.wix.api.decomposite_of) = "wix.common.AggregationData";
  message AggregationResults {
    option (.wix.api.decomposite_of) = "wix.common.AggregationData.AggregationResults";
    message ValueResults {
      option (.wix.api.decomposite_of) = "wix.common.AggregationData.AggregationResults.ValueResults";
      message ValueAggregationResult {
        option (.wix.api.decomposite_of) = "wix.common.AggregationData.AggregationResults.ValueResults.ValueAggregationResult";
        string value = 1;
        int32 count = 2;
      }
      repeated ValueAggregationResult results = 1;
    }

    message RangeResults {
      option (.wix.api.decomposite_of) = "wix.common.AggregationData.AggregationResults.RangeResults";
      message RangeAggregationResult {
        option (.wix.api.decomposite_of) = "wix.common.AggregationData.AggregationResults.RangeResults.RangeAggregationResult";
        google.protobuf.Int32Value from = 1;
        google.protobuf.Int32Value to = 2;
        int32 count = 3;
      }
      repeated RangeAggregationResult results = 1;
    }

    message ScalarResult {
      option (.wix.api.decomposite_of) = "wix.common.AggregationData.AggregationResults.ScalarResult";
      ScalarType type = 1;
      double value = 2;
    }

    string name = 1;
    AggregationType type = 2;
    oneof result {
      ValueResults values = 3;
      RangeResults ranges = 4;
      ScalarResult scalar = 5;
    }
  }

  repeated AggregationResults results = 1; // key = aggregation name (as derived from search request)
}

/*
// Usage example in response composition:
message ProductSearchResponse {
    option (.wix.api.decomposite_of) = "wix.common.ProductSearchResponse";
    AggregationData aggregations = 1;
    PagingMetadataV2 metadata = 2;
    repeated Product products = 3;
}

// example Value type Request:
{
    search: {
        expression: "term"
    },
    aggregations: [
        {
            name: "my-value-aggregation",
            type: "VALUE",
            fieldPath: "path.to.field",
            value: {
                sort_type: "VALUE",
                sort_direction: "DESC",
                limit: 15
            }
        }
    ]
}

// example Value type Response:
{
    aggregations: {
        results: [
            {
                name: "my-value-aggregation",
                type: "VALUE",
                values: {
                    results: [
                        {
                            value: "v1",
                            count: 9
                        },
                        {
                            value: "v2",
                            count: 6
                        }
                    ]
                }
            }
        ]
    },
    metadata: {
      items: 25,
      offset: 25,
      total: 420,
      tooManyToCount: false,
      cursors: {
        next: "SOMEHASHFORNEXT",
        prev: "SOMEHASHFORPREV"
      }
    },
    products: [...]
}

// example Range type Request:
{
    search: {
        expression: "term"
    },
    aggregations: [
        {
            name: "my-range-aggregation",
            type: "RANGE",
            fieldPath: "path.to.field",
            range: {
                buckets: [
                    {
                        to: 10
                    },
                    {
                        from: 10,
                        to: 20
                    },
                    {
                        from: 20
                    }
                ]
            }
        }
    ]
}

// example Range type Response:
{
    aggregations: {
        results: [
            {
                name: "my-range-aggregation",
                type: "RANGE",
                ranges: {
                    results: [
                        {
                            to: 10,
                            count: 5
                        },
                        {
                            from: 10,
                            to: 20,
                            count: 3
                        },
                        {
                            from: 20,
                            count: 1
                        }
                    ]
                }
            }
        ]
    },
    metadata: {
        items: 25,
        offset: 25,
        total: 420,
        tooManyToCount: false,
        cursors: {
          next: "SOMEHASHFORNEXT",
          prev: "SOMEHASHFORPREV"
        }
      },
      products: [...]
}

// example Scalar type Request:
{
    search: {
        expression: "term"
    },
    aggregations: [
        {
            name: "my-scalar-aggregation",
            type: "SCALAR",
            fieldPath: "path.to.field",
            scalar: {
                type: "AVG"
            }
        }
    ]
}

// example Scalar type Response:
{
    aggregations: {
        results: [
            {
                name: "my-scalar-agregation",
                type: "SCALAR",
                scalar: {
                    type: "AVG",
                    value: 5.555
                }
            }
        ]
    },
    metadata: {
        items: 25,
        offset: 25,
        total: 420,
        tooManyToCount: false,
        cursors: {
          next: "SOMEHASHFORNEXT",
          prev: "SOMEHASHFORPREV"
        }
      },
      products: [...]
}
*/