# generated by datamodel-codegen:
#   filename:  VizQLDataServiceOpenAPISchema.json
#   timestamp: 2025-12-18T02:19:52+00:00

from __future__ import annotations

from datetime import date
from enum import Enum
from typing import Annotated, Any, Dict, List, Literal, Optional, Union

from .tableau_model import TableauModel
from pydantic import AwareDatetime, Field as PydanticField, RootModel


class TableauError(TableauModel):
    errorCode: Optional[str] = None
    message: Optional[str] = None
    messages: Optional[List[Any]] = None
    datetime: Optional[AwareDatetime] = None
    debug: Optional[Dict[str, Any]] = None
    tab_error_code: Annotated[Optional[str], PydanticField(alias='tab-error-code')] = None


class TableCalcType(Enum):
    CUSTOM = 'CUSTOM'
    NESTED = 'NESTED'
    DIFFERENCE_FROM = 'DIFFERENCE_FROM'
    PERCENT_DIFFERENCE_FROM = 'PERCENT_DIFFERENCE_FROM'
    PERCENT_FROM = 'PERCENT_FROM'
    PERCENT_OF_TOTAL = 'PERCENT_OF_TOTAL'
    RANK = 'RANK'
    PERCENTILE = 'PERCENTILE'
    RUNNING_TOTAL = 'RUNNING_TOTAL'
    MOVING_CALCULATION = 'MOVING_CALCULATION'


class RelativeTo(Enum):
    PREVIOUS = 'PREVIOUS'
    NEXT = 'NEXT'
    FIRST = 'FIRST'
    LAST = 'LAST'


class RankType(Enum):
    COMPETITION = 'COMPETITION'
    MODIFIED_COMPETITION = 'MODIFIED COMPETITION'
    DENSE = 'DENSE'
    UNIQUE = 'UNIQUE'


class TableCalcComputedAggregation(Enum):
    SUM = 'SUM'
    AVG = 'AVG'
    MIN = 'MIN'
    MAX = 'MAX'


class ColumnClass(Enum):
    COLUMN = 'COLUMN'
    BIN = 'BIN'
    GROUP = 'GROUP'
    CALCULATION = 'CALCULATION'
    TABLE_CALCULATION = 'TABLE_CALCULATION'


class DataType(Enum):
    INTEGER = 'INTEGER'
    REAL = 'REAL'
    STRING = 'STRING'
    DATETIME = 'DATETIME'
    BOOLEAN = 'BOOLEAN'
    DATE = 'DATE'
    SPATIAL = 'SPATIAL'
    UNKNOWN = 'UNKNOWN'


class FieldRole(Enum):
    MEASURE = 'MEASURE'
    DIMENSION = 'DIMENSION'
    UNKNOWN = 'UNKNOWN'


class FieldType(Enum):
    CONTINUOUS = 'CONTINUOUS'
    NOMINAL = 'NOMINAL'
    ORDINAL = 'ORDINAL'
    UNKNOWN = 'UNKNOWN'


class ImageRole(Enum):
    URL = 'URL'


class Formatting(TableauModel):
    decimalPlaces: Annotated[
        Optional[str],
        PydanticField(
            description='Number of places after decimal for a real valued field - Optional.'
        ),
    ] = None


class Connection(TableauModel):
    connectionLuid: Optional[str] = None
    connectionUsername: str
    connectionPassword: str


class Datasource(TableauModel):
    datasourceLuid: Annotated[
        str, PydanticField(description='The LUID of the data source to be queried.')
    ]
    connections: Optional[List[Connection]] = None


class FilterType(Enum):
    QUANTITATIVE_DATE = 'QUANTITATIVE_DATE'
    QUANTITATIVE_NUMERICAL = 'QUANTITATIVE_NUMERICAL'
    SET = 'SET'
    MATCH = 'MATCH'
    CONDITION = 'CONDITION'
    DATE = 'DATE'
    TOP = 'TOP'


class DimensionFilterField(TableauModel):
    fieldCaption: Annotated[
        str, PydanticField(description='The caption of the field to filter on.')
    ]


