from collections import Counter, OrderedDict
from collections.abc import Callable, Iterable, Iterator, Sequence
from typing import Any, NamedTuple

from django.db.models import Expression, Field, FilteredRelation, Model, Q, QuerySet
from django.db.models.expressions import Combinable
from django.db.models.lookups import Lookup, Transform
from django.db.models.query_utils import PathInfo, RegisterLookupMixin
from django.db.models.sql.compiler import SQLCompiler
from django.db.models.sql.datastructures import BaseTable
from django.db.models.sql.where import WhereNode

class JoinInfo(NamedTuple):
    final_field: Any
    targets: Any
    opts: Any
    joins: Any
    path: Any
    transform_function: Any

class RawQuery:
    high_mark: int | None
    low_mark: int | None
    params: Any = ...
    sql: str = ...
    using: str = ...
    extra_select: dict[Any, Any] = ...
    annotation_select: dict[Any, Any] = ...
    cursor: object = ...
    def __init__(self, sql: str, using: str, params: Any = ...) -> None: ...
    def chain(self, using: str) -> RawQuery: ...
    def clone(self, using: str) -> RawQuery: ...
    def get_columns(self) -> list[str]: ...
    def __iter__(self) -> Any: ...

class Query:
    base_table: str
    related_ids: list[int] | None
    related_updates: dict[type[Model], list[tuple[Field[Any, Any], None, int | str]]]
    values: list[Any]
    alias_prefix: str = ...
    subq_aliases: frozenset[Any] = ...
    compiler: str = ...
    model: type[Model] | None = ...
    alias_refcount: dict[str, int] = ...
    alias_map: dict[str, BaseTable] = ...
    external_aliases: set[str] = ...
    table_map: dict[str, list[str]] = ...
    default_cols: bool = ...
    default_ordering: bool = ...
    standard_ordering: bool = ...
    used_aliases: set[str] = ...
    filter_is_sticky: bool = ...
    subquery: bool = ...
    group_by: Sequence[Combinable] | Sequence[str] | bool | None = ...
    order_by: tuple[Any, ...] = ...
    distinct: bool = ...
    distinct_fields: tuple[Any, ...] = ...
    select_for_update: bool = ...
    select_for_update_nowait: bool = ...
    select_for_update_skip_locked: bool = ...
    select_for_update_of: tuple[Any, ...] = ...
    select_related: dict[str, Any] | bool = ...
    max_depth: int = ...
    values_select: tuple[Any, ...] = ...
    annotation_select_mask: set[str] | None = ...
    combinator: str | None = ...
    combinator_all: bool = ...
    combined_queries: tuple[Any, ...] = ...
    extra_select_mask: set[str] | None = ...
    extra_tables: tuple[Any, ...] = ...
    extra_order_by: list[str] | tuple[Any, ...] = ...
    deferred_loading: tuple[set[str] | frozenset[Any], bool] = ...
    explain_query: bool = ...
    explain_format: str | None = ...
    explain_options: dict[str, int] = ...
    high_mark: int | None = ...
    low_mark: int = ...
    where: WhereNode
    def __init__(
        self, model: type[Model] | None, where: type[WhereNode] = ...
    ) -> None: ...
    @property
    def extra(self) -> OrderedDict[Any, Any]: ...
    @property
    def annotations(self) -> OrderedDict[Any, Any]: ...
    @property
    def has_select_fields(self) -> bool: ...
    def sql_with_params(self) -> tuple[str, tuple[Any, ...]]: ...
    def __deepcopy__(self, memo: dict[str, Any]) -> Query: ...
    def get_compiler(
        self, using: str | None = ..., connection: Any = ...
    ) -> SQLCompiler: ...
    def clone(self) -> Query: ...
    def chain(self, klass: type[Query] | None = ...) -> Query: ...
    def relabeled_clone(
        self, change_map: dict[Any, Any] | OrderedDict[Any, Any]
    ) -> Query: ...
    def get_count(self, using: str) -> int: ...
    def has_filters(self) -> WhereNode: ...
    def has_results(self, using: str) -> bool: ...
    def explain(self, using: str, format: str | None = ..., **options: Any) -> str: ...
    def combine(self, rhs: Query, connector: str) -> None: ...
    def deferred_to_data(
        self, target: dict[Any, Any], callback: Callable[..., Any]
    ) -> None: ...
    def ref_alias(self, alias: str) -> None: ...
    def unref_alias(self, alias: str, amount: int = ...) -> None: ...
    def promote_joins(self, aliases: set[str]) -> None: ...
    def demote_joins(self, aliases: set[str]) -> None: ...
    def reset_refcounts(self, to_counts: dict[str, int]) -> None: ...
    def change_aliases(
        self, change_map: dict[Any, Any] | OrderedDict[Any, Any]
    ) -> None: ...
    def bump_prefix(self, outer_query: Query) -> None: ...
    def get_initial_alias(self) -> str: ...
    def count_active_tables(self) -> int: ...
    def resolve_expression(self, query: Query, *args: Any, **kwargs: Any) -> Query: ...
    def as_sql(self, compiler: SQLCompiler, connection: Any) -> Any: ...
    def resolve_lookup_value(
        self, value: Any, can_reuse: set[str] | None, allow_joins: bool
    ) -> Any: ...
    def solve_lookup_type(
        self, lookup: str
    ) -> tuple[Sequence[str], Sequence[str], bool]: ...
    def build_filter(
        self,
        filter_expr: dict[str, str] | tuple[str, tuple[int, int]],
        branch_negated: bool = ...,
        current_negated: bool = ...,
        can_reuse: set[str] | None = ...,
        allow_joins: bool = ...,
        split_subq: bool = ...,
        reuse_with_filtered_relation: bool = ...,
    ) -> tuple[WhereNode, list[Any]]: ...
    def add_filter(self, filter_clause: tuple[str, list[int] | list[str]]) -> None: ...
    def add_q(self, q_object: Q) -> None: ...
    def build_where(self, q_object: Q) -> Any: ...
    def build_filtered_relation_q(
        self,
        q_object: Q,
        reuse: set[str],
        branch_negated: bool = ...,
        current_negated: bool = ...,
    ) -> WhereNode: ...
    def add_filtered_relation(
        self, filtered_relation: FilteredRelation, alias: str
    ) -> None: ...
    def setup_joins(
        self,
        names: list[str],
        opts: Any,
        alias: str,
        can_reuse: set[str] | None = ...,
        allow_many: bool = ...,
        reuse_with_filtered_relation: bool = ...,
    ) -> JoinInfo: ...
    def trim_joins(
        self, targets: tuple[Field[Any, Any]], joins: list[str], path: list[PathInfo]
    ) -> tuple[tuple[Field[Any, Any]], str, list[str]]: ...
    def resolve_ref(
        self,
        name: str,
        allow_joins: bool = ...,
        reuse: set[str] | None = ...,
        summarize: bool = ...,
    ) -> Expression: ...
    def split_exclude(
        self,
        filter_expr: tuple[str, QuerySet[Any] | int],
        can_reuse: set[str],
        names_with_path: list[tuple[str, list[PathInfo]]],
    ) -> tuple[WhereNode, tuple[Any, ...]]: ...
    def set_empty(self) -> None: ...
    def is_empty(self) -> bool: ...
    def set_limits(self, low: int | None = ..., high: int | None = ...) -> None: ...
    def clear_limits(self) -> None: ...
    def has_limit_one(self) -> bool: ...
    def can_filter(self) -> bool: ...
    def clear_select_clause(self) -> None: ...
    def clear_select_fields(self) -> None: ...
    def set_select(self, cols: list[Expression]) -> None: ...
    def add_distinct_fields(self, *field_names: Any) -> None: ...
    def add_fields(
        self, field_names: Iterator[Any] | list[str], allow_m2m: bool = ...
    ) -> None: ...
    def add_ordering(self, *ordering: Any) -> None: ...
    def clear_ordering(self, force_empty: bool) -> None: ...
    def set_group_by(self) -> None: ...
    def add_select_related(self, fields: Iterable[str]) -> None: ...
    def add_extra(
        self,
        select: dict[str, Any] | None,
        select_params: Iterable[Any] | None,
        where: Sequence[str] | None,
        params: Sequence[str] | None,
        tables: Sequence[str] | None,
        order_by: Sequence[str] | None,
    ) -> None: ...
    def clear_deferred_loading(self) -> None: ...
    def add_deferred_loading(self, field_names: Iterable[str]) -> None: ...
    def add_immediate_loading(self, field_names: Iterable[str]) -> None: ...
    def get_loaded_field_names(self) -> dict[type[Model], set[str]]: ...
    def get_loaded_field_names_cb(
        self,
        target: dict[type[Model], set[str]],
        model: type[Model],
        fields: set[Field[Any, Any]],
    ) -> None: ...
    def set_annotation_mask(
        self, names: list[str] | set[str] | tuple[Any, ...] | None
    ) -> None: ...
    def append_annotation_mask(self, names: list[str]) -> None: ...
    def set_extra_mask(self, names: list[str] | tuple[Any, ...]) -> None: ...
    def set_values(self, fields: list[str] | tuple[Any, ...]) -> None: ...
    def trim_start(
        self, names_with_path: list[tuple[str, list[PathInfo]]]
    ) -> tuple[str, bool]: ...
    def is_nullable(self, field: Field[Any, Any]) -> bool: ...
    def build_lookup(
        self,
        lookups: Sequence[str],
        lhs: RegisterLookupMixin | Query,
        rhs: Query | None,
    ) -> Lookup[Any]: ...
    def try_transform(
        self, lhs: RegisterLookupMixin | Query, name: str
    ) -> Transform: ...

class JoinPromoter:
    connector: str = ...
    negated: bool = ...
    effective_connector: str = ...
    num_children: int = ...
    votes: Counter[Any] = ...
    def __init__(self, connector: str, num_children: int, negated: bool) -> None: ...
    def add_votes(
        self, votes: Iterator[Any] | list[Any] | set[str] | tuple[Any, ...]
    ) -> None: ...
    def update_join_types(self, query: Query) -> set[str]: ...
