# coding: utf-8

"""
    Mixpeek API

    This is the Mixpeek API, providing access to various endpoints for data processing and retrieval.

    The version of the OpenAPI document: 1.3.0
    Contact: info@mixpeek.com
    Generated by OpenAPI Generator (https://openapi-generator.tech)

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


from __future__ import annotations
import pprint
import re  # noqa: F401
import json

from pydantic import BaseModel, ConfigDict, Field, StrictBool
from typing import Any, ClassVar, Dict, List, Optional
from typing_extensions import Annotated
from typing import Optional, Set
from typing_extensions import Self

class StageParamsJsonTransform(BaseModel):
    """
    Configuration for JSON Jinja template transformation stage.  Stage Category: APPLY (1-1 transformation)  Transformation: N documents → N documents (or fewer with fail_on_error=False)  Purpose: Applies a Jinja2 template to each document in the retrieval pipeline, rendering the template with full document context and replacing the document with the parsed JSON output. Useful for reformatting documents to match external API schemas or restructuring data for downstream consumers.  Performance: Template rendering is fast (<1ms per document). No caching is implemented as re-rendering is faster than cache overhead for typical document sizes. Processes documents sequentially with error handling.  When to Use:     - Reformat documents for external API calls (webhooks, workflows)     - Rename or reorganize document fields for client consumption     - Drop unnecessary properties to reduce response size     - Expand or flatten nested arrays/objects     - Apply conditional field inclusion based on document values     - Create custom response schemas from standard document format  When NOT to Use:     - For filtering documents (use FILTER stages: structured_filter, llm_filter)     - For sorting documents (use SORT stages: sort_relevance, rerank)     - For enriching with new data (use APPLY stages: document_enrich)     - For joining external data (use APPLY 1-N stages: taxonomy_enrich)  Template Context:     Templates have access to the full retriever template context:     - DOC (or doc): Current document fields and metadata     - INPUT (or input/inputs): Original query inputs from the search request     - CONTEXT (or context): Execution context (namespace_id, internal_id, etc.)     - STAGE (or stage): Current stage execution data and metadata  Template Features:     - Standard Jinja2 syntax with all built-in filters (tojson, length, etc.)     - Conditional logic ({% if %}, {% elif %}, {% else %})     - Loops and iteration ({% for item in items %})     - Variable access with dot notation (DOC.metadata.field)     - JSON filters for proper escaping ({{ value | tojson }})  Error Handling:     Documents that fail template rendering or JSON parsing can either     skip with a warning (default) or fail the entire retrieval pipeline.     Failed documents are tracked in stage metadata for observability.  Operational Behavior:     - Fast stage: runs in API layer (no Engine delegation)     - Sequential processing: documents transformed one at a time     - Error isolation: one document failure doesn't affect others (unless fail_on_error=True)     - Schema replacement: output schema completely defined by template     - Reports metrics to ClickHouse for performance monitoring  Common Pipeline Position: FILTER → SORT → APPLY (this stage)  Requirements:     - template: REQUIRED     - fail_on_error: OPTIONAL (defaults to False)  Use Cases:     - External API formatting: Format documents for webhook payloads     - Response optimization: Remove unused fields to reduce bandwidth     - Schema adaptation: Convert internal format to client-specific format     - Conditional outputs: Include fields based on document properties     - Array flattening: Transform nested structures to flat arrays  Examples:     Basic field selection and renaming:     >>> template = '{\"id\": \"{{ DOC.document_id }}\", \"text\": \"{{ DOC.content }}\"}'      Conditional field inclusion for external API:     >>> template = '_'_'     ... {     ...   \"workflow\": \"{{ DOC.workflow_name }}\",     ...   \"inputs\": [     ...     {\"name\": \"variant_id\", \"value\": \"{{ DOC.variant_id }}\"}     ...     {% if DOC.asset_type == \"VIDEO\" %},     ...     {\"name\": \"video\", \"value\": {\"src\": \"{{ DOC.asset_url }}\"}}     ...     {% endif %}     ...   ]     ... }     ... '_'_'      Array expansion with iteration:     >>> template = '_'_'     ... {     ...   \"items\": [     ...     {% for item in DOC.tags %}     ...     \"{{ item }}\"{% if not loop.last %},{% endif %}     ...     {% endfor %}     ...   ]     ... }     ... '_'_'      Nested field access and JSON escaping:     >>> template = '{\"user\": \"{{ DOC.metadata.user_id }}\", \"data\": {{ DOC.raw_data | tojson }}}'
    """ # noqa: E501
    template: Optional[Annotated[str, Field(min_length=1, strict=True)]] = Field(default='{"id": "{{ DOC.document_id }}", "content": {{ DOC.content | tojson }}, "score": {{ DOC.score }}}', description="Jinja2 template string that must render to valid JSON. The template has access to full retriever context: - DOC (or doc): Current document fields and metadata - INPUT (or input/inputs): Original query inputs from search request - CONTEXT (or context): Execution context (namespace_id, internal_id) - STAGE (or stage): Current stage execution data Both uppercase and lowercase namespace formats work identically (DOC == doc). The template must produce valid JSON syntax when rendered - invalid JSON will cause document to be skipped (unless fail_on_error=True). Supports all Jinja2 features: conditionals ({% if %}), loops ({% for %}), filters (| tojson, | length), variable access (DOC.metadata.field). Common patterns: - Field selection: {'id': '{{ DOC.document_id }}'} - Conditional inclusion: {% if DOC.type == 'video' %}...{% endif %} - Array iteration: {% for item in DOC.tags %}...{% endfor %} - JSON escaping: {{ DOC.data | tojson }} Use cases: API formatting, field renaming, property filtering, structure flattening.")
    fail_on_error: Optional[StrictBool] = Field(default=False, description="OPTIONAL. Whether to fail the entire retrieval pipeline if any document transformation fails. Default: False. False (default): Skip failed documents with warning logged, continue processing remaining documents. Failed documents are tracked in stage metadata for observability and debugging. Use for lenient pipelines where partial results are acceptable (e.g., best-effort reformatting). True: Fail entire retrieval on first transformation error. Use for strict pipelines where all documents must transform successfully (e.g., critical API integrations where incomplete data would cause downstream failures). Failure causes: invalid template syntax, template rendering errors (missing fields), invalid JSON output from template, document missing required fields. Typical values: False for public APIs (resilient), True for internal workflows (data integrity critical).")
    additional_properties: Dict[str, Any] = {}
    __properties: ClassVar[List[str]] = ["template", "fail_on_error"]

    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 StageParamsJsonTransform 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.
        * Fields in `self.additional_properties` are added to the output dict.
        """
        excluded_fields: Set[str] = set([
            "additional_properties",
        ])

        _dict = self.model_dump(
            by_alias=True,
            exclude=excluded_fields,
            exclude_none=True,
        )
        # puts key-value pairs in additional_properties in the top level
        if self.additional_properties is not None:
            for _key, _value in self.additional_properties.items():
                _dict[_key] = _value

        return _dict

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

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

        _obj = cls.model_validate({
            "template": obj.get("template") if obj.get("template") is not None else '{"id": "{{ DOC.document_id }}", "content": {{ DOC.content | tojson }}, "score": {{ DOC.score }}}',
            "fail_on_error": obj.get("fail_on_error") if obj.get("fail_on_error") is not None else False
        })
        # store additional fields in additional_properties
        for _key in obj.keys():
            if _key not in cls.__properties:
                _obj.additional_properties[_key] = obj.get(_key)

        return _obj