class CalculatedFilterField(TableauModel):
    calculation: Annotated[
        str, PydanticField(description='A Tableau calculation that will be used to filter on.')
    ]


class Function(Enum):
    SUM = 'SUM'
    AVG = 'AVG'
    MEDIAN = 'MEDIAN'
    COUNT = 'COUNT'
    COUNTD = 'COUNTD'
    MIN = 'MIN'
    MAX = 'MAX'
    STDEV = 'STDEV'
    VAR = 'VAR'
    COLLECT = 'COLLECT'
    YEAR = 'YEAR'
    QUARTER = 'QUARTER'
    MONTH = 'MONTH'
    WEEK = 'WEEK'
    DAY = 'DAY'
    TRUNC_YEAR = 'TRUNC_YEAR'
    TRUNC_QUARTER = 'TRUNC_QUARTER'
    TRUNC_MONTH = 'TRUNC_MONTH'
    TRUNC_WEEK = 'TRUNC_WEEK'
    TRUNC_DAY = 'TRUNC_DAY'
    AGG = 'AGG'
    NONE = 'NONE'
    UNSPECIFIED = 'UNSPECIFIED'


class Comparison(Enum):
    field_ = '='
    field__ = '<>'
    field__1 = '<'
    field___1 = '<='
    field__2 = '>'
    field___2 = '>='


class ConditionalFilterCondition(TableauModel):
    fieldCaption: Annotated[
        str, PydanticField(description='A Field that provide the condition for filtering.')
    ]
    function: Function
    comparison: Annotated[Comparison, PydanticField(description='The comparison operator.')]
    value: Annotated[
        Any,
        PydanticField(
            description='The value of the condition. Must be a number or date or date/time string.'
        ),
    ]


class QuantitativeFilterType(Enum):
    RANGE = 'RANGE'
    MIN = 'MIN'
    MAX = 'MAX'
    ONLY_NULL = 'ONLY_NULL'
    ONLY_NON_NULL = 'ONLY_NON_NULL'


class QueryOptions(TableauModel):
    debug: Optional[bool] = False
    bypassMetadataCache: Optional[bool] = False
    interpretFieldCaptionsAsFieldNames: Annotated[
        Optional[bool],
        PydanticField(
            description="When true, user will pass in the Field's fieldName instead of the Field's fieldCaption in every place that fieldCaption appears (in Fields, Filters, and Calculation formulas). See FieldMetadata of the read-metadata endpoint."
        ),
    ] = False
    includeHiddenFields: Annotated[
        Optional[bool],
        PydanticField(
            description='When true, hidden fields will be included in the response of read-metadata endpoint.'
        ),
    ] = False
    includeGroupFormulas: Annotated[
        Optional[bool],
        PydanticField(
            description='When true, group formula information will be included in the response of read-metadata endpoint for fields that have categorical bin data.'
        ),
    ] = False


class Event(Enum):
    METADATA = 'METADATA'


class Data(TableauModel):
    rowCount: Optional[int] = None


class SseMetadataEvent(TableauModel):
    event: Literal['METADATA']
    data: Data


class Event1(Enum):
    DATA = 'DATA'


class SseDataEvent(TableauModel):
    event: Literal['DATA']
    data: List[Any]


class Event2(Enum):
    ERROR = 'ERROR'


class SseErrorEvent(TableauModel):
    event: Literal['ERROR']
    data: TableauError


class QueryOutput(TableauModel):
    data: Optional[List[Any]] = None
    error: Optional[Dict[str, Any]] = None


class ReadMetadataRequest(TableauModel):
    datasource: Datasource
    options: Optional[QueryOptions] = None


class ReturnFormat(Enum):
    OBJECTS = 'OBJECTS'
    ARRAYS = 'ARRAYS'


class SortDirection(Enum):
    ASC = 'ASC'
    DESC = 'DESC'


class PeriodType(Enum):
    MINUTES = 'MINUTES'
    HOURS = 'HOURS'
    DAYS = 'DAYS'
    WEEKS = 'WEEKS'
    MONTHS = 'MONTHS'
    QUARTERS = 'QUARTERS'
    YEARS = 'YEARS'


