syntax = "proto3";

package wix.common;

import "google/protobuf/struct.proto";
import "google/protobuf/wrappers.proto";
import "wix/common/paging.proto";
import "wix/common/sorting.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.common";

message 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 Sorting sort = 2;
    //Paging options to limit and skip the number of items.
    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.decomposition_minimum_fields) = {
        field: "filter"
        field: "sort"
        field: "paging"
    };
    option (.wix.api.decomposition_minimum_fields) = {
        field: "filter"
        field: "sort"
        field: "cursor_paging"
    };
    // Filter object.
    //
    //  Learn more about [filtering](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#filters).
    google.protobuf.Struct filter = 1;
    // Sort object.
    //
    // Learn more about [sorting](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#sorting).
    repeated 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 offset the number of items.
        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`.
        CursorPaging cursor_paging = 6;
    }
}

message CursorQuery {
    option (.wix.api.decomposite_of) = "wix.common.QueryV2";
    // Filter object.
    //
    // Learn more about [filtering](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#filters).
    google.protobuf.Struct filter = 1;
     // Sort object.
     //
     // Learn more about [sorting](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#sorting).
    repeated Sorting sort = 2 [(.wix.api.maxSize) = 5];
    reserved 3;
    reserved 4;
    reserved 5;
    oneof pagingMethod { 
        // Cursor paging options.
        //
        // Learn more about [cursor paging](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#cursor-paging).
        CursorPaging cursor_paging = 6;
    }
}

message 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"
    };
    // Filter object.
    //
    // Learn more about [filtering](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#filters).
    google.protobuf.Struct filter = 1;
     // Sort object.
     //
     // Learn more about [sorting](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#sorting).
    repeated Sorting sort = 2 [(.wix.api.maxSize) = 10];
    // 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 = 3 [(.wix.api.maxLength) = 200, (.wix.api.maxSize) = 20];
    // 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 = 4 [(.wix.api.maxLength) = 100, (.wix.api.maxSize) = 20];
    // Logical groupings of data into facets, with summaries for each facet. For example, use aggregations to allow site visitors to narrow down their search results by selecting specific categories.
    repeated Aggregation aggregations = 5 [(.wix.api.maxSize) = 10];
    // Free text to match in searchable fields.
    SearchDetails search = 6;
    oneof paging_method {
        // Paging options to limit and offset the number of items.
        Paging paging = 7;
        // 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.
        CursorPaging cursor_paging = 8;
    }
    // Time zone to adjust date-time-based filters and aggregations, in ISO 8601 (including offsets) or IANA time zone database (including time zone IDs) format.
    // Applies to all relevant filters and aggregations, unless overridden by providing timestamps including time zone. For example, "2023-12-20T10:52:34.795Z".
    google.protobuf.StringValue time_zone = 9 [(.wix.api.maxLength) = 50];
}

message CursorSearch {
    option (.wix.api.decomposite_of) = "wix.common.Search";
    // Filter object.
    //
    // Learn more about [filtering](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#filters).
    google.protobuf.Struct filter = 1;
    // List of sort objects.
    //
    // Learn more about [sorting](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#sorting).
    repeated Sorting sort = 2 [(.wix.api.maxSize) = 10];
    reserved 3;
    reserved 4;
    reserved 7;
    // Logical groupings of data into facets, with summaries for each facet. For example, use aggregations to allow site visitors to narrow down their search results by selecting specific categories.
    repeated Aggregation aggregations = 5 [(.wix.api.maxSize) = 10];
    // Free text to match in searchable fields.
    SearchDetails search = 6;
    oneof paging_method {
        // Cursor paging options.
        //
        // Learn more about [cursor paging](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#cursor-paging).
        CursorPaging cursor_paging = 8;
    }
    // Time zone to adjust date-time-based filters and aggregations, in ISO 8601 (including offsets) or IANA time zone database (including time zone IDs) format.
    // Applies to all relevant filters and aggregations, unless overridden by providing timestamps including time zone. For example, "2023-12-20T10:52:34.795Z".
    google.protobuf.StringValue time_zone = 9 [(.wix.api.maxLength) = 50];
}

message SearchRelated {
    // List of entity IDs to search for related entities.
    repeated string related_to_ids = 1 [(.wix.api.minSize) = 1, (.wix.api.maxSize) = 10, (.wix.api.maxLength) = 50];
    // Search details.
    SearchRelatedDetails search = 2;
    // Filter object.
    //
    // Learn more about [filtering](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#filters).
    google.protobuf.Struct filter = 3;
    // List of sort objects.
    // For example, `[{"fieldName":"sortField1"},{"fieldName":"sortField2","direction":"DESC"}]`.
    // Learn more about [sorting](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#sorting).
    repeated Sorting sort = 4 [(.wix.api.maxSize) = 10];
    // Limit of related items to return.
    google.protobuf.Int32Value limit = 5 [(.wix.api.max) = 100];
}

message SearchRelatedDetails {
    google.protobuf.StringValue expression = 2 [(.wix.api.maxLength) = 100]; // Search term or expression.
    // Fields to search in. If the array is empty, all searchable fields are searched. Use dot notation to specify a JSON path. For example, `order.address.streetName`.
    repeated string fields = 3 [(.wix.api.maxLength) = 200, (.wix.api.maxSize) = 20];
}

message SearchSuggest {
    SearchSuggestDetails suggest = 1; // Suggest details.
    repeated Sorting sort = 2 [(.wix.api.maxSize) = 10]; // Sorting of suggested documents.
    google.protobuf.Struct filter = 3; // Filter in platformized query language (for example) {'field': {'$eq': 'value'}}.
    google.protobuf.Int32Value limit = 4 [(.wix.api.max) = 100]; // Limit of suggested documents to return, defaults to 10.
}

message SearchSuggestDetails {
    // Search query to suggest for.
    string expression = 1 [(.wix.api.minLength) = 1, (.wix.api.maxLength) = 100];
    // Fields to search in. If empty - will search in all searchable fields. Use dot notation to specify json path.
    repeated string fields = 2 [(.wix.api.maxLength) = 200, (.wix.api.maxSize) = 20];
}

message SearchDetails {
    enum Mode {
        OR = 0; // At least one of the search terms must be present.
        AND = 1; // All search terms must be present.
    }
    Mode mode = 1; // Search mode. Defines the search logic for combining multiple terms in the `expression`.
    google.protobuf.StringValue expression = 2 [(.wix.api.maxLength) = 100]; // Search term or expression.
    // Fields to search in. If the array is empty, all searchable fields are searched. Use dot notation to specify a JSON path. For example, `order.address.streetName`.
    repeated string fields = 3 [(.wix.api.maxLength) = 200, (.wix.api.maxSize) = 20];
    /* 
   Whether to enable the search function to use an algorithm to automatically find results that are close to the search expression, such as typos and declensions.
    */ 
    bool fuzzy = 4;
}

enum AggregationType {
    UNKNOWN_AGGREGATION_TYPE = 0 [(.wix.api.enum_maturity) = NOT_IMPLEMENTED];
    VALUE = 1; // Calculates the distribution of a specific field's values within a dataset, providing insights into the overall distribution and key statistics of those values. 
    RANGE = 2; // Calculates the count of the values from the specified field in the dataset that fall within the range of each bucket you define.
    SCALAR = 3; // Calculates a single numerical value from a dataset, summarizing the dataset into one key metric: `COUNT_DISTINCT`, `SUM`, `AVG`, `MIN`, or `MAX`. 
    DATE_HISTOGRAM = 4; // Calculates the count of time values from the specified field in the dataset that fall within each time interval you define (hour, day, week, etc.).
    NESTED = 5; // Flattened list of aggregations, where each aggregation is nested within previous one.
}

enum ScalarType {
    UNKNOWN_SCALAR_TYPE = 0 [(.wix.api.enum_maturity) = NOT_IMPLEMENTED];
    COUNT_DISTINCT = 1; // Total number of distinct values.
    MIN = 2; // Minimum value.
    MAX = 3; // Maximum value.
    SUM = 4 [(.wix.api.enum_exposure) = PRIVATE]; // Sum of values.
    AVG = 5 [(.wix.api.enum_exposure) = PRIVATE]; // Average of values.
}

message Aggregation {
    message RangeAggregation {
        message RangeBucket {
            google.protobuf.DoubleValue from = 1; // Inclusive lower bound of the range. Required if `to` is not provided.
            google.protobuf.DoubleValue to = 2; // Exclusive upper bound of the range. Required if `from` is not provided.
        }
        // List of range buckets. During aggregation each entity is placed in the first bucket its value falls into, based on the provided range bounds.
        repeated RangeBucket buckets = 1 [(.wix.api.maxSize) = 50];
    }

    message ValueAggregation {
        enum SortType {
            COUNT = 0; // Number of matches in the results.
            VALUE = 1; // Alphabetically by the field value.
        }
        enum SortDirection {
            DESC = 0; // Descending order.
            ASC = 1; // Ascending order.
        }

        enum MissingValues {
            EXCLUDE = 0; // Exclude missing values from the aggregation results.
            INCLUDE = 1; // Include missing values in the aggregation results.
        }

        message IncludeMissingValuesOptions {
            string add_to_bucket = 1 [(.wix.api.maxLength) = 20]; // Specify a custom name for the bucket containing the missing values. Defaults are `"N/A"` for strings, `0` for integers, and `false` for booleans.
        }

        SortType sort_type = 1; // Sort type.
        SortDirection sort_direction = 2; // Sort direction.
        // Number of aggregation results to return.
        // Min: `1`
        // Max: `250`
        // Default: `10`
        google.protobuf.Int32Value limit = 3; 

        /*
        Whether to include or exclude missing values in the aggregation results. 
        Default: `EXCLUDE`.
        */
        MissingValues missing_values = 4; 
        oneof options {
            option (.wix.api.aligned_with_enum).field = "missing_values";
            IncludeMissingValuesOptions include_options = 5; // Options for including missing values in results.
        }
    }

    message ScalarAggregation {
        ScalarType type = 1; // Operator type for the scalar aggregation.
    }

    message GroupByAggregation {
        google.protobuf.StringValue name = 1 [(.wix.api.maxLength) = 100]; // Unique, caller-defined aggregation name, returned in `aggregations.results`.
        string field_path = 3 [(.wix.api.maxLength) = 200]; // Field to aggregate by.
        oneof kind {
            ValueAggregation value = 4; // Value aggregation configuration.
        }
    }

    // Nested aggregation expressed through a list of aggregation where each next aggregation is nested within previous one.
    message NestedAggregation {
        reserved 1;

        enum NestedAggregationType {
            UNKNOWN_AGGREGATION_TYPE = 0 [(.wix.api.enum_maturity) = NOT_IMPLEMENTED];
            VALUE = 1; //  Calculates the distribution of a specific field's values within a dataset, providing insights into the overall distribution and key statistics of those values. 
            RANGE = 2; // Calculates the count of the values from the specified field in the dataset that fall within the range of each bucket you define.
            SCALAR = 3; // Calculates a single numerical value from a dataset, summarizing the dataset into one key metric: `COUNT_DISTINCT`, `SUM`, `AVG`, `MIN`, or `MAX`. 
            DATE_HISTOGRAM = 4; // Calculates the count of time values from the specified field in the dataset that fall within each time interval you define (hour, day, week, etc.).
        }

        message NestedAggregationItem {
            google.protobuf.StringValue name = 1 [(.wix.api.maxLength) = 100]; // Unique, caller-defined aggregation name, returned in `aggregations.results`.
            NestedAggregationType type = 2; // Type of aggregation to perform. The matching aggregation field must be passed.
            string field_path = 3 [(.wix.api.maxLength) = 200]; // Field to aggregate by. Use dot notation to specify a JSON path. For example, `order.address.streetName`.
            oneof kind {
                ValueAggregation value = 4; // A value aggregation calculates the distribution of a specific field's values within a dataset, providing insights into the overall distribution and key statistics of those values. For example, use a value aggregation to get the number (count) of orders for each order status.
                RangeAggregation range = 5; // A range aggregation calculates the count of the values from the specified field in the dataset that fall within the range of each bucket you define. For example, use a range aggregation to compare the number of reservations made for parties of 4 or less to the number of reservations made for parties with 5 or more. If ranges overlap, a record that fits more than one range will only be counted in the first range that matches the criteria.
                ScalarAggregation scalar = 6; // A scalar aggregation calculates a single numerical value from a dataset, summarizing the dataset into one key metric: `COUNT_DISTINCT`, `SUM`, `AVG`, `MIN`, or `MAX`. 
                DateHistogramAggregation date_histogram = 9; // A date histogram calculates the count of time values from the specified field in the dataset that fall within each time interval you define (hour, day, week, etc.). For example, use a date histogram to determine how many reservations have been made at a restaurant each week. If ranges overlap, a record that fits more than one range will only be counted in the first range that matches the criteria.
            }
        }

        // Flattened list of aggregations, where each aggregation is nested within previous one.
        repeated NestedAggregationItem nested_aggregations = 2 [(.wix.api.minSize) = 2, (.wix.api.maxSize) = 3];
    }

    message DateHistogramAggregation {
        enum Interval {
            UNKNOWN_INTERVAL = 0 [(.wix.api.enum_maturity) = NOT_IMPLEMENTED];
            YEAR = 1; 
            MONTH = 2; 
            WEEK = 3; 
            DAY = 4; 
            HOUR = 5; 
            MINUTE = 6; 
            SECOND = 7; 
        }

        Interval interval = 1; // Interval for date histogram aggregation.
    }

    google.protobuf.StringValue name = 1 [(.wix.api.maxLength) = 100]; // Aggregation name, returned in `aggregations.results.name`.
    AggregationType type = 2; // Type of aggregation to perform. Must align with the corresponding aggregation field.
    string field_path = 3 [(.wix.api.maxLength) = 200]; // Field to aggregate by. Use dot notation to specify a JSON path. For example, `order.address.streetName`.
    oneof kind {
        ValueAggregation value = 4; // A value aggregation calculates metrics such as count for specific fields within a dataset, providing insights into the overall distribution and key statistics of those values. For example, use a value aggregation to get the number (count) of products for each price listed in the store.
        RangeAggregation range = 5; // A range aggregation calculates the count of the values from the specified field in the dataset that fall within the range of each bucket you define. For example, use a range aggregation to compare the number of reservations made for parties of 4 or less to the number of reservations made for parties with 5 or more.
        ScalarAggregation scalar = 6; // A scalar aggregation calculates a single numerical value from a dataset, summarizing the dataset into one key metric: `COUNT_DISTINCT`, `SUM`, `AVG`, `MIN`, or `MAX`. 
        DateHistogramAggregation date_histogram = 9; // A date histogram calculates the count of time values from the specified field in the dataset that fall within each time interval you define (hour, day, week, etc.) For example, use a date histogram to find how many reservations have been made at a restaurant each week.
        NestedAggregation nested = 8; // A nested aggregation is applied within the results of another aggregation. Rather than aggregating directly on the primary dataset, first group data using one aggregation and then apply another aggregation within each group. It allows for more complex analyses where you can summarize data at different levels of detail or hierarchy. For example, to get the number of products that are in stock and out of stock for each price listed, first perform a value aggregation on `discountedPriceNumeric`, and a second value aggregation on `inStock`.
    }

    // Deprecated. Use `nested` instead.
    GroupByAggregation group_by = 7 [deprecated = true, (.wix.api.field_deprecated) = {replaced_by: "kind.nested", target_removal_date: "2024-03-30"}];
}

message AggregationData {
    message AggregationResults {
        message ValueResults {
            message ValueAggregationResult {
                string value = 1 [(.wix.api.maxLength) = 100]; // Value of the field.
                int32 count = 2; // Number of entities with this value.
            }
            repeated ValueAggregationResult results = 1 [(.wix.api.maxSize) = 250]; // List of value aggregations.
        }

        message RangeResults {
            message RangeAggregationResult {
                google.protobuf.DoubleValue from = 1; // Inclusive lower bound of the range.
                google.protobuf.DoubleValue to = 2; // Exclusive upper bound of the range.
                int32 count = 3; // Total number of entities in this range.
            }
            repeated RangeAggregationResult results = 1 [(.wix.api.maxSize) = 50]; // List of ranges returned in the same order as requested.
        }

        message ScalarResult {
            ScalarType type = 1; // Type of scalar aggregation.
            double value = 2; // Value of the scalar aggregation.
        }

        message ScalarDateResult {
            ScalarType type = 1; // Type of scalar date aggregation. Possible values: `MIN`, `MAX`.
            string value = 2 [(.wix.api.maxLength) = 100]; // Date in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format.
        }

        message GroupByValueResults {
            message NestedValueAggregationResult {
                string value = 1 [(.wix.api.maxLength) = 1000]; // Value of the field.
                NestedAggregationResults nested_results = 2; // Nested aggregations.

            }
            repeated NestedValueAggregationResult results = 1 [(.wix.api.maxSize) = 1000]; // List of value aggregations.
        }

        message NestedAggregationResults {
            string name = 1 [(.wix.api.maxLength) = 100]; // Unique, caller-defined aggregation name, identifiable by the requested aggregation `name`.
            AggregationType type = 2; // Aggregation type. 
            string field_path = 6 [(.wix.api.maxLength) = 200]; // Field which the data was aggregated by.
            oneof result {
                ValueResults values = 3; // Value aggregation results.
                RangeResults ranges = 4; // Range aggregation results.
                ScalarResult scalar = 5; // Scalar aggregation results.
            }
        }

        // Results of `NESTED` aggregation type in a flattened array, identifiable by the requested aggregation `name`.
        message NestedResults {
            message ValueResult {
                string value = 1 [(.wix.api.maxLength) = 1000]; // Value of the field.
                google.protobuf.Int32Value count = 2; // Number of entities with this value.
            }
            message RangeResult {
                google.protobuf.DoubleValue from = 1; // Inclusive lower bound of the range.
                google.protobuf.DoubleValue to = 2; // Exclusive upper bound of the range.
                google.protobuf.Int32Value count = 3; // Number of entities in this range.
            }

            message ScalarResult {
                double value = 1; // Value of the scalar aggregation.
            }

            message ScalarDateResult {
                string value = 1 [(.wix.api.maxLength) = 100]; // Date in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format.
            }

            message NestedResultValue {
                oneof result {
                    ValueResult value = 1; // Value aggregation result.
                    RangeResult range = 2; // Range aggregation result.
                    ScalarResult scalar = 3; // Scalar aggregation result.
                    ValueResult date_histogram = 4; // Date histogram aggregation result.
                    ScalarDateResult scalar_date = 5; // Scalar date aggregation result.
                }
            }

            message Results {
                map<string, NestedResultValue> results = 1; // List of nested aggregations.
            }

            repeated Results results = 1 [(.wix.api.maxSize) = 1000]; // List of nested aggregations.
        }

        message DateHistogramResults {
            message DateHistogramResult {
                string value = 1 [(.wix.api.maxLength) = 100]; // Date in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format.
                int32 count = 2; // Number of entities in the bucket.
            }
            repeated DateHistogramResult results = 1 [(.wix.api.maxSize) = 200]; // List of date histogram aggregations.
        }

        string name = 1 [(.wix.api.maxLength) = 100]; // Aggregation name, returned in `aggregations.results.name`.
        AggregationType type = 2; // Aggregation type. Must align with the corresponding aggregation field.
        string field_path = 6 [(.wix.api.maxLength) = 200]; // Field to aggregate by. Use dot notation to specify a JSON path. For example, `order.address.streetName`.
        oneof result {
            ValueResults values = 3; // Value aggregation results.
            RangeResults ranges = 4; // Range aggregation results.
            ScalarResult scalar = 5; // Scalar aggregation results.
            GroupByValueResults grouped_by_value = 7; // Group by value aggregation results.
            DateHistogramResults date_histogram = 8; // Date histogram aggregation results.
            NestedResults nested = 9; // Nested aggregation results.
            ScalarDateResult scalar_date = 10; // Date aggregation results.
        }
    }

    repeated AggregationResults results = 1 [(.wix.api.maxSize) = 10000]; // List of the aggregated data results.
}

/*
// Usage example in response composition:
message 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: [...]
}

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

// example Scalar type Response:
{
    aggregations: {
        results: [
            {
                name: "my-scalar-aggregation-on-date",
                type: "SCALAR",
                field_path: "path.to.date.field",
                scalar_date: {
                    type: "MAX",
                    value: "2019-02-25T00:00:00.000Z"
                }
            }
        ]
    },
    metadata: {
        items: 25,
        offset: 25,
        total: 420,
        tooManyToCount: false,
        cursors: {
          next: "SOMEHASHFORNEXT",
          prev: "SOMEHASHFORPREV"
        }
      },
      products: [...]
}

// example Group By Aggregation Request:
{
  "filter" : {
    "region" : "EU"
  },
  "aggregations" : [ {
    "name" : "production countries",
    "type" : "VALUE",
    "fieldPath" : "production_countries",
    "value" : {
      "limit" : 5
    },
    "groupBy" : {
      "name" : "production companies",
      "fieldPath" : "production_companies",
      "value" : { }
    }
  } ]
}

// example Group By Aggregation Response:
{
  "aggregations" : {
    "results" : [ {
      "name" : "production companies",
      "type" : "VALUE",
      "fieldPath" : "production_companies",
      "groupedByValue" : {
        "results" : [ {
          "value" : "Warner Bros.",
          "nestedResults" : {
            "name" : "production countries",
            "type" : "VALUE",
            "fieldPath" : "production_countries",
            "values" : {
              "results" : [ {
                "value" : "GB",
                "count" : 221
              }, {
                "value" : "PL",
                "count" : 12
              } ]
            }
          }
        }, {
          "value" : "Metro-Goldwyn-Mayer (MGM)",
          "nestedResults" : {
            "name" : "production countries",
            "type" : "VALUE",
            "fieldPath" : "production_countries",
            "values" : {
              "results" : [ {
                "value" : "SWE",
                "count" : 24
              }, {
                "value" : "FR",
                "count" : 18
              }, {
                "value" : "LT",
                "count" : 2
              } ]
            }
          }
        } ]
      }
    } ]
  }
}

// example of 2-level nested aggregation request:
{
  "filter" : {
    "region" : "EU"
  },
  "aggregations" : [ {
    "name" : "my nested",
    "type" : "NESTED",
    "nested" : {
      "nestedAggregations" : [ {
        "name" : "daily",
        "type" : "DATE_HISTOGRAM",
        "fieldPath" : "date_updated",
        "dateHistogram" : {
          "interval" : "DAY"
        }
      }, {
        "name" : "inventory status",
        "type" : "VALUE",
        "fieldPath" : "status",
        "value" : { }
      }, {
        "name" : "sum",
        "type" : "SCALAR",
        "fieldPath" : "price",
        "scalar" : {
          "type" : "SUM"
        }
      } ]
    }
  } ]
}

// example of 2-level nested aggregation response:
{
  "aggregations" : {
    "results" : [ {
      "name" : "my nested",
      "type" : "NESTED",
      "fieldPath" : "DUNNO WHAT TO DO WITH THIS",
      "nested" : {
        "results" : [ {
          "results" : {
            "daily" : {
              "dateHistogram" : {
                "value" : "2023.1.1"
              }
            },
            "inventory status" : {
              "value" : {
                "value" : "SOLD",
                "count" : 12
              }
            },
            "sum" : {
              "scalar" : {
                "value" : 10.0
              }
            }
          }
        }, {
          "results" : {
            "daily" : {
              "dateHistogram" : {
                "value" : "2023.1.1"
              }
            },
            "inventory status" : {
              "value" : {
                "value" : "NOT-SOLD",
                "count" : 13
              }
            },
            "sum" : {
              "scalar" : {
                "value" : 5.0
              }
            }
          }
        }, {
          "results" : {
            "daily" : {
              "dateHistogram" : {
                "value" : "2023.1.2"
              }
            },
            "inventory status" : {
              "value" : {
                "value" : "SOLD",
                "count" : 5
              }
            },
            "sum" : {
              "scalar" : {
                "value" : 10.0
              }
            }
          }
        }, {
          "results" : {
            "daily" : {
              "dateHistogram" : {
                "value" : "2023.1.2"
              }
            },
            "inventory status" : {
              "value" : {
                "value" : "NOT-SOLD",
                "count" : 7
              }
            },
            "sum" : {
              "scalar" : {
                "value" : 10.0
              }
            }
          }
        } ]
      }
    } ]
  }
}

*/
