from collections import OrderedDict
from typing import Any

from django.db.models.expressions import Expression
from django.db.models.sql.compiler import SQLCompiler
from django.db.models.sql.query import Query
from django.utils import tree

AND: str
OR: str

class WhereNode(tree.Node):
    connector: str
    contains_aggregate: bool
    contains_over_clause: bool
    negated: bool
    default: Any = ...
    resolved: bool = ...
    conditional: bool = ...
    def split_having(
        self, negated: bool = ...
    ) -> tuple[WhereNode | None, WhereNode | None]: ...
    def as_sql(self, compiler: SQLCompiler, connection: Any) -> Any: ...
    def get_group_by_cols(self) -> list[Expression]: ...
    def relabel_aliases(
        self, change_map: dict[str | None, str] | OrderedDict[Any, Any]
    ) -> None: ...
    def clone(self) -> WhereNode: ...
    def relabeled_clone(
        self, change_map: dict[str | None, str] | OrderedDict[Any, Any]
    ) -> WhereNode: ...
    def resolve_expression(self, *args: Any, **kwargs: Any) -> WhereNode: ...

class NothingNode:
    contains_aggregate: bool = ...
    def as_sql(self, compiler: SQLCompiler = ..., connection: Any = ...) -> Any: ...

class ExtraWhere:
    contains_aggregate: bool = ...
    sqls: list[str] = ...
    params: list[int] | list[str] | None = ...
    def __init__(
        self, sqls: list[str], params: list[int] | list[str] | None
    ) -> None: ...
    def as_sql(
        self, compiler: SQLCompiler = ..., connection: Any = ...
    ) -> tuple[str, list[int] | list[str]]: ...

class SubqueryConstraint:
    contains_aggregate: bool = ...
    alias: str = ...
    columns: list[str] = ...
    targets: list[str] = ...
    query_object: Query = ...
    def __init__(
        self, alias: str, columns: list[str], targets: list[str], query_object: Query
    ) -> None: ...
    def as_sql(
        self, compiler: SQLCompiler, connection: Any
    ) -> tuple[str, tuple[Any, ...]]: ...