class DateRangeType(Enum):
    CURRENT = 'CURRENT'
    LAST = 'LAST'
    LASTN = 'LASTN'
    NEXT = 'NEXT'
    NEXTN = 'NEXTN'
    TODATE = 'TODATE'


class Direction(Enum):
    TOP = 'TOP'
    BOTTOM = 'BOTTOM'


class Parameter(TableauModel):
    parameterCaption: Annotated[
        str, PydanticField(description='The caption of the parameter to set.')
    ]
    value: Annotated[
        Any,
        PydanticField(
            description='The value to set for the parameter. The type of the value must match the type of the parameter.'
        ),
    ]


class NullableAny(RootModel[Optional[Any]]):
    root: Optional[Any] = None


class FieldAlias(TableauModel):
    member: Annotated[
        Any, PydanticField(description='The original member value that will be replaced.')
    ]
    value: Annotated[
        Any, PydanticField(description='The alias value to replace the original member with.')
    ]


class AliasedDataValue(TableauModel):
    alias: Annotated[str, PydanticField(description='The alias of the data value.')]
    value: Annotated[Any, PydanticField(description='The data value of the parameter.')]


class ParameterType(Enum):
    ANY_VALUE = 'ANY_VALUE'
    LIST = 'LIST'
    QUANTITATIVE_RANGE = 'QUANTITATIVE_RANGE'
    QUANTITATIVE_DATE = 'QUANTITATIVE_DATE'


class ParameterRecordBase(TableauModel):
    parameterType: ParameterType
    parameterName: Annotated[
        Optional[str],
        PydanticField(
            description='The tableau internal name of the parameter to identify and reference the parameter.'
        ),
    ] = None
    parameterCaption: Annotated[
        str,
        PydanticField(
            description='The user defined name of the parameter to identify and reference the parameter.'
        ),
    ]
    dataType: DataType
    value: Annotated[
        Any,
        PydanticField(
            description='The value to set for the parameter. The type of the value must match the type of the parameter.'
        ),
    ]


class GetDatasourceModelRequest(TableauModel):
    datasource: Datasource
    options: Optional[QueryOptions] = None


class LogicalTable(TableauModel):
    logicalTableId: str
    caption: str
    description: Optional[str] = None


class LogicalTableRelationshipEndpoint(TableauModel):
    logicalTableId: str


class ListSupportedFunctionRequest(TableauModel):
    datasource: Datasource
    options: Optional[QueryOptions] = None


class FunctionType(Enum):
    UNSPECIFIED = 'UNSPECIFIED'
    BOOL = 'BOOL'
    REAL = 'REAL'
    INT = 'INT'
    STR = 'STR'
    DATETIME = 'DATETIME'
    DATE = 'DATE'
    LOCALSTR = 'LOCALSTR'
    NULL = 'NULL'
    ANY = 'ANY'
    BIN = 'BIN'
    TUPLE = 'TUPLE'
    LOCALREAL = 'LOCALREAL'
    LOCALINT = 'LOCALINT'
    SPATIAL = 'SPATIAL'
    TABLE = 'TABLE'
    ERROR = 'ERROR'


class SupportedFunctionOverload(TableauModel):
    arg_types: List[FunctionType]
    return_type: FunctionType


class SupportedFunction(TableauModel):
    name: str
    overloads: List[SupportedFunctionOverload]


class Grouping(TableauModel):
    alias: Annotated[Optional[str], PydanticField(description='The name of the grouping.')] = (
        None
    )
    members: Annotated[
        List[Any],
        PydanticField(
            description='A list of members that belong to this grouping. Members can be of any type.'
        ),
    ]


class Operator(Enum):
    field_ = '='
    field__ = '<>'
    field__1 = '>'
    field__2 = '<'
    field___1 = '>='
    field___2 = '<='


class RelationshipExpressionItem(TableauModel):
    operator: Annotated[
        Operator,
        PydanticField(
            description='The comparison operator used in this relationship (e.g., =, <>, >, <, >=, <=).'
        ),
    ]
    fromField: Annotated[
        str,
        PydanticField(
            description='The field reference from which the relationship originates (e.g., [Order ID]). Field references are typically enclosed in square brackets.'
        ),
    ]
    toField: Annotated[
        str,
        PydanticField(
            description='The field reference to which the relationship targets (e.g., [Order ID (Returns)]). Field references are typically enclosed in square brackets.'
        ),
    ]


