# coding: utf-8

"""
Perigon API

The Perigon API provides access to comprehensive news and web content data. To use the API, simply sign up for a Perigon Business Solutions account to obtain your API key. Your available features may vary based on your plan. See the Authentication section for details on how to use your API key.

The version of the OpenAPI document: 1.0.0
Contact: data@perigon.io
Generated by OpenAPI Generator (https://openapi-generator.tech)

Do not edit the class manually.
"""  # noqa: E501


from __future__ import annotations

import json
import pprint
import re  # noqa: F401
from typing import Any, ClassVar, Dict, List, Optional, Set

from pydantic import BaseModel, ConfigDict, Field, StrictStr
from typing_extensions import Self

from perigon.models.coordinate_filter import CoordinateFilter


class ArticleSearchFilter(BaseModel):
    """
    Complex filter structure for article searches that supports nested logical operations (AND, OR, NOT) and multiple filtering criteria.
    """  # noqa: E501

    article_id: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter by specific article identifiers. Accepts either a single ID or an array of IDs. Returns only articles matching these IDs.",
        alias="articleId",
    )
    cluster_id: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter by specific story identifiers. Accepts either a single ID or an array of IDs. Returns only articles belonging to these stories.",
        alias="clusterId",
    )
    source: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles by specific publisher domains or subdomains. Accepts either a single domain or an array of domains. Multiple values create an OR filter.",
    )
    exclude_source: Optional[List[StrictStr]] = Field(
        default=None,
        description="Exclude articles from specific publisher domains or subdomains. Accepts either a single domain or an array of domains. Multiple values create an AND-exclude filter.",
        alias="excludeSource",
    )
    source_group: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles using Perigon's curated publisher bundles (e.g., top100, top25tech). Accepts either a single source group or an array. Multiple values create an OR filter to include articles from any of the specified bundles.",
        alias="sourceGroup",
    )
    language: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles by their language using ISO-639 two-letter codes in lowercase (e.g., en, es, fr). Accepts either a single language code or an array. Multiple values create an OR filter.",
    )
    exclude_language: Optional[List[StrictStr]] = Field(
        default=None,
        description="Exclude articles in specific languages using ISO-639 two-letter codes in lowercase. Accepts either a single language code or an array. Multiple values create an AND-exclude filter.",
        alias="excludeLanguage",
    )
    label: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles by editorial labels such as Opinion, Paid-news, Non-news, Fact Check, or Press Release. View our docs for an exhaustive list of labels. Accepts either a single label or an array. Multiple values create an OR filter.",
    )
    exclude_label: Optional[List[StrictStr]] = Field(
        default=None,
        description="Exclude articles with specific editorial labels. Accepts either a single label or an array. Multiple values create an AND-exclude filter, removing all content with any of these labels.",
        alias="excludeLabel",
    )
    taxonomy: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter by Google Content Categories. Must pass the full hierarchical path of the category. Accepts either a single path or an array. Example: taxonomy=/Finance/Banking/Other,/Finance/Investing/Funds. Multiple values create an OR filter.",
    )
    category: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter by broad content categories such as Politics, Tech, Sports, Business, or Finance. Accepts either a single category or an array. Use none to find uncategorized articles. Multiple values create an OR filter.",
    )
    topic: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter by specific topics such as Markets, Crime, Cryptocurrency, or College Sports. Accepts either a single topic or an array. Topics are more granular than categories, and articles can have multiple topics. Multiple values create an OR filter.",
    )
    exclude_topic: Optional[List[StrictStr]] = Field(
        default=None,
        description="Exclude articles with specific topics. Accepts either a single topic or an array. Multiple values create an AND-exclude filter, removing all content with any of these topics.",
        alias="excludeTopic",
    )
    country: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles by countries they mention using two-letter country codes in lowercase (e.g., us, gb, jp). Accepts either a single country code or an array. Multiple values create an OR filter. See documentation for supported country codes.",
    )
    exclude_country: Optional[List[StrictStr]] = Field(
        default=None,
        description="Exclude articles from specific countries using two-letter country codes in lowercase. Accepts either a single country code or an array. Multiple values create an AND-exclude filter. See documentation for supported country codes.",
        alias="excludeCountry",
    )
    locations_country: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles where specified countries play a central role in the content, not just mentioned. Uses two-letter country codes in lowercase. Accepts either a single country code or an array. Multiple values create an OR filter. See documentation for supported country codes.",
        alias="locationsCountry",
    )
    exclude_locations_country: Optional[List[StrictStr]] = Field(
        default=None,
        description="Exclude articles where specified countries play a central role in the content. Accepts either a single country code or an array. Multiple values create an AND-exclude filter, removing articles focused on any of these countries. See documentation for supported country codes.",
        alias="excludeLocationsCountry",
    )
    state: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles where specified states play a central role in the content. Accepts either a single state code or an array. Multiple values create an OR filter. Uses two-letter state codes in lowercase. See documentation for supported state codes.",
    )
    exclude_state: Optional[List[StrictStr]] = Field(
        default=None,
        description="Exclude articles where specified states play a central role. Accepts either a single state code or an array. Multiple values create an AND-exclude filter, removing articles focused on any of these states. See documentation for supported state codes.",
        alias="excludeState",
    )
    county: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles that mention or are related to specific counties. Accepts either a single county name or an array. Multiple values create an OR filter. County names typically include the word 'County' (e.g., Los Angeles County).",
    )
    exclude_county: Optional[List[StrictStr]] = Field(
        default=None,
        description="Exclude articles that mention or are related to specific counties. Accepts either a single county name or an array. Multiple values create an AND-exclude filter. County names should match the format in article metadata (e.g., Los Angeles County, Cook County).",
        alias="excludeCounty",
    )
    city: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles that mention or are related to specific cities. Accepts either a single city name or an array. Multiple values create an OR filter.",
    )
    exclude_city: Optional[List[StrictStr]] = Field(
        default=None,
        description="Exclude articles that mention or are related to specific cities. Accepts either a single city name or an array. Multiple values create an AND-exclude filter.",
        alias="excludeCity",
    )
    source_country: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter for articles from publishers based in specific countries. Accepts either a single country code or an array. Uses two-letter country codes in lowercase (e.g., us, gb). See documentation for supported country codes.",
        alias="sourceCountry",
    )
    source_state: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter for articles from publishers based in specific states or regions. Accepts either a single state code or an array. Uses two-letter state codes in lowercase. See documentation for supported state codes.",
        alias="sourceState",
    )
    source_county: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter for articles from publishers based in specific counties. Accepts either a single county name or an array. Multiple values create an OR filter.",
        alias="sourceCounty",
    )
    source_city: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter for articles from publishers based in specific cities. Accepts either a single city name or an array. Multiple values create an OR filter.",
        alias="sourceCity",
    )
    coordinates: Optional[CoordinateFilter] = None
    source_coordinates: Optional[CoordinateFilter] = Field(
        default=None, alias="sourceCoordinates"
    )
    company_id: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles by company identifiers. Accepts either a single ID or an array. Multiple values create an OR filter. For a complete list of tracked companies and their IDs, refer to the /companies endpoint.",
        alias="companyId",
    )
    exclude_company_id: Optional[List[StrictStr]] = Field(
        default=None,
        description="Exclude articles mentioning companies with specific identifiers. Accepts either a single ID or an array. Multiple values create an AND-exclude filter. For a complete list of tracked companies and their IDs, refer to the /companies endpoint.",
        alias="excludeCompanyId",
    )
    company_domain: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles by company domains (e.g., apple.com). Accepts either a single domain or an array. Multiple values create an OR filter. For a complete list of tracked companies and their domains, refer to the /companies endpoint.",
        alias="companyDomain",
    )
    exclude_company_domain: Optional[List[StrictStr]] = Field(
        default=None,
        description="Exclude articles related to companies with specific domains. Accepts either a single domain or an array. Multiple values create an AND-exclude filter. For a complete list of tracked companies and their domains, refer to the /companies endpoint.",
        alias="excludeCompanyDomain",
    )
    company_symbol: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles by company stock symbols (e.g., AAPL, MSFT). Accepts either a single symbol or an array. Multiple values create an OR filter. For a complete list of tracked companies and their symbols, refer to the /companies endpoint.",
        alias="companySymbol",
    )
    exclude_company_symbol: Optional[List[StrictStr]] = Field(
        default=None,
        description="Exclude articles related to companies with specific stock symbols. Accepts either a single symbol or an array. Multiple values create an AND-exclude filter. For a complete list of tracked companies and their symbols, refer to the /companies endpoint.",
        alias="excludeCompanySymbol",
    )
    company_name: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles by company name mentions. Accepts either a single name or an array. Performs exact matching on company names. Multiple values create an OR filter. For a complete list of tracked companies and their names, refer to the /companies endpoint.",
        alias="companyName",
    )
    person_wikidata_id: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles by Wikidata IDs of mentioned people. Accepts either a single ID or an array. Multiple values create an OR filter. For a complete list of tracked individuals and their Wikidata IDs, refer to the /people endpoint.",
        alias="personWikidataId",
    )
    exclude_person_wikidata_id: Optional[List[StrictStr]] = Field(
        default=None,
        description="Exclude articles mentioning people with specific Wikidata IDs. Accepts either a single ID or an array. Multiple values create an AND-exclude filter. For a complete list of tracked individuals and their Wikidata IDs, refer to the /people endpoint.",
        alias="excludePersonWikidataId",
    )
    person_name: Optional[List[StrictStr]] = Field(
        default=None,
        description="Filter articles by exact person name matches. Accepts either a single name or an array. Does not support Boolean operators or wildcards. Multiple values create an OR filter. For a complete list of tracked individuals and their names, refer to the /people endpoint.",
        alias="personName",
    )
    exclude_person_name: Optional[List[StrictStr]] = Field(
        default=None,
        description="Exclude articles mentioning specific people by name. Accepts either a single name or an array. Multiple values create an AND-exclude filter. For a complete list of tracked individuals and their names, refer to the /people endpoint.",
        alias="excludePersonName",
    )
    var_and: Optional[List[ArticleSearchFilter]] = Field(
        default=None,
        description="Adds additional AND filter objects. These objects must be of the same type as the original filter object and will be combined with the existing filter using the AND logical operator.",
        alias="AND",
    )
    var_or: Optional[List[ArticleSearchFilter]] = Field(
        default=None,
        description="Adds additional OR filter objects. These objects must be of the same type as the original filter object and will be combined with the existing filter using the OR logical operator.",
        alias="OR",
    )
    var_not: Optional[List[ArticleSearchFilter]] = Field(
        default=None,
        description="A filter object for logical NOT operations",
        alias="NOT",
    )
    __properties: ClassVar[List[str]] = [
        "articleId",
        "clusterId",
        "source",
        "excludeSource",
        "sourceGroup",
        "language",
        "excludeLanguage",
        "label",
        "excludeLabel",
        "taxonomy",
        "category",
        "topic",
        "excludeTopic",
        "country",
        "excludeCountry",
        "locationsCountry",
        "excludeLocationsCountry",
        "state",
        "excludeState",
        "county",
        "excludeCounty",
        "city",
        "excludeCity",
        "sourceCountry",
        "sourceState",
        "sourceCounty",
        "sourceCity",
        "coordinates",
        "sourceCoordinates",
        "companyId",
        "excludeCompanyId",
        "companyDomain",
        "excludeCompanyDomain",
        "companySymbol",
        "excludeCompanySymbol",
        "companyName",
        "personWikidataId",
        "excludePersonWikidataId",
        "personName",
        "excludePersonName",
        "AND",
        "OR",
        "NOT",
    ]

    model_config = ConfigDict(
        populate_by_name=True,
        validate_assignment=True,
        protected_namespaces=(),
    )

    def to_str(self) -> str:
        """Returns the string representation of the model using alias"""
        return pprint.pformat(self.model_dump(by_alias=True))

    def to_json(self) -> str:
        """Returns the JSON representation of the model using alias"""
        # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
        return json.dumps(self.to_dict())

    @classmethod
    def from_json(cls, json_str: str) -> Optional[Self]:
        """Create an instance of ArticleSearchFilter from a JSON string"""
        return cls.from_dict(json.loads(json_str))

    def to_dict(self) -> Dict[str, Any]:
        """Return the dictionary representation of the model using alias.

        This has the following differences from calling pydantic's
        `self.model_dump(by_alias=True)`:

        * `None` is only added to the output dict for nullable fields that
          were set at model initialization. Other fields with value `None`
          are ignored.
        """
        excluded_fields: Set[str] = set([])

        _dict = self.model_dump(
            by_alias=True,
            exclude=excluded_fields,
            exclude_none=True,
        )
        # override the default output from pydantic by calling `to_dict()` of coordinates
        if self.coordinates:
            _dict["coordinates"] = self.coordinates.to_dict()
        # override the default output from pydantic by calling `to_dict()` of source_coordinates
        if self.source_coordinates:
            _dict["sourceCoordinates"] = self.source_coordinates.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in var_and (list)
        _items = []
        if self.var_and:
            for _item_var_and in self.var_and:
                if _item_var_and:
                    _items.append(_item_var_and.to_dict())
            _dict["AND"] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in var_or (list)
        _items = []
        if self.var_or:
            for _item_var_or in self.var_or:
                if _item_var_or:
                    _items.append(_item_var_or.to_dict())
            _dict["OR"] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in var_not (list)
        _items = []
        if self.var_not:
            for _item_var_not in self.var_not:
                if _item_var_not:
                    _items.append(_item_var_not.to_dict())
            _dict["NOT"] = _items
        # set to None if article_id (nullable) is None
        # and model_fields_set contains the field
        if self.article_id is None and "article_id" in self.model_fields_set:
            _dict["articleId"] = None

        # set to None if cluster_id (nullable) is None
        # and model_fields_set contains the field
        if self.cluster_id is None and "cluster_id" in self.model_fields_set:
            _dict["clusterId"] = None

        # set to None if source (nullable) is None
        # and model_fields_set contains the field
        if self.source is None and "source" in self.model_fields_set:
            _dict["source"] = None

        # set to None if exclude_source (nullable) is None
        # and model_fields_set contains the field
        if self.exclude_source is None and "exclude_source" in self.model_fields_set:
            _dict["excludeSource"] = None

        # set to None if source_group (nullable) is None
        # and model_fields_set contains the field
        if self.source_group is None and "source_group" in self.model_fields_set:
            _dict["sourceGroup"] = None

        # set to None if language (nullable) is None
        # and model_fields_set contains the field
        if self.language is None and "language" in self.model_fields_set:
            _dict["language"] = None

        # set to None if exclude_language (nullable) is None
        # and model_fields_set contains the field
        if (
            self.exclude_language is None
            and "exclude_language" in self.model_fields_set
        ):
            _dict["excludeLanguage"] = None

        # set to None if label (nullable) is None
        # and model_fields_set contains the field
        if self.label is None and "label" in self.model_fields_set:
            _dict["label"] = None

        # set to None if exclude_label (nullable) is None
        # and model_fields_set contains the field
        if self.exclude_label is None and "exclude_label" in self.model_fields_set:
            _dict["excludeLabel"] = None

        # set to None if taxonomy (nullable) is None
        # and model_fields_set contains the field
        if self.taxonomy is None and "taxonomy" in self.model_fields_set:
            _dict["taxonomy"] = None

        # set to None if category (nullable) is None
        # and model_fields_set contains the field
        if self.category is None and "category" in self.model_fields_set:
            _dict["category"] = None

        # set to None if topic (nullable) is None
        # and model_fields_set contains the field
        if self.topic is None and "topic" in self.model_fields_set:
            _dict["topic"] = None

        # set to None if exclude_topic (nullable) is None
        # and model_fields_set contains the field
        if self.exclude_topic is None and "exclude_topic" in self.model_fields_set:
            _dict["excludeTopic"] = None

        # set to None if country (nullable) is None
        # and model_fields_set contains the field
        if self.country is None and "country" in self.model_fields_set:
            _dict["country"] = None

        # set to None if exclude_country (nullable) is None
        # and model_fields_set contains the field
        if self.exclude_country is None and "exclude_country" in self.model_fields_set:
            _dict["excludeCountry"] = None

        # set to None if locations_country (nullable) is None
        # and model_fields_set contains the field
        if (
            self.locations_country is None
            and "locations_country" in self.model_fields_set
        ):
            _dict["locationsCountry"] = None

        # set to None if exclude_locations_country (nullable) is None
        # and model_fields_set contains the field
        if (
            self.exclude_locations_country is None
            and "exclude_locations_country" in self.model_fields_set
        ):
            _dict["excludeLocationsCountry"] = None

        # set to None if state (nullable) is None
        # and model_fields_set contains the field
        if self.state is None and "state" in self.model_fields_set:
            _dict["state"] = None

        # set to None if exclude_state (nullable) is None
        # and model_fields_set contains the field
        if self.exclude_state is None and "exclude_state" in self.model_fields_set:
            _dict["excludeState"] = None

        # set to None if county (nullable) is None
        # and model_fields_set contains the field
        if self.county is None and "county" in self.model_fields_set:
            _dict["county"] = None

        # set to None if exclude_county (nullable) is None
        # and model_fields_set contains the field
        if self.exclude_county is None and "exclude_county" in self.model_fields_set:
            _dict["excludeCounty"] = None

        # set to None if city (nullable) is None
        # and model_fields_set contains the field
        if self.city is None and "city" in self.model_fields_set:
            _dict["city"] = None

        # set to None if exclude_city (nullable) is None
        # and model_fields_set contains the field
        if self.exclude_city is None and "exclude_city" in self.model_fields_set:
            _dict["excludeCity"] = None

        # set to None if source_country (nullable) is None
        # and model_fields_set contains the field
        if self.source_country is None and "source_country" in self.model_fields_set:
            _dict["sourceCountry"] = None

        # set to None if source_state (nullable) is None
        # and model_fields_set contains the field
        if self.source_state is None and "source_state" in self.model_fields_set:
            _dict["sourceState"] = None

        # set to None if source_county (nullable) is None
        # and model_fields_set contains the field
        if self.source_county is None and "source_county" in self.model_fields_set:
            _dict["sourceCounty"] = None

        # set to None if source_city (nullable) is None
        # and model_fields_set contains the field
        if self.source_city is None and "source_city" in self.model_fields_set:
            _dict["sourceCity"] = None

        # set to None if coordinates (nullable) is None
        # and model_fields_set contains the field
        if self.coordinates is None and "coordinates" in self.model_fields_set:
            _dict["coordinates"] = None

        # set to None if source_coordinates (nullable) is None
        # and model_fields_set contains the field
        if (
            self.source_coordinates is None
            and "source_coordinates" in self.model_fields_set
        ):
            _dict["sourceCoordinates"] = None

        # set to None if company_id (nullable) is None
        # and model_fields_set contains the field
        if self.company_id is None and "company_id" in self.model_fields_set:
            _dict["companyId"] = None

        # set to None if exclude_company_id (nullable) is None
        # and model_fields_set contains the field
        if (
            self.exclude_company_id is None
            and "exclude_company_id" in self.model_fields_set
        ):
            _dict["excludeCompanyId"] = None

        # set to None if company_domain (nullable) is None
        # and model_fields_set contains the field
        if self.company_domain is None and "company_domain" in self.model_fields_set:
            _dict["companyDomain"] = None

        # set to None if exclude_company_domain (nullable) is None
        # and model_fields_set contains the field
        if (
            self.exclude_company_domain is None
            and "exclude_company_domain" in self.model_fields_set
        ):
            _dict["excludeCompanyDomain"] = None

        # set to None if company_symbol (nullable) is None
        # and model_fields_set contains the field
        if self.company_symbol is None and "company_symbol" in self.model_fields_set:
            _dict["companySymbol"] = None

        # set to None if exclude_company_symbol (nullable) is None
        # and model_fields_set contains the field
        if (
            self.exclude_company_symbol is None
            and "exclude_company_symbol" in self.model_fields_set
        ):
            _dict["excludeCompanySymbol"] = None

        # set to None if company_name (nullable) is None
        # and model_fields_set contains the field
        if self.company_name is None and "company_name" in self.model_fields_set:
            _dict["companyName"] = None

        # set to None if person_wikidata_id (nullable) is None
        # and model_fields_set contains the field
        if (
            self.person_wikidata_id is None
            and "person_wikidata_id" in self.model_fields_set
        ):
            _dict["personWikidataId"] = None

        # set to None if exclude_person_wikidata_id (nullable) is None
        # and model_fields_set contains the field
        if (
            self.exclude_person_wikidata_id is None
            and "exclude_person_wikidata_id" in self.model_fields_set
        ):
            _dict["excludePersonWikidataId"] = None

        # set to None if person_name (nullable) is None
        # and model_fields_set contains the field
        if self.person_name is None and "person_name" in self.model_fields_set:
            _dict["personName"] = None

        # set to None if exclude_person_name (nullable) is None
        # and model_fields_set contains the field
        if (
            self.exclude_person_name is None
            and "exclude_person_name" in self.model_fields_set
        ):
            _dict["excludePersonName"] = None

        # set to None if var_and (nullable) is None
        # and model_fields_set contains the field
        if self.var_and is None and "var_and" in self.model_fields_set:
            _dict["AND"] = None

        # set to None if var_or (nullable) is None
        # and model_fields_set contains the field
        if self.var_or is None and "var_or" in self.model_fields_set:
            _dict["OR"] = None

        # set to None if var_not (nullable) is None
        # and model_fields_set contains the field
        if self.var_not is None and "var_not" in self.model_fields_set:
            _dict["NOT"] = None

        return _dict

    @classmethod
    def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
        """Create an instance of ArticleSearchFilter from a dict"""
        if obj is None:
            return None

        if not isinstance(obj, dict):
            return cls.model_validate(obj)

        _obj = cls.model_validate(
            {
                "articleId": obj.get("articleId"),
                "clusterId": obj.get("clusterId"),
                "source": obj.get("source"),
                "excludeSource": obj.get("excludeSource"),
                "sourceGroup": obj.get("sourceGroup"),
                "language": obj.get("language"),
                "excludeLanguage": obj.get("excludeLanguage"),
                "label": obj.get("label"),
                "excludeLabel": obj.get("excludeLabel"),
                "taxonomy": obj.get("taxonomy"),
                "category": obj.get("category"),
                "topic": obj.get("topic"),
                "excludeTopic": obj.get("excludeTopic"),
                "country": obj.get("country"),
                "excludeCountry": obj.get("excludeCountry"),
                "locationsCountry": obj.get("locationsCountry"),
                "excludeLocationsCountry": obj.get("excludeLocationsCountry"),
                "state": obj.get("state"),
                "excludeState": obj.get("excludeState"),
                "county": obj.get("county"),
                "excludeCounty": obj.get("excludeCounty"),
                "city": obj.get("city"),
                "excludeCity": obj.get("excludeCity"),
                "sourceCountry": obj.get("sourceCountry"),
                "sourceState": obj.get("sourceState"),
                "sourceCounty": obj.get("sourceCounty"),
                "sourceCity": obj.get("sourceCity"),
                "coordinates": (
                    CoordinateFilter.from_dict(obj["coordinates"])
                    if obj.get("coordinates") is not None
                    else None
                ),
                "sourceCoordinates": (
                    CoordinateFilter.from_dict(obj["sourceCoordinates"])
                    if obj.get("sourceCoordinates") is not None
                    else None
                ),
                "companyId": obj.get("companyId"),
                "excludeCompanyId": obj.get("excludeCompanyId"),
                "companyDomain": obj.get("companyDomain"),
                "excludeCompanyDomain": obj.get("excludeCompanyDomain"),
                "companySymbol": obj.get("companySymbol"),
                "excludeCompanySymbol": obj.get("excludeCompanySymbol"),
                "companyName": obj.get("companyName"),
                "personWikidataId": obj.get("personWikidataId"),
                "excludePersonWikidataId": obj.get("excludePersonWikidataId"),
                "personName": obj.get("personName"),
                "excludePersonName": obj.get("excludePersonName"),
                "AND": (
                    [ArticleSearchFilter.from_dict(_item) for _item in obj["AND"]]
                    if obj.get("AND") is not None
                    else None
                ),
                "OR": (
                    [ArticleSearchFilter.from_dict(_item) for _item in obj["OR"]]
                    if obj.get("OR") is not None
                    else None
                ),
                "NOT": (
                    [ArticleSearchFilter.from_dict(_item) for _item in obj["NOT"]]
                    if obj.get("NOT") is not None
                    else None
                ),
            }
        )
        return _obj


# TODO: Rewrite to not use raise_errors
ArticleSearchFilter.model_rebuild(raise_errors=False)