class FieldBase(TableauModel):
    fieldCaption: Annotated[
        str,
        PydanticField(
            description='Either the name of a specific Field in the data source, or, in the case of a calculation, a user-supplied name for the calculation.'
        ),
    ]
    fieldAlias: Annotated[
        Optional[str],
        PydanticField(
            description='An alternative name to give the field. Will only be used in object format output.'
        ),
    ] = None
    maxDecimalPlaces: Annotated[
        Optional[int],
        PydanticField(
            description='The maximum number of decimal places. Any trailing 0s will be dropped. The maxDecimalPlaces value must be greater or equal to 0.'
        ),
    ] = None
    sortDirection: Optional[SortDirection] = None
    sortPriority: Annotated[
        Optional[int],
        PydanticField(
            description='To enable sorting on a specific Field, provide a sortPriority for that field, and that field will be sorted. The sortPriority provides a ranking of how to sort fields when multiple fields are being sorted. The highest priority (lowest number) field is sorted first. If only one field is being sorted, then any value may be used for sortPriority. SortPriority should be an integer greater than 0.',
            ge=1,
        ),
    ] = None


class DimensionField(FieldBase):
    fieldCaption: Optional[str] = None
    fieldAlias: Optional[str] = None
    maxDecimalPlaces: Optional[int] = None
    sortDirection: Optional[SortDirection] = None
    sortPriority: Optional[int] = None


class MeasureField(FieldBase):
    function: Function
    fieldCaption: Optional[str] = None
    fieldAlias: Optional[str] = None
    maxDecimalPlaces: Optional[int] = None
    sortDirection: Optional[SortDirection] = None
    sortPriority: Optional[int] = None


class CalculatedField(FieldBase):
    calculation: Annotated[
        str,
        PydanticField(
            description='A Tableau calculation that will be returned as a Field in the query.'
        ),
    ]
    fieldCaption: Optional[str] = None
    fieldAlias: Optional[str] = None
    maxDecimalPlaces: Optional[int] = None
    sortDirection: Optional[SortDirection] = None
    sortPriority: Optional[int] = None


class BinField(FieldBase):
    binSize: Annotated[
        float,
        PydanticField(
            description='The size of the bin to be applied. The binSize value must be greater than 0.',
            ge=1.0,
        ),
    ]
    fieldCaption: Optional[str] = None
    fieldAlias: Optional[str] = None
    maxDecimalPlaces: Optional[int] = None
    sortDirection: Optional[SortDirection] = None
    sortPriority: Optional[int] = None


class TableCalcFieldReference(TableauModel):
    fieldCaption: str
    function: Optional[Function] = None


class TableCalcCustomSort(TableauModel):
    fieldCaption: str
    function: Function
    direction: SortDirection


class MeasureFilterField(TableauModel):
    fieldCaption: Annotated[
        str, PydanticField(description='The caption of the field to filter on.')
    ]
    function: Function


class QueryDatasourceOptions(QueryOptions):
    disaggregate: Optional[bool] = False
    returnFormat: Optional[ReturnFormat] = None
    rowLimit: Annotated[Optional[int], PydanticField(ge=1)] = None
    returnServerSentEvents: Optional[bool] = False


class SseResultStream(RootModel[Union[SseMetadataEvent, SseDataEvent, SseErrorEvent]]):
    root: Annotated[
        Union[SseMetadataEvent, SseDataEvent, SseErrorEvent],
        PydanticField(discriminator='event'),
    ]


class AnyValueParameter(ParameterRecordBase):
    pass


class ListParameter(ParameterRecordBase):
    members: Optional[List[AliasedDataValue]] = None


class QuantitativeRangeParameter(ParameterRecordBase):
    min: Annotated[
        Optional[float],
        PydanticField(
            description='The minimum allowable value for this range parameter. Parameter values must be greater than or equal to this value.'
        ),
    ] = None
    max: Annotated[
        Optional[float],
        PydanticField(
            description='The maximum allowable value for this range parameter. Parameter values must be less than or equal to this value.'
        ),
    ] = None
    step: Annotated[
        Optional[float],
        PydanticField(
            description='The increment step size for values within the numeric range. Defines the granularity of allowed values between min and max.'
        ),
    ] = None


class QuantitativeDateParameter(ParameterRecordBase):
    minDate: Annotated[
        Optional[str],
        PydanticField(
            description='An RFC 3339 date indicating the earliest allowable date for this parameter.'
        ),
    ] = None
    maxDate: Annotated[
        Optional[str],
        PydanticField(
            description='An RFC 3339 date indicating the latest allowable date for this parameter.'
        ),
    ] = None
    periodType: Optional[PeriodType] = None
    periodValue: Annotated[
        Optional[float],
        PydanticField(
            description='The numeric value associated with the period type for date granularity.'
        ),
    ] = None


class GroupFormula(TableauModel):
    baseFieldName: Annotated[
        str, PydanticField(description='The field name of the column the group is on.')
    ]
    groupings: Annotated[
        List[Grouping], PydanticField(description='A list of groupings in the group formula.')
    ]
    hasIncludeOther: Annotated[
        bool,
        PydanticField(
            description='If true, all domain values not specified in a grouping will be grouped together.'
        ),
    ]


class FieldRelationshipExpression(TableauModel):
    op: Annotated[
        Optional[str],
        PydanticField(
            description='The logical operator that combines all relationships (e.g., AND, OR).'
        ),
    ] = None
    relationships: Annotated[
        List[RelationshipExpressionItem],
        PydanticField(
            description='An array of relationship items, each representing a single field-to-field relationship.'
        ),
    ]


class TableCalcSpecification(TableauModel):
    tableCalcType: TableCalcType
    dimensions: List[TableCalcFieldReference]


class CustomTableCalcSpecification(TableCalcSpecification):
    levelAddress: Optional[TableCalcFieldReference] = None
    restartEvery: Optional[TableCalcFieldReference] = None
    customSort: Optional[TableCalcCustomSort] = None
    tableCalcType: Literal['CUSTOM']


class NestedTableCalcSpecification(TableCalcSpecification):
    fieldCaption: str
    levelAddress: Optional[TableCalcFieldReference] = None
    restartEvery: Optional[TableCalcFieldReference] = None
    customSort: Optional[TableCalcCustomSort] = None
    tableCalcType: Literal['NESTED']


class DifferenceTableCalcSpecification(TableCalcSpecification):
    levelAddress: Optional[TableCalcFieldReference] = None
    relativeTo: Optional[RelativeTo] = 'PREVIOUS'
    customSort: Optional[TableCalcCustomSort] = None
    tableCalcType: Literal['DIFFERENCE_FROM', 'PERCENT_DIFFERENCE_FROM', 'PERCENT_FROM']


class PercentOfTotalTableCalcSpecification(TableCalcSpecification):
    levelAddress: Optional[TableCalcFieldReference] = None
    customSort: Optional[TableCalcCustomSort] = None
    tableCalcType: Literal['PERCENT_OF_TOTAL']


class RankTableCalcSpecification(TableCalcSpecification):
    rankType: Optional[RankType] = 'COMPETITION'
    direction: Optional[SortDirection] = None
    tableCalcType: Literal['RANK']


class PercentileTableCalcSpecification(TableCalcSpecification):
    direction: Optional[SortDirection] = None
    tableCalcType: Literal['PERCENTILE']


class FieldMetadata(TableauModel):
    fieldName: Annotated[
        Optional[str],
        PydanticField(description='The underlying database column name for the field.'),
    ] = None
    fieldCaption: Annotated[
        Optional[str], PydanticField(description='The caption of the field saved in the PDS.')
    ] = None
    dataType: Annotated[
        Optional[DataType],
        PydanticField(description='Data type of the column, i.e., "STRING", "BOOLEAN", etc.'),
    ] = None
    fieldRole: Annotated[
        Optional[FieldRole],
        PydanticField(description='Field role of the column, i.e., "MEASURE", "DIMENSION".'),
    ] = None
    fieldType: Annotated[
        Optional[FieldType],
        PydanticField(
            description='Field role of the column, i.e., "CONTINUOUS", "NOMINAL", "ORDINAL".'
        ),
    ] = None
    defaultAggregation: Annotated[
        Optional[Function],
        PydanticField(description='The default aggregation applied to the field.'),
    ] = None
    columnClass: Annotated[
        Optional[ColumnClass],
        PydanticField(description='The type of field, i.e., "COLUMN", "GROUP", BIN" etc.'),
    ] = None
    formula: Annotated[
        Optional[str],
        PydanticField(description='The formula for this field if it is a calculation.'),
    ] = None
    groupFormula: Annotated[
        Optional[GroupFormula],
        PydanticField(
            description='The group formula for this field if it is a group calculation.'
        ),
    ] = None
    logicalTableId: Annotated[
        Optional[str],
        PydanticField(
            description='An internal unique identifier for the logical table that this field originates from.'
        ),
    ] = None
    description: Annotated[
        Optional[str], PydanticField(description='Optional description for the field.')
    ] = None
    imageRole: Annotated[
        Optional[ImageRole], PydanticField(description='Optional image role for this field.')
    ] = None
    hidden: Annotated[
        Optional[bool],
        PydanticField(description='Indicates whether the field is hidden in the data source.'),
    ] = None
    defaultFormatting: Annotated[
        Optional[Formatting],
        PydanticField(description='Describing the default formatting for this field.'),
    ] = None
    isLODCalc: Annotated[
        Optional[bool],
        PydanticField(description='Indicates whether the field is an LOD calculation.'),
    ] = None
    aliases: Annotated[
        Optional[List[FieldAlias]],
        PydanticField(
            description='A list of aliases mapping original member values to alias values.'
        ),
    ] = None


class FilterField(
    RootModel[Union[DimensionFilterField, MeasureFilterField, CalculatedFilterField]]
):
    root: Union[DimensionFilterField, MeasureFilterField, CalculatedFilterField]


class ExtraData(TableauModel):
    parameters: Optional[
        List[
            Union[
                AnyValueParameter,
                ListParameter,
                QuantitativeRangeParameter,
                QuantitativeDateParameter,
            ]
        ]
    ] = None


class MetadataOutput(TableauModel):
    data: Optional[List[FieldMetadata]] = None
    extraData: Optional[ExtraData] = None


class LogicalTableRelationship(TableauModel):
    fromLogicalTable: LogicalTableRelationshipEndpoint
    toLogicalTable: LogicalTableRelationshipEndpoint
    expression: Annotated[
        Optional[FieldRelationshipExpression],
        PydanticField(
            description='The expression associated with the relationship, representing how the tables are related.'
        ),
    ] = None


class Filter(TableauModel):
    field: FilterField
    filterType: FilterType
    context: Annotated[
        Optional[bool],
        PydanticField(
            description="Make the given filter a context filter, meaning that it's an independent filter. Any other filters that you set are defined as dependent filters because they process only the data that passes through the context filter."
        ),
    ] = False


class MatchFilter(Filter):
    filterType: Literal[FilterType.MATCH] = FilterType.MATCH
    contains: Annotated[
        Optional[str], PydanticField(description='Matches when a field contains this value.')
    ] = None
    startsWith: Annotated[
        Optional[str], PydanticField(description='Matches when a field starts with this value.')
    ] = None
    endsWith: Annotated[
        Optional[str], PydanticField(description='Matches when a field ends with this value.')
    ] = None
    exclude: Annotated[
        Optional[bool],
        PydanticField(description='When true, the inverse of the matching logic will be used.'),
    ] = False


class ConditionFilter(Filter):
    filterType: Literal[FilterType.CONDITION] = FilterType.CONDITION
    condition: Optional[ConditionalFilterCondition] = None
    calculation: Annotated[
        Optional[str],
        PydanticField(description='A alternate conditional calculation to filter upon.'),
    ] = None


class QuantitativeFilterBase(Filter):
    quantitativeFilterType: QuantitativeFilterType
    includeNulls: Annotated[
        Optional[bool],
        PydanticField(
            description='Should nulls be returned or not. Only applies to RANGE, MIN, and MAX filters. If not provided, the default is to not include null values.'
        ),
    ] = None


class QuantitativeNumericalFilter(QuantitativeFilterBase):
    filterType: Literal[FilterType.QUANTITATIVE_NUMERICAL] = FilterType.QUANTITATIVE_NUMERICAL
    min: Annotated[
        Optional[float],
        PydanticField(
            description='A numerical value, either integer or floating point, indicating the minimum value to filter upon. Required if using quantitativeFilterType RANGE or if using quantitativeFilterType MIN.'
        ),
    ] = None
    max: Annotated[
        Optional[float],
        PydanticField(
            description='A numerical value, either integer or floating point, indicating the maximum value to filter upon. Required if using quantitativeFilterType RANGE or if using quantitativeFilterType MIN.'
        ),
    ] = None


class QuantitativeDateFilter(QuantitativeFilterBase):
    filterType: Literal[FilterType.QUANTITATIVE_DATE] = FilterType.QUANTITATIVE_DATE
    minDate: Annotated[
        Optional[date],
        PydanticField(
            description='An RFC 3339 date indicating the earliest date to filter upon. Required if using quantitativeFilterType RANGE or if using quantitativeFilterType MIN.'
        ),
    ] = None
    maxDate: Annotated[
        Optional[date],
        PydanticField(
            description='An RFC 3339 date indicating the latest date to filter on. Required if using quantitativeFilterType RANGE or if using quantitativeFilterType MIN.'
        ),
    ] = None


class SetFilter(Filter):
    filterType: Literal[FilterType.SET] = FilterType.SET
    values: Annotated[
        List[NullableAny], PydanticField(description='An array of values to filter on.')
    ]
    exclude: Optional[bool] = False


class RelativeDateFilter(Filter):
    filterType: Literal[FilterType.DATE] = FilterType.DATE
    periodType: PeriodType
    dateRangeType: Annotated[
        DateRangeType, PydanticField(description='The direction in the relative date range.')
    ]
    rangeN: Annotated[
        Optional[int],
        PydanticField(
            description='When dateRangeType is LASTN or NEXTN, this is the N value (how many years, months, etc.).'
        ),
    ] = None
    anchorDate: Annotated[
        Optional[date],
        PydanticField(
            description="If a value for this field isn't provided, the value defaults to today."
        ),
    ] = None
    includeNulls: Annotated[
        Optional[bool],
        PydanticField(
            description="Should nulls be returned or not. If a value isn't provided, the default is to not include null values."
        ),
    ] = None


class TopNFilter(Filter):
    filterType: Literal[FilterType.TOP] = FilterType.TOP
    direction: Annotated[
        Optional[Direction],
        PydanticField(description='Top (ascending) or Bottom (descending) N.'),
    ] = 'TOP'
    howMany: Annotated[
        int,
        PydanticField(
            description='The number of values from the top or the bottom of the given fieldToMeasure.'
        ),
    ]
    fieldToMeasure: FilterField


class DatasourceModelOutput(TableauModel):
    logicalTables: Optional[List[LogicalTable]] = None
    logicalTableRelationships: Optional[List[LogicalTableRelationship]] = None


class TableCalcField(FieldBase):
    function: Optional[Function] = None
    calculation: Optional[str] = None
    tableCalculation: Annotated[
        Union[
            CustomTableCalcSpecification,
            NestedTableCalcSpecification,
            DifferenceTableCalcSpecification,
            PercentOfTotalTableCalcSpecification,
            RankTableCalcSpecification,
            PercentileTableCalcSpecification,
            RunningTotalTableCalcSpecification,
            MovingTableCalcSpecification,
        ],
        PydanticField(discriminator='tableCalcType'),
    ]
    nestedTableCalculations: Optional[
        List[
            Union[
                CustomTableCalcSpecification,
                NestedTableCalcSpecification,
                DifferenceTableCalcSpecification,
                PercentOfTotalTableCalcSpecification,
                RankTableCalcSpecification,
                PercentileTableCalcSpecification,
                RunningTotalTableCalcSpecification,
                MovingTableCalcSpecification,
            ]
        ]
    ] = None
    fieldCaption: Optional[str] = None
    fieldAlias: Optional[str] = None
    maxDecimalPlaces: Optional[int] = None
    sortDirection: Optional[SortDirection] = None
    sortPriority: Optional[int] = None


class RunningTotalTableCalcSpecification(TableCalcSpecification):
    aggregation: Optional[TableCalcComputedAggregation] = 'SUM'
    restartEvery: Optional[TableCalcFieldReference] = None
    customSort: Optional[TableCalcCustomSort] = None
    secondaryTableCalculation: Annotated[
        Optional[
            Union[
                CustomTableCalcSpecification,
                NestedTableCalcSpecification,
                DifferenceTableCalcSpecification,
                PercentOfTotalTableCalcSpecification,
                RankTableCalcSpecification,
                PercentileTableCalcSpecification,
                RunningTotalTableCalcSpecification,
                MovingTableCalcSpecification,
            ]
        ],
        PydanticField(discriminator='tableCalcType'),
    ] = None
    tableCalcType: Literal['RUNNING_TOTAL']


class MovingTableCalcSpecification(TableCalcSpecification):
    aggregation: Optional[TableCalcComputedAggregation] = 'SUM'
    previous: Optional[int] = 2
    next: Optional[int] = 0
    includeCurrent: Optional[bool] = True
    fillInNull: Optional[bool] = False
    customSort: Optional[TableCalcCustomSort] = None
    secondaryTableCalculation: Annotated[
        Optional[
            Union[
                CustomTableCalcSpecification,
                NestedTableCalcSpecification,
                DifferenceTableCalcSpecification,
                PercentOfTotalTableCalcSpecification,
                RankTableCalcSpecification,
                PercentileTableCalcSpecification,
                RunningTotalTableCalcSpecification,
                MovingTableCalcSpecification,
            ]
        ],
        PydanticField(discriminator='tableCalcType'),
    ] = None
    tableCalcType: Literal['MOVING_CALCULATION']


class Query(TableauModel):
    fields: Annotated[
        List[Field], PydanticField(description='An array of fields that define the query.')
    ]
    filters: Annotated[
        Optional[
            List[
                Union[
                    MatchFilter,
                    ConditionFilter,
                    QuantitativeNumericalFilter, QuantitativeDateFilter,
                    SetFilter,
                    RelativeDateFilter,
                    TopNFilter,
                ]
            ]
        ],
        PydanticField(description='An optional array of filters to apply to the query.'),
    ] = None
    parameters: Annotated[
        Optional[List[Parameter]],
        PydanticField(description='An optional array of parameters to apply to the query.'),
    ] = None


class QueryRequest(TableauModel):
    datasource: Datasource
    query: Query
    options: Optional[QueryDatasourceOptions] = None


class Field(
    RootModel[
        Union[DimensionField, MeasureField, CalculatedField, BinField, TableCalcField]
    ]
):
    root: Union[DimensionField, MeasureField, CalculatedField, BinField, TableCalcField]


TableCalcField.model_rebuild()
RunningTotalTableCalcSpecification.model_rebuild()
Query.model_rebuild()

class TabFilter(RootModel[Annotated[Union[
    MatchFilter, QuantitativeNumericalFilter, QuantitativeDateFilter, SetFilter, RelativeDateFilter, TopNFilter, ConditionFilter],
    PydanticField(discriminator='filterType')]]):
    root: Annotated[Union[
        MatchFilter, QuantitativeNumericalFilter, QuantitativeDateFilter, SetFilter, RelativeDateFilter, TopNFilter, ConditionFilter],
        PydanticField(discriminator='filterType')]

class ParameterRecord(RootModel[Union[
    AnyValueParameter, ListParameter, QuantitativeRangeParameter, QuantitativeDateParameter]]):
    root: Union[
        AnyValueParameter, ListParameter, QuantitativeRangeParameter, QuantitativeDateParameter]
